From 1aec4c9589db293f3de77c3e27534088ecf71fff Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 13 Oct 2026 14:11:43 -0700 Subject: [PATCH 1/4] chore: Remove plugins --- plugins/.eslintignore | 3 - plugins/.gitignore | 1 - plugins/README.md | 113 - plugins/block-dynamic-connection/CHANGELOG.md | 720 ----- .../block-dynamic-connection/GETSTARTED.md | 24 - plugins/block-dynamic-connection/README.md | 48 - plugins/block-dynamic-connection/package.json | 55 - .../src/connection_previewer.ts | 122 - .../src/dynamic_if.ts | 408 --- .../src/dynamic_list_create.ts | 302 -- .../src/dynamic_text_join.ts | 299 -- plugins/block-dynamic-connection/src/index.ts | 42 - .../test/dynamic_if.mocha.js | 649 ----- .../test/dynamic_list_create.mocha.js | 548 ---- .../test/dynamic_text_join.mocha.js | 550 ---- .../block-dynamic-connection/test/index.html | 18 - .../block-dynamic-connection/test/index.ts | 100 - .../block-dynamic-connection/tsconfig.json | 16 - plugins/block-plus-minus/CHANGELOG.md | 692 ----- plugins/block-plus-minus/README.md | 112 - plugins/block-plus-minus/package.json | 54 - .../readme-media/AllBlocks.png | Bin 17932 -> 0 bytes plugins/block-plus-minus/readme-media/If.png | Bin 2658 -> 0 bytes .../readme-media/IfElseIf.png | Bin 3365 -> 0 bytes .../readme-media/IfElseIfElse.png | Bin 3518 -> 0 bytes .../readme-media/ListCreateWith.png | Bin 3544 -> 0 bytes .../readme-media/ListCreateWithNone.png | Bin 3047 -> 0 bytes .../readme-media/TextJoin.png | Bin 3550 -> 0 bytes .../readme-media/TextJoinNone.png | Bin 1497 -> 0 bytes plugins/block-plus-minus/src/field_minus.js | 69 - plugins/block-plus-minus/src/field_plus.js | 71 - plugins/block-plus-minus/src/if.js | 229 -- plugins/block-plus-minus/src/index.js | 14 - plugins/block-plus-minus/src/list_create.js | 198 -- plugins/block-plus-minus/src/procedures.js | 694 ----- .../src/serialization_helper.js | 27 - plugins/block-plus-minus/src/text_join.js | 179 -- plugins/block-plus-minus/test/if.mocha.js | 229 -- plugins/block-plus-minus/test/index.html | 19 - plugins/block-plus-minus/test/index.js | 90 - .../test/list_create.mocha.js | 312 -- .../block-plus-minus/test/procedures.mocha.js | 782 ----- .../test/procedures_test_helpers.mocha.js | 260 -- .../test/test_helpers.mocha.js | 111 - .../block-plus-minus/test/text_join.mocha.js | 282 -- .../block-shareable-procedures/CHANGELOG.md | 682 ----- plugins/block-shareable-procedures/README.md | 32 - .../block-shareable-procedures/package.json | 58 - .../block-shareable-procedures/src/blocks.ts | 1395 --------- .../src/events_procedure_base.ts | 48 - .../src/events_procedure_change_return.ts | 105 - .../src/events_procedure_create.ts | 84 - .../src/events_procedure_delete.ts | 75 - .../src/events_procedure_enable.ts | 113 - .../src/events_procedure_parameter_base.ts | 79 - .../src/events_procedure_parameter_create.ts | 121 - .../src/events_procedure_parameter_delete.ts | 111 - .../src/events_procedure_parameter_rename.ts | 135 - .../src/events_procedure_rename.ts | 114 - .../src/i_procedure_block.ts | 32 - .../block-shareable-procedures/src/index.ts | 67 - .../src/observable_parameter_model.ts | 192 -- .../src/observable_procedure_model.ts | 305 -- .../src/update_procedures.ts | 22 - .../test/data_models.mocha.js | 547 ---- .../event_procedure_change_return.mocha.js | 224 -- .../test/event_procedure_create.mocha.js | 184 -- .../test/event_procedure_delete.mocha.js | 185 -- .../test/event_procedure_enable.mocha.js | 223 -- .../event_procedure_parameter_create.mocha.js | 356 --- .../event_procedure_parameter_delete.mocha.js | 305 -- .../event_procedure_parameter_rename.mocha.js | 332 --- .../test/event_procedure_rename.mocha.js | 268 -- .../test/event_test_helpers.js | 57 - .../test/index.html | 61 - .../block-shareable-procedures/test/index.js | 146 - .../test/procedure_blocks.mocha.js | 2588 ----------------- .../test/procedure_test_helpers.js | 216 -- .../block-shareable-procedures/tsconfig.json | 16 - plugins/block-test/CHANGELOG.md | 536 ---- plugins/block-test/README.md | 39 - plugins/block-test/package.json | 50 - plugins/block-test/src/align.js | 109 - plugins/block-test/src/basic.js | 219 -- plugins/block-test/src/chameleon.js | 61 - plugins/block-test/src/connections/index.js | 38 - plugins/block-test/src/connections/row.js | 290 -- plugins/block-test/src/connections/stack.js | 190 -- .../block-test/src/connections/statement.js | 267 -- plugins/block-test/src/drag.js | 261 -- plugins/block-test/src/fields/defaults.js | 281 -- plugins/block-test/src/fields/dropdowns.js | 591 ---- plugins/block-test/src/fields/emojis.js | 53 - plugins/block-test/src/fields/images.js | 281 -- plugins/block-test/src/fields/index.js | 51 - plugins/block-test/src/fields/numbers.js | 167 -- plugins/block-test/src/fields/validators.js | 577 ---- plugins/block-test/src/index.js | 80 - plugins/block-test/src/mutators.js | 257 -- .../block-test/src/serialization/blocks.js | 112 - .../block-test/src/serialization/category.js | 193 -- .../block-test/src/serialization/fields.js | 201 -- plugins/block-test/src/style.js | 194 -- plugins/block-test/test/index.html | 26 - plugins/block-test/test/index.js | 27 - plugins/content-highlight/CHANGELOG.md | 687 ----- plugins/content-highlight/README.md | 45 - plugins/content-highlight/package.json | 56 - .../readme-media/content-highlight.gif | Bin 962210 -> 0 bytes plugins/content-highlight/src/index.ts | 302 -- plugins/content-highlight/test/index.html | 18 - plugins/content-highlight/test/index.js | 48 - plugins/content-highlight/tsconfig.json | 16 - plugins/continuous-toolbox/CHANGELOG.md | 704 ----- plugins/continuous-toolbox/GETSTARTED.md | 22 - plugins/continuous-toolbox/README.md | 70 - plugins/continuous-toolbox/package.json | 52 - plugins/continuous-toolbox/screenshot.png | Bin 187895 -> 0 bytes .../src/ContinuousCategory.ts | 78 - .../src/ContinuousFlyout.ts | 340 --- .../src/ContinuousFlyoutMetrics.ts | 47 - .../src/ContinuousMetrics.ts | 87 - .../src/ContinuousToolbox.ts | 210 -- .../src/ContinuousToolboxNavigator.ts | 32 - .../src/RecyclableBlockFlyoutInflater.ts | 172 -- plugins/continuous-toolbox/src/index.ts | 92 - plugins/continuous-toolbox/test/index.html | 18 - plugins/continuous-toolbox/test/index.js | 34 - plugins/continuous-toolbox/tsconfig.json | 16 - plugins/cross-tab-copy-paste/CHANGELOG.md | 720 ----- plugins/cross-tab-copy-paste/GETSTARTED.md | 24 - plugins/cross-tab-copy-paste/README.md | 79 - plugins/cross-tab-copy-paste/package.json | 51 - plugins/cross-tab-copy-paste/src/index.ts | 497 ---- plugins/cross-tab-copy-paste/test/index.html | 23 - plugins/cross-tab-copy-paste/test/index.ts | 43 - plugins/cross-tab-copy-paste/tsconfig.json | 16 - plugins/dev-create/.gitignore | 3 - plugins/dev-create/CHANGELOG.md | 333 --- plugins/dev-create/README.md | 68 - plugins/dev-create/bin/app.js | 66 - plugins/dev-create/bin/common.js | 23 - plugins/dev-create/bin/create.js | 63 - plugins/dev-create/bin/plugin.js | 215 -- plugins/dev-create/package.json | 42 - plugins/dev-create/templates/block/README.md | 34 - .../templates/block/template/src/index.js | 21 - .../block/template/test/block_test.mocha.js | 146 - .../templates/block/template/test/index.html | 18 - .../templates/block/template/test/index.js | 46 - plugins/dev-create/templates/field/README.md | 64 - .../templates/field/template/src/index.js | 34 - .../field/template/test/field_test.mocha.js | 99 - .../templates/field/template/test/index.html | 18 - .../templates/field/template/test/index.js | 43 - plugins/dev-create/templates/plugin/README.md | 51 - .../templates/plugin/template/src/index.js | 35 - .../templates/plugin/template/test/index.html | 18 - .../templates/plugin/template/test/index.js | 40 - plugins/dev-create/templates/theme/README.md | 36 - .../templates/theme/template/src/index.js | 22 - .../templates/theme/template/test/index.html | 18 - .../templates/theme/template/test/index.js | 36 - .../templates/third_party/.gitignore | 24 - .../templates/third_party/GETSTARTED.md | 24 - .../templates/typescript-block/README.md | 34 - .../typescript-block/template/src/index.ts | 21 - .../typescript-block/template/test/index.html | 18 - .../typescript-block/template/test/index.ts | 50 - .../typescript-block/template/tsconfig.json | 16 - .../templates/typescript-field/README.md | 64 - .../typescript-field/template/src/index.ts | 35 - .../typescript-field/template/test/index.html | 18 - .../typescript-field/template/test/index.ts | 47 - .../typescript-field/template/tsconfig.json | 16 - .../templates/typescript-plugin/README.md | 51 - .../typescript-plugin/template/src/index.ts | 36 - .../template/test/index.html | 18 - .../typescript-plugin/template/test/index.ts | 44 - .../typescript-plugin/template/tsconfig.json | 16 - .../templates/typescript-theme/README.md | 36 - .../typescript-theme/template/src/index.ts | 22 - .../typescript-theme/template/test/index.html | 18 - .../typescript-theme/template/test/index.ts | 40 - .../typescript-theme/template/tsconfig.json | 16 - plugins/dev-scripts/CHANGELOG.md | 364 --- plugins/dev-scripts/README.md | 20 - plugins/dev-scripts/bin/blockly-scripts.js | 43 - plugins/dev-scripts/config/webpack.config.js | 173 -- .../config/webpackDevServer.config.js | 31 - plugins/dev-scripts/package.json | 51 - plugins/dev-scripts/scripts/auditFix.js | 31 - plugins/dev-scripts/scripts/build.js | 79 - plugins/dev-scripts/scripts/clean.js | 30 - plugins/dev-scripts/scripts/predeploy.js | 56 - plugins/dev-scripts/scripts/start.js | 188 -- plugins/dev-scripts/scripts/test.js | 92 - plugins/dev-tools/CHANGELOG.md | 688 ----- plugins/dev-tools/README.md | 216 -- plugins/dev-tools/package.json | 63 - .../block-bounds-with-children.png | Bin 53906 -> 0 bytes .../dev-tools/readme-media/block-bounds.png | Bin 42639 -> 0 bytes plugins/dev-tools/readme-media/connection.png | Bin 40456 -> 0 bytes .../dev-tools/readme-media/element-spacer.png | Bin 45737 -> 0 bytes plugins/dev-tools/readme-media/element.png | Bin 41503 -> 0 bytes plugins/dev-tools/readme-media/row-spacer.png | Bin 36903 -> 0 bytes plugins/dev-tools/readme-media/row.png | Bin 40915 -> 0 bytes .../dev-tools/src/block_test_helpers.mocha.js | 238 -- .../src/common_test_helpers.mocha.js | 126 - plugins/dev-tools/src/debug.js | 129 - plugins/dev-tools/src/debugDrawer.js | 456 --- .../dev-tools/src/event_test_helpers.mocha.js | 93 - .../dev-tools/src/field_test_helpers.mocha.js | 310 -- .../dev-tools/src/generateFieldTestBlocks.js | 122 - plugins/dev-tools/src/index.d.ts | 120 - plugins/dev-tools/src/index.js | 50 - plugins/dev-tools/src/logger.js | 34 - .../dev-tools/src/playground/hash_state.js | 73 - plugins/dev-tools/src/playground/id.js | 12 - plugins/dev-tools/src/playground/index.js | 661 ----- plugins/dev-tools/src/playground/monaco.js | 78 - plugins/dev-tools/src/playground/options.js | 1083 ------- plugins/dev-tools/src/playground/state.js | 73 - plugins/dev-tools/src/playground/ui.js | 179 -- plugins/dev-tools/src/populateRandom.js | 45 - plugins/dev-tools/src/screenshot.js | 134 - plugins/dev-tools/src/spaghetti.js | 65 - plugins/dev-tools/src/test_helpers.mocha.js | 53 - plugins/dev-tools/src/toolboxCategories.js | 786 ----- plugins/dev-tools/src/toolboxSimple.js | 83 - plugins/dev-tools/test/index.html | 18 - plugins/dev-tools/test/index.js | 35 - plugins/disable-top-blocks/CHANGELOG.md | 653 ----- plugins/disable-top-blocks/README.md | 50 - plugins/disable-top-blocks/package.json | 50 - plugins/disable-top-blocks/src/index.js | 75 - plugins/disable-top-blocks/test/index.html | 18 - plugins/disable-top-blocks/test/index.js | 44 - plugins/field-angle/CHANGELOG.md | 509 ---- plugins/field-angle/README.md | 112 - plugins/field-angle/package.json | 55 - .../readme-media/clockwise_false.gif | Bin 39421 -> 0 bytes .../readme-media/clockwise_true.gif | Bin 38124 -> 0 bytes .../field-angle/readme-media/collapsed.png | Bin 2033 -> 0 bytes plugins/field-angle/readme-media/compass.gif | Bin 31504 -> 0 bytes .../field-angle/readme-media/offset_right.png | Bin 6737 -> 0 bytes .../field-angle/readme-media/offset_top.png | Bin 6543 -> 0 bytes plugins/field-angle/readme-media/on_block.png | Bin 1945 -> 0 bytes .../field-angle/readme-media/protractor.gif | Bin 40593 -> 0 bytes plugins/field-angle/readme-media/round_70.gif | Bin 114103 -> 0 bytes .../field-angle/readme-media/validator.gif | Bin 60197 -> 0 bytes .../field-angle/readme-media/with_editor.png | Bin 6793 -> 0 bytes plugins/field-angle/readme-media/wrap.gif | Bin 54192 -> 0 bytes plugins/field-angle/src/field_angle.ts | 800 ----- plugins/field-angle/src/index.ts | 7 - .../test/field_angle_test.mocha.js | 328 --- plugins/field-angle/test/index.html | 18 - plugins/field-angle/test/index.ts | 332 --- plugins/field-angle/tsconfig.json | 16 - plugins/field-bitmap/CHANGELOG.md | 699 ----- plugins/field-bitmap/README.md | 109 - plugins/field-bitmap/package.json | 55 - plugins/field-bitmap/src/field-bitmap.ts | 1006 ------- plugins/field-bitmap/src/index.ts | 7 - plugins/field-bitmap/test/field_test.mocha.js | 215 -- plugins/field-bitmap/test/index.html | 18 - plugins/field-bitmap/test/index.js | 336 --- plugins/field-bitmap/tsconfig.json | 16 - plugins/field-colour-hsv-sliders/CHANGELOG.md | 680 ----- plugins/field-colour-hsv-sliders/README.md | 88 - plugins/field-colour-hsv-sliders/package.json | 59 - .../readme-media/hsv_sliders_screenshot.png | Bin 59431 -> 0 bytes .../src/field_colour_hsv_sliders.ts | 864 ------ plugins/field-colour-hsv-sliders/src/index.ts | 7 - .../field_colour_hsv_sliders_test.mocha.js | 142 - ...d_colour_hsv_sliders_test_helpers.mocha.js | 36 - .../field-colour-hsv-sliders/test/index.html | 18 - .../field-colour-hsv-sliders/test/index.ts | 206 -- .../field-colour-hsv-sliders/tsconfig.json | 16 - plugins/field-colour/CHANGELOG.md | 552 ---- plugins/field-colour/README.md | 308 -- plugins/field-colour/package.json | 61 - .../field-colour/readme-media/collapsed.png | Bin 2140 -> 0 bytes .../field-colour/readme-media/customized.png | Bin 2337 -> 0 bytes .../field-colour/readme-media/on_block.png | Bin 1464 -> 0 bytes .../field-colour/readme-media/validator.gif | Bin 173464 -> 0 bytes .../field-colour/readme-media/with_editor.png | Bin 3870 -> 0 bytes .../field-colour/src/blocks/colourBlend.ts | 294 -- .../field-colour/src/blocks/colourPicker.ts | 141 - .../field-colour/src/blocks/colourRandom.ts | 171 -- plugins/field-colour/src/blocks/colourRgb.ts | 249 -- .../field-colour/src/blocks/generatorsType.ts | 24 - plugins/field-colour/src/field_colour.ts | 524 ---- plugins/field-colour/src/index.ts | 33 - .../field-colour/test/blocks_test.mocha.js | 228 -- .../test/field_colour_test.mocha.js | 389 --- plugins/field-colour/test/golden/golden.dart | 65 - plugins/field-colour/test/golden/golden.js | 46 - plugins/field-colour/test/golden/golden.lua | 35 - plugins/field-colour/test/golden/golden.php | 47 - plugins/field-colour/test/golden/golden.py | 32 - plugins/field-colour/test/index.html | 18 - plugins/field-colour/test/index.ts | 274 -- plugins/field-colour/tsconfig.json | 17 - plugins/field-date/.gitignore | 24 - plugins/field-date/CHANGELOG.md | 685 ----- plugins/field-date/README.md | 59 - plugins/field-date/package.json | 57 - plugins/field-date/src/field_date.ts | 286 -- plugins/field-date/src/index.ts | 7 - plugins/field-date/src/utils.ts | 20 - .../field-date/test/field_date_test.mocha.js | 267 -- plugins/field-date/test/index.html | 18 - plugins/field-date/test/index.ts | 231 -- plugins/field-date/tsconfig.json | 16 - plugins/field-dependent-dropdown/CHANGELOG.md | 508 ---- plugins/field-dependent-dropdown/README.md | 105 - plugins/field-dependent-dropdown/package.json | 56 - .../src/dependent_dropdown_options_change.ts | 233 -- .../src/field_dependent_dropdown.ts | 319 -- plugins/field-dependent-dropdown/src/index.ts | 7 - .../test/field_dependent_dropdown.mocha.js | 302 -- .../field_dependent_dropdown_test_block.ts | 130 - .../field-dependent-dropdown/test/index.html | 18 - .../field-dependent-dropdown/test/index.ts | 63 - .../field-dependent-dropdown/tsconfig.json | 16 - plugins/field-grid-dropdown/CHANGELOG.md | 693 ----- plugins/field-grid-dropdown/README.md | 92 - plugins/field-grid-dropdown/package.json | 52 - .../readme-media/dropdown-images.png | Bin 14349 -> 0 bytes .../readme-media/dropdown.png | Bin 8813 -> 0 bytes plugins/field-grid-dropdown/src/grid.ts | 391 --- plugins/field-grid-dropdown/src/grid_item.ts | 198 -- plugins/field-grid-dropdown/src/index.ts | 283 -- .../test/field_test.mocha.js | 218 -- plugins/field-grid-dropdown/test/index.html | 18 - plugins/field-grid-dropdown/test/index.ts | 468 --- plugins/field-grid-dropdown/tsconfig.json | 16 - plugins/field-multilineinput/CHANGELOG.md | 519 ---- plugins/field-multilineinput/README.md | 237 -- plugins/field-multilineinput/package.json | 55 - .../readme-media/collapsed.png | Bin 3564 -> 0 bytes .../readme-media/on_block.png | Bin 7365 -> 0 bytes .../readme-media/spellcheck.gif | Bin 255733 -> 0 bytes .../readme-media/validator.gif | Bin 90957 -> 0 bytes .../readme-media/with_editor.png | Bin 6690 -> 0 bytes .../src/blocks/generatorsType.ts | 24 - .../src/blocks/textMultiline.ts | 169 -- .../src/field_multilineinput.ts | 781 ----- plugins/field-multilineinput/src/index.ts | 16 - .../test/block_test.mocha.js | 94 - .../test/field_multilineinput_test.mocha.js | 300 -- .../test/golden/golden.dart | 4 - .../test/golden/golden.js | 2 - .../test/golden/golden.lua | 2 - .../test/golden/golden.php | 2 - .../test/golden/golden.py | 2 - plugins/field-multilineinput/test/index.html | 18 - plugins/field-multilineinput/test/index.ts | 242 -- plugins/field-multilineinput/tsconfig.json | 16 - plugins/field-slider/CHANGELOG.md | 692 ----- plugins/field-slider/README.md | 59 - plugins/field-slider/package.json | 54 - plugins/field-slider/src/field_slider.ts | 326 --- plugins/field-slider/src/index.ts | 7 - .../test/field_slider_test.mocha.js | 404 --- .../test/field_slider_test_helpers.mocha.js | 42 - plugins/field-slider/test/index.html | 18 - plugins/field-slider/test/index.ts | 274 -- plugins/field-slider/tsconfig.json | 16 - plugins/fixed-edges/CHANGELOG.md | 663 ----- plugins/fixed-edges/README.md | 48 - plugins/fixed-edges/package.json | 50 - plugins/fixed-edges/src/index.js | 123 - plugins/fixed-edges/test/index.html | 18 - plugins/fixed-edges/test/index.js | 42 - plugins/jsconfig.json | 9 - plugins/migration/CHANGELOG.md | 284 -- plugins/migration/README.md | 21 - plugins/migration/bin/command.js | 139 - plugins/migration/bin/fix-imports.js | 268 -- plugins/migration/bin/migrate.js | 18 - plugins/migration/bin/rename.js | 258 -- plugins/migration/bin/versions.js | 76 - plugins/migration/package.json | 44 - .../manual-test-data/fix-imports/import.js | 35 - .../manual-test-data/fix-imports/mixed-1.js | 35 - .../manual-test-data/fix-imports/mixed-2.js | 35 - .../manual-test-data/fix-imports/require.js | 35 - .../migration/test/manual-test-data/rename.js | 28 - plugins/migration/test/rename.mocha.js | 1057 ------- plugins/migration/test/versions.mocha.js | 108 - plugins/modal/CHANGELOG.md | 663 ----- plugins/modal/README.md | 53 - plugins/modal/package.json | 55 - plugins/modal/src/index.js | 392 --- plugins/modal/test/index.html | 18 - plugins/modal/test/index.js | 40 - plugins/modal/test/modal_test.mocha.js | 109 - plugins/scroll-options/CHANGELOG.md | 722 ----- plugins/scroll-options/README.md | 171 -- plugins/scroll-options/package.json | 52 - plugins/scroll-options/src/AutoScroll.ts | 158 - plugins/scroll-options/src/AutoScrollable.ts | 31 - .../scroll-options/src/ScrollBlockDragger.ts | 515 ---- .../src/ScrollMetricsManager.ts | 66 - plugins/scroll-options/src/index.ts | 227 -- plugins/scroll-options/src/utils.ts | 29 - plugins/scroll-options/test/index.html | 18 - plugins/scroll-options/test/index.ts | 60 - plugins/scroll-options/tsconfig.json | 16 - plugins/shadow-block-converter/CHANGELOG.md | 651 ----- plugins/shadow-block-converter/README.md | 55 - plugins/shadow-block-converter/package.json | 56 - plugins/shadow-block-converter/src/index.ts | 7 - .../src/shadow_block_converter.ts | 371 --- .../shadow-block-converter/test/index.html | 18 - plugins/shadow-block-converter/test/index.ts | 126 - .../test/shadow_block_converter_test.mocha.js | 258 -- plugins/shadow-block-converter/tsconfig.json | 16 - .../strict-connection-checker/CHANGELOG.md | 668 ----- plugins/strict-connection-checker/README.md | 46 - .../strict-connection-checker/package.json | 53 - .../strict-connection-checker/src/index.js | 66 - .../src/toolboxCategories.js | 654 ----- .../test/checker_test.mocha.js | 349 --- .../strict-connection-checker/test/index.html | 18 - .../strict-connection-checker/test/index.js | 38 - plugins/suggested-blocks/CHANGELOG.md | 623 ---- plugins/suggested-blocks/README.md | 80 - plugins/suggested-blocks/package.json | 54 - plugins/suggested-blocks/src/index.js | 249 -- plugins/suggested-blocks/test/index.html | 18 - plugins/suggested-blocks/test/index.js | 71 - .../test/suggested_blocks.mocha.js | 243 -- plugins/theme-dark/CHANGELOG.md | 469 --- plugins/theme-dark/README.md | 34 - plugins/theme-dark/package.json | 51 - plugins/theme-dark/readme-media/DarkTheme.png | Bin 162384 -> 0 bytes plugins/theme-dark/src/index.ts | 32 - plugins/theme-dark/test/index.html | 26 - plugins/theme-dark/test/index.js | 807 ----- plugins/theme-dark/tsconfig.json | 16 - plugins/theme-deuteranopia/CHANGELOG.md | 473 --- plugins/theme-deuteranopia/README.md | 36 - plugins/theme-deuteranopia/package.json | 51 - .../readme-media/DeuteranopiaTheme.png | Bin 227114 -> 0 bytes plugins/theme-deuteranopia/src/index.ts | 107 - plugins/theme-deuteranopia/test/index.html | 26 - plugins/theme-deuteranopia/test/index.js | 807 ----- plugins/theme-deuteranopia/tsconfig.json | 16 - plugins/theme-hackermode/.npmignore | 24 - plugins/theme-hackermode/CHANGELOG.md | 8 - plugins/theme-hackermode/README.md | 32 - plugins/theme-hackermode/package.json | 52 - plugins/theme-hackermode/src/index.ts | 118 - plugins/theme-hackermode/test/index.html | 18 - plugins/theme-hackermode/test/index.js | 36 - plugins/theme-hackermode/tsconfig.json | 16 - plugins/theme-highcontrast/CHANGELOG.md | 464 --- plugins/theme-highcontrast/README.md | 35 - plugins/theme-highcontrast/package.json | 51 - .../readme-media/HighContrastTheme.png | Bin 243948 -> 0 bytes plugins/theme-highcontrast/src/index.ts | 100 - plugins/theme-highcontrast/test/index.html | 26 - plugins/theme-highcontrast/test/index.js | 807 ----- plugins/theme-highcontrast/tsconfig.json | 16 - plugins/theme-modern/CHANGELOG.md | 472 --- plugins/theme-modern/README.md | 37 - plugins/theme-modern/package.json | 51 - .../theme-modern/readme-media/ModernTheme.png | Bin 228532 -> 0 bytes plugins/theme-modern/src/index.ts | 103 - plugins/theme-modern/test/index.html | 26 - plugins/theme-modern/test/index.js | 807 ----- plugins/theme-modern/tsconfig.json | 16 - plugins/theme-tritanopia/CHANGELOG.md | 472 --- plugins/theme-tritanopia/README.md | 35 - plugins/theme-tritanopia/package.json | 51 - .../readme-media/TritanopiaTheme.png | Bin 231545 -> 0 bytes plugins/theme-tritanopia/src/index.ts | 105 - plugins/theme-tritanopia/test/index.html | 26 - plugins/theme-tritanopia/test/index.js | 807 ----- plugins/theme-tritanopia/tsconfig.json | 16 - plugins/toolbox-search/.npmignore | 24 - plugins/toolbox-search/CHANGELOG.md | 465 --- plugins/toolbox-search/README.md | 46 - plugins/toolbox-search/package.json | 54 - plugins/toolbox-search/src/block_searcher.ts | 136 - plugins/toolbox-search/src/index.ts | 2 - plugins/toolbox-search/src/toolbox_search.ts | 226 -- plugins/toolbox-search/test/index.html | 18 - plugins/toolbox-search/test/index.ts | 46 - plugins/toolbox-search/test/tests.mocha.js | 219 -- plugins/toolbox-search/tsconfig.json | 17 - plugins/typed-variable-modal/CHANGELOG.md | 676 ----- plugins/typed-variable-modal/README.md | 117 - plugins/typed-variable-modal/package.json | 58 - .../src/TypedVariableModal.js | 391 --- plugins/typed-variable-modal/src/index.js | 7 - .../typed-variable-modal/test/InputModal.js | 65 - plugins/typed-variable-modal/test/index.html | 11 - plugins/typed-variable-modal/test/index.js | 77 - .../test/typed_variable_modal_test.mocha.js | 253 -- plugins/workspace-backpack/CHANGELOG.md | 730 ----- plugins/workspace-backpack/README.md | 201 -- plugins/workspace-backpack/media/backpack.svg | 1 - .../media/filled_backpack.svg | 67 - plugins/workspace-backpack/package.json | 53 - .../context-menu-precondition.gif | Bin 153316 -> 0 bytes .../readme-media/context-menu.gif | Bin 1306066 -> 0 bytes plugins/workspace-backpack/src/backpack.ts | 1151 -------- .../src/backpack_helpers.ts | 219 -- .../workspace-backpack/src/backpackable.ts | 28 - plugins/workspace-backpack/src/index.ts | 9 - plugins/workspace-backpack/src/options.ts | 67 - plugins/workspace-backpack/src/ui_events.ts | 103 - plugins/workspace-backpack/test/index.html | 18 - plugins/workspace-backpack/test/index.ts | 39 - plugins/workspace-backpack/tsconfig.json | 16 - plugins/workspace-minimap/CHANGELOG.md | 456 --- plugins/workspace-minimap/README.md | 120 - plugins/workspace-minimap/package.json | 53 - .../readme-media/sample_minimap.png | Bin 47071 -> 0 bytes plugins/workspace-minimap/src/focus_region.ts | 217 -- plugins/workspace-minimap/src/index.ts | 13 - plugins/workspace-minimap/src/minimap.ts | 460 --- .../src/positioned_minimap.ts | 205 -- plugins/workspace-minimap/test/index.html | 18 - plugins/workspace-minimap/test/index.ts | 48 - .../test/minimap_tests.mocha.js | 618 ---- plugins/workspace-minimap/tsconfig.json | 18 - plugins/workspace-search/CHANGELOG.md | 712 ----- plugins/workspace-search/README.md | 88 - plugins/workspace-search/media/close.svg | 1 - .../media/keyboard_arrow_down.svg | 1 - .../media/keyboard_arrow_up.svg | 1 - plugins/workspace-search/package.json | 55 - plugins/workspace-search/src/css.ts | 104 - plugins/workspace-search/src/index.ts | 7 - .../workspace-search/src/workspace_search.ts | 647 ----- plugins/workspace-search/test/.mocharc.js | 6 - plugins/workspace-search/test/index.html | 12 - plugins/workspace-search/test/index.ts | 44 - .../test/workspace_search_test.mocha.js | 531 ---- plugins/workspace-search/tsconfig.json | 16 - plugins/zoom-to-fit/CHANGELOG.md | 683 ----- plugins/zoom-to-fit/README.md | 46 - plugins/zoom-to-fit/media/zoom_reset.svg | 1 - plugins/zoom-to-fit/package.json | 51 - plugins/zoom-to-fit/src/index.ts | 327 --- plugins/zoom-to-fit/test/index.html | 18 - plugins/zoom-to-fit/test/index.ts | 48 - plugins/zoom-to-fit/tsconfig.json | 16 - 553 files changed, 89096 deletions(-) delete mode 100644 plugins/.eslintignore delete mode 100644 plugins/.gitignore delete mode 100644 plugins/README.md delete mode 100644 plugins/block-dynamic-connection/CHANGELOG.md delete mode 100644 plugins/block-dynamic-connection/GETSTARTED.md delete mode 100644 plugins/block-dynamic-connection/README.md delete mode 100644 plugins/block-dynamic-connection/package.json delete mode 100644 plugins/block-dynamic-connection/src/connection_previewer.ts delete mode 100644 plugins/block-dynamic-connection/src/dynamic_if.ts delete mode 100644 plugins/block-dynamic-connection/src/dynamic_list_create.ts delete mode 100644 plugins/block-dynamic-connection/src/dynamic_text_join.ts delete mode 100644 plugins/block-dynamic-connection/src/index.ts delete mode 100644 plugins/block-dynamic-connection/test/dynamic_if.mocha.js delete mode 100644 plugins/block-dynamic-connection/test/dynamic_list_create.mocha.js delete mode 100644 plugins/block-dynamic-connection/test/dynamic_text_join.mocha.js delete mode 100644 plugins/block-dynamic-connection/test/index.html delete mode 100644 plugins/block-dynamic-connection/test/index.ts delete mode 100644 plugins/block-dynamic-connection/tsconfig.json delete mode 100644 plugins/block-plus-minus/CHANGELOG.md delete mode 100644 plugins/block-plus-minus/README.md delete mode 100644 plugins/block-plus-minus/package.json delete mode 100644 plugins/block-plus-minus/readme-media/AllBlocks.png delete mode 100644 plugins/block-plus-minus/readme-media/If.png delete mode 100644 plugins/block-plus-minus/readme-media/IfElseIf.png delete mode 100644 plugins/block-plus-minus/readme-media/IfElseIfElse.png delete mode 100644 plugins/block-plus-minus/readme-media/ListCreateWith.png delete mode 100644 plugins/block-plus-minus/readme-media/ListCreateWithNone.png delete mode 100644 plugins/block-plus-minus/readme-media/TextJoin.png delete mode 100644 plugins/block-plus-minus/readme-media/TextJoinNone.png delete mode 100644 plugins/block-plus-minus/src/field_minus.js delete mode 100644 plugins/block-plus-minus/src/field_plus.js delete mode 100644 plugins/block-plus-minus/src/if.js delete mode 100644 plugins/block-plus-minus/src/index.js delete mode 100644 plugins/block-plus-minus/src/list_create.js delete mode 100644 plugins/block-plus-minus/src/procedures.js delete mode 100644 plugins/block-plus-minus/src/serialization_helper.js delete mode 100644 plugins/block-plus-minus/src/text_join.js delete mode 100644 plugins/block-plus-minus/test/if.mocha.js delete mode 100644 plugins/block-plus-minus/test/index.html delete mode 100644 plugins/block-plus-minus/test/index.js delete mode 100644 plugins/block-plus-minus/test/list_create.mocha.js delete mode 100644 plugins/block-plus-minus/test/procedures.mocha.js delete mode 100644 plugins/block-plus-minus/test/procedures_test_helpers.mocha.js delete mode 100644 plugins/block-plus-minus/test/test_helpers.mocha.js delete mode 100644 plugins/block-plus-minus/test/text_join.mocha.js delete mode 100644 plugins/block-shareable-procedures/CHANGELOG.md delete mode 100644 plugins/block-shareable-procedures/README.md delete mode 100644 plugins/block-shareable-procedures/package.json delete mode 100644 plugins/block-shareable-procedures/src/blocks.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_base.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_change_return.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_create.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_delete.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_enable.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_parameter_base.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_parameter_create.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_parameter_delete.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_parameter_rename.ts delete mode 100644 plugins/block-shareable-procedures/src/events_procedure_rename.ts delete mode 100644 plugins/block-shareable-procedures/src/i_procedure_block.ts delete mode 100644 plugins/block-shareable-procedures/src/index.ts delete mode 100644 plugins/block-shareable-procedures/src/observable_parameter_model.ts delete mode 100644 plugins/block-shareable-procedures/src/observable_procedure_model.ts delete mode 100644 plugins/block-shareable-procedures/src/update_procedures.ts delete mode 100644 plugins/block-shareable-procedures/test/data_models.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_change_return.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_create.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_delete.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_enable.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_parameter_create.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_parameter_delete.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_parameter_rename.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_procedure_rename.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/event_test_helpers.js delete mode 100644 plugins/block-shareable-procedures/test/index.html delete mode 100644 plugins/block-shareable-procedures/test/index.js delete mode 100644 plugins/block-shareable-procedures/test/procedure_blocks.mocha.js delete mode 100644 plugins/block-shareable-procedures/test/procedure_test_helpers.js delete mode 100644 plugins/block-shareable-procedures/tsconfig.json delete mode 100644 plugins/block-test/CHANGELOG.md delete mode 100644 plugins/block-test/README.md delete mode 100644 plugins/block-test/package.json delete mode 100644 plugins/block-test/src/align.js delete mode 100644 plugins/block-test/src/basic.js delete mode 100644 plugins/block-test/src/chameleon.js delete mode 100644 plugins/block-test/src/connections/index.js delete mode 100644 plugins/block-test/src/connections/row.js delete mode 100644 plugins/block-test/src/connections/stack.js delete mode 100644 plugins/block-test/src/connections/statement.js delete mode 100644 plugins/block-test/src/drag.js delete mode 100644 plugins/block-test/src/fields/defaults.js delete mode 100644 plugins/block-test/src/fields/dropdowns.js delete mode 100644 plugins/block-test/src/fields/emojis.js delete mode 100644 plugins/block-test/src/fields/images.js delete mode 100644 plugins/block-test/src/fields/index.js delete mode 100644 plugins/block-test/src/fields/numbers.js delete mode 100644 plugins/block-test/src/fields/validators.js delete mode 100644 plugins/block-test/src/index.js delete mode 100644 plugins/block-test/src/mutators.js delete mode 100644 plugins/block-test/src/serialization/blocks.js delete mode 100644 plugins/block-test/src/serialization/category.js delete mode 100644 plugins/block-test/src/serialization/fields.js delete mode 100644 plugins/block-test/src/style.js delete mode 100644 plugins/block-test/test/index.html delete mode 100644 plugins/block-test/test/index.js delete mode 100644 plugins/content-highlight/CHANGELOG.md delete mode 100644 plugins/content-highlight/README.md delete mode 100644 plugins/content-highlight/package.json delete mode 100644 plugins/content-highlight/readme-media/content-highlight.gif delete mode 100644 plugins/content-highlight/src/index.ts delete mode 100644 plugins/content-highlight/test/index.html delete mode 100644 plugins/content-highlight/test/index.js delete mode 100644 plugins/content-highlight/tsconfig.json delete mode 100644 plugins/continuous-toolbox/CHANGELOG.md delete mode 100644 plugins/continuous-toolbox/GETSTARTED.md delete mode 100644 plugins/continuous-toolbox/README.md delete mode 100644 plugins/continuous-toolbox/package.json delete mode 100644 plugins/continuous-toolbox/screenshot.png delete mode 100644 plugins/continuous-toolbox/src/ContinuousCategory.ts delete mode 100644 plugins/continuous-toolbox/src/ContinuousFlyout.ts delete mode 100644 plugins/continuous-toolbox/src/ContinuousFlyoutMetrics.ts delete mode 100644 plugins/continuous-toolbox/src/ContinuousMetrics.ts delete mode 100644 plugins/continuous-toolbox/src/ContinuousToolbox.ts delete mode 100644 plugins/continuous-toolbox/src/ContinuousToolboxNavigator.ts delete mode 100644 plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts delete mode 100644 plugins/continuous-toolbox/src/index.ts delete mode 100644 plugins/continuous-toolbox/test/index.html delete mode 100644 plugins/continuous-toolbox/test/index.js delete mode 100644 plugins/continuous-toolbox/tsconfig.json delete mode 100644 plugins/cross-tab-copy-paste/CHANGELOG.md delete mode 100644 plugins/cross-tab-copy-paste/GETSTARTED.md delete mode 100644 plugins/cross-tab-copy-paste/README.md delete mode 100644 plugins/cross-tab-copy-paste/package.json delete mode 100644 plugins/cross-tab-copy-paste/src/index.ts delete mode 100644 plugins/cross-tab-copy-paste/test/index.html delete mode 100644 plugins/cross-tab-copy-paste/test/index.ts delete mode 100644 plugins/cross-tab-copy-paste/tsconfig.json delete mode 100644 plugins/dev-create/.gitignore delete mode 100644 plugins/dev-create/CHANGELOG.md delete mode 100644 plugins/dev-create/README.md delete mode 100644 plugins/dev-create/bin/app.js delete mode 100644 plugins/dev-create/bin/common.js delete mode 100755 plugins/dev-create/bin/create.js delete mode 100644 plugins/dev-create/bin/plugin.js delete mode 100644 plugins/dev-create/package.json delete mode 100644 plugins/dev-create/templates/block/README.md delete mode 100644 plugins/dev-create/templates/block/template/src/index.js delete mode 100644 plugins/dev-create/templates/block/template/test/block_test.mocha.js delete mode 100644 plugins/dev-create/templates/block/template/test/index.html delete mode 100644 plugins/dev-create/templates/block/template/test/index.js delete mode 100644 plugins/dev-create/templates/field/README.md delete mode 100644 plugins/dev-create/templates/field/template/src/index.js delete mode 100644 plugins/dev-create/templates/field/template/test/field_test.mocha.js delete mode 100644 plugins/dev-create/templates/field/template/test/index.html delete mode 100644 plugins/dev-create/templates/field/template/test/index.js delete mode 100644 plugins/dev-create/templates/plugin/README.md delete mode 100644 plugins/dev-create/templates/plugin/template/src/index.js delete mode 100644 plugins/dev-create/templates/plugin/template/test/index.html delete mode 100644 plugins/dev-create/templates/plugin/template/test/index.js delete mode 100644 plugins/dev-create/templates/theme/README.md delete mode 100644 plugins/dev-create/templates/theme/template/src/index.js delete mode 100644 plugins/dev-create/templates/theme/template/test/index.html delete mode 100644 plugins/dev-create/templates/theme/template/test/index.js delete mode 100644 plugins/dev-create/templates/third_party/.gitignore delete mode 100644 plugins/dev-create/templates/third_party/GETSTARTED.md delete mode 100644 plugins/dev-create/templates/typescript-block/README.md delete mode 100644 plugins/dev-create/templates/typescript-block/template/src/index.ts delete mode 100644 plugins/dev-create/templates/typescript-block/template/test/index.html delete mode 100644 plugins/dev-create/templates/typescript-block/template/test/index.ts delete mode 100644 plugins/dev-create/templates/typescript-block/template/tsconfig.json delete mode 100644 plugins/dev-create/templates/typescript-field/README.md delete mode 100644 plugins/dev-create/templates/typescript-field/template/src/index.ts delete mode 100644 plugins/dev-create/templates/typescript-field/template/test/index.html delete mode 100644 plugins/dev-create/templates/typescript-field/template/test/index.ts delete mode 100644 plugins/dev-create/templates/typescript-field/template/tsconfig.json delete mode 100644 plugins/dev-create/templates/typescript-plugin/README.md delete mode 100644 plugins/dev-create/templates/typescript-plugin/template/src/index.ts delete mode 100644 plugins/dev-create/templates/typescript-plugin/template/test/index.html delete mode 100644 plugins/dev-create/templates/typescript-plugin/template/test/index.ts delete mode 100644 plugins/dev-create/templates/typescript-plugin/template/tsconfig.json delete mode 100644 plugins/dev-create/templates/typescript-theme/README.md delete mode 100644 plugins/dev-create/templates/typescript-theme/template/src/index.ts delete mode 100644 plugins/dev-create/templates/typescript-theme/template/test/index.html delete mode 100644 plugins/dev-create/templates/typescript-theme/template/test/index.ts delete mode 100644 plugins/dev-create/templates/typescript-theme/template/tsconfig.json delete mode 100644 plugins/dev-scripts/CHANGELOG.md delete mode 100644 plugins/dev-scripts/README.md delete mode 100755 plugins/dev-scripts/bin/blockly-scripts.js delete mode 100644 plugins/dev-scripts/config/webpack.config.js delete mode 100644 plugins/dev-scripts/config/webpackDevServer.config.js delete mode 100644 plugins/dev-scripts/package.json delete mode 100644 plugins/dev-scripts/scripts/auditFix.js delete mode 100644 plugins/dev-scripts/scripts/build.js delete mode 100644 plugins/dev-scripts/scripts/clean.js delete mode 100644 plugins/dev-scripts/scripts/predeploy.js delete mode 100644 plugins/dev-scripts/scripts/start.js delete mode 100644 plugins/dev-scripts/scripts/test.js delete mode 100644 plugins/dev-tools/CHANGELOG.md delete mode 100644 plugins/dev-tools/README.md delete mode 100644 plugins/dev-tools/package.json delete mode 100644 plugins/dev-tools/readme-media/block-bounds-with-children.png delete mode 100644 plugins/dev-tools/readme-media/block-bounds.png delete mode 100644 plugins/dev-tools/readme-media/connection.png delete mode 100644 plugins/dev-tools/readme-media/element-spacer.png delete mode 100644 plugins/dev-tools/readme-media/element.png delete mode 100644 plugins/dev-tools/readme-media/row-spacer.png delete mode 100644 plugins/dev-tools/readme-media/row.png delete mode 100644 plugins/dev-tools/src/block_test_helpers.mocha.js delete mode 100644 plugins/dev-tools/src/common_test_helpers.mocha.js delete mode 100644 plugins/dev-tools/src/debug.js delete mode 100644 plugins/dev-tools/src/debugDrawer.js delete mode 100644 plugins/dev-tools/src/event_test_helpers.mocha.js delete mode 100644 plugins/dev-tools/src/field_test_helpers.mocha.js delete mode 100644 plugins/dev-tools/src/generateFieldTestBlocks.js delete mode 100644 plugins/dev-tools/src/index.d.ts delete mode 100644 plugins/dev-tools/src/index.js delete mode 100644 plugins/dev-tools/src/logger.js delete mode 100644 plugins/dev-tools/src/playground/hash_state.js delete mode 100644 plugins/dev-tools/src/playground/id.js delete mode 100644 plugins/dev-tools/src/playground/index.js delete mode 100644 plugins/dev-tools/src/playground/monaco.js delete mode 100644 plugins/dev-tools/src/playground/options.js delete mode 100644 plugins/dev-tools/src/playground/state.js delete mode 100644 plugins/dev-tools/src/playground/ui.js delete mode 100644 plugins/dev-tools/src/populateRandom.js delete mode 100644 plugins/dev-tools/src/screenshot.js delete mode 100644 plugins/dev-tools/src/spaghetti.js delete mode 100644 plugins/dev-tools/src/test_helpers.mocha.js delete mode 100644 plugins/dev-tools/src/toolboxCategories.js delete mode 100644 plugins/dev-tools/src/toolboxSimple.js delete mode 100644 plugins/dev-tools/test/index.html delete mode 100644 plugins/dev-tools/test/index.js delete mode 100644 plugins/disable-top-blocks/CHANGELOG.md delete mode 100644 plugins/disable-top-blocks/README.md delete mode 100644 plugins/disable-top-blocks/package.json delete mode 100644 plugins/disable-top-blocks/src/index.js delete mode 100644 plugins/disable-top-blocks/test/index.html delete mode 100644 plugins/disable-top-blocks/test/index.js delete mode 100644 plugins/field-angle/CHANGELOG.md delete mode 100644 plugins/field-angle/README.md delete mode 100644 plugins/field-angle/package.json delete mode 100644 plugins/field-angle/readme-media/clockwise_false.gif delete mode 100644 plugins/field-angle/readme-media/clockwise_true.gif delete mode 100644 plugins/field-angle/readme-media/collapsed.png delete mode 100644 plugins/field-angle/readme-media/compass.gif delete mode 100644 plugins/field-angle/readme-media/offset_right.png delete mode 100644 plugins/field-angle/readme-media/offset_top.png delete mode 100644 plugins/field-angle/readme-media/on_block.png delete mode 100644 plugins/field-angle/readme-media/protractor.gif delete mode 100644 plugins/field-angle/readme-media/round_70.gif delete mode 100644 plugins/field-angle/readme-media/validator.gif delete mode 100644 plugins/field-angle/readme-media/with_editor.png delete mode 100644 plugins/field-angle/readme-media/wrap.gif delete mode 100644 plugins/field-angle/src/field_angle.ts delete mode 100644 plugins/field-angle/src/index.ts delete mode 100644 plugins/field-angle/test/field_angle_test.mocha.js delete mode 100644 plugins/field-angle/test/index.html delete mode 100644 plugins/field-angle/test/index.ts delete mode 100644 plugins/field-angle/tsconfig.json delete mode 100644 plugins/field-bitmap/CHANGELOG.md delete mode 100644 plugins/field-bitmap/README.md delete mode 100644 plugins/field-bitmap/package.json delete mode 100644 plugins/field-bitmap/src/field-bitmap.ts delete mode 100644 plugins/field-bitmap/src/index.ts delete mode 100644 plugins/field-bitmap/test/field_test.mocha.js delete mode 100644 plugins/field-bitmap/test/index.html delete mode 100644 plugins/field-bitmap/test/index.js delete mode 100644 plugins/field-bitmap/tsconfig.json delete mode 100644 plugins/field-colour-hsv-sliders/CHANGELOG.md delete mode 100644 plugins/field-colour-hsv-sliders/README.md delete mode 100644 plugins/field-colour-hsv-sliders/package.json delete mode 100644 plugins/field-colour-hsv-sliders/readme-media/hsv_sliders_screenshot.png delete mode 100644 plugins/field-colour-hsv-sliders/src/field_colour_hsv_sliders.ts delete mode 100644 plugins/field-colour-hsv-sliders/src/index.ts delete mode 100644 plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test.mocha.js delete mode 100644 plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test_helpers.mocha.js delete mode 100644 plugins/field-colour-hsv-sliders/test/index.html delete mode 100644 plugins/field-colour-hsv-sliders/test/index.ts delete mode 100644 plugins/field-colour-hsv-sliders/tsconfig.json delete mode 100644 plugins/field-colour/CHANGELOG.md delete mode 100644 plugins/field-colour/README.md delete mode 100644 plugins/field-colour/package.json delete mode 100644 plugins/field-colour/readme-media/collapsed.png delete mode 100644 plugins/field-colour/readme-media/customized.png delete mode 100644 plugins/field-colour/readme-media/on_block.png delete mode 100644 plugins/field-colour/readme-media/validator.gif delete mode 100644 plugins/field-colour/readme-media/with_editor.png delete mode 100644 plugins/field-colour/src/blocks/colourBlend.ts delete mode 100644 plugins/field-colour/src/blocks/colourPicker.ts delete mode 100644 plugins/field-colour/src/blocks/colourRandom.ts delete mode 100644 plugins/field-colour/src/blocks/colourRgb.ts delete mode 100644 plugins/field-colour/src/blocks/generatorsType.ts delete mode 100644 plugins/field-colour/src/field_colour.ts delete mode 100644 plugins/field-colour/src/index.ts delete mode 100644 plugins/field-colour/test/blocks_test.mocha.js delete mode 100644 plugins/field-colour/test/field_colour_test.mocha.js delete mode 100644 plugins/field-colour/test/golden/golden.dart delete mode 100644 plugins/field-colour/test/golden/golden.js delete mode 100644 plugins/field-colour/test/golden/golden.lua delete mode 100644 plugins/field-colour/test/golden/golden.php delete mode 100644 plugins/field-colour/test/golden/golden.py delete mode 100644 plugins/field-colour/test/index.html delete mode 100644 plugins/field-colour/test/index.ts delete mode 100644 plugins/field-colour/tsconfig.json delete mode 100644 plugins/field-date/.gitignore delete mode 100644 plugins/field-date/CHANGELOG.md delete mode 100644 plugins/field-date/README.md delete mode 100644 plugins/field-date/package.json delete mode 100644 plugins/field-date/src/field_date.ts delete mode 100644 plugins/field-date/src/index.ts delete mode 100644 plugins/field-date/src/utils.ts delete mode 100644 plugins/field-date/test/field_date_test.mocha.js delete mode 100644 plugins/field-date/test/index.html delete mode 100644 plugins/field-date/test/index.ts delete mode 100644 plugins/field-date/tsconfig.json delete mode 100644 plugins/field-dependent-dropdown/CHANGELOG.md delete mode 100644 plugins/field-dependent-dropdown/README.md delete mode 100644 plugins/field-dependent-dropdown/package.json delete mode 100644 plugins/field-dependent-dropdown/src/dependent_dropdown_options_change.ts delete mode 100644 plugins/field-dependent-dropdown/src/field_dependent_dropdown.ts delete mode 100644 plugins/field-dependent-dropdown/src/index.ts delete mode 100644 plugins/field-dependent-dropdown/test/field_dependent_dropdown.mocha.js delete mode 100644 plugins/field-dependent-dropdown/test/field_dependent_dropdown_test_block.ts delete mode 100644 plugins/field-dependent-dropdown/test/index.html delete mode 100644 plugins/field-dependent-dropdown/test/index.ts delete mode 100644 plugins/field-dependent-dropdown/tsconfig.json delete mode 100644 plugins/field-grid-dropdown/CHANGELOG.md delete mode 100644 plugins/field-grid-dropdown/README.md delete mode 100644 plugins/field-grid-dropdown/package.json delete mode 100644 plugins/field-grid-dropdown/readme-media/dropdown-images.png delete mode 100644 plugins/field-grid-dropdown/readme-media/dropdown.png delete mode 100644 plugins/field-grid-dropdown/src/grid.ts delete mode 100644 plugins/field-grid-dropdown/src/grid_item.ts delete mode 100644 plugins/field-grid-dropdown/src/index.ts delete mode 100644 plugins/field-grid-dropdown/test/field_test.mocha.js delete mode 100644 plugins/field-grid-dropdown/test/index.html delete mode 100644 plugins/field-grid-dropdown/test/index.ts delete mode 100644 plugins/field-grid-dropdown/tsconfig.json delete mode 100644 plugins/field-multilineinput/CHANGELOG.md delete mode 100644 plugins/field-multilineinput/README.md delete mode 100644 plugins/field-multilineinput/package.json delete mode 100644 plugins/field-multilineinput/readme-media/collapsed.png delete mode 100644 plugins/field-multilineinput/readme-media/on_block.png delete mode 100644 plugins/field-multilineinput/readme-media/spellcheck.gif delete mode 100644 plugins/field-multilineinput/readme-media/validator.gif delete mode 100644 plugins/field-multilineinput/readme-media/with_editor.png delete mode 100644 plugins/field-multilineinput/src/blocks/generatorsType.ts delete mode 100644 plugins/field-multilineinput/src/blocks/textMultiline.ts delete mode 100644 plugins/field-multilineinput/src/field_multilineinput.ts delete mode 100644 plugins/field-multilineinput/src/index.ts delete mode 100644 plugins/field-multilineinput/test/block_test.mocha.js delete mode 100644 plugins/field-multilineinput/test/field_multilineinput_test.mocha.js delete mode 100644 plugins/field-multilineinput/test/golden/golden.dart delete mode 100644 plugins/field-multilineinput/test/golden/golden.js delete mode 100644 plugins/field-multilineinput/test/golden/golden.lua delete mode 100644 plugins/field-multilineinput/test/golden/golden.php delete mode 100644 plugins/field-multilineinput/test/golden/golden.py delete mode 100644 plugins/field-multilineinput/test/index.html delete mode 100644 plugins/field-multilineinput/test/index.ts delete mode 100644 plugins/field-multilineinput/tsconfig.json delete mode 100644 plugins/field-slider/CHANGELOG.md delete mode 100644 plugins/field-slider/README.md delete mode 100644 plugins/field-slider/package.json delete mode 100644 plugins/field-slider/src/field_slider.ts delete mode 100644 plugins/field-slider/src/index.ts delete mode 100644 plugins/field-slider/test/field_slider_test.mocha.js delete mode 100644 plugins/field-slider/test/field_slider_test_helpers.mocha.js delete mode 100644 plugins/field-slider/test/index.html delete mode 100644 plugins/field-slider/test/index.ts delete mode 100644 plugins/field-slider/tsconfig.json delete mode 100644 plugins/fixed-edges/CHANGELOG.md delete mode 100644 plugins/fixed-edges/README.md delete mode 100644 plugins/fixed-edges/package.json delete mode 100644 plugins/fixed-edges/src/index.js delete mode 100644 plugins/fixed-edges/test/index.html delete mode 100644 plugins/fixed-edges/test/index.js delete mode 100644 plugins/jsconfig.json delete mode 100644 plugins/migration/CHANGELOG.md delete mode 100644 plugins/migration/README.md delete mode 100644 plugins/migration/bin/command.js delete mode 100644 plugins/migration/bin/fix-imports.js delete mode 100755 plugins/migration/bin/migrate.js delete mode 100644 plugins/migration/bin/rename.js delete mode 100644 plugins/migration/bin/versions.js delete mode 100644 plugins/migration/package.json delete mode 100644 plugins/migration/test/manual-test-data/fix-imports/import.js delete mode 100644 plugins/migration/test/manual-test-data/fix-imports/mixed-1.js delete mode 100644 plugins/migration/test/manual-test-data/fix-imports/mixed-2.js delete mode 100644 plugins/migration/test/manual-test-data/fix-imports/require.js delete mode 100644 plugins/migration/test/manual-test-data/rename.js delete mode 100644 plugins/migration/test/rename.mocha.js delete mode 100644 plugins/migration/test/versions.mocha.js delete mode 100644 plugins/modal/CHANGELOG.md delete mode 100644 plugins/modal/README.md delete mode 100644 plugins/modal/package.json delete mode 100644 plugins/modal/src/index.js delete mode 100644 plugins/modal/test/index.html delete mode 100644 plugins/modal/test/index.js delete mode 100644 plugins/modal/test/modal_test.mocha.js delete mode 100644 plugins/scroll-options/CHANGELOG.md delete mode 100644 plugins/scroll-options/README.md delete mode 100644 plugins/scroll-options/package.json delete mode 100644 plugins/scroll-options/src/AutoScroll.ts delete mode 100644 plugins/scroll-options/src/AutoScrollable.ts delete mode 100644 plugins/scroll-options/src/ScrollBlockDragger.ts delete mode 100644 plugins/scroll-options/src/ScrollMetricsManager.ts delete mode 100644 plugins/scroll-options/src/index.ts delete mode 100644 plugins/scroll-options/src/utils.ts delete mode 100644 plugins/scroll-options/test/index.html delete mode 100644 plugins/scroll-options/test/index.ts delete mode 100644 plugins/scroll-options/tsconfig.json delete mode 100644 plugins/shadow-block-converter/CHANGELOG.md delete mode 100644 plugins/shadow-block-converter/README.md delete mode 100644 plugins/shadow-block-converter/package.json delete mode 100644 plugins/shadow-block-converter/src/index.ts delete mode 100644 plugins/shadow-block-converter/src/shadow_block_converter.ts delete mode 100644 plugins/shadow-block-converter/test/index.html delete mode 100644 plugins/shadow-block-converter/test/index.ts delete mode 100644 plugins/shadow-block-converter/test/shadow_block_converter_test.mocha.js delete mode 100644 plugins/shadow-block-converter/tsconfig.json delete mode 100644 plugins/strict-connection-checker/CHANGELOG.md delete mode 100644 plugins/strict-connection-checker/README.md delete mode 100644 plugins/strict-connection-checker/package.json delete mode 100644 plugins/strict-connection-checker/src/index.js delete mode 100644 plugins/strict-connection-checker/src/toolboxCategories.js delete mode 100644 plugins/strict-connection-checker/test/checker_test.mocha.js delete mode 100644 plugins/strict-connection-checker/test/index.html delete mode 100644 plugins/strict-connection-checker/test/index.js delete mode 100644 plugins/suggested-blocks/CHANGELOG.md delete mode 100644 plugins/suggested-blocks/README.md delete mode 100644 plugins/suggested-blocks/package.json delete mode 100644 plugins/suggested-blocks/src/index.js delete mode 100644 plugins/suggested-blocks/test/index.html delete mode 100644 plugins/suggested-blocks/test/index.js delete mode 100644 plugins/suggested-blocks/test/suggested_blocks.mocha.js delete mode 100644 plugins/theme-dark/CHANGELOG.md delete mode 100644 plugins/theme-dark/README.md delete mode 100644 plugins/theme-dark/package.json delete mode 100644 plugins/theme-dark/readme-media/DarkTheme.png delete mode 100644 plugins/theme-dark/src/index.ts delete mode 100644 plugins/theme-dark/test/index.html delete mode 100644 plugins/theme-dark/test/index.js delete mode 100644 plugins/theme-dark/tsconfig.json delete mode 100644 plugins/theme-deuteranopia/CHANGELOG.md delete mode 100644 plugins/theme-deuteranopia/README.md delete mode 100644 plugins/theme-deuteranopia/package.json delete mode 100644 plugins/theme-deuteranopia/readme-media/DeuteranopiaTheme.png delete mode 100644 plugins/theme-deuteranopia/src/index.ts delete mode 100644 plugins/theme-deuteranopia/test/index.html delete mode 100644 plugins/theme-deuteranopia/test/index.js delete mode 100644 plugins/theme-deuteranopia/tsconfig.json delete mode 100644 plugins/theme-hackermode/.npmignore delete mode 100644 plugins/theme-hackermode/CHANGELOG.md delete mode 100644 plugins/theme-hackermode/README.md delete mode 100644 plugins/theme-hackermode/package.json delete mode 100644 plugins/theme-hackermode/src/index.ts delete mode 100644 plugins/theme-hackermode/test/index.html delete mode 100644 plugins/theme-hackermode/test/index.js delete mode 100644 plugins/theme-hackermode/tsconfig.json delete mode 100644 plugins/theme-highcontrast/CHANGELOG.md delete mode 100644 plugins/theme-highcontrast/README.md delete mode 100644 plugins/theme-highcontrast/package.json delete mode 100644 plugins/theme-highcontrast/readme-media/HighContrastTheme.png delete mode 100644 plugins/theme-highcontrast/src/index.ts delete mode 100644 plugins/theme-highcontrast/test/index.html delete mode 100644 plugins/theme-highcontrast/test/index.js delete mode 100644 plugins/theme-highcontrast/tsconfig.json delete mode 100644 plugins/theme-modern/CHANGELOG.md delete mode 100644 plugins/theme-modern/README.md delete mode 100644 plugins/theme-modern/package.json delete mode 100644 plugins/theme-modern/readme-media/ModernTheme.png delete mode 100644 plugins/theme-modern/src/index.ts delete mode 100644 plugins/theme-modern/test/index.html delete mode 100644 plugins/theme-modern/test/index.js delete mode 100644 plugins/theme-modern/tsconfig.json delete mode 100644 plugins/theme-tritanopia/CHANGELOG.md delete mode 100644 plugins/theme-tritanopia/README.md delete mode 100644 plugins/theme-tritanopia/package.json delete mode 100644 plugins/theme-tritanopia/readme-media/TritanopiaTheme.png delete mode 100644 plugins/theme-tritanopia/src/index.ts delete mode 100644 plugins/theme-tritanopia/test/index.html delete mode 100644 plugins/theme-tritanopia/test/index.js delete mode 100644 plugins/theme-tritanopia/tsconfig.json delete mode 100644 plugins/toolbox-search/.npmignore delete mode 100644 plugins/toolbox-search/CHANGELOG.md delete mode 100644 plugins/toolbox-search/README.md delete mode 100644 plugins/toolbox-search/package.json delete mode 100644 plugins/toolbox-search/src/block_searcher.ts delete mode 100644 plugins/toolbox-search/src/index.ts delete mode 100644 plugins/toolbox-search/src/toolbox_search.ts delete mode 100644 plugins/toolbox-search/test/index.html delete mode 100644 plugins/toolbox-search/test/index.ts delete mode 100644 plugins/toolbox-search/test/tests.mocha.js delete mode 100644 plugins/toolbox-search/tsconfig.json delete mode 100644 plugins/typed-variable-modal/CHANGELOG.md delete mode 100644 plugins/typed-variable-modal/README.md delete mode 100644 plugins/typed-variable-modal/package.json delete mode 100644 plugins/typed-variable-modal/src/TypedVariableModal.js delete mode 100644 plugins/typed-variable-modal/src/index.js delete mode 100644 plugins/typed-variable-modal/test/InputModal.js delete mode 100644 plugins/typed-variable-modal/test/index.html delete mode 100644 plugins/typed-variable-modal/test/index.js delete mode 100644 plugins/typed-variable-modal/test/typed_variable_modal_test.mocha.js delete mode 100644 plugins/workspace-backpack/CHANGELOG.md delete mode 100644 plugins/workspace-backpack/README.md delete mode 100644 plugins/workspace-backpack/media/backpack.svg delete mode 100644 plugins/workspace-backpack/media/filled_backpack.svg delete mode 100644 plugins/workspace-backpack/package.json delete mode 100644 plugins/workspace-backpack/readme-media/context-menu-precondition.gif delete mode 100644 plugins/workspace-backpack/readme-media/context-menu.gif delete mode 100644 plugins/workspace-backpack/src/backpack.ts delete mode 100644 plugins/workspace-backpack/src/backpack_helpers.ts delete mode 100644 plugins/workspace-backpack/src/backpackable.ts delete mode 100644 plugins/workspace-backpack/src/index.ts delete mode 100644 plugins/workspace-backpack/src/options.ts delete mode 100644 plugins/workspace-backpack/src/ui_events.ts delete mode 100644 plugins/workspace-backpack/test/index.html delete mode 100644 plugins/workspace-backpack/test/index.ts delete mode 100644 plugins/workspace-backpack/tsconfig.json delete mode 100644 plugins/workspace-minimap/CHANGELOG.md delete mode 100644 plugins/workspace-minimap/README.md delete mode 100644 plugins/workspace-minimap/package.json delete mode 100644 plugins/workspace-minimap/readme-media/sample_minimap.png delete mode 100644 plugins/workspace-minimap/src/focus_region.ts delete mode 100644 plugins/workspace-minimap/src/index.ts delete mode 100644 plugins/workspace-minimap/src/minimap.ts delete mode 100644 plugins/workspace-minimap/src/positioned_minimap.ts delete mode 100644 plugins/workspace-minimap/test/index.html delete mode 100644 plugins/workspace-minimap/test/index.ts delete mode 100644 plugins/workspace-minimap/test/minimap_tests.mocha.js delete mode 100644 plugins/workspace-minimap/tsconfig.json delete mode 100644 plugins/workspace-search/CHANGELOG.md delete mode 100644 plugins/workspace-search/README.md delete mode 100644 plugins/workspace-search/media/close.svg delete mode 100644 plugins/workspace-search/media/keyboard_arrow_down.svg delete mode 100644 plugins/workspace-search/media/keyboard_arrow_up.svg delete mode 100644 plugins/workspace-search/package.json delete mode 100644 plugins/workspace-search/src/css.ts delete mode 100644 plugins/workspace-search/src/index.ts delete mode 100644 plugins/workspace-search/src/workspace_search.ts delete mode 100644 plugins/workspace-search/test/.mocharc.js delete mode 100644 plugins/workspace-search/test/index.html delete mode 100644 plugins/workspace-search/test/index.ts delete mode 100644 plugins/workspace-search/test/workspace_search_test.mocha.js delete mode 100644 plugins/workspace-search/tsconfig.json delete mode 100644 plugins/zoom-to-fit/CHANGELOG.md delete mode 100644 plugins/zoom-to-fit/README.md delete mode 100644 plugins/zoom-to-fit/media/zoom_reset.svg delete mode 100644 plugins/zoom-to-fit/package.json delete mode 100644 plugins/zoom-to-fit/src/index.ts delete mode 100644 plugins/zoom-to-fit/test/index.html delete mode 100644 plugins/zoom-to-fit/test/index.ts delete mode 100644 plugins/zoom-to-fit/tsconfig.json diff --git a/plugins/.eslintignore b/plugins/.eslintignore deleted file mode 100644 index 63520da7d..000000000 --- a/plugins/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -build diff --git a/plugins/.gitignore b/plugins/.gitignore deleted file mode 100644 index 40b878db5..000000000 --- a/plugins/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ \ No newline at end of file diff --git a/plugins/README.md b/plugins/README.md deleted file mode 100644 index 7032f1705..000000000 --- a/plugins/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# @blockly Plugins - -This directory is where [Blockly](http://github.com/RaspberryPiFoundation/blockly) plugins are -authored and stored. These plugin packages are released to npm under the -`@blockly` scope. - -A full list of published packages can be found by searching for the `@blockly` -tag on [npm](https://www.npmjs.com/search?q=%40blockly). - -## Plugins - -### Fields - -- [`@blockly/field-bitmap`](field-bitmap/): A Blockly field that allows for - user-inputted pixel grids. -- [`@blockly/field-colour-hsv-sliders`](field-colour-hsv-sliders/): A colour - picker field that uses HSV sliders. -- [`@blockly/field-date`](field-date/): A date picker field that uses the - Google Closure date picker. -- [`@blockly/field-dependent-dropdown`](field-dependent-dropdown/): A dropdown - field where the available options depend on the value of a parent field. -- [`@blockly/field-grid-dropdown`](field-grid-dropdown/): A Blockly dropdown - field with grid layout. -- [`@blockly/field-slider`](field-slider/): A slider field. - -### Blocks - -- [`@blockly/block-plus-minus`](block-plus-minus/): A group of blocks that - replace the built-in mutator UI with a +/- based UI. -- [`@blockly/block-dynamic-connection`](block-dynamic-connection/): A group of - blocks that add connections dynamically. -- [`@blockly-block-shareable-procedures`](block-shareable-procedures): A group - of blocks that replace the built-in procedures with ones that can be shared - between workspaces. -- [`@blockly/block-test`](block-test/): A group of Blockly test blocks. -- [`@blockly/renderer-inline-row-separators`](renderer-inline-row-separators/): - A renderer that allows putting inline value input connectors on separate rows, - and blocks that demonstrate the feature. - -### Dev - -- [`@blockly/create-package`](dev-create/): A tool for creating a Blockly - plugin based on a pre-existing template. -- [`@blockly/migrate`](migration/): A tool for migrating apps built on Blockly - to newer versions of Blockly that make breaking changes. -- [`@blockly/dev-tool`](dev-tools/): A library of common utilities for Blockly - plugin development. -- [`@blockly/dev-scripts`](dev-scripts/): Configuration and scripts for Blockly - plugins. - -### Themes - -- [`@blockly/theme-modern`](theme-modern/): A Blockly modern theme. -- [`@blockly/theme-dark`](theme-dark/): A Blockly dark theme. -- [`@blockly/theme-highcontrast`](theme-highcontrast/): A Blockly high - contrast theme. -- [`@blockly/theme-deuteranopia`](theme-deuteranopia/): A Blockly theme for - people who have deuteranopia. -- [`@blockly/theme-tritanopia`](theme-tritanopia/): A Blockly theme for people - who have tritanopia. - -### Workspace - -- [`@blockly/continuous-toolbox`](continuous-toolbox/): A Blockly plugin - that adds a continous-scrolling style toolbox and flyout. -- [`@blockly/workspace-content-highlight`](content-highlight/): A Blockly - plugin that highlights the content on the workspace. -- [`@blockly/disable-top-blocks`](disable-top-blocks/): A Blockly plugin that - shows the 'disable' context menu option only on non-orphan blocks. -- [`@blockly/fixed-edges`](fixed-edges/): A Blockly MetricsManager for - configuring fixed sides. -- [`@blockly/keyboard-navigation`](keyboard-navigation/): A Blockly plugin - that adds keyboard navigation support. -- [`@blockly/plugin-strict-connection-checker`](strict-connection-checker/): A - Blockly plugin that makes connection checks strict. -- [`@blockly/plugin-workspace-search`](workspace-search/): A plugin that adds - workspace search support. -- [`@blockly/zoom-to-fit`](zoom-to-fit/): A Blockly plugin that adds a - zoom-to-fit control to the workspace. -- [`@blockly/plugin-scroll-options`](scroll-options/): A Blockly plugin that - adds additional scrolling features. -- [`@blockly/plugin-cross-tab-copy-paste`](cross-tab-copy-paste/): A Blockly plugin - that allows a user to copy and paste blocks between tabs. -- [`@blockly/shadow-block-converter`](shadow-block-converter/): A Blockly plugin - that automatically converts shadow blocks to real blocks when the user edits them. -- [`@blockly/workspace-backpack`](workspace-backpack/): A Blockly plugin that - adds Backpack support. -- [`@blockly/workspace-minimap`](workspace-minimap/): A Blockly plugin that - adds a minimap of the workspace to the workspace. (private; in development) - -### Serializers - -- [`@blockly/serialize-disabled-interactions`](serialize-disabled-interactions/): A serializer that serializes movable, deltable, and editable attributes. - -### Toolbox - -- [`@blockly/toolbox-search`](toolbox-search/): A toolbox category that provides a - search field to filter the available blocks in the toolbox. - -### Other - -- [`@blockly/plugin-modal`](modal/): A Blockly plugin that creates a modal. -- [`@blockly/plugin-typed-variable-modal`](typed-variable-modal/): A plugin to - create a modal for creating typed variables. - -## Using Lerna - -[Lerna](https://lerna.js.org/) is being used to manage all the packages released -under the `@blockly` npm scope. - -Run `npm install` at the root of blockly-samples, rather than from each individual -plugin subdirectory. You can also run other commands such as `npm run format` that -will act on all plugins simultaneously. diff --git a/plugins/block-dynamic-connection/CHANGELOG.md b/plugins/block-dynamic-connection/CHANGELOG.md deleted file mode 100644 index 5f2dc61b0..000000000 --- a/plugins/block-dynamic-connection/CHANGELOG.md +++ /dev/null @@ -1,720 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -### Bug Fixes - -* **block-dynamic-connection:** recache connection pairs after dynamically adding new ones - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Fix the tests for block-dynamic-connection ([#2705](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2705)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [0.8.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.8...@blockly/block-dynamic-connection@0.8.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.7...@blockly/block-dynamic-connection@0.8.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.6...@blockly/block-dynamic-connection@0.8.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [0.8.6](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.5...@blockly/block-dynamic-connection@0.8.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.5](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.4...@blockly/block-dynamic-connection@0.8.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.4](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.3...@blockly/block-dynamic-connection@0.8.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.2...@blockly/block-dynamic-connection@0.8.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.1...@blockly/block-dynamic-connection@0.8.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.8.0...@blockly/block-dynamic-connection@0.8.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.8.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.16...@blockly/block-dynamic-connection@0.8.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [0.7.16](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.15...@blockly/block-dynamic-connection@0.7.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.15](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.14...@blockly/block-dynamic-connection@0.7.15) (2025-05-15) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.14](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.13...@blockly/block-dynamic-connection@0.7.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.13](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.12...@blockly/block-dynamic-connection@0.7.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.12](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.11...@blockly/block-dynamic-connection@0.7.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.11](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.10...@blockly/block-dynamic-connection@0.7.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.10](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.9...@blockly/block-dynamic-connection@0.7.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [0.7.9](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.8...@blockly/block-dynamic-connection@0.7.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [0.7.8](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.7...@blockly/block-dynamic-connection@0.7.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [0.7.7](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.6...@blockly/block-dynamic-connection@0.7.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.6](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.5...@blockly/block-dynamic-connection@0.7.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.5](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.4...@blockly/block-dynamic-connection@0.7.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.4](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.3...@blockly/block-dynamic-connection@0.7.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [0.7.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.2...@blockly/block-dynamic-connection@0.7.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.1...@blockly/block-dynamic-connection@0.7.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.7.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.7.0...@blockly/block-dynamic-connection@0.7.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [0.7.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.6.5...@blockly/block-dynamic-connection@0.7.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* build for the v11 branch ([#2268](https://github.com/google/blockly-samples/issues/2268)) ([c7a4fc5](https://github.com/google/blockly-samples/commit/c7a4fc5e72c5e8d9e9bc926bbbbadd1eb31792fc)) -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) -* dynamic blocks erroring on workspace dispose ([#2271](https://github.com/google/blockly-samples/issues/2271)) ([ac5086d](https://github.com/google/blockly-samples/commit/ac5086de8439f3e7bfc339189d8000412b0ee7aa)) -* dynamic blocks finalizing connections when children are deleted ([#2192](https://github.com/google/blockly-samples/issues/2192)) ([9a7b924](https://github.com/google/blockly-samples/commit/9a7b9246d71823160e7878f8616d450a09ad7ba1)) -* scroll-options fixes and compatibility with custom draggables ([#2358](https://github.com/google/blockly-samples/issues/2358)) ([2da6080](https://github.com/google/blockly-samples/commit/2da6080e1684edc5fc90cca0ba80c90982b5e4e2)) - - - -## [0.6.5](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.6.4...@blockly/block-dynamic-connection@0.6.5) (2024-05-16) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.6.4](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.6.3...@blockly/block-dynamic-connection@0.6.4) (2024-05-09) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.6.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.6.2...@blockly/block-dynamic-connection@0.6.3) (2024-04-25) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.6.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.6.1...@blockly/block-dynamic-connection@0.6.2) (2024-04-04) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.6.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.6.0...@blockly/block-dynamic-connection@0.6.1) (2024-03-28) - - -### Bug Fixes - -* readme for the dynamic connection previewer ([#2272](https://github.com/google/blockly-samples/issues/2272)) ([dc1d05d](https://github.com/google/blockly-samples/commit/dc1d05d225c52bf3e3a6ccd73bfa710941ea15a2)) - - - -## [0.6.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.7...@blockly/block-dynamic-connection@0.6.0) (2024-02-16) - - -### ⚠ BREAKING CHANGES - -* use new connection previewer in block-dynamic-connection (#2204) - -### Features - -* use new connection previewer in block-dynamic-connection ([#2204](https://github.com/google/blockly-samples/issues/2204)) ([fb17b94](https://github.com/google/blockly-samples/commit/fb17b943ad5ef8f9db58a9f87d7f7e0dd28bf3d5)), closes [#2190](https://github.com/google/blockly-samples/issues/2190) - - - -## [0.5.7](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.6...@blockly/block-dynamic-connection@0.5.7) (2024-02-08) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.5.6](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.5...@blockly/block-dynamic-connection@0.5.6) (2023-12-14) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.5.5](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.4...@blockly/block-dynamic-connection@0.5.5) (2023-12-07) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.5.4](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.3...@blockly/block-dynamic-connection@0.5.4) (2023-11-16) - - -### Bug Fixes - -* resolved 15 ESLint warnings ([#2065](https://github.com/google/blockly-samples/issues/2065)) ([2436337](https://github.com/google/blockly-samples/commit/243633746542bb1518fe2893c0421a5a6f79fd32)) - - - -## [0.5.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.2...@blockly/block-dynamic-connection@0.5.3) (2023-11-09) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.5.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.1...@blockly/block-dynamic-connection@0.5.2) (2023-11-02) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.5.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.5.0...@blockly/block-dynamic-connection@0.5.1) (2023-10-30) - - -### Bug Fixes - -* export types for block-dynamic-connection ([#1948](https://github.com/google/blockly-samples/issues/1948)) ([ffa3797](https://github.com/google/blockly-samples/commit/ffa3797112fa0d560835dd56de2d790933cdbc48)) -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [0.5.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.4.3...@blockly/block-dynamic-connection@0.5.0) (2023-09-28) - - -### ⚠ BREAKING CHANGES - -* changes for v10.2.0 (#1989) - -### release - -* changes for v10.2.0 ([#1989](https://github.com/google/blockly-samples/issues/1989)) ([4d81ea7](https://github.com/google/blockly-samples/commit/4d81ea7254412ef199a270fc740c2f45755a2725)), closes [#1844](https://github.com/google/blockly-samples/issues/1844) [#1845](https://github.com/google/blockly-samples/issues/1845) [#1863](https://github.com/google/blockly-samples/issues/1863) [#1880](https://github.com/google/blockly-samples/issues/1880) [#1885](https://github.com/google/blockly-samples/issues/1885) [#1886](https://github.com/google/blockly-samples/issues/1886) [#1887](https://github.com/google/blockly-samples/issues/1887) [#1888](https://github.com/google/blockly-samples/issues/1888) [#1919](https://github.com/google/blockly-samples/issues/1919) [#1920](https://github.com/google/blockly-samples/issues/1920) [#1983](https://github.com/google/blockly-samples/issues/1983) [#1984](https://github.com/google/blockly-samples/issues/1984) [#1985](https://github.com/google/blockly-samples/issues/1985) [#1991](https://github.com/google/blockly-samples/issues/1991) - - - -## [0.4.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.4.2...@blockly/block-dynamic-connection@0.4.3) (2023-09-21) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.4.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.4.1...@blockly/block-dynamic-connection@0.4.2) (2023-09-14) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.4.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.4.0...@blockly/block-dynamic-connection@0.4.1) (2023-08-17) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.4.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.3.3...@blockly/block-dynamic-connection@0.4.0) (2023-07-24) - - -### ⚠ BREAKING CHANGES - -* update dyanamic connection and test block plugins to blockly v10 (#1812) - -### Bug Fixes - -* update dyanamic connection and test block plugins to blockly v10 ([#1812](https://github.com/google/blockly-samples/issues/1812)) ([37a2a4d](https://github.com/google/blockly-samples/commit/37a2a4d868f9707a055d08f204003bfb54af7d4c)) - - - -## [0.3.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.3.2...@blockly/block-dynamic-connection@0.3.3) (2023-07-20) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.3.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.3.1...@blockly/block-dynamic-connection@0.3.2) (2023-07-13) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.3.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.3.0...@blockly/block-dynamic-connection@0.3.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.3.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.18...@blockly/block-dynamic-connection@0.3.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [0.2.18](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.17...@blockly/block-dynamic-connection@0.2.18) (2023-06-22) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.17](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.16...@blockly/block-dynamic-connection@0.2.17) (2023-05-18) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.16](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.15...@blockly/block-dynamic-connection@0.2.16) (2023-05-11) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.15](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.14...@blockly/block-dynamic-connection@0.2.15) (2023-05-04) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.14](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.13...@blockly/block-dynamic-connection@0.2.14) (2023-04-27) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.13](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.12...@blockly/block-dynamic-connection@0.2.13) (2023-03-23) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.12](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.11...@blockly/block-dynamic-connection@0.2.12) (2023-03-09) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.11](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.10...@blockly/block-dynamic-connection@0.2.11) (2023-03-02) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.10](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.9...@blockly/block-dynamic-connection@0.2.10) (2023-02-23) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.9](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.8...@blockly/block-dynamic-connection@0.2.9) (2023-02-23) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.8](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.7...@blockly/block-dynamic-connection@0.2.8) (2023-02-16) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.7](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.6...@blockly/block-dynamic-connection@0.2.7) (2023-02-09) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.6](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.5...@blockly/block-dynamic-connection@0.2.6) (2023-01-26) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.5](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.4...@blockly/block-dynamic-connection@0.2.5) (2023-01-19) - - -### Bug Fixes - -* block-dynamic-connections insertion marker monkey patch ([#1452](https://github.com/google/blockly-samples/issues/1452)) ([5bf1e79](https://github.com/google/blockly-samples/commit/5bf1e79493de4bc3a7fce4bef6a69b5f4055de7b)) - - - -## [0.2.4](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.3...@blockly/block-dynamic-connection@0.2.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.3](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.2...@blockly/block-dynamic-connection@0.2.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.2](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.1...@blockly/block-dynamic-connection@0.2.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.1](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.2.0...@blockly/block-dynamic-connection@0.2.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## [0.2.0](https://github.com/google/blockly-samples/compare/@blockly/block-dynamic-connection@0.1.36...@blockly/block-dynamic-connection@0.2.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) -* Update block-dynamic-connection to use JSON toolbox ([#1238](https://github.com/google/blockly-samples/issues/1238)) ([#1286](https://github.com/google/blockly-samples/issues/1286)) ([428c81c](https://github.com/google/blockly-samples/commit/428c81cef4bb58ce99128cbb78f1930ad238b6e5)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 0.1.36 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 0.1.35 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 0.1.33 (2022-07-21) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## 0.1.32 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 0.1.31 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 0.1.30 (2022-06-21) - -**Note:** Version bump only for package @blockly/block-dynamic-connection - - - - - -## 0.1.29 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 0.1.28 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/block-dynamic-connection/GETSTARTED.md b/plugins/block-dynamic-connection/GETSTARTED.md deleted file mode 100644 index 99e93c7e9..000000000 --- a/plugins/block-dynamic-connection/GETSTARTED.md +++ /dev/null @@ -1,24 +0,0 @@ -This package was bootstrapped with [@blockly/create-package](https://www.npmjs.com/package/@blockly/create-package). - -## Available Scripts - -In this directory, you can run: - -### `npm start` - -Runs the package in development mode. - -Open [http://localhost:3000/test](http://localhost:3000/test) to view the test -playground in the browser. The page will reload if you make edits. - -### `npm run build` - -Builds the package into the `dist` directory. - -### `npm run lint` - -Runs eslint on the `src` and `test` directories. - -### `npm run clean` - -Deletes the `dist` and `build` directories if they exist. diff --git a/plugins/block-dynamic-connection/README.md b/plugins/block-dynamic-connection/README.md deleted file mode 100644 index 7b23547d2..000000000 --- a/plugins/block-dynamic-connection/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# @blockly/block-dynamic-connection [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A group of [Blockly](https://www.npmjs.com/package/blockly) blocks that -add and remove connections dynamically. - -## Installation - -``` -npm install @blockly/block-dynamic-connection --save -``` - -## Usage - -```js -import * as Blockly from 'blockly'; -import * as BlockDynamicConnection from '@blockly/block-dynamic-connection'; - -const myWorkspace = Blockly.inject({ - // options... - plugins: { - connectionPreviewer: - BlockDynamicConnection.decoratePreviewer( - // Replace with a custom connection previewer, or remove to decorate - // the default one. - Blockly.InsertionMarkerPreviewer, - ), - }, - }; - -// Add the change listener so connections will be finalized on deletion. -workspace.addChangeListener(BlockDynamicConnection.finalizeConnections); -``` - -## API - -- `overrideOldBlockDefinitions`: Replaces the Blockly default blocks with the - dynamic connection blocks. This enables projects to use the dynamic block - plugin without changing existing XML/JSON. - -## Blocks - -- `dynamic_text_join` replaces `text_join` -- `dynamic_list_create` replaces `lists_create_with` -- `dynamic_if` replaces `controls_if` - -## License - -Apache 2.0 diff --git a/plugins/block-dynamic-connection/package.json b/plugins/block-dynamic-connection/package.json deleted file mode 100644 index 85e695a36..000000000 --- a/plugins/block-dynamic-connection/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@blockly/block-dynamic-connection", - "version": "13.2.0", - "description": "A group of blocks that add connections dynamically.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "prepublishOnly": "npm run clean && npm run build", - "predeploy": "npm run build && blockly-scripts predeploy", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "", - "keywords": [ - "blockly", - "blockly-plugin", - "block-dynamic-connection" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/block-dynamic-connection#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/block-dynamic-connection" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "mocha": "^11.7.6", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/block-dynamic-connection/src/connection_previewer.ts b/plugins/block-dynamic-connection/src/connection_previewer.ts deleted file mode 100644 index e359d05df..000000000 --- a/plugins/block-dynamic-connection/src/connection_previewer.ts +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -interface ConnectionPreviewerConstructor { - new (draggedBlock: Blockly.BlockSvg): Blockly.IConnectionPreviewer; -} - -type DynamicBlock = Blockly.BlockSvg & { - onPendingConnection(connection: Blockly.RenderedConnection): void; - finalizeConnections(): void; -}; - -/** - * A type guard that checks if the given block fulfills the DynamicBlock - * interface. - * - * @param block - */ -export function blockIsDynamic(block: Blockly.BlockSvg): block is DynamicBlock { - return ( - (block as DynamicBlock)['onPendingConnection'] !== undefined && - (block as DynamicBlock)['finalizeConnections'] !== undefined - ); -} - -/** - * Returns a connection previewer constructor that decorates the passed - * constructor to add connection previewing. - * - * @param BasePreviewerConstructor The constructor for the base connection - * previewer class being decorated. If not provided, the default - * InsertionMarkerPreviewer will be used. - * @return A decorated connection previewer constructor. - */ -export function decoratePreviewer( - BasePreviewerConstructor?: ConnectionPreviewerConstructor, -): ConnectionPreviewerConstructor { - return class implements Blockly.IConnectionPreviewer { - private basePreviewer: Blockly.IConnectionPreviewer; - - private pendingBlocks: Set = new Set(); - - private draggedBlock: Blockly.BlockSvg; - - constructor(draggedBlock: Blockly.BlockSvg) { - const BaseConstructor = - BasePreviewerConstructor ?? Blockly.InsertionMarkerPreviewer; - this.basePreviewer = new BaseConstructor(draggedBlock); - this.draggedBlock = draggedBlock; - } - - previewReplacement( - draggedConn: Blockly.RenderedConnection, - staticConn: Blockly.RenderedConnection, - replacedBlock: Blockly.BlockSvg, - ): void { - this.previewDynamism(staticConn); - this.basePreviewer.previewReplacement( - draggedConn, - staticConn, - replacedBlock, - ); - } - - previewConnection( - draggedConn: Blockly.RenderedConnection, - staticConn: Blockly.RenderedConnection, - ): void { - this.previewDynamism(staticConn); - this.basePreviewer.previewConnection(draggedConn, staticConn); - } - - hidePreview(): void { - this.basePreviewer.hidePreview(); - } - - dispose(): void { - for (const block of this.pendingBlocks) { - if (block.isDeadOrDying()) return; - block.finalizeConnections(); - } - this.pendingBlocks.clear(); - this.basePreviewer.dispose(); - } - - /** - * If the block is a dynamic block, calls onPendingConnection and - * stores the block to be finalized later. When new inputs are added, - * refreshes the dragged block's connection-pair cache so constrained - * / keyboard moves can see the new connections. - * - * @param conn The block to trigger onPendingConnection on. - */ - private previewDynamism(conn: Blockly.RenderedConnection) { - const block = conn.getSourceBlock(); - if (!blockIsDynamic(block)) { - return; - } - - // During onPendingConnection, dynamic blocks only grow (append inputs); - // they never remove or replace them. So an input-count change is enough - // to detect when the block shape has changed. - const inputCountBefore = block.inputList.length; - block.onPendingConnection(conn); - this.pendingBlocks.add(block); - - if (block.inputList.length === inputCountBefore) { - return; - } - - const strategy = this.draggedBlock.getDragStrategy(); - if (strategy instanceof Blockly.dragging.BlockDragStrategy) { - strategy.cacheAllConnectionPairs(); - } - } - }; -} diff --git a/plugins/block-dynamic-connection/src/dynamic_if.ts b/plugins/block-dynamic-connection/src/dynamic_if.ts deleted file mode 100644 index 0cea6e2ea..000000000 --- a/plugins/block-dynamic-connection/src/dynamic_if.ts +++ /dev/null @@ -1,408 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Defines a version of the if block with dyanmic - * inputs that appear when a block is dragged over inputs on the block. - */ - -import * as Blockly from 'blockly/core'; - -/** Type of a block that has the DYNAMIC_IF_MIXIN. */ -type DynamicIfBlock = Blockly.Block & DynamicIfMixin; -/* eslint-disable @typescript-eslint/no-empty-interface */ -/** This interface avoids a "circular reference" compile error. */ -interface DynamicIfMixin extends DynamicIfMixinType {} -/* eslint-enable @typescript-eslint/no-empty-interface */ -type DynamicIfMixinType = typeof DYNAMIC_IF_MIXIN; - -interface CaseConnectionPair { - ifTarget?: Blockly.Connection | null; - doTarget?: Blockly.Connection | null; -} - -interface CaseInputPair { - ifInput: Blockly.Input; - doInput: Blockly.Input; -} - -/** Extra state for serializing controls_if blocks. */ -interface IfExtraState { - elseIfCount?: number; - hasElse?: boolean; -} - -const DYNAMIC_IF_MIXIN = { - /** - * Minimum number of inputs for this block. - * - * @deprecated This is unused. - */ - minInputs: 1, - - /** Count of else-if cases. */ - elseifCount: 0, - - /** Count of else cases (either 0 or 1). */ - elseCount: 0, - - /** - * Block for if/elseif/else statements. Must have one if input. - * Can have any number of elseif inputs and optionally one else input. - */ - init(this: DynamicIfBlock): void { - this.setHelpUrl(Blockly.Msg['CONTROLS_IF_HELPURL']); - this.setStyle('logic_blocks'); - this.addFirstCase(); - this.setNextStatement(true); - this.setPreviousStatement(true); - this.setTooltip(Blockly.Msg['LISTS_CREATE_WITH_TOOLTIP']); - }, - - /** - * Create XML to represent if/elseif/else inputs. - * - * @returns XML storage element. - */ - mutationToDom(this: DynamicIfBlock): Element | null { - if (!this.isDeadOrDying()) { - // If we call finalizeConnections here without disabling events, we get into - // an event loop. - Blockly.Events.disable(); - this.finalizeConnections(); - if (this instanceof Blockly.BlockSvg) this.initSvg(); - Blockly.Events.enable(); - } - - if (!this.elseifCount && !this.elseCount) return null; - - const container = Blockly.utils.xml.createElement('mutation'); - if (this.elseifCount) { - container.setAttribute('elseif', `${this.elseifCount}`); - } - if (this.elseCount) { - container.setAttribute('else', '1'); - } - return container; - }, - - /** - * Parse XML to restore the inputs. - * - * @param xmlElement XML storage element. - */ - domToMutation(this: DynamicIfBlock, xmlElement: Element): void { - if (xmlElement.getAttribute('inputs')) { - this.deserializeInputs(xmlElement); - } else { - this.deserializeCounts(xmlElement); - } - }, - - /** - * Parses XML based on the 'inputs' attribute (non-standard). - * - * @param xmlElement XML storage element. - */ - deserializeInputs(this: DynamicIfBlock, xmlElement: Element): void { - const inputs = xmlElement.getAttribute('inputs'); - if (inputs) { - const inputNumbers = inputs.split(','); - if (this.getInput('IF0')) { - this.removeInput('IF0'); - } - if (this.getInput('DO0')) { - this.removeInput('DO0'); - } - const first = inputNumbers[0]; - this.appendValueInput('IF' + first) - .setCheck('Boolean') - .appendField(Blockly.Msg['CONTROLS_IF_MSG_IF'], 'if'); - this.appendStatementInput('DO' + first).appendField( - Blockly.Msg['CONTROLS_IF_MSG_THEN'], - ); - - for (let i = 1; i < inputNumbers.length; i++) { - this.appendValueInput('IF' + inputNumbers[i]) - .setCheck('Boolean') - .appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSEIF'], 'elseif'); - this.appendStatementInput('DO' + inputNumbers[i]).appendField( - Blockly.Msg['CONTROLS_IF_MSG_THEN'], - ); - } - } - const hasElse = xmlElement.getAttribute('else'); - if (hasElse == 'true') { - this.addElseInput(); - } - }, - - /** - * Parses XML based on the 'elseif' and 'else' attributes (standard). - * - * @param xmlElement XML storage element. - */ - deserializeCounts(this: DynamicIfBlock, xmlElement: Element): void { - this.elseifCount = - parseInt(xmlElement.getAttribute('elseif') ?? '0', 10) || 0; - this.elseCount = parseInt(xmlElement.getAttribute('else') ?? '0', 10) || 0; - for (let i = 1; i <= this.elseifCount; i++) { - this.insertElseIf(this.inputList.length, i); - } - if (this.elseCount) { - this.addElseInput(); - } - }, - - /** - * Returns the state of this block as a JSON serializable object. - * - * @returns The state of this block, ie the else if count and else state. - */ - saveExtraState: function (this: DynamicIfBlock): IfExtraState | null { - if (!this.isDeadOrDying() && !this.isCorrectlyFormatted()) { - // If we call finalizeConnections here without disabling events, we get into - // an event loop. - Blockly.Events.disable(); - this.finalizeConnections(); - if (this instanceof Blockly.BlockSvg) this.initSvg(); - Blockly.Events.enable(); - } - - if (!this.elseifCount && !this.elseCount) { - return null; - } - const state = Object.create(null); - if (this.elseifCount) { - state['elseIfCount'] = this.elseifCount; - } - if (this.elseCount) { - state['hasElse'] = true; - } - return state; - }, - - /** - * Applies the given state to this block. - * - * @param state The state to apply to this block, ie the else if count - * and else state. - */ - loadExtraState: function ( - this: DynamicIfBlock, - state: IfExtraState | string, - ) { - if (typeof state === 'string') { - this.domToMutation(Blockly.utils.xml.textToDom(state)); - return; - } - - this.elseifCount = state['elseIfCount'] || 0; - this.elseCount = state['hasElse'] ? 1 : 0; - for (let i = 1; i <= this.elseifCount; i++) { - this.insertElseIf(this.inputList.length, i); - } - if (this.elseCount) { - this.addElseInput(); - } - }, - - /** - * Finds the index of a connection. Used to determine where in the block to - * insert new inputs. - * - * @param connection A connection on this block. - * @returns The index of the connection in the this.inputList. - */ - findInputIndexForConnection( - this: DynamicIfBlock, - connection: Blockly.Connection, - ): number | null { - if ( - !connection.targetConnection || - connection.targetBlock()?.isInsertionMarker() - ) { - // This connection is available. - return null; - } - for (let i = 0; i < this.inputList.length; i++) { - const input = this.inputList[i]; - if (input.connection == connection) { - return i; - } - } - return null; - }, - - /** - * Inserts a boolean value input and statement input at the specified index. - * - * @param index Index of the input before which to add new inputs. - * @param id An ID to append to the case statement input names to make them - * unique. - * @returns The added inputs. - */ - insertElseIf( - this: DynamicIfBlock, - index: number, - id: string | number, - ): CaseInputPair { - const ifInput = this.appendValueInput('IF' + id) - .setCheck('Boolean') - .appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSEIF'], 'elseif'); - const doInput = this.appendStatementInput('DO' + id).appendField( - Blockly.Msg['CONTROLS_IF_MSG_THEN'], - ); - this.moveInputBefore('IF' + id, this.inputList[index].name); - this.moveInputBefore('DO' + id, this.inputList[index + 1].name); - return {ifInput, doInput}; - }, - - /** - * Called by a monkey-patched version of InsertionMarkerManager when - * a block is dragged over one of the connections on this block. - * - * @param connection The connection on this block that has a pending - * connection. - */ - onPendingConnection( - this: DynamicIfBlock, - connection: Blockly.Connection, - ): void { - if (connection.type === Blockly.NEXT_STATEMENT && !this.getInput('ELSE')) { - this.addElseInput(); - } - const inputIndex = this.findInputIndexForConnection(connection); - if (inputIndex === null) { - return; - } - const input = this.inputList[inputIndex]; - if (input.name.includes('IF')) { - const nextIfInput = this.inputList[inputIndex + 2]; - if (!nextIfInput || nextIfInput.name == 'ELSE') { - this.insertElseIf(inputIndex + 2, Blockly.utils.idGenerator.genUid()); - } else { - const nextIfConnection = - nextIfInput && - nextIfInput.connection && - nextIfInput.connection.targetConnection; - if ( - nextIfConnection && - !nextIfConnection.getSourceBlock().isInsertionMarker() - ) { - this.insertElseIf(inputIndex + 2, Blockly.utils.idGenerator.genUid()); - } - } - } - }, - - /** - * Called by a monkey-patched version of InsertionMarkerManager when a block - * drag ends if the dragged block had a pending connection with this block. - */ - finalizeConnections(this: DynamicIfBlock): void { - const targetCaseConns = this.collectTargetCaseConns(); - const targetElseConn = this.getInput('ELSE')?.connection?.targetConnection; - - this.tearDownBlock(); - - this.addFirstCase(); - this.addCaseInputs(targetCaseConns); - if (targetElseConn) { - this.addElseInput().connection?.connect(targetElseConn); - } - - this.elseifCount = Math.max(targetCaseConns.length - 1, 0); - this.elseCount = targetElseConn ? 1 : 0; - }, - - /** - * Collects all of the target blocks attached to case inputs. If neither the - * if nor the due input in a case has an attached block, that input is - * skipped. If only one of them has an attached block, the other value in - * the pair is undefined. - * - * @returns A list of target connections attached to case inputs. - */ - collectTargetCaseConns(this: DynamicIfBlock): CaseConnectionPair[] { - const targetConns = []; - for (let i = 0; i < this.inputList.length - 1; i += 2) { - const ifTarget = this.inputList[i].connection?.targetConnection; - const doTarget = this.inputList[i + 1].connection?.targetConnection; - if (!ifTarget && !doTarget) continue; - targetConns.push({ifTarget, doTarget}); - } - return targetConns; - }, - - /** Deletes all inputs on the block so it can be rebuilt. */ - tearDownBlock(this: DynamicIfBlock): void { - for (let i = this.inputList.length - 1; i >= 0; i--) { - this.removeInput(this.inputList[i].name); - } - }, - - /** - * Adds inputs for all of the given target connection pairs (if the input - * doesn't already exist), and connects the target connections to them. - * - * This is essentially rebuilding all of the cases with strictly ascending - * case numbers. - * - * @param targetConns The list of target connections to attach to this block. - */ - addCaseInputs(this: DynamicIfBlock, targetConns: CaseConnectionPair[]): void { - for (let i = 0; i < targetConns.length; i++) { - let ifInput = this.getInput(`IF${i}`); - let doInput = this.getInput(`DO${i}`); - if (!ifInput || !doInput) { - ({ifInput, doInput} = this.insertElseIf(i * 2, i)); - } - - const {ifTarget, doTarget} = targetConns[i]; - if (ifTarget) ifInput.connection?.connect(ifTarget); - if (doTarget) doInput.connection?.connect(doTarget); - } - }, - - /** - * Adds an else input to this block. - * - * @returns The appended input. - */ - addElseInput(this: DynamicIfBlock): Blockly.Input { - return this.appendStatementInput('ELSE').appendField( - Blockly.Msg['CONTROLS_IF_MSG_ELSE'], - ); - }, - - /** - * Adds the first 'IF' and 'DO' inputs and their associated labels to this - * block. - */ - addFirstCase(this: DynamicIfBlock): void { - this.appendValueInput('IF0') - .setCheck('Boolean') - .appendField(Blockly.Msg['CONTROLS_IF_MSG_IF'], 'if'); - this.appendStatementInput('DO0').appendField( - Blockly.Msg['CONTROLS_IF_MSG_THEN'], - ); - }, - - /** - * Returns true if all of the inputs on this block are in order. - * False otherwise. - */ - isCorrectlyFormatted(this: DynamicIfBlock): boolean { - for (let i = 0; i < this.inputList.length - 1; i += 2) { - if (this.inputList[i].name !== `IF${i}`) return false; - if (this.inputList[i + 1].name !== `DO${i}`) return false; - } - return true; - }, -}; - -Blockly.Blocks['dynamic_if'] = DYNAMIC_IF_MIXIN; diff --git a/plugins/block-dynamic-connection/src/dynamic_list_create.ts b/plugins/block-dynamic-connection/src/dynamic_list_create.ts deleted file mode 100644 index ebccdf6bd..000000000 --- a/plugins/block-dynamic-connection/src/dynamic_list_create.ts +++ /dev/null @@ -1,302 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Defines a version of the list_create block with dyanmic - * inputs that appear when a block is dragged over inputs on the block. - */ - -import * as Blockly from 'blockly/core'; - -/** Type of a block that has the DYNAMIC_LIST_CREATE_MIXIN. */ -type DynamicListCreateBlock = Blockly.Block & DynamicListCreateMixin; -/* eslint-disable @typescript-eslint/no-empty-interface */ -/** This interface avoids a "circular reference" compile error. */ -interface DynamicListCreateMixin extends DynamicListCreateMixinType {} -/* eslint-enable @typescript-eslint/no-empty-interface */ -type DynamicListCreateMixinType = typeof DYNAMIC_LIST_CREATE_MIXIN; - -const DYNAMIC_LIST_CREATE_MIXIN = { - /** Minimum number of inputs for this block. */ - minInputs: 2, - - /** Count of item inputs. */ - itemCount: 0, - - /** Block for concatenating any number of strings. */ - init(this: DynamicListCreateBlock): void { - this.itemCount = this.minInputs; - - this.setHelpUrl(Blockly.Msg['LISTS_CREATE_WITH_HELPURL']); - this.setStyle('list_blocks'); - this.addFirstInput(); - for (let i = 1; i < this.minInputs; i++) { - this.appendValueInput(`ADD${i}`); - } - this.setOutput(true, 'Array'); - this.setTooltip(Blockly.Msg['LISTS_CREATE_WITH_TOOLTIP']); - }, - - /** - * Create XML to represent number of text inputs. - * - * @returns XML storage element. - */ - mutationToDom(this: DynamicListCreateBlock): Element { - if (!this.isDeadOrDying()) { - // If we call finalizeConnections here without disabling events, we get into - // an event loop. - Blockly.Events.disable(); - this.finalizeConnections(); - if (this instanceof Blockly.BlockSvg) this.initSvg(); - Blockly.Events.enable(); - } - - const container = Blockly.utils.xml.createElement('mutation'); - container.setAttribute('items', `${this.itemCount}`); - return container; - }, - - /** - * Parse XML to restore the text inputs. - * - * @param xmlElement XML storage element. - */ - domToMutation(this: DynamicListCreateBlock, xmlElement: Element): void { - if (xmlElement.getAttribute('inputs')) { - this.deserializeInputs(xmlElement); - } else { - this.deserializeCounts(xmlElement); - } - }, - - /** - * Parses XML based on the 'inputs' attribute (non-standard). - * - * @param xmlElement XML storage element. - */ - deserializeInputs(this: DynamicListCreateBlock, xmlElement: Element): void { - const items = xmlElement.getAttribute('inputs'); - if (items) { - const inputNames = items.split(','); - this.inputList = []; - inputNames.forEach((name) => this.appendValueInput(name)); - this.inputList[0].appendField( - Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH'], - ); - } - }, - - /** - * Parses XML based on the 'items' attribute (standard). - * - * @param xmlElement XML storage element. - */ - deserializeCounts(this: DynamicListCreateBlock, xmlElement: Element): void { - this.itemCount = Math.max( - parseInt(xmlElement.getAttribute('items') ?? '0', 10), - this.minInputs, - ); - // minInputs are added automatically. - for (let i = this.minInputs; i < this.itemCount; i++) { - this.appendValueInput('ADD' + i); - } - }, - - /** - * Returns the state of this block as a JSON serializable object. - * - * @returns The state of this block, ie the item count. - */ - saveExtraState: function (this: DynamicListCreateBlock): {itemCount: number} { - if (!this.isDeadOrDying() && !this.isCorrectlyFormatted()) { - // If we call finalizeConnections here without disabling events, we get - // into an event loop. - Blockly.Events.disable(); - this.finalizeConnections(); - if (this instanceof Blockly.BlockSvg) this.initSvg(); - Blockly.Events.enable(); - } - - return { - itemCount: this.itemCount, - }; - }, - - /** - * Applies the given state to this block. - * - * @param state The state to apply to this block, ie the item count. - */ - loadExtraState: function ( - this: DynamicListCreateBlock, - state: {itemCount?: number; [x: string]: unknown} | string, - ) { - if (typeof state === 'string') { - this.domToMutation(Blockly.utils.xml.textToDom(state)); - return; - } - - this.itemCount = state['itemCount'] ?? 0; - // minInputs are added automatically. - for (let i = this.minInputs; i < this.itemCount; i++) { - this.appendValueInput('ADD' + i); - } - }, - - /** - * Check whether a new input should be added and determine where it should go. - * - * @param connection The connection that has a pending connection. - * @returns The index before which to insert a new input, or null if no input - * should be added. - */ - findInputIndexForConnection( - this: DynamicListCreateBlock, - connection: Blockly.Connection, - ): number | null { - if ( - !connection.targetConnection || - connection.targetBlock()?.isInsertionMarker() - ) { - // This connection is available. - return null; - } - - let connectionIndex = -1; - for (let i = 0; i < this.inputList.length; i++) { - if (this.inputList[i].connection == connection) { - connectionIndex = i; - } - } - - if (connectionIndex == this.inputList.length - 1) { - // This connection is the last one and already has a block in it, so - // we should add a new connection at the end. - return this.inputList.length + 1; - } - - const nextInput = this.inputList[connectionIndex + 1]; - const nextConnection = nextInput?.connection?.targetConnection; - if ( - nextConnection && - !nextConnection.getSourceBlock().isInsertionMarker() - ) { - return connectionIndex + 1; - } - - // Don't add new connection. - return null; - }, - - /** - * Called by a monkey-patched version of InsertionMarkerManager when - * a block is dragged over one of the connections on this block. - * - * @param connection The connection on this block that has a pending - * connection. - */ - onPendingConnection( - this: DynamicListCreateBlock, - connection: Blockly.Connection, - ): void { - const insertIndex = this.findInputIndexForConnection(connection); - if (insertIndex == null) { - return; - } - this.appendValueInput(`ADD${Blockly.utils.idGenerator.genUid()}`); - this.moveNumberedInputBefore(this.inputList.length - 1, insertIndex); - }, - - /** - * Called by a monkey-patched version of InsertionMarkerManager when a block - * drag ends if the dragged block had a pending connection with this block. - */ - finalizeConnections(this: DynamicListCreateBlock): void { - const targetConns = this.removeUnnecessaryEmptyConns( - this.inputList.map((i) => i.connection?.targetConnection), - ); - this.tearDownBlock(); - this.addItemInputs(targetConns); - this.itemCount = targetConns.length; - }, - - /** Deletes all inputs on the block so it can be rebuilt. */ - tearDownBlock(this: DynamicListCreateBlock): void { - for (let i = this.inputList.length - 1; i >= 0; i--) { - this.removeInput(this.inputList[i].name); - } - }, - - /** - * Filters the given target connections so that empty connections are removed, - * unless we need those to reach the minimum input count. Empty connections - * are removed starting at the end of the array. - * - * @param targetConns The list of connections associated with inputs. - * @returns A filtered list of connections (or null/undefined) which should - * be attached to inputs. - */ - removeUnnecessaryEmptyConns( - targetConns: Array, - ): Array { - const filteredConns = [...targetConns]; - for (let i = filteredConns.length - 1; i >= 0; i--) { - if (!filteredConns[i] && filteredConns.length > this.minInputs) { - filteredConns.splice(i, 1); - } - } - return filteredConns; - }, - - /** - * Adds inputs based on the given array of target cons. An input is added for - * every entry in the array (if it does not already exist). If the entry is - * a connection and not null/undefined the connection will be connected to - * the input. - * - * @param targetConns The connections defining the inputs to add. - */ - addItemInputs( - this: DynamicListCreateBlock, - targetConns: Array, - ): void { - const input = this.addFirstInput(); - const firstConn = targetConns[0]; - if (firstConn) input.connection?.connect(firstConn); - - for (let i = 1; i < targetConns.length; i++) { - const input = this.appendValueInput(`ADD${i}`); - - const targetConn = targetConns[i]; - if (targetConn) input.connection?.connect(targetConn); - } - }, - - /** - * Adds the top input with the label to this block. - * - * @returns The added input. - */ - addFirstInput(this: DynamicListCreateBlock): Blockly.Input { - return this.appendValueInput('ADD0').appendField( - Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH'], - ); - }, - - /** - * Returns true if all of the inputs on this block are in order. - * False otherwise. - */ - isCorrectlyFormatted(this: DynamicListCreateBlock): boolean { - for (let i = 0; i < this.inputList.length; i++) { - if (this.inputList[i].name !== `ADD${i}`) return false; - } - return true; - }, -}; - -Blockly.Blocks['dynamic_list_create'] = DYNAMIC_LIST_CREATE_MIXIN; diff --git a/plugins/block-dynamic-connection/src/dynamic_text_join.ts b/plugins/block-dynamic-connection/src/dynamic_text_join.ts deleted file mode 100644 index 24163fa47..000000000 --- a/plugins/block-dynamic-connection/src/dynamic_text_join.ts +++ /dev/null @@ -1,299 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Defines a version of the text_join block with dyanmic - * inputs that appear when a block is dragged over inputs on the block. - */ - -import * as Blockly from 'blockly/core'; - -/** Type of a block that has the DYNAMIC_TEXT_JOIN_MIXIN. */ -type DynamicTextJoinBlock = Blockly.Block & DynamicTextJoinMixin; -/* eslint-disable @typescript-eslint/no-empty-interface */ -/** This interface avoids a "circular reference" compile error. */ -interface DynamicTextJoinMixin extends DynamicTextJoinMixinType {} -/* eslint-enable @typescript-eslint/no-empty-interface */ -type DynamicTextJoinMixinType = typeof DYNAMIC_TEXT_JOIN_MIXIN; - -const DYNAMIC_TEXT_JOIN_MIXIN = { - /** Minimum number of inputs for this block. */ - minInputs: 2, - - /** Count of the item inputs. */ - itemCount: 0, - - /** Block for concatenating any number of strings. */ - init(this: DynamicTextJoinBlock): void { - this.itemCount = this.minInputs; - - this.setHelpUrl(Blockly.Msg['TEXT_JOIN_HELPURL']); - this.setStyle('text_blocks'); - this.addFirstInput(); - for (let i = 1; i < this.minInputs; i++) this.appendValueInput(`ADD${i}`); - this.setOutput(true, 'String'); - this.setTooltip(Blockly.Msg['TEXT_JOIN_TOOLTIP']); - }, - - /** - * Create XML to represent number of text inputs. - * - * @returns XML storage element. - */ - mutationToDom(this: DynamicTextJoinBlock): Element { - if (!this.isDeadOrDying()) { - // If we call finalizeConnections here without disabling events, we get into - // an event loop. - Blockly.Events.disable(); - this.finalizeConnections(); - if (this instanceof Blockly.BlockSvg) this.initSvg(); - Blockly.Events.enable(); - } - - const container = Blockly.utils.xml.createElement('mutation'); - container.setAttribute('items', `${this.itemCount}`); - return container; - }, - - /** - * Parse XML to restore the text inputs. - * - * @param xmlElement XML storage element. - */ - domToMutation(this: DynamicTextJoinBlock, xmlElement: Element): void { - if (xmlElement.getAttribute('inputs')) { - this.deserializeInputs(xmlElement); - } else { - this.deserializeCounts(xmlElement); - } - }, - - /** - * Parses XML based on the 'inputs' attribute (non-standard). - * - * @param xmlElement XML storage element. - */ - deserializeInputs(this: DynamicTextJoinBlock, xmlElement: Element): void { - const items = xmlElement.getAttribute('inputs'); - if (items) { - const inputNames = items.split(','); - this.inputList = []; - inputNames.forEach((name) => this.appendValueInput(name)); - this.inputList[0].appendField(Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH']); - } - }, - - /** - * Parses XML based on the 'items' attribute (standard). - * - * @param xmlElement XML storage element. - */ - deserializeCounts(this: DynamicTextJoinBlock, xmlElement: Element): void { - this.itemCount = Math.max( - parseInt(xmlElement.getAttribute('items') ?? '0', 10), - this.minInputs, - ); - // minInputs are added automatically. - for (let i = this.minInputs; i < this.itemCount; i++) { - this.appendValueInput('ADD' + i); - } - }, - - /** - * Returns the state of this block as a JSON serializable object. - * - * @returns The state of this block, ie the item count. - */ - saveExtraState: function (this: DynamicTextJoinBlock): {itemCount: number} { - if (!this.isDeadOrDying() && !this.isCorrectlyFormatted()) { - // If we call finalizeConnections here without disabling events, we get into - // an event loop. - Blockly.Events.disable(); - this.finalizeConnections(); - if (this instanceof Blockly.BlockSvg) this.initSvg(); - Blockly.Events.enable(); - } - - return { - itemCount: this.itemCount, - }; - }, - - /** - * Applies the given state to this block. - * - * @param state The state to apply to this block, ie the item count. - */ - loadExtraState: function ( - this: DynamicTextJoinBlock, - state: {itemCount?: number; [x: string]: unknown} | string, - ) { - if (typeof state === 'string') { - this.domToMutation(Blockly.utils.xml.textToDom(state)); - return; - } - - this.itemCount = state['itemCount'] ?? 0; - // minInputs are added automatically. - for (let i = this.minInputs; i < this.itemCount; i++) { - this.appendValueInput('ADD' + i); - } - }, - - /** - * Check whether a new input should be added and determine where it should go. - * - * @param connection The connection that has a pending connection. - * @returns The index before which to insert a new input, or null if no input - * should be added. - */ - findInputIndexForConnection( - this: DynamicTextJoinBlock, - connection: Blockly.Connection, - ): number | null { - if ( - !connection.targetConnection || - connection.targetBlock()?.isInsertionMarker() - ) { - // This connection is available. - return null; - } - - let connectionIndex = -1; - for (let i = 0; i < this.inputList.length; i++) { - if (this.inputList[i].connection == connection) { - connectionIndex = i; - } - } - - if (connectionIndex == this.inputList.length - 1) { - // This connection is the last one and already has a block in it, so - // we should add a new connection at the end. - return this.inputList.length + 1; - } - - const nextInput = this.inputList[connectionIndex + 1]; - const nextConnection = nextInput?.connection?.targetConnection; - if ( - nextConnection && - !nextConnection.getSourceBlock().isInsertionMarker() - ) { - return connectionIndex + 1; - } - - // Don't add new connection. - return null; - }, - - /** - * Called by a monkey-patched version of InsertionMarkerManager when - * a block is dragged over one of the connections on this block. - * - * @param connection The connection on this block that has a pending - * connection. - */ - onPendingConnection( - this: DynamicTextJoinBlock, - connection: Blockly.Connection, - ): void { - const insertIndex = this.findInputIndexForConnection(connection); - if (insertIndex == null) { - return; - } - this.appendValueInput(`ADD${Blockly.utils.idGenerator.genUid()}`); - this.moveNumberedInputBefore(this.inputList.length - 1, insertIndex); - }, - - /** - * Called by a monkey-patched version of InsertionMarkerManager when a block - * drag ends if the dragged block had a pending connection with this block. - */ - finalizeConnections(this: DynamicTextJoinBlock): void { - const targetConns = this.removeUnnecessaryEmptyConns( - this.inputList.map((i) => i.connection?.targetConnection), - ); - this.tearDownBlock(); - this.addItemInputs(targetConns); - this.itemCount = targetConns.length; - }, - - /** Deletes all inputs on this block so it can be rebuilt. */ - tearDownBlock(this: DynamicTextJoinBlock): void { - for (let i = this.inputList.length - 1; i >= 0; i--) { - this.removeInput(this.inputList[i].name); - } - }, - - /** - * Filters the given target connections so that empty connections are removed, - * unless we need those to reach the minimum input count. Empty connections - * are removed starting at the end of the array. - * - * @param targetConns The list of connections associated with inputs. - * @returns A filtered list of connections (or null/undefined) which should - * be attached to inputs. - */ - removeUnnecessaryEmptyConns( - this: DynamicTextJoinBlock, - targetConns: Array, - ): Array { - const filteredConns = [...targetConns]; - for (let i = filteredConns.length - 1; i >= 0; i--) { - if (!filteredConns[i] && filteredConns.length > this.minInputs) { - filteredConns.splice(i, 1); - } - } - return filteredConns; - }, - - /** - * Adds inputs based on the given array of target conns. An input is added for - * every entry in the array (if it does not already exist). If the entry is - * a connection and not null/undefined the connection will be connected to - * the input. - * - * @param targetConns The connections defining the inputs to add. - */ - addItemInputs( - this: DynamicTextJoinBlock, - targetConns: Array, - ): void { - const input = this.addFirstInput(); - const firstConn = targetConns[0]; - if (firstConn) input.connection?.connect(firstConn); - - for (let i = 1; i < targetConns.length; i++) { - const input = this.appendValueInput(`ADD${i}`); - - const targetConn = targetConns[i]; - if (targetConn) input.connection?.connect(targetConn); - } - }, - - /** - * Adds the top input with the label to this block. - * - * @returns The added input. - */ - addFirstInput(this: DynamicTextJoinBlock): Blockly.Input { - return this.appendValueInput('ADD0').appendField( - Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH'], - ); - }, - - /** - * Returns true if all of the inputs on this block are in order. - * False otherwise. - */ - isCorrectlyFormatted(this: DynamicTextJoinBlock): boolean { - for (let i = 0; i < this.inputList.length; i++) { - if (this.inputList[i].name !== `ADD${i}`) return false; - } - return true; - }, -}; - -Blockly.Blocks['dynamic_text_join'] = DYNAMIC_TEXT_JOIN_MIXIN; diff --git a/plugins/block-dynamic-connection/src/index.ts b/plugins/block-dynamic-connection/src/index.ts deleted file mode 100644 index 4da41caf7..000000000 --- a/plugins/block-dynamic-connection/src/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Adds blocks that replace the built-in mutator UI with dynamic - * connections that appear when a block is dragged over inputs on the block. - */ - -import * as Blockly from 'blockly/core'; -import './dynamic_if'; -import './dynamic_text_join'; -import './dynamic_list_create'; -import {decoratePreviewer, blockIsDynamic} from './connection_previewer'; - -export {decoratePreviewer, blockIsDynamic}; - -export const overrideOldBlockDefinitions = function (): void { - Blockly.Blocks['lists_create_with'] = Blockly.Blocks['dynamic_list_create']; - Blockly.Blocks['text_join'] = Blockly.Blocks['dynamic_text_join']; - Blockly.Blocks['controls_if'] = Blockly.Blocks['dynamic_if']; -}; - -/** - * Finalizes connections when certain events (such as block deletion) are - * detected. - * - * @param e - */ -export function finalizeConnections(e: Blockly.Events.Abstract) { - if (e.type === Blockly.Events.BLOCK_DELETE) { - const ws = Blockly.Workspace.getById(e.workspaceId ?? ''); - if (!ws) return; - for (const block of ws.getAllBlocks() as Blockly.BlockSvg[]) { - if (blockIsDynamic(block)) { - block.finalizeConnections(); - } - } - } -} diff --git a/plugins/block-dynamic-connection/test/dynamic_if.mocha.js b/plugins/block-dynamic-connection/test/dynamic_if.mocha.js deleted file mode 100644 index 96f78683d..000000000 --- a/plugins/block-dynamic-connection/test/dynamic_if.mocha.js +++ /dev/null @@ -1,649 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const {testHelpers} = require('@blockly/dev-tools'); -const Blockly = require('blockly/core'); -require('blockly/blocks'); -const En = require('blockly/msg/en'); -const {overrideOldBlockDefinitions} = require('../src/index'); - -const assert = chai.assert; - -Blockly.setLocale(En); - -suite('If block', function () { - /** - * Asserts that the if block has the expected inputs. - * @param {!Blockly.Block} block The block to check. - * @param {!Array} expectedInputs The expected inputs. - * @param {string=} type The block type expected. Defaults to 'dynamic_if'. - */ - function assertBlockStructure(block, expectedInputs, type = 'dynamic_if') { - assert.equal(block.type, type); - assert.equal(block.inputList.length, expectedInputs.length); - assert.isTrue(expectedInputs.length >= 2); - for (let i = 0; i < expectedInputs.length; i++) { - assert.match(block.inputList[i].name, expectedInputs[i]); - } - } - - /** - * Creates a boolean block and connects it to the specified connection. - * @param {!Blockly.Workspace} workspace The workspace. - * @param {!Blockly.Connection} connection The connection to connect a new - * block to. - */ - function connectBooleanBlockToConnection(workspace, connection) { - const newBlock = workspace.newBlock('logic_boolean'); - const targetConnection = newBlock.outputConnection; - connection.connect(targetConnection); - } - - /** - * Creates a boolean block and connects it to the specified connection. - * @param {!Blockly.Workspace} workspace The workspace. - * @param {!Blockly.Connection} connection The connection to connect a new - * block to. - */ - function connectStatementBlockToConnection(workspace, connection) { - const newBlock = workspace.newBlock('text_print'); - const targetConnection = newBlock.previousConnection; - connection.connect(targetConnection); - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - overrideOldBlockDefinitions(); - }); - - teardown(function () { - this.workspace.dispose(); - }); - - test('Creation', function () { - const block = this.workspace.newBlock('dynamic_if'); - assertBlockStructure(block, [/IF0/, /DO0/]); - }); - - suite('adding inputs', function () { - test('attaching the first predicate does not create a case', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('IF0').connection; - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/IF0/, /DO0/]); - }); - - test('attaching the second predicate creates a case', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('IF0').connection; - connectBooleanBlockToConnection(this.workspace, connection); - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/IF0/, /DO0/, /IF.*/, /DO.*/]); - }); - - test('attaching the first statement creates an else', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('DO0').connection; - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/IF0/, /DO0/, /ELSE/]); - }); - - test('attaching the second statement creates an else', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('DO0').connection; - connectStatementBlockToConnection(this.workspace, connection); - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/IF0/, /DO0/, /ELSE/]); - }); - - test('attaching to the next connection creates an else', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.nextConnection; - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/IF0/, /DO0/, /ELSE/]); - }); - }); - - suite('finalizing inputs', function () { - test('the block does not go below one case', function () { - const block = this.workspace.newBlock('dynamic_if'); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/]); - }); - - test('a case with no blocks is removed', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('IF0').connection; - connectBooleanBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/]); - }); - - test('a case with a predicate and statements is kept', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('IF0').connection; - connectBooleanBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - connectBooleanBlockToConnection( - this.workspace, - block.inputList[2].connection, - ); - connectStatementBlockToConnection( - this.workspace, - block.inputList[3].connection, - ); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/, /IF1/, /DO1/]); - }); - - test('a case with only a predicate is kept', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('IF0').connection; - connectBooleanBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - connectBooleanBlockToConnection( - this.workspace, - block.inputList[2].connection, - ); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/, /IF1/, /DO1/]); - }); - - test('a case with only statements is kept', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('IF0').connection; - connectBooleanBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - connectStatementBlockToConnection( - this.workspace, - block.inputList[3].connection, - ); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/, /IF1/, /DO1/]); - }); - - test('an else with no statements is removed', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('DO0').connection; - block.onPendingConnection(connection); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/]); - }); - - test('an else with statements is kept', function () { - const block = this.workspace.newBlock('dynamic_if'); - const connection = block.getInput('DO0').connection; - block.onPendingConnection(connection); - connectStatementBlockToConnection( - this.workspace, - block.getInput('ELSE').connection, - ); - - block.finalizeConnections(); - - assertBlockStructure(block, [/IF0/, /DO0/, /ELSE/]); - }); - }); - - const testCases = [ - { - title: 'empty XML', - xml: '', - expectedXml: - '' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/IF0/, /DO0/]); - }, - }, - { - title: 'one if one else - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/IF0/, /DO0/, /ELSE/]); - }, - }, - { - title: 'multiple inputs with children - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [ - /IF0/, - /DO0/, - /IF1/, - /DO1/, - /IF2/, - /DO2/, - /ELSE/, - ]); - }, - }, - { - title: 'multiple nonsequential inputs - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '\n', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/IF0/, /DO0/, /IF1/, /DO1/, /IF2/, /DO2/]); - }, - }, - { - title: 'one if one else - standard serialization', - xml: - '\n' + - ' \n' + - '', - expectedXml: - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/IF0/, /DO0/], 'dynamic_if'); - }, - }, - { - title: 'one if one else with children - standard serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' TRUE\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure( - block, - [/IF0/, /DO0/, /IF1/, /DO1/, /ELSE/], - 'dynamic_if', - ); - }, - }, - { - title: 'one if one else with children - json', - json: { - type: 'dynamic_if', - id: '1', - extraState: { - elseIfCount: 1, - hasElse: true, - }, - inputs: { - IF0: { - block: { - type: 'logic_boolean', - id: '2', - fields: { - BOOL: 'TRUE', - }, - }, - }, - IF1: { - block: { - type: 'logic_boolean', - id: '3', - fields: { - BOOL: 'TRUE', - }, - }, - }, - ELSE: { - block: { - type: 'text_print', - id: '4', - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure( - block, - [/IF0/, /DO0/, /IF1/, /DO1/, /ELSE/], - 'dynamic_if', - ); - }, - }, - { - title: 'one if one else with children - json with stringified old XML', - json: { - type: 'dynamic_if', - id: '1', - extraState: '', - inputs: { - IF1: { - block: { - type: 'logic_boolean', - id: '2', - fields: { - BOOL: 'TRUE', - }, - }, - }, - IF3: { - block: { - type: 'logic_boolean', - id: '3', - fields: { - BOOL: 'TRUE', - }, - }, - }, - IF2: { - block: { - type: 'logic_boolean', - id: '4', - fields: { - BOOL: 'TRUE', - }, - }, - }, - ELSE: { - block: { - type: 'text_print', - id: '5', - }, - }, - }, - }, - expectedJson: { - type: 'dynamic_if', - id: '1', - extraState: { - elseIfCount: 2, - hasElse: true, - }, - inputs: { - IF0: { - block: { - type: 'logic_boolean', - id: '2', - fields: { - BOOL: 'TRUE', - }, - }, - }, - IF1: { - block: { - type: 'logic_boolean', - id: '3', - fields: { - BOOL: 'TRUE', - }, - }, - }, - IF2: { - block: { - type: 'logic_boolean', - id: '4', - fields: { - BOOL: 'TRUE', - }, - }, - }, - ELSE: { - block: { - type: 'text_print', - id: '5', - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure( - block, - [/IF0/, /DO0/, /IF1/, /DO1/, /IF2/, /DO2/, /ELSE/], - 'dynamic_if', - ); - }, - }, - ]; - testHelpers.runSerializationTestSuite(testCases, Blockly); -}); diff --git a/plugins/block-dynamic-connection/test/dynamic_list_create.mocha.js b/plugins/block-dynamic-connection/test/dynamic_list_create.mocha.js deleted file mode 100644 index 1a600c409..000000000 --- a/plugins/block-dynamic-connection/test/dynamic_list_create.mocha.js +++ /dev/null @@ -1,548 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const {testHelpers} = require('@blockly/dev-tools'); -const Blockly = require('blockly/core'); -require('blockly/blocks'); -const En = require('blockly/msg/en'); -const {overrideOldBlockDefinitions} = require('../src/index'); - -const assert = chai.assert; - -Blockly.setLocale(En); - -suite('List create block', function () { - /** - * Asserts that the list create block has the expected inputs. - * @param {!Blockly.Block} block The block to check. - * @param {!Array} expectedInputs The expected inputs. - * @type {string=} The block type expected. Defaults to 'dynamic_list_create'. - */ - function assertBlockStructure( - block, - expectedInputs, - type = 'dynamic_list_create', - ) { - assert.equal(block.type, type); - assert.equal(block.inputList.length, expectedInputs.length); - for (let i = 0; i < expectedInputs.length; i++) { - assert.match(block.inputList[i].name, expectedInputs[i]); - } - } - - /** - * Creates a block and connects it to the specified connection. - * @param {!Blockly.Workspace} workspace The workspace. - * @param {!Blockly.Connection} connection The connection to connect a new - * block to. - */ - function connectBlockToConnection(workspace, connection) { - const newBlock = workspace.newBlock('text'); - const targetConnection = newBlock.outputConnection; - connection.connect(targetConnection); - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - overrideOldBlockDefinitions(); - - const def1 = {...Blockly.Blocks['dynamic_list_create']}; - def1.minInputs = 1; - Blockly.Blocks['dynamic_list_1_input'] = def1; - - const def5 = {...Blockly.Blocks['dynamic_list_create']}; - def5.minInputs = 5; - Blockly.Blocks['dynamic_list_5_inputs'] = def5; - }); - - teardown(function () { - this.workspace.dispose(); - delete Blockly.Blocks['dynamic_list_5_inputs']; - }); - - suite('Creation', function () { - test('the default definition has two inputs', function () { - const block = this.workspace.newBlock('dynamic_list_create'); - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }); - - test('minInputs controls the number of inputs', function () { - const block = this.workspace.newBlock('dynamic_list_5_inputs'); - assertBlockStructure( - block, - [/ADD0/, /ADD1/, /ADD2/, /ADD3/, /ADD4/], - 'dynamic_list_5_inputs', - ); - }); - }); - - suite('adding inputs', function () { - test('attaching min items does not add an input', function () { - const block = this.workspace.newBlock('dynamic_list_1_input'); - const connection = block.getInput('ADD0').connection; - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/ADD0/], 'dynamic_list_1_input'); - }); - - test('attaching three items creates an input', function () { - const block = this.workspace.newBlock('dynamic_list_1_input'); - const connection = block.getInput('ADD0').connection; - connectBlockToConnection(this.workspace, connection); - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/ADD0/, /ADD.*/], 'dynamic_list_1_input'); - }); - }); - - suite('finalizing inputs', function () { - test('the block does not go below min inputs', function () { - const block = this.workspace.newBlock('dynamic_list_5_inputs'); - - block.finalizeConnections(); - - assertBlockStructure( - block, - [/ADD0/, /ADD1/, /ADD2/, /ADD3/, /ADD4/], - 'dynamic_list_5_inputs', - ); - }); - - test('an extra input with no blocks is removed', function () { - const block = this.workspace.newBlock('dynamic_list_1_input'); - const connection = block.getInput('ADD0').connection; - connectBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - - block.finalizeConnections(); - - assertBlockStructure(block, [/ADD0/], 'dynamic_list_1_input'); - }); - - test('an extra input with blocks is kept', function () { - const block = this.workspace.newBlock('dynamic_list_1_input'); - const connection = block.getInput('ADD0').connection; - connectBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - connectBlockToConnection(this.workspace, block.inputList[1].connection); - - block.finalizeConnections(); - - assertBlockStructure(block, [/ADD0/, /ADD1/], 'dynamic_list_1_input'); - }); - - test('extra inputs are removed starting at the end', function () { - const block = this.workspace.newBlock('dynamic_list_5_inputs'); - const connection0 = block.getInput('ADD0').connection; - const connection1 = block.getInput('ADD1').connection; - connectBlockToConnection(this.workspace, connection0); - connectBlockToConnection(this.workspace, connection1); - block.onPendingConnection(connection0); - - block.finalizeConnections(); - - assertBlockStructure( - block, - [/ADD0/, /ADD1/, /ADD2/, /ADD3/, /ADD4/], - 'dynamic_list_5_inputs', - ); - assert.isOk(block.getInputTargetBlock('ADD0')); - assert.isNotOk( - block.getInputTargetBlock('ADD1'), - 'Expected the empty input created by pending to still exist.', - ); - assert.isOk(block.getInputTargetBlock('ADD2')); - }); - }); - - const testCases = [ - { - title: 'empty XML', - xml: '', - expectedXml: - '\n' + - ' \n', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'default state - old serialization', - xml: - '\n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'two inputs with one child - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'multiple inputs with children - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'multiple non-sequential inputs with children - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'two inputs one child - standard serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'multiple inputs with children - standard serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'standard/core XML still maintains minimum inputs', - xml: - '' + - ' ' + - '', - expectedXml: - '\n' + - ' \n', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/], 'lists_create_with'); - }, - }, - { - title: 'two inputs one child - json', - json: { - type: 'dynamic_list_create', - id: '1', - extraState: { - itemCount: 2, - }, - inputs: { - ADD1: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'multiple inputs with children - json', - json: { - type: 'dynamic_list_create', - id: '1', - extraState: { - itemCount: 4, - }, - inputs: { - ADD0: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'a', - }, - }, - }, - ADD1: { - block: { - type: 'text', - id: '3', - fields: { - TEXT: 'b', - }, - }, - }, - ADD2: { - block: { - type: 'text', - id: '4', - fields: { - TEXT: 'c', - }, - }, - }, - ADD3: { - block: { - type: 'text', - id: '5', - fields: { - TEXT: 'd', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'multiple inputs with children - json with stringified old XML', - json: { - type: 'dynamic_list_create', - id: '1', - extraState: - '', - inputs: { - ADD1: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'a', - }, - }, - }, - ADD5: { - block: { - type: 'text', - id: '3', - fields: { - TEXT: 'b', - }, - }, - }, - ADD2: { - block: { - type: 'text', - id: '4', - fields: { - TEXT: 'c', - }, - }, - }, - ADD4: { - block: { - type: 'text', - id: '5', - fields: { - TEXT: 'd', - }, - }, - }, - }, - }, - expectedJson: { - type: 'dynamic_list_create', - id: '1', - extraState: { - itemCount: 4, - }, - inputs: { - ADD0: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'a', - }, - }, - }, - ADD1: { - block: { - type: 'text', - id: '3', - fields: { - TEXT: 'b', - }, - }, - }, - ADD2: { - block: { - type: 'text', - id: '4', - fields: { - TEXT: 'c', - }, - }, - }, - ADD3: { - block: { - type: 'text', - id: '5', - fields: { - TEXT: 'd', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - ]; - testHelpers.runSerializationTestSuite(testCases, Blockly); -}); diff --git a/plugins/block-dynamic-connection/test/dynamic_text_join.mocha.js b/plugins/block-dynamic-connection/test/dynamic_text_join.mocha.js deleted file mode 100644 index 6f944d95a..000000000 --- a/plugins/block-dynamic-connection/test/dynamic_text_join.mocha.js +++ /dev/null @@ -1,550 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const {testHelpers} = require('@blockly/dev-tools'); -const Blockly = require('blockly/core'); -require('blockly/blocks'); -const En = require('blockly/msg/en'); -const {overrideOldBlockDefinitions} = require('../src/index'); - -const assert = chai.assert; - -Blockly.setLocale(En); - -suite('Text join block', function () { - /** - * Asserts that the text join block has the expected inputs. - * @param {!Blockly.Block} block The block to check. - * @param {!Array} expectedInputs The expected inputs. - * @type {string=} The block type expected. Defaults to 'dynamic_text_join'. - */ - function assertBlockStructure( - block, - expectedInputs, - type = 'dynamic_text_join', - ) { - assert.equal(block.type, type); - assert.equal(block.inputList.length, expectedInputs.length); - for (let i = 0; i < expectedInputs.length; i++) { - assert.match(block.inputList[i].name, expectedInputs[i]); - } - } - - /** - * Creates a block and connects it to the specified connection. - * @param {!Blockly.Workspace} workspace The workspace. - * @param {!Blockly.Connection} connection The connection to connect a new - * block to. - */ - function connectBlockToConnection(workspace, connection) { - const newBlock = workspace.newBlock('text'); - const targetConnection = newBlock.outputConnection; - connection.connect(targetConnection); - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - overrideOldBlockDefinitions(); - - const def1 = {...Blockly.Blocks['dynamic_text_join']}; - def1.minInputs = 1; - Blockly.Blocks['dynamic_text_1_input'] = def1; - - const def5 = {...Blockly.Blocks['dynamic_text_join']}; - def5.minInputs = 5; - Blockly.Blocks['dynamic_text_5_inputs'] = def5; - }); - - teardown(function () { - this.workspace.dispose(); - delete Blockly.Blocks['dynamic_text_5_inputs']; - }); - - suite('Creation', function () { - test('the default definition has two inputs', function () { - const block = this.workspace.newBlock('dynamic_text_join'); - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }); - - test('minInputs controls the number of inputs', function () { - const block = this.workspace.newBlock('dynamic_text_5_inputs'); - assertBlockStructure( - block, - [/ADD0/, /ADD1/, /ADD2/, /ADD3/, /ADD4/], - 'dynamic_text_5_inputs', - ); - }); - }); - - suite('adding inputs', function () { - test('attaching min items does not add an input', function () { - const block = this.workspace.newBlock('dynamic_text_1_input'); - const connection = block.getInput('ADD0').connection; - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/ADD0/], 'dynamic_text_1_input'); - }); - - test('attaching three items creates an input', function () { - const block = this.workspace.newBlock('dynamic_text_1_input'); - const connection = block.getInput('ADD0').connection; - connectBlockToConnection(this.workspace, connection); - - block.onPendingConnection(connection); - - assertBlockStructure(block, [/ADD0/, /ADD.*/], 'dynamic_text_1_input'); - }); - }); - - suite('finalizing inputs', function () { - test('the block does not go below min inputs', function () { - const block = this.workspace.newBlock('dynamic_text_5_inputs'); - - block.finalizeConnections(); - - assertBlockStructure( - block, - [/ADD0/, /ADD1/, /ADD2/, /ADD3/, /ADD4/], - 'dynamic_text_5_inputs', - ); - }); - - test('an extra input with no blocks is removed', function () { - const block = this.workspace.newBlock('dynamic_text_1_input'); - const connection = block.getInput('ADD0').connection; - connectBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - - block.finalizeConnections(); - - assertBlockStructure(block, [/ADD0/], 'dynamic_text_1_input'); - }); - - test('an extra input with blocks is kept', function () { - const block = this.workspace.newBlock('dynamic_text_1_input'); - const connection = block.getInput('ADD0').connection; - connectBlockToConnection(this.workspace, connection); - block.onPendingConnection(connection); - connectBlockToConnection(this.workspace, block.inputList[1].connection); - - block.finalizeConnections(); - - assertBlockStructure(block, [/ADD0/, /ADD1/], 'dynamic_text_1_input'); - }); - - test('extra inputs are removed starting at the end', function () { - const block = this.workspace.newBlock('dynamic_text_5_inputs'); - const connection0 = block.getInput('ADD0').connection; - const connection1 = block.getInput('ADD1').connection; - connectBlockToConnection(this.workspace, connection0); - connectBlockToConnection(this.workspace, connection1); - block.onPendingConnection(connection0); - - block.finalizeConnections(); - - assertBlockStructure( - block, - [/ADD0/, /ADD1/, /ADD2/, /ADD3/, /ADD4/], - 'dynamic_text_5_inputs', - ); - assert.isOk(block.getInputTargetBlock('ADD0')); - assert.isNotOk( - block.getInputTargetBlock('ADD1'), - 'Expected the empty input created by pending to still exist.', - ); - assert.isOk(block.getInputTargetBlock('ADD2')); - }); - }); - - const testCases = [ - { - title: 'empty XML', - xml: '', - expectedXml: - '\n' + - ' \n', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'default state - old serialization', - xml: - '\n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'two inputs with one child - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'multiple inputs with children - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'multiple non-sequential inputs with children - old serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'two inputs one child - standard serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' abc\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'multiple inputs with children - standard serialization', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' b\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' d\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' c\n' + - ' \n \n' + - ' \n' + - ' \n' + - ' a\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: 'standard/core XML still maintains minimum inputs', - xml: - '' + - ' ' + - '', - expectedXml: - '\n' + - ' \n', - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/], 'lists_create_with'); - }, - }, - { - title: 'two inputs one child - json', - json: { - type: 'dynamic_text_join', - id: '1', - extraState: { - itemCount: 2, - }, - inputs: { - ADD1: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/]); - }, - }, - { - title: 'multiple inputs with children - json', - json: { - type: 'dynamic_text_join', - id: '1', - extraState: { - itemCount: 4, - }, - inputs: { - ADD0: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'a', - }, - }, - }, - ADD1: { - block: { - type: 'text', - id: '3', - fields: { - TEXT: 'b', - }, - }, - }, - ADD2: { - block: { - type: 'text', - id: '4', - fields: { - TEXT: 'c', - }, - }, - }, - ADD3: { - block: { - type: 'text', - id: '5', - fields: { - TEXT: 'd', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - { - title: - 'multiple non-sequential inputs with children - ' + - 'json with stringified old XML', - json: { - type: 'dynamic_text_join', - id: '1', - extraState: - '', - inputs: { - ADD1: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'a', - }, - }, - }, - ADD5: { - block: { - type: 'text', - id: '3', - fields: { - TEXT: 'b', - }, - }, - }, - ADD2: { - block: { - type: 'text', - id: '4', - fields: { - TEXT: 'c', - }, - }, - }, - ADD4: { - block: { - type: 'text', - id: '5', - fields: { - TEXT: 'd', - }, - }, - }, - }, - }, - expectedJson: { - type: 'dynamic_text_join', - id: '1', - extraState: { - itemCount: 4, - }, - inputs: { - ADD0: { - block: { - type: 'text', - id: '2', - fields: { - TEXT: 'a', - }, - }, - }, - ADD1: { - block: { - type: 'text', - id: '3', - fields: { - TEXT: 'b', - }, - }, - }, - ADD2: { - block: { - type: 'text', - id: '4', - fields: { - TEXT: 'c', - }, - }, - }, - ADD3: { - block: { - type: 'text', - id: '5', - fields: { - TEXT: 'd', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertBlockStructure(block, [/ADD0/, /ADD1/, /ADD2/, /ADD3/]); - }, - }, - ]; - testHelpers.runSerializationTestSuite(testCases, Blockly); -}); diff --git a/plugins/block-dynamic-connection/test/index.html b/plugins/block-dynamic-connection/test/index.html deleted file mode 100644 index dc96c578f..000000000 --- a/plugins/block-dynamic-connection/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Plugin Test - - - - -
- - - diff --git a/plugins/block-dynamic-connection/test/index.ts b/plugins/block-dynamic-connection/test/index.ts deleted file mode 100644 index 3b12c355e..000000000 --- a/plugins/block-dynamic-connection/test/index.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Dynamic block connection test playground. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import * as BlockDynamicConnection from '../src/index'; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const ws = Blockly.inject(blocklyDiv, options); - ws.addChangeListener(BlockDynamicConnection.finalizeConnections); - return ws; -} - -document.addEventListener('DOMContentLoaded', function () { - BlockDynamicConnection.overrideOldBlockDefinitions(); - - const toolbox = { - kind: 'flyoutToolbox', - contents: [ - { - kind: 'block', - type: 'text_join', - }, - { - kind: 'block', - type: 'lists_create_with', - }, - { - kind: 'block', - type: 'controls_if', - }, - { - kind: 'block', - type: 'logic_boolean', - fields: { - BOOL: 'TRUE', - }, - }, - { - kind: 'block', - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - { - kind: 'block', - type: 'math_number', - fields: { - NUM: '123', - }, - }, - { - kind: 'block', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - block: undefined, - }, - }, - }, - ], - }; - - const defaultOptions: Blockly.BlocklyOptions = { - toolbox, - plugins: { - connectionPreviewer: BlockDynamicConnection.decoratePreviewer( - Blockly.InsertionMarkerPreviewer, - ), - }, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/block-dynamic-connection/tsconfig.json b/plugins/block-dynamic-connection/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/block-dynamic-connection/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/block-plus-minus/CHANGELOG.md b/plugins/block-plus-minus/CHANGELOG.md deleted file mode 100644 index 9988afca0..000000000 --- a/plugins/block-plus-minus/CHANGELOG.md +++ /dev/null @@ -1,692 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Add ARIA labels for block-plus-minus (#2696) -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Add ARIA labels for block-plus-minus ([#2696](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2696)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [9.0.10](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-plus-minus@9.0.9...@blockly/block-plus-minus@9.0.10) (2026-04-09) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-plus-minus@9.0.8...@blockly/block-plus-minus@9.0.9) (2026-01-22) - - -### Bug Fixes - -* Update JSDoc types in plus-minus procedure blocks ([#2673](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2673)) ([25142c1](https://github.com/RaspberryPiFoundation/blockly-samples/commit/25142c1a5aff0b3fb01890ca83ee9b2d5bb0278b)) - - - -## [9.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-plus-minus@9.0.7...@blockly/block-plus-minus@9.0.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-plus-minus@9.0.6...@blockly/block-plus-minus@9.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [9.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@9.0.5...@blockly/block-plus-minus@9.0.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@9.0.4...@blockly/block-plus-minus@9.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@9.0.3...@blockly/block-plus-minus@9.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@9.0.2...@blockly/block-plus-minus@9.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@9.0.1...@blockly/block-plus-minus@9.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@9.0.0...@blockly/block-plus-minus@9.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [9.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.16...@blockly/block-plus-minus@9.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [8.0.16](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.15...@blockly/block-plus-minus@8.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.15](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.14...@blockly/block-plus-minus@8.0.15) (2025-05-15) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.14](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.13...@blockly/block-plus-minus@8.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.13](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.12...@blockly/block-plus-minus@8.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.12](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.11...@blockly/block-plus-minus@8.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.11](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.10...@blockly/block-plus-minus@8.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.10](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.9...@blockly/block-plus-minus@8.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [8.0.9](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.8...@blockly/block-plus-minus@8.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [8.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.7...@blockly/block-plus-minus@8.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [8.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.6...@blockly/block-plus-minus@8.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.5...@blockly/block-plus-minus@8.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.4...@blockly/block-plus-minus@8.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.3...@blockly/block-plus-minus@8.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [8.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.2...@blockly/block-plus-minus@8.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.1...@blockly/block-plus-minus@8.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [8.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@8.0.0...@blockly/block-plus-minus@8.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [8.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.7...@blockly/block-plus-minus@8.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* block plus minus incompatibility with v11 ([#2169](https://github.com/google/blockly-samples/issues/2169)) ([2b857d4](https://github.com/google/blockly-samples/commit/2b857d4528402aebc0f536897fe3ea9447b4117b)) -* build for the v11 branch ([#2268](https://github.com/google/blockly-samples/issues/2268)) ([c7a4fc5](https://github.com/google/blockly-samples/commit/c7a4fc5e72c5e8d9e9bc926bbbbadd1eb31792fc)) -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) -* use undeprecated align value ([3535d19](https://github.com/google/blockly-samples/commit/3535d19c54a049dd7592c117c479cab4017ddac9)) - - - -## [7.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.6...@blockly/block-plus-minus@7.0.7) (2024-05-16) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [7.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.5...@blockly/block-plus-minus@7.0.6) (2024-05-09) - - -### Bug Fixes - -* Fix incorrect Blockly imports ([#2339](https://github.com/google/blockly-samples/issues/2339)) ([9af40b9](https://github.com/google/blockly-samples/commit/9af40b9ca075275af2b48cedcc1750d458084eb3)) - - - -## [7.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.4...@blockly/block-plus-minus@7.0.5) (2024-04-25) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [7.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.3...@blockly/block-plus-minus@7.0.4) (2024-04-04) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [7.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.2...@blockly/block-plus-minus@7.0.3) (2024-03-28) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [7.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.1...@blockly/block-plus-minus@7.0.2) (2024-02-08) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [7.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@7.0.0...@blockly/block-plus-minus@7.0.1) (2023-12-14) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [7.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.8...@blockly/block-plus-minus@7.0.0) (2023-12-07) - - -### ⚠ BREAKING CHANGES - -* bump min blockly version - -### Bug Fixes - -* bump min blockly version ([1dbf1b8](https://github.com/google/blockly-samples/commit/1dbf1b88ecaa85ddd447d7b120e3aac4c3a48f93)) -* text join block warning when using block-plus-minus plugin ([#2025](https://github.com/google/blockly-samples/issues/2025)) ([7b076df](https://github.com/google/blockly-samples/commit/7b076dfa0c9195a0687962679a6eb431875b37fa)), closes [#2022](https://github.com/google/blockly-samples/issues/2022) [#1877](https://github.com/google/blockly-samples/issues/1877) [#2022](https://github.com/google/blockly-samples/issues/2022) - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.7...@blockly/block-plus-minus@6.0.8) (2023-12-07) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.6...@blockly/block-plus-minus@6.0.7) (2023-11-09) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.5...@blockly/block-plus-minus@6.0.6) (2023-11-02) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.4...@blockly/block-plus-minus@6.0.5) (2023-10-30) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.3...@blockly/block-plus-minus@6.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.2...@blockly/block-plus-minus@6.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.1...@blockly/block-plus-minus@6.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@6.0.0...@blockly/block-plus-minus@6.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@5.0.1...@blockly/block-plus-minus@6.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@5.0.0...@blockly/block-plus-minus@5.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.17...@blockly/block-plus-minus@5.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [4.0.17](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.16...@blockly/block-plus-minus@4.0.17) (2023-06-22) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.16](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.15...@blockly/block-plus-minus@4.0.16) (2023-05-18) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.15](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.14...@blockly/block-plus-minus@4.0.15) (2023-05-11) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.14](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.13...@blockly/block-plus-minus@4.0.14) (2023-05-04) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.13](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.12...@blockly/block-plus-minus@4.0.13) (2023-04-27) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.12](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.11...@blockly/block-plus-minus@4.0.12) (2023-03-23) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.11](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.10...@blockly/block-plus-minus@4.0.11) (2023-03-09) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.10](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.9...@blockly/block-plus-minus@4.0.10) (2023-03-02) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.9](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.8...@blockly/block-plus-minus@4.0.9) (2023-02-23) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.7...@blockly/block-plus-minus@4.0.8) (2023-02-23) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.6...@blockly/block-plus-minus@4.0.7) (2023-02-16) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.5...@blockly/block-plus-minus@4.0.6) (2023-02-09) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.4...@blockly/block-plus-minus@4.0.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.3...@blockly/block-plus-minus@4.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.2...@blockly/block-plus-minus@4.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.1...@blockly/block-plus-minus@4.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@4.0.0...@blockly/block-plus-minus@4.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-plus-minus@3.0.22...@blockly/block-plus-minus@4.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Features - -* convert block-plus-minus :toolbox definition from xml to json ([#1285](https://github.com/google/blockly-samples/issues/1285)) ([d8d1c67](https://github.com/google/blockly-samples/commit/d8d1c676b87ee695ea1f070937651fbabe5377c3)) - - -### Bug Fixes - -* generator imports for use with blockly v9 ([#1305](https://github.com/google/blockly-samples/issues/1305)) ([51d59e9](https://github.com/google/blockly-samples/commit/51d59e98d172400e45fc74755f577e068df9996b)) -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 3.0.22 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 3.0.21 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 3.0.19 (2022-07-21) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## 3.0.18 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 3.0.17 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 3.0.16 (2022-06-21) - -**Note:** Version bump only for package @blockly/block-plus-minus - - - - - -## 3.0.15 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 3.0.14 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/block-plus-minus/README.md b/plugins/block-plus-minus/README.md deleted file mode 100644 index 076a681de..000000000 --- a/plugins/block-plus-minus/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# @blockly/block-plus-minus [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A group of [Blockly](https://www.npmjs.com/package/blockly) blocks that replace the built-in mutator UI with a +/- -based UI. - -Currently this only affects the built-in blocks that use mutators (controls_if, text_join, list_create_with, -procedures_defnoreturn, and procedures_defreturn). - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/If.png) - -But the ability to easily add this to your own mutators may be added -in the future. - -## Installation - -### Yarn - -``` -yarn add @blockly/block-plus-minus -``` - -### npm - -``` -npm install @blockly/block-plus-minus --save -``` - -## Usage - -### Import - -```js -import Blockly from 'blockly'; -import '@blockly/block-plus-minus'; -``` - -### Localization and text customization - -The plus and minus buttons have ARIA labels to communicate their purpose to -screenreaders. These are localizable; additionally, if you want to customize the -labels (for example, to use a different term that "input" for procedure blocks) -you can do so by adjusting the messages: - -```javascript -Blockly.Msg['ARIA_LABEL_ADD_INPUT'] = 'Add parameter'; -// Inject workspace, etc... -``` - -### XML - -Blocks will automatically use the +/- UI when loaded from XML. But here is some example XML incase you are trying to -add specific mutations of blocks: - -#### If - -```xml - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/If.png) - -```xml - - - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/IfElseIf.png) - -```xml - - - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/IfElseIfElse.png) - -#### Text Join - -```xml - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/TextJoin.png) - -```xml - - - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/TextJoinNone.png) - -#### List Create - -```xml - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/ListCreateWith.png) - -```xml - - - -``` - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/block-plus-minus/readme-media/ListCreateWithNone.png) - -## License - -Apache 2.0 diff --git a/plugins/block-plus-minus/package.json b/plugins/block-plus-minus/package.json deleted file mode 100644 index 0695325f0..000000000 --- a/plugins/block-plus-minus/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@blockly/block-plus-minus", - "version": "13.2.0", - "description": "A group of blocks that replace the built-in mutator UI with a +/- based UI.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "unpkg": "./dist/index.js", - "author": "Beka Westberg", - "keywords": [ - "blockly", - "block", - "mutator" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/block-plus-minus#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/block-plus-minus" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "mocha": "^11.7.6", - "sinon": "^22.0.0" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/block-plus-minus/readme-media/AllBlocks.png b/plugins/block-plus-minus/readme-media/AllBlocks.png deleted file mode 100644 index fca021aacdd4c07ffe7a58f07aac10bc10d31bd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17932 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 ojN5HK>}bl^ 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 PxMlEk^>bP0l+XkKH(T=F diff --git a/plugins/block-plus-minus/readme-media/If.png b/plugins/block-plus-minus/readme-media/If.png deleted file mode 100644 index 6c610b9c0cba692415390a6a1da65f2897ab77b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2658 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 diff --git a/plugins/block-plus-minus/readme-media/IfElseIfElse.png b/plugins/block-plus-minus/readme-media/IfElseIfElse.png deleted file mode 100644 index 58f44ae6e82e2c74fe9574a76d45d293cc5fa3f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3518 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 diff --git a/plugins/block-plus-minus/readme-media/ListCreateWith.png b/plugins/block-plus-minus/readme-media/ListCreateWith.png deleted file mode 100644 index 047b187be6e3822e24cb597096fd78d1d6cc6df0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3544 zcmYjUXH*kRvqn&Q7nK%~ASk^gAk`oent(J#q*v*R^e#vVy(1+Q30*0n1nD3xAP^x) z2)#;q4OM!(;r;IY&OLi(XZD$y=j@#Q^K6ukwkjPpJ2eRj37xu{vL4Y-5zUQ~oVc4@ zA4d}%xz#gOWs=LQmET&DLPV(EsTsMGkkH(`vTGz+a8@En;i0YtrC7dBf0Ih^kz(K~ zkdpTrMVx#(iiW9jx4<+&a&ts4BZ>_8rs zgEI8@CQMg6ni~EqJG(KxL6~U#g(qmM{(%q2%?g41;wN1jQ29Kyinv8&Qp(TpqNs>e z#e3Y#*~|XH`QIK2IL1b`aDiyQhdpmQKJg8NK-&6^5#<6(uu~QHeJ-l^B4OVypQKb% zF+rK7xHq|8eCO*XOMFPwDPJ{jGv#f(ADE(DJ+S;U1|4btrS@lj)faK&|;^v%C=ZiAlor{{^7w(ZP zJ>kkUazFy4a79d{OP&3BtzFcR^ODPjl1m>0m+86aR`0dk$+_*8@V-2gfrwRM=JM?D zo?T*nW+q2eFAKwJmj4=iMrWOXJNI)}BTcvQRt;NUs z@H((G;;b;JDZYNxGcS*q^W{+tuYRQEj{&PVTU+tqlhLxEFCC>(>(!q}@?(Ffpjq&~ z25(<$;A?0lC>QGX-<`E$);(->TipTBahh0RW3{B=uD4#n-DPdG>0^PB4+MT&50WOF zOPF&yuK1k(5)2ec7!xfj=ln2#-Zm2wRlb z=;%A~K~x!@x;AO&B6c!9CQSkSH%QI!weY0YI8JAVl(w&_Z#JmKSBn!%W39H<7JZ)H zQP8+1`lnv!I*UtSdcj=KU?us3lut8%tjwkwSr2D#b8*oBPrTE*GOwGZkTDW@GgQOKy0D};e&OQdffu%I?6!J zGOGM|@7VB_&kaY#UcqnBV$g3ba}I8sQrb$SUn*Z2s}L=jbX1F|&fnUxl8;5gqiyl`QF2tp?EJ$Nf61dIK4Wh5);Ny> zyqZjOq-1JlCq&Y%equ_jTtxdg9vAEO|4#CwsmC<0P0j|M(x8>!+UAObny{y^;gIud z0f?ort|Wh&SI6Z_ZKmmu2p%=1HW$m7_{Wd9By-!ptiH19UwS+H%5$oZFgK(8#{V)W zXFfSRHB%lQSeu4=Ov0dgxNd1nIg@sy&8oFyZjH9eZrvQcX%>CULzH$H?|3m1NJ zosaVL<*cU{w`xU?Sg$(NYMb;>u!~w5*CsdOUn_E#nh;7YLv3^p0&muV-L^BVfh6%5 z8Jk=ThtnOsBTGSr0a|lSM~U?^?z5-Xv`sBXrly>;gw8@AzR4H&C?9I9O^R#o{+S_bU`X34?Sl2VWRzTZz&Gc(3TF^4<1i6 zi>dUcCqG#`tB&~|4ILZf5VI+<1apWLJ0QiGP-O^R@?sNVHky~nip8b_N{cb^y=uBc z_i|tE>^#%H_DZgzhN-BE6<|sBIq1awO>;_;B%Z~VZ{9?Tp$Rimd@Ayb7k}UDzCIih zK}e*?0DT;~ChFB!&ySe9Lz0u8>8j&+x1)K1r_GLrTxl(Zc_)FN$pJ&ytqJzVE@OgE z#}O>)tjNQrAo?XtN2hFUU+q+t|3&jb?<+#8;#AGZ6pH}6hB6IkKPa9w5pO1;j z7HVtQ*Ud#AS~<0AK99^vR}sEtEL=EUj>vOfw7^byW^+-0Y?GV*W-r}|N@)!6e{uJj zM(o#s#>ATF+CTVx-p#4j;msiDHjU^{Y+^z`ts(1$g1@u~uX&Dn*)k$?;G4PYL(A(b z7`Z89${SC20I2G66|nQjD1J8B{5$yfwphB|JqU*^z_28Jr3J|w_uG4TW`djGIvt`! zi?{qEoGaL_g{W(TuaE`LCrT!iCo`^k1)&$>1py#$@q{7=Ds68gL-`3)9eDPj+FU&y z6E;hu{F#Wm)!Ro0nQa-<0gmGwYqHxnTp~H^u0?nz?AhgH0%tzexn&Q3F)7Bf7mU}y zQcW04XM$8bMBtu#zJ&sGMa{ReB?7B~TG@#(2;)pO^z5;*-g{uveFC@{5`y+HGq)Hx ze08VJtZ*o|bKuhte&K-*13kqdKF~Tng%r+1zuqj%xK|AKa(6JxMDuv>m7ZZ|iWA*+ z)4OMnAw1U<_+p~q27rhHQb%*MST?nmCUV{HvFo6Rl>L)Yleo@-%JF$G%?dtu(5j< zT<;Ul)C@aQKODPAx^(WF{im%&^0fiKxx3XWo5z09SWA5(EvaD2rJ&Mvb4{9)<1$O|2d;B;gj2Z_B!y;16X52x9;o5l54)OoasZDq=}d8( z@#&N4z)RC>=rq-y(y=a*x6sl{ z(Fq$(MFzOapWV(AB=C6d{RfZ}5?)4|p7I{~df$3GZ9nReoqH6A@TBLCF&W9{aUM#Y z+o`8@8t*u23eOWEP9t$Ue{Y-l=(ZW>zoN11;v= z1zm1esUc27qBQL0q57|q{J-cuby#9G6}RQhE8z%(eJh0tDYw8*qtQy;G2g2G-@)Ec zIXy{haB`nrxdB)crZuQHLQGrUtd(*esr)w>{YY#k0$`W_%_K{4Cn+j^=TkQ54uslp zFGA}CfzKwozosQ8$JZk;IyGM{wjH6%&(6DiRC|xD69A?fYH>DD8>;M#`oB^AocQ2e z(A*JX;UpSO#V))GY0x!oR#GAAUZ?<&X6J+Y6=!Og7E$|NDc)|=#2Gd2O-Njbl(ntaz_)JZN^+Sz4rZmA&;ZOER!RNjZwe;TBM% zQ0)t&E)e=U945g(D$q^FcNOaEGGsHa_;VfitC=&I2pFnF z_r?05l6)#w?O%ESpFzU@JJP?Av9f(-0P%(VJ3eCv?va{vz4ADIeM)< zb7kVJ5|S!iRlS|!5QD{?E<^*z!WgTZ$Pn3P3p<-Hak_uxWH1snJ@b^snRb&r`Z;L0 zxlDpY&5T6AhRe7+gObo){rkl$i`;B@a0A=W=HGJ87$>R4c^_BLS)1ECjPcG{*BiE`YOmNWYSrFatEvsLN6b(&MzvIHw~bXL zVsEu;M63L5um6Yl>wC_7?s@KWp5MLa+^;wOp`I2q6CV>56&15K5@C4Ztrt>YxO~xH zc3@90?6SR%7J};h-zsP+O}QY9UPyBvDyl0S|B9L_8^?PA>3y|zHR+dVSvZ&&dzd}j zFJ`{l2sNX?$*tV52bN>NI3b749T%@l)n0H*>Kp32)Rl#@C^c>Jof6CP`)?oK^c8eZ zcSe-trNa&_qPjHG;jN9$M39kNG!L!erG}+jwGkYBg{i>x^wK@B{H1oKxjyG~o2rclYG0e~87Jq9Slb^}2 zEd|9_MojWjBBtK_dkPv+>#YLGE6Lh@V}DQ@3YtvUMe?_pRcsTa7h;Pu-6aZ;5sSyK zt_p)d3o8tBr^~#BeGBDdtp@R?`N!flXU!tc;h$;Z!ob!0LP6iVX>v?{cRLWLd{A<; z{fly!x##Y0-)$r!jALFc1?D6-`!@bVR^n`Vp5hM7@t@XITiFCFj0qtUrhY}g7&7k6 zR|H96^vw$G&{kVwrI4Cn?h_u-n@hXoq@~WGH49iJM^_r@0BYOgh|KWBYd%fK^iCS5 zR+$vuc+odHK)S0^(v_>d?8e_ypC?=!3=Cp|QpVc4dZ@X?UAI?2WWgsg9UC9JvsPFz z{)Y@Sj!U)G9$atLR)P}n{(sD48Vyxd<|5&rjIsu11tD-a<1~q zl;$;3ELc_B#YjWLF}38<;Z2ihe;_bRmFgqUK%z`X=Uh^PIX&W*w5PrTQO>JNPtMh`EZYmD8J zyWcx$p|DPy2OB6qDr>=1alYJa!O_-FAG-p?k7VX-`Z#Vod}PEy6&P%-O_V&tLXynlmv! zwF)faewC5&T@XivmZgeCR4{7CA}YI>lTNKI`pb4!_rV#Pp!;b(8oE@5+z$eJ*-UUZ z?AbL?I~pRQrAq^DO@aB|4MNf+sw-F0KDjX8T!w7AlmQD?1EEcCmyJfs4IY;iNtcm| zd+R{-)j+ivCU=a0aX1|`r`jcvjgRiHj_GH20*E=rUtx+rU3W@Ks}N8JQ=*<$g+zA= zX08x~k>NrPkHls^U|-I!?>^|O09j$E;tyT#0Bm>~r4w>zvqK;5b_*r z)NMKIsXp$J9GRBY5 z72f6&&&{rS3%V_OSA{bNJVPVJ+8^l5~C45WPoB_|D7bf|D+@}V8m@a6wP9B%5E~8IsV>8 zcYI4^ja7!*ut?6eN6(<(hb3z7QGgv4yO=D*Fg4OpQ>}?5EH-1?fdwM-CveN~*k&QkqgJ%Amx@{ zKH7sxqQ-^PuxT1~22mEjjW>_hf6uAK-(N@ zteAd87_kMh;a2)^n9JaU8}OF;$EsC@(Ao@;%;O^}_!}V-IPH(BA6-cn8}FZ;fmnG9 z3AK3v$$p)(@IYpzG5vHI$$al@dlTMa@K52VTdS|Fqt@f)ig%?vajbj_*N!;pDuvrK*uVjPqG8;2CBkRFNymm#u2FtQvyT3InN2+cS0p>q5PCG+Yb zRYt$w?%9CoC{s93Zo0QT0qUSb6l-qwjNG}zgyyE8sl)94`8s>Hr3Luh#fVZSo(dON za{vCWlVjctu3sPUJZ;%W!}Yw4*V65ZF1HOGQSa$yID@3`uE}` Or_$EcLsYBVzW5KvsloLC diff --git a/plugins/block-plus-minus/readme-media/TextJoin.png b/plugins/block-plus-minus/readme-media/TextJoin.png deleted file mode 100644 index a25561891b7cde927085c04b9e107ee86e18d82b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3550 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 diff --git a/plugins/block-plus-minus/readme-media/TextJoinNone.png b/plugins/block-plus-minus/readme-media/TextJoinNone.png deleted file mode 100644 index 99915d566966b1decb384ba81efd6cc586b5c386..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1497 zcmZvcc{J1u6vuzEPm!!+8%r|EI>NI>q?kxaWG68^+rxyhFL|=fsE0w>^%`Xv>j)!5 zG>&buJY{*q43jL4r8%;MH@)}IJMX-6&-Z@M{r++9x&M4JZrNH2fTTbG00_XXEN-(s zfh{9G9(L~{nA~L>kGHj@1#tYM%DZs6?1Vqm${7g&Cq;gU19(~tW{12F;5V-FE^!Hp zfbCKMszpQCE%c>?AD9 z4PRe5a$2ca+l@bJpTm#fqbSSF=mZKfSkf75W*k>t&2MFFM&}p4`52YbC!$m;zr~dS z{cn^?Z#e#gH-3BQv^Hm&i?LZ6x2cKKwsvk4T~f<`t@E1l#>3STSH?s{tZ4pC_eI~t z^PCNQ$Y*B1zQk7V*ykbtNoz#KG?gDmsTzPS7d181Ak@ECCN0V?SBBY+(3=_3UJEVy zGgR$QaqJ7I`?RLdM@98n`k`;m#9+v!4C%_P)~~M`KD}pVC>&8{L--U{=J#--Btq`I zBDqk*i1>Cu`}w*2?nsOP@`bHs7(#DHr^IR>h0K=x=+G?Q#WW+%-jYMtI9!P9+Sc`- zRP(q*kVvotBS-1A>xG9GtPL<9ujATs z2l2}-uvwqI>JD)Zcps+oIVWkgiQCH|fSB;TCY3#T9_=D+K1eQXQZuvsq$i;7WGPxn zLfG4t4d;iR@yHI*vaq?YJHcbs&c?sgB`xl#&w=)ZM`uy3vflb!Sq5^x?fnDexMYq6 zR`e#7@~FXU#s(ZMd*P&C(!Ih-3C*1BEOV>&)%d2KR9$3{mOl!(Y?o%xQRhmO0v2+) zWQd`9G?*zRj~l2~X(2tePr{ZCeU20)1!n!7AxOXCpNg2oWI2uY5#-|r1)uiwQXrAenz{>=ftf~9Y z=%PVwV2Y9`p8Pm{=csg20>7xw{_alpb=cmG9cz_A9ZNE+(&i#d3X%XPMSK$iNSZuj zKHYht%$_G5i&SqsnUS7#a~$fJw`u^1y&IGwDo7i+bTQ?0!IU|UwmFqEZ&SQd3>HlG zbLLXAD~jMKgT9Et*Tis4t-pNDg!GPHoQLMewghyLza)7IhrU=-e5J-1L*WBMhob{) z#he@nKxw(0tL?g_e)zJoN|6rt#z#kU$`E(CBd0%~K7@Hz7^G7%zu4Pva!`nrYBiKOtm4LLw7u&SC>D1gO;|r@<$x$? zX^eWpwp_5Bc#P*0P?qAPOu>VMZgBRrvU@?Ql1^lfN#t>4^V*wmNJyZRE*17Z3zJL@ zi=e40Q;V^JQ6%XL7!AQKX@zR`@_K z*bg$IiLfEoW9=I!XG9unc$4O`;ln*68|41IuuYvz)a9su$Yji-_lrh{TlSaq1|=fI v?7NVvhv-lG$rar?zt{giu>Q?3^ROcxhQeqSystN(4PgL&)z+fk+$-fTA*s&{ diff --git a/plugins/block-plus-minus/src/field_minus.js b/plugins/block-plus-minus/src/field_minus.js deleted file mode 100644 index 990a354b4..000000000 --- a/plugins/block-plus-minus/src/field_minus.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A function that creates a minus button used for mutation. - */ -'use strict'; - -import * as Blockly from 'blockly/core'; -import {getExtraBlockState} from './serialization_helper'; - -/** - * Creates a minus image field used for mutation. - * @param {!String} altText An accessibility label for the minus button. - * @param {Object=} args Untyped args passed to block.minus when the field - * is clicked. - * @returns {Blockly.FieldImage} The minus field. - */ -export function createMinusField(altText, args = undefined) { - const minus = new Blockly.FieldImage(minusImage, 15, 15, altText, onClick_); - /** - * Untyped args passed to block.minus when the field is clicked. - * @type {?(Object|undefined)} - * @private - */ - minus.args_ = args; - return minus; -} - -/** - * Calls block.minus(args) when the minus field is clicked. - * @param {Blockly.FieldImage} minusField The field being clicked. - * @private - */ -function onClick_(minusField) { - // TODO: This is a dupe of the mutator code, anyway to unify? - const block = minusField.getSourceBlock(); - - if (block.isInFlyout) { - return; - } - - Blockly.Events.setGroup(true); - const oldExtraState = getExtraBlockState(block); - block.minus(minusField.args_); - const newExtraState = getExtraBlockState(block); - - if (oldExtraState != newExtraState) { - Blockly.Events.fire( - new Blockly.Events.BlockChange( - block, - 'mutation', - null, - oldExtraState, - newExtraState, - ), - ); - } - Blockly.Events.setGroup(false); -} - -const minusImage = - 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAw' + - 'MC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cGF0aCBkPS' + - 'JNMTggMTFoLTEyYy0xLjEwNCAwLTIgLjg5Ni0yIDJzLjg5NiAyIDIgMmgxMmMxLjEwNCAw' + - 'IDItLjg5NiAyLTJzLS44OTYtMi0yLTJ6IiBmaWxsPSJ3aGl0ZSIgLz48L3N2Zz4K'; diff --git a/plugins/block-plus-minus/src/field_plus.js b/plugins/block-plus-minus/src/field_plus.js deleted file mode 100644 index df15364a7..000000000 --- a/plugins/block-plus-minus/src/field_plus.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A field for a plus button used for mutation. - */ -'use strict'; - -import * as Blockly from 'blockly/core'; -import {getExtraBlockState} from './serialization_helper'; - -/** - * Creates a plus image field used for mutation. - * @param {!String} altText An accessibility label for the plus button. - * @param {Object=} args Untyped args passed to block.minus when the field - * is clicked. - * @returns {Blockly.FieldImage} The Plus field. - */ -export function createPlusField(altText, args = undefined) { - const plus = new Blockly.FieldImage(plusImage, 15, 15, altText, onClick_); - /** - * Untyped args passed to block.plus when the field is clicked. - * @type {?(Object|undefined)} - * @private - */ - plus.args_ = args; - return plus; -} - -/** - * Calls block.plus(args) when the plus field is clicked. - * @param {!Blockly.FieldImage} plusField The field being clicked. - * @private - */ -function onClick_(plusField) { - // TODO: This is a dupe of the mutator code, anyway to unify? - const block = plusField.getSourceBlock(); - - if (block.isInFlyout) { - return; - } - - Blockly.Events.setGroup(true); - const oldExtraState = getExtraBlockState(block); - block.plus(plusField.args_); - const newExtraState = getExtraBlockState(block); - - if (oldExtraState != newExtraState) { - Blockly.Events.fire( - new Blockly.Events.BlockChange( - block, - 'mutation', - null, - oldExtraState, - newExtraState, - ), - ); - } - Blockly.Events.setGroup(false); -} - -const plusImage = - 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC' + - '9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cGF0aCBkPSJNMT' + - 'ggMTBoLTR2LTRjMC0xLjEwNC0uODk2LTItMi0ycy0yIC44OTYtMiAybC4wNzEgNGgtNC4wNz' + - 'FjLTEuMTA0IDAtMiAuODk2LTIgMnMuODk2IDIgMiAybDQuMDcxLS4wNzEtLjA3MSA0LjA3MW' + - 'MwIDEuMTA0Ljg5NiAyIDIgMnMyLS44OTYgMi0ydi00LjA3MWw0IC4wNzFjMS4xMDQgMCAyLS' + - '44OTYgMi0ycy0uODk2LTItMi0yeiIgZmlsbD0id2hpdGUiIC8+PC9zdmc+Cg=='; diff --git a/plugins/block-plus-minus/src/if.js b/plugins/block-plus-minus/src/if.js deleted file mode 100644 index 5bf48db47..000000000 --- a/plugins/block-plus-minus/src/if.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Changes the if block to use a +/- mutator UI. - */ - -import * as Blockly from 'blockly/core'; -import {createMinusField} from './field_minus'; -import {createPlusField} from './field_plus'; - -const controlsIfMutator = { - /** - * Number of else-if inputs on this block. - * @type {number} - */ - elseIfCount_: 0, - /** - * Whether this block has an else input or not. - * @type {boolean} - */ - hasElse_: false, - - /** - * Creates XML to represent the number of else-if and else inputs. - * @returns {Element} XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - if (!this.elseIfCount_ && !this.hasElse_) { - return null; - } - const container = Blockly.utils.xml.createElement('mutation'); - container.setAttribute('elseif', this.elseIfCount_); - if (this.hasElse_) { - // Has to be stored as an int for backwards compat. - container.setAttribute('else', 1); - } - return container; - }, - - /** - * Parses XML to restore the else-if and else inputs. - * @param {!Element} xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - const targetCount = parseInt(xmlElement.getAttribute('elseif'), 10) || 0; - this.hasElse_ = !!parseInt(xmlElement.getAttribute('else'), 10) || 0; - if (this.hasElse_ && !this.getInput('ELSE')) { - this.appendStatementInput('ELSE').appendField( - Blockly.Msg['CONTROLS_IF_MSG_ELSE'], - ); - } - this.updateShape_(targetCount); - }, - - /** - * Returns the state of this block as a JSON serializable object. - * @returns {{elseIfCount: (number|undefined), - * haseElse: (boolean|undefined)}} The state of this block, ie the else - * if count and else state. - */ - saveExtraState: function () { - if (!this.elseIfCount_ && !this.hasElse_) { - return null; - } - const state = Object.create(null); - if (this.elseIfCount_) { - state['elseIfCount'] = this.elseIfCount_; - } - if (this.hasElse_) { - state['hasElse'] = true; - } - return state; - }, - - /** - * Applies the given state to this block. - * @param {*} state The state to apply to this block, ie the else if count and - * else state. - */ - loadExtraState: function (state) { - const targetCount = state['elseIfCount'] || 0; - this.hasElse_ = state['hasElse'] || false; - if (this.hasElse_ && !this.getInput('ELSE')) { - this.appendStatementInput('ELSE').appendField( - Blockly.Msg['CONTROLS_IF_MSG_ELSE'], - ); - } - this.updateShape_(targetCount); - }, - - /** - * Adds else-if and do inputs to the block until the block matches the - * target else-if count. - * @param {number} targetCount The target number of else-if inputs. - * @this {Blockly.Block} - * @private - */ - updateShape_: function (targetCount) { - while (this.elseIfCount_ < targetCount) { - this.addElseIf_(); - } - while (this.elseIfCount_ > targetCount) { - this.removeElseIf_(); - } - }, - - /** - * Callback for the plus field. Adds an else-if input to the block. - */ - plus: function () { - this.addElseIf_(); - }, - - /** - * Callback for the minus field. Triggers "removing" the input at the specific - * index. - * @see removeInput_ - * @param {number} index The index of the else-if input to "remove". - * @this {Blockly.Block} - */ - minus: function (index) { - if (this.elseIfCount_ == 0) { - return; - } - this.removeElseIf_(index); - }, - - /** - * Adds an else-if and a do input to the bottom of the block. - * @this {Blockly.Block} - * @private - */ - addElseIf_: function () { - // Because else-if inputs are 1-indexed we increment first, decrement last. - this.elseIfCount_++; - this.appendValueInput('IF' + this.elseIfCount_) - .setCheck('Boolean') - .appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSEIF']) - .appendField( - createMinusField( - Blockly.Msg['ARIA_LABEL_REMOVE_ELSE_IF'], - this.elseIfCount_, - ), - 'MINUS' + this.elseIfCount_, - ); - this.appendStatementInput('DO' + this.elseIfCount_).appendField( - Blockly.Msg['CONTROLS_IF_MSG_THEN'], - ); - - // Handle if-elseif-else block. - if (this.getInput('ELSE')) { - this.moveInputBefore('ELSE', /* put at end */ null); - } - }, - - /** - * Appears to remove the input at the given index. Actually shifts attached - * blocks and then removes the input at the bottom of the block. This is to - * make sure the inputs are always IF0, IF1, etc with no gaps. - * @param {?number=} index The index of the input to "remove", or undefined - * to remove the last input. - * @this {Blockly.Block} - * @private - */ - removeElseIf_: function (index = undefined) { - // The strategy for removing a part at an index is to: - // - Kick any blocks connected to the relevant inputs. - // - Move all connect blocks from the other inputs up. - // - Remove the last input. - // This makes sure all of our indices are correct. - - if (index !== undefined && index != this.elseIfCount_) { - // Each else-if is two inputs on the block: - // the else-if input and the do input. - const elseIfIndex = index * 2; - const inputs = this.inputList; - let connection = inputs[elseIfIndex].connection; // If connection. - if (connection.isConnected()) { - connection.disconnect(); - } - connection = inputs[elseIfIndex + 1].connection; // Do connection. - if (connection.isConnected()) { - connection.disconnect(); - } - this.bumpNeighbours(); - for (let i = elseIfIndex + 2, input; (input = this.inputList[i]); i++) { - if (input.name == 'ELSE') { - break; // Should be last, so break. - } - const targetConnection = input.connection.targetConnection; - if (targetConnection) { - this.inputList[i - 2].connection.connect(targetConnection); - } - } - } - - this.removeInput('IF' + this.elseIfCount_); - this.removeInput('DO' + this.elseIfCount_); - // Because else-if inputs are 1-indexed we increment first, decrement last. - this.elseIfCount_--; - }, -}; - -/** - * Adds the initial plus button to the if block. - * @this {Blockly.Block} - */ -const controlsIfHelper = function () { - this.getInput('IF0').insertFieldAt( - 0, - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_ELSE_IF']), - 'PLUS', - ); -}; - -if (Blockly.Extensions.isRegistered('controls_if_mutator')) { - Blockly.Extensions.unregister('controls_if_mutator'); -} -Blockly.Extensions.registerMutator( - 'controls_if_mutator', - controlsIfMutator, - controlsIfHelper, -); diff --git a/plugins/block-plus-minus/src/index.js b/plugins/block-plus-minus/src/index.js deleted file mode 100644 index 5e2cb3c17..000000000 --- a/plugins/block-plus-minus/src/index.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Adds blocks that replace the built-in mutator UI with a +/- UI. - */ - -import './if.js'; -import './list_create.js'; -import './procedures.js'; -import './text_join'; diff --git a/plugins/block-plus-minus/src/list_create.js b/plugins/block-plus-minus/src/list_create.js deleted file mode 100644 index 85cd33c52..000000000 --- a/plugins/block-plus-minus/src/list_create.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Changes the list_create block to use a +/- mutator UI. - */ - -import * as Blockly from 'blockly/core'; -import {createPlusField} from './field_plus'; -import {createMinusField} from './field_minus'; - -// Delete original block because there's no way to unregister it: -// https://github.com/RaspberryPiFoundation/blockly-samples/issues/768#issuecomment-885663394 -delete Blockly.Blocks['lists_create_with']; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'lists_create_with', - message0: '%{BKY_LISTS_CREATE_EMPTY_TITLE} %1', - args0: [ - { - type: 'input_dummy', - name: 'EMPTY', - }, - ], - output: 'Array', - style: 'list_blocks', - helpUrl: '%{BKY_LISTS_CREATE_WITH_HELPURL}', - tooltip: '%{BKY_LISTS_CREATE_WITH_TOOLTIP}', - mutator: 'new_list_create_with_mutator', - }, -]); - -const listCreateMutator = { - /** - * Number of item inputs the block has. - * @type {number} - */ - itemCount_: 0, - - /** - * Creates XML to represent number of text inputs. - * @returns {!Element} XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - const container = Blockly.utils.xml.createElement('mutation'); - container.setAttribute('items', this.itemCount_); - return container; - }, - /** - * Parses XML to restore the text inputs. - * @param {!Element} xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - const targetCount = parseInt(xmlElement.getAttribute('items'), 10); - this.updateShape_(targetCount); - }, - - /** - * Returns the state of this block as a JSON serializable object. - * @returns {{itemCount: number}} The state of this block, ie the item count. - */ - saveExtraState: function () { - return { - itemCount: this.itemCount_, - }; - }, - - /** - * Applies the given state to this block. - * @param {*} state The state to apply to this block, ie the item count. - */ - loadExtraState: function (state) { - this.updateShape_(state['itemCount']); - }, - - /** - * Adds inputs to the block until it reaches the target number of inputs. - * @param {number} targetCount The target number of inputs for the block. - * @this {Blockly.Block} - * @private - */ - updateShape_: function (targetCount) { - while (this.itemCount_ < targetCount) { - this.addPart_(); - } - while (this.itemCount_ > targetCount) { - this.removePart_(); - } - this.updateMinus_(); - }, - - /** - * Callback for the plus image. Adds an input to the end of the block and - * updates the state of the minus. - */ - plus: function () { - this.addPart_(); - this.updateMinus_(); - }, - - /** - * Callback for the minus image. Removes an input from the end of the block - * and updates the state of the minus. - */ - minus: function () { - if (this.itemCount_ == 0) { - return; - } - this.removePart_(); - this.updateMinus_(); - }, - - // To properly keep track of indices we have to increment before/after adding - // the inputs, and decrement the opposite. - // Because we want our first input to be ADD0 (not ADD1) we increment after. - - /** - * Adds an input to the end of the block. If the block currently has no - * inputs it updates the top 'EMPTY' input to receive a block. - * @this {Blockly.Block} - * @private - */ - addPart_: function () { - if (this.itemCount_ == 0) { - this.removeInput('EMPTY'); - this.topInput_ = this.appendValueInput('ADD' + this.itemCount_) - .appendField( - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_LIST_ITEM']), - 'PLUS', - ) - .appendField(Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH']); - } else { - this.appendValueInput('ADD' + this.itemCount_); - } - this.itemCount_++; - }, - - /** - * Removes an input from the end of the block. If we are removing the last - * input this updates the block to have an 'EMPTY' top input. - * @this {Blockly.Block} - * @private - */ - removePart_: function () { - this.itemCount_--; - this.removeInput('ADD' + this.itemCount_); - if (this.itemCount_ == 0) { - this.topInput_ = this.appendDummyInput('EMPTY') - .appendField( - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_LIST_ITEM']), - 'PLUS', - ) - .appendField(Blockly.Msg['LISTS_CREATE_EMPTY_TITLE']); - } - }, - - /** - * Makes it so the minus is visible iff there is an input available to remove. - * @private - */ - updateMinus_: function () { - const minusField = this.getField('MINUS'); - if (!minusField && this.itemCount_ > 0) { - this.topInput_.insertFieldAt( - 1, - createMinusField(Blockly.Msg['ARIA_LABEL_REMOVE_LIST_ITEM']), - 'MINUS', - ); - } else if (minusField && this.itemCount_ < 1) { - this.topInput_.removeField('MINUS'); - } - }, -}; - -/** - * Updates the shape of the block to have 3 inputs if no mutation is provided. - * @this {Blockly.Block} - */ -const listCreateHelper = function () { - this.getInput('EMPTY').insertFieldAt( - 0, - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_LIST_ITEM']), - 'PLUS', - ); - this.updateShape_(3); -}; - -Blockly.Extensions.registerMutator( - 'new_list_create_with_mutator', - listCreateMutator, - listCreateHelper, -); diff --git a/plugins/block-plus-minus/src/procedures.js b/plugins/block-plus-minus/src/procedures.js deleted file mode 100644 index a00034bac..000000000 --- a/plugins/block-plus-minus/src/procedures.js +++ /dev/null @@ -1,694 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Changes the procedure blocks to use a +/- mutator UI. - */ - -import * as Blockly from 'blockly/core'; -import {createMinusField} from './field_minus'; -import {createPlusField} from './field_plus'; - -Blockly.Msg['PROCEDURE_VARIABLE'] = 'variable:'; - -// Delete original blocks because there's no way to unregister them: -// https://github.com/RaspberryPiFoundation/blockly-samples/issues/768#issuecomment-885663394 -delete Blockly.Blocks['procedures_defnoreturn']; -delete Blockly.Blocks['procedures_defreturn']; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'procedures_defnoreturn', - message0: '%{BKY_PROCEDURES_DEFNORETURN_TITLE} %1 %2', - message1: '%{BKY_PROCEDURES_DEFNORETURN_DO} %1', - args0: [ - { - type: 'field_input', - name: 'NAME', - text: '', - }, - { - type: 'input_dummy', - name: 'TOP', - }, - ], - args1: [ - { - type: 'input_statement', - name: 'STACK', - }, - ], - style: 'procedure_blocks', - helpUrl: '%{BKY_PROCEDURES_DEFNORETURN_HELPURL}', - tooltip: '%{BKY_PROCEDURES_DEFNORETURN_TOOLTIP}', - extensions: [ - 'get_procedure_def_no_return', - 'procedure_context_menu', - 'procedure_rename', - 'procedure_vars', - ], - mutator: 'procedure_def_mutator', - }, - { - type: 'procedures_defreturn', - message0: '%{BKY_PROCEDURES_DEFRETURN_TITLE} %1 %2', - message1: '%{BKY_PROCEDURES_DEFRETURN_DO} %1', - message2: '%{BKY_PROCEDURES_DEFRETURN_RETURN} %1', - args0: [ - { - type: 'field_input', - name: 'NAME', - text: '', - }, - { - type: 'input_dummy', - name: 'TOP', - }, - ], - args1: [ - { - type: 'input_statement', - name: 'STACK', - }, - ], - args2: [ - { - type: 'input_value', - align: 'right', - name: 'RETURN', - }, - ], - style: 'procedure_blocks', - helpUrl: '%{BKY_PROCEDURES_DEFRETURN_HELPURL}', - tooltip: '%{BKY_PROCEDURES_DEFRETURN_TOOLTIP}', - extensions: [ - 'get_procedure_def_return', - 'procedure_context_menu', - 'procedure_rename', - 'procedure_vars', - ], - mutator: 'procedure_def_mutator', - }, -]); - -/** - * Defines the what are essentially info-getters for the procedures_defnoreturn - * block. - * @type {{callType_: string, getProcedureDef: (function(): Array)}} - */ -const getDefNoReturn = { - /** - * Returns info about this block to be used by the Blockly.Procedures. - * @returns {Array} An array of info. - * @this {Blockly.Block} - */ - getProcedureDef: function () { - const argNames = this.argData_.map((elem) => elem.model.name); - return [this.getFieldValue('NAME'), argNames, false]; - }, - - /** - * Used by the context menu to create a caller block. - * @type {string} - */ - callType_: 'procedures_callnoreturn', -}; - -Blockly.Extensions.registerMixin('get_procedure_def_no_return', getDefNoReturn); - -/** - * Defines what are essentially info-getters for the procedures_def_return - * block. - * @type {{callType_: string, getProcedureDef: (function(): Array)}} - */ -const getDefReturn = { - /** - * Returns info about this block to be used by the Blockly.Procedures. - * @returns {Array} An array of info. - * @this {Blockly.Block} - */ - getProcedureDef: function () { - const argNames = this.argData_.map((elem) => elem.model.name); - return [this.getFieldValue('NAME'), argNames, true]; - }, - /** - * Used by the context menu to create a caller block. - * @type {string} - */ - callType_: 'procedures_callreturn', -}; - -Blockly.Extensions.registerMixin('get_procedure_def_return', getDefReturn); - -const procedureContextMenu = { - /** - * Adds an option to create a caller block. - * Adds an option to create a variable getter for each variable included in - * the procedure definition. - * @this {Blockly.Block} - * @param {!Array} options The current options for the context menu. - */ - customContextMenu: function (options) { - if (this.isInFlyout) { - return; - } - - // Add option to create caller. - const name = this.getFieldValue('NAME'); - const text = Blockly.Msg['PROCEDURES_CREATE_DO'].replace('%1', name); - - const xml = Blockly.utils.xml.createElement('block'); - xml.setAttribute('type', this.callType_); - xml.appendChild(this.mutationToDom(true)); - const callback = Blockly.ContextMenu.callbackFactory(this, xml); - - options.push({ - enabled: true, - text: text, - callback: callback, - }); - - if (this.isCollapsed()) { - return; - } - - // Add options to create getters for each parameter. - const varModels = this.getVarModels(); - for (const model of varModels) { - const text = Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace( - '%1', - model.name, - ); - - const xml = Blockly.utils.xml.createElement('block'); - xml.setAttribute('type', 'variables_get'); - xml.appendChild(Blockly.Variables.generateVariableFieldDom(model)); - const callback = Blockly.ContextMenu.callbackFactory(this, xml); - - options.push({ - enabled: true, - text: text, - callback: callback, - }); - } - }, -}; - -Blockly.Extensions.registerMixin( - 'procedure_context_menu', - procedureContextMenu, -); - -const procedureDefMutator = { - /** - * Create XML to represent the argument inputs. - * @param {boolean=} isForCaller If true include the procedure name and - * argument IDs. Used by Blockly.Procedures.mutateCallers for - * reconnection. - * @returns {!Element} XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function (isForCaller = false) { - const container = Blockly.utils.xml.createElement('mutation'); - if (isForCaller) { - container.setAttribute('name', this.getFieldValue('NAME')); - } - this.argData_.forEach((element) => { - const argument = Blockly.utils.xml.createElement('arg'); - const argModel = element.model; - argument.setAttribute('name', argModel.name); - argument.setAttribute('varid', argModel.getId()); - argument.setAttribute('argid', element.argId); - if (isForCaller) { - argument.setAttribute('paramid', element.argId); - } - container.appendChild(argument); - }); - - // Not used by this block, but necessary if switching back and forth - // between this mutator UI and the default UI. - if (!this.hasStatements_) { - container.setAttribute('statements', 'false'); - } - - return container; - }, - - /** - * Parse XML to restore the argument inputs. - * @param {!Element} xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - // We have to handle this so that the user doesn't add blocks to the stack, - // in which case it would be impossible to return to the old mutators. - this.hasStatements_ = xmlElement.getAttribute('statements') !== 'false'; - if (!this.hasStatements_) { - this.removeInput('STACK'); - } - - const names = []; - const varIds = []; - const argIds = []; - for (const childNode of xmlElement.childNodes) { - if (childNode.nodeName.toLowerCase() == 'arg') { - names.push(childNode.getAttribute('name')); - varIds.push( - childNode.getAttribute('varid') || childNode.getAttribute('varId'), - ); - argIds.push(childNode.getAttribute('argid')); - } - } - this.updateShape_(names, varIds, argIds); - }, - - /** - * Returns the state of this block as a JSON serializable object. - * @returns {{params: (!Array<{name: string, id: string}>|undefined), - * hasStatements: (boolean|undefined)}} The state of this block, eg the - * parameters and statements. - */ - saveExtraState: function () { - if (!this.argData_.length && this.hasStatements_) { - return null; - } - - const state = Object.create(null); - if (this.argData_.length) { - state['params'] = []; - this.argData_.forEach((arg) => { - const model = arg.model; - state['params'].push({ - name: model.name, - id: model.getId(), - argId: arg.argId, - }); - }); - } - if (!this.hasStatements_) { - state['hasStatements'] = false; - } - return state; - }, - - /** - * Applies the given state to this block. - * @param {*} state The state to apply to this block, eg the parameters and - * statements. - */ - loadExtraState: function (state) { - // We have to handle this so that the user doesn't add blocks to the stack, - // in which case it would be impossible to return to the old mutators. - this.hasStatements_ = state['hasStatements'] !== false; - if (!this.hasStatements_) { - this.removeInput('STACK'); - } - - const names = []; - const varIds = []; - const argIds = []; - if (state['params']) { - for (let i = 0; i < state['params'].length; i++) { - const param = state['params'][i]; - names.push(param['name']); - varIds.push(param['id']); - argIds.push(param['argId']); - } - } - this.updateShape_(names, varIds, argIds); - }, - - /** - * Adds arguments to the block until it matches the targets. - * @param {!Array} names An array of argument names to display. - * @param {!Array} varIds An array of variable IDs associated with - * those names. - * @param {!Array} argIds An array of argument IDs associated with - * those names. - * @this {Blockly.Block} - * @private - */ - updateShape_: function (names, varIds, argIds) { - if (names.length != varIds.length) { - throw Error('names and varIds must have the same length.'); - } - // Usually it's more efficient to modify the block, rather than tearing it - // down and rebuilding (less render calls), but in this case it's easier - // to just work from scratch. - - // We need to remove args in reverse order so that it doesn't mess up - // as removeArg_ modifies our array. - for (let i = this.argData_.length - 1; i >= 0; i--) { - this.removeArg_(this.argData_[i].argId); - } - this.argData_ = []; - const length = varIds.length; - for (let i = 0; i < length; i++) { - this.addArg_(names[i], varIds[i], argIds[i]); - } - Blockly.Procedures.mutateCallers(this); - }, - - /** - * Callback for the plus image. Adds an argument to the block and mutates - * callers to match. - */ - plus: function () { - this.addArg_(); - Blockly.Procedures.mutateCallers(this); - }, - - /** - * Callback for the minus image. Removes the argument associated with the - * given argument ID and mutates the callers to match. - * @param {string} argId The argId of the argument to remove. - * @this {Blockly.Block} - */ - minus: function (argId) { - if (!this.argData_.length) { - return; - } - this.removeArg_(argId); - Blockly.Procedures.mutateCallers(this); - }, - - /** - * Adds an argument to the block and updates the block's parallel tracking - * arrays as appropriate. - * @param {?string=} name An optional name for the argument. - * @param {?string=} varId An optional variable ID for the argument. - * @param {?string=} argId An optional argument ID for the argument - * (used to identify the argument across variable merges). - * @this {Blockly.Block} - * @private - */ - addArg_: function (name = null, varId = null, argId = null) { - if (!this.argData_.length) { - const withField = new Blockly.FieldLabel( - Blockly.Msg['PROCEDURES_BEFORE_PARAMS'], - ); - this.getInput('TOP').appendField(withField, 'WITH'); - } - - const argNames = this.argData_.map((elem) => elem.model.name); - name = - name || - Blockly.Variables.generateUniqueNameFromOptions( - Blockly.Procedures.DEFAULT_ARG, - argNames, - ); - const variable = Blockly.Variables.getOrCreateVariablePackage( - this.workspace, - varId, - name, - '', - ); - argId = argId || Blockly.utils.idGenerator.genUid(); - - this.addVarInput_(name, argId); - if (this.getInput('STACK')) { - this.moveInputBefore(argId, 'STACK'); - } else { - this.moveInputBefore(argId, 'RETURN'); - } - - this.argData_.push({ - model: variable, - argId: argId, - }); - }, - - /** - * Removes the argument associated with the given argument ID from the block. - * @param {string} argId An ID used to track arguments on the block. - * @private - */ - removeArg_: function (argId) { - if (this.removeInput(argId, true)) { - if (this.argData_.length == 1) { - // Becoming argumentless. - this.getInput('TOP').removeField('WITH'); - } - this.argData_ = this.argData_.filter((element) => element.argId != argId); - } - }, - - /** - * Appends the actual inputs and fields associated with an argument to the - * block. - * @param {string} name The name of the argument. - * @param {string} argId The UUID of the argument (different from var ID). - * @this {Blockly.Block} - * @private - */ - addVarInput_: function (name, argId) { - const nameField = new Blockly.FieldTextInput(name, this.validator_); - nameField.onFinishEditing_ = this.finishEditing_.bind(nameField); - nameField.varIdsToDelete_ = []; - nameField.preEditVarModel_ = null; - - this.appendDummyInput(argId) - .setAlign(Blockly.inputs.Align.RIGHT) - .appendField( - createMinusField(Blockly.Msg['ARIA_LABEL_REMOVE_INPUT'], argId), - ) - .appendField(Blockly.Msg['PROCEDURE_VARIABLE']) // Untranslated! - .appendField(nameField, argId); // The name of the field is the arg id. - }, - - /** - * Validates text entered into the argument name field. - * @param {string} newName The new text entered into the field. - * @returns {?string} The field's new value. - * @this {Blockly.FieldTextInput} - */ - validator_: function (newName) { - const sourceBlock = this.getSourceBlock(); - const workspace = sourceBlock.workspace; - const argData = sourceBlock.argData_; - const argDatum = sourceBlock.argData_.find( - (element) => element.argId == this.name, - ); - const currId = argDatum.model.getId(); - - // Replace all whitespace with normal spaces, then trim. - newName = newName.replace(/[\s\xa0]+/g, ' ').trim(); - const caselessName = newName.toLowerCase(); - - /** - * Returns true if the given argDatum is associated with this field, or has - * a different caseless name than the argDatum associated with this field. - * @param {{model: Blockly.IVariableModel, argId:string}} argDatum The - * argDatum we want to make sure does not conflict with the argDatum - * associated with this field. - * @returns {boolean} True if the given datum does not conflict with the - * datum associated with this field. - * @this {Blockly.FieldTextInput} - */ - const hasDifName = (argDatum) => { - // The field name (aka id) is always equal to the arg id. - return ( - argDatum.argId == this.name || - caselessName != argDatum.model.name.toLowerCase() - ); - }; - /** - * Returns true if the variable associated with this field is only used - * by this block, or callers of this procedure. - * @returns {boolean} True if the variable associated with this field is - * only used by this block, or callers of this procedure. - */ - const varOnlyUsedHere = () => { - return Blockly.Variables.getVariableUsesById(workspace, currId).every( - (block) => { - return ( - block.id == sourceBlock.id || - (block.getProcedureCall && - block.getProcedureCall() == sourceBlock.getProcedureDef()[0]) - ); - }, - ); - }; - - if (!newName || !argData.every(hasDifName)) { - if (this.preEditVarModel_) { - argDatum.model = this.preEditVarModel_; - this.preEditVarModel_ = null; - } - Blockly.Procedures.mutateCallers(sourceBlock); - return null; - } - - if (!this.varIdsToDelete_.length) { - this.preEditVarModel_ = argDatum.model; - if (varOnlyUsedHere()) { - this.varIdsToDelete_.push(currId); - } - } - - // Create new vars instead of renaming the old ones, so users can't - // accidentally rename/coalesce vars. - let model = workspace.getVariableMap().getVariable(newName, ''); - if (!model) { - model = workspace.getVariableMap().createVariable(newName, ''); - this.varIdsToDelete_.push(model.getId()); - } else if (model.name != newName) { - // Blockly is case-insensitive so we have to update the var instead of - // creating a new one. - const variable = workspace - .getVariableMap() - .getVariableById(model.getId()); - workspace.getVariableMap().renameVariable(variable, newName); - } - if (model.getId() != currId) { - argDatum.model = model; - } - Blockly.Procedures.mutateCallers(sourceBlock); - return newName; - }, - - /** - * Removes any unused vars that were created as a result of editing. - * @param {string} _finalName The final value of the field. - * @this {Blockly.FieldTextInput} - */ - finishEditing_: function (_finalName) { - const source = this.getSourceBlock(); - const argDatum = source.argData_.find( - (element) => element.argId == this.name, - ); - - const currentVarId = argDatum.model.getId(); - this.varIdsToDelete_.forEach((id) => { - if (id != currentVarId) { - source.workspace.deleteVariableById(id); - } - }); - this.varIdsToDelete_.length = 0; - this.preEditVarModel_ = null; - }, -}; - -/** - * Initializes some private variables for procedure blocks. - * @this {Blockly.Block} - */ -const procedureDefHelper = function () { - /** - * An array of objects containing data about the args belonging to the - * procedure definition. - * @type {!Array<{ - * model:Blockly.IVariableModel, - * argId: string - * }>} - * @private - */ - this.argData_ = []; - /** - * Does this block have a 'STACK' input for statements? - * @type {boolean} - * @private - */ - this.hasStatements_ = true; - - this.getInput('TOP').insertFieldAt( - 0, - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_INPUT']), - 'PLUS', - ); -}; - -Blockly.Extensions.registerMutator( - 'procedure_def_mutator', - procedureDefMutator, - procedureDefHelper, -); - -/** - * Sets the validator for the procedure's name field. - * @this {Blockly.Block} - */ -const procedureRename = function () { - this.getField('NAME').setValidator(Blockly.Procedures.rename); -}; - -Blockly.Extensions.register('procedure_rename', procedureRename); - -/** - * Defines functions for dealing with variables and renaming variables. - * @this {Blockly.Block} - */ -const procedureVars = function () { - // This is a hack to get around the don't-override-builtins check. - const mixin = { - /** - * Return all variables referenced by this block. - * @returns {!Array.} List of variable names. - * @this {Blockly.Block} - */ - getVars: function () { - return this.argData_.map((elem) => elem.model.name); - }, - - /** - * Return all variables referenced by this block. - * @returns {!Array.} List of variable models. - * @this {Blockly.Block} - */ - getVarModels: function () { - return this.argData_.map((elem) => elem.model); - }, - - /** - * Notification that a variable was renamed to the same name as an existing - * variable. These variables are coalescing into a single variable with the - * ID of the variable that was already using the name. - * @param {string} oldId The ID of the variable that was renamed. - * @param {string} newId The ID of the variable that was already using - * the name. - */ - renameVarById: function (oldId, newId) { - const argData = this.argData_.find( - (element) => element.model.getId() == oldId, - ); - if (!argData) { - return; // Not on this block. - } - - const newVar = this.workspace.getVariableMap().getVariableById(newId); - const newName = newVar.name; - this.addVarInput_(newName, newId); - this.moveInputBefore(newId, oldId); - this.removeInput(oldId); - argData.model = newVar; - Blockly.Procedures.mutateCallers(this); - }, - - /** - * Notification that a variable is renaming but keeping the same ID. If the - * variable is in use on this block, rerender to show the new name. - * @param {!Blockly.IVariableModel} variable The variable being renamed. - * @package - * @override - * @this {Blockly.Block} - */ - updateVarName: function (variable) { - const id = variable.getId(); - const argData = this.argData_.find( - (element) => element.model.getId() == id, - ); - if (!argData) { - return; // Not on this block. - } - this.setFieldValue(variable.name, argData.argId); - argData.model = variable; - }, - }; - - this.mixin(mixin, true); -}; - -Blockly.Extensions.register('procedure_vars', procedureVars); diff --git a/plugins/block-plus-minus/src/serialization_helper.js b/plugins/block-plus-minus/src/serialization_helper.js deleted file mode 100644 index 3c71412b9..000000000 --- a/plugins/block-plus-minus/src/serialization_helper.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -/** - * Returns the extra state of the given block (either as XML or a JSO, depending - * on the block's definition). - * @param {!Blockly.BlockSvg} block The block to get the extra state of. - * @returns {string} A stringified version of the extra state of the given - * block. - */ -export function getExtraBlockState(block) { - // TODO: This is a dupe of the BlockChange.getExtraBlockState code, do we - // want to make that public? - if (block.saveExtraState) { - const state = block.saveExtraState(); - return state ? JSON.stringify(state) : ''; - } else if (block.mutationToDom) { - const state = block.mutationToDom(); - return state ? Blockly.Xml.domToText(state) : ''; - } - return ''; -} diff --git a/plugins/block-plus-minus/src/text_join.js b/plugins/block-plus-minus/src/text_join.js deleted file mode 100644 index 6d4aa769b..000000000 --- a/plugins/block-plus-minus/src/text_join.js +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Changes the text_join block to use a +/- mutator UI. - */ - -import * as Blockly from 'blockly/core'; -import {createPlusField} from './field_plus'; -import {createMinusField} from './field_minus'; - -const textJoinMutator = { - /** - * Number of text inputs on this block. - * @type {number} - */ - itemCount_: 0, - - /** - * Creates XML to represent number of inputs. - * @returns {!Element} XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - const container = Blockly.utils.xml.createElement('mutation'); - container.setAttribute('items', this.itemCount_); - return container; - }, - - /** - * Parses XML to restore the inputs. - * @param {!Element} xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - const targetCount = parseInt(xmlElement.getAttribute('items'), 10); - this.updateShape_(targetCount); - }, - - /** - * Returns the state of this block as a JSON serializable object. - * @returns {{itemCount: number}} The state of this block, ie the item count. - */ - saveExtraState: function () { - return { - itemCount: this.itemCount_, - }; - }, - - /** - * Applies the given state to this block. - * @param {*} state The state to apply to this block, ie the item count. - */ - loadExtraState: function (state) { - this.updateShape_(state['itemCount']); - }, - - /** - * Adds inputs to the block until the block reaches the target input count. - * @param {number} targetCount The number of inputs the block should have. - * @this {Blockly.Block} - * @private - */ - updateShape_: function (targetCount) { - while (this.itemCount_ < targetCount) { - this.addPart_(); - } - while (this.itemCount_ > targetCount) { - this.removePart_(); - } - this.updateMinus_(); - }, - - /** - * Callback for the plus image. Adds an input to the block and updates the - * state of the minus. - * @this {Blockly.Block} - */ - plus: function () { - this.addPart_(); - this.updateMinus_(); - }, - - /** - * Callback for the minus image. Removes the input at the end of the block and - * updates the state of the minus. - * @this {Blockly.Block} - */ - minus: function () { - if (this.itemCount_ == 0) { - return; - } - this.removePart_(); - this.updateMinus_(); - }, - - /** - * Adds an input to the end of the block. If the block currently has no - * inputs it updates the top 'EMPTY' input to receive a block. - * @this {Blockly.Block} - * @private - */ - addPart_: function () { - if (this.itemCount_ == 0) { - if (this.getInput('EMPTY')) { - this.removeInput('EMPTY'); - } - this.topInput_ = this.appendValueInput('ADD' + this.itemCount_) - .appendField( - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_TEXT']), - 'PLUS', - ) - .appendField(Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH']); - } else { - this.appendValueInput('ADD' + this.itemCount_); - } - // Because item inputs are 0-index we decrement first, increment last. - this.itemCount_++; - }, - - /** - * Removes an input from the end of the block. If we are removing the last - * input this updates the block to have an 'EMPTY' top input. - * @this {Blockly.Block} - * @private - */ - removePart_: function () { - this.itemCount_--; - this.removeInput('ADD' + this.itemCount_); - if (this.itemCount_ == 0) { - this.topInput_ = this.appendDummyInput('EMPTY') - .appendField( - createPlusField(Blockly.Msg['ARIA_LABEL_ADD_TEXT']), - 'PLUS', - ) - .appendField(this.newQuote_(true)) - .appendField(this.newQuote_(false)); - } - }, - - /** - * Makes it so the minus is visible iff there is an input available to remove. - * @private - */ - updateMinus_: function () { - const minusField = this.getField('MINUS'); - if (!minusField && this.itemCount_ > 0) { - this.topInput_.insertFieldAt( - 1, - createMinusField(Blockly.Msg['ARIA_LABEL_REMOVE_TEXT']), - 'MINUS', - ); - } else if (minusField && this.itemCount_ < 1) { - this.topInput_.removeField('MINUS'); - } - }, -}; - -/** - * Adds the quotes mixin to the block. Also updates the shape so that if no - * mutator is provided the block has two inputs. - * @this {Blockly.Block} - */ -const textJoinHelper = function () { - Blockly.Extensions.apply('quote_image_mixin', this, false); - this.updateShape_(2); -}; - -if (Blockly.Extensions.isRegistered('text_join_mutator')) { - Blockly.Extensions.unregister('text_join_mutator'); -} -Blockly.Extensions.registerMutator( - 'text_join_mutator', - textJoinMutator, - textJoinHelper, -); diff --git a/plugins/block-plus-minus/test/if.mocha.js b/plugins/block-plus-minus/test/if.mocha.js deleted file mode 100644 index b2f93cd8e..000000000 --- a/plugins/block-plus-minus/test/if.mocha.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const {testHelpers} = require('@blockly/dev-tools'); -const {runPlusMinusTestSuite} = require('./test_helpers.mocha'); -const Blockly = require('blockly'); -const {dartGenerator} = require('blockly/dart'); -const {javascriptGenerator} = require('blockly/javascript'); -const {luaGenerator} = require('blockly/lua'); -const {phpGenerator} = require('blockly/php'); -const {pythonGenerator} = require('blockly/python'); - -require('../src/index'); - -const assert = chai.assert; - -const { - CodeGenerationTestSuite, - runCodeGenerationTestSuites, - runSerializationTestSuite, - SerializationTestCase, -} = testHelpers; - -suite('If block', function () { - /** - * Asserts that the if block has the expected inputs and fields. - * @param {!Blockly.Block} block The if block to check. - * @param {number} ifCount The number of ifs we expect. - * @param {boolean=} hasElse If we expect an else input. - */ - function assertIfBlockStructure(block, ifCount, hasElse) { - assert.equal(block.type, 'controls_if'); - const inputs = block.inputList; - assert.exists(inputs); - const length = inputs.length; - const expectedLength = hasElse ? ifCount * 2 + 1 : ifCount * 2; - assert.equal(length, expectedLength); - for (let i = 0; i < ifCount; i++) { - assert.equal(inputs[i * 2].name, 'IF' + i); - assert.equal(inputs[i * 2 + 1].name, 'DO' + i); - if (i > 0) { - assert.isNotNull(block.getField('MINUS' + i)); - } - } - if (hasElse) { - assert.equal(inputs[length - 1].name, 'ELSE'); - } - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - }); - - teardown(function () { - this.workspace.dispose(); - }); - - test('Creation', function () { - this.block = this.workspace.newBlock('controls_if'); - assertIfBlockStructure(this.block, 1); - }); - - suite('Code generation', function () { - const trivialCreateBlock = (workspace) => { - return workspace.newBlock('controls_if'); - }; - - /** - * Test suites for code generation tests. - * @type {Array} - */ - const testSuites = [ - { - title: 'Dart', - generator: dartGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'if (false) {\n}\n', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'JavaScript', - generator: javascriptGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'if (false) {\n}\n', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Lua', - generator: luaGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'if false then\nend\n', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'PHP', - generator: phpGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'if (false) {\n}\n', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Python', - generator: pythonGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'if False:\n pass\n', - createBlock: trivialCreateBlock, - }, - ], - }, - ]; - runCodeGenerationTestSuites(testSuites); - }); - - suite('XML', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'Empty Xml', - xml: '', - expectedXml: - '', - assertBlockStructure: (block) => { - assertIfBlockStructure(block, 1); - }, - }, - { - title: '2 elseif no else', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertIfBlockStructure(block, 3); - }, - }, - { - title: '3 elseif with else', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertIfBlockStructure(block, 4, true); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - suite('JSON', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'No mutation', - json: { - type: 'controls_if', - }, - expectedJson: { - type: 'controls_if', - id: '1', - }, - assertBlockStructure: (block) => { - assertIfBlockStructure(block, 1); - }, - }, - { - title: '2 elseif no else', - json: { - type: 'controls_if', - extraState: { - elseIfCount: 2, - }, - id: '1', - }, - assertBlockStructure: (block) => { - assertIfBlockStructure(block, 3); - }, - }, - { - title: '3 elseif with else', - json: { - type: 'controls_if', - extraState: { - elseIfCount: 3, - hasElse: true, - }, - id: '1', - }, - assertBlockStructure: (block) => { - assertIfBlockStructure(block, 4, true); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - runPlusMinusTestSuite('controls_if', 1, 1, 'IF', assertIfBlockStructure); -}); diff --git a/plugins/block-plus-minus/test/index.html b/plugins/block-plus-minus/test/index.html deleted file mode 100644 index cf52f2924..000000000 --- a/plugins/block-plus-minus/test/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Blockly Plus/Minus Mutators Test - - - - -
- - - - diff --git a/plugins/block-plus-minus/test/index.js b/plugins/block-plus-minus/test/index.js deleted file mode 100644 index fb0e133b5..000000000 --- a/plugins/block-plus-minus/test/index.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Plus minus blocks' test playground. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import '../src/index.js'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -const toolbox = { - kind: 'categoryToolbox', - contents: [ - { - kind: 'category', - name: 'Others', - categorystyle: 'logic_category', - contents: [ - { - kind: 'block', - type: 'controls_if', - }, - { - kind: 'block', - type: 'controls_if', - extraState: { - hasElse: true, - }, - }, - { - kind: 'block', - type: 'controls_ifelse', - }, - { - kind: 'block', - type: 'text_join', - }, - { - kind: 'block', - type: 'lists_create_with', - extraState: { - itemCount: 0, - }, - }, - { - kind: 'block', - type: 'lists_create_with', - }, - ], - }, - { - kind: 'category', - name: 'Functions', - categorystyle: 'procedure_category', - custom: 'PROCEDURE', - }, - { - kind: 'category', - name: 'Variables', - categorystyle: 'variable_category', - custom: 'VARIABLE', - }, - ], -}; - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolbox, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/block-plus-minus/test/list_create.mocha.js b/plugins/block-plus-minus/test/list_create.mocha.js deleted file mode 100644 index e17d3b852..000000000 --- a/plugins/block-plus-minus/test/list_create.mocha.js +++ /dev/null @@ -1,312 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const {testHelpers} = require('@blockly/dev-tools'); -const {runPlusMinusTestSuite} = require('./test_helpers.mocha'); -const Blockly = require('blockly'); -const {dartGenerator} = require('blockly/dart'); -const {javascriptGenerator} = require('blockly/javascript'); -const {luaGenerator} = require('blockly/lua'); -const {phpGenerator} = require('blockly/php'); -const {pythonGenerator} = require('blockly/python'); - -require('../src/index'); - -const assert = chai.assert; -const { - CodeGenerationTestSuite, - runCodeGenerationTestSuites, - runSerializationTestSuite, - SerializationTestCase, -} = testHelpers; - -suite('List create block', function () { - /** - * Asserts that the list block has the inputs and fields we expect. - * @param {!Blockly.Block} block The list block. - * @param {number=} inputCount The number of inputs we expect. - */ - function assertListBlockStructure(block, inputCount = 0) { - assert.equal(block.type, 'lists_create_with'); - if (inputCount === 0) { - assert.equal(block.inputList.length, 1); - const input = block.inputList[0]; - assert.equal(input.type, Blockly.inputs.inputTypes.DUMMY); - assert.equal(input.name, 'EMPTY'); - assert.isNull(block.getField('MINUS')); - // Easy way to test we're displaying empty instead of normal text. - assert.equal(block.toString(), 'Add list item create empty list'); - return; - } - - assert.equal(block.inputList.length, inputCount); - for (let i = 0; i < inputCount; i++) { - chai.assert.equal(block.inputList[i].name, 'ADD' + i); - } - assert.isNotNull(block.getField('MINUS')); - // Easy way to test we're displaying normal text instead of empty. - assert.notEqual(block.toString(), 'Add list item create empty list'); - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - }); - - teardown(function () { - this.workspace.dispose(); - }); - - test('Creation', function () { - this.block = this.workspace.newBlock('lists_create_with'); - assertListBlockStructure(this.block, 3); - }); - - suite('Code generation', function () { - const trivialCreateBlock = (workspace) => { - return workspace.newBlock('lists_create_with'); - }; - - /** - * Test suites for code generation tests. - * @type {Array} - */ - const testSuites = [ - { - title: 'Dart', - generator: dartGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: '[null, null, null]', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'JavaScript', - generator: javascriptGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: '[null, null, null]', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Lua', - generator: luaGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: '{nil, nil, nil}', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'PHP', - generator: phpGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'array(null, null, null)', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Python', - generator: pythonGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: '[None, None, None]', - createBlock: trivialCreateBlock, - }, - ], - }, - ]; - runCodeGenerationTestSuites(testSuites); - }); - - suite('Xml', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'Empty XML', - xml: '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertListBlockStructure(block, 3); - }, - }, - { - title: '3 items', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertListBlockStructure(block, 3); - }, - }, - { - title: '5 items', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertListBlockStructure(block, 5); - }, - }, - { - title: '0 items', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertListBlockStructure(block, 0); - }, - }, - { - title: '4 items with child attached', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' FALSE\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertListBlockStructure(block, 4); - const child = block.getInputTargetBlock('ADD3'); - assert.isNotNull(child); - assert.equal(child.type, 'logic_boolean'); - assert.equal(child.getFieldValue('BOOL'), 'FALSE'); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - suite('Json', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'No mutation', - json: { - type: 'lists_create_with', - }, - expectedJson: { - type: 'lists_create_with', - id: '1', - extraState: { - itemCount: 3, - }, - }, - assertBlockStructure: (block) => { - assertListBlockStructure(block, 3); - }, - }, - { - title: '3 items', - json: { - type: 'lists_create_with', - id: '1', - extraState: { - itemCount: 3, - }, - }, - assertBlockStructure: (block) => { - assertListBlockStructure(block, 3); - }, - }, - { - title: '5 items', - json: { - type: 'lists_create_with', - id: '1', - extraState: { - itemCount: 5, - }, - }, - assertBlockStructure: (block) => { - assertListBlockStructure(block, 5); - }, - }, - { - title: '0 items', - json: { - type: 'lists_create_with', - id: '1', - extraState: { - itemCount: 0, - }, - }, - assertBlockStructure: (block) => { - assertListBlockStructure(block, 0); - }, - }, - { - title: '4 items with child attached', - json: { - type: 'lists_create_with', - id: '1', - extraState: { - itemCount: 4, - }, - inputs: { - ADD3: { - block: { - type: 'logic_boolean', - id: '1', - fields: { - BOOL: 'FALSE', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertListBlockStructure(block, 4); - const child = block.getInputTargetBlock('ADD3'); - assert.isNotNull(child); - assert.equal(child.type, 'logic_boolean'); - assert.equal(child.getFieldValue('BOOL'), 'FALSE'); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - runPlusMinusTestSuite( - 'lists_create_with', - 3, - 0, - 'ADD', - assertListBlockStructure, - ); -}); diff --git a/plugins/block-plus-minus/test/procedures.mocha.js b/plugins/block-plus-minus/test/procedures.mocha.js deleted file mode 100644 index a35b65186..000000000 --- a/plugins/block-plus-minus/test/procedures.mocha.js +++ /dev/null @@ -1,782 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const Blockly = require('blockly'); -const {testHelpers} = require('@blockly/dev-tools'); -const procedureTestHelpers = require('./procedures_test_helpers.mocha'); -const {dartGenerator} = require('blockly/dart'); -const {javascriptGenerator} = require('blockly/javascript'); -const {luaGenerator} = require('blockly/lua'); -const {phpGenerator} = require('blockly/php'); -const {pythonGenerator} = require('blockly/python'); - -require('../src/index'); - -const assert = chai.assert; -const { - CodeGenerationTestSuite, - runCodeGenerationTestSuites, - runSerializationTestSuite, - SerializationTestCase, -} = testHelpers; -const { - assertDefBlockStructure, - assertCallBlockStructure, - assertProcBlocksStructure, - createProcDefBlock, - createProcCallBlock, -} = procedureTestHelpers; - -suite('Procedure blocks', function () { - setup(function () { - this.workspace = new Blockly.Workspace(); - this.clock = sinon.useFakeTimers(); - }); - - teardown(function () { - // We have to make sure the procedure call gets the change event before - // we teardown. Otherwise we get a race condition where it tries to create - // a new def. - this.clock.tick(100); - this.workspace.dispose(); - sinon.restore(); - }); - - const testSuites = [ - { - title: 'with return', - hasReturn: true, - defType: 'procedures_defreturn', - callType: 'procedures_callreturn', - }, - { - title: 'no return', - hasReturn: false, - defType: 'procedures_defnoreturn', - callType: 'procedures_callnoreturn', - }, - ]; - - testSuites.forEach((testSuite) => { - suite(testSuite.title, function () { - suite('Structure', function () { - test('Definition block', function () { - const defBlock = this.workspace.newBlock(testSuite.defType); - assertDefBlockStructure(defBlock, testSuite.hasReturn); - }); - - test('Call block', function () { - this.workspace.newBlock(testSuite.defType); - const callBlock = this.workspace.newBlock(testSuite.callType); - assertCallBlockStructure(callBlock); - }); - }); - - suite('Code generation', function () { - const createBlockFn = (numArgs) => { - return (workspace) => { - const block = createProcDefBlock(workspace, testSuite.hasReturn); - for (let i = 0; i < numArgs; i++) { - block.plus(); - } - return block; - }; - }; - - /** - * Test suites for code generation test. - * @type {Array} - */ - const codeGenerationTestSuites = [ - { - title: 'Dart', - generator: dartGenerator, - testCases: [ - { - title: 'No arguments', - useWorkspaceToCode: true, - expectedCode: - 'void proc_name() {\n' + '}\n\n\n' + 'main() {\n' + '}', - createBlock: createBlockFn(0), - }, - { - title: 'One argument', - useWorkspaceToCode: true, - expectedCode: - 'var x;\n\n' + - 'void proc_name(x) {\n' + - '}\n\n\n' + - 'main() {\n' + - '}', - createBlock: createBlockFn(1), - }, - ], - }, - { - title: 'JavaScript', - generator: javascriptGenerator, - testCases: [ - { - title: 'No arguments', - useWorkspaceToCode: true, - expectedCode: 'function proc_name() {\n' + '}\n', - createBlock: createBlockFn(0), - }, - { - title: 'One argument', - useWorkspaceToCode: true, - expectedCode: - 'var x;\n\n' + 'function proc_name(x) {\n' + '}\n', - createBlock: createBlockFn(1), - }, - ], - }, - { - title: 'Lua', - generator: luaGenerator, - testCases: [ - { - title: 'No arguments', - useWorkspaceToCode: true, - expectedCode: 'function proc_name()\n' + 'end\n', - createBlock: createBlockFn(0), - }, - { - title: 'One argument', - useWorkspaceToCode: true, - expectedCode: 'function proc_name(x)\n' + 'end\n', - createBlock: createBlockFn(1), - }, - ], - }, - { - title: 'PHP', - generator: phpGenerator, - testCases: [ - { - title: 'No arguments', - useWorkspaceToCode: true, - expectedCode: 'function proc_name() {\n' + '}\n', - createBlock: createBlockFn(0), - }, - { - title: 'One argument', - useWorkspaceToCode: true, - expectedCode: 'function proc_name($x) {\n' + '}\n', - createBlock: createBlockFn(1), - }, - ], - }, - { - title: 'Python', - generator: pythonGenerator, - testCases: [ - { - title: 'No arguments', - useWorkspaceToCode: true, - expectedCode: 'def proc_name():\n' + ' pass\n', - createBlock: createBlockFn(0), - }, - { - title: 'One argument', - useWorkspaceToCode: true, - expectedCode: - 'x = None\n\n' + 'def proc_name(x):\n' + ' pass\n', - createBlock: createBlockFn(1), - }, - ], - }, - ]; - - runCodeGenerationTestSuites(codeGenerationTestSuites); - }); - - suite('Xml', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'Minimal definition', - xml: '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn); - }, - }, - { - title: 'Common definition', - xml: - '' + - ' do something' + - '', - expectedXml: - '\n' + - ' do something\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn); - }, - }, - { - title: 'With vars definition', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - ' x\n' + // Because genUID is stubbed. - ' y\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn, ['x', 'y']); - }, - }, - { - title: 'No statements definition', - xml: - '\n' + - ' \n' + - ' do something\n' + - '', - expectedXml: - '\n' + - ' \n' + - ' do something\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, true, [], false); - }, - }, - { - title: 'Minimal caller', - xml: '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'Common caller', - xml: - '\n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'With vars caller', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertCallBlockStructure(block, ['x', 'y']); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - suite('Json', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'Minimal definition', - json: { - type: testSuite.defType, - }, - expectedJson: { - type: testSuite.defType, - id: '1', - fields: { - NAME: '', - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn); - }, - }, - { - title: 'Common definition', - json: { - type: testSuite.defType, - fields: { - NAME: 'do something', - }, - }, - expectedJson: { - type: testSuite.defType, - id: '1', - fields: { - NAME: 'do something', - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn); - }, - }, - { - title: 'With vars definition', - json: { - type: testSuite.defType, - fields: { - NAME: 'do something', - }, - extraState: { - params: [ - { - name: 'x', - id: 'id1', - argId: 'arg1', - }, - { - name: 'y', - id: 'id2', - argId: 'arg2', - }, - ], - }, - }, - expectedJson: { - type: testSuite.defType, - id: '1', - fields: { - NAME: 'do something', - arg1: 'x', - arg2: 'y', - }, - extraState: { - params: [ - { - name: 'x', - id: 'id1', - argId: 'arg1', - }, - { - name: 'y', - id: 'id2', - argId: 'arg2', - }, - ], - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn, ['x', 'y']); - }, - }, - { - title: 'No statements definition', - json: { - type: testSuite.defType, - fields: { - NAME: 'do something', - }, - extraState: { - hasStatements: false, - }, - }, - expectedJson: { - type: testSuite.defType, - id: '1', - fields: { - NAME: 'do something', - }, - extraState: { - hasStatements: false, - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, testSuite.hasReturn, [], false); - }, - }, - { - title: 'Minimal caller', - json: { - type: testSuite.callType, - }, - expectedJson: { - type: testSuite.callType, - id: '1', - extraState: { - name: '', - }, - }, - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'Common caller', - json: { - type: testSuite.callType, - extraState: { - name: 'do something', - }, - }, - expectedJson: { - type: testSuite.callType, - id: '1', - extraState: { - name: 'do something', - }, - }, - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'With vars caller', - json: { - type: testSuite.callType, - extraState: { - name: 'do something', - params: ['x', 'y'], - }, - }, - expectedJson: { - type: testSuite.callType, - id: '1', - extraState: { - name: 'do something', - params: ['x', 'y'], - }, - }, - assertBlockStructure: (block) => { - assertCallBlockStructure(block, ['x', 'y']); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - suite('Adding and removing inputs', function () { - setup(function () { - this.def = createProcDefBlock(this.workspace, testSuite.hasReturn); - this.call = createProcCallBlock(this.workspace, testSuite.hasReturn); - }); - - test('Add', function () { - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn); - this.def.plus(); - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn, [ - 'x', - ]); - }); - - test('Add many', function () { - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn); - for (let i = 0; i < 5; i++) { - this.def.plus(); - } - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn, [ - 'x', - 'y', - 'z', - 'a', - 'b', - ]); - }); - - if (testSuite.hasReturn) { - test('Add, no stack', function () { - this.def = createProcDefBlock( - this.workspace, - true, - 'proc name2', - false, - ); - this.call = createProcCallBlock(this.workspace, true, 'proc name2'); - assertProcBlocksStructure(this.def, this.call, true, [], false); - this.def.plus(); - assertProcBlocksStructure(this.def, this.call, true, ['x'], false); - }); - } - - test('Remove', function () { - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn); - this.def.plus(); - this.def.minus(this.def.argData_[0].argId); - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn); - }); - - test('Remove many', function () { - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn); - for (let i = 0; i < 10; i++) { - this.def.plus(); - } - // Remove every other input. Must do it backwards so that the array - // doesn't get out of whack. - for (let i = 9; i > 0; i -= 2) { - this.def.minus(this.def.argData_[i].argId); - } - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn, [ - 'x', - 'z', - 'b', - 'd', - 'f', - ]); - }); - - test('Remove too many (w/ no args)', function () { - this.def.minus('whatevs'); - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn); - }); - - test('Remove bad arg', function () { - this.def.plus(); - this.def.minus('whatevs'); - assertProcBlocksStructure(this.def, this.call, testSuite.hasReturn, [ - 'x', - ]); - }); - }); - - suite('Vars', function () { - setup(function () { - this.assertVars = function (constsArray) { - const constNames = this.workspace - .getVariableMap() - .getVariablesOfType('') - .map((model) => model.name); - assert.sameMembers(constNames, constsArray); - }; - }); - teardown(function () { - delete this.assertVars; - }); - - suite('Renaming args', function () { - setup(function () { - this.def = createProcDefBlock(this.workspace, testSuite.hasReturn); - this.call = createProcCallBlock( - this.workspace, - testSuite.hasReturn, - ); - }); - test('Simple Rename', function () { - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue('newName'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['newName'], - ); - this.assertVars(['x', 'newName']); - }); - test('Change Case', function () { - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue('X'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['X'], - ); - this.assertVars(['X']); - }); - test('Empty', function () { - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue(''); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['x'], - ); - this.assertVars(['x']); - }); - test('Whitespace', function () { - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue(' newName '); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['newName'], - ); - this.assertVars(['x', 'newName']); - }); - test('Duplicate', function () { - this.def.plus(); - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue('y'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['x', 'y'], - ); - this.assertVars(['x', 'y']); - }); - test('Duplicate Different Case', function () { - this.def.plus(); - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue('Y'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['x', 'y'], - ); - this.assertVars(['x', 'y']); - }); - test('Match Existing', function () { - this.workspace.getVariableMap().createVariable('test', ''); - this.def.plus(); - const field = this.def.inputList[1].fieldRow[2]; - field.setValue('test'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['test'], - ); - this.assertVars(['x', 'test']); - assert.equal( - this.def.argData_[0].model.getId(), - this.workspace.getVariableMap().getVariable('test', '').getId(), - ); - }); - }); - suite('Vars Renamed Elsewhere', function () { - setup(function () { - this.def = createProcDefBlock(this.workspace, testSuite.hasReturn); - this.call = createProcCallBlock( - this.workspace, - testSuite.hasReturn, - ); - }); - test('Simple Rename', function () { - this.def.plus(); - const Variable = this.workspace - .getVariableMap() - .getVariable('x', ''); - this.workspace.getVariableMap().renameVariable(Variable, 'test'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['test'], - ); - this.assertVars(['test']); - }); - // Don't know how we want to react here. - test.skip('Duplicate', function () { - this.def.plus(); - this.def.plus(); - const Variable = this.workspace - .getVariableMap() - .getVariable('x', ''); - this.workspace.getVariableMap().renameVariable(Variable, 'y'); - // Don't know what we want to have happen. - }); - test('Change Case', function () { - this.def.plus(); - const Variable = this.workspace - .getVariableMap() - .getVariable('x', ''); - this.workspace.getVariableMap().renameVariable(Variable, 'X'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['X'], - ); - this.assertVars(['X']); - }); - test('Coalesce Change Case', function () { - const variable = this.workspace - .getVariableMap() - .createVariable('test'); - this.def.plus(); - this.workspace.getVariableMap().renameVariable(variable, 'X'); - assertProcBlocksStructure( - this.def, - this.call, - testSuite.hasReturn, - ['X'], - ); - this.assertVars(['X']); - }); - }); - }); - }); - }); -}); diff --git a/plugins/block-plus-minus/test/procedures_test_helpers.mocha.js b/plugins/block-plus-minus/test/procedures_test_helpers.mocha.js deleted file mode 100644 index 12dc415a9..000000000 --- a/plugins/block-plus-minus/test/procedures_test_helpers.mocha.js +++ /dev/null @@ -1,260 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const Blockly = require('blockly'); - -require('../src/index'); -const assert = chai.assert; - -/** - * Asserts that the procedure definition block has the expected inputs and - * fields. - * @param {!Blockly.Block} defBlock The procedure definition block. - * @param {boolean=} hasReturn If we expect the procedure def to have a return - * input or not. - * @param {Array=} args An array of argument names. - * @param {boolean=} hasStatements If we expect the procedure def to have a - * statement input or not. - */ -function assertDefBlockStructure( - defBlock, - hasReturn = false, - args = [], - hasStatements = true, -) { - if (hasStatements) { - assert.isNotNull( - defBlock.getInput('STACK'), - 'Def block should have STACK input', - ); - } else { - assert.isNull( - defBlock.getInput('STACK'), - 'Def block should not have STACK input', - ); - } - if (hasReturn) { - assert.isNotNull( - defBlock.getInput('RETURN'), - 'Def block should have RETURN input', - ); - } else { - assert.isNull( - defBlock.getInput('RETURN'), - 'Def block should not have RETURN input', - ); - } - if (args.length) { - assert.include( - defBlock.toString(), - 'with', - 'Def block string should include "with"', - ); - } else { - assert.notInclude( - defBlock.toString(), - 'with', - 'Def block string should not include "with"', - ); - } - - assertDefBlockArgsStructure_(defBlock, hasReturn, args, hasStatements); -} - -/** - * Asserts that the procedure definition block has the expected inputs and - * fields. - * @param {!Blockly.Block} callBlock The procedure call block. - * @param {Array=} args An array of argument names. - */ -function assertCallBlockStructure(callBlock, args = []) { - if (args.length) { - assert.include(callBlock.toString(), 'with'); - } else { - assert.notInclude(callBlock.toString(), 'with'); - } - - assertCallBlockArgsStructure_(callBlock, args); -} - -/** - * Asserts that the procedure definition block has the expected arguments. - * @param {!Blockly.Block} defBlock The procedure definition block. - * @param {boolean=} hasReturn If we expect the procedure def to have a return - * input or not. - * @param {Array=} args An array of argument names. - * @param {boolean=} hasStatements If we expect the procedure def to have - * a statement input or not. - * @private - */ -function assertDefBlockArgsStructure_( - defBlock, - hasReturn, - args, - hasStatements, -) { - // inputList also contains "TOP" input and optionally "RETURN" and "STACK" - let defArgCount = defBlock.inputList.length - 1; - if (hasReturn) { - defArgCount--; - } - if (hasStatements) { - defArgCount--; - } - - assert.equal( - defArgCount, - args.length, - 'def block has the expected number of args', - ); - - assert.sameOrderedMembers(defBlock.getVars(), args); - - if (!args.length) { - return; - } - - const argIds = defBlock.argData_.map((element) => element.argId); - for (let i = 0; i < args.length; i++) { - const expectedName = args[i]; - const defInput = defBlock.inputList[i + 1]; - assert.equal(defInput.type, Blockly.inputs.inputTypes.DUMMY); - assert.equal(defInput.name, argIds[i]); - assert.equal( - defInput.fieldRow[2].getValue(), - expectedName, - 'def block consts did not match expected', - ); - } - - // Assert the last input is not a dummy. Sometimes - // arg inputs don't get moved which is bad. - const lastInput = defBlock.inputList[defBlock.inputList.length - 1]; - assert.notEqual( - lastInput.type, - Blockly.inputs.inputTypes.DUMMY, - 'last input is not a dummy', - ); -} - -/** - * Asserts that the procedure call block has the expected arguments. - * @param {!Blockly.Block} callBlock The procedure definition block. - * @param {Array=} args An array of argument names. - * @private - */ -function assertCallBlockArgsStructure_(callBlock, args) { - // inputList also contains "TOPROW" - assert.equal( - callBlock.inputList.length - 1, - args.length, - 'call block has the expected number of args', - ); - - for (let i = 0; i < args.length; i++) { - const expectedName = args[i]; - const callInput = callBlock.inputList[i + 1]; - assert.equal(callInput.type, Blockly.INPUT_VALUE); - assert.equal(callInput.name, 'ARG' + i); - assert.equal( - callInput.fieldRow[0].getValue(), - expectedName, - 'Call block consts did not match expected.', - ); - } -} - -/** - * Asserts that the procedure definition and call blocks have the expected - * inputs and fields. - * @param {!Blockly.Block} def The procedure definition block. - * @param {!Blockly.Block} call The procedure call block. - * @param {boolean=} hasReturn If we expect the procedure def to have a return - * input or not. - * @param {Array=} args An array of argument names. - * @param {boolean=} hasStatements If we expect the procedure def to have - * a statement input or not. - */ -function assertProcBlocksStructure( - def, - call, - hasReturn = false, - args = [], - hasStatements = true, -) { - assertDefBlockStructure(def, hasReturn, args, hasStatements); - assertCallBlockStructure(call, args); -} - -/** - * Creates procedure definition block using domToBlock call. - * @param {!Blockly.Workspace} workspace The Blockly workspace. - * @param {boolean=} hasReturn Whether the procedure definition should have - * return. - * @param {string=} nameId The procedure name. - * @param {boolean=} hasStatements Whether the block has statements (STACK). - * @returns {Blockly.Block} The created block. - */ -function createProcDefBlock( - workspace, - hasReturn = false, - nameId = 'proc name', - hasStatements = true, -) { - const type = hasReturn ? 'procedures_defreturn' : 'procedures_defnoreturn'; - return Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom( - '' + - (hasStatements - ? '' - : ' \n') + - ' ' + - nameId + - '' + - '', - ), - workspace, - ); -} - -/** - * Creates procedure call block using domToBlock call. - * @param {!Blockly.Workspace} workspace The Blockly workspace. - * @param {boolean=} hasReturn Whether the corresponding procedure definition - * has return. - * @param {string=} nameId The procedure name. - * @returns {Blockly.Block} The created block. - */ -function createProcCallBlock( - workspace, - hasReturn = false, - nameId = 'proc name', -) { - const type = hasReturn ? 'procedures_callreturn' : 'procedures_callnoreturn'; - return Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom( - '' + - ' ' + - '', - ), - workspace, - ); -} - -module.exports = { - assertDefBlockStructure, - assertCallBlockStructure, - assertProcBlocksStructure, - createProcDefBlock, - createProcCallBlock, -}; diff --git a/plugins/block-plus-minus/test/test_helpers.mocha.js b/plugins/block-plus-minus/test/test_helpers.mocha.js deleted file mode 100644 index cb6ec108a..000000000 --- a/plugins/block-plus-minus/test/test_helpers.mocha.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {assert} = require('chai'); - -/** - * Runs test suite for plus/minus functionality for the block of the given - * type. - * @param {string} blockType The block type of block being tested. - * @param {number} defaultInputCount The default count of inputs for this block. - * @param {number} minimumInputCount The minimum allowed inputs for this block. - * @param {string} inputPrefix The prefix to use to create input name for test. - * @param {function(Blockly.Block, number)} assertBlockStructure The assertion - * function to use. - */ -function runPlusMinusTestSuite( - blockType, - defaultInputCount, - minimumInputCount, - inputPrefix, - assertBlockStructure, -) { - suite('Adding and removing inputs', function () { - setup(function () { - this.block = this.workspace.newBlock(blockType); - }); - - test('Add', function () { - assertBlockStructure(this.block, defaultInputCount); - this.block.plus(); - assertBlockStructure(this.block, defaultInputCount + 1); - }); - - test('Add many', function () { - assertBlockStructure(this.block, defaultInputCount); - for (let i = 0; i < 8; i++) { - this.block.plus(); - } - assertBlockStructure(this.block, defaultInputCount + 8); - }); - - if (defaultInputCount === minimumInputCount) { - test('Remove', function () { - assertBlockStructure(this.block, defaultInputCount); - this.block.plus(); - this.block.minus(); - assertBlockStructure(this.block, defaultInputCount); - }); - } else { - test('Remove', function () { - assertBlockStructure(this.block, defaultInputCount); - this.block.minus(); - assertBlockStructure(this.block, defaultInputCount - 1); - }); - } - - test('Remove many', function () { - assertBlockStructure(this.block, defaultInputCount); - for (let i = 0; i < 8; i++) { - this.block.plus(); - } - for (let i = 0; i < 5; i++) { - this.block.minus(); - } - assertBlockStructure(this.block, defaultInputCount + 3); - }); - - test('Remove too many', function () { - assertBlockStructure(this.block, defaultInputCount); - for (let i = 0; i < defaultInputCount + 1; i++) { - this.block.minus(); - } - assertBlockStructure(this.block, minimumInputCount); - }); - - test('Remove with child attached', function () { - const block = this.workspace.newBlock('logic_boolean'); - assertBlockStructure(this.block, defaultInputCount); - - let inputCount = defaultInputCount; - if (minimumInputCount === defaultInputCount) { - this.block.plus(); - inputCount++; - } - - const childInputName = inputPrefix + (inputCount - 1); - - this.block - .getInput(childInputName) - .connection.connect(block.outputConnection); - assert.equal(this.block.getInputTargetBlock(childInputName), block); - - this.block.minus(); - assertBlockStructure(this.block, inputCount - 1); - assert.isNull(this.block.getInputTargetBlock(childInputName)); - assert.isNull(block.outputConnection.targetBlock()); - - // Assert that it does not get reattached. Only reattach on undo. - this.block.plus(); - assertBlockStructure(this.block, inputCount); - assert.isNull(block.outputConnection.targetBlock()); - }); - }); -} - -module.exports = { - runPlusMinusTestSuite, -}; diff --git a/plugins/block-plus-minus/test/text_join.mocha.js b/plugins/block-plus-minus/test/text_join.mocha.js deleted file mode 100644 index acd96a43e..000000000 --- a/plugins/block-plus-minus/test/text_join.mocha.js +++ /dev/null @@ -1,282 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const {testHelpers} = require('@blockly/dev-tools'); -const {runPlusMinusTestSuite} = require('./test_helpers.mocha'); -const Blockly = require('blockly'); -const {dartGenerator} = require('blockly/dart'); -const {javascriptGenerator} = require('blockly/javascript'); -const {luaGenerator} = require('blockly/lua'); -const {phpGenerator} = require('blockly/php'); -const {pythonGenerator} = require('blockly/python'); - -require('../src/index'); - -const assert = chai.assert; -const { - CodeGenerationTestSuite, - runCodeGenerationTestSuites, - runSerializationTestSuite, - SerializationTestCase, -} = testHelpers; - -suite('Text join block', function () { - /** - * Asserts that the join block has the inputs and fields we expect. - * @param {!Blockly.Block} block The text join block. - * @param {number=} inputCount The number of inputs we expect. - */ - function assertTextJoinBlockStructure(block, inputCount) { - assert.equal(block.type, 'text_join'); - if (!inputCount) { - assert.equal(block.inputList.length, 1); - const input = block.inputList[0]; - assert.equal(input.type, Blockly.inputs.inputTypes.DUMMY); - assert.equal(input.name, 'EMPTY'); - assert.isNull(block.getField('MINUS')); - // Easy way to test we're displaying quotes instead of normal text. - assert.equal(block.toString(), 'Add text “ ”'); - return; - } - - assert.equal(block.inputList.length, inputCount); - for (let i = 0; i < inputCount; i++) { - chai.assert.equal(block.inputList[i].name, 'ADD' + i); - } - assert.isNotNull(block.getField('MINUS')); - // Easy way to test we're displaying normal text instead of quotes. - assert.notEqual(block.toString(), 'Add text “ ”'); - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - }); - - teardown(function () { - this.workspace.dispose(); - }); - - test('Creation', function () { - this.block = this.workspace.newBlock('text_join'); - assertTextJoinBlockStructure(this.block, 2); - }); - - suite('Code generation', function () { - const trivialCreateBlock = (workspace) => { - return workspace.newBlock('text_join'); - }; - - /** - * Test suites for code generation tests. - * @type {Array} - */ - const testSuites = [ - { - title: 'Dart', - generator: dartGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: "['',''].join()", - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'JavaScript', - generator: javascriptGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: "'' + ''", - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Lua', - generator: luaGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: "'' .. ''", - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'PHP', - generator: phpGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: "'' . ''", - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Python', - generator: pythonGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: "'' + ''", - createBlock: trivialCreateBlock, - }, - ], - }, - ]; - - runCodeGenerationTestSuites(testSuites); - }); - - suite('Xml', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'Empty XML', - xml: '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 2); - }, - }, - { - title: '0 items', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 0); - }, - }, - { - title: '3 items', - xml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 3); - }, - }, - { - title: '3 items with child attached', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' FALSE\n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 3); - const child = block.getInputTargetBlock('ADD2'); - assert.isNotNull(child); - assert.equal(child.getFieldValue('BOOL'), 'FALSE'); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - suite('Json', function () { - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - { - title: 'No mutation', - json: { - type: 'text_join', - }, - expectedJson: { - type: 'text_join', - id: '1', - extraState: { - itemCount: 2, - }, - }, - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 2); - }, - }, - { - title: '0 items', - json: { - type: 'text_join', - id: '1', - extraState: { - itemCount: 0, - }, - }, - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 0); - }, - }, - { - title: '3 items', - json: { - type: 'text_join', - id: '1', - extraState: { - itemCount: 3, - }, - }, - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 3); - }, - }, - { - title: '3 items with child attached', - json: { - type: 'text_join', - id: '1', - extraState: { - itemCount: 3, - }, - inputs: { - ADD2: { - block: { - type: 'logic_boolean', - id: '1', - fields: { - BOOL: 'FALSE', - }, - }, - }, - }, - }, - assertBlockStructure: (block) => { - assertTextJoinBlockStructure(block, 3); - const child = block.getInputTargetBlock('ADD2'); - assert.isNotNull(child); - assert.equal(child.type, 'logic_boolean'); - assert.equal(child.getFieldValue('BOOL'), 'FALSE'); - }, - }, - ]; - runSerializationTestSuite(testCases, Blockly); - }); - - runPlusMinusTestSuite('text_join', 2, 0, 'ADD', assertTextJoinBlockStructure); -}); diff --git a/plugins/block-shareable-procedures/CHANGELOG.md b/plugins/block-shareable-procedures/CHANGELOG.md deleted file mode 100644 index e135fbac9..000000000 --- a/plugins/block-shareable-procedures/CHANGELOG.md +++ /dev/null @@ -1,682 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Remove deprecated calls from block-shareable-procedures ([#2699](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2699)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [6.0.12](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.11...@blockly/block-shareable-procedures@6.0.12) (2026-04-23) - - -### Bug Fixes - -* Fix creation of variables in the main workspace when opening flyout ([#2686](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2686)) ([d7dba88](https://github.com/RaspberryPiFoundation/blockly-samples/commit/d7dba8803ca2cfc66cbdfb72a060a7f101f40c8a)) - - - -## [6.0.11](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.10...@blockly/block-shareable-procedures@6.0.11) (2026-04-09) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.10](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.9...@blockly/block-shareable-procedures@6.0.10) (2026-01-15) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.8...@blockly/block-shareable-procedures@6.0.9) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.7...@blockly/block-shareable-procedures@6.0.8) (2026-01-05) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.6...@blockly/block-shareable-procedures@6.0.7) (2025-12-22) - - -### Bug Fixes - -* reconnect procedure block statement inputs ([#2657](https://github.com/google/blockly-samples/issues/2657)) ([761b514](https://github.com/google/blockly-samples/commit/761b5147fff499d990a33ff15562362bd1236478)) - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.5...@blockly/block-shareable-procedures@6.0.6) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.4...@blockly/block-shareable-procedures@6.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.3...@blockly/block-shareable-procedures@6.0.4) (2025-10-02) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.2...@blockly/block-shareable-procedures@6.0.3) (2025-07-17) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.1...@blockly/block-shareable-procedures@6.0.2) (2025-06-12) - - -### Bug Fixes - -* Fix a bug that could cause a crash when deleting a shared procedure definition. ([#2560](https://github.com/google/blockly-samples/issues/2560)) ([506067b](https://github.com/google/blockly-samples/commit/506067b5999c54849cc205c66afffa5b49d3eec8)) - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@6.0.0...@blockly/block-shareable-procedures@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.17...@blockly/block-shareable-procedures@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.16...@blockly/block-shareable-procedures@5.0.17) (2025-05-16) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.15...@blockly/block-shareable-procedures@5.0.16) (2025-05-15) - - -### Bug Fixes - -* Remove use of deleted `Block.setEnabled()`. ([bf44961](https://github.com/google/blockly-samples/commit/bf449611e35e063a5ccd59e25d6a5e3eca3c7f56)) - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.14...@blockly/block-shareable-procedures@5.0.15) (2025-02-27) - - -### Bug Fixes - -* Mitigate shareable procedure flyout bug. ([a37225a](https://github.com/google/blockly-samples/commit/a37225a6dc4369fcec14e2a704eaa6bef9842b8c)) - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.13...@blockly/block-shareable-procedures@5.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.12...@blockly/block-shareable-procedures@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.11...@blockly/block-shareable-procedures@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.10...@blockly/block-shareable-procedures@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.9...@blockly/block-shareable-procedures@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.8...@blockly/block-shareable-procedures@5.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.7...@blockly/block-shareable-procedures@5.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.6...@blockly/block-shareable-procedures@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.5...@blockly/block-shareable-procedures@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.4...@blockly/block-shareable-procedures@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.3...@blockly/block-shareable-procedures@5.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.2...@blockly/block-shareable-procedures@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.1...@blockly/block-shareable-procedures@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@5.0.0...@blockly/block-shareable-procedures@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.6...@blockly/block-shareable-procedures@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* build for the v11 branch ([#2268](https://github.com/google/blockly-samples/issues/2268)) ([c7a4fc5](https://github.com/google/blockly-samples/commit/c7a4fc5e72c5e8d9e9bc926bbbbadd1eb31792fc)) -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) -* insertion markers destroying procedure models v11 ([#2174](https://github.com/google/blockly-samples/issues/2174)) ([f14666f](https://github.com/google/blockly-samples/commit/f14666f8f7a94314bd76fc4fea2b5e88f8ba11b1)) -* shareable procedures v11 ([#2180](https://github.com/google/blockly-samples/issues/2180)) ([2d27dad](https://github.com/google/blockly-samples/commit/2d27dad7103b2039df9fca3acc706910eccf93fc)) - - - -## [4.1.6](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.5...@blockly/block-shareable-procedures@4.1.6) (2024-05-16) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.1.5](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.4...@blockly/block-shareable-procedures@4.1.5) (2024-05-09) - - -### Bug Fixes - -* add boolean to dispose function call ([#2341](https://github.com/google/blockly-samples/issues/2341)) ([161c0d1](https://github.com/google/blockly-samples/commit/161c0d18aa74bd5809ef23bdfea7a5648fb45a39)), closes [#2217](https://github.com/google/blockly-samples/issues/2217) - - - -## [4.1.4](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.3...@blockly/block-shareable-procedures@4.1.4) (2024-04-25) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.1.3](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.2...@blockly/block-shareable-procedures@4.1.3) (2024-04-04) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.1.2](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.1...@blockly/block-shareable-procedures@4.1.2) (2024-03-28) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.1.1](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.1.0...@blockly/block-shareable-procedures@4.1.1) (2024-02-08) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.1.0](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.7...@blockly/block-shareable-procedures@4.1.0) (2024-01-11) - - -### Features - -* create createBackingVariable method ([#2106](https://github.com/google/blockly-samples/issues/2106)) ([1d0df1e](https://github.com/google/blockly-samples/commit/1d0df1e56d457e67c9660e2a93e6a4f06a316395)) - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.6...@blockly/block-shareable-procedures@4.0.7) (2023-12-21) - - -### Bug Fixes - -* procedure parameter serialization ([#2125](https://github.com/google/blockly-samples/issues/2125)) ([0996ed7](https://github.com/google/blockly-samples/commit/0996ed79fe75663ed2916bc0b20cc35540887324)) - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.5...@blockly/block-shareable-procedures@4.0.6) (2023-12-14) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.4...@blockly/block-shareable-procedures@4.0.5) (2023-12-07) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.3...@blockly/block-shareable-procedures@4.0.4) (2023-11-09) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.2...@blockly/block-shareable-procedures@4.0.3) (2023-11-02) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.1...@blockly/block-shareable-procedures@4.0.2) (2023-10-30) - - -### Features - -* Publish types for block-shareable-procedures ([#1952](https://github.com/google/blockly-samples/issues/1952)) ([2b60231](https://github.com/google/blockly-samples/commit/2b602317ff1a4d28cb6e1e2ad3476d4672e61a84)) - - -### Bug Fixes - -* loading procedure callers before defs without models ([#2037](https://github.com/google/blockly-samples/issues/2037)) ([517ba1b](https://github.com/google/blockly-samples/commit/517ba1b713e20f31725c760fb1a8ab8656e242d0)) -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@4.0.0...@blockly/block-shareable-procedures@4.0.1) (2023-10-05) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.7...@blockly/block-shareable-procedures@4.0.0) (2023-09-28) - - -### ⚠ BREAKING CHANGES - -* changes for v10.2.0 (#1989) - -### release - -* changes for v10.2.0 ([#1989](https://github.com/google/blockly-samples/issues/1989)) ([4d81ea7](https://github.com/google/blockly-samples/commit/4d81ea7254412ef199a270fc740c2f45755a2725)), closes [#1844](https://github.com/google/blockly-samples/issues/1844) [#1845](https://github.com/google/blockly-samples/issues/1845) [#1863](https://github.com/google/blockly-samples/issues/1863) [#1880](https://github.com/google/blockly-samples/issues/1880) [#1885](https://github.com/google/blockly-samples/issues/1885) [#1886](https://github.com/google/blockly-samples/issues/1886) [#1887](https://github.com/google/blockly-samples/issues/1887) [#1888](https://github.com/google/blockly-samples/issues/1888) [#1919](https://github.com/google/blockly-samples/issues/1919) [#1920](https://github.com/google/blockly-samples/issues/1920) [#1983](https://github.com/google/blockly-samples/issues/1983) [#1984](https://github.com/google/blockly-samples/issues/1984) [#1985](https://github.com/google/blockly-samples/issues/1985) [#1991](https://github.com/google/blockly-samples/issues/1991) - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.6...@blockly/block-shareable-procedures@3.0.7) (2023-09-21) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.5...@blockly/block-shareable-procedures@3.0.6) (2023-09-14) - - -### Bug Fixes - -* caller args disconnecting shareable procedures ([#1918](https://github.com/google/blockly-samples/issues/1918)) ([b11bf6a](https://github.com/google/blockly-samples/commit/b11bf6a4a863dd513c3d6f6686236916b8c5a0a7)) -* deleting procedures with callers not being undoable ([#1917](https://github.com/google/blockly-samples/issues/1917)) ([3d26841](https://github.com/google/blockly-samples/commit/3d268418f6e4be8d8f739fa21d582a9dc48342d7)) - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.4...@blockly/block-shareable-procedures@3.0.5) (2023-08-31) - - -### Bug Fixes - -* loading parameters for shareable procedure blocks ([#1874](https://github.com/google/blockly-samples/issues/1874)) ([117469b](https://github.com/google/blockly-samples/commit/117469bb225e5fad11f377b33866e10753cbd7b4)) - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.3...@blockly/block-shareable-procedures@3.0.4) (2023-08-24) - - -### Bug Fixes - -* shareable procedures incorrectly reconnecting caller child blocks during mutation for ([#1865](https://github.com/google/blockly-samples/issues/1865)) ([c0ce651](https://github.com/google/blockly-samples/commit/c0ce651edc2c3064a039ce465782a681e398f51a)) - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.2...@blockly/block-shareable-procedures@3.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.1...@blockly/block-shareable-procedures@3.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@3.0.0...@blockly/block-shareable-procedures@3.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@2.0.1...@blockly/block-shareable-procedures@3.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@2.0.0...@blockly/block-shareable-procedures@2.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.11...@blockly/block-shareable-procedures@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - -### Bug Fixes - -* procedure blocks build ([4ffd49e](https://github.com/google/blockly-samples/commit/4ffd49e452881b77ec1b9942da1bed7aae559f1f)) - - - -## [1.2.11](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.10...@blockly/block-shareable-procedures@1.2.11) (2023-06-22) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.10](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.9...@blockly/block-shareable-procedures@1.2.10) (2023-05-18) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.9](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.8...@blockly/block-shareable-procedures@1.2.9) (2023-05-11) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.8](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.7...@blockly/block-shareable-procedures@1.2.8) (2023-05-04) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.7](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.6...@blockly/block-shareable-procedures@1.2.7) (2023-04-27) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.6](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.5...@blockly/block-shareable-procedures@1.2.6) (2023-03-29) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.5](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.4...@blockly/block-shareable-procedures@1.2.5) (2023-03-23) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.4](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.3...@blockly/block-shareable-procedures@1.2.4) (2023-03-09) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.3](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.2...@blockly/block-shareable-procedures@1.2.3) (2023-03-02) - - -### Bug Fixes - -* event cycles caused by deleting and adding parameters to models ([#1552](https://github.com/google/blockly-samples/issues/1552)) ([06f5186](https://github.com/google/blockly-samples/commit/06f5186edc93a7d4e3453fdceedc0c68ea2b34d8)) -* undoing moving params ([#1585](https://github.com/google/blockly-samples/issues/1585)) ([f425670](https://github.com/google/blockly-samples/commit/f4256704d4c24158c52bf175e0f2b5821e40e940)) -* undoing renames ([#1593](https://github.com/google/blockly-samples/issues/1593)) ([4ed6f93](https://github.com/google/blockly-samples/commit/4ed6f93c28a3e5a7ebacedf1c32d7daa0f8f7c13)) - - - -## [1.2.2](https://github.com/google/blockly-samples/compare/@blockly/block-shareable-procedures@1.2.1...@blockly/block-shareable-procedures@1.2.2) (2023-02-23) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## 1.2.1 (2023-02-23) - -**Note:** Version bump only for package @blockly/block-shareable-procedures - - - - - -## [1.2.0](https://github.com/google/blockly-samples/compare/@blockly/block-sharable-procedures@1.1.1...@blockly/block-sharable-procedures@1.2.0) (2023-02-23) - - -### Features - -* add procedure blocks ([#1544](https://github.com/google/blockly-samples/issues/1544)) ([c190eca](https://github.com/google/blockly-samples/commit/c190eca57865090d9b6027ae4af7eecf425396e8)) - - -### Bug Fixes - -* callers creating definition blocks in other workspaces ([#1557](https://github.com/google/blockly-samples/issues/1557)) ([a8d91d3](https://github.com/google/blockly-samples/commit/a8d91d39616793636696cf2b6a610db82ec02303)) -* create events not fired ([#1556](https://github.com/google/blockly-samples/issues/1556)) ([b70c6d8](https://github.com/google/blockly-samples/commit/b70c6d8dcfb7af45dd2a25940426971189a6b44b)) -* updating callers in response to variable renames in other workspaces ([#1558](https://github.com/google/blockly-samples/issues/1558)) ([504fd5e](https://github.com/google/blockly-samples/commit/504fd5ed95503845c4b737041da1daa134aa3d8d)) - - - -## [1.1.1](https://github.com/google/blockly-samples/compare/@blockly/block-sharable-procedures@1.1.0...@blockly/block-sharable-procedures@1.1.1) (2023-02-16) - -**Note:** Version bump only for package @blockly/block-sharable-procedures - - - - - -## [1.1.0](https://github.com/google/blockly-samples/compare/@blockly/block-sharable-procedures@1.0.1...@blockly/block-sharable-procedures@1.1.0) (2023-02-09) - - -### Features - -* add procedure data models ([#1526](https://github.com/google/blockly-samples/issues/1526)) ([2921277](https://github.com/google/blockly-samples/commit/29212774a6d438dd4f2d2e1f36f1b70ef800e6f0)) -* add procedure events ([#1536](https://github.com/google/blockly-samples/issues/1536)) ([05a02ae](https://github.com/google/blockly-samples/commit/05a02aed7f3f59758db83eb2d8459ce727405d4d)) - - - -## 1.0.1 (2023-02-02) - -**Note:** Version bump only for package @blockly/block-sharable-procedures diff --git a/plugins/block-shareable-procedures/README.md b/plugins/block-shareable-procedures/README.md deleted file mode 100644 index b961d086f..000000000 --- a/plugins/block-shareable-procedures/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# @blockly/block-shareable-procedures [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A set of [Blockly](https://www.npmjs.com/package/blockly) blocks that allow -end-users to define procedures (i.e. functions). These blocks reference explicit -backing data models, which allows them to be more easily manipulated, and shared -between workspaces. - -Note that these blocks have the same names as the built-in procedure blocks, so -you can seamlessly upgrade your existing project to use the new blocks. - -## Installation - -### Yarn - -``` -yarn add @blockly/block-shareable-procedures -``` - -### npm - -``` -npm install @blockly/block-shareable-procedures -``` - -## Usage - -See [developers.google.com/blockly/guides/create-custom-blocks/procedures/using-procedures](https://developers.google.com/blockly/guides/create-custom-blocks/procedures/using-procedures) -for more information about using this plugin. - -## License - -Apache 2.0 diff --git a/plugins/block-shareable-procedures/package.json b/plugins/block-shareable-procedures/package.json deleted file mode 100644 index 649d558b6..000000000 --- a/plugins/block-shareable-procedures/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@blockly/block-shareable-procedures", - "version": "13.2.0", - "description": "A plugin that adds procedure blocks which are backed by explicit data models.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "blockly-plugin", - "blockly-block", - "shareable-procedures" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/block-shareable-procedures#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/block-shareable-procedures" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "jsdom": "^29.1.1", - "jsdom-global": "^3.0.2", - "sinon": "^22.0.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/block-shareable-procedures/src/blocks.ts b/plugins/block-shareable-procedures/src/blocks.ts deleted file mode 100644 index 742b6da83..000000000 --- a/plugins/block-shareable-procedures/src/blocks.ts +++ /dev/null @@ -1,1395 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -import * as Blockly from 'blockly/core'; -import {ObservableProcedureModel} from './observable_procedure_model'; -import {ObservableParameterModel} from './observable_parameter_model'; -import {IProcedureBlock} from './i_procedure_block'; -import {ProcedureCreate} from './events_procedure_create'; - -/* eslint-disable @typescript-eslint/naming-convention */ - -/** - * A dictionary of the block definitions provided by this module. - * - * @type {!Object} - */ -export const blocks = Blockly.common.createBlockDefinitionsFromJsonArray([ - { - type: 'procedures_defnoreturn', - message0: '%{BKY_PROCEDURES_DEFNORETURN_TITLE} %1 %2 %3', - message1: '%{BKY_PROCEDURES_DEFNORETURN_DO} %1', - args0: [ - { - type: 'field_input', - name: 'NAME', - text: '', - spellcheck: false, - }, - { - type: 'field_label', - name: 'PARAMS', - text: '', - }, - { - type: 'input_dummy', - name: 'TOP', - }, - ], - args1: [ - { - type: 'input_statement', - name: 'STACK', - }, - ], - style: 'procedure_blocks', - helpUrl: '%{BKY_PROCEDURES_DEFNORETURN_HELPURL}', - tooltip: '%{BKY_PROCEDURES_DEFNORETURN_TOOLTIP}', - extensions: [ - 'procedure_def_get_def_mixin', - 'procedure_def_var_mixin', - 'procedure_def_update_shape_mixin', - 'procedure_def_context_menu_mixin', - 'procedure_def_onchange_mixin', - 'procedure_def_validator_helper', - 'procedure_defnoreturn_get_caller_block_mixin', - 'procedure_defnoreturn_set_comment_helper', - 'procedure_def_set_no_return_helper', - ], - mutator: 'procedure_def_mutator', - }, - { - type: 'procedures_callnoreturn', - message0: '%1 %2', - args0: [ - {type: 'field_label', name: 'NAME', text: '%{BKY_UNNAMED_KEY}'}, - { - type: 'input_dummy', - name: 'TOPROW', - }, - ], - nextStatement: null, - previousStatement: null, - style: 'procedure_blocks', - helpUrl: '%{BKY_PROCEDURES_CALLNORETURN_HELPURL}', - extensions: [ - 'procedure_caller_get_def_mixin', - 'procedure_caller_var_mixin', - 'procedure_caller_update_shape_mixin', - 'procedure_caller_context_menu_mixin', - 'procedure_caller_onchange_mixin', - 'procedure_callernoreturn_get_def_block_mixin', - ], - mutator: 'procedure_caller_mutator', - }, - { - type: 'procedures_defreturn', - message0: '%{BKY_PROCEDURES_DEFRETURN_TITLE} %1 %2 %3', - message1: '%{BKY_PROCEDURES_DEFRETURN_DO} %1', - message2: '%{BKY_PROCEDURES_DEFRETURN_RETURN} %1', - args0: [ - { - type: 'field_input', - name: 'NAME', - text: '', - spellcheck: false, - }, - { - type: 'field_label', - name: 'PARAMS', - text: '', - }, - { - type: 'input_dummy', - name: 'TOP', - }, - ], - args1: [ - { - type: 'input_statement', - name: 'STACK', - }, - ], - args2: [ - { - type: 'input_value', - align: 'right', - name: 'RETURN', - }, - ], - style: 'procedure_blocks', - helpUrl: '%{BKY_PROCEDURES_DEFRETURN_HELPURL}', - tooltip: '%{BKY_PROCEDURES_DEFRETURN_TOOLTIP}', - extensions: [ - 'procedure_def_get_def_mixin', - 'procedure_def_var_mixin', - 'procedure_def_update_shape_mixin', - 'procedure_def_context_menu_mixin', - 'procedure_def_onchange_mixin', - 'procedure_def_validator_helper', - 'procedure_defreturn_get_caller_block_mixin', - 'procedure_defreturn_set_comment_helper', - 'procedure_def_set_return_helper', - ], - mutator: 'procedure_def_mutator', - }, - { - type: 'procedures_callreturn', - message0: '%1 %2', - args0: [ - {type: 'field_label', name: 'NAME', text: '%{BKY_UNNAMED_KEY}'}, - { - type: 'input_dummy', - name: 'TOPROW', - }, - ], - output: null, - style: 'procedure_blocks', - helpUrl: '%{BKY_PROCEDURES_CALLRETURN_HELPURL}', - extensions: [ - 'procedure_caller_get_def_mixin', - 'procedure_caller_var_mixin', - 'procedure_caller_update_shape_mixin', - 'procedure_caller_context_menu_mixin', - 'procedure_caller_onchange_mixin', - 'procedure_callerreturn_get_def_block_mixin', - ], - mutator: 'procedure_caller_mutator', - }, -]); - -const procedureDefGetDefMixin = function () { - const mixin = { - model_: null, - - /** - * Returns the data model for this procedure block. - * - * @returns The data model for this procedure - * block. - */ - getProcedureModel() { - return this.model_; - }, - - /** - * True if this is a procedure definition block, false otherwise (i.e. - * it is a caller). - * - * @returns True because this is a procedure definition block. - */ - isProcedureDef() { - return true; - }, - - /** - * Return all variables referenced by this block. - * - * @returns List of variable names. - * @this {Blockly.Block} - */ - getVars: function () { - return this.getProcedureModel() - .getParameters() - .map((p) => p.getVariableModel().name); - }, - - /** - * Return all variables referenced by this block. - * - * @returns List of variable models. - * @this {Blockly.Block} - */ - getVarModels: function () { - return this.getProcedureModel() - .getParameters() - .map((p) => p.getVariableModel()); - }, - - /** - * Disposes of the data model for this procedure block when the block is - * disposed. - */ - destroy: function () { - if (!this.isInsertionMarker()) { - this.workspace - .getProcedureMap() - .delete(this.getProcedureModel().getId()); - } - }, - }; - - mixin.model_ = new ObservableProcedureModel( - this.workspace, - Blockly.Procedures.findLegalName(this.getFieldValue('NAME'), this), - ); - - // Events cannot be fired from instantiation when deserializing or dragging - // from the flyout. So make this consistent and never fire from instantiation. - Blockly.Events.disable(); - this.workspace.getProcedureMap().add(mixin.getProcedureModel()); - Blockly.Events.enable(); - - this.mixin(mixin, true); -}; -// Using register instead of registerMixin to avoid triggering warnings about -// overriding built-ins. -Blockly.Extensions.register( - 'procedure_def_get_def_mixin', - procedureDefGetDefMixin, -); - -const procedureDefVarMixin = function () { - const mixin = { - /** - * Notification that a variable is renaming. - * If the ID matches one of this block's variables, rename it. - * - * @param oldId ID of variable to rename. - * @param newId ID of new variable. May be the same as oldId, but - * with an updated name. Guaranteed to be the same type as the old - * variable. - * @override - * @this {Blockly.Block} - */ - renameVarById: function (oldId, newId) { - const oldVar = this.workspace.getVariableMap().getVariableById(oldId); - const model = this.getProcedureModel(); - const index = model - .getParameters() - .findIndex((p) => p.getVariableModel() === oldVar); - if (index === -1) return; // Not found. - const newVar = this.workspace.getVariableMap().getVariableById(newId); - const oldParam = model.getParameter(index); - oldParam.setName(newVar.name); - }, - - /** - * Notification that a variable is renaming but keeping the same ID. If the - * variable is in use on this block, rerender to show the new name. - * - * @param variable The variable being renamed. - * @package - * @override - * @this {Blockly.Block} - */ - updateVarName: function (variable) { - const containsVar = this.getProcedureModel() - .getParameters() - .some((p) => p.getVariableModel() === variable); - if (containsVar) { - this.doProcedureUpdate(); // Rerender. - } - }, - }; - - this.mixin(mixin, true); -}; -// Using register instead of registerMixin to avoid triggering warnings about -// overriding built-ins. -Blockly.Extensions.register('procedure_def_var_mixin', procedureDefVarMixin); - -const procedureDefUpdateShapeMixin = { - /** - * Updates the block to reflect the state of the procedure model. - */ - doProcedureUpdate: function () { - this.setFieldValue(this.getProcedureModel().getName(), 'NAME'); - this.setDisabledReason(!this.getProcedureModel().getEnabled()); - this.updateParameters_(); - this.updateMutator_(); - }, - - /** - * Updates the parameters field to reflect the parameters in the procedure - * model. - */ - updateParameters_: function () { - const params = this.getProcedureModel() - .getParameters() - .map((p) => p.getName()); - const paramString = params.length - ? `${Blockly.Msg['PROCEDURES_BEFORE_PARAMS']} ${params.join(', ')}` - : ''; - - // The field is deterministic based on other events, no need to fire. - Blockly.Events.disable(); - try { - this.setFieldValue(paramString, 'PARAMS'); - } finally { - Blockly.Events.enable(); - } - }, - - /** - * Updates the parameter blocks in the mutator (if it is open) to reflect - * the state of the procedure model. - */ - updateMutator_: function () { - const mutator = this.getIcon(Blockly.icons.MutatorIcon.TYPE); - if (!mutator?.bubbleIsVisible()) return; - - const mutatorWorkspace = this.mutator.getWorkspace(); - for (const p of this.getProcedureModel().getParameters()) { - const block = mutatorWorkspace.getBlockById(p.getId()); - if (!block) continue; // Should not happen. - if (block.getFieldValue('NAME') !== p.getName()) { - block.setFieldValue(p.getName(), 'NAME'); - } - } - }, - - /** - * Add or remove the statement block from this function definition. - * - * @param hasStatements True if a statement block is needed. - * @this {Blockly.Block} - */ - setStatements_: function (hasStatements) { - if (this.hasStatements_ === hasStatements) { - return; - } - if (hasStatements) { - this.appendStatementInput('STACK').appendField( - Blockly.Msg['PROCEDURES_DEFNORETURN_DO'], - ); - if (this.getInput('RETURN')) { - this.moveInputBefore('STACK', 'RETURN'); - } - // Restore the stack, if one was saved. - this.statementConnection_?.reconnect(this, 'STACK'); - this.statementConnection_ = null; - } else { - // Save the stack, then disconnect it. - const stackConnection = this.getInput('STACK').connection; - this.statementConnection_ = stackConnection.targetConnection; - if (this.statementConnection_) { - const stackBlock = stackConnection.targetBlock(); - stackBlock.unplug(); - stackBlock.bumpNeighbours(); - } - this.removeInput('STACK', true); - } - this.hasStatements_ = hasStatements; - }, -}; -Blockly.Extensions.registerMixin( - 'procedure_def_update_shape_mixin', - procedureDefUpdateShapeMixin, -); - -const procedureDefValidatorHelper = function () { - const nameField = this.getField('NAME'); - nameField.setValue(Blockly.Procedures.findLegalName('', this)); - nameField.setValidator(Blockly.Procedures.rename); -}; -Blockly.Extensions.register( - 'procedure_def_validator_helper', - procedureDefValidatorHelper, -); - -const procedureDefMutator = { - hasStatements_: true, - - /** - * Create XML to represent the argument inputs. - * Backwards compatible serialization implementation. - * - * @returns XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - const container = Blockly.utils.xml.createElement('mutation'); - const params = this.getProcedureModel().getParameters(); - for (let i = 0; i < params.length; i++) { - const parameter = Blockly.utils.xml.createElement('arg'); - const varModel = params[i].getVariableModel(); - parameter.setAttribute('name', varModel.name); - parameter.setAttribute('varid', varModel.getId()); - container.appendChild(parameter); - } - - // Save whether the statement input is visible. - if (!this.hasStatements_) { - container.setAttribute('statements', 'false'); - } - return container; - }, - - /** - * Parse XML to restore the argument inputs. - * Backwards compatible serialization implementation. - * - * @param xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - for (let i = 0; i < xmlElement.childNodes.length; i++) { - const node = xmlElement.childNodes[i]; - if (node.nodeName.toLowerCase() !== 'arg') continue; - const varId = node.getAttribute('varid'); - this.getProcedureModel().insertParameter( - new ObservableParameterModel( - this.workspace, - node.getAttribute('name'), - undefined, - varId, - ), - i, - ); - } - this.setStatements_(xmlElement.getAttribute('statements') !== 'false'); - }, - - /** - * Returns the state of this block as a JSON serializable object. - * - * @param doFullSerialization Tells the block if it should serialize - * its entire state (including data stored in the backing procedure - * model). Used for copy-paste. - * @returns The state of this block, eg the parameters and statements. - */ - saveExtraState: function (doFullSerialization) { - const state = Object.create(null); - state['procedureId'] = this.getProcedureModel().getId(); - - if (doFullSerialization) { - state['fullSerialization'] = true; - const params = this.getProcedureModel().getParameters(); - if (params.length) { - state['params'] = params.map((p) => { - return { - name: p.getName(), - id: p.getVariableModel().getId(), - // Ideally this would be id, and the other would be varId, - // but backwards compatibility :/ - paramId: p.getId(), - }; - }); - } - } - if (!this.hasStatements_) { - state['hasStatements'] = false; - } - return state; - }, - - /** - * Applies the given state to this block. - * - * @param state The state to apply to this block, eg the parameters and - * statements. - */ - loadExtraState: function (state) { - const map = this.workspace.getProcedureMap(); - - const procedureId = state['procedureId']; - if (map.has(procedureId) && !state['fullSerialization']) { - if (map.has(this.model_.getId())) { - map.delete(this.model_.getId()); - } - this.model_ = map.get(procedureId); - } - - const model = this.getProcedureModel(); - const newParams = state['params'] ?? []; - const newIds = new Set(newParams.map((p) => p.id)); - const currParams = model.getParameters(); - if (state['fullSerialization']) { - for (let i = currParams.length - 1; i >= 0; i--) { - if (!newIds.has(currParams[i].getId)) { - model.deleteParameter(i); - } - } - } - for (let i = 0; i < newParams.length; i++) { - const {name, id, paramId} = state['params'][i]; - this.getProcedureModel().insertParameter( - new ObservableParameterModel(this.workspace, name, paramId, id), - i, - ); - } - - this.doProcedureUpdate(); - this.setStatements_(state['hasStatements'] === false ? false : true); - }, - - /** - * Populate the mutator's dialog with this block's components. - * - * @param workspace Blockly.Mutator's workspace. - * @returns Root block in mutator. - * @this {Blockly.Block} - */ - decompose: function (workspace) { - const containerBlockDef = { - type: 'procedures_mutatorcontainer', - inputs: { - STACK: {}, - }, - }; - - let connDef = containerBlockDef['inputs']['STACK']; - for (const param of this.getProcedureModel().getParameters()) { - connDef['block'] = { - type: 'procedures_mutatorarg', - id: param.getId(), - fields: { - NAME: param.getName(), - }, - next: {}, - }; - connDef = connDef['block']['next']; - } - - const containerBlock = Blockly.serialization.blocks.append( - containerBlockDef as unknown as Blockly.serialization.blocks.State, - workspace, - {recordUndo: false}, - ); - - if (this.type === 'procedures_defreturn') { - containerBlock.setFieldValue(this.hasStatements_, 'STATEMENTS'); - } else { - containerBlock.removeInput('STATEMENT_INPUT'); - } - - return containerBlock; - }, - - /** - * Reconfigure this block based on the mutator dialog's components. - * - * @param containerBlock Root block in mutator. - * @this {Blockly.Block} - */ - compose: function (containerBlock) { - // Note that only one of these four things can actually occur for any given - // composition, because the user can only drag blocks around so quickly. - // So we can use that when making assumptions inside the definitions of - // these sub procedures. - this.deleteParamsFromModel_(containerBlock); - this.renameParamsInModel_(containerBlock); - this.addParamsToModel_(containerBlock); - - const hasStatements = containerBlock.getFieldValue('STATEMENTS'); - if (hasStatements !== null) { - this.setStatements_(hasStatements === 'TRUE'); - } - }, - - /** - * Deletes any parameters from the procedure model that do not have associated - * parameter blocks in the mutator. - * - * @param containerBlock Root block in the mutator. - */ - deleteParamsFromModel_: function (containerBlock) { - const ids = new Set(containerBlock.getDescendants().map((b) => b.id)); - const model = this.getProcedureModel(); - const count = model.getParameters().length; - for (let i = count - 1; i >= 0; i--) { - if (!ids.has(model.getParameter(i).getId())) { - model.deleteParameter(i); - } - } - }, - - /** - * Renames any parameters in the procedure model whose associated parameter - * blocks have been renamed. - * - * @param containerBlock Root block in the mutator. - */ - renameParamsInModel_: function (containerBlock) { - const model = this.getProcedureModel(); - - let i = 0; - let paramBlock = containerBlock.getInputTargetBlock('STACK'); - while (paramBlock && !paramBlock.isInsertionMarker()) { - const param = model.getParameter(i); - if ( - param && - param.getId() === paramBlock.id && - param.getName() !== paramBlock.getFieldValue('NAME') - ) { - param.setName(paramBlock.getFieldValue('NAME')); - } - paramBlock = - paramBlock.nextConnection && paramBlock.nextConnection.targetBlock(); - i++; - } - }, - - /** - * Adds new parameters to the procedure model for any new procedure parameter - * blocks. - * - * @param containerBlock Root block in the mutator. - */ - addParamsToModel_: function (containerBlock) { - const model = this.getProcedureModel(); - - let i = 0; - let paramBlock = containerBlock.getInputTargetBlock('STACK'); - while (paramBlock && !paramBlock.isInsertionMarker()) { - if ( - !model.getParameter(i) || - model.getParameter(i).getId() !== paramBlock.id - ) { - model.insertParameter( - new ObservableParameterModel( - this.workspace, - paramBlock.getFieldValue('NAME'), - paramBlock.id, - ), - i, - ); - } - paramBlock = - paramBlock.nextConnection && paramBlock.nextConnection.targetBlock(); - i++; - } - }, -}; -Blockly.Extensions.registerMutator( - 'procedure_def_mutator', - procedureDefMutator, - undefined, - ['procedures_mutatorarg'], -); - -const procedureDefContextMenuMixin = { - /** - * Add custom menu options to this block's context menu. - * - * @param options List of menu options to add to. - * @this {Blockly.Block} - */ - customContextMenu: function ( - options: Array< - | Blockly.ContextMenuRegistry.ContextMenuOption - | Blockly.ContextMenuRegistry.LegacyContextMenuOption - >, - ) { - if (this.isInFlyout) { - return; - } - - const xmlMutation = Blockly.utils.xml.createElement('mutation'); - xmlMutation.setAttribute('name', this.getFieldValue('NAME')); - const params = this.getProcedureModel().getParameters(); - for (const param of params) { - const xmlArg = Blockly.utils.xml.createElement('arg'); - xmlArg.setAttribute('name', param.getName()); - xmlMutation.appendChild(xmlArg); - } - const xmlBlock = Blockly.utils.xml.createElement('block'); - xmlBlock.setAttribute('type', this.callType_); - xmlBlock.appendChild(xmlMutation); - - // Add option to create caller. - options.push({ - enabled: true, - text: Blockly.Msg['PROCEDURES_CREATE_DO'].replace( - '%1', - this.getFieldValue('NAME'), - ), - callback: Blockly.ContextMenu.callbackFactory( - this, - xmlBlock, - ) as () => void, - }); - - // Add options to create getters for each parameter. - if (this.isCollapsed()) return; - - for (const param of params) { - const argVar = param.getVariableModel(); - const argXmlField = Blockly.Variables.generateVariableFieldDom(argVar); - const argXmlBlock = Blockly.utils.xml.createElement('block'); - argXmlBlock.setAttribute('type', 'variables_get'); - argXmlBlock.appendChild(argXmlField); - options.push({ - enabled: true, - text: Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace( - '%1', - argVar.name, - ), - callback: Blockly.ContextMenu.callbackFactory( - this, - argXmlBlock, - ) as () => void, - }); - } - }, -}; -Blockly.Extensions.registerMixin( - 'procedure_def_context_menu_mixin', - procedureDefContextMenuMixin, -); - -const procedureDefOnChangeMixin = { - onchange: function (e) { - if (e.type === Blockly.Events.BLOCK_CREATE && e.blockId === this.id) { - Blockly.Events.fire( - new ProcedureCreate(this.workspace, this.getProcedureModel()), - ); - } - if ( - e.type === Blockly.Events.BLOCK_CHANGE && - e.blockId === this.id && - e.element === 'disabled' - ) { - this.getProcedureModel().setEnabled(this.isEnabled()); - } - }, -}; -Blockly.Extensions.registerMixin( - 'procedure_def_onchange_mixin', - procedureDefOnChangeMixin, -); - -const procedureDefNoReturnSetCommentHelper = function () { - if ( - (this.workspace.options.comments || - (this.workspace.options.parentWorkspace && - this.workspace.options.parentWorkspace.options.comments)) && - Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT'] - ) { - this.setCommentText(Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']); - } -}; -Blockly.Extensions.register( - 'procedure_defnoreturn_set_comment_helper', - procedureDefNoReturnSetCommentHelper, -); - -const procedureDefReturnSetCommentHelper = function () { - if ( - (this.workspace.options.comments || - (this.workspace.options.parentWorkspace && - this.workspace.options.parentWorkspace.options.comments)) && - Blockly.Msg['PROCEDURES_DEFRETURN_COMMENT'] - ) { - this.setCommentText(Blockly.Msg['PROCEDURES_DEFRETURN_COMMENT']); - } -}; -Blockly.Extensions.register( - 'procedure_defreturn_set_comment_helper', - procedureDefReturnSetCommentHelper, -); - -const procedureDefNoReturnGetCallerBlockMixin = { - callType_: 'procedures_callnoreturn', -}; -Blockly.Extensions.registerMixin( - 'procedure_defnoreturn_get_caller_block_mixin', - procedureDefNoReturnGetCallerBlockMixin, -); - -const procedureDefReturnGetCallerBlockMixin = { - callType_: 'procedures_callreturn', -}; -Blockly.Extensions.registerMixin( - 'procedure_defreturn_get_caller_block_mixin', - procedureDefReturnGetCallerBlockMixin, -); - -const procedureDefSetNoReturnHelper = function () { - this.getProcedureModel().setReturnTypes(null); -}; -Blockly.Extensions.register( - 'procedure_def_set_no_return_helper', - procedureDefSetNoReturnHelper, -); - -const procedureDefSetReturnHelper = function () { - this.getProcedureModel().setReturnTypes([]); -}; -Blockly.Extensions.register( - 'procedure_def_set_return_helper', - procedureDefSetReturnHelper, -); - -const procedureCallerGetDefMixin = function () { - const mixin = { - model_: null, - - prevParams_: [], - - argsMap_: new Map(), - - /** - * Returns the procedure model associated with this block. - * - * @returns The procedure model associated with this block. - */ - getProcedureModel() { - return this.model_; - }, - - /** - * Returns the procedure model tha was found. - * - * @param name The name of the procedure model to find. - * @param params The param names of the procedure model - * to find. - * @returns The procedure model that was found. - */ - findProcedureModel_(name, params = []) { - const workspace = this.getTargetWorkspace_(); - const model = workspace - .getProcedureMap() - .getProcedures() - .find((proc) => proc.getName() === name); - if (!model) return null; - - const returnTypes = model.getReturnTypes(); - const hasMatchingReturn = this.hasReturn_ ? returnTypes : !returnTypes; - if (!hasMatchingReturn) return null; - - const hasMatchingParams = model - .getParameters() - .every((p, i) => p.getName() === params[i]); - if (!hasMatchingParams) return null; - - return model; - }, - - /** - * Returns the main workspace (i.e. not the flyout workspace) associated - * with this block. - * - * @returns The main workspace (i.e. not the flyout workspace) associated - * with this block. - */ - getTargetWorkspace_() { - return this.workspace.isFlyout - ? this.workspace.targetWorkspace - : this.workspace; - }, - - /** - * True if this is a procedure definition block, false otherwise (i.e. - * it is a caller). - * - * @returns False because this is not a procedure definition block. - */ - isProcedureDef() { - return false; - }, - - /** - * Return all variables referenced by this block. - * - * @returns List of variable names. - * @this {Blockly.Block} - */ - getVars: function () { - return this.getProcedureModel() - .getParameters() - .map((p) => p.getVariableModel().name); - }, - - /** - * Return all variables referenced by this block. - * - * @returns List of variable models. - * @this {Blockly.Block} - */ - getVarModels: function () { - return this.getProcedureModel() - .getParameters() - .map((p) => p.getVariableModel()); - }, - }; - - this.mixin(mixin, true); -}; -// Using register instead of registerMixin to avoid triggering warnings about -// overriding built-ins. -Blockly.Extensions.register( - 'procedure_caller_get_def_mixin', - procedureCallerGetDefMixin, -); - -const procedureCallerVarMixin = function () { - const mixin = { - /** - * Notification that a variable is renaming but keeping the same ID. If the - * variable is in use on this block, rerender to show the new name. - * - * @param variable The variable being renamed. - * @package - * @override - * @this {Blockly.Block} - */ - updateVarName: function (variable) { - const containsVar = this.getProcedureModel() - .getParameters() - .some((p) => p.getVariableModel() === variable); - if (containsVar) { - this.doProcedureUpdate(); // Rerender. - } - }, - }; - - this.mixin(mixin, true); -}; -// Using register instead of registerMixin to avoid triggering warnings about -// overriding built-ins. -Blockly.Extensions.register( - 'procedure_caller_var_mixin', - procedureCallerVarMixin, -); - -const procedureCallerMutator = { - paramsFromSerializedState_: [], - - /** - * Create XML to represent the (non-editable) name and arguments. - * Backwards compatible serialization implementation. - * - * @returns XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - const container = Blockly.utils.xml.createElement('mutation'); - const model = this.getProcedureModel(); - if (!model) return container; - - container.setAttribute('name', model.getName()); - for (const param of model.getParameters()) { - const arg = Blockly.utils.xml.createElement('arg'); - arg.setAttribute('name', param.getName()); - container.appendChild(arg); - } - return container; - }, - - /** - * Parse XML to restore the (non-editable) name and parameters. - * Backwards compatible serialization implementation. - * - * @param xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - const name = xmlElement.getAttribute('name'); - const params = []; - for (const n of xmlElement.childNodes) { - if (n.nodeName.toLowerCase() === 'arg') { - params.push(n.getAttribute('name')); - } - } - this.deserialize_(name, params); - }, - - /** - * Returns the state of this block as a JSON serializable object. - * - * @returns The state of - * this block, ie the params and procedure name. - */ - saveExtraState: function () { - const state = Object.create(null); - const model = this.getProcedureModel(); - if (!model) { - // We reached here because we've deserialized a caller into a workspace - // where its model did not already exist (no procedures array in the json, - // and deserialized before any definition block), and are reserializing - // it before the event delay has elapsed and change listeners have run. - // (If they had run, we would have found or created a model). - // Just reserialize any deserialized state. Nothing should have happened - // in-between to change it. - state['name'] = this.getFieldValue('NAME'); - state['params'] = this.paramsFromSerializedState_; - return state; - } - state['name'] = model.getName(); - if (model.getParameters().length) { - state['params'] = model.getParameters().map((p) => p.getName()); - } - return state; - }, - - /** - * Applies the given state to this block. - * - * @param state The state to apply to this block, ie the params and - * procedure name. - */ - loadExtraState: function (state) { - this.deserialize_(state['name'], state['params'] || []); - }, - - /** - * Applies the given name and params from the serialized state to the block. - * - * @param name The name to apply to the block. - * @param params The parameters to apply to the block. - */ - deserialize_: function (name, params) { - this.setFieldValue(name, 'NAME'); - if (!this.model_) this.model_ = this.findProcedureModel_(name, params); - if (this.getProcedureModel()) { - this.initBlockWithProcedureModel_(); - } else { - // Create inputs based on the mutation so that children can be connected. - this.createArgInputs_(params); - } - this.paramsFromSerializedState_ = params; - }, -}; -Blockly.Extensions.registerMutator( - 'procedure_caller_mutator', - procedureCallerMutator, -); - -const PROCEDURE_MODEL_DISABLED_REASON = 'PROCEDURE_MODEL_DISABLED'; - -const procedureCallerUpdateShapeMixin = { - /** - * Renders the block for the first time based on the procedure model. - */ - initBlockWithProcedureModel_() { - this.prevParams_ = [...this.getProcedureModel().getParameters()]; - this.doProcedureUpdate(); - }, - - /** - * Updates the shape of this block to reflect the state of the data model. - */ - doProcedureUpdate: function () { - if (!this.getProcedureModel() || this.isDeadOrDying()) return; - const id = this.getProcedureModel().getId(); - if ( - !this.getTargetWorkspace_().getProcedureMap().has(id) && - !this.isInFlyout - ) { - this.dispose(true); - return; - } - this.updateName_(); - this.updateEnabled_(); - this.updateParameters_(); - }, - - /** - * Updates the name field of this block to match the state of the data model. - */ - updateName_: function () { - const name = this.getProcedureModel().getName(); - this.setFieldValue(name, 'NAME'); - const baseMsg = this.outputConnection - ? Blockly.Msg['PROCEDURES_CALLRETURN_TOOLTIP'] - : Blockly.Msg['PROCEDURES_CALLNORETURN_TOOLTIP']; - this.setTooltip(baseMsg.replace('%1', name)); - }, - - /** - * Updates the enabled state of this block to match the state of the data - * model. - */ - updateEnabled_: function () { - this.setDisabledReason( - !this.getProcedureModel().getEnabled(), - PROCEDURE_MODEL_DISABLED_REASON, - ); - }, - - /** - * Updates the parameter fields/inputs of this block to match the state of the - * data model. - */ - updateParameters_: function () { - this.syncArgsMap_(); - this.deleteAllArgInputs_(); - this.addParametersLabel__(); - this.createArgInputs_(); - this.reattachBlocks_(); - this.prevParams_ = [...this.getProcedureModel().getParameters()]; - }, - - /** - * Makes sure that if we are updating the parameters before any move events - * have happened, the args map records the current state of the block. Does - * not remove entries from the array, since blocks can be disconnected - * temporarily during mutation (which triggers this method). - */ - syncArgsMap_: function () { - // We look at the prevParams array because the current state of the block - // matches the old params, not the new params state. - for (const [i, p] of this.prevParams_.entries()) { - const target = this.getInputTargetBlock(`ARG${i}`); - if (target) this.argsMap_.set(p.getId(), target); - } - }, - - /** - * Saves a map of parameter IDs to target blocks attached to the inputs - * of this caller block. - */ - updateArgsMap_: function () { - for (const [i, p] of this.getProcedureModel().getParameters().entries()) { - const target = this.getInputTargetBlock(`ARG${i}`); - if (target) { - this.argsMap_.set(p.getId(), target); - } else { - this.argsMap_.delete(p.getId()); - } - } - }, - - /** - * Deletes all the parameter inputs on this block. - */ - deleteAllArgInputs_: function () { - let i = 0; - while (this.getInput(`ARG${i}`)) { - this.removeInput(`ARG${i}`); - i++; - } - }, - - /** - * Adds or removes the parameter label to match the state of the data model. - */ - addParametersLabel__: function () { - const topRow = this.getInput('TOPROW'); - if (this.getProcedureModel().getParameters().length) { - if (!this.getField('WITH')) { - topRow.appendField( - Blockly.Msg['PROCEDURES_CALL_BEFORE_PARAMS'], - 'WITH', - ); - topRow.init(); - } - } else if (this.getField('WITH')) { - topRow.removeField('WITH'); - } - }, - - /** - * Creates all of the parameter inputs to match the state of the data model. - * - * @param params The params to add to the block, or null to - * use the params defined in the procedure model. - */ - createArgInputs_: function (params = null) { - if (!params) { - params = this.getProcedureModel() - .getParameters() - .map((p) => p.getName()); - } - for (const [i, p] of params.entries()) { - this.appendValueInput(`ARG${i}`) - .appendField(new Blockly.FieldLabel(p), `ARGNAME${i}`) - .setAlign(Blockly.inputs.Align.RIGHT); - } - }, - - /** - * Reattaches blocks to this blocks' inputs based on the data saved in the - * argsMap_. - */ - reattachBlocks_: function () { - const params = this.getProcedureModel().getParameters(); - for (const [i, p] of params.entries()) { - if (!this.argsMap_.has(p.getId())) continue; - this.getInput(`ARG${i}`).connection.connect( - this.argsMap_.get(p.getId()).outputConnection, - ); - } - }, - - /** - * Notification that a procedure is renaming. - * If the name matches this block's procedure, rename it. - * - * @param oldName Previous name of procedure. - * @param newName Renamed procedure. - * @this {Blockly.Block} - */ - renameProcedure: function (oldName, newName) { - if (Blockly.Names.equals(oldName, this.getFieldValue('NAME'))) { - this.setFieldValue(newName, 'NAME'); - const baseMsg = this.outputConnection - ? Blockly.Msg['PROCEDURES_CALLRETURN_TOOLTIP'] - : Blockly.Msg['PROCEDURES_CALLNORETURN_TOOLTIP']; - this.setTooltip(baseMsg.replace('%1', newName)); - } - }, -}; -Blockly.Extensions.registerMixin( - 'procedure_caller_update_shape_mixin', - procedureCallerUpdateShapeMixin, -); - -const procedureCallerOnChangeMixin = { - /** - * Procedure calls cannot exist without the corresponding procedure - * definition. Enforce this link whenever an event is fired. - * - * @param event Change event. - * @this {Blockly.Block} - */ - onchange: function (event) { - if (this.disposed || this.workspace.isFlyout) return; - if (event.type === Blockly.Events.BLOCK_MOVE) this.updateArgsMap_(true); - if ( - event.type !== Blockly.Events.FINISHED_LOADING && - !this.eventIsCreatingThisBlockDuringPaste_(event) - ) - return; - - // We already found our model, which means we don't need to create a block. - if (this.getProcedureModel()) return; - - // Look for the case where a procedure call was created (usually through - // paste) and there is no matching definition. In this case, create - // an empty definition block with the correct signature. - const name = this.getFieldValue('NAME'); - let def = Blockly.Procedures.getDefinition(name, this.workspace); - if (!this.defMatches_(def)) def = null; - if (!def) { - // We have no def nor procedure model. - Blockly.Events.setGroup(event.group); - this.model_ = this.createDef_( - this.getFieldValue('NAME'), - this.paramsFromSerializedState_, - ); - Blockly.Events.setGroup(false); - } - if (!this.getProcedureModel()) { - // We have a def, but no reference to its model. - this.model_ = this.findProcedureModel_( - this.getFieldValue('NAME'), - this.paramsFromSerializedState_, - ); - } - this.initBlockWithProcedureModel_(); - }, - - /** - * @param event The event to check. - * @returns True if the given event is a paste event for this block. - */ - eventIsCreatingThisBlockDuringPaste_(event) { - return ( - event.type === Blockly.Events.BLOCK_CREATE && - (event.blockId === this.id || event.ids.indexOf(this.id) !== -1) && - // Record undo makes sure this is during paste. - event.recordUndo - ); - }, - - /** - * Returns true if the given def block matches the definition of this caller - * block. - * - * @param defBlock The definition block to check against. - * @returns Whether the def block matches or not. - */ - defMatches_(defBlock) { - return ( - defBlock && - defBlock.type === this.defType_ && - JSON.stringify(defBlock.getVars()) === - JSON.stringify(this.paramsFromSerializedState_) - ); - }, - - /** - * Creates a procedure definition block with the given name and params, - * and returns the procedure model associated with it. - * - * @param name The name of the procedure to create. - * @param params The names of the parameters to create. - * @returns The procedure model associated with the new - * procedure definition block. - */ - createDef_(name, params = []) { - const xy = this.getRelativeToSurfaceXY(); - const newName = Blockly.Procedures.findLegalName(name, this); - this.renameProcedure(name, newName); - - const blockDef = { - type: this.defType_, - x: xy.x + Blockly.config.snapRadius * (this.RTL ? -1 : 1), - y: xy.y + Blockly.config.snapRadius * 2, - extraState: { - params: params.map((p) => ({name: p})), - }, - fields: {NAME: newName}, - }; - const block = Blockly.serialization.blocks.append( - blockDef, - this.getTargetWorkspace_(), - {recordUndo: true}, - ); - return (block as unknown as IProcedureBlock).getProcedureModel(); - }, -}; -Blockly.Extensions.registerMixin( - 'procedure_caller_onchange_mixin', - procedureCallerOnChangeMixin, -); - -const procedureCallerContextMenuMixin = { - /** - * Add menu option to find the definition block for this call. - * - * @param options List of menu options to add to. - * @this {Blockly.Block} - */ - customContextMenu: function (options) { - if (!this.workspace.isMovable()) { - // If we center on the block and the workspace isn't movable we could - // lose blocks at the edges of the workspace. - return; - } - - const name = this.getFieldValue('NAME'); - const workspace = this.workspace; - const callback = function () { - const def = Blockly.Procedures.getDefinition(name, workspace); - if (def && def instanceof Blockly.BlockSvg) { - workspace.centerOnBlock(def.id); - def.select(); - } - }; - options.push({ - enabled: true, - text: Blockly.Msg['PROCEDURES_HIGHLIGHT_DEF'], - callback: callback, - }); - }, -}; -Blockly.Extensions.registerMixin( - 'procedure_caller_context_menu_mixin', - procedureCallerContextMenuMixin, -); - -const procedureCallerNoReturnGetDefBlockMixin = { - hasReturn_: false, - defType_: 'procedures_defnoreturn', -}; -Blockly.Extensions.registerMixin( - 'procedure_callernoreturn_get_def_block_mixin', - procedureCallerNoReturnGetDefBlockMixin, -); - -const procedureCallerReturnGetDefBlockMixin = { - hasReturn_: true, - defType_: 'procedures_defreturn', -}; -Blockly.Extensions.registerMixin( - 'procedure_callerreturn_get_def_block_mixin', - procedureCallerReturnGetDefBlockMixin, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_base.ts b/plugins/block-shareable-procedures/src/events_procedure_base.ts deleted file mode 100644 index 11a7978f5..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_base.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -/** - * The base event for an event associated with a procedure. - */ -export abstract class ProcedureBase extends Blockly.Events.Abstract { - static readonly TYPE: string = 'procedure_base'; - - /** A string used to check the type of the event. */ - type = ProcedureBase.TYPE; - - isBlank = false; - - /** - * Constructs the base procedure event. - * - * @param workspace The workspace the procedure model exists in. - * @param procedure The procedure model associated with this event. - */ - constructor( - workspace: Blockly.Workspace, - readonly procedure: Blockly.procedures.IProcedureModel, - ) { - super(); - this.workspaceId = workspace.id; - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureBaseJson { - const json = super.toJson() as ProcedureBaseJson; - json['procedureId'] = this.procedure.getId(); - return json; - } -} - -export interface ProcedureBaseJson extends Blockly.Events.AbstractEventJson { - procedureId: string; -} diff --git a/plugins/block-shareable-procedures/src/events_procedure_change_return.ts b/plugins/block-shareable-procedures/src/events_procedure_change_return.ts deleted file mode 100644 index 956f748ce..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_change_return.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; - -/** - * Notifies listeners that a procedure's return type/status has changed. - */ -export class ProcedureChangeReturn extends ProcedureBase { - static readonly TYPE = 'procedure_change'; - - /** A string used to check the type of the event. */ - type = ProcedureChangeReturn.TYPE; - - /** The new type(s) the procedure's return has been set to. */ - private newTypes: string[] | null; - - /** - * Constructs the procedure change event. - * - * @param workpace The workspace this change event is associated with. - * @param procedure The model this change event is associated with. - * @param oldTypes The type(s) the procedure's return was set to before it - * changed. - */ - constructor( - workpace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - readonly oldTypes: string[] | null, - ) { - super(workpace, procedure); - - this.newTypes = procedure.getReturnTypes(); - } - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const procedureModel = this.getEventWorkspace_() - .getProcedureMap() - .get(this.procedure.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot change the type of a procedure that does not exist ' + - 'in the procedure map', - ); - } - if (forward) { - procedureModel.setReturnTypes(this.newTypes); - } else { - procedureModel.setReturnTypes(this.oldTypes); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureChangeReturnJson { - const json = super.toJson() as ProcedureChangeReturnJson; - json['oldTypes'] = this.oldTypes; - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure change event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure change return event. - * @internal - */ - static fromJson( - json: ProcedureChangeReturnJson, - workspace: Blockly.Workspace, - ): ProcedureChangeReturn { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure change return event because the ' + - 'target procedure does not exist', - ); - } - return new ProcedureChangeReturn(workspace, model, json['oldTypes']); - } -} - -export interface ProcedureChangeReturnJson extends ProcedureBaseJson { - oldTypes: string[] | null; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureChangeReturn.TYPE, - ProcedureChangeReturn, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_create.ts b/plugins/block-shareable-procedures/src/events_procedure_create.ts deleted file mode 100644 index f4ede8dd9..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_create.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; -import {ObservableParameterModel} from './observable_parameter_model'; -import {ObservableProcedureModel} from './observable_procedure_model'; - -/** - * Notifies listeners that a procedure data model has been created. - */ -export class ProcedureCreate extends ProcedureBase { - static readonly TYPE = 'procedure_create'; - - /** A string used to check the type of the event. */ - type = ProcedureCreate.TYPE; - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - if (forward) { - if (procedureMap.get(this.procedure.getId())) return; - procedureMap.add(this.procedure); - } else { - if (!procedureMap.get(this.procedure.getId())) return; - procedureMap.delete(this.procedure.getId()); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureCreateJson { - const json = super.toJson() as ProcedureCreateJson; - json['procedure'] = Blockly.serialization.procedures.saveProcedure( - this.procedure, - ); - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure create event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure create event. - * @internal - */ - static fromJson( - json: ProcedureCreateJson, - workspace: Blockly.Workspace, - ): ProcedureCreate { - return new ProcedureCreate( - workspace, - Blockly.serialization.procedures.loadProcedure( - ObservableProcedureModel, - ObservableParameterModel, - json['procedure'], - workspace, - ), - ); - } -} - -export interface ProcedureCreateJson extends ProcedureBaseJson { - procedure: Blockly.serialization.procedures.State; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureCreate.TYPE, - ProcedureCreate, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_delete.ts b/plugins/block-shareable-procedures/src/events_procedure_delete.ts deleted file mode 100644 index 02b8a9f97..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_delete.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; - -/** - * Notifies listeners that a procedure data model has been deleted. - */ -export class ProcedureDelete extends ProcedureBase { - static readonly TYPE = 'procedure_delete'; - - /** A string used to check the type of the event. */ - type = ProcedureDelete.TYPE; - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - if (forward) { - if (!procedureMap.get(this.procedure.getId())) return; - procedureMap.delete(this.procedure.getId()); - } else { - if (procedureMap.get(this.procedure.getId())) return; - procedureMap.add(this.procedure); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureDeleteJson { - return super.toJson() as ProcedureDeleteJson; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure delete event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure delete event. - * @internal - */ - static fromJson( - json: ProcedureDeleteJson, - workspace: Blockly.Workspace, - ): ProcedureDelete { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure delete event because the ' + - 'target procedure does not exist', - ); - } - return new ProcedureDelete(workspace, model); - } -} - -export type ProcedureDeleteJson = ProcedureBaseJson; - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureDelete.TYPE, - ProcedureDelete, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_enable.ts b/plugins/block-shareable-procedures/src/events_procedure_enable.ts deleted file mode 100644 index 0122b9f31..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_enable.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; - -/** - * Notifies listeners that the procedure data model has been enabled or - * disabled. - */ -export class ProcedureEnable extends ProcedureBase { - static readonly TYPE = 'procedure_enable'; - - /** A string used to check the type of the event. */ - type = ProcedureEnable.TYPE; - - private oldState: boolean; - private newState: boolean; - - /** - * Constructs the procedure enable event. - * - * @param workspace The workspace this event is associated with. - * @param procedure The model this event is associated with. - * @param newState The (optional) new enabled state of the procedure model. - * If not provided, the procedure model will be inspected to determine - * its current state. - */ - constructor( - workspace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - newState?: boolean, - ) { - super(workspace, procedure); - - if (newState === undefined) { - this.oldState = !procedure.getEnabled(); - this.newState = procedure.getEnabled(); - } else { - this.oldState = !newState; - this.newState = newState; - } - } - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const procedureModel = this.getEventWorkspace_() - .getProcedureMap() - .get(this.procedure.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot change the enabled state of a procedure that does not ' + - 'exist in the procedure map', - ); - } - if (forward) { - procedureModel.setEnabled(this.newState); - } else { - procedureModel.setEnabled(this.oldState); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureEnableJson { - const json = super.toJson() as ProcedureEnableJson; - json['newState'] = this.newState; - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure enable event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure enable event. - * @internal - */ - static fromJson( - json: ProcedureEnableJson, - workspace: Blockly.Workspace, - ): ProcedureEnable { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure enable event because the ' + - 'target procedure does not exist', - ); - } - return new ProcedureEnable(workspace, model, json['newState']); - } -} - -export interface ProcedureEnableJson extends ProcedureBaseJson { - newState: boolean; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureEnable.TYPE, - ProcedureEnable, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_parameter_base.ts b/plugins/block-shareable-procedures/src/events_procedure_parameter_base.ts deleted file mode 100644 index 3884126a2..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_parameter_base.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; - -/** - * The base event for an event associated with a procedure parameter. - */ -export abstract class ProcedureParameterBase extends ProcedureBase { - static readonly TYPE: string = 'procedure_parameter_base'; - - /** A string used to check the type of the event. */ - type = ProcedureParameterBase.TYPE; - - /** - * Constructs the procedure parameter base event. - * - * @param workspace The workspace the parameter model exists in. - * @param procedure The procedure model the parameter model belongs to. - * @param parameter The parameter model associated with this event. - */ - constructor( - workspace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - readonly parameter: Blockly.procedures.IParameterModel, - ) { - super(workspace, procedure); - this.recordUndo = false; - } - - /** - * Finds the parameter with the given ID in the procedure model with the given - * ID, if both things exist. - * - * @param workspace The workspace to search for the parameter. - * @param procedureId The ID of the procedure model to search for - * the parameter. - * @param paramId The ID of the parameter to search for. - * @returns The parameter model that was found. - * @internal - */ - static findMatchingParameter( - workspace: Blockly.Workspace, - procedureId: string, - paramId: string, - ): ProcedureParameterPair { - const procedure = workspace.getProcedureMap().get(procedureId); - if (!procedure) return {procedure: undefined, parameter: undefined}; - const parameter = procedure - .getParameters() - .find((p) => p.getId() === paramId); - if (!parameter) return {procedure, parameter: undefined}; - return {procedure, parameter}; - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterBaseJson { - const json = super.toJson() as ProcedureParameterBaseJson; - json['parameterId'] = this.parameter.getId(); - return json; - } -} - -export interface ProcedureParameterPair { - procedure?: Blockly.procedures.IProcedureModel; - parameter?: Blockly.procedures.IParameterModel; -} - -export interface ProcedureParameterBaseJson extends ProcedureBaseJson { - parameterId: string; -} diff --git a/plugins/block-shareable-procedures/src/events_procedure_parameter_create.ts b/plugins/block-shareable-procedures/src/events_procedure_parameter_create.ts deleted file mode 100644 index 9b7617045..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_parameter_create.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import { - ProcedureParameterBase, - ProcedureParameterBaseJson, -} from './events_procedure_parameter_base'; -import {ObservableParameterModel} from './observable_parameter_model'; - -/** - * Notifies listeners that a parameter has been added to a procedure model. - */ -export class ProcedureParameterCreate extends ProcedureParameterBase { - static readonly TYPE = 'procedure_parameter_create'; - - /** A string used to check the type of the event. */ - type = ProcedureParameterCreate.TYPE; - - parameter: ObservableParameterModel; - - /** - * Constructs the procedure parameter create event.js. - * - * @param workspace The workspace this event is associated with. - * @param procedure The procedure model this event is associated with. - * @param parameter The parameter model that was just added to the procedure. - * @param index The index the parameter was inserted at. - */ - constructor( - workspace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - parameter: ObservableParameterModel, - readonly index: number, - ) { - super(workspace, procedure, parameter); - } - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - const procedureModel = procedureMap.get(this.procedure.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot add a parameter to a procedure that does not exist ' + - 'in the procedure map', - ); - } - if (forward) { - procedureModel.insertParameter(this.parameter, this.index); - } else { - procedureModel.deleteParameter(this.index); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterCreateJson { - const json = super.toJson() as ProcedureParameterCreateJson; - json['name'] = this.parameter.getName(); - json['id'] = this.parameter.getId(); - json['varId'] = this.parameter.getVariableModel().getId(); - json['index'] = this.index; - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure parameter create event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure parameter create event. - * @internal - */ - static fromJson( - json: ProcedureParameterCreateJson, - workspace: Blockly.Workspace, - ): ProcedureParameterCreate { - const procedure = workspace.getProcedureMap().get(json['procedureId']); - if (!procedure) { - throw new Error( - 'Cannot deserialize parameter create event because the ' + - 'target procedure does not exist', - ); - } - return new ProcedureParameterCreate( - workspace, - procedure, - new ObservableParameterModel( - workspace, - json['name'], - json['id'], - json['varId'], - ), - json['index'], - ); - } -} - -export interface ProcedureParameterCreateJson extends ProcedureParameterBaseJson { - parameter: Blockly.serialization.procedures.ParameterState; - index: number; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureParameterCreate.TYPE, - ProcedureParameterCreate, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_parameter_delete.ts b/plugins/block-shareable-procedures/src/events_procedure_parameter_delete.ts deleted file mode 100644 index ef467931b..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_parameter_delete.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import { - ProcedureParameterBase, - ProcedureParameterBaseJson, -} from './events_procedure_parameter_base'; - -/** - * Notifies listeners that a parameter has been removed from a procedure. - */ -export class ProcedureParameterDelete extends ProcedureParameterBase { - static readonly TYPE = 'procedure_parameter_delete'; - - /** A string used to check the type of the event. */ - type = ProcedureParameterDelete.TYPE; - - /** - * Constructs the procedure parameter delete event. - * - * @param workspace The workspace this event is associated with. - * @param procedure The procedure model this event is associated with. - * @param parameter The parameter model that was just removed from the - * procedure. - * @param index The index the parameter was at before it was removed. - */ - constructor( - workspace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - parameter: Blockly.procedures.IParameterModel, - readonly index: number, - ) { - super(workspace, procedure, parameter); - } - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const workspace = this.getEventWorkspace_(); - const procedureMap = workspace.getProcedureMap(); - const procedureModel = procedureMap.get(this.procedure.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot add a parameter to a procedure that does not exist ' + - 'in the procedure map', - ); - } - if (forward) { - procedureModel.deleteParameter(this.index); - } else { - procedureModel.insertParameter(this.parameter, this.index); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterDeleteJson { - const json = super.toJson() as ProcedureParameterDeleteJson; - json['index'] = this.index; - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure parameter delete event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure parameter delete event. - * @internal - */ - static fromJson( - json: ProcedureParameterDeleteJson, - workspace: Blockly.Workspace, - ): ProcedureParameterDelete { - const {procedure, parameter} = ProcedureParameterBase.findMatchingParameter( - workspace, - json['procedureId'], - json['parameterId'], - ); - if (!parameter) { - throw new Error('Cannot delete a non existant parameter'); - } - return new ProcedureParameterDelete( - workspace, - procedure, - parameter, - json['index'], - ); - } -} - -export interface ProcedureParameterDeleteJson extends ProcedureParameterBaseJson { - index: number; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureParameterDelete.TYPE, - ProcedureParameterDelete, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_parameter_rename.ts b/plugins/block-shareable-procedures/src/events_procedure_parameter_rename.ts deleted file mode 100644 index e2991c9cb..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_parameter_rename.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import { - ProcedureParameterBase, - ProcedureParameterBaseJson, -} from './events_procedure_parameter_base'; -import {ObservableParameterModel} from './observable_parameter_model'; - -/** - * Notifies listeners that a procedure parameter was renamed. - */ -export class ProcedureParameterRename extends ProcedureParameterBase { - static readonly TYPE = 'procedure_parameter_rename'; - - /** A string used to check the type of the event. */ - type = ProcedureParameterRename.TYPE; - - /** The new name of the procedure parameter. */ - private readonly newName: string; - - /** The new ID the backing variable for the parameter. */ - private readonly newVarId: string; - - /** - * Constructs the procedure parameter rename event. - * - * @param workspace The workpace this event is associated with. - * @param procedure The procedure model this event is associated with. - * @param parameter The parameter model this event is associated with. - * @param oldName The old name of the procedure parameter. - * @param newName The (optional) new name of the procedure parameter. If not - * provided, the parameter model will be inspected to see what its current - * name is. - * @param newVarId The (optional) new id of the procedure parameter's backing - * variable. If not provided, the parameter model will be inspected to - * see what its current name is. - */ - constructor( - workspace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - parameter: ObservableParameterModel, - readonly oldName: string, - newName?: string, - newVarId?: string, - ) { - super(workspace, procedure, parameter); - - this.newName = newName ?? parameter.getName(); - this.newVarId = newVarId ?? parameter.getVariableModel().getId(); - } - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const {parameter} = ProcedureParameterBase.findMatchingParameter( - this.getEventWorkspace_(), - this.procedure.getId(), - this.parameter.getId(), - ); - if (forward) { - if (parameter.getName() !== this.oldName) return; - (parameter as ObservableParameterModel).setName( - this.newName, - this.newVarId, - ); - } else { - if (parameter.getName() !== this.newName) return; - parameter.setName(this.oldName); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureParameterRenameJson { - const json = super.toJson() as ProcedureParameterRenameJson; - json['newName'] = this.newName; - json['newVarId'] = this.newVarId; - json['oldName'] = this.oldName; - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure parameter rename event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure parameter rename event. - * @internal - */ - static fromJson( - json: ProcedureParameterRenameJson, - workspace: Blockly.Workspace, - ): ProcedureParameterRename { - const {procedure, parameter} = ProcedureParameterBase.findMatchingParameter( - workspace, - json['procedureId'], - json['parameterId'], - ); - if (!parameter) { - throw new Error('Cannot delete a non existant parameter'); - } - return new ProcedureParameterRename( - workspace, - procedure, - parameter as ObservableParameterModel, - json['oldName'], - json['newName'], - json['newVarId'], - ); - } -} - -export interface ProcedureParameterRenameJson extends ProcedureParameterBaseJson { - oldName: string; - newName: string; - newVarId: string; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureParameterRename.TYPE, - ProcedureParameterRename, -); diff --git a/plugins/block-shareable-procedures/src/events_procedure_rename.ts b/plugins/block-shareable-procedures/src/events_procedure_rename.ts deleted file mode 100644 index 23f0d04ae..000000000 --- a/plugins/block-shareable-procedures/src/events_procedure_rename.ts +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; - -/** Notifies listeners that a procedure model has been renamed. */ -export class ProcedureRename extends ProcedureBase { - static readonly TYPE = 'procedure_rename'; - - /** A string used to check the type of the event. */ - type = ProcedureRename.TYPE; - - private newName: string; - - /** - * Constructs the procedure rename event. - * - * @param workspace The workspace this event is associated with. - * @param procedure The model this event is associated with. - * @param oldName The old name of the procedure model. - * @param newName The (optional) new name of the procedure. If not provided, - * the procedure model will be inspected to see what its current - * name is. - */ - constructor( - workspace: Blockly.Workspace, - procedure: Blockly.procedures.IProcedureModel, - readonly oldName: string, - newName?: string, - ) { - super(workspace, procedure); - - this.newName = newName ?? procedure.getName(); - } - - /** - * Replays the event in the workspace. - * - * @param forward if true, play the event forward (redo), otherwise play it - * backward (undo). - */ - run(forward: boolean) { - const procedureModel = this.getEventWorkspace_() - .getProcedureMap() - .get(this.procedure.getId()); - if (!procedureModel) { - throw new Error( - 'Cannot change the type of a procedure that does not exist ' + - 'in the procedure map', - ); - } - if (forward) { - if (procedureModel.getName() !== this.oldName) return; - procedureModel.setName(this.newName); - } else { - if (procedureModel.getName() !== this.newName) return; - procedureModel.setName(this.oldName); - } - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): ProcedureRenameJson { - const json = super.toJson() as ProcedureRenameJson; - json['newName'] = this.newName; - json['oldName'] = this.oldName; - return json; - } - - /** - * Deserializes the JSON event. - * - * @param json The JSON representation of a procedure rename event. - * @param workspace The workspace to deserialize the event into. - * @returns The new procedure rename event. - * @internal - */ - static fromJson( - json: ProcedureRenameJson, - workspace: Blockly.Workspace, - ): ProcedureRename { - const model = workspace.getProcedureMap().get(json['procedureId']); - if (!model) { - throw new Error( - 'Cannot deserialize procedure rename event because the ' + - 'target procedure does not exist', - ); - } - return new ProcedureRename( - workspace, - model, - json['oldName'], - json['newName'], - ); - } -} - -export interface ProcedureRenameJson extends ProcedureBaseJson { - oldName: string; - newName: string; -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - ProcedureRename.TYPE, - ProcedureRename, -); diff --git a/plugins/block-shareable-procedures/src/i_procedure_block.ts b/plugins/block-shareable-procedures/src/i_procedure_block.ts deleted file mode 100644 index 166f9de9a..000000000 --- a/plugins/block-shareable-procedures/src/i_procedure_block.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -/* eslint-disable @typescript-eslint/naming-convention */ - -/** The interface for a block which models a procedure. */ -export interface IProcedureBlock { - getProcedureModel(): Blockly.procedures.IProcedureModel; - doProcedureUpdate(): void; - isProcedureDef(): boolean; -} - -/** - * A type guard which checks if the given block is a procedure block. - * - * @param block The block to check for procedure-y-ness. - * @returns Whether this block is a procedure block or not. - */ -export function isProcedureBlock( - block: Blockly.Block | IProcedureBlock, -): block is IProcedureBlock { - return ( - (block as IProcedureBlock).getProcedureModel !== undefined && - (block as IProcedureBlock).doProcedureUpdate !== undefined && - (block as IProcedureBlock).isProcedureDef !== undefined - ); -} diff --git a/plugins/block-shareable-procedures/src/index.ts b/plugins/block-shareable-procedures/src/index.ts deleted file mode 100644 index 27acbd794..000000000 --- a/plugins/block-shareable-procedures/src/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ObservableParameterModel} from './observable_parameter_model'; -import {ObservableProcedureModel} from './observable_procedure_model'; - -export {blocks} from './blocks'; -export {IProcedureBlock, isProcedureBlock} from './i_procedure_block'; -export {ProcedureBase, ProcedureBaseJson} from './events_procedure_base'; -export { - ProcedureChangeReturn, - ProcedureChangeReturnJson, -} from './events_procedure_change_return'; -export {ProcedureCreate, ProcedureCreateJson} from './events_procedure_create'; -export {ProcedureDelete, ProcedureDeleteJson} from './events_procedure_delete'; -export { - ProcedureParameterBase, - ProcedureParameterBaseJson, -} from './events_procedure_parameter_base'; -export { - ProcedureParameterCreate, - ProcedureParameterCreateJson, -} from './events_procedure_parameter_create'; -export { - ProcedureParameterDelete, - ProcedureParameterDeleteJson, -} from './events_procedure_parameter_delete'; -export { - ProcedureParameterRename, - ProcedureParameterRenameJson, -} from './events_procedure_parameter_rename'; -export {ProcedureRename, ProcedureRenameJson} from './events_procedure_rename'; -export {triggerProceduresUpdate} from './update_procedures'; - -export {ObservableParameterModel, ObservableProcedureModel}; - -/** - * Unregisters all of the procedure blocks. - * - * Usually used to unregister the built-in blocks, before register the - * blocks provided by this plugin. - */ -export function unregisterProcedureBlocks() { - delete Blockly.Blocks['procedures_defnoreturn']; - delete Blockly.Blocks['procedures_callnoreturn']; - delete Blockly.Blocks['procedures_defreturn']; - delete Blockly.Blocks['procedures_callreturn']; -} - -/** - * Unregisters any existing procedure serializer, and registers a new one - * parameterized with the shareable procedure backing data models. - */ -export function registerProcedureSerializer() { - Blockly.serialization.registry.unregister('procedures'); - Blockly.serialization.registry.register( - 'procedures', - new Blockly.serialization.procedures.ProcedureSerializer( - ObservableProcedureModel, - ObservableParameterModel, - ), - ); -} diff --git a/plugins/block-shareable-procedures/src/observable_parameter_model.ts b/plugins/block-shareable-procedures/src/observable_parameter_model.ts deleted file mode 100644 index d6f51f6d2..000000000 --- a/plugins/block-shareable-procedures/src/observable_parameter_model.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ProcedureParameterRename} from './events_procedure_parameter_rename'; -import {triggerProceduresUpdate} from './update_procedures'; - -/** Represents a procedure parameter. */ -export class ObservableParameterModel - implements Blockly.procedures.IParameterModel -{ - private id: string; - private variable: Blockly.IVariableModel; - private shouldFireEvents = false; - private procedureModel: Blockly.procedures.IProcedureModel | null = null; - - /** - * Constructor for the procedure parameter. - * - * @param workspace The workspace this parameter model exists in. - * @param name The name of this parameter. - * @param id The optional unique language-neutral ID of the parameter. - * @param varId The optional ID of the variable this parameter should be - * associated with. - */ - constructor( - private readonly workspace: Blockly.Workspace, - name: string, - id?: string, - varId?: string, - ) { - this.id = id ?? Blockly.utils.idGenerator.genUid(); - this.variable = this.createBackingVariable(name, varId); - } - - /** - * Sets the name of this parameter to the given name. - * - * @param name The string to set the name to. - * @param id The optional ID the backing variable should have. - * @returns This parameter model. - */ - setName(name: string, id?: string): this { - if (name === this.variable.getName()) return this; - const oldName = this.variable.getName(); - this.variable = - this.workspace.getVariableMap().getVariable(name) ?? - this.workspace.getVariableMap().createVariable(name, '', id); - triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - Blockly.Events.fire( - new ProcedureParameterRename( - this.workspace, - this.procedureModel, - this, - oldName, - ), - ); - } - return this; - } - - /** - * Creates a backing variable in a way that is subclassable. - * - * @param name The string to set set the variable to. - * @param varId The optional ID the backing variable should have. - * @returns The created variable model. - */ - protected createBackingVariable( - name: string, - varId?: string, - ): Blockly.IVariableModel { - this.variable = Blockly.Variables.getOrCreateVariablePackage( - this.workspace, - varId || null, - name, - '', - ); - return this.variable; - } - - /** - * Unimplemented. The built-in ParameterModel does not support typing. - * If you want your procedure blocks to have typed parameters, you need to - * implement your own ParameterModel. - * - * @param types The types to set this parameter to. - * @throws {!Error} Throws for the ObservableParameterModel specifically - * because this method is unimplemented. - */ - setTypes(types: string[]): this { - throw new Error( - 'The built-in ParameterModel does not support typing. You need to ' + - 'implement your own custom ParameterModel.', - ); - } - - /** - * @returns the name of this parameter. - */ - getName(): string { - return this.variable.getName(); - } - - /** - * @returns the types of this parameter. - */ - getTypes(): string[] { - return []; - } - - /** - * Returns the unique language-neutral ID for the parameter. This represents - * the identity of the variable model which does not change over time. - * - * @returns The unique language-neutral ID for the parameter. - */ - getId(): string { - return this.id; - } - - /** - * @returns the variable model associated with the parameter model. - */ - getVariableModel(): Blockly.IVariableModel { - return this.variable; - } - - /** - * Tells the parameter model it should fire events. - * - * @internal - */ - startPublishing() { - this.shouldFireEvents = true; - } - - /** - * Tells the parameter model it should not fire events. - * - * @internal - */ - stopPublishing() { - this.shouldFireEvents = false; - } - - /** - * Sets the procedure model this parameter is a part of. - * - * @param model The procedure model this parameter is a part of. - * @returns This parameter model. - */ - setProcedureModel(model: Blockly.procedures.IProcedureModel): this { - this.procedureModel = model; - return this; - } - - /** - * Serializes the state of this parameter to JSON. - * - * @returns JSON serializable state of the parameter. - */ - saveState(): Blockly.serialization.procedures.ParameterState { - const state: Blockly.serialization.procedures.ParameterState = { - id: this.getId(), - name: this.getName(), - }; - if (!this.getTypes().length) return state; - state.types = this.getTypes(); - return state; - } - - /** - * Returns a new parameter model with the given state. - * - * @param state The state of the parameter to load. - * @param workspace The workspace to load the parameter into. - * @returns The loaded parameter model. - */ - static loadState( - state: Blockly.serialization.procedures.ParameterState, - workspace: Blockly.Workspace, - ): ObservableParameterModel { - const model = new ObservableParameterModel(workspace, state.name, state.id); - if (state.types) model.setTypes(state.types); - return model; - } -} diff --git a/plugins/block-shareable-procedures/src/observable_procedure_model.ts b/plugins/block-shareable-procedures/src/observable_procedure_model.ts deleted file mode 100644 index e90d7ccf4..000000000 --- a/plugins/block-shareable-procedures/src/observable_procedure_model.ts +++ /dev/null @@ -1,305 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ObservableParameterModel} from './observable_parameter_model'; -import {ProcedureChangeReturn} from './events_procedure_change_return'; -import {ProcedureCreate} from './events_procedure_create'; -import {ProcedureDelete} from './events_procedure_delete'; -import {ProcedureEnable} from './events_procedure_enable'; -import {ProcedureParameterCreate} from './events_procedure_parameter_create'; -import {ProcedureParameterDelete} from './events_procedure_parameter_delete'; -import {ProcedureRename} from './events_procedure_rename'; -import {triggerProceduresUpdate} from './update_procedures'; - -/** Represents a procedure signature. */ -export class ObservableProcedureModel - implements Blockly.procedures.IProcedureModel -{ - private id: string; - private name: string; - private parameters: ObservableParameterModel[] = []; - private returnTypes: string[] | null = null; - private enabled = true; - private shouldFireEvents = false; - private shouldTriggerUpdates = true; - - /** - * Constructor for the procedure model. - * - * @param workspace The workspace the procedure model is associated with. - * @param name The name of the new procedure. - * @param id The (optional) unique language-neutral ID for the procedure. - */ - constructor( - private readonly workspace: Blockly.Workspace, - name: string, - id?: string, - ) { - this.id = id ?? Blockly.utils.idGenerator.genUid(); - this.name = name; - } - - /** - * Sets the human-readable name of the procedure. - * - * @param name The human-readable name of the procedure. - * @returns This procedure model. - */ - setName(name: string): this { - if (name === this.name) return this; - const oldName = this.name; - this.name = name; - if (this.shouldTriggerUpdates) triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - Blockly.Events.fire(new ProcedureRename(this.workspace, this, oldName)); - } - return this; - } - - /** - * Inserts a parameter into the list of parameters. - * To move a parameter, first delete it, and then re-insert. - * - * @param parameterModel The parameter model to insert. - * @param index The index to insert it at. - * @returns This procedure model. - */ - insertParameter( - parameterModel: ObservableParameterModel, - index: number, - ): this { - if ( - this.parameters[index] && - this.parameters[index].getId() === parameterModel.getId() - ) { - return this; - } - - this.parameters.splice(index, 0, parameterModel); - parameterModel.setProcedureModel(this); - if (Blockly.isObservable(parameterModel)) { - if (this.shouldFireEvents) { - parameterModel.startPublishing(); - } else { - parameterModel.stopPublishing(); - } - } - - if (this.shouldTriggerUpdates) triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - Blockly.Events.fire( - new ProcedureParameterCreate( - this.workspace, - this, - parameterModel, - index, - ), - ); - } - return this; - } - - /** - * Removes the parameter at the given index from the parameter list. - * - * @param index The index of the parameter to remove. - * @returns This procedure model. - */ - deleteParameter(index: number): this { - if (!this.parameters[index]) return this; - const oldParam = this.parameters[index]; - - this.parameters.splice(index, 1); - if (this.shouldTriggerUpdates) triggerProceduresUpdate(this.workspace); - if (Blockly.isObservable(oldParam)) { - oldParam.stopPublishing(); - } - - if (this.shouldFireEvents) { - Blockly.Events.fire( - new ProcedureParameterDelete(this.workspace, this, oldParam, index), - ); - } - return this; - } - - /** - * Sets whether the procedure has a return value (empty array) or no return - * value (null). - * This procedure model does not support procedures that have actual - * return types (i.e. non-empty arrays, e.g. ['number']). - * - * @param types Used to set whether this procedure has a return value - * (empty array) or no return value (null). - * @returns This procedure model. - */ - setReturnTypes(types: string[] | null): this { - if (types && types.length) { - throw new Error( - 'The built-in ProcedureModel does not support typing. You need to ' + - 'implement your own custom ProcedureModel.', - ); - } - // Either they're both an empty array, or both null. Noop either way. - if (!!types === !!this.returnTypes) return this; - const oldReturnTypes = this.returnTypes; - this.returnTypes = types; - if (this.shouldTriggerUpdates) triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - Blockly.Events.fire( - new ProcedureChangeReturn(this.workspace, this, oldReturnTypes), - ); - } - return this; - } - - /** - * Sets whether this procedure is enabled/disabled. If a procedure is disabled - * all procedure caller blocks should be disabled as well. - * - * @param enabled Whether this procedure is enabled/disabled. - * @returns This procedure model. - */ - setEnabled(enabled: boolean): this { - if (enabled === this.enabled) return this; - this.enabled = enabled; - if (this.shouldTriggerUpdates) triggerProceduresUpdate(this.workspace); - if (this.shouldFireEvents) { - Blockly.Events.fire(new ProcedureEnable(this.workspace, this)); - } - return this; - } - - /** - * Disables triggering updates to procedure blocks until the endBulkUpdate - * is called. - * - * @internal - */ - startBulkUpdate() { - this.shouldTriggerUpdates = false; - } - - /** - * Triggers an update to procedure blocks. Should be used with - * startBulkUpdate. - * - * @internal - */ - endBulkUpdate() { - this.shouldTriggerUpdates = true; - triggerProceduresUpdate(this.workspace); - } - - /** - * @returns The unique language-neutral ID for the procedure. - */ - getId(): string { - return this.id; - } - - /** - * @returns The human-readable name of the procedure - */ - getName(): string { - return this.name; - } - - /** - * @param index The index of the parameter to return. - * @returns the parameter at the given index in the parameter list. - */ - getParameter(index: number): Blockly.procedures.IParameterModel { - return this.parameters[index]; - } - - /** - * @returns an array of all of the parameters in the parameter list. - */ - getParameters(): Blockly.procedures.IParameterModel[] { - return [...this.parameters]; - } - - /** - * Returns the return type of the procedure. - * Null represents a procedure that does not return a value. - * - * @returns the return type of the procedure. - */ - getReturnTypes(): string[] | null { - return this.returnTypes; - } - - /** - * Returns whether the procedure is enabled/disabled. If a procedure is - * disabled, all procedure caller blocks should be disabled as well. - * - * @returns Returns whether the procedure is enabled/disabled. - */ - getEnabled(): boolean { - return this.enabled; - } - - /** - * Tells the procedure model it should fire events. - * - * @internal - */ - startPublishing() { - this.shouldFireEvents = true; - Blockly.Events.fire(new ProcedureCreate(this.workspace, this)); - for (const param of this.parameters) { - if (Blockly.isObservable(param)) param.startPublishing(); - } - } - - /** - * Tells the procedure model it should not fire events. - * - * @internal - */ - stopPublishing() { - triggerProceduresUpdate(this.workspace); - Blockly.Events.fire(new ProcedureDelete(this.workspace, this)); - this.shouldFireEvents = false; - for (const param of this.parameters) { - if (Blockly.isObservable(param)) param.stopPublishing(); - } - } - - /** - * Serializes the state of the procedure to JSON. - * - * @returns JSON serializable state of the procedure. - */ - saveState(): Blockly.serialization.procedures.State { - // Parameter state is serialized by core. - return { - id: this.getId(), - name: this.getName(), - returnTypes: this.getReturnTypes(), - }; - } - - /** - * Returns a new procedure model with the given state. - * - * @param state The state of the procedure to load. - * @param workspace The workspace to load the procedure into. - * @returns The loaded procedure model. - */ - static loadState( - state: Blockly.serialization.procedures.State, - workspace: Blockly.Workspace, - ): ObservableProcedureModel { - return new ObservableProcedureModel( - workspace, - state.name, - state.id, - ).setReturnTypes(state.returnTypes); - } -} diff --git a/plugins/block-shareable-procedures/src/update_procedures.ts b/plugins/block-shareable-procedures/src/update_procedures.ts deleted file mode 100644 index ed8714629..000000000 --- a/plugins/block-shareable-procedures/src/update_procedures.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -/** - * Calls the `doProcedureUpdate` method on all blocks which implement it. - * - * @param workspace The workspace within which to trigger block updates. - * @internal - */ -export function triggerProceduresUpdate(workspace: Blockly.Workspace) { - if (workspace.isClearing) return; - for (const block of workspace.getAllBlocks(false)) { - if (Blockly.procedures.isProcedureBlock(block)) { - block.doProcedureUpdate(); - } - } -} diff --git a/plugins/block-shareable-procedures/test/data_models.mocha.js b/plugins/block-shareable-procedures/test/data_models.mocha.js deleted file mode 100644 index 745f72ff7..000000000 --- a/plugins/block-shareable-procedures/test/data_models.mocha.js +++ /dev/null @@ -1,547 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const eventTestHelpers = require('./event_test_helpers'); -const Blockly = require('blockly'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ObservableParameterModel} = require('../src/observable_parameter_model'); -const {ProcedureCreate} = require('../src/events_procedure_create'); -const {ProcedureDelete} = require('../src/events_procedure_delete'); -const {ProcedureRename} = require('../src/events_procedure_rename'); -const { - ProcedureChangeReturn, -} = require('../src/events_procedure_change_return'); -const {ProcedureEnable} = require('../src/events_procedure_enable'); -const { - ProcedureParameterCreate, -} = require('../src/events_procedure_parameter_create'); -const { - ProcedureParameterDelete, -} = require('../src/events_procedure_parameter_delete'); -const { - ProcedureParameterRename, -} = require('../src/events_procedure_parameter_rename'); - -suite('Procedure data models', function () { - setup(function () { - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - }); - - teardown(function () { - this.workspace.dispose(); - this.clock.runAll(); - this.sandbox.restore(); - }); - - suite('triggering block updates', function () { - setup(function () { - Blockly.Blocks['procedure_mock'] = { - init: function () {}, - doProcedureUpdate: function () {}, - getProcedureModel: function () {}, - isProcedureDef: function () {}, - }; - - this.procedureBlock = this.workspace.newBlock('procedure_mock'); - - this.updateSpy = this.sandbox.spy( - this.procedureBlock, - 'doProcedureUpdate', - ); - }); - - teardown(function () { - delete Blockly.Blocks['procedure_mock']; - }); - - suite('procedure map updates', function () { - test('inserting a procedure does not trigger an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ); - this.procedureMap.set(procedureModel.getId(), procedureModel); - - chai.assert.isFalse( - this.updateSpy.called, - 'Expected no update to be triggered', - ); - }); - - test('adding a procedure does not trigger an update', function () { - this.procedureMap.add( - new ObservableProcedureModel(this.workspace, 'test name'), - ); - - chai.assert.isFalse( - this.updateSpy.called, - 'Expected no update to be triggered', - ); - }); - - test('deleting a procedure triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ); - this.procedureMap.add(procedureModel); - - this.procedureMap.delete(procedureModel.getId()); - - chai.assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - }); - - suite('procedure model updates', function () { - test('setting the name triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ); - this.procedureMap.add(procedureModel); - - procedureModel.setName('new name'); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - - test('setting the return type triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ); - this.procedureMap.add(procedureModel); - - procedureModel.setReturnTypes([]); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - - test('removing the return type triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ).setReturnTypes([]); - this.procedureMap.add(procedureModel); - this.updateSpy.resetHistory(); - - procedureModel.setReturnTypes(null); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - - test('disabling the procedure triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ); - this.procedureMap.add(procedureModel); - - procedureModel.setEnabled(false); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - - test('enabling the procedure triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ).setEnabled(false); - this.procedureMap.add(procedureModel); - this.updateSpy.resetHistory(); - - procedureModel.setEnabled(true); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - - test('inserting a parameter triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ); - this.procedureMap.add(procedureModel); - - procedureModel.insertParameter( - new ObservableParameterModel(this.workspace, ''), - 0, - ); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - - test('deleting a parameter triggers an update', function () { - const procedureModel = new ObservableProcedureModel( - this.workspace, - 'test name', - ).insertParameter(new ObservableParameterModel(this.workspace, ''), 0); - this.procedureMap.add(procedureModel); - this.updateSpy.resetHistory(); - - procedureModel.deleteParameter(0); - - assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - }); - - suite('parameter model updates', function () { - test('setting the name triggers an update', function () { - const parameterModel = new ObservableParameterModel( - this.workspace, - 'test1', - ); - this.procedureMap.add( - new ObservableProcedureModel( - this.workspace, - 'test name', - ).insertParameter(parameterModel, 0), - ); - this.updateSpy.resetHistory(); - - parameterModel.setName('test2'); - - chai.assert.isTrue( - this.updateSpy.calledOnce, - 'Expected an update to be triggered', - ); - }); - }); - }); - - suite('firing events', function () { - setup(function () { - this.eventSpy = this.sandbox.spy(); - this.spyData = this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.workspace.removeChangeListener(this.spyData); - }); - - suite('procedure model creation and destruction', function () { - test('inserting a procedure model fires a create event', function () { - const procedure = new ObservableProcedureModel(this.workspace, 'proc'); - this.procedureMap.add(procedure); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureCreate, - {procedure}, - this.workspace.id, - ); - }); - - test('removing a procedure model fires a delete event', function () { - const procedure = new ObservableProcedureModel(this.workspace, 'proc'); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - this.procedureMap.delete(procedure.getId()); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureDelete, - {procedure}, - this.workspace.id, - ); - }); - }); - - suite('procedure model changes', function () { - test('setting the name fires a rename event', function () { - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - procedure.setName('new name'); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureRename, - { - procedure, - oldName: 'old name', - newName: 'new name', - }, - this.workspace.id, - ); - }); - - test('setting the return type fires a change return event', function () { - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ).setReturnTypes(null); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - const newTypes = []; - procedure.setReturnTypes(newTypes); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureChangeReturn, - { - procedure, - oldTypes: null, - newTypes, - }, - this.workspace.id, - ); - }); - - test('removing the return type fires a change return event', function () { - const oldTypes = []; - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ).setReturnTypes(oldTypes); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - procedure.setReturnTypes(null); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureChangeReturn, - { - procedure, - oldTypes, - newTypes: null, - }, - this.workspace.id, - ); - }); - - test('disabling the procedure fires an enable event', function () { - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ).setEnabled(true); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - procedure.setEnabled(false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureEnable, - { - procedure, - oldState: true, - newState: false, - }, - this.workspace.id, - ); - }); - - test('enabling the procedure fires an enable event', function () { - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ).setEnabled(false); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - procedure.setEnabled(true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureEnable, - { - procedure, - oldState: false, - newState: true, - }, - this.workspace.id, - ); - }); - - test('inserting a parameter fires a parameter create event', function () { - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ); - this.procedureMap.add(procedure); - this.clock.runAll(); - const parameter = new ObservableParameterModel(this.workspace, 'param'); - - this.eventSpy.resetHistory(); - procedure.insertParameter(parameter, 0); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterCreate, - { - procedure, - parameter, - index: 0, - }, - this.workspace.id, - ); - }); - - test('deleting a parameter fires a parameter delete event', function () { - const parameter = new ObservableParameterModel(this.workspace, 'param'); - const procedure = new ObservableProcedureModel( - this.workspace, - 'old name', - ).insertParameter(parameter, 0); - this.procedureMap.add(procedure); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - procedure.deleteParameter(0); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterDelete, - { - procedure, - parameter, - index: 0, - }, - this.workspace.id, - ); - }); - }); - - suite('parameter model changes', function () { - test('setting the name fires a procedure rename event', function () { - const parameter = new ObservableParameterModel( - this.workspace, - 'old name', - ); - this.procedureMap.add( - new ObservableProcedureModel(this.workspace, 'proc').insertParameter( - parameter, - 0, - ), - ); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - parameter.setName('new name'); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterRename, - { - parameter, - oldName: 'old name', - newName: 'new name', - }, - this.workspace.id, - ); - }); - }); - }); - - suite('backing variable to parameters', function () { - test('construction references an existing variable if available', function () { - const variable = this.workspace.getVariableMap().createVariable('test1'); - const param = new ObservableParameterModel(this.workspace, 'test1'); - - chai.assert.equal( - variable, - param.getVariableModel(), - 'Expected the parameter model to reference the existing variable', - ); - }); - - test('construction creates a variable if none exists', function () { - const param = new ObservableParameterModel(this.workspace, 'test1'); - - chai.assert.equal( - this.workspace.getVariableMap().getVariable('test1'), - param.getVariableModel(), - 'Expected the parameter model to create a variable', - ); - }); - - test('setName references an existing variable if available', function () { - const variable = this.workspace.getVariableMap().createVariable('test2'); - const param = new ObservableParameterModel(this.workspace, 'test1'); - - param.setName('test2'); - - chai.assert.equal( - variable, - param.getVariableModel(), - 'Expected the parameter model to reference the existing variable', - ); - }); - - test('setName creates a variable if none exits', function () { - const param = new ObservableParameterModel(this.workspace, 'test1'); - - param.setName('test2'); - - chai.assert.equal( - this.workspace.getVariableMap().getVariable('test2'), - param.getVariableModel(), - 'Expected the parameter model to create a variable', - ); - }); - - test('setTypes is unimplemented', function () { - const param = new ObservableParameterModel(this.workspace, 'test1'); - - chai.assert.throws(() => { - param.setTypes(['some', 'types']); - }, 'The built-in ParameterModel does not support typing'); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_change_return.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_change_return.mocha.js deleted file mode 100644 index 280286ff2..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_change_return.mocha.js +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const { - ProcedureChangeReturn, -} = require('../src/events_procedure_change_return'); - -suite('Procedure Change Return Event', function () { - const DEFAULT_TYPES = null; - const NON_DEFAULT_TYPES = []; - - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (id) => { - return new ObservableProcedureModel(this.workspace, 'test name', id); - }; - - this.createEventToState = (procedureModel) => { - const event = new ProcedureChangeReturn( - this.workspace, - procedureModel, - procedureModel.getReturnTypes() === DEFAULT_TYPES - ? NON_DEFAULT_TYPES - : DEFAULT_TYPES, - ); - return event; - }; - }); - - suite('forward (redo)', function () { - test('the procedure with the matching ID has its return set', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initial.getReturnTypes(), - final.getReturnTypes(), - "Expected the procedure's return type to be toggled", - ); - }); - - test('one changing the return fires a change return event', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureChangeReturn, - { - procedure: initial, - oldTypes: DEFAULT_TYPES, - }, - this.workspace.id, - ); - }); - - test('noop return changes do not fire change return events', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureChangeReturn, - {}, - this.workspace.id, - ); - }); - - test( - 'attempting to change the return of a procedure that ' + - 'does not exist in the map throws', - function () { - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - - assert.throws(() => { - event.run(/* forward= */ true); - }); - }, - ); - }); - - suite('backward (undo)', function () { - test('the procedure with the matching ID has its return set', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setReturnTypes(NON_DEFAULT_TYPES); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - initial.getReturnTypes(), - DEFAULT_TYPES, - "Expected the procedure's return type to be toggled", - ); - }); - - test('changing the return fires a change return event', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setReturnTypes(NON_DEFAULT_TYPES); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureChangeReturn, - { - procedure: initial, - oldTypes: NON_DEFAULT_TYPES, - }, - this.workspace.id, - ); - }); - - test('noop return changes do not fire change return events', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureChangeReturn, - {}, - this.workspace.id, - ); - }); - - test( - 'attempting to change the return of a procedure that ' + - 'does not exist throws', - function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setReturnTypes(NON_DEFAULT_TYPES); - undoable.setReturnTypes(NON_DEFAULT_TYPES); - const event = this.createEventToState(undoable); - - assert.throws(() => { - event.run(/* forward= */ false); - }); - }, - ); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ); - this.procedureMap.add(model); - const origEvent = new ProcedureChangeReturn( - this.workspace, - model, - NON_DEFAULT_TYPES, - ); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_create.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_create.mocha.js deleted file mode 100644 index b18193636..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_create.mocha.js +++ /dev/null @@ -1,184 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const {testHelpers} = require('@blockly/dev-tools'); -const eventTestHelpers = require('./event_test_helpers'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ProcedureCreate} = require('../src/events_procedure_create'); -const {ProcedureDelete} = require('../src/events_procedure_delete'); - -suite('Procedure Create Event', function () { - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (name, id) => { - return new ObservableProcedureModel(this.workspace, name, id); - }; - - this.createEventToState = (procedureModel) => { - return new ProcedureCreate(this.workspace, procedureModel); - }; - }); - - suite('forward', function () { - test('a procedure model is created if it does not exist', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - event.run(/* forward= */ true); - this.clock.runAll(); - - const createdProc = this.procedureMap.get('test id'); - assert.isDefined(createdProc, 'Expected the procedure to exist'); - assert.equal( - createdProc.getName(), - model.getName(), - "Expected the procedure's name to match the model", - ); - assert.equal( - createdProc.getId(), - model.getId(), - "Expected the procedure's id to match the model", - ); - }); - - test('creating a procedure model fires a create event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureCreate, - {procedure: this.procedureMap.get('test id')}, - this.workspace.id, - ); - }); - - test( - 'a procedure model is not created if a model with a ' + - 'matching ID exists', - function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - this.procedureMap.get('test id'), - model, - 'Expected the model in the procedure map to be the same ' + - 'as the original model', - ); - }, - ); - - test('not creating a model does not fire a create event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.clock.runAll(); - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureCreate, - {}, - this.workspace.id, - ); - }); - }); - - suite('backward', function () { - test('a procedure model is deleted if a model with a matching ID exists', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.isUndefined( - this.procedureMap.get('test id'), - 'Expected the procedure to be deleted', - ); - }); - - test('deleting a model fires a delete event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureDelete, - {procedure: model}, - this.workspace.id, - ); - }); - - test('not deleting a model does not fire a delete event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureDelete, - {}, - this.workspace.id, - ); - }); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ); - const origEvent = new ProcedureCreate(this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_delete.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_delete.mocha.js deleted file mode 100644 index 1a287ca96..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_delete.mocha.js +++ /dev/null @@ -1,185 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ProcedureDelete} = require('../src/events_procedure_delete'); -const {ProcedureCreate} = require('../src/events_procedure_create'); - -suite('Procedure Delete Event', function () { - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (name, id) => { - return new ObservableProcedureModel(this.workspace, name, id); - }; - - this.createEventToState = (procedureModel) => { - return new ProcedureDelete(this.workspace, procedureModel); - }; - }); - - suite('forward', function () { - test('a procedure model is deleted if a model with a matching ID exists', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.isUndefined( - this.procedureMap.get('test id'), - 'Expected the procedure to be deleted', - ); - }); - - test('deleting a model fires a delete event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureDelete, - {procedure: model}, - this.workspace.id, - ); - }); - - test('not deleting a model does not fire a delete event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureDelete, - {}, - this.workspace.id, - ); - }); - }); - - suite('backward', function () { - test('a procedure model is created if it does not exist', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - event.run(/* forward= */ false); - this.clock.runAll(); - - const createdProc = this.procedureMap.get('test id'); - assert.isDefined(createdProc, 'Expected the procedure to exist'); - assert.equal( - createdProc.getName(), - model.getName(), - "Expected the procedure's name to match the model", - ); - assert.equal( - createdProc.getId(), - model.getId(), - "Expected the procedure's id to match the model", - ); - }); - - test('creating a procedure model fires a create event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureCreate, - {procedure: this.procedureMap.get('test id')}, - this.workspace.id, - ); - }); - - test( - 'a procedure model is not created if a model with a ' + - 'matching ID exists', - function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - this.procedureMap.get('test id'), - model, - 'Expected the model in the procedure map to be the same ' + - 'as the original model', - ); - }, - ); - - test('not creating a model does not fire a create event', function () { - const model = this.createProcedureModel('test name', 'test id'); - const event = this.createEventToState(model); - this.procedureMap.add(model); - - this.clock.runAll(); - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureCreate, - {}, - this.workspace.id, - ); - }); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ); - this.procedureMap.add(model); - const origEvent = new ProcedureDelete(this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_enable.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_enable.mocha.js deleted file mode 100644 index fe6fc2f24..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_enable.mocha.js +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ProcedureEnable} = require('../src/events_procedure_enable'); - -suite('Procedure Enable Event', function () { - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (id) => { - return new ObservableProcedureModel(this.workspace, 'test name', id); - }; - - this.createEventToState = (procedureModel) => { - return new ProcedureEnable(this.workspace, procedureModel); - }; - }); - - suite('forward', function () { - test('the procedure with the matching ID is toggled', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initial.getEnabled(), - final.getEnabled(), - "Expected the procedure's enabled state to be flipped", - ); - }); - - test('toggling a procedure fires an enable event', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureEnable, - {procedure: initial}, - this.workspace.id, - ); - }); - - test('noop toggles do not fire enable events', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureEnable, - this.workspace.id, - ); - }); - - test('attempting to toggle a procedure that does not exist throws', function () { - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - - assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - - test('deserializing the event and running it triggers the effect', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setEnabled(!final.getEnabled()); // Set it to the non-default. - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - const newEvent = Blockly.Events.fromJson( - event.toJson(), - this.workspace, - ); - newEvent.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initial.getEnabled(), - final.getEnabled(), - "Expected the procedure's enabled state to be flipped", - ); - }); - }); - - suite('backward', function () { - test('the procedure with the matching ID is toggled', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - initial.setEnabled(!defaultEnabled); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - initial.getEnabled(), - defaultEnabled, - "Expected the procedure's enabled state to be flipped", - ); - }); - - test('toggling a procedure fires an enable event', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - initial.setEnabled(!defaultEnabled); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureEnable, - {procedure: initial}, - this.workspace.id, - ); - }); - - test('noop toggles do not fire enable events', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureEnable, - {}, - this.workspace.id, - ); - }); - - test('attempting to toggle a procedure that does not exist throws', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - // Set them to be non-default. - const defaultEnabled = initial.getEnabled(); - initial.setEnabled(!defaultEnabled); - undoable.setEnabled(!defaultEnabled); - const event = this.createEventToState(undoable); - - assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ); - this.procedureMap.add(model); - const origEvent = new ProcedureEnable(this.workspace, model); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_parameter_create.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_parameter_create.mocha.js deleted file mode 100644 index 5a47900b6..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_parameter_create.mocha.js +++ /dev/null @@ -1,356 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ObservableParameterModel} = require('../src/observable_parameter_model'); -const { - ProcedureParameterCreate, -} = require('../src/events_procedure_parameter_create'); -const { - ProcedureParameterDelete, -} = require('../src/events_procedure_parameter_delete'); - -suite('Procedure Parameter Create Event', function () { - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (name, id, workspace) => { - return new ObservableProcedureModel( - workspace ?? this.workspace, - name, - id, - ); - }; - - this.createProcedureAndParameter = ( - procName, - procId, - paramName, - paramId, - ) => { - const param = new ObservableParameterModel( - this.workspace, - paramName, - paramId, - ); - const proc = new ObservableProcedureModel( - this.workspace, - procName, - procId, - ).insertParameter(param, 0); - return {param, proc}; - }; - - this.createEventToState = (procedureModel, parameterModel) => { - return new ProcedureParameterCreate( - this.workspace, - procedureModel, - parameterModel, - 0, - ); - }; - }); - - suite('forward', function () { - test('a parameter is inserted if it does not exist', function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - event.run(/* forward= */ true); - this.clock.runAll(); - - const createdParam = actualProc.getParameter(0); - assert.isDefined(createdParam, 'Expected the parameter to exist'); - assert.equal( - createdParam.getName(), - modelParam.getName(), - "Expected the parameter's name to match the model", - ); - assert.equal( - createdParam.getId(), - modelParam.getId(), - "Expected the parameter's id to match the model", - ); - }); - - test('inserting a parameter fires a create event', function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterCreate, - { - procedure: actualProc, - parameter: actualProc.getParameter(0), - index: 0, - }, - this.workspace.id, - ); - }); - - test( - 'a parameter is not created if a parameter with a ' + - 'matching ID and index already exists', - function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - const actualProc = this.procedureMap.get('test id'); - assert.equal( - actualProc, - modelProc, - 'Expected the procedure in the procedure map to not ' + - 'have changed', - ); - assert.equal( - actualProc.getParameter(0), - modelParam, - 'Expected the parameter to not have changed', - ); - }, - ); - - test('not creating a parameter model does not fire a create event', function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureParameterCreate, - {}, - this.workspace.id, - ); - }); - - test( - 'deserializing the event into a different workspace creates ' + - 'an identical parameter (including variable ID)', - function () { - const otherWorkspace = new Blockly.Workspace(); - const otherProcedureMap = otherWorkspace.getProcedureMap(); - - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel( - 'test name', - 'test id', - otherWorkspace, - ); - otherProcedureMap.add(actualProc); - - const otherEvent = Blockly.Events.fromJson( - event.toJson(), - otherWorkspace, - ); - otherEvent.run(/* forward= */ true); - this.clock.runAll(); - - const createdParam = actualProc.getParameter(0); - assert.isDefined(createdParam, 'Expected the parameter to exist'); - assert.equal( - createdParam.getName(), - modelParam.getName(), - "Expected the parameter's name to match the model", - ); - assert.equal( - createdParam.getId(), - modelParam.getId(), - "Expected the parameter's id to match the model", - ); - assert.equal( - createdParam.getVariableModel().getId(), - modelParam.getVariableModel().getId(), - "Expected the parameter's variable's id to match the model", - ); - }, - ); - }); - - suite('backward', function () { - test('a parameter is removed if it exists', function () { - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.isUndefined( - proc.getParameter(0), - 'Expected the parameter to be deleted', - ); - }); - - test('removing a parameter fires a delete event', function () { - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterDelete, - { - procedure: proc, - parameter: param, - index: 0, - }, - this.workspace.id, - ); - }); - - test( - 'running the event throws if a parameter with a ' + - 'matching ID and index does not exist', - function () { - // TODO: Figure out what we want to do in this case. - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - - this.eventSpy.resetHistory(); - chai.assert.throws(() => { - event.run(/* forward= */ false); - }); - }, - ); - - test('not removing a parameter does not fire a delete event', function () { - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - proc.deleteParameter(0); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureParameterDelete, - {}, - this.workspace.id, - ); - }); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const param = new ObservableParameterModel( - this.workspace, - 'test param name', - 'test param id', - ); - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ); - this.procedureMap.add(model); - const origEvent = new ProcedureParameterCreate( - this.workspace, - model, - param, - 0, - ); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_parameter_delete.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_parameter_delete.mocha.js deleted file mode 100644 index ce7613322..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_parameter_delete.mocha.js +++ /dev/null @@ -1,305 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ObservableParameterModel} = require('../src/observable_parameter_model'); -const { - ProcedureParameterDelete, -} = require('../src/events_procedure_parameter_delete'); -const { - ProcedureParameterCreate, -} = require('../src/events_procedure_parameter_create'); - -suite('Procedure Parameter Delete Event', function () { - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.clock.runAll(); - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (name, id) => { - return new ObservableProcedureModel(this.workspace, name, id); - }; - - this.createProcedureAndParameter = ( - procName, - procId, - paramName, - paramId, - ) => { - const param = new ObservableParameterModel( - this.workspace, - procName, - paramId, - ); - const proc = new ObservableProcedureModel( - this.workspace, - paramName, - procId, - ).insertParameter(param, 0); - return {param, proc}; - }; - - this.createEventToState = (procedureModel, parameterModel) => { - return new ProcedureParameterDelete( - this.workspace, - procedureModel, - parameterModel, - 0, - ); - }; - }); - - suite('forward', function () { - test('a parameter is removed if it exists', function () { - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.isUndefined( - proc.getParameter(0), - 'Expected the parameter to be deleted', - ); - }); - - test('removing a parameter fires a delete event', function () { - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterDelete, - { - procedure: proc, - parameter: param, - index: 0, - }, - this.workspace.id, - ); - }); - - test( - 'running the event throws if a parameter with a ' + - 'matching ID and index does not exist', - function () { - // TODO: Figure out what we want to do in this case. - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - - this.eventSpy.resetHistory(); - chai.assert.throws(() => { - event.run(/* forward= */ true); - }); - }, - ); - - test('not removing a parameter does not fire a delete event', function () { - const {param, proc} = this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(proc, param); - this.procedureMap.add(proc); - proc.deleteParameter(0); - - this.clock.runAll(); - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureParameterDelete, - {}, - this.workspace.id, - ); - }); - }); - - suite('backward', function () { - test('a parameter is inserted if it does not exist', function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - event.run(/* forward= */ false); - this.clock.runAll(); - - const createdParam = actualProc.getParameter(0); - assert.isDefined(createdParam, 'Expected the parameter to exist'); - assert.equal( - createdParam.getName(), - modelParam.getName(), - "Expected the parameter's name to match the model", - ); - assert.equal( - createdParam.getId(), - modelParam.getId(), - "Expected the parameter's id to match the model", - ); - }); - - test('inserting a parameter fires a create event', function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - const actualProc = this.createProcedureModel('test name', 'test id'); - this.procedureMap.add(actualProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterCreate, - { - procedure: actualProc, - parameter: actualProc.getParameter(0), - index: 0, - }, - this.workspace.id, - ); - }); - - test( - 'a parameter is not created if a parameter with a ' + - 'matching ID and index already exists', - function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - const actualProc = this.procedureMap.get('test id'); - assert.equal( - actualProc, - modelProc, - 'Expected the procedure in the procedure map to not ' + - 'have changed', - ); - assert.equal( - actualProc.getParameter(0), - modelParam, - 'Expected the parameter to not have changed', - ); - }, - ); - - test('not creating a parameter model does not fire a create event', function () { - const {param: modelParam, proc: modelProc} = - this.createProcedureAndParameter( - 'test name', - 'test id', - 'test param name', - 'test param id', - ); - const event = this.createEventToState(modelProc, modelParam); - this.procedureMap.add(modelProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureParameterCreate, - {}, - this.workspace.id, - ); - }); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const param = new ObservableParameterModel( - this.workspace, - 'test param name', - 'test param id', - ); - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ).insertParameter(param, 0); - this.procedureMap.add(model); - const origEvent = new ProcedureParameterDelete( - this.workspace, - model, - param, - 0, - ); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_parameter_rename.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_parameter_rename.mocha.js deleted file mode 100644 index 4505d69df..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_parameter_rename.mocha.js +++ /dev/null @@ -1,332 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ObservableParameterModel} = require('../src/observable_parameter_model'); -const { - ProcedureParameterRename, -} = require('../src/events_procedure_parameter_rename'); - -suite('Procedure Parameter Rename Event', function () { - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - const DEFAULT_NAME = 'default'; - const NON_DEFAULT_NAME = 'non-default'; - - setup(function () { - this.createProcedureAndParameter = (procId, paramId) => { - const param = new ObservableParameterModel( - this.workspace, - DEFAULT_NAME, - paramId, - ); - const proc = new ObservableProcedureModel( - this.workspace, - 'test name', - procId, - ).insertParameter(param, 0); - return {param, proc}; - }; - - this.createEventToState = (procedureModel, parameterModel) => { - return new ProcedureParameterRename( - this.workspace, - procedureModel, - parameterModel, - parameterModel.getName() === DEFAULT_NAME - ? NON_DEFAULT_NAME - : DEFAULT_NAME, - ); - }; - }); - - suite('forward', function () { - test('the parameter with the matching ID and index is renamed', function () { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initialParam.getName(), - finalParam.getName(), - "Expected the procedure parameter's name to be changed", - ); - }); - - test('renaming a parameter fires a rename event', function () { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterRename, - { - procedure: initialProc, - parameter: initialParam, - oldName: DEFAULT_NAME, - }, - this.workspace.id, - ); - }); - - test('noop renames do not fire rename events', function () { - const {proc: initialProc} = this.createProcedureAndParameter( - 'test procId', - 'test paramId', - ); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureParameterRename, - {}, - this.workspace.id, - ); - }); - - test('attempting to rename a parameter that does not exist throws', function () { - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - this.clock.runAll(); - - assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - - test( - 'attempting to rename a procedure with a different old name ' + - 'does not work', - function () { - const otherNonDefaultName = 'other non-default name'; - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - const {param: testParam, proc: testProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - testParam.setName(otherNonDefaultName); - this.procedureMap.add(testProc); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - testParam.getName(), - otherNonDefaultName, - "Expected the parameter's name to be unchanged", - ); - }, - ); - - test('deserializing the event and running it triggers the effect', function () { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: finalParam, proc: finalProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - finalParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(finalProc, finalParam); - this.procedureMap.add(initialProc); - - const newEvent = Blockly.Events.fromJson( - event.toJson(), - this.workspace, - ); - newEvent.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initialParam.getName(), - finalParam.getName(), - "Expected the procedure parameter's name to be changed", - ); - }); - }); - - suite('backward', function () { - test('the parameter with the matching ID and index is renamed', function () { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - initialParam.setName(NON_DEFAULT_NAME); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - this.procedureMap.add(initialProc); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - initialParam.getName(), - DEFAULT_NAME, - "Expected the procedure parameter's name to be changed", - ); - }); - - test('renaming a parameter fires a rename event', function () { - const {param: initialParam, proc: initialProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - initialParam.setName(NON_DEFAULT_NAME); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - this.procedureMap.add(initialProc); - this.clock.runAll(); - - this.eventSpy.resetHistory(); - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureParameterRename, - { - procedure: initialProc, - parameter: initialParam, - oldName: NON_DEFAULT_NAME, - }, - this.workspace.id, - ); - }); - - test('noop renames do not fire rename events', function () { - const {proc: initialProc} = this.createProcedureAndParameter( - 'test procId', - 'test paramId', - ); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - this.procedureMap.add(initialProc); - - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureParameterRename, - {}, - this.workspace.id, - ); - }); - - test('attempting to rename a parameter that does not exist throws', function () { - const {param: initialParam} = this.createProcedureAndParameter( - 'test procId', - 'test paramId', - ); - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - initialParam.setName(NON_DEFAULT_NAME); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - - assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - - test( - 'attempting to rename a procedure with a different old name ' + - 'does not work', - function () { - const otherNonDefaultName = 'other non-default name'; - const {param: undoableParam, proc: undoableProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - undoableParam.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoableProc, undoableParam); - const {param: testParam, proc: testProc} = - this.createProcedureAndParameter('test procId', 'test paramId'); - testParam.setName(otherNonDefaultName); - this.procedureMap.add(testProc); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - testParam.getName(), - otherNonDefaultName, - "Expected the parameter's name to be unchanged", - ); - }, - ); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const param = new ObservableParameterModel( - this.workspace, - 'test param name', - 'test param id', - ); - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ).insertParameter(param, 0); - this.procedureMap.add(model); - const origEvent = new ProcedureParameterRename( - this.workspace, - model, - param, - 'old name', - ); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_procedure_rename.mocha.js b/plugins/block-shareable-procedures/test/event_procedure_rename.mocha.js deleted file mode 100644 index 4eeeeb59c..000000000 --- a/plugins/block-shareable-procedures/test/event_procedure_rename.mocha.js +++ /dev/null @@ -1,268 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const assert = chai.assert; -const Blockly = require('blockly'); -const eventTestHelpers = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {ProcedureRename} = require('../src/events_procedure_rename'); - -suite('Procedure Rename Event', function () { - const DEFAULT_NAME = 'default'; - const NON_DEFAULT_NAME = 'non-default'; - - setup(function () { - this.sandbox = sinon.createSandbox(); - this.clock = this.sandbox.useFakeTimers(); - this.workspace = new Blockly.Workspace(); - this.procedureMap = this.workspace.getProcedureMap(); - this.eventSpy = sinon.spy(); - this.workspace.addChangeListener(this.eventSpy); - }); - - teardown(function () { - this.sandbox.restore(); - }); - - suite('running', function () { - setup(function () { - this.createProcedureModel = (id) => { - return new ObservableProcedureModel(this.workspace, DEFAULT_NAME, id); - }; - - this.createEventToState = (procedureModel) => { - return new ProcedureRename( - this.workspace, - procedureModel, - procedureModel.getName() === DEFAULT_NAME - ? NON_DEFAULT_NAME - : DEFAULT_NAME, - ); - }; - }); - - suite('forward', function () { - test('the procedure with the matching ID is renamed', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initial.getName(), - final.getName(), - "Expected the procedure's name to be changed", - ); - }); - - test('renaming a procedure fires a rename event', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureRename, - {procedure: initial, oldName: DEFAULT_NAME}, - this.workspace.id, - ); - }); - - test('noop renames do not fire rename events', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - event.run(/* forward= */ true); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureRename, - {}, - this.workspace.id, - ); - }); - - test('attempting to rename a procedure that does not exist throws', function () { - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - - assert.throws(() => { - event.run(/* forward= */ true); - }); - }); - - test( - 'attempting to rename a procedure with a different old name ' + - 'does not work', - function () { - const otherNonDefaultName = 'other non-default name'; - const final = - this.createProcedureModel('test id').setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - const testModel = - this.createProcedureModel('test id').setName(otherNonDefaultName); - this.procedureMap.add(testModel); - - event.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - testModel.getName(), - otherNonDefaultName, - "Expected the procedure's name to be unchanged", - ); - }, - ); - - test('deserializing the event and running it triggers the effect', function () { - const initial = this.createProcedureModel('test id'); - const final = this.createProcedureModel('test id'); - final.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(final); - this.procedureMap.add(initial); - - const newEvent = Blockly.Events.fromJson( - event.toJson(), - this.workspace, - ); - newEvent.run(/* forward= */ true); - this.clock.runAll(); - - assert.equal( - initial.getName(), - final.getName(), - "Expected the procedure's name to be changed", - ); - }); - }); - - suite('backward', function () { - test('the procedure with the matching ID is renamed', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - undoable.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - initial.getName(), - DEFAULT_NAME, - "Expected the procedure's name to be changed", - ); - }); - - test('renaming a procedure fires a rename event', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - undoable.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - this.clock.runAll(); - - eventTestHelpers.assertEventFiredShallow( - this.eventSpy, - ProcedureRename, - {procedure: initial, oldName: NON_DEFAULT_NAME}, - this.workspace.id, - ); - }); - - test('noop renames do not fire rename events', function () { - const initial = this.createProcedureModel('test id'); - const undoable = this.createProcedureModel('test id'); - initial.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - this.procedureMap.add(initial); - - event.run(/* forward= */ false); - this.clock.runAll(); - - testHelpers.assertEventNotFired( - this.eventSpy, - ProcedureRename, - {}, - this.workspace.id, - ); - }); - - test('attempting to rename a procedure that does not exist throws', function () { - const undoable = this.createProcedureModel('test id'); - undoable.setName(NON_DEFAULT_NAME); - const event = this.createEventToState(undoable); - - assert.throws(() => { - event.run(/* forward= */ false); - }); - }); - - test( - 'attempting to rename a procedure with a different new name ' + - 'does not work', - function () { - const otherNonDefaultName = 'other non-default name'; - const undoable = this.createProcedureModel('test id'); - const event = this.createEventToState(undoable); - const testModel = - this.createProcedureModel('test id').setName(otherNonDefaultName); - this.procedureMap.add(testModel); - - event.run(/* forward= */ false); - this.clock.runAll(); - - assert.equal( - testModel.getName(), - otherNonDefaultName, - "Expected the procedure's name to be unchanged", - ); - }, - ); - }); - }); - - suite('serialization', function () { - test('events round-trip through JSON', function () { - const model = new ObservableProcedureModel( - this.workspace, - 'test name', - 'test id', - ); - this.procedureMap.add(model); - const origEvent = new ProcedureRename( - this.workspace, - model, - NON_DEFAULT_NAME, - ); - - const json = origEvent.toJson(); - const newEvent = Blockly.Events.fromJson(json, this.workspace); - - assert.deepEqual(newEvent, origEvent); - }); - }); -}); diff --git a/plugins/block-shareable-procedures/test/event_test_helpers.js b/plugins/block-shareable-procedures/test/event_test_helpers.js deleted file mode 100644 index 815cf8c11..000000000 --- a/plugins/block-shareable-procedures/test/event_test_helpers.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const sinon = require('sinon'); - -/** - * Returns a matcher that asserts that the actual object has the same properties - * and values (shallowly equated) as the expected object. - * @param {!Object} expected The expected set of properties we expect the - * actual object to have. - * @returns {function(*): boolean} A matcher that returns true if the `actual` - * object has all of the properties of the `expected` param, with the same - * values. - */ -export function shallowMatch(expected) { - return (actual) => { - for (const key in expected) { - if (actual[key] !== expected[key]) { - return false; - } - } - return true; - }; -} - -/** - * Asserts that an event with the given values (shallowly evaluated) was fired. - * @param {!sinon.SinonSpyCall|!sinon.SinonSpy} spy The spy or spy call to use. - * @param {function(new:Blockly.Events.Abstract)} instanceType Expected instance - * type of event fired. - * @param {!Object} expectedProperties Map of of expected properties - * to check on fired event. - * @param {string} expectedWorkspaceId Expected workspace id of event fired. - * @param {?string=} expectedBlockId Expected block id of event fired. - */ -export function assertEventFiredShallow( - spy, - instanceType, - expectedProperties, - expectedWorkspaceId, - expectedBlockId, -) { - const properties = { - ...expectedProperties, - workspaceId: expectedWorkspaceId, - blockId: expectedBlockId, - }; - sinon.assert.calledWith( - spy, - sinon.match - .instanceOf(instanceType) - .and(sinon.match(shallowMatch(properties))), - ); -} diff --git a/plugins/block-shareable-procedures/test/index.html b/plugins/block-shareable-procedures/test/index.html deleted file mode 100644 index 64d2578c2..000000000 --- a/plugins/block-shareable-procedures/test/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - Blockly Shareable Procedures - - - - -
-
-
-
-

Saved State

- -

Workspace 1

- -

Workspace 2

- -
-
- - - diff --git a/plugins/block-shareable-procedures/test/index.js b/plugins/block-shareable-procedures/test/index.js deleted file mode 100644 index 72c9dda85..000000000 --- a/plugins/block-shareable-procedures/test/index.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -/** - * @fileoverview Block test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories} from '@blockly/dev-tools'; -import { - blocks, - unregisterProcedureBlocks, - registerProcedureSerializer, -} from '../src/index'; -import {ProcedureBase} from '../src/events_procedure_base'; - -/* eslint no-unused-vars: "off" */ - -unregisterProcedureBlocks(); -Blockly.common.defineBlocks(blocks); - -registerProcedureSerializer(); - -let workspace1; -let workspace2; - -document.addEventListener('DOMContentLoaded', function () { - injectTwoWorkspaces(); -}); - -/** - * Injects two workspaces that share procedure models. Undo and redo are off. - */ -function injectTwoWorkspaces() { - const options = { - toolbox: toolboxCategories, - }; - workspace1 = Blockly.inject('blockly1', options); - workspace2 = Blockly.inject('blockly2', options); - // If we allow undoing operations, it can create event loops when sharing - // events between workspaces. - workspace1.MAX_UNDO = 0; - workspace2.MAX_UNDO = 0; - workspace1.addChangeListener(createEventSharer(workspace2)); - workspace2.addChangeListener(createEventSharer(workspace1)); - - workspace1.addChangeListener( - createSerializationListener(workspace1, 'save1'), - ); - workspace2.addChangeListener( - createSerializationListener(workspace2, 'save2'), - ); - - document - .getElementById('load') - .addEventListener('click', () => reloadWorkspaces()); -} - -/** Injects one workspace with undo and redo enabled. */ -function injectOneWorkspace() { - const elem = document.getElementById('blockly2'); - elem.parentElement.removeChild(elem); - - const options = { - toolbox: toolboxCategories, - }; - workspace1 = Blockly.inject('blockly1', options); - - workspace1.addChangeListener( - createSerializationListener(workspace1, 'save1'), - ); - - document - .getElementById('load') - .addEventListener('click', () => loadWorkspace()); -} - -/** - * Returns an event listener that shares procedure and var events from the - * connected workspace to the other workspace. - * @param {!Blockly.Workspace} otherWorkspace The workspace to share events to. - * @returns {function(Blockly.Events.Abstract)} The listener. - */ -function createEventSharer(otherWorkspace) { - return (e) => { - if ( - !(e instanceof ProcedureBase) && - !(e instanceof Blockly.Events.VarBase) - ) { - return; - } - let event; - try { - event = Blockly.Events.fromJson(e.toJson(), otherWorkspace); - } catch (e) { - // Could not deserialize event. This is expected to happen. E.g. - // when round-tripping parameter deletes, the delete in the - // secondary workspace cannot be deserialized into the original - // workspace. - return; - } - event.run(true); - }; -} - -/** - * Returns an event listener that serializes the given workspace to JSON and - * outputs it to the text area with the given ID. - * @param {!Blockly.Workspace} workspace The workspace to serialize. - * @param {string} textAreaId The ID of the text area to output to. - * @returns {function(Blockly.Events.Abstract)} The listener. - */ -function createSerializationListener(workspace, textAreaId) { - const textArea = document.getElementById(textAreaId); - return (e) => { - if (workspace.isDragging()) return; - textArea.value = JSON.stringify( - Blockly.serialization.workspaces.save(workspace), - undefined, - 2, - ); - }; -} - -/** - * Reloads both workspaces to showcase serialization working. - */ -async function reloadWorkspaces() { - const save1 = Blockly.serialization.workspaces.save(workspace1); - const save2 = Blockly.serialization.workspaces.save(workspace2); - workspace1.clear(); - workspace2.clear(); - // Show people the cleared workspace so they know the reload did something. - await new Promise((resolve) => setTimeout(resolve, 500)); - Blockly.serialization.workspaces.load(save1, workspace1); - Blockly.serialization.workspaces.load(save2, workspace2); -} - -/** Loads the workspace in single workspace mode. */ -function loadWorkspace() { - const save1 = JSON.parse(document.getElementById('save1').value); - workspace1.clear(); - Blockly.serialization.workspaces.load(save1, workspace1); -} diff --git a/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js b/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js deleted file mode 100644 index c2e95b9eb..000000000 --- a/plugins/block-shareable-procedures/test/procedure_blocks.mocha.js +++ /dev/null @@ -1,2588 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const Blockly = require('blockly'); -const chai = require('chai'); -const assert = chai.assert; -const sinon = require('sinon'); -const { - assertCallBlockStructure, - assertDefBlockStructure, - createGenUidStubWithReturns, - createProcCallBlock, - createProcDefBlock, -} = require('./procedure_test_helpers'); -const {assertEventFiredShallow} = require('./event_test_helpers'); -const {testHelpers} = require('@blockly/dev-tools'); -const {ObservableParameterModel} = require('../src/observable_parameter_model'); -const {ObservableProcedureModel} = require('../src/observable_procedure_model'); -const {blocks} = require('../src/blocks'); -const { - unregisterProcedureBlocks, - registerProcedureSerializer, -} = require('../src/index'); -const {ProcedureDelete} = require('../src/events_procedure_delete'); -const {ProcedureCreate} = require('../src/events_procedure_create'); - -suite('Procedures', function () { - setup(function () { - this.jsdomCleanup = require('jsdom-global')( - '
', - {pretendToBeVisual: true}, - ); - - this.sandbox = sinon.createSandbox(); - globalThis.clock = this.sandbox.useFakeTimers(); - - unregisterProcedureBlocks(); - Blockly.common.defineBlocks(blocks); - - registerProcedureSerializer(); - - this.workspace = Blockly.inject('blocklyDiv', {}); - - this.eventSpy = this.sandbox.spy(); - this.workspace.addChangeListener(this.eventSpy); - - this.workspace - .getVariableMap() - .createVariable('preCreatedVar', '', 'preCreatedVarId'); - this.workspace - .getVariableMap() - .createVariable('preCreatedTypedVar', 'type', 'preCreatedTypedVarId'); - - Blockly.defineBlocksWithJsonArray([ - { - type: 'row_block', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - output: null, - }, - ]); - - this.getContextStub = this.sandbox - .stub(window.HTMLCanvasElement.prototype, 'getContext') - .callsFake(() => { - return { - measureText: function () { - return {width: 0}; - }, - }; - }); - this.findParentWsStub = this.sandbox - .stub(Blockly.Workspace.prototype, 'getRootWorkspace') - .callsFake(() => { - return this.workspace; - }); - }); - - teardown(function () { - globalThis.clock.runAll(); - delete Blockly.Blocks['row_block']; - this.sandbox.restore(); - this.jsdomCleanup(); - }); - - suite('updating data models', function () { - test('renaming a procedure def block updates the procedure model', function () { - const defBlock = createProcDefBlock(this.workspace); - - defBlock.setFieldValue('new name', 'NAME'); - - assert.equal( - defBlock.getProcedureModel().getName(), - 'new name', - 'Expected the procedure model name to be updated', - ); - }); - - test('disabling a procedure def block updates the procedure model', function () { - const defBlock = createProcDefBlock(this.workspace); - - defBlock.setDisabledReason(true); - globalThis.clock.runAll(); - - assert.isFalse( - defBlock.getProcedureModel().getEnabled(), - 'Expected the procedure model to be disabled', - ); - }); - - test('adding a parameter to a procedure def updates the procedure model', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param name', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - - defBlock.compose(containerBlock); - - assert.equal( - defBlock.getProcedureModel().getParameter(0).getName(), - 'param name', - 'Expected the procedure model to have a matching parameter', - ); - }); - - test('adding a parameter adds a variable to the variable map', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param name', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - - defBlock.compose(containerBlock); - - assert.isTrue( - this.workspace - .getVariableMap() - .getVariablesOfType('') - .some((variable) => variable.name === 'param name'), - 'Expected the variable map to have a matching variable', - ); - }); - - test('moving a parameter in the procedure def updates the procedure model', function () { - // Create a stack of container, param1, param2. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock1 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock1.setFieldValue('param name1', 'NAME'); - const paramBlock2 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock2.setFieldValue('param name2', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock1.previousConnection); - paramBlock1.nextConnection.connect(paramBlock2.previousConnection); - defBlock.compose(containerBlock); - const id1 = defBlock.getProcedureModel().getParameter(0).getId(); - const id2 = defBlock.getProcedureModel().getParameter(1).getId(); - - // Reconfigure the stack to be container, param2, param1. - paramBlock2.previousConnection.disconnect(); - paramBlock1.previousConnection.disconnect(); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock2.previousConnection); - paramBlock2.nextConnection.connect(paramBlock1.previousConnection); - defBlock.compose(containerBlock); - - assert.equal( - defBlock.getProcedureModel().getParameter(0).getName(), - 'param name2', - 'Expected the first parameter of the procedure to be param 2', - ); - assert.equal( - defBlock.getProcedureModel().getParameter(0).getId(), - id2, - 'Expected the first parameter of the procedure to be param 2', - ); - assert.equal( - defBlock.getProcedureModel().getParameter(1).getName(), - 'param name1', - 'Expected the second parameter of the procedure to be param 1', - ); - assert.equal( - defBlock.getProcedureModel().getParameter(1).getId(), - id1, - 'Expected the second parameter of the procedure to be param 1', - ); - }); - - test('decomposing and recomposing maintains parameter IDs', function () { - // Create a stack of container, param. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param name', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - const paramBlockId = defBlock.getProcedureModel().getParameter(0).getId(); - - Blockly.Events.disable(); - this.workspace.clear(); - Blockly.Events.enable(); - const container = defBlock.decompose(this.workspace); - defBlock.compose(container); - - assert.equal( - defBlock.getProcedureModel().getParameter(0).getId(), - paramBlockId, - 'Expected the parameter ID to be maintained', - ); - }); - - test('deleting a parameter from a procedure def updates the procedure model', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param name', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - containerBlock.getInput('STACK').connection.disconnect(); - defBlock.compose(containerBlock); - - assert.isEmpty( - defBlock.getProcedureModel().getParameters(), - 'Expected the procedure model to have no parameters', - ); - }); - - test('renaming a procedure parameter updates the parameter model', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param name', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - paramBlock.setFieldValue('new param name', 'NAME'); - defBlock.compose(containerBlock); - - assert.equal( - defBlock.getProcedureModel().getParameter(0).getName(), - 'new param name', - 'Expected the procedure model to have a matching parameter', - ); - }); - - test('deleting a procedure deletes the procedure model', function () { - const defBlock = createProcDefBlock(this.workspace); - const model = defBlock.getProcedureModel(); - defBlock.dispose(); - - assert.isUndefined( - this.workspace.getProcedureMap().get(model.getId()), - 'Expected the model to be removed from the procedure map', - ); - }); - }); - - suite('responding to data model updates', function () { - suite('def blocks', function () { - test('renaming the procedure data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - - procModel.setName('new name'); - - assert.equal( - defBlock.getFieldValue('NAME'), - 'new name', - 'Expected the procedure block to be renamed', - ); - }); - - test('disabling a procedure data model disables blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - - procModel.setEnabled(false); - - assert.isFalse( - defBlock.isEnabled(), - 'Expected the procedure block to be disabled', - ); - }); - - test('adding a parameter to a data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - - procModel.insertParameter( - new ObservableParameterModel(this.workspace, 'param1', 'id'), - 0, - ); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('param1'), - 'Expected the params field to contain the name of the new param', - ); - }); - - test('moving a parameter in the data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - const param2 = new ObservableParameterModel( - this.workspace, - 'param2', - 'id2', - ); - procModel.insertParameter(param1, 0); - procModel.insertParameter(param2, 1); - - procModel.deleteParameter(1); - procModel.insertParameter(param2, 0); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('param2, param1'), - 'Expected the params field order to match the parameter order', - ); - }); - - test('deleting a parameter from the data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - const param2 = new ObservableParameterModel( - this.workspace, - 'param2', - 'id2', - ); - procModel.insertParameter(param1, 0); - procModel.insertParameter(param2, 1); - - procModel.deleteParameter(0); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('param2'), - 'Expected the params field order to contain one parameter', - ); - assert.isFalse( - defBlock.getFieldValue('PARAMS').includes('param1'), - 'Expected the params field to not contain the ' + 'deleted parameter', - ); - }); - - test('renaming a procedure parameter in the data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - procModel.insertParameter(param1, 0); - - param1.setName('new name'); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('new name'), - 'Expected the params field to contain the new param name', - ); - }); - }); - - suite('caller blocks', function () { - test('renaming the procedure data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - - procModel.setName('new name'); - - assert.equal( - callBlock.getFieldValue('NAME'), - 'new name', - 'Expected the procedure block to be renamed', - ); - }); - - test('disabling a procedure data model disables blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - - procModel.setEnabled(false); - - assert.isFalse( - callBlock.isEnabled(), - 'Expected the procedure block to be disabled', - ); - }); - - test('adding a parameter to a data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - - procModel.insertParameter( - new ObservableParameterModel(this.workspace, 'param1', 'id'), - 0, - ); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'param1', - 'Expected the params field to match the name of the new param', - ); - }); - - test('moving a parameter in the data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - const param2 = new ObservableParameterModel( - this.workspace, - 'param2', - 'id2', - ); - procModel.insertParameter(param1, 0); - procModel.insertParameter(param2, 1); - - procModel.deleteParameter(1); - procModel.insertParameter(param2, 0); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the first param input to exist', - ); - assert.isNotNull( - callBlock.getInput('ARG1'), - 'Expected the second param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'param2', - 'Expected the first params field to match the name of the param', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME1'), - 'param1', - 'Expected the second params field to match the name of the param', - ); - }); - - test('moving a parameter in the data model moves input blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - const param2 = new ObservableParameterModel( - this.workspace, - 'param2', - 'id2', - ); - procModel.insertParameter(param1, 0); - procModel.insertParameter(param2, 1); - const rowBlock1 = this.workspace.newBlock('row_block'); - const rowBlock2 = this.workspace.newBlock('row_block'); - callBlock - .getInput('ARG0') - .connection.connect(rowBlock1.outputConnection); - callBlock - .getInput('ARG1') - .connection.connect(rowBlock2.outputConnection); - globalThis.clock.runAll(); - - procModel.deleteParameter(1); - procModel.insertParameter(param2, 0); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the first param input to exist', - ); - assert.equal( - callBlock.getInputTargetBlock('ARG0'), - rowBlock2, - 'Expected the second row block to be attached to the ' + - 'first input', - ); - assert.isNotNull( - callBlock.getInput('ARG1'), - 'Expected the second param input to exist', - ); - assert.equal( - callBlock.getInputTargetBlock('ARG1'), - rowBlock1, - 'Expected the first row block to be attached to the ' + - 'second input', - ); - }); - - test('deleting a parameter from the data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - const param2 = new ObservableParameterModel( - this.workspace, - 'param2', - 'id2', - ); - procModel.insertParameter(param1, 0); - procModel.insertParameter(param2, 1); - - procModel.deleteParameter(0); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the first param input to exist', - ); - assert.isNull( - callBlock.getInput('ARG1'), - 'Expected the second param input to not exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'param2', - 'Expected the first params field to match the name of ' + 'the param', - ); - }); - - test('renaming a procedure parameter in the data model updates blocks', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const procModel = defBlock.getProcedureModel(); - const param1 = new ObservableParameterModel( - this.workspace, - 'param1', - 'id1', - ); - procModel.insertParameter(param1, 0); - - param1.setName('new name'); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'new name', - 'Expected the params field to match the new name of the param', - ); - }); - }); - }); - - suite('renaming procedures', function () { - test('callers are updated to have the new name', function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - - defBlock.setFieldValue('new name', 'NAME'); - - assert.equal( - callBlock.getFieldValue('NAME'), - 'new name', - 'Expected the procedure block to be renamed', - ); - }); - - test( - 'setting an illegal name results in both the ' + - 'procedure and the caller getting the legal name', - function () { - createProcDefBlock(this.workspace, undefined, undefined, 'procA'); - const defBlockB = createProcDefBlock( - this.workspace, - undefined, - undefined, - 'procB', - ); - const callBlockB = createProcCallBlock( - this.workspace, - undefined, - 'procB', - ); - - defBlockB.setFieldValue('procA', 'NAME'); - - assert.notEqual( - defBlockB.getFieldValue('NAME'), - 'procA', - 'Expected the procedure def block to have a legal name', - ); - assert.notEqual( - callBlockB.getFieldValue('NAME'), - 'procA', - 'Expected the procedure call block to have a legal name', - ); - }, - ); - }); - - suite('adding procedure parameters', function () { - test('adding a parameter to the procedure updates procedure defs', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('param1'), - 'Expected the params field to contain the name of the new param', - ); - }); - - test('adding a parameter to the procedure updates procedure callers', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'param1', - 'Expected the params field to match the name of the new param', - ); - }); - }); - - suite('deleting procedure parameters', function () { - test('deleting a parameter from the procedure updates procedure defs', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - paramBlock.dispose(); - defBlock.compose(containerBlock); - - assert.isFalse( - defBlock.getFieldValue('PARAMS').includes('param1'), - 'Expected the params field to not contain the name of the ' + - 'new param', - ); - }); - - test('deleting a parameter from the procedure updates procedure callers', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - paramBlock.checkAndDelete(); - defBlock.compose(containerBlock); - - assert.isNull( - callBlock.getInput('ARG0'), - 'Expected the param input to not exist', - ); - }); - }); - - suite('renaming procedure parameters', function () { - test('defs are updated for parameter renames', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - paramBlock.setFieldValue('new name', 'NAME'); - defBlock.compose(containerBlock); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('new name'), - 'Expected the params field to contain the new name of the param', - ); - }); - - test('defs are updated for parameter renames when two params exist', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock1 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock1.setFieldValue('param1', 'NAME'); - const paramBlock2 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock2.setFieldValue('param2', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock1.previousConnection); - paramBlock1.nextConnection.connect(paramBlock2.previousConnection); - defBlock.compose(containerBlock); - - paramBlock1.setFieldValue('new name', 'NAME'); - defBlock.compose(containerBlock); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('new name'), - 'Expected the params field to contain the new name of the param', - ); - }); - - test('callers are updated for parameter renames', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - paramBlock.setFieldValue('new name', 'NAME'); - defBlock.compose(containerBlock); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'new name', - 'Expected the params field to match the name of the new param', - ); - }); - - test('variables associated with procedure parameters are not renamed', function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - paramBlock.setFieldValue('param2', 'NAME'); - defBlock.compose(containerBlock); - - assert.isNotNull( - this.workspace.getVariableMap().getVariable('param1', ''), - 'Expected the old variable to continue to exist', - ); - }); - - test( - 'renaming a variable associated with a parameter updates ' + - 'procedure defs', - function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - const variable = this.workspace - .getVariableMap() - .getVariable('param1', ''); - this.workspace.getVariableMap().renameVariable(variable, 'new name'); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('new name'), - 'Expected the params field to contain the new name of the param', - ); - }, - ); - - // TODO(blockly/#): We can't open mutators in node (even with JSDOM) due to - // failing instanceof checks. So we can't currently test this. - test.skip( - 'renaming a variable associated with a parameter updates ' + - 'mutator parameters', - function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - const variable = this.workspace - .getVariableMap() - .getVariable('param1', ''); - this.workspace.getVariableMap().renameVariable(variable, 'new name'); - - assert.equal( - paramBlock.getFieldValue('NAME'), - 'new name', - 'Expected the params field to contain the new name of the param', - ); - }, - ); - - test( - 'renaming a variable associated with a parameter updates ' + - 'procedure callers', - function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - const variable = this.workspace - .getVariableMap() - .getVariable('param1', ''); - this.workspace.getVariableMap().renameVariable(variable, 'new name'); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'new name', - 'Expected the params field to match the name of the new param', - ); - }, - ); - - test( - 'coalescing a variable associated with a parameter updates ' + - 'procedure defs', - function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - const variable = this.workspace - .getVariableMap() - .getVariable('param1', ''); - this.workspace - .getVariableMap() - .renameVariable(variable, 'preCreatedVar'); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('preCreatedVar'), - 'Expected the params field to contain the new name of the param', - ); - }, - ); - - // TODO(blockly/#): We can't open mutators in node (even with JSDOM) due to - // failing instanceof checks. So we can't currently test this. - test.skip( - 'coalescing a variable associated with a parameter updates ' + - 'mutator parameters', - function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - const variable = this.workspace - .getVariableMap() - .getVariable('param1', ''); - this.workspace - .getVariableMap() - .renameVariable(variable, 'preCreatedVar'); - - assert.equal( - paramBlock.getFieldValue('NAME'), - 'preCreatedVar', - 'Expected the params field to contain the new name of the param', - ); - }, - ); - - test( - 'coalescing a variable associated with a parameter updates ' + - 'procedure callers', - function () { - // Create a stack of container, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock.setFieldValue('param1', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock.previousConnection); - defBlock.compose(containerBlock); - - const variable = this.workspace - .getVariableMap() - .getVariable('param1', ''); - this.workspace - .getVariableMap() - .renameVariable(variable, 'preCreatedVar'); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'preCreatedVar', - 'Expected the params field to match the name of the new param', - ); - }, - ); - - test.skip( - 'renaming a variable such that you get a parameter ' + - 'conflict does... something!', - function () {}, - ); - }); - - suite('reordering procedure parameters', function () { - test('reordering procedure parameters updates procedure blocks', function () { - // Create a stack of container, parameter, parameter. - const defBlock = createProcDefBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock1 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock1.setFieldValue('param1', 'NAME'); - const paramBlock2 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock2.setFieldValue('param2', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock1.previousConnection); - paramBlock1.nextConnection.connect(paramBlock2.previousConnection); - defBlock.compose(containerBlock); - - // Reorder the parameters. - paramBlock2.previousConnection.disconnect(); - paramBlock1.previousConnection.disconnect(); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock2.previousConnection); - paramBlock2.nextConnection.connect(paramBlock1.previousConnection); - defBlock.compose(containerBlock); - - assert.isNotNull( - defBlock.getField('PARAMS'), - 'Expected the params field to exist', - ); - assert.isTrue( - defBlock.getFieldValue('PARAMS').includes('param2, param1'), - 'Expected the params field order to match the parameter order', - ); - }); - - test('reordering procedure parameters updates caller blocks', function () { - // Create a stack of container, parameter, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock1 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock1.setFieldValue('param1', 'NAME'); - const paramBlock2 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock2.setFieldValue('param2', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock1.previousConnection); - paramBlock1.nextConnection.connect(paramBlock2.previousConnection); - defBlock.compose(containerBlock); - - // Reorder the parameters. - paramBlock2.previousConnection.disconnect(); - paramBlock1.previousConnection.disconnect(); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock2.previousConnection); - paramBlock2.nextConnection.connect(paramBlock1.previousConnection); - defBlock.compose(containerBlock); - - assert.isNotNull( - callBlock.getInput('ARG0'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME0'), - 'param2', - 'Expected the params field to match the name of the second param', - ); - assert.isNotNull( - callBlock.getInput('ARG1'), - 'Expected the param input to exist', - ); - assert.equal( - callBlock.getFieldValue('ARGNAME1'), - 'param1', - 'Expected the params field to match the name of the first param', - ); - }); - - test( - 'reordering procedure parameters reorders the blocks ' + - 'attached to caller inputs', - function () { - // Create a stack of container, parameter, parameter. - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - const containerBlock = this.workspace.newBlock( - 'procedures_mutatorcontainer', - ); - const paramBlock1 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock1.setFieldValue('param1', 'NAME'); - const paramBlock2 = this.workspace.newBlock('procedures_mutatorarg'); - paramBlock2.setFieldValue('param2', 'NAME'); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock1.previousConnection); - paramBlock1.nextConnection.connect(paramBlock2.previousConnection); - defBlock.compose(containerBlock); - - // Add args to the parameter inputs on the caller. - const block1 = this.workspace.newBlock('text'); - const block2 = this.workspace.newBlock('text'); - callBlock.getInput('ARG0').connection.connect(block1.outputConnection); - callBlock.getInput('ARG1').connection.connect(block2.outputConnection); - globalThis.clock.runAll(); - - // Reorder the parameters. - paramBlock2.previousConnection.disconnect(); - paramBlock1.previousConnection.disconnect(); - defBlock.compose(containerBlock); - containerBlock - .getInput('STACK') - .connection.connect(paramBlock2.previousConnection); - paramBlock2.nextConnection.connect(paramBlock1.previousConnection); - defBlock.compose(containerBlock); - - assert.equal( - callBlock.getInputTargetBlock('ARG0'), - block2, - 'Expected the second block to be in the first slot', - ); - assert.equal( - callBlock.getInputTargetBlock('ARG1'), - block1, - 'Expected the first block to be in the second slot', - ); - }, - ); - }); - - suite('enabling and disabling procedure blocks', function () { - test( - 'if a procedure definition is disabled, the procedure caller ' + - 'is also disabled', - function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - - defBlock.setDisabledReason(true); - globalThis.clock.runAll(); - - assert.isFalse( - callBlock.isEnabled(), - 'Expected the caller block to be disabled', - ); - }, - ); - - test( - 'if a procedure definition is enabled, the procedure caller ' + - 'is also enabled', - function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - defBlock.setDisabledReason(true); - globalThis.clock.runAll(); - - defBlock.setDisabledReason(false); - globalThis.clock.runAll(); - - assert.isTrue( - callBlock.isEnabled(), - 'Expected the caller block to be enabled', - ); - }, - ); - - test( - 'if a procedure caller block was already disabled before ' + - 'its definition was disabled, it is not reenabled', - function () { - this.workspace.options.disable = true; - const defBlock = createProcDefBlock(this.workspace); - const callBlock = createProcCallBlock(this.workspace); - globalThis.clock.runAll(); - callBlock.setDisabledReason(true); - globalThis.clock.runAll(); - defBlock.setDisabledReason(true); - globalThis.clock.runAll(); - - defBlock.setDisabledReason(false); - globalThis.clock.runAll(); - - assert.isFalse( - callBlock.isEnabled(), - 'Expected the caller block to continue to be disabled', - ); - }, - ); - }); - - suite('creating procedure blocks', function () { - test( - 'when a procedure definition block is created, a create event for ' + - 'its data model is fired', - function () { - const defBlock = createProcDefBlock(this.workspace); - const procedure = defBlock.getProcedureModel(); - globalThis.clock.runAll(); - - assertEventFiredShallow( - this.eventSpy, - ProcedureCreate, - { - procedure: procedure, - }, - this.workspace.id, - ); - }, - ); - }); - - suite('deleting procedure blocks', function () { - test( - 'when the procedure definition block is deleted, all of its ' + - 'associated callers are deleted as well', - function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock1 = createProcCallBlock(this.workspace); - const callBlock2 = createProcCallBlock(this.workspace); - - defBlock.dispose(); - globalThis.clock.runAll(); - - assert.isTrue( - callBlock1.disposed, - 'Expected the first caller to be disposed', - ); - assert.isTrue( - callBlock2.disposed, - 'Expected the second caller to be disposed', - ); - }, - ); - - test( - 'when a procedure definition block is deleted, deleting its callers ' + - 'with arguments that call another procedure does not cause a crash', - function () { - // This test exercises the scenario reported in - // https://github.com/RaspberryPiFoundation/blockly-samples/issues/2557 - Blockly.serialization.workspaces.load( - { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defnoreturn', - id: 'dosomething', - extraState: { - procedureId: 'dosomething_procmodel', - }, - fields: { - NAME: 'do something', - }, - }, - { - type: 'procedures_defreturn', - id: 'dosomething2', - extraState: { - procedureId: 'dosomething2_procmodel', - }, - fields: { - NAME: 'do something2', - }, - }, - { - type: 'procedures_callnoreturn', - id: 'call_dosomething', - extraState: { - name: 'do something', - params: ['x'], - }, - inputs: { - ARG0: { - block: { - type: 'procedures_callreturn', - id: 'call_dosomething2', - extraState: { - name: 'do something2', - }, - }, - }, - }, - }, - ], - }, - variables: [ - { - name: 'x', - id: 'x_var', - }, - ], - procedures: [ - { - id: 'dosomething_procmodel', - name: 'do something', - returnTypes: null, - parameters: [ - { - id: 'x_param', - name: 'x', - }, - ], - }, - { - id: 'dosomething2_procmodel', - name: 'do something2', - returnTypes: [], - }, - ], - }, - this.workspace, - ); - - const defBlock = this.workspace.getBlockById('dosomething'); - // Should not cause an exception to be thrown. - defBlock.dispose(); - globalThis.clock.runAll(); - }, - ); - - test( - 'when a procedure definition block is deleted, a delete event for ' + - 'its data model is fired', - function () { - const defBlock = createProcDefBlock(this.workspace); - const procedure = defBlock.getProcedureModel(); - - defBlock.dispose(); - globalThis.clock.runAll(); - - assertEventFiredShallow( - this.eventSpy, - ProcedureDelete, - { - procedure: procedure, - }, - this.workspace.id, - ); - }, - ); - - test( - 'when the procedure definition block is deleted, all of its ' + - 'associated callers are deleted, but the other blocks remain', - function () { - const defBlock = createProcDefBlock(this.workspace); - const callBlock1 = createProcCallBlock(this.workspace); - const ifBlock1 = this.workspace.newBlock('controls_if'); - const ifBlock2 = this.workspace.newBlock('controls_if'); - - ifBlock1.nextConnection.connect(callBlock1.previousConnection); - callBlock1.nextConnection.connect(ifBlock2.previousConnection); - - defBlock.dispose(true); - globalThis.clock.runAll(); - - assert.isTrue( - callBlock1.disposed, - 'Expected the first caller to be disposed', - ); - assert.isFalse( - ifBlock1.disposed, - 'Expected the first if block 1 to be not be disposed', - ); - assert.isFalse( - ifBlock2.disposed, - 'Expected the second if block 2 to be not be disposed', - ); - }, - ); - }); - - suite('caller blocks creating new def blocks', function () { - setup(function () { - this.TEST_VAR_ID = 'test-id'; - this.genUidStub = createGenUidStubWithReturns(this.TEST_VAR_ID); - }); - - teardown(function () { - this.genUidStub.restore(); - }); - - suite('xml', function () { - test('callers that can find models do not create defs', function () { - this.workspace - .getProcedureMap() - .add(new ObservableProcedureModel(this.workspace, 'do something')); - Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom(` - - - `), - this.workspace, - ); - globalThis.clock.runAll(); - assert.equal( - this.workspace.getTopBlocks().length, - 1, - 'Expected only the call block to exist', - ); - }); - - test('callers without defs create new defs', function () { - const callBlock = Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom(` - - - `), - this.workspace, - ); - globalThis.clock.runAll(); - assertDefBlockStructure( - this.workspace.getBlocksByType('procedures_defreturn')[0], - true, - ); - assertCallBlockStructure(callBlock, [], [], 'do something'); - }); - - test('callers without mutations create unnamed defs', function () { - const callBlock = Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom( - '', - ), - this.workspace, - ); - globalThis.clock.runAll(); - assertDefBlockStructure( - this.workspace.getBlocksByType('procedures_defreturn')[0], - true, - ); - assertCallBlockStructure(callBlock, [], [], 'unnamed'); - }); - - test('callers with missing args create new defs', function () { - const defBlock = Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom(` - - do something - - - - - `), - this.workspace, - ); - const callBlock = Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom( - '' + - ' ' + - '', - ), - this.workspace, - ); - globalThis.clock.runAll(); - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure(callBlock, [], [], 'do something2'); - }); - - test('callers with mismatched args create new defs', function () { - const defBlock = Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom(` - - do something - - - - - `), - this.workspace, - ); - const callBlock = Blockly.Xml.domToBlock( - Blockly.utils.xml.textToDom(` - - - - - - `), - this.workspace, - ); - globalThis.clock.runAll(); - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure( - callBlock, - ['y'], - [this.TEST_VAR_ID], - 'do something2', - ); - }); - - test('callers whose defs are deserialized later do not create defs', function () { - Blockly.Xml.domToWorkspace( - Blockly.utils.xml.textToDom(` - - - - - - - - do something - - - - - - `), - this.workspace, - ); - globalThis.clock.runAll(); - const defBlock = this.workspace.getBlocksByType( - 'procedures_defreturn', - )[0]; - const callBlock = this.workspace.getBlocksByType( - 'procedures_callreturn', - )[0]; - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure(callBlock, ['x'], ['arg'], 'do something'); - assert.equal( - defBlock.getProcedureModel(), - callBlock.getProcedureModel(), - 'Expected the blocks to have the same procedure model', - ); - }); - }); - - suite('json', function () { - test('callers that can find models do not create defs', function () { - this.workspace - .getProcedureMap() - .add(new ObservableProcedureModel(this.workspace, 'do something')); - Blockly.serialization.blocks.append( - { - type: 'procedures_callnoreturn', - extraState: { - name: 'do something', - }, - }, - this.workspace, - {recordUndo: true}, - ); - globalThis.clock.runAll(); - assert.equal( - this.workspace.getTopBlocks().length, - 1, - 'Expected only the call block to exist', - ); - }); - - test('callers without defs create new defs', function () { - const callBlock = Blockly.serialization.blocks.append( - { - type: 'procedures_callreturn', - extraState: { - name: 'do something', - }, - }, - this.workspace, - {recordUndo: true}, - ); - globalThis.clock.runAll(); - assertDefBlockStructure( - this.workspace.getBlocksByType('procedures_defreturn')[0], - true, - ); - assertCallBlockStructure(callBlock, [], [], 'do something'); - }); - - test('callers without extra state create unamed defs', function () { - // recordUndo must be true to trigger change listener. - const callBlock = Blockly.serialization.blocks.append( - { - type: 'procedures_callreturn', - }, - this.workspace, - {recordUndo: true}, - ); - globalThis.clock.runAll(); - assertDefBlockStructure( - this.workspace.getBlocksByType('procedures_defreturn')[0], - true, - ); - assertCallBlockStructure(callBlock, [], [], 'unnamed'); - }); - - test('callers with missing args create new defs', function () { - const defBlock = Blockly.serialization.blocks.append( - { - type: 'procedures_defreturn', - fields: { - NAME: 'do something', - }, - extraState: { - params: [ - { - name: 'x', - id: 'arg', - }, - ], - }, - }, - this.workspace, - ); - const callBlock = Blockly.serialization.blocks.append( - { - type: 'procedures_callreturn', - extraState: { - name: 'do something', - }, - }, - this.workspace, - {recordUndo: true}, - ); - globalThis.clock.runAll(); - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure(callBlock, [], [], 'do something2'); - }); - - test('callers with mismatched args create new defs', function () { - const defBlock = Blockly.serialization.blocks.append( - { - type: 'procedures_defreturn', - fields: { - NAME: 'do something', - }, - extraState: { - params: [ - { - name: 'x', - id: 'arg', - }, - ], - }, - }, - this.workspace, - ); - const callBlock = Blockly.serialization.blocks.append( - { - type: 'procedures_callreturn', - extraState: { - name: 'do something', - params: ['y'], - }, - }, - this.workspace, - {recordUndo: true}, - ); - globalThis.clock.runAll(); - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure( - callBlock, - ['y'], - [this.TEST_VAR_ID], - 'do something2', - ); - }); - - test('callers whose defs are deserialized later do not create defs', function () { - Blockly.serialization.workspaces.load( - { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_callreturn', - extraState: { - params: ['x'], - }, - }, - { - type: 'procedures_defreturn', - fields: { - NAME: 'do something', - }, - extraState: { - params: [ - { - name: 'x', - id: 'arg', - }, - ], - }, - }, - ], - }, - }, - this.workspace, - {recordUndo: true}, - ); - globalThis.clock.runAll(); - const defBlock = this.workspace.getBlocksByType( - 'procedures_defreturn', - )[0]; - const callBlock = this.workspace.getBlocksByType( - 'procedures_callreturn', - )[0]; - assertDefBlockStructure(defBlock, true, ['x'], ['arg']); - assertCallBlockStructure(callBlock, ['x'], ['arg'], 'do something'); - assert.equal( - defBlock.getProcedureModel(), - callBlock.getProcedureModel(), - 'Expected the blocks to have the same procedure model', - ); - }); - }); - }); - - suite('definition block context menu', function () { - test('the context menu includes an option for creating the caller', function () { - const def = Blockly.serialization.blocks.append( - { - type: 'procedures_defnoreturn', - fields: { - NAME: 'test name', - }, - }, - this.workspace, - ); - - const options = []; - def.customContextMenu(options); - - assert.isTrue( - options[0].text.includes('test name'), - 'Expected the context menu to have an option to create ' + 'the caller', - ); - }); - - test('the context menu includes an option for each parameter', function () { - const def = Blockly.serialization.blocks.append( - { - type: 'procedures_defnoreturn', - fields: { - NAME: 'test name', - }, - extraState: { - params: [ - { - name: 'testParam1', - id: 'varId1', - paramId: 'paramId1', - }, - { - name: 'testParam2', - id: 'varId2', - paramId: 'paramId2', - }, - ], - }, - }, - this.workspace, - ); - - const options = []; - def.customContextMenu(options); - - assert.isTrue( - options[1].text.includes('testParam1'), - 'Expected the context menu to have an option to create the ' + - 'first param', - ); - assert.isTrue( - options[2].text.includes('testParam2'), - 'Expected the context menu to have an option to create the ' + - 'second param', - ); - }); - }); - - suite('deserializing data models', function () { - suite('return types', function () { - test('procedure defs without returns have null return types', function () { - const json = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defnoreturn', - fields: { - NAME: 'test name', - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(json, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.isNull( - procedureModel.getReturnTypes(), - 'Expected the return types to be null', - ); - }); - - test('procedure defs with returns have array return types', function () { - const json = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defreturn', - fields: { - NAME: 'test name', - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(json, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.isArray( - procedureModel.getReturnTypes(), - 'Expected the return types to be an array', - ); - }); - }); - - suite('json', function () { - test('procedure names get deserialized', function () { - const json = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defnoreturn', - fields: { - NAME: 'test name', - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(json, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.equal( - procedureModel.name, - 'test name', - 'Expected the name of the procedure model to equal the name ' + - 'being deserialized.', - ); - }); - - test('procedure parameter names get deserialized', function () { - const json = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defnoreturn', - fields: { - NAME: 'test name', - }, - extraState: { - params: [ - { - id: 'test id 1', - name: 'test name 1', - }, - { - id: 'test id 2', - name: 'test name 2', - }, - ], - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(json, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.equal( - procedureModel.getParameter(0).getName(), - 'test name 1', - 'Expected the name of the first parameter to equal the name ' + - 'being deserialized.', - ); - assert.equal( - procedureModel.getParameter(1).getName(), - 'test name 2', - 'Expected the name of the second parameter to equal the name ' + - 'being deserialized.', - ); - }); - - test('procedure variables get matching IDs', function () { - const json = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defnoreturn', - extraState: { - params: [ - { - name: 'test param name', - id: 'test param id', - }, - ], - }, - fields: { - NAME: 'test proc name', - }, - }, - ], - }, - variables: [ - { - name: 'test param name', - id: 'test param id', - }, - ], - }; - Blockly.serialization.workspaces.load(json, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.equal( - procedureModel.getParameter(0).getVariableModel().getId(), - 'test param id', - 'Expected the variable id to match the serialized param id', - ); - }); - }); - - suite('xml', function () { - test('procedure names get deserialized', function () { - const xml = Blockly.utils.xml.textToDom( - `` + - ` test name` + - ``, - ); - Blockly.Xml.domToBlock(xml, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.equal( - procedureModel.name, - 'test name', - 'Expected the name of the procedure model to equal the name ' + - 'being deserialized.', - ); - }); - - test('procedure parameter names get deserialized', function () { - const xml = Blockly.utils.xml.textToDom( - `` + - ` ` + - ` ` + - ` ` + - ` ` + - ` test name` + - ``, - ); - Blockly.Xml.domToBlock(xml, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.equal( - procedureModel.getParameter(0).getName(), - 'test name 1', - 'Expected the name of the first parameter to equal the name ' + - 'being deserialized.', - ); - assert.equal( - procedureModel.getParameter(1).getName(), - 'test name 2', - 'Expected the name of the second parameter to equal the name ' + - 'being deserialized.', - ); - }); - - test('procedure variables get matching IDs', function () { - const xml = Blockly.utils.xml.textToDom( - `` + - ` ` + - ` test param name` + - ` ` + - ` ` + - ` ` + - ` ` + - ` ` + - ` test name` + - ` ` + - ``, - ); - Blockly.Xml.domToWorkspace(xml, this.workspace); - const procedureModel = this.workspace - .getProcedureMap() - .getProcedures()[0]; - - assert.equal( - procedureModel.getParameter(0).getVariableModel().getId(), - 'test param id', - 'Expected the variable id to match the serialized param id', - ); - }); - }); - }); - - suite('full workspace serialization test cases', function () { - test('definitions with parameters are properly rendered', function () { - Blockly.serialization.workspaces.load( - { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'procedures_defnoreturn', - extraState: { - procedureId: 'procId', - }, - fields: { - NAME: 'do something', - }, - }, - ], - }, - procedures: [ - { - id: 'procId', - name: 'do something', - returnTypes: null, - parameters: [ - { - id: 'paramId', - name: 'x', - }, - ], - }, - ], - variables: [ - { - name: 'x', - id: 'varId', - }, - ], - }, - this.workspace, - ); - assertDefBlockStructure( - this.workspace.getTopBlocks(false)[0], - false, - ['x'], - ['varId'], - ); - }); - }); - - suite('getDefinition', function () { - test('individual definitions are returned', function () { - const defBlock = createProcDefBlock( - this.workspace, - false, - [], - 'proc name', - ); - const def = Blockly.procedures.getDefinition('proc name', this.workspace); - assert.equal(def, defBlock); - }); - - test('definitions of different procedures are not returned', function () { - const defBlock1 = createProcDefBlock( - this.workspace, - false, - [], - 'proc name', - ); - createProcDefBlock(this.workspace, false, [], 'other proc name'); - const def = Blockly.procedures.getDefinition('proc name', this.workspace); - assert.equal(def, defBlock1); - }); - }); - - suite('getCallers', function () { - test('individual callers are returned', function () { - createProcDefBlock(this.workspace, false, [], 'proc name'); - const callBlock = createProcCallBlock(this.workspace, false, 'proc name'); - const callers = Blockly.procedures.getCallers( - 'proc name', - this.workspace, - ); - assert.equal(callers.length, 1); - assert.equal(callers[0], callBlock); - }); - - test('multiple callers of the same procedure are returned', function () { - createProcDefBlock(this.workspace, false, [], 'proc name'); - const callBlock1 = createProcCallBlock( - this.workspace, - false, - 'proc name', - ); - const callBlock2 = createProcCallBlock( - this.workspace, - false, - 'proc name', - ); - const callers = Blockly.procedures.getCallers( - 'proc name', - this.workspace, - ); - assert.equal(callers.length, 2); - assert.includeMembers(callers, [callBlock1, callBlock2]); - }); - - test('callers of different procedures are not returned', function () { - createProcDefBlock(this.workspace, false, [], 'proc name1'); - const callBlock1 = createProcCallBlock( - this.workspace, - false, - 'proc name1', - ); - createProcDefBlock(this.workspace, false, [], 'proc name2'); - createProcCallBlock(this.workspace, false, 'proc name2'); - const callers = Blockly.procedures.getCallers( - 'proc name1', - this.workspace, - ); - assert.equal(callers.length, 1); - assert.equal(callers[0], callBlock1); - }); - }); - - const xmlTestCases = [ - { - title: 'XML - Minimal definition', - xml: '', - expectedXml: - '\n' + - ' unnamed\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, false); - }, - }, - { - title: 'XML - Common definition', - xml: - '' + - ' do something' + - '', - expectedXml: - '\n' + - ' do something\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, false); - }, - }, - { - title: 'XML - With vars definition', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, false, ['x', 'y'], ['arg1', 'arg2']); - }, - }, - { - title: 'XML - With pre-created vars definition', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' do something\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure( - block, - false, - ['preCreatedVar'], - ['preCreatedVarId'], - ); - }, - }, - { - title: 'XML - No statements definition', - xml: - '\n' + - ' \n' + - ' do something\n' + - '', - expectedXml: - '\n' + - ' \n' + - ' do something\n' + - '', - assertBlockStructure: (block) => { - assertDefBlockStructure(block, true, [], [], false); - }, - }, - { - title: 'XML - Minimal caller', - xml: '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'XML - Common caller', - xml: - '\n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'XML - With pre-created vars caller', - xml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - '', - expectedXml: - '\n' + - ' \n' + - ' \n' + - ' \n' + - '', - assertBlockStructure: (block) => { - assertCallBlockStructure(block, ['preCreatedVar'], ['preCreatedVarId']); - }, - }, - ]; - testHelpers.runSerializationTestSuite(xmlTestCases, Blockly); - - const jsonTestCases = [ - { - title: 'JSON - Minimal definition', - json: { - type: 'procedures_defnoreturn', - }, - expectedJson: { - type: 'procedures_defnoreturn', - id: '1', - fields: { - NAME: 'unnamed', - }, - extraState: { - procedureId: '1', - fullSerialization: true, - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, false); - }, - }, - { - title: 'JSON - Common definition', - json: { - type: 'procedures_defnoreturn', - fields: { - NAME: 'do something', - }, - }, - expectedJson: { - type: 'procedures_defnoreturn', - id: '1', - fields: { - NAME: 'do something', - }, - extraState: { - procedureId: '1', - fullSerialization: true, - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, false); - }, - }, - { - title: 'JSON - With vars definition', - json: { - type: 'procedures_defnoreturn', - fields: { - NAME: 'do something', - }, - extraState: { - params: [ - { - name: 'x', - id: 'arg1', - }, - { - name: 'y', - id: 'arg2', - }, - ], - }, - }, - expectedJson: { - type: 'procedures_defnoreturn', - id: '1', - fields: { - NAME: 'do something', - }, - extraState: { - procedureId: '1', - fullSerialization: true, - params: [ - { - name: 'x', - id: 'arg1', - paramId: '1', - }, - { - name: 'y', - id: 'arg2', - paramId: '1', - }, - ], - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, false, ['x', 'y'], ['arg1', 'arg2']); - }, - }, - { - title: 'JSON - With pre-created vars definition', - json: { - type: 'procedures_defnoreturn', - extraState: { - params: [ - { - name: 'preCreatedVar', - id: 'preCreatedVarId', - }, - ], - }, - fields: { - NAME: 'do something', - }, - }, - expectedJson: { - type: 'procedures_defnoreturn', - id: '1', - fields: { - NAME: 'do something', - }, - extraState: { - procedureId: '1', - fullSerialization: true, - params: [ - { - name: 'preCreatedVar', - id: 'preCreatedVarId', - paramId: '1', - }, - ], - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure( - block, - false, - ['preCreatedVar'], - ['preCreatedVarId'], - ); - }, - }, - { - title: 'JSON - No statements definition', - json: { - type: 'procedures_defreturn', - fields: { - NAME: 'do something', - }, - extraState: { - hasStatements: false, - }, - }, - expectedJson: { - type: 'procedures_defreturn', - id: '1', - fields: { - NAME: 'do something', - }, - extraState: { - procedureId: '1', - fullSerialization: true, - hasStatements: false, - }, - }, - assertBlockStructure: (block) => { - assertDefBlockStructure(block, true, [], [], false); - }, - }, - { - title: 'JSON - Minimal caller', - json: { - type: 'procedures_callnoreturn', - }, - expectedJson: { - type: 'procedures_callnoreturn', - id: '1', - extraState: { - name: 'unnamed', - }, - }, - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'JSON - Common caller', - json: { - type: 'procedures_callnoreturn', - extraState: { - name: 'do something', - }, - }, - expectedJson: { - type: 'procedures_callnoreturn', - id: '1', - extraState: { - name: 'do something', - }, - }, - assertBlockStructure: (block) => { - assertCallBlockStructure(block); - }, - }, - { - title: 'JSON - With pre-created vars caller', - json: { - type: 'procedures_callnoreturn', - extraState: { - name: 'do something', - params: ['preCreatedVar'], - }, - }, - expectedJson: { - type: 'procedures_callnoreturn', - id: '1', - extraState: { - name: 'do something', - params: ['preCreatedVar'], - }, - }, - assertBlockStructure: (block) => { - assertCallBlockStructure(block, ['preCreatedVar'], ['preCreatedVarId']); - }, - }, - ]; - testHelpers.runSerializationTestSuite(jsonTestCases, Blockly); -}); diff --git a/plugins/block-shareable-procedures/test/procedure_test_helpers.js b/plugins/block-shareable-procedures/test/procedure_test_helpers.js deleted file mode 100644 index 1b574e0c8..000000000 --- a/plugins/block-shareable-procedures/test/procedure_test_helpers.js +++ /dev/null @@ -1,216 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -const Blockly = require('blockly/core'); -const chai = require('chai'); -const assert = chai.assert; -const sinon = require('sinon'); - -/** - * Creates stub for Blockly.utils.idGenerator.genUid that returns the - * provided id or ids. - * Recommended to also assert that the stub is called the expected number of - * times. - * @param {string|!Array} returnIds The return values to use for the - * created stub. If a single value is passed, then the stub always returns - * that value. - * @returns {!sinon.SinonStub} The created stub. - */ -export function createGenUidStubWithReturns(returnIds) { - const stub = sinon.stub(Blockly.utils.idGenerator.TEST_ONLY, 'genUid'); - if (Array.isArray(returnIds)) { - for (let i = 0; i < returnIds.length; i++) { - stub.onCall(i).returns(returnIds[i]); - } - } else { - stub.returns(returnIds); - } - return stub; -} - -/** - * Asserts that the procedure definition or call block has the expected var - * models. - * @param {!Blockly.Block} block The procedure definition or call block to - * check. - * @param {!Array} varIds An array of variable ids. - */ -export function assertBlockVarModels(block, varIds) { - const expectedVarModels = []; - for (let i = 0; i < varIds.length; i++) { - expectedVarModels.push( - block.workspace.getVariableMap().getVariableById(varIds[i]), - ); - } - assert.sameDeepOrderedMembers(block.getVarModels(), expectedVarModels); -} - -/** - * Asserts that the procedure call block has the expected arguments. - * @param {!Blockly.Block} callBlock The procedure definition block. - * @param {Array=} args An array of argument names. - */ -export function assertCallBlockArgsStructure(callBlock, args) { - // inputList also contains "TOPROW" - assert.equal( - callBlock.inputList.length - 1, - args.length, - 'call block has the expected number of args', - ); - - for (let i = 0; i < args.length; i++) { - const expectedName = args[i]; - const callInput = callBlock.inputList[i + 1]; - assert.equal(callInput.type, Blockly.ConnectionType.INPUT_VALUE); - assert.equal(callInput.name, 'ARG' + i); - assert.equal( - callInput.fieldRow[0].getValue(), - expectedName, - 'Call block consts did not match expected.', - ); - } - assert.sameOrderedMembers(callBlock.getVars(), args); -} - -/** - * Asserts that the procedure definition block has the expected inputs and - * fields. - * @param {!Blockly.Block} defBlock The procedure definition block. - * @param {boolean=} hasReturn If we expect the procedure def to have a return - * input or not. - * @param {Array=} args An array of argument names. - * @param {Array=} varIds An array of variable ids. - * @param {boolean=} hasStatements If we expect the procedure def to have a - * statement input or not. - */ -export function assertDefBlockStructure( - defBlock, - hasReturn = false, - args = [], - varIds = [], - hasStatements = true, -) { - if (hasStatements) { - assert.isNotNull( - defBlock.getInput('STACK'), - 'Def block should have STACK input', - ); - } else { - assert.isNull( - defBlock.getInput('STACK'), - 'Def block should not have STACK input', - ); - } - if (hasReturn) { - assert.isNotNull( - defBlock.getInput('RETURN'), - 'Def block should have RETURN input', - ); - } else { - assert.isNull( - defBlock.getInput('RETURN'), - 'Def block should not have RETURN input', - ); - } - if (args.length) { - assert.include( - defBlock.toString(), - 'with', - 'Def block string should include "with"', - ); - } else { - assert.notInclude( - defBlock.toString(), - 'with', - 'Def block string should not include "with"', - ); - } - - assert.sameOrderedMembers(defBlock.getVars(), args); - assertBlockVarModels(defBlock, varIds); -} - -/** - * Asserts that the procedure call block has the expected inputs and - * fields. - * @param {!Blockly.Block} callBlock The procedure call block. - * @param {Array=} args An array of argument names. - * @param {Array=} varIds An array of variable ids. - * @param {string=} name The name we expect the caller to have. - */ -export function assertCallBlockStructure( - callBlock, - args = [], - varIds = [], - name = undefined, -) { - if (args.length) { - assert.include(callBlock.toString(), 'with'); - } else { - assert.notInclude(callBlock.toString(), 'with'); - } - - assertCallBlockArgsStructure(callBlock, args); - assertBlockVarModels(callBlock, varIds); - if (name !== undefined) { - assert.equal(callBlock.getFieldValue('NAME'), name); - } -} - -/** - * Creates procedure definition block using domToBlock call. - * @param {!Blockly.Workspace} workspace The Blockly workspace. - * @param {boolean=} hasReturn Whether the procedure definition should have - * return. - * @param {Array=} args An array of argument names. - * @param {string=} name The name of the def block (defaults to 'proc name'). - * @returns {Blockly.Block} The created block. - */ -export function createProcDefBlock( - workspace, - hasReturn = false, - args = [], - name = 'proc name', -) { - return Blockly.serialization.blocks.append( - { - type: hasReturn ? 'procedures_defreturn' : 'procedures_defnoreturn', - fields: { - NAME: name, - }, - extraState: { - params: args.map((a) => ({name: a})), - }, - }, - workspace, - ); -} - -/** - * Creates procedure call block using domToBlock call. - * @param {!Blockly.Workspace} workspace The Blockly workspace. - * @param {boolean=} hasReturn Whether the corresponding procedure definition - * has return. - * @param {string=} name The name of the caller block - * (defaults to 'proc name'). - * @returns {Blockly.Block} The created block. - */ -export function createProcCallBlock( - workspace, - hasReturn = false, - name = 'proc name', -) { - return Blockly.serialization.blocks.append( - { - type: hasReturn ? 'procedures_callreturn' : 'procedures_callnoreturn', - extraState: { - name: name, - }, - }, - workspace, - ); -} diff --git a/plugins/block-shareable-procedures/tsconfig.json b/plugins/block-shareable-procedures/tsconfig.json deleted file mode 100644 index b4bc95bc1..000000000 --- a/plugins/block-shareable-procedures/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": false - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/block-test/CHANGELOG.md b/plugins/block-test/CHANGELOG.md deleted file mode 100644 index de6888d52..000000000 --- a/plugins/block-test/CHANGELOG.md +++ /dev/null @@ -1,536 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Fix block-test under v13 ([#2714](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2714)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [7.0.6](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-test@7.0.5...@blockly/block-test@7.0.6) (2026-04-09) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [7.0.5](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/block-test@7.0.4...@blockly/block-test@7.0.5) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [7.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-test@7.0.3...@blockly/block-test@7.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [7.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-test@7.0.2...@blockly/block-test@7.0.3) (2025-12-19) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [7.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@7.0.1...@blockly/block-test@7.0.2) (2025-07-17) - - -### Bug Fixes - -* Add labels to empty statement blocks for drag tests ([285b11e](https://github.com/google/blockly-samples/commit/285b11ebed3b3414904a7661f503989b35491ca9)) - - - -## [7.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@7.0.0...@blockly/block-test@7.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [7.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.13...@blockly/block-test@7.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [6.0.13](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.12...@blockly/block-test@6.0.13) (2025-05-16) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.12](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.11...@blockly/block-test@6.0.12) (2025-05-15) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.11](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.10...@blockly/block-test@6.0.11) (2024-12-03) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.10](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.9...@blockly/block-test@6.0.10) (2024-11-07) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.9](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.8...@blockly/block-test@6.0.9) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.7...@blockly/block-test@6.0.8) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.6...@blockly/block-test@6.0.7) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.5...@blockly/block-test@6.0.6) (2024-08-08) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.4...@blockly/block-test@6.0.5) (2024-08-01) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.3...@blockly/block-test@6.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.2...@blockly/block-test@6.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.1...@blockly/block-test@6.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@6.0.0...@blockly/block-test@6.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.1.3...@blockly/block-test@6.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) - - - -## [5.1.3](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.1.2...@blockly/block-test@5.1.3) (2024-05-16) - - -### Bug Fixes - -* **block-test:** Fix incorrect references to Blockly.prompt ([#2344](https://github.com/google/blockly-samples/issues/2344)) ([3684d45](https://github.com/google/blockly-samples/commit/3684d452b8188d0ffaf7aefc7122a8ee4dec6305)) -* remove angle fields from block-test ([#2346](https://github.com/google/blockly-samples/issues/2346)) ([337ce75](https://github.com/google/blockly-samples/commit/337ce75ab72a74b6c9c2551f92442cbf848a5e90)) - - - -## [5.1.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.1.1...@blockly/block-test@5.1.2) (2024-05-09) - - -### Bug Fixes - -* Fix incorrect Blockly imports ([#2339](https://github.com/google/blockly-samples/issues/2339)) ([9af40b9](https://github.com/google/blockly-samples/commit/9af40b9ca075275af2b48cedcc1750d458084eb3)) - - - -## [5.1.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.1.0...@blockly/block-test@5.1.1) (2024-04-04) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [5.1.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.0.4...@blockly/block-test@5.1.0) (2024-02-08) - - -### Features - -* add chameleon test block ([#2193](https://github.com/google/blockly-samples/issues/2193)) ([435f282](https://github.com/google/blockly-samples/commit/435f28200f75362afce241922bb233f9fad9a36d)) - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.0.3...@blockly/block-test@5.0.4) (2023-12-14) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.0.2...@blockly/block-test@5.0.3) (2023-11-09) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.0.1...@blockly/block-test@5.0.2) (2023-11-02) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@5.0.0...@blockly/block-test@5.0.1) (2023-10-30) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@4.0.2...@blockly/block-test@5.0.0) (2023-07-24) - - -### ⚠ BREAKING CHANGES - -* update dyanamic connection and test block plugins to blockly v10 (#1812) - -### Bug Fixes - -* update dyanamic connection and test block plugins to blockly v10 ([#1812](https://github.com/google/blockly-samples/issues/1812)) ([37a2a4d](https://github.com/google/blockly-samples/commit/37a2a4d868f9707a055d08f204003bfb54af7d4c)) - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@4.0.1...@blockly/block-test@4.0.2) (2023-07-20) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@4.0.0...@blockly/block-test@4.0.1) (2023-07-13) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.1.3...@blockly/block-test@4.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [3.1.3](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.1.2...@blockly/block-test@3.1.3) (2023-06-22) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.1.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.1.1...@blockly/block-test@3.1.2) (2023-05-18) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.1.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.1.0...@blockly/block-test@3.1.1) (2023-05-11) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.1.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.9...@blockly/block-test@3.1.0) (2023-05-04) - - -### Features - -* add test block with resizable block in mutator ([#1638](https://github.com/google/blockly-samples/issues/1638)) ([ce6bebf](https://github.com/google/blockly-samples/commit/ce6bebfb7856950918ea1f0f48a5dce729354674)) - - - -## [3.0.9](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.8...@blockly/block-test@3.0.9) (2023-04-27) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.8](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.7...@blockly/block-test@3.0.8) (2023-03-23) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.6...@blockly/block-test@3.0.7) (2023-03-09) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.5...@blockly/block-test@3.0.6) (2023-03-02) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.4...@blockly/block-test@3.0.5) (2023-02-16) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.3...@blockly/block-test@3.0.4) (2023-02-09) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.2...@blockly/block-test@3.0.3) (2023-01-05) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.1...@blockly/block-test@3.0.2) (2022-12-15) - - -### Bug Fixes - -* Don't use private fields to access the workspace flyout buttons are on. ([#1458](https://github.com/google/blockly-samples/issues/1458)) ([742ce59](https://github.com/google/blockly-samples/commit/742ce5932736a3859b0b45e34b1716d7a9b5dd81)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/block-test@3.0.0...@blockly/block-test@3.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/block-test@2.0.18...@blockly/block-test@3.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* block-test unregister warning ([#1280](https://github.com/google/blockly-samples/issues/1280)) ([2e20697](https://github.com/google/blockly-samples/commit/2e20697f74c14410eb873a4e8c93832e8c4429b8)) -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 2.0.18 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 2.0.17 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 2.0.15 (2022-07-21) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## 2.0.14 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 2.0.13 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 2.0.12 (2022-06-21) - -**Note:** Version bump only for package @blockly/block-test - - - - - -## 2.0.11 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 2.0.10 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/block-test/README.md b/plugins/block-test/README.md deleted file mode 100644 index d97290898..000000000 --- a/plugins/block-test/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# @blockly/block-test [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A set of [Blockly](https://www.npmjs.com/package/blockly) test blocks. - -## Installation - -### Yarn - -``` -yarn add @blockly/block-test -``` - -### npm - -``` -npm install @blockly/block-test --save -``` - -## Usage - -### Import - -```js -import * as Blockly from 'blockly'; -import {toolboxTestBlocks, toolboxTestBlocksInit} from '@blockly/block-test'; - -// Configure the Blockly workspace to use the test block's toolbox. -const workspace = Blockly.inject('blocklyDiv', { - ...options - toolbox: toolboxTestBlocks, -}); - -// Initalize the test block's toolbox. -toolboxTestBlocksInit(workspace); -``` - -## License - -Apache 2.0 diff --git a/plugins/block-test/package.json b/plugins/block-test/package.json deleted file mode 100644 index c3ec58375..000000000 --- a/plugins/block-test/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@blockly/block-test", - "version": "13.2.0", - "description": "A group of Blockly test blocks.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start" - }, - "main": "./dist/index.js", - "module": "./src/index.js", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "blockly-plugin", - "blockly-block", - "test" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/block-test#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/block-test" - }, - "license": "Apache 2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/block-test/src/align.js b/plugins/block-test/src/align.js deleted file mode 100644 index 235728ca4..000000000 --- a/plugins/block-test/src/align.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Align test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_align_dummy_right', - message0: 'text right %1 long text right %2', - args0: [ - { - type: 'input_dummy', - align: 'RIGHT', - }, - { - type: 'input_dummy', - align: 'RIGHT', - }, - ], - style: 'math_blocks', - }, - { - type: 'test_align_all', - message0: - 'text %1 long text left %2 text centre %3 much longer text ' + 'right %4', - args0: [ - { - type: 'input_dummy', - }, - { - type: 'input_dummy', - align: 'LEFT', - }, - { - type: 'input_dummy', - align: 'CENTRE', - }, - { - type: 'input_dummy', - align: 'RIGHT', - }, - ], - style: 'math_blocks', - }, - { - type: 'test_align_with_external_input', - message0: - 'text right %1 long text centre %2 text left %3 much longer ' + 'text %4', - args0: [ - { - type: 'input_dummy', - align: 'RIGHT', - }, - { - type: 'input_dummy', - align: 'CENTRE', - }, - { - type: 'input_dummy', - align: 'LEFT', - }, - { - type: 'input_value', - name: 'VALUE', - }, - ], - inputsInline: false, - style: 'math_blocks', - }, -]); - -/** - * The Align category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Align', - contents: [ - { - kind: 'BLOCK', - type: 'test_align_dummy_right', - }, - { - kind: 'BLOCK', - type: 'test_align_all', - }, - { - kind: 'BLOCK', - type: 'test_align_with_external_input', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/basic.js b/plugins/block-test/src/basic.js deleted file mode 100644 index 68d093125..000000000 --- a/plugins/block-test/src/basic.js +++ /dev/null @@ -1,219 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Basic test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_basic_empty', - message0: '', - args0: [], - }, - { - type: 'test_basic_stack', - message0: 'stack block', - previousStatement: null, - nextStatement: null, - colour: '120', - }, - { - type: 'test_basic_dummy', - message0: 'dummy input %1', - args0: [ - { - type: 'input_dummy', - }, - ], - style: 'math_blocks', - }, - { - type: 'test_basic_multiple_dummy', - message0: 'first dummy %1 second dummy %2', - args0: [ - { - type: 'input_dummy', - }, - { - type: 'input_dummy', - }, - ], - style: 'math_blocks', - }, - { - type: 'test_basic_row', - message0: 'row block %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_basic_value_to_stack', - message0: 'value to stack', - nextStatement: null, - output: null, - style: 'math_blocks', - }, - { - type: 'test_basic_value_to_statement', - message0: 'value to statement %1', - args0: [ - { - type: 'input_statement', - name: 'STATEMENT', - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_basic_limit_instances', - message0: 'limit 3 instances %1 %2', - args0: [ - { - type: 'input_dummy', - }, - { - type: 'input_statement', - name: 'STATEMENT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'math_blocks', - }, - { - type: 'test_basic_tooltips', - message0: '%1 %2 %3', - args0: [ - { - type: 'field_label', - name: 'NAME', - text: 'field tooltip', - tooltip: 'This is a JSON tooltip for the *field*.', - }, - { - type: 'input_dummy', - }, - { - type: 'field_label', - name: 'NAME', - text: 'block tooltip', - }, - ], - tooltip: 'This is a JSON tooltip for the *block*.', - style: 'math_blocks', - }, - { - type: 'test_basic_javascript', - message0: 'function %1(%2) { %3 %4 return %5 }', - args0: [ - 'foo', - 'args', - { - type: 'input_dummy', - }, - { - type: 'input_statement', - name: 'STACK', - }, - { - type: 'input_value', - check: 'number', - align: 'right', - name: 'RETURN', - }, - ], - inputsInline: true, - colour: 200, - tooltip: 'Hello world.', - }, -]); - -Blockly.Blocks['test_basic_empty_with_mutator'] = { - init: function () { - this.setMutator(new Blockly.icons.MutatorIcon(['math_number'], this)); - }, - - decompose: function (workspace) { - const topBlock = workspace.newBlock('math_number'); - topBlock.initSvg(); - return topBlock; - }, - compose: function () {}, -}; - -/** - * The Basic Category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Basic', - contents: [ - { - kind: 'BLOCK', - type: 'test_basic_empty', - }, - { - kind: 'BLOCK', - type: 'test_basic_empty_with_mutator', - }, - { - kind: 'BLOCK', - type: 'test_basic_dummy', - }, - { - kind: 'BLOCK', - type: 'test_basic_multiple_dummy', - }, - { - kind: 'BLOCK', - type: 'test_basic_stack', - }, - { - kind: 'BLOCK', - type: 'test_basic_row', - }, - { - kind: 'BLOCK', - type: 'test_basic_value_to_stack', - }, - { - kind: 'BLOCK', - type: 'test_basic_value_to_statement', - }, - { - kind: 'BLOCK', - type: 'test_basic_limit_instances', - }, - { - kind: 'BLOCK', - type: 'test_basic_tooltips', - }, - { - kind: 'BLOCK', - type: 'test_basic_javascript', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/chameleon.js b/plugins/block-test/src/chameleon.js deleted file mode 100644 index 00754aab8..000000000 --- a/plugins/block-test/src/chameleon.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Blocks that have both a previous connection and an output - * connection while they are being dragged. - */ - -import * as Blockly from 'blockly/core'; - -Blockly.Blocks['test_chameleon'] = { - hasOutput: true, - hasPrevious: true, - - init: function () { - this.appendDummyInput().appendField('chameleon'); - this.setColour(120); - this.updateShape(); - }, - - onchange: function (e) { - if (e.type === Blockly.Events.BLOCK_DRAG) { - console.log('got drag event'); - this.hasPrevious = - !this.outputConnection || !this.outputConnection.targetBlock(); - this.hasOutput = !this.getPreviousBlock(); - this.updateShape(); - } - }, - - updateShape: function () { - this.setPreviousStatement(this.hasPrevious); - this.setOutput(this.hasOutput); - }, -}; - -/** - * The Chameleon Category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Chameleon', - contents: [ - { - kind: 'BLOCK', - type: 'test_chameleon', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/connections/index.js b/plugins/block-test/src/connections/index.js deleted file mode 100644 index 7e9610930..000000000 --- a/plugins/block-test/src/connections/index.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Connection test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import {category as rowCategory, onInit as initRow} from './row'; -import {category as stackCategory, onInit as initStack} from './stack'; -import { - category as statementCategory, - onInit as initStatement, -} from './statement'; - -/** - * The Connections category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Connections', - expanded: 'true', - contents: [rowCategory, stackCategory, statementCategory], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - initRow(workspace); - initStack(workspace); - initStatement(workspace); -} diff --git a/plugins/block-test/src/connections/row.js b/plugins/block-test/src/connections/row.js deleted file mode 100644 index 8f879c325..000000000 --- a/plugins/block-test/src/connections/row.js +++ /dev/null @@ -1,290 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Row connection test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_connections_row_input', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'NAME', - }, - ], - colour: '#aaaaaa', - tooltip: 'No Checks\n' + 'Can connect to any output connection.', - }, - { - type: 'test_connections_row_blue', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'NAME', - check: 'greenRel', - }, - ], - output: 'noneOut', - colour: 230, - tooltip: - 'Output: noneOut\n' + - 'Input: greenRel\n' + - 'Input connection can accept yellow blocks but not red blocks.', - }, - { - type: 'test_connections_row_yellow', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'NAME', - check: ['orangeRel', 'yellowRel'], - }, - ], - output: ['yellowRel', 'greenRel'], - colour: 60, - tooltip: - 'Output: yellowRel, greenRel\n' + - 'Input: yellowRel, orangeRel\n' + - 'Output can connect to yellow blocks and blue blocks, but not red ' + - 'blocks.\n' + - 'Input can connect to yellow blocks and red blocks, but not blue ' + - 'blocks.', - }, - { - type: 'test_connections_row_red', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'NAME', - check: 'noneIn', - }, - ], - output: 'orangeRel', - colour: 0, - tooltip: - 'Output: orangeRel\n' + - 'Input: noneIn\n' + - 'Output can connect to yellow blocks, but not blue blocks.', - }, - { - type: 'test_connections_row_output', - message0: '', - output: null, - colour: '#aaaaaa', - tooltip: 'No Checks\n' + 'Can connect to any input connection.', - }, - - { - type: 'test_connections_multivalue_1valid', - message0: 'none %1 both %2', - args0: [ - { - type: 'input_value', - name: 'NAME1', - align: 'RIGHT', - check: 'noneIn', - }, - { - type: 'input_value', - name: 'NAME2', - align: 'RIGHT', - check: ['yellowRel', 'orangeRel'], - }, - ], - output: ['yellowRel', 'greenRel'], - colour: 60, - tooltip: - 'Output: yellowRel, greenRel\n' + - 'Input Top: noneIn\n' + - 'Input Bottom: yellowRel, orangeRel\n' + - 'Output can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Top Input can connect to nothing, except grey blocks.\n' + - 'Bottom Input can connect to yellow blocks and red blocks, but not' + - ' blue blocks.', - }, - { - type: 'test_connections_multivalue_2valid', - message0: 'both %1 both %2', - args0: [ - { - type: 'input_value', - name: 'NAME1', - align: 'RIGHT', - check: ['yellowRel', 'orangeRel'], - }, - { - type: 'input_value', - name: 'NAME2', - align: 'RIGHT', - check: ['yellowRel', 'orangeRel'], - }, - ], - output: ['yellowRel', 'greenRel'], - colour: 60, - tooltip: - 'Output: yellowRel, greenRel\n' + - 'Input Top: yellowRel, orangeRel\n' + - 'Input Bottom: yellowRel, orangeRel\n' + - 'Output can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Top Input can connect to yellow blocks and red blocks, but not blue' + - ' blocks.\n' + - 'Bottom Input can connect to yellow blocks and red blocks, but not' + - ' blue blocks.', - }, -]); - -/** - * Handles "insert" button in the connection row test category. This will insert - * a group of test blocks connected in a row. - * @param {!Blockly.FlyoutButton} button The Flyout button. - */ -const insertConnectionRows = function (button) { - const workspace = button.getTargetWorkspace(); - Blockly.Xml.domToWorkspace( - Blockly.utils.xml.textToDom( - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - ), - workspace, - ); -}; - -/** - * The Row connections category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Row', - contents: [ - { - kind: 'LABEL', - text: 'blocks have', - }, - { - kind: 'SEP', - gap: '-1', - }, - { - kind: 'LABEL', - text: 'tooltips', - }, - { - kind: 'BUTTON', - text: 'insert', - callbackkey: 'insertConnectionRows', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_row_input', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_row_blue', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_row_yellow', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_row_red', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_row_output', - }, - { - kind: 'BLOCK', - blockxml: ` - - - - - -`, - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_multivalue_1valid', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_multivalue_2valid', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - workspace.registerButtonCallback( - 'insertConnectionRows', - insertConnectionRows, - ); -} diff --git a/plugins/block-test/src/connections/stack.js b/plugins/block-test/src/connections/stack.js deleted file mode 100644 index d19edae98..000000000 --- a/plugins/block-test/src/connections/stack.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Stack connection test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_connections_stack_next', - message0: '', - nextStatement: null, - colour: '#aaaaaa', - tooltip: 'No Checks\n' + 'Can connect to any previous connection.', - }, - { - type: 'test_connections_stack_blue', - message0: '', - previousStatement: 'nonePrev', - nextStatement: 'greenRel', - colour: 230, - tooltip: - 'Prev: nonePrev\n' + - 'Next: greenRel\n' + - 'Next connection can accept yellow blocks but not red blocks.', - }, - { - type: 'test_connections_stack_yellow', - message0: '', - previousStatement: ['greenRel', 'yellowRel'], - nextStatement: ['yellowRel', 'orangeRel'], - colour: 60, - tooltip: - 'Prev: yellowRel, greenRel\n' + - 'Next: yellowRel, orangeRel\n' + - 'Prev can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Next can connect to yellow blocks and red blocks, but not blue' + - ' blocks.', - }, - { - type: 'test_connections_stack_red', - message0: '', - previousStatement: 'orangeRel', - nextStatement: 'noneNext', - colour: 0, - tooltip: - 'Prev: orangeRel\n' + - 'Next: noneNext\n' + - 'Prev can connect to yellow blocks, but not blue blocks.', - }, - { - type: 'test_connections_stack_prev', - message0: '', - previousStatement: null, - colour: '#aaaaaa', - tooltip: 'No Checks\n' + 'Can connect to any input connection.', - }, -]); - -/** - * Handles "insert" button in the connection stack test category. This will - * insert a group of test blocks connected in a stack. - * @param {!Blockly.FlyoutButton} button The flyout button. - */ -const insertConnectionStacks = function (button) { - const workspace = button.getTargetWorkspace(); - Blockly.Xml.domToWorkspace( - Blockly.utils.xml.textToDom( - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - ), - workspace, - ); -}; - -/** - * The Stack connections category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Stack', - contents: [ - { - kind: 'LABEL', - text: 'blocks have', - }, - { - kind: 'SEP', - gap: '-1', - }, - { - kind: 'LABEL', - text: 'tooltips', - }, - { - kind: 'BUTTON', - text: 'insert', - callbackkey: 'insertConnectionStacks', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_stack_next', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_stack_blue', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_stack_yellow', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_stack_red', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_stack_prev', - }, - { - kind: 'BLOCK', - blockxml: ` - - - - -`, - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - workspace.registerButtonCallback( - 'insertConnectionStacks', - insertConnectionStacks, - ); -} diff --git a/plugins/block-test/src/connections/statement.js b/plugins/block-test/src/connections/statement.js deleted file mode 100644 index 603c52f18..000000000 --- a/plugins/block-test/src/connections/statement.js +++ /dev/null @@ -1,267 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Statement connection test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_connections_statement_blue', - message0: 'Blue %1', - args0: [ - { - type: 'input_statement', - name: 'NAME', - check: 'greenRel', - }, - ], - previousStatement: 'nonePrev', - nextStatement: 'greenRel', - colour: 230, - tooltip: - 'Prev: nonePrev\n' + - 'Next: greenRel\n' + - 'Statement: greenRel\n' + - 'Next connection can accept yellow blocks but not red blocks.\n' + - 'Statement connection can accept yellow blocks but not red blocks.', - }, - { - type: 'test_connections_statement_yellow', - message0: 'Yellow %1', - args0: [ - { - type: 'input_statement', - name: 'NAME', - check: ['yellowRel', 'orangeRel'], - }, - ], - previousStatement: ['greenRel', 'yellowRel'], - nextStatement: ['yellowRel', 'orangeRel'], - colour: 60, - tooltip: - 'Prev: yellowRel, greenRel\n' + - 'Next: yellowRel, orangeRel\n' + - 'Statement: orangeRel\n' + - 'Prev can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Next can connect to yellow blocks and red blocks, but not blue' + - ' blocks.\n' + - 'Statement connection can accept yellow blocks and red blocks but not' + - ' blue blocks.\n', - }, - { - type: 'test_connections_statement_red', - message0: 'Red %1', - args0: [ - { - type: 'input_statement', - name: 'NAME', - check: 'noneNext', - }, - ], - previousStatement: 'orangeRel', - nextStatement: 'noneNext', - colour: 0, - tooltip: - 'Prev: orangeRel\n' + - 'Next: noneNext\n' + - 'Statement: noneNext\n' + - 'Prev connection can accept yellow blocks but not blue blocks.\n' + - 'Statement connection accepts none.', - }, - { - type: 'test_connections_statement_nonext', - message0: 'None %1', - args0: [ - { - type: 'input_statement', - name: 'NAME', - check: ['yellowRel', 'orangeRel'], - }, - ], - previousStatement: ['greenRel', 'yellowRel'], - colour: 60, - tooltip: - 'Prev: yellowRel, greenRel\n' + - 'Next: yellowRel, orangeRel\n' + - 'Statement: orangeRel\n' + - 'Prev can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Statement connection can accept yellow blocks and red blocks but not' + - ' blue blocks.\n', - }, - { - type: 'test_connections_multistatement_1valid', - message0: 'none %1 both %2', - args0: [ - { - type: 'input_statement', - name: 'NAME', - check: 'noneNext', - }, - { - type: 'input_statement', - name: 'NAME', - check: ['yellowRel', 'orangeRel'], - }, - ], - previousStatement: ['greenRel', 'yellowRel'], - colour: 60, - tooltip: - 'Prev: yellowRel, greenRel\n' + - 'Next: yellowRel, orangeRel\n' + - 'Statement: orangeRel\n' + - 'Prev can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Top Statement cannot connect to anything, except grey blocks.\n' + - 'Bottom Statement connection can accept yellow blocks and red blocks' + - ' but not blue blocks.\n', - }, - { - type: 'test_connections_multistatement_2valid', - message0: 'both %1 both %2', - args0: [ - { - type: 'input_statement', - name: 'NAME', - check: ['yellowRel', 'orangeRel'], - }, - { - type: 'input_statement', - name: 'NAME', - check: ['yellowRel', 'orangeRel'], - }, - ], - previousStatement: ['greenRel', 'yellowRel'], - colour: 60, - tooltip: - 'Prev: yellowRel, greenRel\n' + - 'Next: yellowRel, orangeRel\n' + - 'Statement: orangeRel\n' + - 'Prev can connect to yellow blocks and blue blocks, but not red' + - ' blocks.\n' + - 'Top Statement connection can accept yellow blocks and red blocks but' + - ' not blue blocks.\n' + - 'Bottom Statement connection can accept yellow blocks and red blocks' + - ' but not blue blocks.\n', - }, -]); - -/** - * Handles "insert" button in the connection statement test category. This will - * insert a group of test blocks connected as statements. - * @param {!Blockly.FlyoutButton} button The flyout button. - */ -const insertConnectionStatements = function (button) { - const workspace = button.getTargetWorkspace(); - Blockly.Xml.domToWorkspace( - Blockly.utils.xml.textToDom( - '\n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - '', - ), - workspace, - ); -}; - -/** - * The Statement connections category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Statement', - contents: [ - { - kind: 'LABEL', - text: 'blocks have', - }, - { - kind: 'SEP', - gap: '-1', - }, - { - kind: 'LABEL', - text: 'tooltips', - }, - { - kind: 'BUTTON', - text: 'insert', - callbackkey: 'insertConnectionStatements', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_statement_blue', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_statement_yellow', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_statement_red', - }, - { - kind: 'BLOCK', - type: 'test_connections_statement_nonext', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_multistatement_1valid', - }, - { - kind: 'SEP', - gap: '7', - }, - { - kind: 'BLOCK', - type: 'test_connections_multistatement_2valid', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - workspace.registerButtonCallback( - 'insertConnectionStatements', - insertConnectionStatements, - ); -} diff --git a/plugins/block-test/src/drag.js b/plugins/block-test/src/drag.js deleted file mode 100644 index 1eac79eee..000000000 --- a/plugins/block-test/src/drag.js +++ /dev/null @@ -1,261 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Drag test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -/** Block that duplicates itself on drag. */ -Blockly.Blocks['drag_to_dupe'] = { - init: function () { - this.setOutput(true, null); - this.appendDummyInput().appendField('drag to dupe'); - this.setDragStrategy(new DragToDupe(this)); - - this.cloningAllowed = true; - this.isCloningAllowed = () => { - return this.cloningAllowed && !this.isInFlyout && !this.isShadow(); - }; - this.setCloningAllowed = (/** @type {boolean} */ allowed) => { - this.cloningAllowed = allowed; - }; - }, -}; - -/** Drag strategy that duplicates the block on drag. */ -class DragToDupe extends Blockly.dragging.BlockDragStrategy { - /** - * Creates a new `DragToDupe` drag strategy. - * @param {!Blockly.BlockSvg} block The block that will be dragged. - */ - constructor(block) { - super(block); - this.draggingBlock = block; - } - - /** - * Returns a block instance on which the drag should actually be performed, - * which may differ from that which we were instantiated with. - * @returns {!Blockly.BlockSvg} The block to drag. - */ - getTargetBlock() { - let targetBlock; - - if ( - 'isCloningAllowed' in this.draggingBlock && - typeof this.draggingBlock.isCloningAllowed === 'function' && - this.draggingBlock.isCloningAllowed() - ) { - const json = Blockly.serialization.blocks.save(this.draggingBlock, { - addCoordinates: true, - }); - if (json) { - targetBlock = /** @type {!Blockly.BlockSvg} */ ( - Blockly.serialization.blocks.appendInternal( - json, - this.draggingBlock.workspace, - { - recordUndo: true, - }, - ) - ); - } - } - - targetBlock ??= super.getTargetBlock(); - this.maybeSetCloningAllowed(targetBlock, false); - return targetBlock; - } - - /** - * Handles the end of a drag. - * @param {!PointerEvent|!KeyboardEvent} event The event that triggered the - * end of the drag. - * @param {Blockly.DragDisposition} disposition How the drag is being ended. - */ - endDrag(event, disposition) { - super.endDrag(event, disposition); - this.maybeSetCloningAllowed(this.draggingBlock, true); - - if (disposition === Blockly.DragDisposition.REVERT) { - this.draggingBlock.dispose(); - } - } - - /** - * Handles a drag being reverted/cancelled. - */ - revertDrag() { - super.revertDrag(); - if ( - 'isCloningAllowed' in this.draggingBlock && - typeof this.draggingBlock.isCloningAllowed === 'function' - ) { - this.draggingBlock.dispose(); - } - } - - /** - * If supported, sets whether or not cloning the given block is allowed. - * @param {!Blockly.BlockSvg} block The block to toggle cloning on. - * @param {boolean} allowed Whether or not cloning should be allowed. - */ - maybeSetCloningAllowed(block, allowed) { - if ( - 'setCloningAllowed' in block && - typeof block.setCloningAllowed === 'function' - ) { - block.setCloningAllowed(allowed); - } - } -} - -/** - * The Drag category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Drag', - contents: [ - { - kind: 'LABEL', - text: 'Drag each to the workspace', - }, - { - kind: 'BLOCK', - blockxml: ` - - - - Drag me by this child - - -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - - - Drag me by this shadow - - -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - - - Shadow value - - - - - - - Shadow statement - - - - -`, - }, - { - kind: 'LABEL', - text: 'Multiple Variable Refs', - }, - { - kind: 'BLOCK', - blockxml: ` - - - - item - - - - - - - item - - - - -`, - }, - { - kind: 'LABEL', - text: 'Procedure Definitions', - }, - { - kind: 'BLOCK', - blockxml: ` - - without arguments - - - - - No argument reference. - - - - -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - - with one argument - - - - - Expected an argument reference here. - - - fnArgument - - - - -`, - }, - { - kind: 'BLOCK', - type: 'drag_to_dupe', - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'drag_to_dupe', - }, - }, - }, - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/fields/defaults.js b/plugins/block-test/src/fields/defaults.js deleted file mode 100644 index cf2a9bd91..000000000 --- a/plugins/block-test/src/fields/defaults.js +++ /dev/null @@ -1,281 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Default field test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_fields_text_input', - message0: 'text input %1', - args0: [ - { - type: 'field_input', - name: 'TEXT_INPUT', - text: 'default', - }, - ], - style: 'math_blocks', - tooltip: '', - helpUrl: '', - }, - { - type: 'test_fields_only_text_input', - message0: '%1', - args0: [ - { - type: 'field_input', - name: 'TEXT_INPUT', - text: 'default', - }, - ], - style: 'textInput', - tooltip: '', - helpUrl: '', - output: 'String', - }, - { - type: 'test_fields_checkbox', - message0: 'checkbox %1', - args0: [ - { - type: 'field_checkbox', - name: 'CHECKBOX', - checked: true, - }, - ], - style: 'math_blocks', - tooltip: '', - helpUrl: '', - }, - { - type: 'test_fields_variable', - message0: 'variable %1', - args0: [ - { - type: 'field_variable', - name: 'VARIABLE', - variable: 'item', - }, - ], - style: 'math_blocks', - tooltip: '', - helpUrl: '', - }, - { - type: 'test_fields_label_serializable', - message0: 'label serializable %1', - args0: [ - { - type: 'field_label_serializable', - name: 'LABEL', - text: 'default', - }, - ], - style: 'math_blocks', - tooltip: '', - helpUrl: '', - }, - { - type: 'test_fields_image', - message0: 'image %1', - args0: [ - { - type: 'field_image', - name: 'IMAGE', - src: 'https://blockly-demo.appspot.com/static/tests/media/a.png', - width: 32, - height: 32, - alt: 'A', - }, - ], - colour: 230, - }, -]); - -/** - * The Default fields category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Defaults', - contents: [ - { - kind: 'BUTTON', - text: 'add blocks to workspace', - callbackkey: 'addAllBlocksToWorkspace', - }, - { - kind: 'SEP', - gap: '8', - }, - { - kind: 'BUTTON', - text: 'set random style', - callbackkey: 'setRandomStyle', - }, - { - kind: 'SEP', - gap: '8', - }, - { - kind: 'BUTTON', - text: 'toggle enabled', - callbackkey: 'toggleEnabled', - }, - { - kind: 'SEP', - gap: '8', - }, - { - kind: 'BUTTON', - text: 'toggle shadow', - callbackkey: 'toggleShadow', - }, - { - kind: 'SEP', - gap: '8', - }, - { - kind: 'BUTTON', - text: 'toggle collapsed', - callbackkey: 'toggleCollapsed', - }, - { - kind: 'BLOCK', - type: 'test_fields_checkbox', - }, - { - kind: 'BLOCK', - type: 'test_fields_text_input', - }, - { - kind: 'BLOCK', - type: 'test_fields_only_text_input', - }, - { - kind: 'BLOCK', - type: 'test_fields_variable', - }, - { - kind: 'BUTTON', - text: 'randomize label text', - callbackkey: 'randomizeLabelText', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_fields_label_serializable', - }, - { - kind: 'BUTTON', - text: 'change image', - callbackkey: 'changeImage', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_fields_image', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - const randomizeLabelText = function (button) { - const blocks = button - .getTargetWorkspace() - .getBlocksByType('test_fields_label_serializable'); - const possible = 'AB'; - for (let i = 0, block; (block = blocks[i]); i++) { - let text = ''; - for (let j = 0; j < 4; j++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - block.setFieldValue(text, 'LABEL'); - } - }; - const setRandomStyle = function (button) { - const blocks = button - .getTargetWorkspace() - .getFlyout() - .getWorkspace() - .getAllBlocks(false); - const styles = Object.keys( - workspace.getRenderer().getConstants().blockStyles, - ); - styles.splice(styles.indexOf(blocks[0].getStyleName()), 1); - const style = styles[Math.floor(Math.random() * styles.length)]; - for (let i = 0, block; (block = blocks[i]); i++) { - block.setStyle(style); - } - }; - const toggleEnabled = function (button) { - const blocks = button - .getTargetWorkspace() - .getFlyout() - .getWorkspace() - .getAllBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - block.setDisabledReason(block.isEnabled(), 'Toggle block enabled'); - } - }; - const toggleShadow = function (button) { - const blocks = button - .getTargetWorkspace() - .getFlyout() - .getWorkspace() - .getAllBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - block.setShadow(!block.isShadow()); - } - }; - const toggleCollapsed = function (button) { - const blocks = button - .getTargetWorkspace() - .getFlyout() - .getWorkspace() - .getAllBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - block.setCollapsed(!block.isCollapsed()); - } - }; - const changeImage = function (button) { - const blocks = button - .getTargetWorkspace() - .getFlyout() - .getWorkspace() - .getBlocksByType('test_fields_image'); - const possible = 'abcdefghijklm'; - const image = possible.charAt(Math.floor(Math.random() * possible.length)); - const src = - 'https://blockly-demo.appspot.com/static/tests/media/' + image + '.png'; - for (let i = 0, block; (block = blocks[i]); i++) { - const imageField = block.getField('IMAGE'); - imageField.setValue(src); - } - }; - workspace.registerButtonCallback('randomizeLabelText', randomizeLabelText); - workspace.registerButtonCallback('setRandomStyle', setRandomStyle); - workspace.registerButtonCallback('toggleEnabled', toggleEnabled); - workspace.registerButtonCallback('toggleShadow', toggleShadow); - workspace.registerButtonCallback('toggleCollapsed', toggleCollapsed); - workspace.registerButtonCallback('changeImage', changeImage); -} diff --git a/plugins/block-test/src/fields/dropdowns.js b/plugins/block-test/src/fields/dropdowns.js deleted file mode 100644 index 723bbebf6..000000000 --- a/plugins/block-test/src/fields/dropdowns.js +++ /dev/null @@ -1,591 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Dropdown fields test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_dropdowns_long', - message0: 'long: %1', - args0: [ - { - type: 'field_dropdown', - name: 'FIELDNAME', - options: [ - ['first item', 'ITEM1'], - ['second item', 'ITEM2'], - ['third item', 'ITEM3'], - ['fourth item', 'ITEM4'], - ['fifth item', 'ITEM5'], - ['sixth item', 'ITEM6'], - ['seventh item', 'ITEM7'], - ['eighth item', 'ITEM8'], - ['ninth item', 'ITEM9'], - ['tenth item', 'ITEM10'], - ['eleventh item', 'ITEM11'], - ['twelfth item', 'ITEM12'], - ['thirteenth item', 'ITEM13'], - ['fourteenth item', 'ITEM14'], - ['fifteenth item', 'ITEM15'], - ['sixteenth item', 'ITEM16'], - ['seventeenth item', 'ITEM17'], - ['eighteenth item', 'ITEM18'], - ['nineteenth item', 'ITEM19'], - ['twentieth item', 'ITEM20'], - ['twenty-first item', 'ITEM21'], - ['twenty-second item', 'ITEM22'], - ['twenty-third item', 'ITEM23'], - ['twenty-fourth item', 'ITEM24'], - ['twenty-fifth item', 'ITEM25'], - ['twenty-sixth item', 'ITEM26'], - ['twenty-seventh item', 'ITEM27'], - ['twenty-eighth item', 'ITEM28'], - ['twenty-ninth item', 'ITEM29'], - ['thirtieth item', 'ITEM30'], - ['thirty-first item', 'ITEM31'], - ['thirty-second item', 'ITEM32'], - ], - }, - ], - }, - { - type: 'test_dropdowns_images', - message0: '%1', - args0: [ - { - NOTE: 'The following paths are relative to playground.html', - type: 'field_dropdown', - name: 'FIELDNAME', - options: [ - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/a.png', - width: 32, - height: 32, - alt: 'A', - }, - 'A', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/b.png', - width: 32, - height: 32, - alt: 'B', - }, - 'B', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/c.png', - width: 32, - height: 32, - alt: 'C', - }, - 'C', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/d.png', - width: 32, - height: 32, - alt: 'D', - }, - 'D', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/e.png', - width: 32, - height: 32, - alt: 'E', - }, - 'E', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/f.png', - width: 32, - height: 32, - alt: 'F', - }, - 'F', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/g.png', - width: 32, - height: 32, - alt: 'G', - }, - 'G', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/h.png', - width: 32, - height: 32, - alt: 'H', - }, - 'H', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/i.png', - width: 32, - height: 32, - alt: 'I', - }, - 'I', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/j.png', - width: 32, - height: 32, - alt: 'J', - }, - 'J', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/k.png', - width: 32, - height: 32, - alt: 'K', - }, - 'K', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/l.png', - width: 32, - height: 32, - alt: 'L', - }, - 'L', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/m.png', - width: 32, - height: 32, - alt: 'M', - }, - 'M', - ], - ], - }, - ], - }, - { - type: 'test_dropdowns_images_and_text', - message0: '%1', - args0: [ - { - type: 'field_dropdown', - name: 'FIELDNAME', - options: [ - ['images and text', 'IMAGES AND TEXT'], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/a.png', - width: 32, - height: 32, - alt: 'A', - }, - 'A', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/b.png', - width: 32, - height: 32, - alt: 'B', - }, - 'B', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/c.png', - width: 32, - height: 32, - alt: 'C', - }, - 'C', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/d.png', - width: 32, - height: 32, - alt: 'D', - }, - 'D', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/e.png', - width: 32, - height: 32, - alt: 'E', - }, - 'E', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/f.png', - width: 32, - height: 32, - alt: 'F', - }, - 'F', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/g.png', - width: 32, - height: 32, - alt: 'G', - }, - 'G', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/h.png', - width: 32, - height: 32, - alt: 'H', - }, - 'H', - ], - ['xyz', 'LMNOP'], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/i.png', - width: 32, - height: 32, - alt: 'I', - }, - 'I', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/j.png', - width: 32, - height: 32, - alt: 'J', - }, - 'J', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/k.png', - width: 32, - height: 32, - alt: 'K', - }, - 'K', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/l.png', - width: 32, - height: 32, - alt: 'L', - }, - 'L', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/m.png', - width: 32, - height: 32, - alt: 'M', - }, - 'M', - ], - ], - }, - ], - }, - { - type: 'test_dropdowns_in_mutator', - message0: 'dropdown mutator', - mutator: 'test_dropdown_mutator', - }, - { - type: 'test_dropdowns_in_mutator_block', - message0: 'dropdown %1', - args0: [ - { - type: 'field_dropdown', - name: 'DROPDOWN', - options: [ - ['option', 'ONE'], - ['option', 'TWO'], - ], - }, - ], - }, -]); - -/** - * An array of options for the dynamic dropdown. - * @type {!Array.} - * @private - */ -const dynamicDropdownOptions_ = []; - -/** - * Handles "add option" button in the field test category. This will prompt - * the user for an option to add. - * @package - */ -const addDynamicDropdownOption = function () { - Blockly.dialog.prompt( - 'Add an option?', - 'option ' + dynamicDropdownOptions_.length, - function (text) { - if (text) { - // Do not remove this log! Helps you know if it was added correctly. - console.log('Adding option: ' + text); - // The option is an array containing human-readable text and a - // language-neutral id. - dynamicDropdownOptions_.push([ - text, - 'OPTION' + dynamicDropdownOptions_.length, - ]); - } - }, - ); -}; - -/** - * Handles "remove option" button in the field test category. This will prompt - * the user for an option to remove. May remove multiple options with the - * same name. - * @package - */ -const removeDynamicDropdownOption = function () { - const defaultText = dynamicDropdownOptions_[0] - ? dynamicDropdownOptions_[0][0] - : ''; - Blockly.dialog.prompt('Remove an option?', defaultText, function (text) { - for (let i = 0, option; (option = dynamicDropdownOptions_[i]); i++) { - // The option is an array containing human-readable text and a - // language-neutral id, we'll compare against the human-readable text. - if (option[0] == text) { - // Do not remove this log! Helps you know if it was removed correctly. - console.log('Removing option: ' + text); - dynamicDropdownOptions_.splice(i, 1); - } - } - }); -}; - -Blockly.Blocks['test_dropdowns_dynamic_random'] = { - init: function () { - const dropdown = new Blockly.FieldDropdown(this.dynamicOptions); - this.appendDummyInput() - .appendField('dynamic random') - .appendField(dropdown, 'OPTIONS'); - }, - - dynamicOptions: function () { - const random = Math.floor(Math.random() * 10) + 1; - const options = []; - for (let i = 0; i < random; i++) { - options.push([String(i), String(i)]); - } - return options; - }, -}; - -Blockly.Blocks['test_dropdowns_dynamic_connect_dependant'] = { - init: function () { - const dropdown = new Blockly.FieldDropdown(this.dynamicOptions); - this.appendDummyInput() - .appendField('dynamic connect-dependant') - .appendField(dropdown, 'OPTIONS'); - this.setNextStatement(true); - this.setPreviousStatement(true); - }, - - dynamicOptions: function () { - if (this.sourceBlock_ && this.sourceBlock_.getSurroundParent()) { - const parent = this.sourceBlock_.getSurroundParent(); - const options = [ - ['connected', 'CONNECTED_KEY'], - [`surroundParent: ${parent.type}`, `${parent.id}_type_key`], - [`surroundParent: ${parent.id}`, `${parent.id}_key`], - ]; - const top = this.sourceBlock_.getTopStackBlock(); - if (top.id !== parent.id) { - options.push([`topStack: ${top.type}`, `${top.id}_type_key`]); - options.push([`topStack: ${top.id}`, `${top.id}_key`]); - } - return options; - } else { - return [['unconnected', 'UNCONNECTED_KEY']]; - } - }, -}; - -/** - * Mutator methods added to the test_dropdowns_in_mutator block. - * @mixin - * @package - * @readonly - */ -const DROPDOWN_MUTATOR = { - /** - * Create XML to represent the block mutation. - * @returns {Element} XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - const container = Blockly.utils.xml.createElement('mutation'); - return container; - }, - /** - * Restore a block from XML. - * @param {!Element} _xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (_xmlElement) {}, - /** - * Returns the state of the block as a JSON serializable object. - * @returns {!Object} The state of the block as a JSON serializable object. - */ - saveExtraState: function () { - return {}; - }, - /** - * Applies the given state to the block. - * @param {!Object} _state The state to apply. - */ - loadExtraState: function (_state) {}, - /** - * Populate the mutator's dialog with this block's components. - * @param {!Blockly.Workspace} workspace Mutator's workspace. - * @returns {!Blockly.Block} Root block in mutator. - * @this {Blockly.Block} - */ - decompose: function (workspace) { - const containerBlock = workspace.newBlock( - 'test_dropdowns_in_mutator_block', - ); - containerBlock.initSvg(); - - 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) {}, -}; - -/** - * Register custom mutator used by the test_dropdowns_in_mutator block. - */ -Blockly.Extensions.registerMutator( - 'test_dropdown_mutator', - DROPDOWN_MUTATOR, - null, - ['test_dropdowns_in_mutator_block'], -); - -Blockly.Blocks['test_dropdowns_dynamic'] = { - init: function () { - const dropdown = new Blockly.FieldDropdown(this.dynamicOptions); - this.appendDummyInput() - .appendField('dynamic') - .appendField(dropdown, 'OPTIONS'); - }, - - dynamicOptions: function () { - if (!dynamicDropdownOptions_.length) { - return [['', 'OPTION0']]; - } - return dynamicDropdownOptions_; - }, -}; - -/** - * The Dropdown field category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Drop-downs', - contents: [ - { - kind: 'LABEL', - text: 'Dynamic', - }, - { - kind: 'BLOCK', - type: 'test_dropdowns_dynamic', - }, - { - kind: 'BUTTON', - text: 'Add option', - callbackkey: 'addDynamicOption', - }, - { - kind: 'BUTTON', - text: 'Remove option', - callbackkey: 'removeDynamicOption', - }, - { - kind: 'BLOCK', - type: 'test_dropdowns_dynamic_random', - }, - { - kind: 'BLOCK', - type: 'test_dropdowns_dynamic_connect_dependant', - }, - { - kind: 'LABEL', - text: 'Other', - }, - { - kind: 'BLOCK', - type: 'test_dropdowns_long', - }, - { - kind: 'BLOCK', - type: 'test_dropdowns_images', - }, - { - kind: 'BLOCK', - type: 'test_dropdowns_images_and_text', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - workspace.registerButtonCallback( - 'addDynamicOption', - addDynamicDropdownOption, - ); - workspace.registerButtonCallback( - 'removeDynamicOption', - removeDynamicDropdownOption, - ); -} diff --git a/plugins/block-test/src/fields/emojis.js b/plugins/block-test/src/fields/emojis.js deleted file mode 100644 index fc4ae83f7..000000000 --- a/plugins/block-test/src/fields/emojis.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Emojis in fields test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -/** - * The Emoji category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Emoji! o((*^ᴗ^*))o', - contents: [ - { - kind: 'LABEL', - text: 'Unicode & Emojis', - }, - { - kind: 'BLOCK', - type: 'test_style_emoji', - }, - { - kind: 'BLOCK', - blockxml: ` - - Robot face in text field:🤖 -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - Zalgo in text field:B̛̻̦̬̘̰͎̥̈̔͊͞ͅl̡͖̫̺̬̖̣̳̃̀́͑͑̕͟͠͝o̢̹͙̮̫͔͋̉̊̑̿̽̚c̸̹̹̜͙̹̠͋̒͑̊̇͝k̡͉̫͇̖̳͖̊͒́̆̄̎̂̔̕͜͞l̰̙̞̳̩̠͖̯̀̆̈́̿̈̓͗y̨̡̟͇̮͈̬̙̲̏̅̀͘͠ -`, - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/fields/images.js b/plugins/block-test/src/fields/images.js deleted file mode 100644 index 607b8f940..000000000 --- a/plugins/block-test/src/fields/images.js +++ /dev/null @@ -1,281 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Image fields test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_images_datauri', - message0: 'Image data: URI %1', - args0: [ - { - type: 'field_image', - src: 'data:image/png;base64,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', - width: 50, - height: 50, - alt: '*', - }, - ], - style: 'text_blocks', - }, - { - type: 'test_images_small', - message0: 'Image too small %1', - args0: [ - { - type: 'field_image', - src: 'media/30px.png', - width: 50, - height: 50, - alt: '*', - }, - ], - style: 'text_blocks', - }, - { - type: 'test_images_large', - message0: 'Image too large %1', - args0: [ - { - type: 'field_image', - src: 'media/200px.png', - width: 50, - height: 50, - alt: '*', - }, - ], - style: 'text_blocks', - }, - { - type: 'test_images_fliprtl', - message0: 'Image flipped RTL %1', - args0: [ - { - type: 'field_image', - src: 'media/arrow.png', - width: 50, - height: 50, - alt: '*', - flipRtl: true, - }, - ], - colour: 160, - }, - { - type: 'test_images_missing', - message0: 'Image missing %1', - args0: [ - { - type: 'field_image', - src: 'missing.png', - width: 50, - height: 50, - alt: '*', - }, - ], - style: 'text_blocks', - }, - { - type: 'test_images_many_icons', - message0: - 'Lots of network icons: %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11' + - ' %12 %13 %14 %15 %16 %17 %18', - args0: [ - { - type: 'input_dummy', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/a.png', - width: 32, - height: 32, - alt: 'A', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/b.png', - width: 32, - height: 32, - alt: 'B', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/c.png', - width: 32, - height: 32, - alt: 'C', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/d.png', - width: 32, - height: 32, - alt: 'D', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/e.png', - width: 32, - height: 32, - alt: 'E', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/f.png', - width: 32, - height: 32, - alt: 'F', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/g.png', - width: 32, - height: 32, - alt: 'G', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/h.png', - width: 32, - height: 32, - alt: 'H', - }, - { - type: 'input_dummy', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/a.png', - width: 32, - height: 32, - alt: 'A', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/b.png', - width: 32, - height: 32, - alt: 'B', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/c.png', - width: 32, - height: 32, - alt: 'C', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/d.png', - width: 32, - height: 32, - alt: 'D', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/e.png', - width: 32, - height: 32, - alt: 'E', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/f.png', - width: 32, - height: 32, - alt: 'F', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/g.png', - width: 32, - height: 32, - alt: 'G', - }, - { - type: 'field_image', - src: 'https://blockly-demo.appspot.com/static/tests/media/h.png', - width: 32, - height: 32, - alt: 'H', - }, - ], - style: 'text_blocks', - }, -]); - -Blockly.Blocks['test_images_clickhandler'] = { - init: function () { - this.appendDummyInput() - .appendField('Image click handler') - .appendField( - new Blockly.FieldImage( - 'https://blockly-demo.appspot.com/static/tests/media/a.png', - 32, - 32, - 'image with click handler', - this.onClick_, - ), - 'IMAGE', - ); - this.setStyle('text_blocks'); - }, - onClick_: function () { - alert('Image clicked'); - }, -}; - -/** - * The Image field category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Images', - contents: [ - { - kind: 'BLOCK', - type: 'test_images_datauri', - }, - { - kind: 'BLOCK', - type: 'test_images_small', - }, - { - kind: 'BLOCK', - type: 'test_images_large', - }, - { - kind: 'BLOCK', - type: 'test_images_fliprtl', - }, - { - kind: 'BLOCK', - type: 'test_images_missing', - }, - { - kind: 'BLOCK', - type: 'test_images_many_icons', - }, - { - kind: 'BLOCK', - type: 'test_images_clickhandler', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/fields/index.js b/plugins/block-test/src/fields/index.js deleted file mode 100644 index 259058e35..000000000 --- a/plugins/block-test/src/fields/index.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Fields test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import {category as fieldDefaults, onInit as initDefaults} from './defaults'; -import {category as fieldNumbers, onInit as initNumbers} from './numbers'; -import {category as fieldDropdowns, onInit as initDropdowns} from './dropdowns'; -import {category as fieldImages, onInit as initImages} from './images'; -import {category as fieldEmoji, onInit as initEmoji} from './emojis'; -import { - category as fieldValidators, - onInit as initValidators, -} from './validators'; - -/** - * The fields category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Fields', - expanded: 'true', - contents: [ - fieldDefaults, - fieldNumbers, - fieldDropdowns, - fieldImages, - fieldEmoji, - fieldValidators, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - initDefaults(workspace); - initNumbers(workspace); - initDropdowns(workspace); - initImages(workspace); - initEmoji(workspace); - initValidators(workspace); -} diff --git a/plugins/block-test/src/fields/numbers.js b/plugins/block-test/src/fields/numbers.js deleted file mode 100644 index fd7d0b412..000000000 --- a/plugins/block-test/src/fields/numbers.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Number fields test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_numbers_float', - message0: 'float %1', - args0: [ - { - type: 'field_number', - name: 'NUM', - text: '0', - }, - ], - style: 'math_blocks', - output: 'Number', - tooltip: 'A number.', - }, - { - type: 'test_numbers_whole', - message0: 'precision 1 %1', - args0: [ - { - type: 'field_number', - name: 'NUM', - precision: 1, - text: '0', - }, - ], - style: 'math_blocks', - output: 'Number', - tooltip: 'The number should be rounded to multiples of 1', - }, - { - type: 'test_numbers_hundredths', - message0: 'precision 0.01 %1', - args0: [ - { - type: 'field_number', - name: 'NUM', - precision: 0.01, - text: '0', - }, - ], - style: 'math_blocks', - output: 'Number', - tooltip: 'The number should be rounded to multiples of 0.01', - }, - { - type: 'test_numbers_halves', - message0: 'precision 0.5 %1', - args0: [ - { - type: 'field_number', - name: 'NUM', - precision: 0.5, - text: '0', - }, - ], - style: 'math_blocks', - output: 'Number', - tooltip: 'The number should be rounded to multiples of 0.5', - }, - { - type: 'test_numbers_three_halves', - message0: 'precision 1.5 %1', - args0: [ - { - type: 'field_number', - name: 'NUM', - precision: 1.5, - text: '0', - }, - ], - style: 'math_blocks', - output: 'Number', - tooltip: 'The number should be rounded to multiples of 1.5', - }, - { - type: 'test_numbers_whole_bounded', - message0: 'midi note %1', - args0: [ - { - type: 'field_number', - name: 'NOTE', - precision: 1, - min: 1, - max: 127, - text: '0', - }, - ], - style: 'math_blocks', - output: 'Note', - tooltip: 'A midi note.', - }, -]); - -/** - * The Numbers field category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Numbers', - contents: [ - { - kind: 'BLOCK', - blockxml: ` - - 123.456 -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - 123.456 -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - 123.456 -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - 123.456 -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - 123.456 -`, - }, - { - kind: 'BLOCK', - blockxml: ` - - 60 -`, - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/fields/validators.js b/plugins/block-test/src/fields/validators.js deleted file mode 100644 index a0c155fb4..000000000 --- a/plugins/block-test/src/fields/validators.js +++ /dev/null @@ -1,577 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Field validators test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.Blocks['test_validators_dispose_block'] = { - init: function () { - this.appendDummyInput() - .appendField('dispose block') - .appendField( - new Blockly.FieldTextInput('default', this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'Any changes to the text cause the block to be' + ' disposed', - ); - }, - - validate: function (newValue) { - if (newValue != 'default') { - this.getSourceBlock().dispose(true); - } - }, -}; - -Blockly.Blocks['test_validators_text_null'] = { - init: function () { - this.appendDummyInput() - .appendField('always null') - .appendField( - new Blockly.FieldTextInput('default', this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'All input validates to null (invalid). The display' + - ' text will remain the input text, but the value should be the' + - ' default text. The input should be red after the first keystroke.', - ); - }, - - validate: function (newValue) { - return null; - }, -}; -Blockly.Blocks['test_validators_text_A'] = { - init: function () { - this.appendDummyInput() - .appendField("remove 'a'") - .appendField( - new Blockly.FieldTextInput('default', this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - "All 'a' characters are removed from field value." + - " The display text will include invalid 'a' characters while the" + - ' field is being edited, but the value will not.', - ); - }, - - validate: function (newValue) { - return newValue.replace(/a/g, ''); - }, -}; -Blockly.Blocks['test_validators_text_B'] = { - init: function () { - this.appendDummyInput() - .appendField("'b' -> null") - .appendField( - new Blockly.FieldTextInput('default', this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - "Upon detecting a 'b' character the input will" + - ' validated to null (invalid). Upon removal it should revert to' + - ' being valid. The display text will remain the input text, but if' + - ' the input text is invalid the value should be the default text.', - ); - }, - - validate: function (newValue) { - if (newValue.indexOf('b') !== -1) { - return null; - } - return newValue; - }, -}; - -Blockly.Blocks['test_validators_checkbox_null'] = { - init: function () { - this.appendDummyInput() - .appendField('always null') - .appendField(new Blockly.FieldCheckbox(true, this.validate), 'INPUT'); - this.setColour(230); - this.setCommentText( - 'The new input always validates to null (invalid).' + - ' This means that the field value should not change.', - ); - }, - - validate: function (newValue) { - return null; - }, -}; -Blockly.Blocks['test_validators_checkbox_match'] = { - init: function () { - this.appendDummyInput() - .appendField('force match') - .appendField(new Blockly.FieldCheckbox(true), 'MATCH') - .appendField(new Blockly.FieldCheckbox(true, this.validate), 'INPUT'); - this.setColour(230); - this.setCommentText( - 'The validator for this block only works on the end-most checkbox.' + - ' The validator will always return the value of the start-most' + - ' checkbox. Therefore they should always match.', - ); - }, - - validate: function (newValue) { - return this.sourceBlock_.getFieldValue('MATCH'); - }, -}; -Blockly.Blocks['test_validators_checkbox_not_match_null'] = { - init: function () { - this.appendDummyInput() - .appendField('not match -> null') - .appendField(new Blockly.FieldCheckbox(true), 'MATCH') - .appendField(new Blockly.FieldCheckbox(true, this.validate), 'INPUT'); - this.setColour(230); - this.setCommentText( - 'The validator for this block only works on the' + - ' end-most checkbox. If the new value does not match the value of the' + - ' start-most checkbox, it will return null (invalid), which means the' + - ' field value should not change. Therefore they should always match.', - ); - }, - - validate: function (newValue) { - if (this.sourceBlock_.getFieldValue('MATCH') != newValue) { - return null; - } - return newValue; - }, -}; - -Blockly.Blocks['test_validators_dropdown_null'] = { - init: function () { - this.appendDummyInput() - .appendField('always null') - .appendField( - new Blockly.FieldDropdown( - [ - ['1a', '1A'], - ['1b', '1B'], - ['1c', '1C'], - ['2a', '2A'], - ['2b', '2B'], - ['2c', '2C'], - ], - this.validate, - ), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'All input validates to null (invalid). This means' + - ' the field value should not change.', - ); - }, - - validate: function (newValue) { - return null; - }, -}; -Blockly.Blocks['test_validators_dropdown_force_1s'] = { - init: function () { - this.appendDummyInput() - .appendField('force 1s') - .appendField( - new Blockly.FieldDropdown( - [ - ['1a', '1A'], - ['1b', '1B'], - ['1c', '1C'], - ['2a', '2A'], - ['2b', '2B'], - ['2c', '2C'], - ], - this.validate, - ), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - "The input's value will always change to start with 1.", - ); - }, - - validate: function (newValue) { - return '1' + newValue.charAt(1); - }, -}; -Blockly.Blocks['test_validators_dropdown_1s_null'] = { - init: function () { - this.appendDummyInput() - .appendField('not 1s -> null') - .appendField( - new Blockly.FieldDropdown( - [ - ['1a', '1A'], - ['1b', '1B'], - ['1c', '1C'], - ['2a', '2A'], - ['2b', '2B'], - ['2c', '2C'], - ], - this.validate, - ), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'If the input does not start with 1, the input will validate to' + - ' null (invalid). Otherwise it will return the input value.', - ); - }, - - validate: function (newValue) { - if (newValue.charAt(0) != '1') { - return null; - } - return newValue; - }, -}; - -Blockly.Blocks['test_validators_number_null'] = { - init: function () { - this.appendDummyInput() - .appendField('always null') - .appendField( - new Blockly.FieldNumber(123, null, null, null, this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'All input validates to null (invalid). The field will display the' + - ' input while the field is being edited, but the value should be the' + - ' default value. The input should be red after the first' + - ' keystroke.', - ); - }, - - validate: function (newValue) { - return null; - }, -}; -Blockly.Blocks['test_validators_number_mult10_force'] = { - init: function () { - this.appendDummyInput() - .appendField('force mult of 10') - .appendField( - new Blockly.FieldNumber(123, null, null, null, this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'The input value will be rounded to the nearest' + - ' multiple of 10. The field will display the input while the field is' + - ' being edited, but the value should be the validated (rounded)' + - ' value. Note: If you want to do rounding this is not the proper' + - ' way, use the precision option of the number field constructor' + - ' instead.', - ); - }, - - validate: function (newValue) { - return Math.round(newValue / 10) * 10; - }, -}; -Blockly.Blocks['test_validators_number_mult10_null'] = { - init: function () { - this.appendDummyInput() - .appendField('not mult of 10 -> null') - .appendField( - new Blockly.FieldNumber(123, null, null, null, this.validate), - 'INPUT', - ); - this.setColour(230); - this.setCommentText( - 'If the input value is not a multiple of 10, the' + - ' input will validate to null (invalid). The field will display the' + - ' input while the field is being edited, but if the input value is' + - ' invalid the value should be the default value.', - ); - }, - - validate: function (newValue) { - if (newValue % 10 != 0) { - return null; - } - return newValue; - }, -}; - -Blockly.Blocks['test_validators_variable_null'] = { - init: function () { - this.appendDummyInput() - .appendField('always null') - .appendField(new Blockly.FieldVariable('1a', this.validate), 'INPUT'); - this.setColour(230); - this.setCommentText( - 'All ids validate to null (invalid). This means' + - ' the variable should not change.', - ); - }, - - validate: function (newValue) { - return null; - }, -}; -Blockly.Blocks['test_validators_variable_force_1s'] = { - init: function () { - this.appendDummyInput() - .appendField('force 1s') - .appendField(new Blockly.FieldVariable('1a', this.validate), 'INPUT'); - this.setColour(230); - this.setCommentText('The id will always change to start with 1.'); - }, - - validate: function (newValue) { - return '1' + newValue.charAt(1); - }, -}; -Blockly.Blocks['test_validators_variable_1s_null'] = { - init: function () { - this.appendDummyInput() - .appendField('not 1s -> null') - .appendField(new Blockly.FieldVariable('1a', this.validate), 'INPUT'); - this.setColour(230); - this.setCommentText( - 'If the id does not start with 1, the id will' + - ' validate to null (invalid). Otherwise it will return the id.', - ); - }, - - validate: function (newValue) { - if (newValue.charAt(0) != '1') { - return null; - } - return newValue; - }, -}; - -/** - * The Validators field category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Validators', - contents: [ - { - kind: 'BUTTON', - text: 'add blocks to workspace', - callbackkey: 'addAllBlocksToWorkspace', - }, - { - kind: 'SEP', - gap: '8', - }, - { - kind: 'BUTTON', - text: 'set input', - callbackkey: 'setInput', - }, - { - kind: 'LABEL', - text: 'Dispose block', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_dispose_block', - }, - { - kind: 'LABEL', - text: 'Checkboxes', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_checkbox_null', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_checkbox_match', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_checkbox_not_match_null', - }, - { - kind: 'LABEL', - text: 'Dropdowns', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_dropdown_null', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_dropdown_force_1s', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_dropdown_1s_null', - }, - { - kind: 'LABEL', - text: 'Numbers', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_number_null', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_number_mult10_force', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_number_mult10_null', - }, - { - kind: 'LABEL', - text: 'Text', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_text_null', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_text_A', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_text_B', - }, - { - kind: 'LABEL', - text: 'Variables', - }, - { - kind: 'SEP', - gap: '8', - }, - { - 'kind': 'BUTTON', - 'text': 'add test variables', - 'callbackkey': 'addVariables', - 'web-class': 'modifiesWorkspace', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_variable_null', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_variable_force_1s', - }, - { - kind: 'SEP', - gap: '12', - }, - { - kind: 'BLOCK', - type: 'test_validators_variable_1s_null', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - const addVariables = function (button) { - workspace.getVariableMap().createVariable('1b', '', '1B'); - workspace.getVariableMap().createVariable('1c', '', '1C'); - workspace.getVariableMap().createVariable('2a', '', '2A'); - workspace.getVariableMap().createVariable('2b', '', '2B'); - workspace.getVariableMap().createVariable('2c', '', '2C'); - }; - const setInput = function (button) { - Blockly.dialog.prompt('Input text to set.', 'ab', function (input) { - const blocks = button.getTargetWorkspace().getAllBlocks(false); - for (let i = 0, block; (block = blocks[i]); i++) { - if (block.getField('INPUT')) { - block.setFieldValue(input, 'INPUT'); - } - } - }); - }; - - workspace.registerButtonCallback('addVariables', addVariables); - workspace.registerButtonCallback('setInput', setInput); -} diff --git a/plugins/block-test/src/index.js b/plugins/block-test/src/index.js deleted file mode 100644 index 4b0771834..000000000 --- a/plugins/block-test/src/index.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Import all the test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -import {category as alignCategory, onInit as initAlign} from './align'; -import {category as basicCategory, onInit as initBasic} from './basic'; -import { - category as chameleonCategory, - onInit as initChameleon, -} from './chameleon'; -import { - category as connectionsCategory, - onInit as initConnections, -} from './connections'; -import {category as dragCategory, onInit as initDrag} from './drag'; -import {category as fieldsCategory, onInit as initFields} from './fields'; -import {category as mutatorsCategory, onInit as initMutators} from './mutators'; -import {category as styleCategory, onInit as initStyle} from './style'; -import { - category as serializationCategory, - onInit as initSerialization, -} from './serialization/category'; - -/** - * The Test blocks toolbox. - */ -export const toolboxTestBlocks = { - contents: [ - alignCategory, - basicCategory, - chameleonCategory, - connectionsCategory, - dragCategory, - fieldsCategory, - mutatorsCategory, - styleCategory, - serializationCategory, - ], -}; - -/** - * Initialize this toolbox. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function toolboxTestBlocksInit(workspace) { - initAlign(workspace); - initBasic(workspace); - initChameleon(workspace); - initConnections(workspace); - initDrag(workspace); - initFields(workspace); - initMutators(workspace); - initStyle(workspace); - initSerialization(workspace); - - const addAllBlocksToWorkspace = function (button) { - const workspace = button.getTargetWorkspace(); - const blocks = workspace.getFlyout().getWorkspace().getTopBlocks(); - for (let i = 0, block; (block = blocks[i]); i++) { - const state = Blockly.serialization.blocks.save(block, { - addCoordinates: true, - }); - Blockly.serialization.blocks.append(state, workspace); - } - }; - workspace.registerButtonCallback( - 'addAllBlocksToWorkspace', - addAllBlocksToWorkspace, - ); -} diff --git a/plugins/block-test/src/mutators.js b/plugins/block-test/src/mutators.js deleted file mode 100644 index 76316f9cc..000000000 --- a/plugins/block-test/src/mutators.js +++ /dev/null @@ -1,257 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Mutator test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_mutator_textChange', - message0: 'mutator text: %1', - args0: [ - { - type: 'field_input', - name: 'MUTATOR_TEXT', - text: 'a label', - }, - ], - style: 'colour_blocks', - }, -]); - -/** - * Mutator methods added to the test_mutators_many block. - * @mixin - * @package - * @readonly - */ -const COLOR_CHANGE_MUTATOR = { - /** - * Create XML to represent the block mutation. - * @returns {Element} XML storage element. - * @this {Blockly.Block} - */ - mutationToDom: function () { - const container = Blockly.utils.xml.createElement('mutation'); - container.setAttribute('arbitrary', this.getFieldValue('LABEL')); - return container; - }, - /** - * Restore a block from XML. - * @param {!Element} xmlElement XML storage element. - * @this {Blockly.Block} - */ - domToMutation: function (xmlElement) { - this.setFieldValue(xmlElement.getAttribute('arbitrary'), 'LABEL'); - }, - /** - * Returns the state of this block as a json serializable object. - * @returns {{arbitrary: string}} The state of this block. - * @this {Blockly.Block} - */ - saveExtraState: function () { - return {arbitrary: this.getFieldValue('LABEL')}; - }, - /** - * Applies the state to this block. - * @param {{arbitrary: string}} state The state to apply. - * @this {Blockly.Block} - */ - loadExtraState: function (state) { - this.setFieldValue(state['arbitrary'], 'LABEL'); - }, - /** - * Populate the mutator's dialog with this block's components. - * @param {!Blockly.Workspace} workspace Mutator's workspace. - * @returns {!Blockly.Block} Root block in mutator. - * @this {Blockly.Block} - */ - decompose: function (workspace) { - const containerBlock = Blockly.serialization.blocks.append( - {type: 'test_mutator_textChange'}, - workspace, - ); - containerBlock - .getField('MUTATOR_TEXT') - .setValue(this.getFieldValue('LABEL')); - 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) { - this.setFieldValue(containerBlock.getFieldValue('MUTATOR_TEXT'), 'LABEL'); - }, -}; - -const n = 20; -const blocksIds = []; -for (let i = 0; i < n; i++) { - blocksIds.push(`test_mutator_category_${i}`); -} - -const defineBlocks = blocksIds.map((t) => ({ - type: t, - message0: 'mutator text: %1', - args0: [ - { - type: 'field_input', - name: 'MUTATOR_TEXT', - text: 'a label', - }, - ], - style: 'colour_blocks', -})); - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_mutators_many', - message0: 'test many blocks mutator %1', - args0: [ - { - type: 'field_label', - name: 'LABEL', - text: 'changeable label', - }, - ], - mutator: 'test_many_blocks_mutator', - colour: '#000000', - }, - ...defineBlocks, -]); - -/** Register custom mutator used by the test_mutators_many block. */ -Blockly.Extensions.registerMutator( - 'test_many_blocks_mutator', - COLOR_CHANGE_MUTATOR, - null, - [...blocksIds], -); - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_mutators_noflyout', - message0: 'noflyout mutator %1', - args0: [ - { - type: 'field_label', - name: 'LABEL', - text: 'changeable label', - }, - ], - mutator: 'test_noflyout_mutator', - colour: '#000000', - }, -]); - -/** Register custom mutator used by the test_mutators_noflyout block. */ -Blockly.Extensions.registerMutator( - 'test_noflyout_mutator', - COLOR_CHANGE_MUTATOR, - null, - [], -); - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_mutators_changeableFlyout', - message0: 'changeable flyout mutator %1', - args0: [ - { - type: 'field_label', - name: 'LABEL', - text: 'changeable label', - }, - ], - mutator: 'test_changeableFlyout_mutator', - colour: '#000000', - }, -]); - -/** Register custom mutator used by the test_mutators_changeableFlyout block. */ -Blockly.Extensions.registerMutator( - 'test_changeableFlyout_mutator', - COLOR_CHANGE_MUTATOR, - null, - ['text'], -); - -/** - * The Mutators category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Mutators', - contents: [ - { - kind: 'LABEL', - text: 'logic_compare', - }, - { - kind: 'BLOCK', - type: 'logic_compare', - inputs: { - A: { - shadow: { - type: 'math_number', - fields: {NUM: 10}, - }, - }, - B: { - shadow: { - type: 'math_number', - fields: {NUM: 10}, - }, - }, - }, - }, - { - kind: 'BLOCK', - type: 'logic_compare', - inputs: { - A: { - block: { - type: 'math_number', - fields: {NUM: 10}, - }, - }, - B: { - block: { - type: 'math_number', - fields: {NUM: 10}, - }, - }, - }, - }, - { - kind: 'BLOCK', - type: 'test_mutators_noflyout', - }, - { - kind: 'BLOCK', - type: 'test_mutators_many', - }, - { - kind: 'BLOCK', - type: 'test_mutators_changeableFlyout', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/src/serialization/blocks.js b/plugins/block-test/src/serialization/blocks.js deleted file mode 100644 index bb7d6a0ae..000000000 --- a/plugins/block-test/src/serialization/blocks.js +++ /dev/null @@ -1,112 +0,0 @@ -// @ts-nocheck -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -import * as Blockly from 'blockly/core'; -import './fields'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_field_serialization_no_overrides', - message0: 'no overrides: %1', - args0: [ - { - type: 'field_no_overrides', - name: 'LABEL', - text: 'test', - }, - ], - colour: 0, - output: null, - }, - { - type: 'test_field_serialization_xml', - message0: 'xml: %1', - args0: [ - { - type: 'field_xml', - name: 'LABEL', - text: 'test', - }, - ], - colour: 30, - output: null, - }, - { - type: 'test_field_serialization_jso', - message0: 'jso: %1', - args0: [ - { - type: 'field_jso', - name: 'LABEL', - text: 'test', - }, - ], - colour: 90, - output: null, - }, - { - type: 'test_field_serialization_both', - message0: 'both: %1', - args0: [ - { - type: 'field_both', - name: 'LABEL', - text: 'test', - }, - ], - colour: 150, - output: null, - }, -]); - -Blockly.Blocks['test_extra_state_xml'] = Object.assign( - {}, - Blockly.Blocks['lists_create_with'], -); -delete Blockly.Blocks['test_extra_state_xml'].saveExtraState; -delete Blockly.Blocks['test_extra_state_xml'].loadExtraState; -Blockly.Blocks['test_extra_state_xml'].init = function () { - this.setColour(30); - this.itemCount_ = 3; - this.updateShape_(); - this.setOutput(true, 'Array'); - this.setMutator( - new Blockly.icons.MutatorIcon(['lists_create_with_item'], this), - ); -}; - -Blockly.Blocks['test_extra_state_jso'] = Object.assign( - {}, - Blockly.Blocks['lists_create_with'], -); -delete Blockly.Blocks['test_extra_state_jso'].mutationToDom; -delete Blockly.Blocks['test_extra_state_jso'].domToMutation; -Blockly.Blocks['test_extra_state_jso'].init = function () { - this.setColour(90); - this.itemCount_ = 3; - this.updateShape_(); - this.setOutput(true, 'Array'); - this.setMutator( - new Blockly.icons.MutatorIcon(['lists_create_with_item'], this), - ); -}; - -Blockly.Blocks['test_extra_state_both'] = Object.assign( - {}, - Blockly.Blocks['lists_create_with'], -); -Blockly.Blocks['test_extra_state_both'].init = function () { - this.setColour(150); - this.itemCount_ = 3; - this.updateShape_(); - this.setOutput(true, 'Array'); - this.setMutator( - new Blockly.icons.MutatorIcon(['lists_create_with_item'], this), - ); -}; diff --git a/plugins/block-test/src/serialization/category.js b/plugins/block-test/src/serialization/category.js deleted file mode 100644 index 776f1bd89..000000000 --- a/plugins/block-test/src/serialization/category.js +++ /dev/null @@ -1,193 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -import * as Blockly from 'blockly/core'; -import './blocks'; - -/** - * The Serialization category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Serialization', - contents: [ - { - kind: 'BUTTON', - text: 'add blocks to workspace', - callbackkey: 'addAllBlocksToWorkspace', - }, - { - kind: 'SEP', - gap: '8', - }, - { - kind: 'BUTTON', - text: 'randomize text', - callbackkey: 'randomizeText', - }, - { - kind: 'BLOCK', - type: 'test_field_serialization_no_overrides', - }, - { - kind: 'BLOCK', - type: 'test_field_serialization_xml', - }, - { - kind: 'BLOCK', - type: 'test_field_serialization_jso', - }, - { - kind: 'BLOCK', - type: 'test_field_serialization_both', - }, - { - kind: 'SEP', - gap: 30, - }, - { - kind: 'BLOCK', - blockxml: - '' + - '' + - '', - }, - { - kind: 'BLOCK', - type: 'test_extra_state_jso', - extraState: { - itemCount: 2, - }, - }, - { - kind: 'BLOCK', - type: 'test_extra_state_both', - extraState: { - itemCount: 2, - }, - }, - { - kind: 'SEP', - gap: 30, - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'test_field_serialization_no_overrides', - }, - }, - }, - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'test_field_serialization_xml', - }, - }, - }, - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'test_field_serialization_jso', - }, - }, - }, - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'test_field_serialization_both', - }, - }, - }, - }, - { - kind: 'SEP', - gap: 30, - }, - { - kind: 'BLOCK', - blockxml: - '' + - '' + - '' + - '' + - '' + - '' + - '', - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'test_extra_state_jso', - extraState: { - itemCount: 2, - }, - }, - }, - }, - }, - { - kind: 'BLOCK', - type: 'text_print', - inputs: { - TEXT: { - shadow: { - type: 'test_extra_state_both', - extraState: { - itemCount: 2, - }, - }, - }, - }, - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - const randomizeText = function (button) { - const targetWorkspace = button.getTargetWorkspace(); - const blocks = [ - ...targetWorkspace.getBlocksByType( - 'test_field_serialization_no_overrides', - ), - ...targetWorkspace.getBlocksByType('test_field_serialization_xml'), - ...targetWorkspace.getBlocksByType('test_field_serialization_jso'), - ...targetWorkspace.getBlocksByType('test_field_serialization_both'), - ]; - const possible = 'ABCDEF'; - for (let i = 0, block; (block = blocks[i]); i++) { - let text = ''; - for (let j = 0; j < 4; j++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - block.setFieldValue(text, 'LABEL'); - } - }; - workspace.registerButtonCallback('randomizeText', randomizeText); -} diff --git a/plugins/block-test/src/serialization/fields.js b/plugins/block-test/src/serialization/fields.js deleted file mode 100644 index 0c687225c..000000000 --- a/plugins/block-test/src/serialization/fields.js +++ /dev/null @@ -1,201 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -import * as Blockly from 'blockly/core'; - -/** - * Field that does not override any serialization hooks. - */ -class NoOverridesField extends Blockly.FieldLabel { - /** - * Constructor. - * @param {string=} value The value for the field to hold. - * @param {string=} cssClass The css class to apply to the field. - * @param {*} config The config for the field. - */ - constructor(value, cssClass, config) { - super(value, cssClass, config); - - this.EDITABLE = false; - this.SERIALIZABLE = true; - } -} - -/** - * Creates the field based on its JSON definition. - * @param {*} options Options for creating the field. - * @returns {!NoOverridesField} The field that was created. - */ -NoOverridesField.fromJson = function (options) { - const text = Blockly.utils.parsing.replaceMessageReferences(options['text']); - return new this(text, undefined, options); -}; - -Blockly.fieldRegistry.register('field_no_overrides', NoOverridesField); - -/** - * Field that overrides XML serialization hooks. - */ -class XmlField extends Blockly.FieldLabel { - /** - * Constructor. - * @param {string=} value The value for the field to hold. - * @param {string=} cssClass The css class to apply to the field. - * @param {*} config The config for the field. - */ - constructor(value, cssClass, config) { - super(value, cssClass, config); - - this.EDITABLE = false; - this.SERIALIZABLE = true; - } - - /** - * Saves the state of the field as XML. - * @param {!Element} element The element to add the state to. - * @returns {!Element} The element with the state added. - */ - toXml(element) { - element.setAttribute('value', this.getValue()); - return element; - } - - /** - * Applies the given state to the field. - * @param {!Element} element The element containing the state to apply. - */ - fromXml(element) { - this.setValue(element.getAttribute('value')); - } -} - -/** - * Creates the field based on its JSON definition. - * @param {*} options Options for creating the field. - * @returns {!XmlField} The field that was created. - */ -XmlField.fromJson = function (options) { - const text = Blockly.utils.parsing.replaceMessageReferences(options['text']); - return new this(text, undefined, options); -}; - -Blockly.fieldRegistry.register('field_xml', XmlField); - -/** - * Field that overrides JSO serialization hooks. - */ -class JsoField extends Blockly.FieldLabel { - /** - * Constructor. - * @param {string=} value The value for the field to hold. - * @param {string=} cssClass The css class to apply to the field. - * @param {*} config The config for the field. - */ - constructor(value, cssClass, config) { - super(value, cssClass, config); - - this.EDITABLE = false; - this.SERIALIZABLE = true; - } - - /** - * Saves the state of the field as a JSON serializable value. - * @returns {*} The state of the field. - */ - saveState() { - return { - value: this.getValue(), - }; - } - - /** - * Applies the given state to the field. - * @param {*} state The state to apply. - */ - loadState(state) { - this.setValue(state['value']); - } -} - -/** - * Creates the field based on its JSON definition. - * @param {*} options Options for creating the field. - * @returns {!JsoField} The field that was created. - */ -JsoField.fromJson = function (options) { - const text = Blockly.utils.parsing.replaceMessageReferences(options['text']); - return new this(text, undefined, options); -}; - -Blockly.fieldRegistry.register('field_jso', JsoField); - -/** - * Field that overrides XML and JSO serialization hooks. - */ -class BothField extends Blockly.FieldLabel { - /** - * Constructor. - * @param {string=} value The value for the field to hold. - * @param {string=} cssClass The css class to apply to the field. - * @param {*} config The config for the field. - */ - constructor(value, cssClass, config) { - super(value, cssClass, config); - - this.EDITABLE = false; - this.SERIALIZABLE = true; - } - - /** - * Saves the state of the field as XML. - * @param {!Element} element The element to add the state to. - * @returns {!Element} The element with the state added. - */ - toXml(element) { - element.setAttribute('value', this.getValue()); - return element; - } - - /** - * Applies the given state to the field. - * @param {!Element} element The element containing the state to apply. - */ - fromXml(element) { - this.setValue(element.getAttribute('value')); - } - - /** - * Saves the state of the field as a JSON serializable value. - * @returns {*} The state of the field. - */ - saveState() { - return { - value: this.getValue(), - }; - } - - /** - * Applies the given state to the field. - * @param {*} state The state to apply. - */ - loadState(state) { - this.setValue(state['value']); - } -} - -/** - * Creates the field based on its JSON definition. - * @param {*} options Options for creating the field. - * @returns {!BothField} The field that was created. - */ -BothField.fromJson = function (options) { - const text = Blockly.utils.parsing.replaceMessageReferences(options['text']); - return new this(text, undefined, options); -}; - -Blockly.fieldRegistry.register('field_both', BothField); diff --git a/plugins/block-test/src/style.js b/plugins/block-test/src/style.js deleted file mode 100644 index 06c3715a6..000000000 --- a/plugins/block-test/src/style.js +++ /dev/null @@ -1,194 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -/** - * @fileoverview Style test blocks. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_style_hat', - message0: 'Hat block (event)', - nextStatement: null, - style: 'hat_blocks', - }, - { - type: 'test_style_hex1', - message0: 'Block color: Bright purple %1 %2 %3 %4', - args0: [ - { - type: 'field_input', - name: 'TEXT', - text: '#992aff', - }, - { - type: 'field_dropdown', - name: 'DROPDOWN', - options: [ - ['option', 'ONE'], - ['option', 'TWO'], - ], - }, - { - type: 'field_checkbox', - name: 'NAME', - checked: true, - }, - { - type: 'input_value', - name: 'NAME', - }, - ], - previousStatement: null, - nextStatement: null, - colour: '#992aff', - }, - { - type: 'test_style_hex2', - message0: 'Block color: White %1 %2 %3 %4', - args0: [ - { - type: 'field_input', - name: 'TEXT', - text: '#fefefe', - }, - { - type: 'field_dropdown', - name: 'DROPDOWN', - options: [ - ['option', 'ONE'], - ['option', 'TWO'], - ], - }, - { - type: 'field_checkbox', - name: 'NAME', - checked: true, - }, - { - type: 'input_value', - name: 'NAME', - }, - ], - previousStatement: null, - nextStatement: null, - colour: '#fefefe', - }, - { - type: 'test_style_hex3', - message0: 'Block color: Black %1 %2 %3 %4', - args0: [ - { - type: 'field_input', - name: 'TEXT', - text: '#010101', - }, - { - type: 'field_dropdown', - name: 'DROPDOWN', - options: [ - ['option', 'ONE'], - ['option', 'TWO'], - ], - }, - { - type: 'field_checkbox', - name: 'NAME', - checked: true, - }, - { - type: 'input_value', - name: 'NAME', - }, - ], - previousStatement: null, - nextStatement: null, - colour: '#010101', - }, - { - type: 'test_style_no_colour', - message0: 'Block color: unset', - }, - { - type: 'test_style_hex4', - message0: 'Block color: #RRGGBBAA (invalid)', - colour: '#992aff99', - }, - { - type: 'test_style_hex5', - message0: 'Block color: #RRGGBB (invalid)', - colour: '#NotHex', - }, - { - type: 'test_style_emoji', - message0: 'Robot Face: \uD83E\uDD16', - colour: '#AAAAAA', - }, -]); - -/** - * The Style category. - */ -export const category = { - kind: 'CATEGORY', - name: 'Style', - contents: [ - { - kind: 'LABEL', - text: 'Hats', - }, - { - kind: 'BLOCK', - type: 'test_style_hat', - }, - { - kind: 'LABEL', - text: 'Colour', - }, - { - kind: 'BLOCK', - type: 'test_style_hex1', - }, - { - kind: 'BLOCK', - type: 'test_style_hex2', - }, - { - kind: 'BLOCK', - type: 'test_style_hex3', - }, - { - kind: 'BLOCK', - type: 'test_style_no_colour', - }, - { - kind: 'BLOCK', - type: 'test_style_hex4', - }, - { - kind: 'BLOCK', - type: 'test_style_hex5', - gap: '40', - }, - { - kind: 'BLOCK', - type: 'test_style_hex5', - disabled: 'true', - }, - ], -}; - -/** - * Initialize this toolbox category. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function onInit(workspace) { - // NOP -} diff --git a/plugins/block-test/test/index.html b/plugins/block-test/test/index.html deleted file mode 100644 index 8d4238a20..000000000 --- a/plugins/block-test/test/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Blockly Test Blocks - - - - -
- - - diff --git a/plugins/block-test/test/index.js b/plugins/block-test/test/index.js deleted file mode 100644 index 2f7e56754..000000000 --- a/plugins/block-test/test/index.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Block test. - */ - -import * as Blockly from 'blockly'; -import { - toolboxTestBlocks as toolbox, - toolboxTestBlocksInit as onInit, -} from '../src/index'; - -// Do not use the advanced playground here because it will create a circular -// dependency with the @blockly/dev-tools package. -document.addEventListener('DOMContentLoaded', function () { - const workspace = Blockly.inject('root', { - toolbox: toolbox, - maxInstances: { - test_basic_limit_instances: 3, - }, - }); - onInit(workspace); -}); diff --git a/plugins/content-highlight/CHANGELOG.md b/plugins/content-highlight/CHANGELOG.md deleted file mode 100644 index 630e89852..000000000 --- a/plugins/content-highlight/CHANGELOG.md +++ /dev/null @@ -1,687 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [6.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.8...@blockly/workspace-content-highlight@6.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.7...@blockly/workspace-content-highlight@6.0.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.6...@blockly/workspace-content-highlight@6.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.5...@blockly/workspace-content-highlight@6.0.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.4...@blockly/workspace-content-highlight@6.0.5) (2025-12-19) - - -### Bug Fixes - -* handle comment moves and resizes in content-highlight ([#2653](https://github.com/google/blockly-samples/issues/2653)) ([031f351](https://github.com/google/blockly-samples/commit/031f351c295c60c5df1db7e9136c35b7e72661fd)) - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.3...@blockly/workspace-content-highlight@6.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.2...@blockly/workspace-content-highlight@6.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.1...@blockly/workspace-content-highlight@6.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@6.0.0...@blockly/workspace-content-highlight@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.17...@blockly/workspace-content-highlight@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.16...@blockly/workspace-content-highlight@5.0.17) (2025-05-16) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.15...@blockly/workspace-content-highlight@5.0.16) (2025-05-15) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.14...@blockly/workspace-content-highlight@5.0.15) (2025-02-20) - - -### Bug Fixes - -* update content highlight when undoing the deletion of blocks. ([#2487](https://github.com/google/blockly-samples/issues/2487)) ([b216e9e](https://github.com/google/blockly-samples/commit/b216e9eeaf84e5f51af2bc72b8b15a40c7137697)) - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.13...@blockly/workspace-content-highlight@5.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.12...@blockly/workspace-content-highlight@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.11...@blockly/workspace-content-highlight@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.10...@blockly/workspace-content-highlight@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.9...@blockly/workspace-content-highlight@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.8...@blockly/workspace-content-highlight@5.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.7...@blockly/workspace-content-highlight@5.0.8) (2024-08-22) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.6...@blockly/workspace-content-highlight@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.5...@blockly/workspace-content-highlight@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.4...@blockly/workspace-content-highlight@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.3...@blockly/workspace-content-highlight@5.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.2...@blockly/workspace-content-highlight@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.1...@blockly/workspace-content-highlight@5.0.2) (2024-06-06) - - -### Bug Fixes - -* Update content highlight when workspace comment is moved. ([#2381](https://github.com/google/blockly-samples/issues/2381)) ([f769849](https://github.com/google/blockly-samples/commit/f769849a01799f38245134587311d244f731d1a1)) - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@5.0.0...@blockly/workspace-content-highlight@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.17...@blockly/workspace-content-highlight@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) -* make content highlight build with v11 beta ([#2168](https://github.com/google/blockly-samples/issues/2168)) ([2596711](https://github.com/google/blockly-samples/commit/25967118219142281db52a16299c4a6c5795ff28)) - - - -## [4.0.17](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.16...@blockly/workspace-content-highlight@4.0.17) (2024-05-16) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.16](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.15...@blockly/workspace-content-highlight@4.0.16) (2024-05-09) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.15](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.14...@blockly/workspace-content-highlight@4.0.15) (2024-04-25) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.14](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.13...@blockly/workspace-content-highlight@4.0.14) (2024-04-04) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.13](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.12...@blockly/workspace-content-highlight@4.0.13) (2024-03-28) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.12](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.11...@blockly/workspace-content-highlight@4.0.12) (2024-02-08) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.11](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.10...@blockly/workspace-content-highlight@4.0.11) (2023-12-14) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.10](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.9...@blockly/workspace-content-highlight@4.0.10) (2023-12-07) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.9](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.8...@blockly/workspace-content-highlight@4.0.9) (2023-11-23) - - -### Bug Fixes - -* enables strict mode for content-highlight ([#2076](https://github.com/google/blockly-samples/issues/2076)) ([cc4e02e](https://github.com/google/blockly-samples/commit/cc4e02e1962c8ee6b7f40c2bfd55f090ccb754ae)) - - - -## [4.0.8](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.7...@blockly/workspace-content-highlight@4.0.8) (2023-11-09) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.6...@blockly/workspace-content-highlight@4.0.7) (2023-11-02) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.5...@blockly/workspace-content-highlight@4.0.6) (2023-10-30) - - -### Bug Fixes - -* [#1898](https://github.com/google/blockly-samples/issues/1898) publish types for content-highlight ([#1949](https://github.com/google/blockly-samples/issues/1949)) ([b049389](https://github.com/google/blockly-samples/commit/b049389a35a80979776207a5d967ab6eb49327e3)) -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.4...@blockly/workspace-content-highlight@4.0.5) (2023-09-21) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.3...@blockly/workspace-content-highlight@4.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.2...@blockly/workspace-content-highlight@4.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.1...@blockly/workspace-content-highlight@4.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@4.0.0...@blockly/workspace-content-highlight@4.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@3.0.1...@blockly/workspace-content-highlight@4.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@3.0.0...@blockly/workspace-content-highlight@3.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.17...@blockly/workspace-content-highlight@3.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [2.0.17](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.16...@blockly/workspace-content-highlight@2.0.17) (2023-06-22) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.16](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.15...@blockly/workspace-content-highlight@2.0.16) (2023-05-18) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.15](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.14...@blockly/workspace-content-highlight@2.0.15) (2023-05-11) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.14](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.13...@blockly/workspace-content-highlight@2.0.14) (2023-05-04) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.13](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.12...@blockly/workspace-content-highlight@2.0.13) (2023-04-27) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.12](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.11...@blockly/workspace-content-highlight@2.0.12) (2023-03-23) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.11](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.10...@blockly/workspace-content-highlight@2.0.11) (2023-03-09) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.10](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.9...@blockly/workspace-content-highlight@2.0.10) (2023-03-02) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.9](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.8...@blockly/workspace-content-highlight@2.0.9) (2023-02-23) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.8](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.7...@blockly/workspace-content-highlight@2.0.8) (2023-02-23) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.7](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.6...@blockly/workspace-content-highlight@2.0.7) (2023-02-16) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.6](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.5...@blockly/workspace-content-highlight@2.0.6) (2023-02-09) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.5](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.4...@blockly/workspace-content-highlight@2.0.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.4](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.3...@blockly/workspace-content-highlight@2.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.3](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.2...@blockly/workspace-content-highlight@2.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.1...@blockly/workspace-content-highlight@2.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@2.0.0...@blockly/workspace-content-highlight@2.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/workspace-content-highlight@1.0.31...@blockly/workspace-content-highlight@2.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) -* resizing the content highlight when it's a block change event ([#1288](https://github.com/google/blockly-samples/issues/1288)) ([5ea46b4](https://github.com/google/blockly-samples/commit/5ea46b46f7ceeb7efdfe8817d11c397442913389)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 1.0.31 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 1.0.30 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 1.0.28 (2022-07-21) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## 1.0.27 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 1.0.26 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 1.0.25 (2022-06-21) - -**Note:** Version bump only for package @blockly/workspace-content-highlight - - - - - -## 1.0.24 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 1.0.23 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/content-highlight/README.md b/plugins/content-highlight/README.md deleted file mode 100644 index 7fe317cda..000000000 --- a/plugins/content-highlight/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# @blockly/workspace-content-highlight [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that highlights the -content on the workspace. - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/content-highlight/readme-media/content-highlight.gif) - -## Installation - -### Yarn - -``` -yarn add @blockly/workspace-content-highlight -``` - -### npm - -``` -npm install @blockly/workspace-content-highlight --save -``` - -## Usage - -```js -import * as Blockly from 'blockly'; -import {ContentHighlight} from '@blockly/workspace-content-highlight'; - -// Inject Blockly. -const workspace = Blockly.inject('blocklyDiv', { - toolbox: toolboxCategories, -}); - -// Initialize plugin. -const contentHighlight = new ContentHighlight(workspace); -contentHighlight.init(); -``` - -## API - -- `init`: Initializes the content highlight. -- `dispose`: Disposes of content highlight. - -## License - -Apache 2.0 diff --git a/plugins/content-highlight/package.json b/plugins/content-highlight/package.json deleted file mode 100644 index 27c5f3c78..000000000 --- a/plugins/content-highlight/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@blockly/workspace-content-highlight", - "version": "13.2.0", - "description": "A Blockly workspace plugin that adds a highlight around the content area.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "blockly-plugin", - "content", - "content-highlight", - "highlight", - "workspace" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/content-highlight#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/content-highlight" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/content-highlight/readme-media/content-highlight.gif b/plugins/content-highlight/readme-media/content-highlight.gif deleted file mode 100644 index 61c82cd47f2cb21b08772537e067579e6e0b4353..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 962210 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≠k3$`7;BXYS6T1y2ZI;EL;yqWq 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
|ssZ1;w!#n}jDMpO29 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⪚6lrlA|rj~5?w9c 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

    _VMC(qs%%i`sy4y@nTi~iVMq+KE-@T=hZ37- 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 Qm;jgnm;ji-e@@`P06hBotpET3 diff --git a/plugins/content-highlight/src/index.ts b/plugins/content-highlight/src/index.ts deleted file mode 100644 index 3fd6551d4..000000000 --- a/plugins/content-highlight/src/index.ts +++ /dev/null @@ -1,302 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A plugin that highlights the content on the workspace. - */ - -import * as Blockly from 'blockly/core'; - -/** - * List of events that cause a change in content area size. - */ -const contentChangeEvents: string[] = [ - Blockly.Events.VIEWPORT_CHANGE, - Blockly.Events.BLOCK_CREATE, - Blockly.Events.BLOCK_MOVE, - Blockly.Events.BLOCK_DELETE, - Blockly.Events.COMMENT_MOVE, - Blockly.Events.COMMENT_RESIZE, - Blockly.Events.COMMENT_CREATE, - Blockly.Events.COMMENT_DELETE, -]; - -/** - * The default padding to use for the content highlight in workspace units. - */ -const defaultPadding = 10; - -/** - * Length of opacity change transition in seconds. - */ -const animationTime = 0.25; - -/** - * A plugin that highlights the area where content exists on the workspace. - */ -export class ContentHighlight { - /** - * The width of the highlight rectangle in workspace units. - */ - private width = 0; - - /** - * The height of the highlight rectangle in workspace units. - */ - private height = 0; - - /** - * The top offset of the highlight rectangle in pixels. - */ - private top = 0; - - /** - * The left offset of the highlight rectangle in pixels. - */ - private left = 0; - - /** - * The last scale value applied on the content highlight. - */ - private lastScale = 1; - - /** - * The cached content metrics for the workspace in workspace units. - */ - private cachedContentMetrics?: Blockly.MetricsManager.ContainerRegion; - - /** - * The padding to use around the content area. - */ - private padding = defaultPadding; - - private svgGroup?: SVGGElement; - private rect?: SVGRectElement; - private background?: SVGRectElement; - private onChangeWrapper?: (event: Blockly.Events.Abstract) => void; - - /** - * Constructor for the content highlight plugin. - * - * @param workspace The workspace that the plugin will be added to. - */ - constructor(protected workspace: Blockly.WorkspaceSvg) {} - - /** - * Initializes the plugin. - * - * @param padding The padding to use for the content area highlight - * rectangle, in workspace units. - */ - init(padding?: number) { - this.padding = padding || defaultPadding; - - /** @type {SVGElement} */ - this.svgGroup = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - {class: 'contentAreaHighlight'}, - null, - ); - - const rnd = String(Math.random()).substring(2); - const mask = Blockly.utils.dom.createSvgElement( - new Blockly.utils.Svg('mask'), - { - id: 'contentAreaHighlightMask' + rnd, - }, - this.svgGroup, - ); - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - x: 0, - y: 0, - width: '100%', - height: '100%', - fill: 'white', - }, - mask, - ); - this.rect = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - x: 0, - y: 0, - rx: Blockly.bubbles.Bubble.BORDER_WIDTH, - ry: Blockly.bubbles.Bubble.BORDER_WIDTH, - fill: 'black', - }, - mask, - ); - this.background = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.RECT, - { - x: 0, - y: 0, - width: '100%', - height: '100%', - mask: `url(#contentAreaHighlightMask${rnd})`, - }, - this.svgGroup, - ); - - this.applyColor(); - const metricsManager = this.workspace.getMetricsManager(); - this.cachedContentMetrics = metricsManager.getContentMetrics(true); - this.resize(this.cachedContentMetrics); - const absoluteMetrics = metricsManager.getAbsoluteMetrics(); - this.position(this.cachedContentMetrics, absoluteMetrics); - - // Apply transition animation for opacity changes. - this.svgGroup.style.transition = `opacity ${animationTime}s`; - - const parentSvg = this.workspace.getParentSvg(); - if (parentSvg.firstChild) { - parentSvg.insertBefore(this.svgGroup, parentSvg.firstChild); - } else { - parentSvg.appendChild(this.svgGroup); - } - - this.onChangeWrapper = this.onChange.bind(this); - this.workspace.addChangeListener(this.onChangeWrapper); - } - - /** - * Disposes of content highlight. - * Unlinks from all DOM elements and remove all event listeners - * to prevent memory leaks. - */ - dispose() { - if (this.svgGroup) { - Blockly.utils.dom.removeNode(this.svgGroup); - } - if (this.onChangeWrapper) { - this.workspace.removeChangeListener(this.onChangeWrapper); - } - } - - /** - * Handles events triggered on the workspace. - * - * @param event The event. - */ - private onChange(event: Blockly.Events.Abstract) { - if (event.type === Blockly.Events.THEME_CHANGE) { - this.applyColor(); - } else if (contentChangeEvents.indexOf(event.type) !== -1) { - const metricsManager = this.workspace.getMetricsManager(); - if (event.type !== Blockly.Events.VIEWPORT_CHANGE) { - // The content metrics change when it's not a viewport change event. - this.cachedContentMetrics = metricsManager.getContentMetrics(true); - this.resize(this.cachedContentMetrics); - } - const absoluteMetrics = metricsManager.getAbsoluteMetrics(); - if (this.cachedContentMetrics) { - this.position(this.cachedContentMetrics, absoluteMetrics); - } - } else if (event.type === Blockly.Events.BLOCK_DRAG) { - this.handleDragEvent(event as Blockly.Events.BlockDrag); - } else if (event.type === Blockly.Events.COMMENT_DRAG) { - this.handleDragEvent(event as Blockly.Events.CommentDrag); - } else if (event.type === Blockly.Events.BLOCK_CHANGE) { - // Resizes the content highlight when it is a block change event - const metricsManager = this.workspace.getMetricsManager(); - this.cachedContentMetrics = metricsManager.getContentMetrics(true); - this.resize(this.cachedContentMetrics); - } - } - - /** - * Changes opacity of the highlight based on what kind of block drag event - * is passed. - * - * @param event The BlockDrag event. - */ - private handleDragEvent( - event: Blockly.Events.BlockDrag | Blockly.Events.CommentDrag, - ) { - const opacity = event.isStart ? '0' : '1'; - this.svgGroup?.setAttribute('opacity', opacity); - } - - /** - * Applies the color fill for the highlight based on the current theme. - */ - private applyColor() { - const theme = this.workspace.getTheme(); - const bgColor = - theme.getComponentStyle('workspaceBackgroundColour') || '#ffffff'; - - const colorDarkened = Blockly.utils.colour.blend('#000', bgColor, 0.1); - const colorLightened = Blockly.utils.colour.blend('#fff', bgColor, 0.1); - const color = - bgColor === '#ffffff' || bgColor === '#fff' - ? colorDarkened - : colorLightened; - if (!color) return; - this.background?.setAttribute('fill', color); - } - - /** - * Resizes the content highlight. - * - * @param contentMetrics The content metrics for the workspace in workspace - * coordinates. - */ - private resize(contentMetrics: Blockly.MetricsManager.ContainerRegion) { - const width = contentMetrics.width - ? contentMetrics.width + 2 * this.padding - : 0; - const height = contentMetrics.height - ? contentMetrics.height + 2 * this.padding - : 0; - if (width !== this.width) { - this.width = width; - this.rect?.setAttribute('width', `${width}`); - } - if (height !== this.height) { - this.height = height; - this.rect?.setAttribute('height', `${height}`); - } - } - - /** - * Positions the highlight on the workspace based on the workspace metrics. - * - * @param contentMetrics The content metrics for the workspace in workspace - * coordinates. - * @param absoluteMetrics The absolute metrics for the workspace. - */ - private position( - contentMetrics: Blockly.MetricsManager.ContainerRegion, - absoluteMetrics: Blockly.MetricsManager.AbsoluteMetrics, - ) { - // Compute top/left manually to avoid unnecessary extra computation. - const viewTop = -this.workspace.scrollY; - const viewLeft = -this.workspace.scrollX; - const scale = this.workspace.scale; - const top = - absoluteMetrics.top + - contentMetrics.top * scale - - viewTop - - this.padding * scale; - const left = - absoluteMetrics.left + - contentMetrics.left * scale - - viewLeft - - this.padding * scale; - - if (top !== this.top || left !== this.left || this.lastScale !== scale) { - this.top = top; - this.left = left; - this.lastScale = scale; - this.rect?.setAttribute( - 'transform', - `translate(${left}, ${top}) scale(${scale})`, - ); - } - } -} diff --git a/plugins/content-highlight/test/index.html b/plugins/content-highlight/test/index.html deleted file mode 100644 index dc96c578f..000000000 --- a/plugins/content-highlight/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Plugin Test - - - - -

    - - - diff --git a/plugins/content-highlight/test/index.js b/plugins/content-highlight/test/index.js deleted file mode 100644 index fdf5b888e..000000000 --- a/plugins/content-highlight/test/index.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Content highlight test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import {ContentHighlight} from '../src/index'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - - const contentHighlight = new ContentHighlight(workspace); - contentHighlight.init(); - - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - grid: { - spacing: 25, - length: 3, - colour: '#ccc', - snap: true, - }, - zoom: { - controls: true, - }, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/content-highlight/tsconfig.json b/plugins/content-highlight/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/content-highlight/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/continuous-toolbox/CHANGELOG.md b/plugins/continuous-toolbox/CHANGELOG.md deleted file mode 100644 index 4ba956c9d..000000000 --- a/plugins/continuous-toolbox/CHANGELOG.md +++ /dev/null @@ -1,704 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Fix keyboard navigation for the continuous toolbox ([#2690](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2690)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [7.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/continuous-toolbox@7.0.8...@blockly/continuous-toolbox@7.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [7.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/continuous-toolbox@7.0.7...@blockly/continuous-toolbox@7.0.8) (2026-01-15) - - -### Bug Fixes - -* Remove unsafe cast in ContinuousFlyout ([#2671](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2671)) ([5d84f65](https://github.com/RaspberryPiFoundation/blockly-samples/commit/5d84f65d6689d3c73839f4e0b012f2547bb22d47)) - - - -## [7.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/continuous-toolbox@7.0.6...@blockly/continuous-toolbox@7.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [7.0.6](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@7.0.5...@blockly/continuous-toolbox@7.0.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [7.0.5](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@7.0.4...@blockly/continuous-toolbox@7.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [7.0.4](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@7.0.3...@blockly/continuous-toolbox@7.0.4) (2025-12-19) - - -### Bug Fixes - -* In continuous toolbox plugin, replace blocklyTreeLabel with blocklyToolboxCategoryLabel ([#2633](https://github.com/google/blockly-samples/issues/2633)) ([9ac3c28](https://github.com/google/blockly-samples/commit/9ac3c284b03955587ca9f573c52ebcf99f6c00e2)) - - - -## [7.0.3](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@7.0.2...@blockly/continuous-toolbox@7.0.3) (2025-10-02) - - -### Bug Fixes - -* use type-only export for LabelFlyoutItem to fix build error ([#2607](https://github.com/google/blockly-samples/issues/2607)) ([cd10c49](https://github.com/google/blockly-samples/commit/cd10c4957363e39363297acb8d3a0ee595a78e29)) - - - -## [7.0.2](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@7.0.1...@blockly/continuous-toolbox@7.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [7.0.1](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@7.0.0...@blockly/continuous-toolbox@7.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [7.0.0](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.16...@blockly/continuous-toolbox@7.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [6.0.16](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.15...@blockly/continuous-toolbox@6.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.15](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.14...@blockly/continuous-toolbox@6.0.15) (2025-05-15) - - -### Bug Fixes - -* Don't pin continuous-toolbox to Blockly v12.0.0-beta.0. ([#2532](https://github.com/google/blockly-samples/issues/2532)) ([9f49e28](https://github.com/google/blockly-samples/commit/9f49e2811a8c078a6377c4b38025c2cf5d04e744)) -* Fix scrolling and API issues with the continuous toolbox plugin. ([#2485](https://github.com/google/blockly-samples/issues/2485)) ([7476290](https://github.com/google/blockly-samples/commit/7476290ff118105c2b6fa39c747b0871cf5ea411)) - - - - - -## [6.0.14](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.13...@blockly/continuous-toolbox@6.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.13](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.12...@blockly/continuous-toolbox@6.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.12](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.11...@blockly/continuous-toolbox@6.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.11](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.10...@blockly/continuous-toolbox@6.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.10](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.9...@blockly/continuous-toolbox@6.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [6.0.9](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.8...@blockly/continuous-toolbox@6.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.7...@blockly/continuous-toolbox@6.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.6...@blockly/continuous-toolbox@6.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.5...@blockly/continuous-toolbox@6.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.4...@blockly/continuous-toolbox@6.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.3...@blockly/continuous-toolbox@6.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.2...@blockly/continuous-toolbox@6.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.1...@blockly/continuous-toolbox@6.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@6.0.0...@blockly/continuous-toolbox@6.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.19...@blockly/continuous-toolbox@6.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) - - - -## [5.0.19](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.18...@blockly/continuous-toolbox@5.0.19) (2024-05-16) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.18](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.17...@blockly/continuous-toolbox@5.0.18) (2024-05-09) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.16...@blockly/continuous-toolbox@5.0.17) (2024-05-02) - - -### Bug Fixes - -* only select the first category when the flyout is shown when there is no selection ([#2337](https://github.com/google/blockly-samples/issues/2337)) ([fe779cb](https://github.com/google/blockly-samples/commit/fe779cba6318ae95861f6d932b20666ec22cdccb)) - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.15...@blockly/continuous-toolbox@5.0.16) (2024-04-25) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.14...@blockly/continuous-toolbox@5.0.15) (2024-04-04) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.13...@blockly/continuous-toolbox@5.0.14) (2024-03-28) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.12...@blockly/continuous-toolbox@5.0.13) (2024-02-29) - - -### Bug Fixes - -* Include padding above category labels when jumping to a category. ([#2218](https://github.com/google/blockly-samples/issues/2218)) ([bd3cba1](https://github.com/google/blockly-samples/commit/bd3cba121c33e6a5dc3b1d11d432f5af5f169074)) - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.11...@blockly/continuous-toolbox@5.0.12) (2024-02-08) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.10...@blockly/continuous-toolbox@5.0.11) (2024-01-25) - - -### Bug Fixes - -* Use the referencesVariables() method to identify variable-related fields instead of checking their type. ([#2161](https://github.com/google/blockly-samples/issues/2161)) ([09b650a](https://github.com/google/blockly-samples/commit/09b650aa269ebbf170a3297214fc197b647b2e33)) - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.9...@blockly/continuous-toolbox@5.0.10) (2023-12-14) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.8...@blockly/continuous-toolbox@5.0.9) (2023-12-07) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.7...@blockly/continuous-toolbox@5.0.8) (2023-11-09) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.6...@blockly/continuous-toolbox@5.0.7) (2023-11-02) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.5...@blockly/continuous-toolbox@5.0.6) (2023-10-30) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.4...@blockly/continuous-toolbox@5.0.5) (2023-10-19) - - -### Bug Fixes - -* fix continuous toolbox not enabling blocks ([#2016](https://github.com/google/blockly-samples/issues/2016)) ([4d8aaf2](https://github.com/google/blockly-samples/commit/4d8aaf2fbcd00bd36fdb5394db17c93efb167c12)) - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.3...@blockly/continuous-toolbox@5.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.2...@blockly/continuous-toolbox@5.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.1...@blockly/continuous-toolbox@5.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@5.0.0...@blockly/continuous-toolbox@5.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@4.0.1...@blockly/continuous-toolbox@5.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@4.0.0...@blockly/continuous-toolbox@4.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.17...@blockly/continuous-toolbox@4.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - -### Bug Fixes - -* continuous flyout calling wrong private method ([#1725](https://github.com/google/blockly-samples/issues/1725)) ([1fbf9ff](https://github.com/google/blockly-samples/commit/1fbf9ff4644c8dbe0a0b9f98109b824f37574e12)) - - - -## [3.0.17](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.16...@blockly/continuous-toolbox@3.0.17) (2023-06-22) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.16](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.15...@blockly/continuous-toolbox@3.0.16) (2023-05-18) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.15](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.14...@blockly/continuous-toolbox@3.0.15) (2023-05-11) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.14](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.13...@blockly/continuous-toolbox@3.0.14) (2023-05-04) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.13](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.12...@blockly/continuous-toolbox@3.0.13) (2023-04-27) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.12](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.11...@blockly/continuous-toolbox@3.0.12) (2023-03-23) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.11](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.10...@blockly/continuous-toolbox@3.0.11) (2023-03-09) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.10](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.9...@blockly/continuous-toolbox@3.0.10) (2023-03-02) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.9](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.8...@blockly/continuous-toolbox@3.0.9) (2023-02-23) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.8](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.7...@blockly/continuous-toolbox@3.0.8) (2023-02-23) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.6...@blockly/continuous-toolbox@3.0.7) (2023-02-16) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.5...@blockly/continuous-toolbox@3.0.6) (2023-02-09) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.4...@blockly/continuous-toolbox@3.0.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.3...@blockly/continuous-toolbox@3.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.2...@blockly/continuous-toolbox@3.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.1...@blockly/continuous-toolbox@3.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@3.0.0...@blockly/continuous-toolbox@3.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/continuous-toolbox@2.0.40...@blockly/continuous-toolbox@3.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 2.0.40 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 2.0.39 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 2.0.37 (2022-07-21) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## 2.0.36 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 2.0.35 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 2.0.34 (2022-06-21) - -**Note:** Version bump only for package @blockly/continuous-toolbox - - - - - -## 2.0.33 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 2.0.32 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/continuous-toolbox/GETSTARTED.md b/plugins/continuous-toolbox/GETSTARTED.md deleted file mode 100644 index 5a69fc1d5..000000000 --- a/plugins/continuous-toolbox/GETSTARTED.md +++ /dev/null @@ -1,22 +0,0 @@ -## Available Scripts - -In this directory, you can run: - -### `npm start` - -Runs the package in development mode. - -Open [http://localhost:3000/test](http://localhost:3000/test) to view the test -playground in the browser. The page will reload if you make edits. - -### `npm run build` - -Builds the package into the `dist` directory. - -### `npm run lint` - -Runs eslint on the `src` and `test` directories. - -### `npm run clean` - -Deletes the `dist` and `build` directories if they exist. diff --git a/plugins/continuous-toolbox/README.md b/plugins/continuous-toolbox/README.md deleted file mode 100644 index 65d6e9126..000000000 --- a/plugins/continuous-toolbox/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# @blockly/continuous-toolbox [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that creates a continuous-scrolling style toolbox/flyout that is always open. All of the blocks from all categories are in the flyout together, and the user can either click a category name in the toolbox or scroll to the category they're looking for. This flyout only works as a vertical flyout and it works in both left-to-right and right-to-left modes. Parts of the toolbox style have been changed already, but you can customize the style further by following the [toolbox documentation](https://developers.google.com/blockly/guides/configure/web/toolbox). - -![Screenshot of continuous toolbox showing multiple categories of blocks in the flyout at once](https://github.com/RaspberryPiFoundation/blockly-samples/blob/master/plugins/continuous-toolbox/screenshot.png?raw=true) -The continuous toolbox is shown here with the 'Zelos' theme, and the style can be further customized. - -## Installation - -### Yarn - -``` -yarn add @blockly/continuous-toolbox -``` - -### npm - -``` -npm install @blockly/continuous-toolbox --save -``` - -## Usage - -Import and call the `registerContinuousToolbox()` function before injecting -Blockly. This style of flyout works best with a toolbox definition that does -not use collapsible categories. - -Note that this plugin uses APIs introduced in the `v12` release of Blockly, so -you will need to use at least this version or higher. - -```js -import * as Blockly from 'blockly'; -import {registerContinuousToolbox} from '@blockly/continuous-toolbox'; - -// Inject Blockly. -registerContinuousToolbox(); -const workspace = Blockly.inject('blocklyDiv', { - toolbox: toolboxCategories, - plugins: { - flyoutsVerticalToolbox: 'ContinuousFlyout', - metricsManager: 'ContinuousMetrics', - toolbox: 'ContinuousToolbox', - }, - // ... your other options here ... -}); -``` - -## Block Recycling - -As a performance optimization, by default the continuous toolbox "recycles" -blocks to avoid having to create DOM elements for potentially hundreds of blocks -every time the flyout is shown. With the default set of blocks, this drops the -time to show the flyout from roughly 35ms to 25ms; the effect is naturally -larger with larger block sets. - -Recycling is unrelated to Blockly's Trash feature; instead, it entails moving -the blocks offscreen when the flyout is hidden, and then simply repositioning -them when the flyout is shown again. Not all block types are amenable to this; -in particular, blocks with dynamic behavior (e.g. those that reference -variables, support mutations, or have dynamic dropdown fields) are excluded by -default. - -This feature can be toggled by calling `setRecyclingEnabled()` on an instance of -`ContinuousFlyout`, and the default ruleset for determining which blocks are -safe for recycling can be replaced with a custom callback by passing that -function to `setBlockIsRecyclable()`. - -## License - -Apache 2.0 diff --git a/plugins/continuous-toolbox/package.json b/plugins/continuous-toolbox/package.json deleted file mode 100644 index 3e6283184..000000000 --- a/plugins/continuous-toolbox/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "@blockly/continuous-toolbox", - "version": "13.2.0", - "description": "A Blockly plugin that adds a continous-scrolling style toolbox and flyout", - "scripts": { - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "audit:fix": "blockly-scripts auditFix", - "predeploy": "npm run build && blockly-scripts predeploy" - }, - "main": "./dist/index.js", - "module": "./src/index.js", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "blockly-plugin", - "continuous-toolbox" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/continuous-toolbox#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/continuous-toolbox" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/continuous-toolbox/screenshot.png b/plugins/continuous-toolbox/screenshot.png deleted file mode 100644 index 368bb29aad5a1726b7d6e1b81fe07e1719993c21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187895 zcmaG|1wfohmc|kqw-AE626t^VxCVFE;O-XO-5r7icemgU!QI{6;W{&unZ4b;gQmN> zs$SLq%AS2iu&lHQ0xT9R7#J9Wn5fWaFfb@zFfhnLz*|tx9>@767#M7esi2^&n4lnm ztgV%isktE-m}qc(0<=Qx!27=4$Di0V_LSLd{I2n+u6sZE6$DU4DHuqg&?||l8r};D z@oCD*33Vz`>In)}Rsbk`9r)kBanPg=f*pMH7Mb%nZMhw7-W_IZw`=EeI!R};8^s5M z)q#a7s(=SGeS+65jO3!>BufZ*#Le=dCIExe888Tjx{8Vd^PW3;a(aA1=99nlm@LwG zeR*w9p-v^%0|)abNb7iC`4br!8J0-xLk|h2fVnZN8cmqALFTvZFX{u}P1?xA#7o)m z!^}vEfI+$j0}HqJCud6jK?2rq7L=JVATDqbg+XLKYJ7PIkeNRGvB5YG$P{q)R9m>9 zJoz+7zfR{8^OC^C9}_zu8FMB{HyLod6%180toXWX^JFCS66NK3bx zS_6-2{-fL;f2Lu+wWYR=xL^0!Ha*FGb;G(`b=p8Ee2Sr*c+#szSYS8ZyFl@S-7}A+ z-J9!#s|>OSiFWP)1BJP56FRW0eJC#uhQa&SN`{lne&{#q#78A|k7P|m z&-P?9+)-EGGfUV>kQg15j%xTvwoY0hf9@W;{~6teJ40Z#F`7o_$pq#g3?{oec7G)c z)=zM|mJ>z#-e~l0Tpk~u0K$|2Nx}Q=ICy}lVM51yc5t?}H&1-@0B8msN*zL$0&qeV z@T$(YQE(TXv=ta}-hyiYc5vyh)meBN5VIXp))@BQmS<2`KKy5I!@S3IaC`}HgnSC4 zVDn)1`N^V44Uii7v}D2F!S?W-%c6D%cFVHXzzhb$W})uUE5JNMXnL3N*Jn%bp-dqm z2;yg1(ZiB;T~u(EAkldr>vA3;1$IfSk+9>A`r57GS~F-MX8InkeL2%?z&`o9+L24) zO_cpkPK`o7j%N@OJuKuCX^vlEZ6UV;%6A;aa5JIWoRi!KSt~j12^D5^DZ$j7^zpVm z05e>AgjVQE1TB9i-)y$}`0d2=9?BIG{F~eWhE8_94@oAHs77zdFy#G;I;Qk2b($Ey zCXK03E1`VxuI+lz)2|qqo1QzKgPg-MN2^2Q^2Y61x29r8OJkz_(ARCaW^40kQ(&!Z zquIc}gux9{9$eq;wyA&a{v_;<@^z)PLUmL9Z4_x zfqW1ZA!xMQT945NvNB0Us)gTO{7IB3x<(8!?-L20DNj+7eSm%Fl+1&80x@lZ&{MQP_MZF_MP(fPAfhtLhB{x2$a+ zY_)978*v(mZD+UN7E*jioc=nPW0`~ZZ6ynFP=6a?3-e;&;{KvwdvROj-PXGjbRu*m zsyHeQr9F8e%7c%L@8r>)s4^7Y3-6@FG=s~!uxl|D)N z=Wl$A$*EHRrnQ|+r8ceN5PbkU{q;MW!s=*j<}Pz23!T-q*fWim8Sih7z%9`-v^n_hwqt?o#qu6Q)HqdTMYMLK0F# z$`U0GD#e;#G#2@|1l)2R!*7^yb0S)$bELDSt4D*%@-4G0>n!6>^m%+UTJe;vGPR0V zlG=Pc<6hoByFL>_8bSu}C-BF2$_s{M7wb0ZHm*YwmqfS9g-n3wBI?i0^(KAMFmoS+ zVy$FZPsX9&Pm4@GrO)JTclV5>oR70iF;z2Mu*x@iuTwWsvU0QxvHYeI&XLYU^Q>#B zmwWoD@E#401CBQ|{C)U)eClu-)r4;eNF@|XD@unYSS2g!sVa6QNNTqWvK9~)b#u&% z?)A0R=nG1Vh>QCRJ&W=4*K%?c3fq)=nzB)&uLsxuyC6o2q@h>5}Q6)1)~O zXqZ*{Rh{kEy{qe(ChsfkGT}x@SGJ84fyy+>`Cl3j;n;B5>eT%gKQ^K8BzuOuj4m%} z?r9wYch>hRdvgcSw)Z!acjr$?chT1sH?Eh|7r6$S2i>~+dW~ykV(EHkSDosukOb2^ z^%NL|pN^hp?rQI1pSzwUp0uGpKm#DLAlLcYJ9vC#zFzs>@n3fmB%!pB->C-ii@Nsr ze46`27%Gm@3SSEtL9{@~4WNPJ!o1;F;&C^=iv@H6Y=rFc>k zSSFnG74)4M5Goty`sYICCVI3&Z)x$us)L8Z-5R=e1_nv%6Tj0+X}Y>3Uoq}f*_|id z72d_3qYdjAao92YM9U`7|G3aO)^F8qu7sQK!ZDTx-&M@9)8pTejj{Wgk*8bsu|DWA zVYl<+daKNh6fllE0X5B*+mMlks+J5P^L?hH4_%+kdOh{5N}H`qL5EP($2|!r$<@k zy=8qgFB^;>MBlkFw^^_?`RMx5>dPZ*vBhKkbHD!X@&MZy-C*Y2=z`}id1z*cSISa! zL#{``@#xp)isrj!yc5S|j~u=_f?^#VnYD~20X1E%^@7%+n-$tBTF#ot2AP)fa`vnS z-S(3g%|~+a2GZqkC*N2M%?uX@dl4&;>~Zb6R6InVWnZ$bcrQIqc#iBE$~4+r_5e4c zJJE?E#F2G))x1io*=o_+=g;h~&a1)WXf*MT@$ux-(kCUp#odZs1sl>1X*b-`UKO{~h6i z-i1&jj7aUDO$x56>ldRRyFYR$la(83;##0Gx3(tOTV%PYUdA3y%;MKjo0+z+du`50 zouxPC#p1-_#Nxtm)Y`W_ zZgO0`d>MfbgLZ2E+Qfw~%zbnme7JvTc#Fs*?s4^Ev$J_leweA3vBMMVqI9Kk>~e1< z+&+CZf1`PFdt~K?a# z?z|8_ip+C$IqkmMKUQ0ixEh?bo;_~`9^)$l@m>v{i(HruuI_hh#y0g`v=!RY?#y0m zuhpmOl{Y_DuZ?>!<}1SF!J6zx1X8xD?}<7dxfX)pg1wkM!?-Nn7JV-<}0&YPW-kc?Pne$ zsSq-9UZN(HK$GNCp4iyU>)6=Uk5PK~kmFY_!d)`SE-YZf2b8Y%C0}^%Fdm_60uT?F zbi6@IE0~_4ikOj<6c`mK4FH1xM+JifrNBYIV1cG!P=BPsz{o(KAPqPs01O)Ri3<9Y z&4Tz{3gw#x`8y3c_^Tqnyr7sE=u=+b*3i(>&cw=o0X!ie3=9Hjs-R-8A|=VGZ)HKN zYha~kNb782{fh*Q+nE!Tv@o>SC2+Pdx3uGQ<{|o{1}7-}E1Qmp;EyWyUwDXAq+|&M zt!xbmSZJAP>4|`_1Ox=!wgyI=pM`|~A_slrAu_SIx8|gyb8>Q`bz-8mvNfh-;Nak( zqi3XJWTXMrps{nYwAXc}v9u%pvytEJ2pQVx+nQS2n_5{C{AyQM&&t7`hluD`M}PnP z`J9H%rvLP0Y4;afAO`7vmC!NJ($oDnGJ8{_|AXvT$)99@@bzbR+`k&*RJ1d+6|}Oj zFtoG>{xi7TfAsXf3jcY|KM7?`oej-ZgiJw{b|9XB3=AyHf06xr(SIdX{fCr;js9OL z|E1(#D1Y(5DPwC2dQjb8g9v2cru&b)zv^?-{Tkta8Sy`-^N(E6d;(#)>Hc0DKv*_` z24OHTJ}@yMeg$XnqjYF@oSyraRmIcg)`8YFRC9sTUgQ`ZSAo-XFhU&yKJPO)nlq$n zF>AmFR969p>{P7pK47dTb>^yNRU|_P&o8G;yFBR!>3ONugO?A)r^_ctEljKP>B}yb zA$A+Vgm}Qmyn=#UFmSB zMEUV!^@09S0?lVRIo;{Le5usD@81W%BOPZrel`w8rHXy?t5)};$^5Rck)~~>AI+TECQGIZ5WyPafug4m7JF-@1 z>#)o^+X*6B?oL7VpgttDN zut0Hf@nNQAVLCx>wwY3O;|m|op#Y?o$h9T`;2IqZ3(Hms0mS-?H}(FL4^m5eb{lN14+<31T}NvmUP(6V5=I%)6k*|_phaN;tJRA6h0m=Z zHc+-;6VuI8}QgWQznDh83Y{=^ZgwYK!jYHRSQ`A7TYrR3_14e2P8Q=Pxc=dK zkomaCnLj3?60)iV%loCYpMerYX9*<`Oag!>HGkfgk_E;GKnAtyn=vY!>!w3UI+r>u z-o0RN<3JklH$vwh*|C)Gstxx%d~eCri4cAw;G2NWyU#T76qrABl;1Vvo6j_#`3R?t z+{#{w^KEwLBVCDCOgwhCBFXOh#+Sb3dg_2K`>2lKc*m!?ePht&gdK28HKokz+R(87 zNk;Mt_~Ti3=*K!_YyO$BgfkfS)r&y#+}`>|m6O};!b3KMr|e3Di1`Db71NZwrs-m{ zp+VLe*DB^CM_mfWONORo0$6oa%|e*hScY@ z$J%!^UQ#ojH#Hje=RJ(O3tt?SKbJbKlt2NCT9WA|g(&vi5xh`$&Cv2$bu z5iuHf(wWp_jcxSO{`8$=!$2xlj<-=0l`)_`)h{FmA?9+Xbc6CvdI#uS9)`)3zkJ4u zXls&$@I5T{uT$O?4;+@Cr+hd`?{{zDbl|v{Mpgpjbp(P?oY!G?BsK^4jQ2J7;GYP( zA+t>`Ol9^sFp}(0pu>MlioZq7p9unIh|!&qRGuUo&NRoVu?RNb(LzDG)40VnB>d=$ z9va2-|%njLCR5L_trrSaKS7(AIO{Vb1dotHweC~}v{h)%RyY5_K8X_5If{_IrByaaB#Qt7o zL4FRt1k@;z)144f@VJtl1c=@K?52MS=s(5uzr6dv2sv|SbYu&>+ek+OvPg6XQgEVS zY~=m3Jb$UXvw+tu*Ul6vIYo%0>!;v-$atr2pUZ0f80-i$h{h7y@@m z3bYXIClb;KswPjGlwCoKG35zgE%{z`lH1JwAq|r>xhNVH4INln+q~7v_AR$2hhNE} zWM3hHQJ(0VmuntLcYwn?%YvVSvH#ZB!&{#USbh(1)0tj4()XYgG z?u+N0K3LybgQDOCek(S=M{J!C865?sP5b*KJEKEYzw?c|ZWj119~rZ!rpRj&z~|r)ABM9aL)7Jb?2r8%<5Jzjl)&TjVg~3_`}kWz&s$x9f?^NC>bY96ixv;Yt)27SFAC|Ir_{`I)td#$6=` z8@AEj-HDPS|LcF*6%Q0X6=hhCTe{Gq6Bn}r0a$-DGabK;ioaNe0T3d*ZvKRh$zL%rqw9Ng_%!nL#@74A*}riV;KqaNbd7A4X#*b zd1Y-{S84L=ZN|1&~$>3Th{;rd3ZEwo9^^nPD|AdE=(_*yUBJ-)ulj- ziAzQBSUNbwd>*@yE01Q$R3%xN*f1V}k$^}1t)Y;ZK_1(iS_eFv9Mn(T79}_dELsK~ z1~#7qLP#7l8#C3;ii_XLteZtY84@if)UYqnII&a7=HnAdyWZ~eV>n6=c8Kw+a8F(9>*wTaD}n~pR&^WiNHH31jD#P!6rYAh|yZD z!o<<4;V!x~gzqx*Ri*6yd9sWO{5n((5IX!*zQ^W}ra3)Qs4m&yh;r@L}t`s0p){juO1X3Q?T4QcI zm#N;4I5@p&_4kgu?bP&TZ;JmU6xxTDgU2stO7x)#jjcsq)n0g&dXx~mrZRQ8=rT2P z3#UaXZ67Y>)bjc#1J1xPZ<;k=OGK9mdBI zkmA)9*-iub_$`27MpLdE;i6|ctI5FArj;auTPjDsSHj?lFF5JW+x*z6zGRs}RGdno zLo$62ZVc(~Is9$g#KQQsiXiKRV=@V6JnyFvok6XG97IZ2`v{_uOMQ0=_#du3hxZd&ZdA2T3V>YVGb}4I#F)tee6)y8yOIC_>u-^?mbtfFHk^ffFP?B3vhq*HF z*@u8gA#Kqf?asU0eL)m1Ai%$a9!beUvz0D?XVn9`=`On^M-BJ{@|=5i;9b0sOBn8D z!DFWLWQA5fq~m1^zH?IjO2scN6h>l{xpTs}*Z>|V_7tfdGwks~R;l{P!qH3jAA=wd zuF4~KPQf0Ui1!syE@nsH=b_xz*a@qTQv*P-ILbG9PeXyNLCi?Q3- z;vsHyr?G1nLTg8NaE8Dr|Hq!>3JHUs_FRu%bfe(BK|-e~(4-b#R!OE~`!78y9Ox)9 zWWm*uh{|v}{azl1$=$;B@9^}fE*F8#Wlhui+3&CpYMo$)Cl|(Rlv<%1LHA=g^Dk#pTBt>w4ay#GN8PXqfCn(ScDyMjf5CGUe^s?w2d?Sm{*1D)LUufz| zj6oZ1*FJe1I<)PPk_lnDvo9(vImhh^9a-O|3dJW8^OKb;TXBgy>COB8^^KfisCPvMkWXK~0%NeSbjxtqB|qh2R!YFhMK z7Ui{4V;UQmm>9^d^$NJWxX7!j`stk#BY7XVVT33{>v_(2!{;GsjwSvG$r{URrG!v%or_1S!@C*E9#3 zsR6rhGw@kU8yZwDE*DM5{5xFan22??G9Bmq9Zc(mtq+bV3JL7RKgv7v{kpK)-Azos~aNzpA&1Hqu=+f}}WWFN+f* zi5e{Vu5Y*?w^FxIWhRO7l;#FbCA7i|Li;H&#I=r$m_U zb?muT6CNoMGz-o70{B4A*Qn|~?(kw^?$iufe98^U=fJuk;-2KEq#N5{w6PTR))#9n zi%Mr}OEAI6ELRI5;Xs}18e+Oed0W=+XJ;|6NbMfo&ccGuCw8a(czt6Gt!~IWu~y0{ z`gE=JqWS6Wt;1f|#M)F=&S$Fgk2R@=EA1<>#V0O5k9fD17Cm&+{U&y7`pB*g1#@)seRaMotWb^ zPH;P#Yc%@Qvp;@cWQF3Jp&~oAgtBD}$Lnnv_x(nn?e@Khn52E){OJocA&eK?>*H6+ z%orL)MHVB=tbO_Fk(aGJqny+m)>v^57}L|S$+i!&?pc!N!TioeiwW%`%HZDIcIv0H8{G$Qd%CycfC>@B$t|Rl>=Os9$Agn}DF68t{?X zPLMzqgb4mvyTSa0nNglo%5~iY8r7n&H&4eizfxyDyMZ(efZ3zoaBRcHItx%{5K}6f z6>A!(jUbFM{<})jx9ga2(jYrDm_OTD+hpFN>jxZv7DeU7?7VTN#S4W0@o1m^=iBk# z10pf0tAj7-O$*}*KR79AixY>3Ut-ed{k88Dp3dFt3Shw=B(?%XYMe%mH}XzOiAJCD zMIAj!eMzfom7|THAs6^Yl}^ZCcZ=no_~LvW{UK2kb0PZ+*S7wX5=4Hc-B#^Kpe@L0VmK z8m@hhi)+!1W^VDpU8txd1f#|J&YKQbOD`B0UNGz&er8t^Uun;DM=)%p4P&KSt)WtXiRla@wpV`IarAu22! za1O3rSy`#%ZeV1Dg|Dirii(D&-y_oQ`5dP57QgOb`Q`Z$8-H%0$q^d72;JV5RT2Kj>AKXD9$;2R(}75pz>AxcOoLf5nR zBSg675;-gUEz5}=^V0fIK(?nZ5`AxRKpjP7-Q2l}Dt9(}bOr zilj;7^D2ZLyRWRYx?g7492I#k^B~pHeUL4$n@VG}Wr>EAEMiK+3|w?O6B#Y1238?oSGu1t(HxM zafinTE=`fwb*nIo3x|Es9b8U`^z(xn7#(H3raf`Mev3~m62a`7T_{WRCaJD!EboTQ#Tv~=4}oQ{u+}(Kl0^?(WUCj^sPUIdb~p+TxmhKGV_BW<-g#TxamLWj zKCUw3V$!l>x!lodrLTt*K25i>CWG+7R`Em$jm*i;N5kgUUHi^CJ;}9)^SCmP735z` zcH4BZy-$x!J%!s{HV`7XBpvt4MPx%&`l1(w;$u#OZZ!xPerlNBV#{YGn|xFaJZGWo z`boMV|3yN-f!33XmXeL3yN~UqiqjIb*6rrU49~o4yekvql#=K%_nmdvdVMavxGmyN zpOoBg_9mK|TsaO0+xN~G%Ew)1yUGWZSGSXbbH?tkwYQ4`Y2#t^)$Y+NSQscoQ2@aq z3ga;dI&aMQlK$0!u*ci#Bw(LI z#a(iri@^6Z4`#B&tEeS4@Lv=GX?ZzW2NMDk1a`0F>OyfZ``_*1zK#1*y2UGVKQ z-i^IRoV(ZxYn2N|8YQjp&FxFNDZMI#7gCK;bDf5zO%`eKGfXTLD)AR(gSYDh-pp>t z*p`n+}m_p!nv7>@yk0xINkn8j%ll3Fh40y$1;lx&;8TSNr+7RZ>@Deuj5LC6dlcxbqBwEl2J9$#(;EtKKqKAQiqwv`|VHCc|r*;b+^ zaz%zxt=de}XT`|VN!ssv=t>^$S%2Js2-o-0ANYd=U|Ja(8&zxyALVRbuAxPBa zV1gb&m=*#=&7`UNg#;^wfZ9R9dijX^mSqNKmUPL!e@?dCdTV)d=M~wPsCFp5{llcu z8Y12Yj_!}l!%57aU!1Q^+uC0+DPy7!a5o#djboo4B4q|D1CL1ug3oPx!|hV3o$%r$ zg7|ZdQnF?~5nOM~-zCk?c8drFXi|?REjsA!WwMbu?9Ninp@-&4V;C)WH{={$s9t{;f@Gq-UIunStt+h%pO8?oUe zRbEedx%6b1lCMT?TXe|WUN%x$j2tT6cG}1wt9-E~;MY&WZ`)#%p^pjK@$1H}CXBGp zc!T)oXAiW`h>$n@bmqr}BeV9Z#!&qJ!_Czi;C+KLmDwd|@L>$vuAVTYZrX(Y21kF% zlm^DRt~G~Cu?5pHxW7Zbr~2r#CZ##Z&jMZa;VMk@byHFXb!=m@#SVi1O76U``brP| z-C$4k2AgXe;9gx;!JLZ)jppQyU5j51xi) zTb7hjN1e~Zd1ETzM@6$h)~?P9st-FTKXCYJIcoqvkf5^qyu2!(Gn!uC$Dt%c-5ODuhyzRQ|D4#GjvC->lhso8yR_~>?4spq?<>|i6Zaee!MJRvd zsZ>?Ct*ne+%VPrz7r0$YPT!8S1IBru11)9#vdXY^81AKIER>_#-Xd|swWD-@c4>I= zBUgEF&-~OcNKWo}mTgGciqQ@#8yb1^(`nA!2i&?3B}HqP3Nl#%y?A_k4Ks9N^AD=e z4}k`KkB?#_F&{~74|$&>&WQhGN0@_R4-}_G-(klo5E&!O+h3YAT(;vc&bp9>WV{|G z3C0dMI-8g?WZkCCUF-seKVV>Fz~}Pg6kitI$uNfF0Y4xrWe=4W2aOYk%1@N?V-K;c zWDp#uH}4k%f@x_nuBLo+74y@6s8JSKjuQ&NFj5t54{D4`9>4h-T$(z+9NA9Q?s3M! zw11gn{6c_Tk3K*-%R`dsxvR;D*ICYMRk!3ZU1YnfU*0c;#7jrFk z)60Q?j~28lHb8fT#rVFKP!i_gNr1ka7CpN!ZZ)Y;v$!7q-j01=+y<3RvZs;GL3IA@ zY`W8;T5>aC%~5*xZu9EGvL5?v2ums{|L%Qfh|b9F4FwhLq~U5V3FU+v4cn_$E)l_K zU=Xv-kxp=AsOjwL3H#oFmlUSwft_Y4(RLj>`n-Zpv5HM3vw{V~rOUUXis0bYFTLC( zAUDzd59mkTK4|E{{+HSqPhOjBj&CJ$U=;2m4)wzUSP+`lY zC&cjt70-U2YJu@Zt^k;^tpphbGEyG0H- z@OTX+>ukDuBiQBWp11Hh`39Imgy_u>$(63v&w?E&+g5<4g+snfj{zxJ< zXBeTL5J_Opw)KZh*g&In(H7xeDX~8y2XaG=oJapm)Y5x4_z=h-9^Ko2KU>?l)}youLXb z0;;&!Ptf8N0arTxvwkpW?nKC=97h#h!$qMObgX(Zy1LmKwgaR_K^TYzhK2)01qV3v zoL9vxk56`|gFxQb`!SEeNUjrhOpxgZ3d8o+N8&ee`1r;zFd2QjQjLaab#$b`UmcMM z86f@-%+Fpn)Q<&Xz~x=X%}VpW2K~gugwcm2X$_iRz7E}#a==@LLYkq00froz&!1!H zMBUw6WOOc$x1j%>jX&W;dtFdO2Z!oqYX+er8fi{dt55El=mTR^R8+&`AoDOOsjyhH z$YOcHo=7=J$U@cDwhHDn6GPIw)&1UT< zx@ajtz`|0Rn&&t0UjR@(ZJ#;@aro(4uVS9gzS2%C4Uh7^x-;F5S=28Zk=X(dORDo~ zYNn`RBD0d9O**{6ZM#uK`ngV9h?TWHYKK!;Br2#q+7TD{~0Cw`(1_jSKtu2s=u;?4PK&dv%E3g{->DmQ70qlD0p0bQ|!@6k8_l4 zoWVeZ+_vg*yKMV-T%W4g^`2Tqhb$3z+H$#d-iMFjZg(_(h^}2jn(LUk z+HGez*>>JA@t!QrvCFpE4F>)YpT@;RHgc(T9}sxEr*is?jHrF3o7mBf(gct99}#+2 zaB$h%_LAMy*B^BpG#f04b~% zDVVhH_qbF0nwgo+m49$Dt(S~&Gg$tTr~CwVne8?vDz_A{`MyxTL><|>{JMGszqf{u zrD)b7EdO#;yq^HzAmUyxL<(p^ZPxlAt}BEF)c zA}gIbniI&%tP*yatFgZ8c(&leKl6E9%J=UA!Dm2txzhT(!s24Ir+H8*pwG?`1k9_l z+m%i&G?>hn`mCmAHZ1}YRdMn0s@Kt=of97)ujEmpUN3FVn>$mc`K47_qt&(c+Rb`< zFn(sWRH;Nox3=Z{hz|&Y<9%l-o}IJTEhE|DM7e0${wPGEu@5fFYvruoi}=!s@CE zVg<|65(rw;JvM2hYbLj8)^~iw7=}K9JcB=kflnTDdZ0LsbN^Q~XNQ{ytNM;>oj-wl z{=C>FAk2}elfR1kJzq@m` zv4TKwe?a!e#>Uu)5OzqzLPOyik(h;HVPW&~@`N@vH%o`Tf`rkvswVElKv>J9q@<`_ zNDyq#fEa&ZV8F;>UY3iWxW1ubZVNP1Q^zJH#7K8tEQYzXK6~C(-jP>V_8)K8zAF~z zwX`e+B_$^(E3K3gKy*T1M90UYA8fEXyb~e_LR#~8_gj!v=8qEu4h{{H5;GA`(GFLe zj-;@V;rB}j3-5WXEz^*b_iaID+GzSO5L|5FL49mt%lr1tf5AT(+X1GVVCtOpz(GUe z%*TDLF(W1h^}?MG%C^U;Mg13qFS~6Sgy57}lMxq(t%bW>nrm^XZhSo}^WGIHL?A+j zdKbrWaOLOcC)-S~hv`QU$CKgZJQJ`G75HnyUUt~p8xb%_Y3O}M+rZWYdg18tPVTA+ zx&0_Sf_DumkEtN<00t1QCsmbnX`#3PX7HdQz> z{1BGz6dCs|0+s<5Nu4{NITojVp=p%Lc{H+>Q1yCOAhyj!2$JEObE~cXXr=B?8o4GF z{M|TAMqx$e0v^l0aDy#{g`&dYScW6eC;ZGyov_!Ig$TFU86GBk5g!g zbf^oT(pp(|L<0pq@ax>Omd^1)-hi3kS#Ne%zjp|JY;A3Ey85uueF^^eqrqGC=3{Src4nD|40b=y!+mlJZZDFIDUspM<9i zXT^e}m1@Z%^2Da=0AXGy;OUlFwW^lg{Xlzc5_!zLjX0nS8cGJ19d*T0X!D`bc|zbw2M53=9DHPI|+w4jRnLqVjSA9;Txul^?Z zmEbEU9&enF6bu88m7!6o;9Ggx^H6Pd_m6w`4ijlW6_e3&1B&Azs>|@^XkLko2+l_7 z1Mcr5`F}&M?A0NfJxu0WZW8jly-tId&K9@ zM-y!)dN77SXp?0NdJbmu`s{+=NWMKKD0b!&b#!R7f8g5S5Y1A6A5{T~8Xoa+@G^;e z)sa#CFUNFTDw*wqW|?Xfl#N_l<+r>hO7MGpKta?v0a;OcM%2H=%-%T^1=RH&k-^)) zq)XNqD&RRKn?K7Ba5cmvlZeYiF1C~w3mL)}geoAnR7;*}XHC12^?zc^WOVAU0Gu01 znV9_K=M9iwWs0=>FO-4NSGNfRKW4RV7r(p`yFtwxOa2CDjH3Z6L}X3 zAau1^;O!vd!$cEDL-_ikMtha{H%-2Z-Pk5)>4)CKN=5E&e*&n+PT2+X^FQjq^mTt6uGKRio+$x7rTK0mcz=(+P9 zk<(Pt4Z(Nm!T&FM4seLWUz|`Lm2}<(Q9#v?9Q38OSM2}fMUo(=tqo{hi0n^6LlM(I zJcZnoFERKW2AT%}8hc-51`cq1QC+Ul6MQs~?|^UlzvRo**K|ZfLxZ zJh}nk|A#BGgAn;=Q!_Jf5ixy{xg3w8T5spoA6_rXf{!v+zI`~nbP|2pck0ji6iUL= z`o-o=YSi4^oX*!e_+8VeDkLxJZ}A8;kv2%bpWd4V;wxj0(9JVd-Z>H`BT3#l1LJQk z3LF)H;X{Fo{hn4^xT0|{Cv>}q97B97Ew*{9{-((P*G>zRf;#xD=adeQV$$2tAS=|v z{*R)?x0cFw6UWc{TnA}PPw~4$ke(_H8X;l;U{}MfG|zmFaJ$_7r)ds58>v%ZaPegH znb1G||Laig=|d4=Vg2A$*avM$ii@Ydbkwh5-g&zz><=os49)*lu_PHshgiqP*hw5@ z(C_WPe05g)xvEa4c-u;mbV?pYC^_9qm-1^%?uorGb4hYVMaz%>Yah9yf^!cY9vqaA zxm@myeAdt~|5NXZi&ObS?=mzr{8R4&8E+*ID$S0i3W|!V*Oji{RYu`7T5rPsr9QdTCrt;)2}ip_G# zWYXW|kDD8y+XDt5yPQ>1l%L;cYj^kGl(4;{;O0JpEo%2;hsN8sM}rLMhcwVW+?aQ2 z=?=pui%u>gle_lk8nL}p!8Pw|)`s1|NMX8NSdLwzb?yn(_c$J{GsqVfmyDZCkLjt2;)^7%XsnQ~+tW6Nztv4x37lv_;`&NwzH46_27O>K9Nm(Dacle{Zm)V5p;2B zEK#WxAd^fYkdw>ydJc4kke-uHW1nzB2xMeJ_8|c3H22}T`7xTIC4PiZR91exKrtgn z_K`(IHj|~@?2AOIg+pU2BUgq8h2hNmJ+g3SN>qspF>Er|@Zf9tp#+w6K>uFBL97tr z8hXR=%?k>#u-}4zk>E_Zww2K5$Ufq(00fXyIpyC37B?0c-UBaNAUG_5rvnL%2=4+U z7+vGoQ+s`RUXCPO6o6W&G7P0_D=DE~-IetKp?WrtTp0#H_d67)+MET>+mN^4=hMy5 zdv&DoW2AYtQU4(w*F03OcV9(KeUy151_q-l(a85u&#Mh?@bOMi&;*SwT4eRUdq%|! zOMD}`hB6HjWkg!)H){^jNeV5MIC=ZMLfiBnqlK2VB9y#EN0W9wA?Xe0tSg=9y1|j{5#fyYvk%EjGrf>)4{v);T>KO=? z;6zaf6W}XRmO%)}CQNQ@z~h=x7iezQ3afTI;lM#^G9MlIbSPcoT*xOz z_Mt}sHJaqlGpDdc(mdiD;uwQXucP~y#R1tOvJW9tm<$y1L|qMfnrlB1EP_bY&AOTD zl*qy&j3Tqfa}3QrqQG23;|$YQ2?+s7<0f?O#sQKzC|!8`%TG=F=9t9l>L94Qow-H_ z9>4R8JqTWS+s72d&+2LO$@2`3OH0;*Wv*)*GW<=Dah(wO7U=5Ic!i_ay#J~!_Da`; z&K?2~qV=OwJT8`XogXio1?YIW=i~AHQqOkB=V6$Ok*fY48R{%oTINHN0&*rC`#4Z```V?eNCD=w2pN{Tqc_-&?C&C6Pw`gaA61f-^dthBCtg0-px z8lZV7-xKtF*vNM0U124^)aQUri+^S~X%5S0+2j@)Sq2=!R)kB0uTLkF z)l{WDuapkGB!rmwB~7x%(5xTEt&k$p3GqB$u!z9^MLzh@q6JmW8`cjM9rB|%g873*rWDuQ4*aK_jK+8jWWzM zEAx(^qtjPSa50~VV0gZVJ*p%#{v(81Bl+I-YB^3vux|j+dVcuBHDf78^0f0SzX|;V zsoiH(2nVD6FG%fusEm`elv)SQ0i!r+$$eA(?Fx8J8=Zcw4IOL?V~8PIgW`drjN>68 z)-Qs_k0E4__x?}|B*;ax_A_!DBr+CEqE@_X-G^p454*uXgD>ma=17{khOi9u`AbI+ zi5Y9OH7|@y^`l=2^p_14c7~Y6(R_f#m~=NeGkJTdRF?^whqAQQOlY;2)@NlG-1X z9(n!$!`NGf#kH;J+ABB-P6+M}2^yTj-GjRX_uvk}A%WoT?h@SH-QC>_cZzSOyZ7F! z`}Eo8`&V37K~b}24SC=Denw$;4{m1ojtv8pZ_%`EG-phWC!9Pg$JY51P#EXOYK^|F z+*?jM|IRs$t^QLFKmf1K`R!2Dt;WSO6XWzO$tIrn`Qt6UUmY{6U4}3Abzih0h4frq z{lg*>}j0XR9YU9U{I{63N9^V_L$yXsa>;TC@m*1+g9r+u}1D+GckT zHtBsQA6M0MS4fVDM{~cLrEzLg{TyygvXQ;kmsXKtoa9Qdr6TXvmrvU#>1utl_C0@t zg#j()GlXECb$Z=Pkr2JC-6*(F9L-y@x1!jtn8(C-gC(6PaN;x!1989ZNLX`cmHkIiLA)!N?_kLgD>ypoGebgCW z-R_oEBiPm(&5u#+;4&C0TA%nG3LozFHk%(`CVg5=RT~#ttb=)<@0VFB^$O!VW}2pK z7nJ>vKs>|v6bAR97;&6JWSBux-La-dUMpBt6pWHm^mxh$ej!%#+=}zH$+Q|*Dk}#Pk*cRB{PsedrYfk8>@d=B?-+Lj~}@2#E5~Af7&+f z*6q{D>8+Ohr$LkHf);|%{}xA}7N~$V9_FX){ApzXmC7N2A^apA|Iu8CSs{@+-Brl@ zu6cbBp4gM*Pk$p6e!14tX)IJHD9fgz^)^}C{V;Fu9w_TFGPXZgc`PiklX0u;BUt1W zNSpG;|C3Qqs;+JR!6Rv2=*VYX^RQ*bFUeNhl&k*-Q*Sb#xYhMaLK+^8qIJqKKG@r3 zu`ql6Al=Ucgy;MS&v?Oag!r0ja!p<6Ft%LaQFOhq} z$yxhG_LZXUwNuuQ$|Qp!DY%s$+Qf_Ix5iR;PgAYZyupH+!1PtK+30Z1!ySXz`i|q1 z@d_uGYbzhIVfAg?!Fw#PmygfJC;O?yfBP^ZFc7k57o1pt;gnC(Ba0BV-m z9pu?6j5!z%JN<2!*Xn*+d(hBp{xrmHph5^6sxsi zztz9z@Ge(t4T=F~5!rDY#%(&}#$rYo>6MY62g%=MkOw(oMLqzgI zSZ|0Q^NEU(m-}m&@u}0<>fK*9Tb90FY^?khq<4F4X+gmaQ&K?aHkcM&&8$b{aR|-z zQXhdco;Yps-}!u%SOt&6R#BGIonvE232_qm9vlRp5!Wi;tg-iU3~D?|ryhj}kF~D4 z{9@cVd(PZFJ$d+1@A*!-MQKhfwlknPs zZDQMxGPxrA)KEF04x@I1oZ4631$S4s^EZj?3{S)r^WTzP^sZj(U$pMb=xfSr?EJnW z@F%f~Dm%upU?pASx#YL!BRRf`wL&;RMY@b(UW37 z&AyP=zMsoPV(OaQHg>9t4yYf*^bT_jB&j|3-gCYLKx^h=2w^}zK53mxZtq#=12xcPDkA3UyfNXPGLF3ed|@~SUYb1W3bj&ZoyHtn+bX-3 zoy(*hz#Q|Dtct@f8-r|BlW&o?^p zV#wg!?Zn92cp_$SIpm{zuNas>!y!f5wmtM+LvbJG#uzBrYC=IezZEs@yo+XG~AzdOa!uduBj?Z&&P<#OU=llRbdC%aosod&g=dFo~@$WWy5%95*2nunzqAUlt%(e0dQ`mJ0m2vuaLBAMIQh^Nl% zq#Q5uhwQ(@Qf5OjJt6*V^U1%q-Xo9%h7O|GJ0;$W>(uHRuXhL<1@nCtN|y7a*Luw} zb}2J3cV`g%cAN`(zN-({zuG;nAMW|B`-YC4N{Zp>6w@!Av;W12ae5hks}tf89%JCo z>a~8Cnri*ul!dj&4^IVSEdYS`WSQhtsS9th&~`I&Q?^!6M2l#DRS^+ms`ntnz;%qU zXt^YD>UI4OW#Q{^s`<<5BClRW$xwWMrML$k_hP%v%R+f8AS~2+*oUCh6&@@4d^Aa~ z{puywIPbN_dm37&Orq$XT;~44ip8es$?Y&Bjtt!H8gr{19$PKPC&6w*8~p^iY|?h> zl!uDHIQ4Na8nuK0{n*<6Dx=t>h3nw~a~MJJ_o}b&svHU3`;s8oAyFVlC5(VeacU|V z@-@N>%@2t9ph#po_g~{1-A-aM@UvQNnx)v@OR;6Y_|rN$hwnyXxfa6X^K5vqIc{Gl za-cLky;u@kwTK^B{ktc?E>!1vCyg76JIi%PcYuSAV5(+)-M6{!pHrsJj0*3LlLe3H z&fAa=`aW@vbn6XEvr$*ROOIs4=Qxvr7H11bOF zI~P~f)HN5$oc4DA&g;}~+}A5veH%66&-fYSP1Jl!R_(LGtTxQm{`9kSXqAkA&9G+0 zar0tt{_cN@0!!05$PQGmT|dxvw8GzkoSc)yMX~#_-cP)P&F?m3iY=O~DVQtQ{T%+Z zbYG(s$R7?Lu5MeAeg}}GbQLr+eYB%49(An?4VF(nB95H#J;xxGe7m{BZ=^`(GX{oY zXhS|KMzc=gn_8Y06Kj(4wF}4X-7&BB+iKcZgZxvvoOHK62WZ*JLKz4~P;s8%Q_6W) zu?=|@w{SZOH&~2mtszkLxemA>;P)AkaednbU+JRFtq1$-vH1}t3fRjb2 zcVATpNEk*KqxXYbaFiP=Icon-Q~==r<85Ng3Y`idEkX=`hi z=(AAiCAU1@aQXgm)!}B>{S@o4HF37cNZ*F~8Uc?jyItGsxcpem(C<4mbD^S#9&DAs z{J_q|QnOrHbDW(~z*^gvv~~_CyUo87R=yjEg&6wl(J?W`fXb*?an&kv#LHb?rrkK@ zDI+NvrQb#J&CSj2rz=p2_9R1fhXFn8#F&g_0_dC&lj#J$Z3`(rhYiwj?xbjrUVPX1 zSbXwUZ!|ANN(XkI;uIyL)SMx1bcv^MT1dew?x*$q+;W3uUG=Wo^~`s3Mncxyktf;U z-=%$WcPT%FCLarIkNQ@uw>S0qdwVz!O3^LB zuGA&t!ADI~ML)o;Z9%;EuhSb}(lANP-cH4H-d2u* zd_|UX`ZgGIE{adYOv)o{tS+ICh4jvMiCKDUjNWa>^mq}?85Sxy2vJxGg%g<{h{30` zzT?|ssL@;rFWPXZ65aF8Ww|pcZDH5BRCXKB#PayNJREFpYONc~+b`cAe8-wD8LJ%g z-r8EYfS!vzZ*+bo(LAQ=y{e?UA1Ed_QV1{D4tP zEH%^`zVbdThk~!}cb4bviLjBxtE1k;61T14JD!!$wxYnOmAgx6ZzYD{|>zxpVKiSHiRtb&J+kQBNMNr|%E>`Fw_ZewWW+Q>p;gN0Uy9 zQI;Lgw48k{FyE=cp5+>qtTlQ}jQ4j}M~S50*TRlDWaxV-QwEk}1C~zrBfDf=E(d2c zr(XG>AQHG<6bp3u1Q#<@c1%Y1W*N(2NX(|`QoR%H6VBeX+v9qMl%`a65^rm(QDy<+$wH3FKvb{{a|ScV1R-i0*`c}b zF$t2&<8$r$aHASOog|{2J@`|Bn(u-LKf*#MLdezS zO-xlEm1*ET`I-j3@0=#_uy2y_V7ouRmQGhR-HYo|j~+HcAe4B5(;A>ZI=s?6|HL0u zZT7&uefGK4Z)B$*#{_oyLQiF(MJN(!DyV2I&yecFoz|xje1%tH&mbaxy%%D#v3vgH zRTFO#B;@G_kCA}6#9;(Xrhb%bUGc<~rq-GVGH?gH%u0!@qiIDTnZKM8`W07eyc5(B zLn5_pIoC3-OM+U*l!4n=;`%Y)>3SWcjiG1dx6=4S-lfvhtgJlVf7eb}E06+U7O>Y# znY-(geO?#QJ>CY{ta^^WGpRBS;CZ=hv>#uYHxf`S=Hi&}L6cv11@k1iO%U~=c7a*F z95bg|`bpu8^-6r&=g2Pe*%C2jBS>Tj*1D7x%J0Cqb7TT$E}03*TJyW@*}Zzlt=QEy zrdrQ5Sjsn=N>@8CWz*h_Jf`uR?)$8b=GRWN@ag4i9`o@h*Sp6Ibq~Z z3*Usx=0rzFavY=sYr|3=_SOE?8#wq0lPyH~OMl=4OyXV;_`M#O``r-P+gnL&jbjCPFqU zRi}>oZ}z2Or?bR$K*%j;cTb-q<@YFwyl$+&hyYt7QQH5`rxum?^2djnldzJR4$_a4 zqaZ90`Xc^OPBag!wkLHK4>d@%GA{ENhSk9YV+9^GG=lg=j08-KuQ>#wdy+g0{N?_9 zhdu0}2O()syvkg;xl`MT|0#ccL-u%ZylX!LQId@aW}k*)HamCR&1r`$vm-dEM@b~) zIg734uGKKVwSxs&IET`t_tF^&oqs>i^669VV5VbzUB4udUS|EHM zbGf_5m>40hw#Gt+<{laMk_n;qh&W9)groQ5%CTK_s(MS2IDkuU+&N*^2Q#Jgdia9! zhEhDjvb#xi3Ga#U^zE`0rv3m9Rg&|TxVxwm($h8nHhvIMswf% z1(wvNuUuDtpgVcF1yr|krMdd}_@&l;rhd9wy5{Qi-1{8N<+8E1y*uubW=R#?hXH1~ z{>$wq)KdB27gLFp0meo%@#K@nX*s@+`QFRLE2NLVA_kMuRlwv$QS=iVf-obmdtTTW zk$w+(b#>Zne8rkkR~Gz)Ft;01bY*fz3lM0v7U1srT$CkQ)|% zE$>9(zU8Hu5~gbwU#6k6ui>0D7wCg7gLlS?5T&kCu44J38S>-Dd0^XPc8>9CkZ0rJ z8TJSrjK_+xx(O&BBjVZ>Sj=$CYx1y@I;|{J;nx47rVHgv26<${Z+q>c1`PCR$ds zssdFhLya1I$g+?LS&<(6-5Xu<5T0!lK9b@P#>sANJx@r>e>_Pt0~>S&zt~VFA=h|D`f$xN z+Re}mX<4+tQz;lqi)ba|06n*~d;_c4Uq(G8=TPf7v_E@nl0B?nxg4JVMoO~ZA{b<( zi{jYRwWZ2*-afdlE02k7hlm#dLr&upu_SQIsbq_Y?4mX{+Bv8$S%A5`X&(l z+w-r_-XiiDMuhCD*Ltl)boh7Mm{g2leywS(lheRG{_!uFHEiKUFSZAx0c%#G;A192 z*=m#shg)URcl5hnEJZI4(1fti*A`vptRYYbgxGY`RSs~eXv$VNW3^vLO(Z88{iwq6 zr*b*SsqXuY#>|Tl#WKwygeXkd$YT{HmJ_r6aPVw9G=%|yA0vNQsXLYI__X1;#Is2p z3bgK}!KB$f^PN&ETJ0%ItG+QjcS>>B1%2|JZm zt0fIaWOSmz^i2ufQxe?l;RZvpX$dSCFZM&2Q{U;wiR$b$W9}rY*a~=5JW($EtGvvH znQJ8b;J}A1i+yOkfnM$`236!MaOmV1?J3dad-I6ISI`=nOmG08jD2C4Hr{B_w?|*qx_4x^!4|afW-0k z9_@n|jF1Aos>vUbT7GVD z%H<~Cl2Sr%ako<{@S(!ZQ0wix+9n2`u6rqaW zxKWu$1iZ2*_NGn2@vs<0-(pOSDR6NutArGN7E-{>&~i*v63XW^UzBy;mUhU37bX@% z#n*>u!k|<_`$aD+(F#m-1T(Mq&ViwV-@S(l-|};D>@Cya29GYUP2d#Yy)Z(hEmB8# z*q>ogOT)fF+MeP!oK0~m+)i3ef#0*BbJY^B!g3AtON6ZQw0=QiZ=Q=1>yV@6@rTLtW#t!`!v||xFW+FcYO@@zFdnFB+SRYvFp+_sb$LnTlD+>-!7)aU}a#1kfbxBMp9Sy&< z2s<$u!Glo!G(crMnF8D@*H;4fIZh$p3)-@UH(j*!OIt$tYv)XnmaJ)yZ-05n;JSE3 z%ls{Wtwx@tn8@qgBjogVKM{x`PsXGGK|e7La*-l=e^VR76cN#!>ZLc# zb0z&h1%WgQH1v_T4R%9>jsJiaIKv_yIwQjTwOq z?Tr6F!fbMhA1Z-Fn#KTo0k;JV{|)p78%jyEz;m9%hC5@#o3nD`*x#u#F8sLin&F*$JCLF=~BPpjpFC zl}%xHvwEE}fIdG9sjeRGH*CC0KBA*__wh+$mP;5r>b@N=`~(?XsAh;5b;<#_Y-w3-OU;%K&m2_fs3e0GH=S-4=B~w6r+u z6xif(XlZI%LST!bmap3uK5qCi^p^aa3_$GtK%G%R`|>R#f|!3T88w8)EbJFPhg^2H zV`mH+{^c8VSmZl^)>OZEb5Q~0WC0R~(M;i&InVc4SVb9W?imr4d(hcpqN0I77>70) zxmNku;_TL&66@tUT;>l>*~r8|%1X^17InaElyi7&z zee%m;Bp^~Qt?7Viy41h=d=U6Dr|YGQFvM7%(DK}7*Gk!Q#BwM6l?Dd3tro}c&y8D( zc~FcN0F!O7HCAROjNpgbveFrhd;xRO4Y2iOZ*?nmbaltGUNZRn_CsB~5E9wL0kq!| z0H5eq_Ss?ZI1;WmqY+vHE8pm{i@?wGcr{Q!*>+zbogngMTeX?NFa)(>cJ2LCkk4M= z|D<>>{$GT%Z@L%>!MJ@2GHikikTqfTz3CwnH9=&f%o-hmHZ!7QcO$5B^sQ6e>61U- z$`n!yvbaYIA5?-rJ{iGyNBV|v1@0L7j_&&vfYh zZ%T5t{x44hh+R0SRiUH~nf-SkK1RCmyQ`@(=+X8D_6AvNnk0v1aO#>6vPheZr+)%M zt3e5kn55}mZPB)Xskgu9OH2I^@$A3Bypupm@8ps{?xjn@s>gaOi|raOuFH(;VLSM* zL7WU)L=8kLE-Y9q#hNOG%k~ATk~LjgY#qm_kw)jSGpXWQ6*On9po7GJEQ&LgV60?6 ztQPg0Q~YfM_}3fp`T9FR#d6$;oq*|$&S-xet)Q?MiIw5>h^9c1u;SRdwBD`S8Z=hS z(4vlbK18n$({H9$=Uj+W>HbI&{Nd)wHu$> zTW|TR#3Q}>uKyw0fqehO^9Cq>#rr3bp-GN*Tf5CnjTYqZqzWTM1#rv)+JEmj{QbiF zZXk#h!eX<)WL0wGPzCj+3h1!)_%@*ZJ1#yXC@APpGA@*KkD*hg0H!efHi{hyL(jkC z@4L1yU{J8K(ZJr<WbpQEM0Qc?( zP8Go*f&b^<9!&>nskXK%4%NrO%V~T^3xT#H{kM_gFh{lp3^tWs2@}5WQYsZ)X zW{|NpZQ5%J9%s1qLlzW;&AlT+pv{e3yX6NWO z{hg7dD$%^l=jm~2AolEt5I9yLxOECSVq9PUtED z2McSiYwfotLp6->o`$f&=G)rKC*b*~Ol8o}4I3N!J{*DxrntUPSjiupU&V z?*ch(O(4i~wbQWb;NWN!uy{m7Mvgl_|K{_dVz^5m2AGaz6ui~d6W5*e6#_4>uC6En zjkvydU5bgb=PwlQY+zADk^68r05}M(n!UBk&|l7fgom?TK6mI7j$gI3@DiSNh-4t- zKtJ{XcLiV5<)g~kf;MBo$Jd|W&1-P#hHWnN3R z_IfZ5|D%>OcgzFtTjTF?%1<#x5?X{QO`4t{h?c|q{~O^3dvo$go04=5z@|0i;f}!S}6x9 z)ECb4EV(B@tQds8jLV^ zRjXE^E9RJq%t?KJeK6S_f@1mc`>o^g+-L|&sx7an0jH#_EL%P_xUs?8K!M#(r?Vm8 z0`tu2T8ql@e%q_F&U%@hx-`Z^X##f)82j5EA@mxp_ONJU+@?2ZNe4l2YA(S-mYCiJCguq}<- zli$JjEAX+NElMFde#$A`_x7<-3I>0M2ISuI!Q;1J-g^b{;r+ByO%tQMzvx2-P4!6} zVU89j)9+wY>~-vuf5981E&PJW3M+{7`n|v;=iVeOmiq_^<3Kj z-MWnLIqntZZ5U;>8utC?BtZB81&#Rn^ zIwsBy0z41x9e}P~6=!%82Oy58E&uhJXsn^R#~5 z+ug}8MxIZD$n#uK-pl*ur?P^ zf(e8F3801Epw+~&n?dS~ndN@s|JxPbLo7@(FiG|6iy&r<0!Xf2Y`q!F-mTuBH#NU$ zmGWnnBZ!H;uA{Vp)EmDd<3E5j??n%0bVf$Sv<{&0SAFe$tI_7!$X5qI)-Dj(cOM3f z6LhG$gHh*|{+uMS&)0`6+Ce0QL>TuSRFgB8dPDX1h2?)dUVul$2}KWZ1{RD%U&IM1 zGrS**R)DD&17nLtOg$(|GKOk!UeD)L>=FRC|D*o`a=(uJL;tc{FHxZKKUV?~Jj9nH ztm6{y?o9!Kja$dphtmbRGMNBLrUx7uLIZS~XN<|<(D{H!&9lq9+n};KigT5a19A*D z8H$#I1)*uEiVVDE`AjWh{ocVx4z+`5%W9KFa)44F1Qe+lLzp1xAmZl;-XrCnDZu-Am0I@?gpZ zG>4or_fh%o1^)E15m8Yq3O+nxVqzMPrE+1sf1exCiI3n$3cTUg=f~p;AhdyQxcewQL$iRV#E`)sO@wml@(CFO3yrU6W$_(m&ST(&$uV9ud3{R`UPi zj0%th@H=9rIAx>n0^hP1X2iRudJjwA)9P-j3?7xmVSM-+gBC2C-F1S2Yk=L%@|TJV zPcJ$_)@5N!*?SK&zn)(W@ZxqTXD!x;P4>Vvs)T;uh2s4jWRT{MEuDq3k)4slY zo3PQ4wdAUz)bfSS-dp*U?rvnr`d_=R|J>~zyoU*6psWGnh%6<}q5MeA2BRt6HF0;jG-8Ik#OJ{2T3w&q0Ae|GRAE{jpf+DemCNiDtpI+ip;!pc-{ zbo@?aVoL$VXYeOlxi&?*uMx2u#o=#Cf>q!1%$1-Y1ipGP>Uq~Iuel!m5W7iYz5>zG zSHwQq@+(P6(Hkw@yp|>Om4AE(f0jT>O$btL%5Q*sc$Z)k4WIGcpxabgsn6wnNyBAw zDG`d`;^x=-couOvI4|o_v*OfE8$HRPa+ds1UaDKbtItcp$te+pDwUx0YgOL8fZBt= zyrt1j`q#?qz173Rol}*aWgXH<0#yMKhi-Y(fdt|^WSdxnM`7?#@(s_PcK0IBZf(6Zu^(Q`Q(b}o3nyyfg3MS; z#Nx;CF5Rb!xFNcN9-3{`T=f@*qHj`GxjI917L*i7`*iZeS2q#l#Ss*;LLV8MV{P1Z zaI;dmOFq%aL{s}v3ZjE@U2hC6GA!Fo8#^z$myBSzkE_IYZTID(B;gy*48~csstE~V zNN0x%m7+lPx^b^H$s))N+TaS>MY3MY^vJ1ETPgLWNeuooJD11H(~RNr3`WIv z{QB{<5d8l+OijE&OhiPhfrrTt?v(If;0N@9%iRRMBl2JZdkJ!7rsq_Tvqlz^5u7A$ zr{ddl-!B8$7pYJtvVyF;hcnt!hpx+=$Gzb7YV3=h#N?0$wQtEwJfwm}S%JXuVm znm@)Ok`IT!y6T9@G>XQTE#*(UJzcFn$8nG16OSbLQzOM5GjNGn%&ZiqfZc?Dab9H{ z;guF8SU-(0MIkxJ$?f1L)pBv86JM6@oM@Tr^L}|PBk+Rsy_#{1CQ?ocujk4S& z%${9mjA@h}pOon=>@)rrHKA#iF*H>5wks16p`KNO?v@p_3y(?S~hsB@$F8uszeowa57A`9 z^~Ubj)fu=J>ot$FCHG(-y{a#LL{7miHHdCgV#0SdeG`@S0k z@31grNz*i@KWc7|a)3SGeO7g@9ot$kYpFv;>C1Y~@Lq_5(nxe(+j_R?r-uI{r-(4- zdrsaP4UZIKS=8qJbPoz(&(V);p-y#64jBi+-?E`aw>jgJ`rCeyjV(zPsXC!t_=WVXDqXi6@~d>J2WQI{H~<8=Ygo=RcC(-b2! ze{WIY{=7@_JFrK3Ga7fRwD@YkzmuX09H^)jMPIvX(c8w3gEw!pK#B@_iSoQC8$Pz0 zdLz7B^$sQBMeN2w&G@G2)P831Zg3?-O{%^epog)j2SiPY^CJ@CRfg7yU6pjbT*@I{ zBRiA!4}n0P9o=j7A!WJnOCP6pJr_&<%;Y$HbzB@|1v!)~oyG!=4v zv`AhMFTb_%_;7|oX1-6`Jt4jI{P5Q7Ez#FVieD>iwm*GUEO+K$b@B@Jl$Ss66CK z=+4&aqk4_*98GtRSA9A|@EN~4vBznvn~gA9%a>n#RsrdBE|;RO@i7s&1qDGjDmN_$ zrNU0`9Lh_vZmK@tKobepC3EMiohxl$O5k#jQ~T1= zaslCW8XJpVNJMbkNs`}LZ~!Nawu27YATjl~bFn5;7fTu#nhiqmL36r7Lk+OPHj8zO zbgtJ>SmF|}p7Ja5WxRFWTIehPI6&>6^B!UHcV^+pRo%OFN0{IsQnR60S`5PQ*P4>o zS}+$%1Vt%^^Rjh4Vt#O%)11a5Cz2Se>DWw3pw72W*gs`(YlW`&)zS=&B5ewYYLR0owD~P3LjlF=%#6`-|?j4Lul*Hu<4=4oufWQgqFR6mV^fyAvWkZek8E% zA=U#Qf8R7}q|(QkMv@9{?7Hx40J))nP`4|9Z<{Mz^KKMpIgownTO;pUK1c#9O59lvL)`w_y{as{%)D6U zas{78dD}gXSBq^$x&0be#NbfvveC@MntKML50mvr8eWw^5S?neK!zE4Bz=Z#83DV@ z#NK6TMI523+uoP|u@RKWj6wgV4u|Vg_f8j-4h1~{6fr?AgTPj&f`3l#BQ2``B+$O3 z0FL(Zc->e4pxNA(6|Be){TKLxx#%Q#(nH(ZwC4mCg~L}3zpb$(<`1u9#1*=w#7>#> zPdqEmB+`e4#WWjvTXK>znM0blzRlpCXIkwncb8__aR57uj&we zJkLK|uKxLp^gW&;|JdXY@N3}LBSa+T^eGUVAOnxj4-af8217h-KW(j&pN+t$dk__0 zSWl-sVQyREuc9(r7{V@xi0E8st`m1TwahPJA=PrpoupJj1LMti)9`ZLmK$K^b`d4L zn*?7l*hQJ5{QW@Xa!ZSUAPu!G$6wUvVeivf3ovLDM$Mz6WFu8XbBcbeb!CM!Cs&a1 zlBcUMK3NQ<+@=&Mb5%{6)n>`~H5=QdROIbRTZ*Qd^yIMpV)5XrS0FDc7BDn&xL@SJ zskip5pWe}M7yedmO#y}9wZTKJl3W5siAYyE4tp{AW{9TP$j2#7!+zr4x9V`7x-^5& zi+saLz21=0=DJ(4ZQFr%^|G8t&+Jkpln{biv{I|^BYtIfZ5;Xk*v81f5O^3mmF54{ z#cH-t2@;C{g)$K$5ldHM;PO2sFZdg(gps_u!mwGSK=;9@IM?>SRX)>iD4R~gAz zlf-E)PM&tV)4nyVd7s(J@X&2wDo)GkyXlMJIB_X&Jnyw)lKq4NVZdWd1-5xa-cApm z+wF}lC}wEbc6>I7q*N}b=&PEpV?eG`Xab_)Ud zQpr30P!(=&`vq4`()F&$0&f9c@%+iD7&1#oq)-}g$E))dZoM>I0JdF^o^5xr?fu~A ze-5bs^V;rFwpuIjZGgJ1Lka&2+#Uszhzz3C%Q;E{-}U%k5*TV}2 zVfWxAyH=%Z8gPc9G_`=h;m>jp%{8A*INayf66K;d(|Kw8$6Tatct9q@MxS6@;#;U}!vB0P(b5nlK9b?*58f6Ai zmo`fPRW=(hA*;~fQ0or<-bTmZc)*4|I%EsHUqN@s`I(ua8GN$$TwIi+ADjO4G1F+I@>coaX_}6 zxGuVaYcJrYtJ+f9g>0Jkk#Rw#38_9ug6@=+<82SZXAOHj?qVeG-5+NVm(Z@q`r8M3 z>Ee+upV!M6X;5qQxm>#h%I=;rREy&(_`dXo3UY`1R!O=^aXD(4vpvTDT|CC+=Hmo8 zmXE6bb!>~{|1~aa7+uY_zJh-PUD;5{&en5uLWtYcDKypwl98Y+$Ch>^&G@9XHd~!y zxwJu7OSjPBy}AQ$+|#&^KCj$=vLfUXmWjRg41~O#F=EcXuXN#i)c7GiWW2N(V?1)s z$D&Y1a5oV{ESdUaG`4)GdADsouc}zH>?D599#;9sQ8rtZM=x~v)K|)yXkP2mL>fyoSWq zT|Dc`o3yg+`?kHU9OYE10`_Om>sg_@toBs9%4d&0Hw*#-3focD-!`!%=Z?ZjxvHrC zztq-VzCgf?!NWYStzrz#yKcKqmtj1#yrFVjK&%INkKm5as#HCOR<`!kjIEWSR{EV7 zkzTmKxo#1^htyWiNmY0HN7>|LKVTv+ZgIb1d+654$+v?Qol&xz2oSW`t$o>PI%GUV z&7T3?bbM~SI8)p0z&wjhlh&Ed41#@$Olc<&C5h44n3T`gSgGBN1(Hol0T+CaKE2KU#w`=Mov`)oP(vg+waxq<74~{4?Cv{O6 z$hVZZBi=sK3_nZIRqea;7@1^Tu9Oho$D&vf6A{^n1=C@jil2MNaHDYm{E%W-*HQJI zX%19Yj#zI>ad|mAo)QBZ_XOPeTSPlI(Z?%Zbz@i|ag{hrJo9hgVyG-jxUC^50Vpf@ z_x(ZLn~^rFO|^~XqsA*hnyHAWsN~mdOZ0%fsk)nmK4g4K20pp1?OBgNQjL0>G$71X zLMDtpJ{=Lr%P%c33Do{a7C=-@&F9f!kp~(FAa-r4M2#`$X?dh^H5PDrU zdgSn!olORu3N&|@Ii3U@VZhI?_a}?i1-w=^a_DghG%nv%q=P&j(~IJ0I}ztqBZ&C^ zKi1wdDy}VC|0Y=B5(pXy?w%mQo#5^cA&|n|o#5{7?hxEviUfCpgg|h2e>dlLpWEkj z_y2x*$6yRSt?B#EGXV#6#rjcEz{MSo!XCMgY?JZ){4=+h<1M{Ucr$1JpK9q#uTH^U0Pr|Vl zz%X~Qyc5C=f8BBJ+9F(WjfFr|%%i6=j<)@FB2sX>%Qf)l3rj)m>TJJGN(^q6?QYP4 zPqLW=iNl(X5AJCDVc5FX@wr9saF4XEl~pA+4i5O2zNo0@5rhMKfo9~nlb!k_6CaJQ z;zGa#E{sCm3;(R4p%3KnXn4NWq5GA(trXnci@`P6;@OjvN}h7-(>ELwjlBo~UYyj_ z5-(rA3_n+Af&O{hPl8rn43;&_H!r7zJBdS@}Vy<@Tv` zH*Xxx!#^QJi0qaw9lg4zi>Umb(dF@Hi?H_>cMNzbDNv-w3y=>HN6Mxl(%Wq3f^#{Jf^th}%TCI`k6iW%rA=ZLd=`D+u`$f(-tbGPFX zKCd5O5S|Spr-G-zp+~7?;X2p3nc@Cjbu?3^Za&6<#eAwp#5&*aJui#5$w1_LjNq4q z%*!dW@`feX;6fiOkSc8EsPl=*cp$vS>-K^0fg6Rrkk8LXx7!^O-?e4{`2CB6P{d{3 zVM}UCKYsj}EL?!9$zs<!3J^MGZonGfwcx<}sv&gXl*jbDXk+kIeGpuV*S=T+@32uRxPmLHt z%OJjkCp%5RTA_vL9m08j}D0aQV-~QY!h{_4$<~Srws0vQ>R^VU#JsXgeO+T=+9U_>K2fi4xhq>b z*+xF80+w3wN3O}Su=k=+bD0N8wqA4*{eMpk1Ez2)(2<_q6lN@-?4UD`Erbw2cP-Od@?%!WaamJE_zSW+$gZ#@#C zVJ{b_s{vNz<~;9dI3S#E;aI#h-x(1Mi*YyE8Za^p3K|h85`$EXF(o8r>QfHB_6`IX zSWc;b577QuB9z6Nrym*YML7R$&OB64Jv(IHIOxI-&0fwHF8m>kcPNaF=I^oHKVRB` zRXsO5dz-l^Px}+`-NU^?^ZG`yT2k=;^&*hl3`-wuk3)3>o^SalQf7#tCiZ`r#y=)@ z6#>=(jHd9kw%@FTUrHph;Yh(dw1VN zMA&I^Ghm|aAVS@YbC5x78f24yVFUiTME_?cYEfZ~8%!)Ye;k<)k4`k-G)DSAKFs!X z^?feeP9pZSU4@5?Z><8=zsR8evbwWPpkJ`V*6R=z{`+$NpP#UZkz}*_tsD1HzHJ<^ zwiME&iTk(i_WwL+vb|`X+Oc?_kfoGgP&i~=M*pCay8VCr^$UbuU~#wcG?s2^-6TVs z}jSJ$_)AeO_Tr5wtvEXnN`$`cN6ZuNDnjh^8l6%tN31|;af^Z#@v00D;(9-SW{Pt)uxNXo=v45-rL=pc)ezrV% z02;4=jFhTs0<19TJQ+LQS_{Ml@IxJ7z+N{tDao{a^-E*~A%~QgSBD}IAT5aV^Mf{# zWVN52hb z@kFke_-e&?RUXl}iPU)1nn&`quQQyEI+f!ZAaL-#>x*A|w%wHpD&@YVJy$Pu$ksV; z1iTF1l|Hu@5Rhqjwyy;OFR+RPAeXaP?N}~Gi$~|9(gZpnq)bn&Tz$#@6(#UkxxU^& zXtHSc%Xx1_JJaQYGX$X|;Q{_jT`2;d@255$QtAx1N>Op~20CkZtSDl>7Fn_E-a&sj z|2JvhshnD$Og9W!{7z4VZiqBN#9C$&3JTG`XQ;Nnf9!$6=C+ZO+3kuzCqfJA{lIe^ z4UAy6D371Ne_GDsrAVSLyg$7%H^Z-x5~np@U_MNEyB~b_Agg|N(A?w1aopqjLZI^$ zGte$E0@3!8Yy-?3y@L=7RG%asp62gDF8Mx#oMz~U7y0=V-eu$P^Y!L)yXLs!MF3gWxkt08OR-(mg<{#m zw{0!tjYf{KQk6~3&%d%t2kSYV$f)f=X!B-ZVBl64bQ=YT2zI>7*Y$)t_pH0yQOQw9 zIWxZkO@9C!5LFNe?rwaqVv37tI`@XYeVg_qMM-h7O0L%I8lQe%5P&b?ipgmw?aC0e zcvc6@M#2L9$L>%z{G^}J^Tod-$b%8jy`yjdozUw=gaD9cc0olTiOxrtkU^ipzHHEI z1tu%0HiQ(HVYE85ws)y4pEM7;V7M^2kNqMdzXfC)3zW zxLkukD5(3>BN;;)bZCzS!#R!5J?;%$W4EGM{=nEx;aO>cl7S2D^n{gls9qyw){rmm z*wTn3!U%$uLo@KH@=t)Za>RDm8R0Lbw$7jYoTM(MUsq<_uMRDNX9S6B z+Z;|!O+{=&QO8GJW?OTTvOv~|&{~ee*+`oTj~NEfW&>()9S81SRMP$kDzw0PbkVN{ z=;4uO<3Tj6bWggoCF_pFW`WVTw^V~ev>-TOf5O;F+_)hpQ*I*W<&t_tFY&cuK3fHe!C9#UZ62Mq1a#^U%=3tPu*#Nkly4j(qfp| zu74r;e?p;l(R)-*l()OA;}G!M_y2jTaNvS=U&eqnN`A=(^o)Jjv4Pbz{LdTxHVG_r zi-!luum}97XyGprm0%IYnqW1B6chrNdBJt7ZEfqfA9nFC%-~dkr@a%(wto7lw75xE zQ_)rzg8gGz4|-Hcz6`;`cu^bW>@N)-y0TJzU@%Wi1L(ngtlx8=Vdo zof3M#{pWaTJOvRigP_6ompIU2+4gL2vA)cJZgDh&XZa4eQSYu;?G1b`$|yt?0*G&Y z?JxuW|1whNu;Fs3?!O{9cVDFQd$s@~x#4onue%3Z=r6aYVfVYq>QysZLSC4s%f4sj zE`uqoB&V%i5CPyRd>=aFLqg*bIH-5egZ95)KA6zrMS(Y3zsMuGgvBFY(;6BYK0{x~ zxJ>bY*O|C!=b9gKzH|~3oAaU0%}!C)d51q5_lIXM^XH8Y$OK54nH8^iPswr)0|qG! znwpv&rDz)5+Ln@C4vG`}!X#})AEsGij`fU?_d23fO8wRI3N_MIzmWBhh=zJ$m8`Un zy(=yqpmjoQ>t=rE>WvslNOd{>u?95fYLE*3tDH7rH>w4DG>M|t#wK(1N z1iSCrLx2t$mFjZG%= zCEW-I0XF~K;Vs2VyL+RG`jM`+Z@wk2^kNI(68ls;ZyvU6%23Qb*#132;Dv8CLd>;D zAC5Okgy19ZvXEk^DQ68O5p67R)Lbg7#6CT+;MyaGfo`Q^zb<>RuCRjv%(&0+(}+G0GJu_YY5RoD1W zo)DZLnuPv&VgC`NXJq(zT2~Sz#>SH2wHQ;i4yxDT}l6f!k_~XZqcBfIgL>;E)B^>hyR#$n+`@px9 zb;rmLJWb#{?>#u?IK(n<+D@e~d^Mdjp0?K}sk9Q-dr%U!}<;z&i9+b}f*K%=#Fs@xVoQf273Tdi~ zx61{UF$G41H1AGg${Z9W9R!Zjzt(=$}Q+Ak}0lKSjgvAEhotIQ#h&vu$l8*ftly*!a@xy5HJvSawW9VCjPB zC2-d7Y2lzFr!Xw%u;`C;6I>tQr?bs_6T3D~3i*viYis<-c=9VVdLHvi3i5Nc%t`KZ zd=}4N0(l?UZ z|MAzAOkoh%rFStLB!Q6+VC!~2zkn5H1#@$A&ofg~32q+mjy3^=Yp!$EbMESCjgw|_ zdn~l}C8E3)uPS8|M-{4D!l17#9KMy56En`%6<-?nV#fm>1&?_ulL)Gcs*2XpU>Z;0 zYd3;m$dZcJQNiqiWr@`X{MYp04Te$5t=Ua;F!H8Qs(BUtm({0P8f0Mwg^ZuoIexpl z1e>qapWI4I9Br+^Qq-4syPI3GPp3zZGt~rMHwUsw`bd{1S}}YoaC?=-RZOs+Q7wZ` zUL>QaSF-}MeN|c}h_z*(bxK*PX#I#v+tfaMnDlzdbI(M(dXs_uXj{ZX9ZreKC$E0u z{9F35DrwFYu~}Jzka6#9)6J%S#9foi+Nrf-!5o5tX zLCX!$n4zvkyD70tf7_EDNemojsuSrn^bQGV%C+jHa2U0wX>J-UE1xQj4Z@m)5@j;D zRWm(KCHJ=YPaW6B#vV>Ko&6_8GG&ngF^BYs(n z_DXfjFcn}E*y}f4*C~h;Ni9jE7h2X|3dmA@=ustpB_Ymg%fy?*+WH1W-vCa9R3{~D zDb&*2t9DE}CxDNx+*)ET2OtkB{Wpqpy49!LCEs3cEo%48ZgJr1<3-k*&dtXb3q>r2&HEhh4u)^J$gD&^|LR zQlXU)+WVU~YlKjlxqm8}l-6ab##wlEw063hu+?JZ4F?pC~yJxQmF?q?fY zt8>Eu*SGPwG#390{Y^z&y4y*f-I^D^-S_@oZspUBF#X|j^^TbGbm)x2VvP(!^qb#< zn|60F);qQ0=zEk&nF3-={HC!yV)iXRLQpK{**=w)#8Ed_n(Ej$>zA1yKIzO&;W=87 z?s6HSy?^4Gx@b-5Jif01m6=Ol%B+H^ETw}msHrIo!%v|WX(;!yl!p^qF-7r}FgdB~ zMsk!IE<7E}aGEX~Pmj`@rDraV>pkvggm+e3%U-uUVKm=_Vo}sfXMiTY6$!)+X5Q)8 zorZ2C59e+C#K-**^=?zL=;Pic?=$qYF>>@64N!XTFPaeTdQAqU=i<4tz)Csc+G3?y zLOjCCXiAm@*{2Kng=F&h?T69Tb;cAL2gu#i9C%TG&lSBOuU22}Vx>fRiHl1ORAFqr zF?er*>|@fJL6XF`XPD4m(t5E@5(0sopI1LztqK@Kdnl@usj=DZhY+qy-+r3fcM%~{ zgXt}Wwmo#wjo|N{mUx)sJK!~mSAc15tBUUyb(N;g3;E9W(V$c#-3VGldgXP-%Iua} zOkb}kQoL=x15mj67+f(Ip{Ke8&&QM-&R+ZQYLoILbM`agslK|FN$>=ai-p{1cutdO z?ab7uUb;-r2l7`%FdtV(e@luNq7$>ghkW=VL=1gTh89LH4r@8`q&Q=eJs;S)ODAvu zU31Z{Y+1&U*Iq#Auur}eZF+w4Y40~(&f$@qOIQgek5TEz_GMU}e#>)-N)AhRwHfu9 z<(yqEl#9c{UBaL18M)yI8abslzF_Ov`M~13oRY;4a3X1uWBDjj6$#z~XDOoM0mE@m zKu4F{-p$FhthuRH1+?`unbyZnyPg>1jVX2OSmZG-(aP36RoC+cW`IA^0}Jx&m9+wk zUFzr@yAd33JDrbdx8+DZ5}Tl{f|9)TW005A;J*3vGHK)d7xj?#*UCu~nRbIh4tSDf zX5_iy#BVwoaPTD~*6xZGkge#n$0L`NyAg2r^gHQe_tPD^u9{OVH%a_Vv=punk50e7 zmR4r%Q84b*LMB$h>@2iPKkf%LRhgyj1uS3=ad+HON7kB7gxDYU&`tVyg)RKEX0H-9 zJk}w4Epq9Q?5(irV%2WH*DSF0`W9%fOh3q$^~4tst!zoD45&ghCgm5*dsV+>P!x1k zLQ9~lPYoQ72V&zXdL&r#oPOMedy1W`m2%xYq2CPcBxZc_w2b_5ImWpxhMg2|PCgFY z3KR#UV&%6OVwH=&W4l197Jm+mlW*5ftXeD$kMN!v)OXzinFM%rXLN3&7O8A}ivyqw zsm)5U-PuZ2IZa5imU5xh_Y0-ATUK_WLz5E5vDnmFB06{_$q_L&xPOW3ff(OMAAt*e zCBuFq{kekSW49li-MnFt#ni)!=C;HozaIV)m{u5f~g^e+54Nb{?m706UW7*wgxHLEQLT6fnfVyf&SSCqZlL; znx)g^;8)g#TKIv#>5Wm_6jfN(#d8ZgH3sW3LG<({?c}2~oK4}Zph_EjcLEa?p4=eX zJIVS}7A5~rC=h!AEbYe5T@N+8tpV?nTiz1yMK+a|O4FurQrFcc-hhTu<0ahzBEofC zA@AT&(pax%f5 zLXPx_LYZH4d#(c{@hRQmT*LLK+1#<`v#ES+AE~#p9;bcX$=2oF>Lf8A`l@3kzt_1T z`A7fI9kyRToi}f#qhkCAOwE`xl%tm9V_)VjLsmR53Etl%+um|QO9(vFo_d|I$?hLS z=?1=@&QXv0Xvyp5GFzmipi;^w@B^+iqLtVUNJK~_!DT&)9Cd88^-{EWXW&jATs_IV zGkBg|9=IVb-4qc~EIIAR24&ugR%SZI*NG>UmUA_B7FV|45=$K3!cvD;%&{M4FFN*8-q@Gk4LQon0yTJE&y1y(^wRMBGu?qf9AuS#+PmE4k#{t2YTe{>7hhw~idAGg zhIX}Kr`ly>Gqou$iC795y1}tBAV*zui;Wy5gfcj0-H|cPwq37>wYZw5=Y*q5b=>aKmlPLAS77eBc+J|6A&&#+HPb4aH8q@l#N`9E9Zz!|vZ~)6dW=an3j%6o9S7-kVd%Grd&4;n zyOiOTtJ)CT^rqvPmwZDHyaW)`KH62bESg}~P8x$3iER%(^sN_i16$x{lRI#V5~b9Y z=g)!N$d^G;`A1#Xlvxy4QYQ82o7>`BwbpQ1h%uBNcSDW-Zqy~Q(g1;NUkk6DR%x25 zjq+;des25(^19-i1CuYFi4&+xZ~{N8q`{#&j$bellsd$`7uG^%qub#Xm{TC{$FX#2QEdsfm-=)omZt z&ubI^1V+yf8|7D#e{(7mwj*3TVjD!?`-?av6eX?~?RBmS?qP-98P6MV0Vu*eHDqztV^cxmYRVGfQZtpm!v-A+ z0wN-d>%N03&Gp}OPQQKko8Tj`g2A4W2s=?6Gs*H*6|IY_DvFr(8}6;F4jA~O)ZGMrf@&r6cU zvzz^vMr-~3QM2RPDn!TjF6=h0dD~X zUD6Z>1ZoB;`TQ9Aj?Hh6SmEDu3g~R%PXopsNXR?ubhUOxt!C}Mw29GbGOYF{HV^%= zC-n$E`$2kG#4M`GY@4K`rDP@ynnjCxq??-d=MY1#{qjY|8Ok(XC5}$SDq=iu7RTcz z+Pux4x9ADiO&>g0QXwHe;}|-|Us`pi>V!oWSH`RB@+jTLFCc`)X&cNUVe<@5%w#NHz^O+!DPFl08DjxpLuEmVgw|y7$;|#H~2FBACaQZGYg{_Ue zJ4Ln5Nl$O*Z0{=MRbxr6DzAJ?ajkUZNrq~K8gZ*II3vXJc?;ch2D{SqypD0lNm2Ke z@jy$X<*@QagR<-Q`P(144F}-eIf1_BH3eHH^{FD>2!0c$BYa8THm1(dL1P{Se?4}D z0QG2sbRJydqsMJ7VLXR2WB!@%y0z$pE&SlMG#d?FqcSUmCQA(*=GFaKAM>X(>!)a; zhban2d6E_D-xW4*1_$o-=cE8EJ@xmLmvua~-nA4C^Aba&zGv?J@nc5q&n<~MCfL+V zY7sw+cA_h>x+2(y*w{t|M%>s8(2UVydKMhIO%b3bM9u9W!r*VMkqh07_ zcJgS?#U#M_D)*yatyBZG3ZHtnYUv(Q zf{|wE*v0nYX|E6HXmuRIuo*hU070c?1H+iVe0zR4la$x}u~qX^qQbi75PuE2ws6lX`_qP91R&?~!8?Sy2mOwNsU=$bpg;*JO|cZM z_unp79m`@~CCDM7mUNDB&u(z?e(Y&!HG1Jnpqlz^JQ9W-0z=Z4G!OrSTFzyJDpN~Gp1bvGZ52Kv}C7Q>p(iu{*r}rg$xPFz0iyI7vB1JYAnlpg0GIYzN33hPBk&{ zdDljM^*<`o&m`Z)h;-ujZ9%+e_Qxfu}*T`c$VB$?MRxV)Z?1ebTP^ z?((W`Yw+VHQJuwwS_YACF&~`r>?43{yHVDn^FPT3qV7M7i$W^P5)Pjp?V6AT?*-a> z7CsL~%{jL3WX^4-$Eog9Q+DjuLhQYJ@uv6SJ@xwLb_@=`fnmzlOGw6FPRQpMh4$B- zS=JQjW*hVFBnxJK)~-RVN=YqMa@21iQ?{2(u!SWSTtqGwYDqoKaN}0>U*>-ZU9R(;n%smfaGk>5Mmk6Ja82@7+)^DIX;(sgzaclWg{v^@L^~& zSTIGD6i&hM@l4V4A2zwO^XqzOc}`0K|3&fGm&*C3xk)98va0AOpI@Tc;!DIA$t?9Z zKCSU^mXM4*9O7s{xr^N%O$54d&7K~*J1qouY%eMarDl{>I-|C{)yLTJ3i)tqYoz?9 zeyV=DU8{bWojGipsS|Rj=8mK=!P&O)V zu4v2638g7U+*$F7FfLaZouyZyD7kMio4zhjJcL(|2{FFi+tJeaO;i@DsqA)1F{6L^ zDe+f_Ae=)WXp(kHCsT09W6EjsL7fr-- zc5!6>b8QjAtaVI32qaa(X@W z;@j;+cRgk49)T(tA7e=uygRhyTW4Km2G*xZZ>G7WWo4|*4AZK(PMwGR*RF-T=<(_N zj^0EbT2E%jgC&Kv2W9Jw1}&X?i<%DCX~-kyJTDj`4V5t$51i&&MVF+(+|&-)9^0&x z(?59@c6Y%S=&2-mTQJZ8DkY z+dj!2{E9)=TZAQxcO3?4?B^rSxtmq zw_5Rf&qT~E%s(vD#rEiOthGC{G(Df}WJHyD*k?LN<-rCf1%YgK%9uxXY z>z!jkU!XAqBQ1Zme(EI!IN8cnE{6?a^Ft~feY^Ir?17G5utp_wrz6X`(VPQ&)y~g_ z!nW!B<0KAw#50D*TnOz#q;bDuHi}UF=Anooh88bMZQa=d*^Tjkdk-Xadi)F ziEJNQMCGC2pc2MMGrpK;yI*#@rMuLG&eJPF+KN8;!AfVro_$cA8U^x7P(pYnq!tQ+|m+1eiMA z>VQC?G;pBa59m282ZI=7Z{$kqKDqGl@M&8t*)|IiP~oq^fdMI_+|U!#wMU;wR6>qz zj=uhW{HYqJ1FiNC2u7l*;KALQvI2=HVmC)EEbj5B=RB(0)gdD$CU^o023TEcj%MEngLdRz{3Sfl+-C{CGy|tKUG3Ex6POx)_Yu)}4 z+k)PaUz|Cte$W67dfyf10Y-vB=YUZYi;;&QPc`?ufs!UCSv;=nyzFd2JA3;A0P7oY z*x1}`R`2DQK*N(C4~&g{DJd_{If=GC1c1C@oH_FEPCWb~p8;K~FQ(gC?EAG9mFRhh6BV$zo-eKDWp)+)(MxlbM7S|1{2P*he zO2~FTuUI)ARRwc?$ZG@4*z&?|N_SbG>^6YCoD>yYncqg(sZ@IkJx1uWcoonVL&xRd zu7^`|?lE>K8H<5y@@nsbkQ*ZnK`1Ycjk`PgON$!;9xw8lYLY3jegkF}gnh<*?BX}0 zazRUCXcB#|v2SBu#mbh#i#%gXy6EOpQDI(|`$#onA685uZViu`^Vn#xV+2SLLq{wA zO5NrgRMld&gU3hFj2Koj-ntkeYHm6meVCO>O5QpJc)t`*%2)3Nq*M*x1~wJ4HJA#t zp@~eTGQL2U=!@t@Cg!JlBu65`W6Aai4#DL?aRdCS#0mBUYzh|*wLlOMa~;gw*N~*j zKyHJz6W7#4gkqedWQx1p&EikNSQl^LrZSo)9{`t)il03*#f* z5*^52$Hp&md)thBAjolVcISm7fW&a5r?9Y9YJL@mjEr2o4~dH6oYe0g59pu}5Liw2 z#S8>)e@$M>N(4{#-Q3m(H+l^gDIJ43dD2ORPa!jEMB4%eu)P8$`6(r%bMcA9!0PZm7Q=WUWN!g z&4c!@$I!izaSHu}khzaX{r|v!+v-s4U98qL_pDEz7cQVnloyGPG9ADb!3YiAwv83N z>QoVaDNZYqsNfkh!|gxqr!`hTim?II8>q`n5!foqzs5%;lo)vUB*hSvFO?@uaZBG_ zs`0Q;*02q3cB`^fWva`OlwlK;qX=R`NN@{LSlx~M3|X6cLb(nw@rqkWj%$_sCu$cG zKmp%#?g*z^G9X;Kx@~%Z?m)^!&Y&%8w|*ETf}uyuAOZzHMb$U?BG13%$x8$T0cfag zHr63H_c9_XM-6xeyayS)$MMKO?zJ!L*4-mK@YZ;*Q}NETI{>1kD=sw^{IMDeAX*I9 zX8(m~`PI2frMHm-HlQUqsDSej<>SHw*C0tQT z1ZS{~VLdVkK9xf=B*R`}u&}a++x%}3NP+>Yg;`C7F_RPN84IO$*c0?0xykVy#QBPA zc%qh9<-C7AVElb4^~Wkj4D(CcTSV!Sv1&nMh*0KZvj z978w%Q>{Jz?gc2(Y-!2QguoPVE?xEFlUJ+IBXzx5Xpsszp=Dz+u9iu)^LZ}gF?TmK z?nyoT`EGxCFs_KW?--RGM4V3hH8X`0gu*Wo=)kAvMj4gRG-Q=(DkNEG0lAS)H1(u7 zQ){D2x<7c?{BvOMioo0r_JI9dMdlyC!5#Js;0MY@{t16F*=BGrmH;b&3}C;l7+TND ze}+ZMs+tsIMI?r5dJhu=iqAhGuc)?(@oRGH+R@>RJJ^(L2-`oV zG5Z&0Hfiy%jJLCYTBdf18B~2k_Q%}*@%4!;FP1s>jH+Wk7ZXACOU`y%2y-#-l!IQp z(4U{>Z&>YdMwea+fz!Ss^=JRleA1*lJ>{tQRVHs8oK0TpERV;ILA|rIa|E`rWP*Q` z_p`|{vLzHGxTMR;|G7MTIH6x$AqdN4Z;Z!Gs*z(5uzntT`Fo=2Pt@jGyvyqA zf`{}@kctKoif>L75l7x~0cj=1{|PB0{NZ7m_)Ilhs(&N-e}l)>JQ<^j$~UzAjrwC# z(tUR&T)H@r{69a%-yYP-kYp1Jm8n%l>kS)gS0+T!D*PYM4$N-5w+IQ_pZ)&_Yc30< z94Pt#EVR`{zyCL-e7U%|_{Tri72aJ-yTvJxK-Iz!FZthQ*(^m+P#rbx-6oV~=7r)& z{V6Nl|9hb46YA0-^0a^jG~M%JZw+m%YZZOwls`#e6it0@O9hS(Mzv)0tBBW`v2(99 zZ{)hJ;tQ+jAuGNJ^l0r?ot)XJjoxT316NgI*xq~Yyjae4VWFLZdRAZur(C1q6= zl{&t!QSZAU`D<>w41Z9@=U+0!K)1Sa&}xN_fZH#u=syADQ85ySx-C!AXYl*iug%y_ zU9v2O_OHuZmvIGCj+!*~`nYAioC`6U+%is37)IgC=!{^ zRVDz^G2^Y*S68X*=J|l(X>nu%y}A^Tg;yj3>`mv!w3Nr}&UZ!<8K*p3X^C9a1$kuf z!Q;+ryg>8}DMr(gZ>p4OfVqM@ME`L_1$$)G)M=ZQHtp+$^pGG)v~4|cl>5X^YVc(X zKJ!hX!y1vp)@Vj8AZ*Oze(u8z#Iyqg3T7Zk5V5kcP&y2tVIJiu&1*kGc2b5)Z5gs| zI&m8=xfbcreRNTl)cWysa7wL$9|mXQ2;1EcH9FfE!ku^KhqkvAkLK`h+}9e*4}=4_ zb?}s;nL~v-B@?h{aF<(Sl`C-c-E!o>1fm9CSPBQJdhac*a@#~IHe4JWohlMT8Y-!k z502ZevPS{{Ms-I1=Td;nWh1c7kD+>`VeBmgoXYMVPaEeFsXgR?-e4K+bO8pFfOKe$ z4luSs_mQcCVeSMx#b%ki@fcF0felw$QZmGAVIX@h0O+i!N=S5UxqDLs*mN#8{xVro z=?v>8z18+e+m(LS6;)~OE%n`K0CGbwIm2;iodtU(p9EHtO+zeY6P%rUjXaJMWzms_YR`KWi*>vMjwd$-v+#z%{Yh^RM}ytre-wW#6%K;)xA z_p?rENMI@~NWVWl7gv+W9uzrmu!yj5-*jES;7*t4D;yjujwW)j&BK)SlI zJ(qE#k39^RY>JyfjZvjYHpn)zVh?HS#~;&>1Q6k=W`P}VfI#~Jl$^uNN=gGr4YEO3 zA&51L;}gL2sCoR-dq;}u*w@#0t&0i~)lZ0zrzqsj1RBjaW-S#+<90V7hJ=Mp4MYHX z&5+1QjvV1L-z#yz@=sJ$6c2FWltIA&px%nCEvk6HFBROY12A9V7wS!!EDGO%!<&;g zfQy@>R}1;WnS(;0#d zrqkt!|3ru9uMm>m7FMpbAOwGQjBwz9hOiJd8BAmz8}L1DoL!l0`zqQkJ>3q|3+U1y zb9NM=^4E_Nbc0^x)SwSWf7lS-AUzh zZ}7Og;MJ^m`?9fVx>x>>_~(D@NA2P+>od<0P7|=F{_&9nx2Oc8vPV6=7P$Yx*lvG= zwV)eMno_Z88HJAw%pP?TUm*U+@5~5a5cn+)L^S`&`CanA7+gsuXt+uvUL*JuNB#!Z zeqn_=1N@D5Bp8^Vk~Tt~5+KJDsFBCi{|p%Z8ALmp4(1=+ue=-UoqT2)lyxY(2>7U*gIZLT&e)(Ko;)5(GsWBv?sg4 z`&qk(Oce?2OLPy)8q{=@N^m%l5p~kwT;nY8Olm~}irL|2IK=?0q=!m$pE&;44EG6$ z?qA|nfNNdzhDJ;K{`*PEli|b{M2xZBxl@?t5UKBVBlg@g>eOl4~8IdAGFe zBXDxId$^d}dw0}vR|#lgbcsFB6=?z9;d6{BV3zvaCoRM3`uHdRY}eCpY(t4b&E`lx z%?TTA1fM4OKv7Fl!7=hF!7=(JITpNBxuq_s#1g6$|E;)%u3YSoRqN#~6d^OuxkLYc zy#^{M67E2xt?Z%#m*I%gT5maHt3e=Sr2Okh`&7YR?shhM174h()ds$md%0p^8~b0! zW^H|#+Kz>RJ4+%EgennxT^k~zp(O%z@}9%V$;si)$0**@U=o~(Xi|}l>t9j0@wSta z)Sr7}s-W&uDvgFWV_Pk2nAoU}XhT+Q3IlMwa=bx62i+pN#F-dG><6Y%%Q43docoep zD{a>j*aaPB-6s`PQ{(?VEB!Hpz~QPLjBrZ94ba{|UwikXgy(KtE3R8a@6W!y-2`kw z6M%*s%|KD~;-nXiN5=gjJ~0vU41OyY%EatU6(OItU#+-5H}yKd-BQeb9z!Gk@S1h-{4rU5^g`dI<0wWy00> zsF6u#5h8R>oqR(;K=*7Gdoibv%DwXL<8rO0qExhKVX0R zpHO;V!9V1S@LEOco~G%xf$6|>)P5X(*?bD2H~G-PD^_3XE+>>F%siZOwwwoJB5 zfb|~^q0THehF!KF<5N;o`^_FTobiX}9DTtTu1mddlyL{<<_q<*%mj0@WGQ1LzNzgl z9Tu0-RNAvYYN+0x{PPa*zah9FIY2Jh$?hTl(+gmRWo(h_H5y+(vQQ2y(SGYuN1VF8 zrz&9(%M9|00ICVlKIe2sU4Iz3xo;F@dHrFI=+d!s<;$fH19tR(Rk6o8AuVH2yo5o!H3ih*)~0SC3G50 zsyAT;EiV3Z?=oz+erKr0cD9OFXyN3Ksf(H|J8D;qCVkh$9RI|V>n3gUgQeS9!G*J` z#k?#uzky6Wql!`~=IyFE!6C)J4Y^rLR|hMz%nX*TSD|bg6_BZ7`#ecO1bf@ES2@K9 z=#ea@U*dUVyfJ&cznSdx_O@hk1Fl&|?$^jo(`qHJ#xHYu#JUJ|idY(}wIJp_6s(lG zr9_{B6o9nUh;Cw*l!=B7SL)??F?~UI;`f|zm|jY&{XD?ru5v{PAmv3(bSPsU9@VTn zFUTou1wyu63ptqHnZOEbwUTQI#{oV!w}piiJvx%C-DoG` z8C?n6kFMs-p^UGEFns+cEUm5Pi-S-Xk3&&Y~P6&5D(-T#R~z2ZJh zaO6Fjkj1c2OS#~7I`m#(p{Rh zH8SO`={j&ttC@Is{OFH`(zR|Z4{m+bpp!{Mvm8}27=5up;c_bS_E zLz=lXq_K3$E3L(Q-@C*Z(8D4A>RlL2q#t=q`L&;p67lH+E>QI4wo^ z7kh_?)9Ih2g@k9z90;X5J|1_`ZO5J!-FM_Ur3PFkcN19^645%XXl?|RB%FYw0byZLrNIc-F z?CVDL$&g9@Xw3z$r1GL@A`=S;ZL{M zPlE_%-vh>gwi44d=}wP@X;wYf-gnwM?g#acg=hlzHVisV zE!tywcOBkYJxD0L-!qyFzB^#h#;Mq?zPPApgt-s#b)hj+mbz8QcC~glZ$ZAC{Z8|Z ze1zoavbc$%p=CI=Gl0Q~P4VR9^TwyEh$`I{tFP#{MYZQ8xA($z@g9N)w+OjT{lTfQ z>&BY6+V+kz+g6liOc4x0D7G7K;Fd<8X!f$Y>{hI)Ypd&b>0PuT;k&iie;MIF#@irE zu%ZO}6ij;}HA_VEycl-ax33e( z8iK0z8RieyMCoeAy;Y}%lFak8Jc}W(^hxA>aqFC;Tit||g%k;s?+SML8mE!Y!;|2s zZcxC*s(JQ?LOT0M;bHUDW9e)k>Bj6C7MX7YZ4W6nVqd~SLK$`Lm+FRzkf!5?cz8|; z4b6T0<97##3ReE?DdkSzqGJTUaGaWsck%{~dU9);w?prH5)27^X?VLs(d45WCA{jT zu5n=165oPiG6N&bYJ8a${4FH_GB#>W?OTjXn>VIbsiUf|gJilRK`Ke2Z`w-2)f zuob<<_^fto4ZcIzbjz20B#e<&fAQ)F%60H=sHj#QhG3@+(w9UQtCNu7EUuZm-oHVN zU~SIWtiQZxoYI7vdafOZL_07d8LF~|=*=tY%t@!tGHW`f3&qo4qnPWi;MERxJ$IhgZ?oza=KZBJ%SgAwfWZ{?~8kv`fn7URXK{uR6e-vkSnNCdN1_;6zKtX;Ars z6Gil$;rfr8(QiXVN+g->@W|h(wn&x z<@iGCr}ObeLOSlWl|1LWvW)AaL>n+%#lE^}@0z^=QQ28V*g%R-0dpsnkx! zyE8@02W3KnB3HbU(u{iys7fE2EC<6u(HWdN7u8KYva~Z9W_95bv*`l8{~urP93FSS zbq_bTZ8o-THc4YlW7~FPtFdi2P8wrk8;$M8e&>FkgZuoRbG`o!uK8*{*n91@_ToGD zJFAYq3Y5z}Auy#K&RAPvEdBdF8}Rkk`X_*jfT%C zniAQSb{KbqX-by1fc~N0!Rvsm{R9piS0ek&Q>%FxDThzpGHHUehD2tHxQ}D0z+UDG zGuReu1Je>@Vie-WUcH zS;;Td`@Xn=l)338LAie!Fp0amHvRSemV9GVQ&Y+D*5NtGnL=4p(|px+kPlSm2U(Rt z&$+OOHu&{>ad2fkP#~OwAUvXR%AnQ{0ptdktA?N{h+LG0VbaCkB@BH{vtxt6&`X3a z;YT4>aV?n5O`qJ%;-F2eN8Z6HdOxlVvZ|omme+MoRTzK!tA{WE-(yE@V)q_S6963=cYy=f(L;AgU;<(2M%6-q7mL2%2&y3eUbN z^#gkANiqjZ-enA0Gzmw8Bo^K|(Z*mxeK_C)943PIlPi0<3abP7`WzqhMKNhzPcq!RccGt|Q+X{m|L7W#x z5U#c|z-TYa8WU(*4pZV0x3dmlz<2ps7a3A#ssKzA&>%lo1HibmP=$zK>zg5%$Bbn? zxG#@zR#_fKi85K^vD^aRk_>U`|kR^CGh}Y$>Hrv4ei4VVHT4`2RXaOIck+9(L4YZV9EPhV z(}O)L5J-LUzSiWNYB@lt==8KQCg*3CP9^{_r=_D)8PodM^@E9}SUh+3em!HEgviBV zA4m(vUrNT~d-P+uK!2gtY|K4`_~B3tBj)XFm?4|W!DE`O z>3Hqc7+RDthnhIejq;}K-2KYWm@QGw+`}%he_{+14B!f0Z>QV5D>pc!C7Kw5RTcl|JUJ}IztjWYnrW13;>toVnZ()D)Z*D9b z7gndFJS`dPeY(g)i4+U4g4uRes+t2qxseHb%t6#Y0I)XNVeXEVblS6w6s~=I_(G28 zpA)*FDV>+o2Ay;koTbSvs`xMMoGk^GOa5id3MHs;Lu8P!4hN)vsfxMAshJVHbdx%wv)_+j}$)YKqox+KdvbK*f@3odJg&*M{Qmlg_D z-A2!y)(Pv?w)YGJQAkKg#TdwRYj`|5p~)5oH5BCmz*JgV8YFBsJe)wG-mtQ=A_MYL z5{LTB;(V2e%>)*gncW1G$dBR&Od$ySPsCsE0_iK^hsLYSM+PD=>MiG}t~|!u-KZ6F zqCw1~@2+?&e#S9NAZAXo_c28~cDo>ZQB5e$^fB<5j1{7B=WN zo);4@ftG-NBf;f>-#ORdcq2TwME(IO&X|oO4=PkNPO?U+xn~q=X3TXR%fXw<-wm9i z==@coTo$P|3NsdHos)h@k<0uTQgJvo&rcOVv0b0&`Xlq63aXvAXiT@J9f`)*m>4~bsYpLX2h;yhFq!JNc=?XC=B7yEOAC#)CU%1O zX*kF8uQ4~Hdhy+@sSK&TUPg=cdlT53 zW|LL|_dLTVPYcG6=vFdkd4D8dGbT@PD{N8Y+ci?vLtl61UTOEm3!675*FywO%j0-&KDtbwqb_8RUQ&E^vh6W zsvtzMVVbDBSq2q~x?Hma_5eOaHkvwy#ZzcJ%u_drwNub)Kf!P_(eriGD+zYqAL*S7Lg`|5HW9tY^<4kC-@zy4<#((g7 zPSO7KUdJ)l_H0pPzwxMe5tKa|?Msv*i;T30pBv{Jrfa22ZB51~b-XX$wAmJ2RpUke zXZ-}u$|?H)#M!XmXG3fK5ozDeg~0V9`}FUWS>QnZHXl+dPy&8_KqZO{`RV;MRfa*Q zad2-rwF&8CGDOot2OOj0=co+msfqruC{3esL&$2b7u`3rt6PhUQVEf!x0_^YiW|Nf z_u`>h)6TnUlT)nEYfdOQbpBP&1J?mAMX#rcG-w7-DphDJa)R(5f&c%c0d*)82HR;E z&>4sGZS`i$gC;f19MSc4@{fi|&7VrII4+`9Q6yvj%Yz6)0Lui>D#75$ zvt`Jj8mN#lH#l#p)rM8cTj>8PYH|vJ*UE}#MQU!mp01K5Q*Tg*GlwwV2@it1wEmI4 z`lQ1O-F^_hc09X*AXr%n_+9@X(e6V7)?D-sIlL=p?3sJ zg#{Vlgo%4*2S%fNv^-~N{SG@3)a3N^^jkCltp5u<{0r|1hYk=z!S=n}crfaHg?fB0 zu5}cfB^PiU7rq*V8e2GwF#gCN?aKGn2|JDa&rIz<-`yex2sOa2{xn6XX*q1C&Szj?viE!{${_OhNDeu1y zk`Jk#ojb4HMe#}G`zs2RN)O>qbuXwv#GU3=1+@Qz-TnK~|0|PCbp1uBT!;~lAKzTgWS*thS<9wr- z=i~Lpc(KG1$rAerp=+RG$vm?}3?Ca3GN4PEwDhurRPf(d@UI0lPY%+iy~e$beUX3B zUMr3uwv)+h;_Fy;WXEPFwb}V#VSYZaHZ}}@hV1_V1pYP5UQoefVq(h5%04jzR8&;r zGczkw0$7$g6cE0Acl@0iBFZsC7EM3jJB#;3`GT&#}|t|V!AQ>9Yqb;mk2S|o1aH2ss5 z)@^&sgpHuL}#eCvL zD@)6WDC9WcTtBgt8!k{VJPf%ZS5rYjp+p!15VrEb3qutX7CT%Mo3pUDlc%OR?CfmHRiVeFU#vL8*Ti^W!^9RN1!q z|7O|cK@Ifv$bY5SuMCHWjKb~{^M;Uc2bXBK&#XO!JU)e>je;uit!J}iSJN#h5BN8q=b>8$ZSUQ; zVLk~b#T4Vc?T3B#Z%Zo=TH|s_yCXNe-JCXs){t5onnffUlIYb!HX&MfZy+{W=Ms*G zNVTFE`iOof7{leRy+GL2L2)4(^6iylAMgmposwX8#cdy-HoVPsP2-&5bitKt80vj9 zCo+o(T0?qGV~y>(pCAkiz+j$0&C$9Zh@loXQ;=x0%~8XXV;}0pp!Y*NC)~%w)Dt6g4>+$0^s=3<=&7g_{N9K*tpfI(Uk8U>A{bkSB7+WcQwO4dafns6dbFJI zDb|gncGb3lzzpIzJaiA@N1rsZ*Ed@oMNoeI=(qI}c!>f^b5ZU1uY|b8VT5zRLBrt) z*5~&h=Ox7LO9Z>jZsAAo0Yt+ejU^>g37zsB8D#Q5oYwB{?nFgnjLV~39bT%aSsa`g zTpiW|JO+Q-7FKKhVz#(tS(q?Fj)`^CdB5_eHd4MI&*Hs{j_n{{^|RZ!(fU@8`Qd$& z9DV|<_|d<8`+jgqtj8!GR#w&@6@oSWhyCM@S5XxD9YLZn!g7zRoN|w*nfhul?Z|%l zhxJzt0}K(V$X$L-kc*BLY4*v$*v> zvPX8zZRhNhyMXRPUrt6$m1I-`N5{(pea>Dhd+^3j844md|cwOpV^(iiXbnSfRsRvW82-my~Zdz>Z-vbFn-dA@}k7n zk|1X9$?C)eCo>slqQ6gr)>Tml?n;WC+ZO#i9LS%u> zHYoS;^9v&T+_KTFUoF;M#B$Mg|w==Rz>Tp&h2JdxLv z*Wwd05W_YE*jP+p?i2b7=AT++==L@sA(f0X;fw7qgtb0|`@r|2sWO1hSd699% zAoV>t{2vNyVH0r`TalzU+%QP;KhHaz{5CMffuKMG5gxMn{I?Lz5Lr+-3V60{ z)NY|B;HJ)csZKm>HyB58z&4k8$XoKVQe>7mdk1bhY=nfVBl+Gjds{6vE~4eLQWhy1 z=ijd~uh;_Wi{1-SD4J+u24VJE)q<6%s2w!hah>1?55fKik07jaGx+LDXxz3_r6n=l;S^*8YVI}-ehip~6EE?LnK}<<4nea*;u|6b41a1-=XvWIC9Wv9M!{o{h)n2m3}rucl(-cMV#ri)YarF*@WpC%t-(BU*L z?Ov{@NEMB2nmIf#+>0*x-}fkjin|BPVedgeJA=xJwq>Yj;lF{PgW_$055=A1Ocozc z*leY*sdWGKxIf=K4n{-h%LW-VRqW6D@em+NT2LndkH^*>Ew-9Q^d}H0Ra#oSqIGld zS}nZd6Qq=ROel3ffs)aMm7xk)=(n()^5l<`)S{5ek&t>-U^;?WwDyPSHaWx7j$zL) zlN#2GdJb+SR11H0TpGa?zrW2gQWhCBhh)3p&Tf;-j5-IAc#(kAK&ceD=hni2>Pu+s z%=X{QCxZ>Vo?3F)xNU%*?y$HaZC)rI^GoD$2HFsIbDCrOmQl7Q_Ssfa)bF1pbqAY= z9-&Z~TvG~Yt7-FK-t1kqcbngr%I&;vtwvO|&>19bfvM{kC2~Kl<4Fx7)bGJl$3j56 zu>q*HDTp*pNO?8P^7m&LP6FQEAS5*U=OO66vbqOM7@>M91(wlUY}l9G-vz?%`P7;0 zK~nqi(!J|D*A0W(5~q~6#nRmkRoHJFyYc)ucw$_;((<7_zG zO~>n}b$zX?JC}hHHOQlwKC+Vl$UTXWNOhllG(X!;bCLx-FUaCiX4iXkcCzDC)z$(* z1e}WXMis@{L&#zOV@kh)2k4n1Ro2vK3`~Kn9vnb^)Vr;_u|adk z1KReTAs{{$ig~sx_HUmX1ru}Cyj~j06lMtJvgC@tFA0c*kTg`W_ix_c0|DQY*`k}~ zMf}g{3=W+(aYH9V?}K2z&y!)+r|BeqSrYR<_91mgZ=B1$UP$+c0=!4(@A?tXwBqRb zQM;vTY$v4tmR9h^AnrI<;b`Ky&g|~~j?vxX=b#NWv-|-h34+`NH(-aN~Y^!69dGvKIJB=tk7Ta+>`lp8fhB zhC(q}wWtQ>d%Vz7Gex1XP0m!AzYuYzXW|*9m9B;fNiHc8EfX03o+} z1xb_mV#!n3Iu5^#4a=j5Q zdVeYLL=2$rJIw3e9>sO;i(iO)O6{PlzaPHp5OSd+*;gJL?|`Q#CSd^@J0 z#gt`bbI@^X#G-Bmp`F=4dC|Hi=XYrZbg;%}+V7hYrMYnDjiq_QPAt<}i?X_9fnLl+ zQ~ub`)a0-OXkaMy@ps<%dEUQdM!yySMLIaMmd-!>Ew7r|!zUuJvU~G6VK^WEi8)(! z^~zfQtrU#4ukW^Er+-6Zx^j`z zuAW%GxB=a|vU_kcRJY#l+bRZRyJXMe9IhxRSMhk<4ogT(3>stVs7m|+a*c%4_kVMZ z&(yTFWqiLa72fVg5r*tYn#d6(Skm)mEK$t;eeA(>h5y|`pwkGzvZ6+U|}Lcox+|v)56aXgXAR~GZ=AUT$v1hHnP*P#cUbt#~&S-%kTO4 z89$LTt^`SWL51tEJXW;EJ70sjQ#6z}X#|v>+6zzkml%=&$*{>GY5Jwz>Z#$K!xTA( zk#gyBH#0@z7+&-Ba82Q7c+6;(WZ%oJbe^ZOw*~XpVIPp2nhP0nCch+_sJY*zh>5w& zaE&DJgg_t4sw0gwp)$4kJ3}5hS>TBrUkrfXi#0)*tMBrmhwdl5(Ml)yYC*Rc|K7JF zd)-TVgq!XN24=5kA)*pXRre3a5B_V{eSCqAb6(Xuhh1qL;t)xSSm4frdtP(XqKmH? zO<5cWNMm|*qm$ucn`1GuRk}9)kc_O&Vxkz2c4g=@q9*~pq z7nNb2eT-S^t(Sfrsp7G+tXvMr{=~4msA~dWwvh-VOp$f#%Fm2%_$K}g_7Kjwe z%03EyPJ-ei`75(kcE{1O#P|$UuyPxks2R4ooB&5l`c9 zq`jTbf90p?Se?}Zog^|ACT8$iZTHWrzk>oSsHil0aM3)UR;QN07bNLaQ{GRKg;Z#k zaE<`{!Bsz>`hR5YYGY4=ed)Tce)#iof+SfHf}&Z|zdF(7F5XXJIv3kHif$p}#^>j9 zuJ3S^HNta|hxgdK?aXStGkld{xl=vSf%!Zt&6g+&4VUx-rz^Y03XyD#HpP|sCFRwB zjKAxSki_qtzg<0D7aj|Zr!@W`uBm|L~@4(UX5KRzySa(LT>%7z0XBskPaNls%Eah6P)vuKyr2=X6 zkI44D?$@2CX#0+0`7dC9a-6t0go8Ju8X=T`oDgt#fpI9x;*oz3IB3T9G;ACDKdrUtOO>y#)($+6r6bXkeSas z7M>HHQ7q=8xR?i~Xj4wi#I48Vrq})T!91tSvvHczi(y=B;kp~I=m_ZH1kOdX!hL0* zd&CA0uF7XdikZYl>O4ju;{3FVOQ3`5_T{SfkE^G)fF#)@j#9K2K?)6n?F5}x_9l^+ z_&x?3L6227p3BYSZp^ct?M|+ARx4=psk###b#q+^g{85*REGz7zQ2^y1UMLuub)-r z9D#!^^iGAU5VlZ-b5gEN^gB*+nFuMI1Ds2Vr}2rTZA86N$ecCbsvhh_gfPrx)yZCl zH1sw`-1YrRua@g+aZeeoTehN)OLs#_bmIu7UOB&JJHaQ2oofgxAStx&9E~~d_vP+1 zBiQ%H9p(gSzF#KCSD-V%;UWKy8YwjyvVyPf>Wo2UgXvJ{tQ#R zC5IsqghHSQpn~*bmr0B}W6Zu?rG(#CQN#KJjN=3~ip!Yk=)g%x${DokJ^=}x<%<@I zbN&v+zTtqy+V|JnXb6M7=?g2p&By-2O7kUVIn{}@SN+PQS}wH2LiJs1m{FeMCoCsN zy6otm=!;~-NRFpJ(;(ioZ&9#^%Ac-5!YNv>*xKl(zyH<@zGyMn&ebY95k#}S7&Z}3g=HWXU zwK*x*5|fI(#F!zZ4ypHdQEvP|Dr~>tx10O0Y^tzS-)B|R2&eZ)XXSXEPs|Bw$&++H z3m#E~7~i6+yrgy(SGouJ2QPQ(0>v$VY2qddnt`$t@>+aS{D-9>34Gf*IM z+lYd^u6N=4VRPsAxGyQ?@1GO-_mJ3YfJgJnR%iN}zJ(3|^=quQF2ULpLhduIEUp8! z5Xq=gsN7WF03g?!_<4ujGp9jn>G_>xnqsSP!yVw4`fKbe@WYSA2+faY)IImjXmtv1 zZK>x%JwLY1V^)$Un87Y>_|Fk>$Xw8AYT4cIoufo{R!MPCOiU%rGfaEMsd_3GT4(Toxi&`Q zu|ub)_fmQ43`r>E(c^FfMauwu?a?uWyei45$shs^WK(l<1z*62*+d3bE8d6e^Q`To zga16Y_in8=$3OCqTRd>%L!I!0z+pDFI{>xhb&q(DWC{&noL?dQru1p3 z{zmmVU;^R1Y%MSQ`d4H?p`!qqQ-g|1hxXu*@+k!hI1jR-X$O5st;*8Joa&GI(Dfd- zi|U^1uyHZ`L9({v+9_2f4TK-GA$*A zOWKsE#P8Kr?n_rL?rOPp$Xx8e3~{l+RwJ2=B>r|iY+u{0dN{WwXoyVYIB-KN0qM35@h;h|sCP4uxziq4>nfmukh06MD+NdEWlBO%&G5K!7jzf*o0(geW*l3zCb-G3ESr9SHXWWPGzy0U_jVHq3H9Pvq1GWzye~o%?GX|AxSg7g{S`8tw@Dx=0qeU* z;hMIL*DTCpiPngb`grgCEx-F&b%%G@HIPw{Wuqwrp7C zxPGbb4NjHEfxFi8!>Qvc=fn1qoL?!jq0!Oi!#lchC{piHp8yv1QHAg;$zy+C`kJf`IQXkVUC&& zfTgVT9d-&{R!XI{Zo#=gLuGK9z$Bn>*FIOT3fSJ3kAj<99bj^_XMzaei%i{bqtdf= zP(ygeK8HR=Ly+Vgf9ku;ATIPDxLseZO|Ji3^`dOMRP;+kk+oE{Bk>cs(^ewo)TOFa zWf5qyc|uowkS4H-M^_l8>fWVp3}YknL+?vGJFMd(?^(x-bU*IkFI+Te=K?9h1d4{V zB!j_$B;RzOI4|Drg_=GZXG*8LNSo3d<{fbiS#0(d-M4|9f>5J)`Y#~(cisj;z)bkg~7@;u2lfH6dCS<>du-iX!4^1)|qO1ulp z&!0cPzwx`BDeWoyQwF|fC;ba5{R_hIit6E36xWxtV^+238)Jg<)_?}wAIbS6`^fB# zmj(G2p(ILxLB_qKqDi*h%DF0p%fe~@c6h!`n#6dqo)Q)Xyx^w)GVxKPRFzgpcw<9E7A zr-r!`HjK93L!p7$d>%0V{RRcKQ%0070jaBX+8YbkMOs&lR6S7N)U&YHhc^k2 zSv21JBSWRgq{zi<6KR1swVJ$zz8TiYl2YX;w)RpDn@>L8gwllOfw_r&i$r@Aw=YGM zVMPKrh8l-31&d>bD_D05kvx2a9NX=Vttg@@_C)tiqOUO*qvb+_5_O5zo@`0{M{T$d zYjCygEc$HpMBP};^V+pYp+9ZX%<)&JOoSu`Z)^bd(*ayS@WP9?@GXYu*?ppooQ4Ne z&YWF!lEj4xArR=`XjE`?E_eyeMdBuSh1;C5bI-MC56@?3{l+EfR;P|BSLLwhP0tG2 zzLkJ41{Bn+FcUdu!f*q+kC8IuRI`tK$kLFkRPs=R;*l*+;dv&Jac1G7kP8X>yEz4& z6+GGD7b1APhLl#rbSe_4N7j&DXZS-zhlqM0Qyz88RbJI4vM|Dep_@f*`|ZC}Rma;? zJiCbMZWnEbfkEP%E^`X4`zhK64J&F^9=}J*5BTAM(Cr`rrz6N~$QYzbF-T>xOWYV{ zYCj^!#g-s^Ob?Q27{kMmC)D~T@pov%7aR;3@@+#-7bSTltEWmUfHNJFZWC1ty|D(z z7t;0{j9h**zRev54Ixc?hrEIKv8Ka&FuG84UX*YCiMzH`y{*!%?2@`zOgdvBSLg3L zR}(te&|HPM&{9~hwPr?_U(=8Be!bW zrYJ|}D7a=OoDM4=_r>u2vTbdZbDLD#Kz`9LAxcJ75V z$>XVVYr-38n_-ZLlypaiaFuMZGq`m0Hn62=UJ*?B%+3vwr4T*13oj(CkpbbJ%qves z`T+^*fi_J~9=_4Z)A_P97^M#H@fE@zHjz^v6VJ{-we;&CNKPANUDF0#n(daMtYC_| z3u^Y!XJZE{77~L*emZ_n`>kg`$6h-WdG|3FYLt80r+5zuyP;-BsB^2rDPqYmY1T{r zlhGs+414zWO`*JzRa)ibX&n~jq{GT|K&c)&9ayF6Qi@nY1GTF>!aHZoJroGdDGH5CaZa z&1zyE#LPque0^&FL!drhAG!RQF9j0HWZe8uA*z z-sJ{LG&oo}i!ZlFR96a^%$T$eT?;jb@7(U&1fV0V%pCQ5sz3u)poV4O4<_~?A2?I` zioy~{gh{5b#!6nQ7-RiGl1!UHQ&e;IpXO!nHpM&&+rg~cxcb-eRRSc}ngEpuvi>ld zWF(W7VK%QnxVR}|pF6&w9SLawR01HnrLn_7j5ZPqgIx~qPBgcfXQ1$V0LWv;!G@U1 zVYzzD?xDUVz&6)qR#vOkfecj6EC7d(CE)(Lzbcg2n0b$YO7DHtKS^n zVtY$ac(y+6+YR*=hauvDQ#8lVKw~IN>5vsxF{fm-)HBZ`%Vbw_HGO>HB!w|hDMfI$ z86Iowlj{D21ijK&sUBDw#*@H%tTEbXEdB#j!3EJ>?aqqhWLUuQXt9gp<%X5oxg{Y3 zM58_>iry;MdouK1lfEpZ(Y~X7dwJKT4}ygehMR|u?v&~@?|R+6J}mR#Av_Fipv)HD*6Ger924q?!kAK(7)`~Z z?@eJ#Rp`<>KQx&0C9~;FOic=NHs2Q2A|>yjgy^+vz>C>O9tIAm zY1!92#wXK@*D3njLRg_~J`akH7)xHbhMl&)4OMQeE!y8;h*}Hl7mhB!(U(tH{RomL z@nlOlrc^gor|Y=|bn|H2jtPtAF{6dAtkGj|B$yl+6_glL)m?ltAP?KqbiPL*yWOTdQPz2-eq_Ujdb$3+eZ0$PYb-?A zjoI}YkKg0N8=!r;-2^ZK%dZ zSM{$LU2%=9_Dgec^wjk**bukcWG>Y`*PQ6}-n5KL$EeVMj|8LFUAh5SI&8-9fdaYA zmlQTx?-%7terOdpdIF1Wie;~$+4@e}5N+m0a*nW+g zG>R6?%8)s^b{@7p_P<2f9>Q+Tt^Sp^ml-bvhNIZ7G}vbpXio(I+i2M$R$n-FY|bt1 z2@SS!H8T+V5z6m(kaA0EF3zzDv-09n(GN*sB|ScUnZnT4N8 zYH+%A7t6BtN%Uv+7K>>G}CoIevP&?}{#Qm|$Xi;DlAn$B`# zIBT*uUiw4u*;)${2T2?b}-NlY^eT~uCD7KO|6!asWfjEF(H@+`PAaz&5N zy<|%&SnA{^=8%}QS!qcwdDOqnu9$PqPtB)O1Hr-J9_l6KwN0WgULw7Q_j-9+Q0-7jIfOd}+RpY__m|CpRe9C8i6Sz0o0|C>{Nxv4XaI@ws2i>@y3 zeq{Vhv>1i;^2SFS%-nsh8D>yJkgor#>-*M}4czUE`K82Hzu1bo_2uY6oZlrsV;#W~ zMOp;h=*@@)<~F6a;I&(AYu3=UiWV^l!ZGuYKf`2Qem!wp+D-|wANn z4|EEodMDmH+ct|A9ha>`e(z#rV325SbLV*DKKU6d=zU-2PWP3`6h!2=h>VI_c!51- z2}0a?fZB1Kf6L9yt#zpebn{@e|K&>>Y*9=H>Bkr1a&*I9hjo_Z;^ei%W`M_r4N+B8qU6B0 zR^1C>gb%)zj_*j6u=3 zqC^kZTpe6^tZriGaqa*GYlZkPv3UKK>r2MsO1z1ZsbAZJVe_Ow*}pP}%6Gf|Kjpg~ zk(rUbB7NQ!AFA zsgpAIt{nTXZ!65}yw~iOG0ulca!BT(JHj^Z`bd=PTfpx)?{EbzIeZ+W11p}mzfkaS zzmMuxad0&aQlA?6D@J9OZGbdjcY?!m?BS$~GfJCzuv;MQo~jJKT}yqv@}REu7kf5I znB9KkZO}jGUkaETxfVuu0wyo|6+b_t{?xnOxR2@;Z)p7s-EN&mqJ4(JW}zOtDM zo!+}AuGqCjA)4uWg#h2pk|{dvK(dqHf5e}Q0ns8eM52%lqE71HMJkYv7T}f6V?jdW zgUcHTcE3Soao!{92)}(>@TCfSZ`-H!&v*&oDzSLBZdi>EG>I(SrTD}n_4NlMnq8cB zal_>@cE>kgQO9KLz4J{+&4INE6VE&K&x6RPVSSrm$KUWzXkKvjVQk=1jpQ`I%1%#4 z1{ZLeD9R2&u<w= z@C$#(`euEXjeFepu{r5(FI6cVg$7qoV$RVY;PCh5Fhz^!ew0D}_L=#Txrl0ojU)Ip z-r<#8MSd|l;4YE&tXd)Z78B%Lh~wjSxpxENVWRW6yKKgII7GKQG~^(X^9)(f%KT%$ zojybUx^;oIqrt-0Mk*E5D@bxbhSAyHBVT$LWfa!6-A6@2g2-JKR$26zy1U8J;;{&e z<8H_Pd%`PRTAU+HP8R|!rwB2{=Ic<}xQ<;> zv@+6!-k$jiOA;F;p2jN^HfcZyV!-Grof#^8>YUS0me#@_Tc7$M7FAhXM-L$!Cd;+zoAiP5}Q<8Nu)Hwn1L z%Q7Vqr*8T5&(ZFS6W|;330`21>p7nu|Ea=>6L43h;aK{YK%1hO1|Jq(=9A>?X7$}# zPwpPqX}(Nsgk*MC>>ySYs|*1I23RKE^(Sa5%+51TL0nG8E{tLe@2Uw;EQ_K~K?Jo? z_tR;M_Ey()=pX}Q39WCS3PqQ%!_(-g0i7Zxmv({h^kFSf^!n<Sb zjnjiM>kXOltVm4j&-k_>7M3*9Uybn4!*PuQ7fYUYh9wHatB=sb7|9uc`JPL14ofXS zTAAUDkb%I$?Fv2d!|Uv?6MUhBu>-FZe97(%(?^=q1FwbQB9lr>L8-IQ?wIsYH6{g1 zVtXp|3EowSmx2>1U-p>M6!28HYStw7HgQ}8k)m8Z98J$hKAgfu>?z${Nacu>Nperok1<1rAWVf$gK~FzS^Q^mKu(M*fgdei zM5+*58y`SB4lfJ&8JjR_{Ov<3an?n>(-L@7_IA)B0k0MBzLz}Vp9G&28uA``)B3jCFC`D4j<_ORMW(|8Qilyh%A8;X8a9W*rWG9 z_^wN3@cd~r+`A+m%(R6^7~|kNZp)W2XdAdFyEJ}&a@r%o4&iE78}S<6sKcrz3MaLb zy9;vp*?P)d=-2<|^7boqPuZN*_<+by5H!;Y4(MY+J(PI2YbojfPCEm!D|$Xji~I~7 zJc9gFJ9Bn1Yaje(NYNw)tC>nQU~-Szkl)nqLTQfLJH4KBEatq_6M&C-kf>jCnpx(u zGAtG*OWMp;_P7O!-+YPV8%y-V|J6!zH0hU66oU(&)~`lOLxdj|A#k6X6gf1Wgvtw$B#&(Di%VDFD1!{ar>eGW?z-AJ2}Vap*& zxA`tP5LJHRjWPpnm}b)a4vF@8 zdw9?D26dUnK1%S@JEe>j5yQTS5o+-tp}FBh)p7I>wAC?c?Ds1pSQ85Gx9uIhG?6PR zA8FxvxUidv*zHq{j1rL0;S+6GE138QBo4ZL~Tjn+W(eOMV)^;0VM(MYU|n0WIO}kk#jVMc zEM-Vf`j^U-I&dtRQ#R>+J>gcB|BBw#F1mg7?4$g2#NUtY;Hf!G_fzz1dAr>fZpkF; z)97@OKV2i#SWJJuDKX@Ep1sc!CIHd0u=e`$)NWAWw~{W^=QDCrclYys!duJ)uky0j zGaV3sd#6gJlfV8xD$J83lQ#kCUsD4d&~5BHmg3LhwhLlxa~V}Zr@{7aKG6jB49b7K zy6HunL4HMFZIo7@^ZBrP@&9DoP3`kg?Wn)nufOS|NJZ(cI<@QU9p!>3OYv0{9!*Gr zKZgSS2<^j=Fmr_UR*O6!M|7jbJ(M!QCn$nxG9X{1fhSu1Lxmc{o(cs*GQq>e(JLD( zU~p7@ylxd?m5kt@Gp*;71gW}WFUjEs?(6=InB<)${aC|f5TQXln z8yWym+DHP6vZ9Ve_cZH6%LU)5IYJI+DU+x&33Ee6@&OWAi5TR4?m5MwDyIDlgXG`-XT_;u1MHxr*u*4ns~> ze7AqgJ(K|h9<;FhLZD)IBEM2EBmMy}?nxB8z*z*>Shy0QH|Z^k^xszJ1=pTL74cA> zjm5BVJS}u5fr_^p1K0p<4|NojV*4eB1Qz`xqwq0C$N+96lT(1In+h^F)3RF(!*eoU z5<(#j@^i^dW6h5rA_zD4D%S`DP;G&K2#(se&w+p-Vmk7u3alfq91AtEMTm@MFxIi- z3@zyBHms$428}zGhDDg#10Zz=+YkkND8UWMg)wY6sNMWVcGn7J{6t_h%_&c*#?{U# z;_`#RHKWCPLuQfdrx}m|=A4a44lRzdAwnaMU#6xVTDZ-xyg-H!88FL=jUI%6Oc>R_ z-4%NFyf?@mdm|AGDs`-p;1cZkI!pEm|B_MPrZV_w92j(A7TlC^`mlw-y&M_2Ys*R9 zMNrWFIla;36(=Ev_QvVN1>ve|8X2M-R`p9JhkD6}s)t)o9L5G@JDtFAQO1{Vsg=h^ zYIR$Ir(BpandzT*Fg`(ie6l}%b7lXHpC8`hhV>MCZ-V&*qJAfC_z#2M25~sctEM}? z-a*ZHts(1g`WTOR5xu|tzr4TEBU6K)u{>K?YYKi#^hS9jgZ$}PvtQN8ZO`6K)W6Gs>e1%B(lqA;f>IA>2%-wy;P`q!(pG(i+3K70gF%kcXB)Q1r zpqWpK83|l@(I3#p>A3*OT)VF2MKO%e6FDaYj&ys8k1%{2ANa0f{SD#I znN#a*a(hA&Q`fJ-ecg zDFUOuj9}W^&auW$?S9c<^~?sst&fex+S7kx0KpguFi@M-QK{mrtG#s?SnmiiL#8V^ z83Pc3yU&I@wej0`|9cD(phLrb6XZvZcmhaF%0l@;<}V>vfYq+f9QsE4tAh_*?Qxj$ z_@7mh&t|oQ51`p5FSZy+{tT{YH71Pbg!Ss?0~2=2-`b$suq1~~BrnUhH1dPL3JZbx z_M?H5rM6nN+;d>nvh<_Y1WC)dCPV;gn*B4B#+xpf?bW0XD|e*92YTN8m2^!(pnPuf z#ZHnRcT%V@pv$^KlT}+GzSUnl9?r*RNU^xozW2D4Rc*0Kb2}DsWAc4g#gvFn?wc3h z=mue8zD$KA1eGkz5Y@KxT+C{=`Ow@i5NndPz^>R+yUv*EX?UXb&l& zS*^agNayBDE@>JLG2D1*RRJ{ocX^qE)*dOwv_!G2GQP9?`Ih@yj(9<9iImEUt_-*L z)QW(InMRW=vlwj@;2caGL}TR^B`#p?b+QJQw9nn(krBW0^9vCgjM6&zMP{v0uxYmKD## zIN425;Ph;+mb1gXW^aZ$`x0Lp>klPY=Gh`x$)0rvP8oNQulE*?qMAkTMa>@b7!2hI z#)^YG7#fLI&+`a6K75;Td%>gWAH-MPS4LCr!v$SM7rf&v9dg$QhdQdY7qHkqSi|Fo zIn$V=6a-d)h&2LaVh&r$xa1J7@Y$Z**6%shYwr{$D9*0*d#Cz)D$d~BleYSRNIZ93 zF?Tq%dUc67)3}}Rs&dbaBdl}%@d3sk9hHsB8-x#vid}VF$8C*EXVXV~!$n*3s&(E5 zJ0sA#hc2?|mi(;A9*oq{+Tx-L}^mQ}~ zJ>XyRpa8DOtn@gYFjn(#D8>shXj5=-mmK*9egMoo`TA2M|J;OsT~^S?x0-#edD?Bi zluKuMeGs{eB*i>GH%g7e_FPG%=^%V+|Tzq@RbFqPP4cZVYtjhH_v&em=Snfr3Zpx} zSR|uozA8UF5bmLiIao<>i26K$B&$RYM@7cTido%f$bySSw{2M!zc5FF4A}aKgfbor zJN#t0rfbu!DkLHzDX4`$F&MHIVRixng~IF4jCQ;-f-)QzZE|n5MOAU=30&R=`kkJ2 z>((2wK`VFz5h9i$&4RvXdj5nJ)4kqCOs2++Vv(AJ}8!X%IT}N`WqQGjvf-Z z%*^k_y25FIe<+zy8QsJi$vR-YDm%hhQF`FJSlL<-#~T%CtN_40Lj^u2H-@sCKcZ>x zB2*ofDk!9ziGE9Mz5}E>XQMh@@U9g5dB8V#tSGxak6;ccg~hUi#utMJ>@t<#gU7m|MJp^wAS12AQtPWRCDgH)(`si-Kg0NQI9! zI&>?DdS0Vge!BxEQ!i-}8}Zenmf19J4*J$h<0W{Bz!nMRT(fAz#g|VnWtMV)c3ReB2f@m>#1z#sUHnC`ylH*d+SR-Dn zR$}8$%M^%7RcYO~_wNkYeq{vebNR@u>NwX5N zwc~rjn8fesZ&|k@-3;0*lv}CR!zxRC`vI+jL7!EV`qzq3AyV{^19fHg044hma11L1PIXTOp5ZJ7e5`QNT|RAK4Ju{eXA}vjc{-} zS8q`h*jPOBrFDTIA0MN9cY>F;F$+FXbi7b`0acrsoRtTq=L>O)RUkf~23(!xnEQg< z@lfoSv~fqZM`oOSJ|@33$FbF935|YrLfly1)KP(UPdF0j5G~O*rtk_lQDGW^qR=nDwHeB+l%3H+0ye_QRNo0kR*?`Dp7RfFZWB!9feJEH_T{)ss=e!fFAN>G znVfNV5xav11rW&V>V38HMX%6Eo+HG%R#XfuM(1g2hqH_3_)5=K(ZBR^sSlHYyHEq_ z$?3y`m&t|Uq6^;y`l9eF$Mhuv60(%~FZ6`~2Y4t=E2K&4CU#ZE83s5cD`;(I45DS) z4i87&)igiWvSex32bKQmxyS_0&e%);avzuU-n|Tag6Nb~9a6@H(5nGY9k#XsS?SJP^{RZWxPR7ZiZq?*QVY4}BKSEcvf%N;|)gy5KY#Ox0LQR0{28U`q0PI(Jm(w2t;#he#mzFHr2(IEU z)g?=;0lnA$ZOE?dWk=})<7sD7qh(@M!r87=Ax2mv38%&!Gir~hA|;%td`E63$A%SnW57L4-b zgK3;|i5%p!#&qB(PPac ziw%_2j|gPJTs>j|GGCa!+pSWY{sIx`PVO7;H@$N=^9>-8|DoLjZ6#MCu6OnbM1TZ;R5PH>hoS)*GP3_!s zw2&{ct|?(a3A|S@dpBW$C$Or&QYv2uto?4DH8JH2M7(U??S5`uC_4R`XTt&v?`d-#NM@!3Y+GGYab*6gh_gv7; zy-b|@zW|6W0pPJZhBd5#b4fc_Bt3d$?m zb8y{|`Sr0OVFOR?-_)y|u1~TBo2B5oGOqc(_%mnepFAK?`1d|p?mH2~qxokle|4e$ zn=Sm$mOEad+)3KNi_Sw^nlyfV(Mz6S>cR7#o3YvHo1y8GzEid6)zSwC+$!q7bh`iF ziKdvrUuY5+fY~SZ>+`8bs;Xd38!R})^;~WtK;YFV+}1-ulKq$${q~-y-S)+6s{Y&4 zH7~XUJ}&967=q>o{c4-9RW&yKKa! zU9uPx1CQojVu;;(++w(3o5Qv@|ElcMtxT78_tpT%aHdU%ktIv6sHEh@cfcTC7rU^a zT3DEd(H*|(*1ith^oTHW%QGeOO2ZKING6iv%6@ZP{xLqbZ)2EHlwJr_K>!6AC@gez> z>jAiR7@xryX_LX*DN-b~=SmyfwR_sf?WAKe7ig=P*xE+}OZq)|C=4)=V0rs;&;cazNCZd(@d8KS!l07okU@;& zkkK*@%?_6;1FDz%&aXKhB`LBqKb_rHRBoev%h$aw&;NLBUaVjEax>HO1oydsy$Z7b z?hr>ij&QBmya$!~iB}%C-ODR+e}&vfBaoK6ohjZGdL_C6i#$;C`*dqd|GV{HgdZB- z-;hZHJP6dmb|-W1LTS7ePsWoa>O)FKf~TEx!8=VRBVt;5bs?vrfFmc96Zt&)fUbRZy|}fLvYiK1Om6yv z?L*1%BbZV+|4_}Pt4<>;gBOzL8D~S=f3W|aCchM{#*C5}J2bUKD8iKSIHe<2e_%_$ z5y1Lv)wyymh1LiaCs19XaEP2E=M18-ZguJ%`88qyMiOO;ybke~@E1J+nu!wZo2Wg7ISF)mbeTr=$gp93j&ut7^H!kbFrf5A>tF%3K^0zBGrUMgPr5gaeJ#FME3ibrh^?>gC)F$Ppf;B@Tsm2646!?G zLau@WRo8=MfW5xGk2b!IC)5!lT1jD_6yPbWMuOoA;NS190tc8r1kr4)~U)mXBDnY zM>mu%9Hmf@O2}zV&_x#^DhUnXj^!#8arb4!#zKvZdYu##`t|9-^(uZ3MxTT80>>@o zs>#~mf4_j1yp!C8kbI)WNMj1Oki1e8HaM2Q$O$+LDNM_DU<>VsLs+V6#!a{X4$BP_ zVG!|jc6GRs@vQxkQ_C+{TL8;$tGRc}*Tv@iL%By)Cu9~9tw57Iyk$y3T@y7}^Fb`{ zmXdXbSrA?Ba9Zv~Cm6aN`}m+>T96Tp5xBm4-5koh>EpYY_hcrs0B(apYgJHHHH886 zlfa*vYIQXAQin@oEsVGNJ#!gC0Q$jUlMtw2OIN5gu@aZgy&j>8>6f&k^* z<@vq`-s{YC$k{s+6Dwv&<6im}#ZXsW3?}9suB>x%?!%S>iMR)XQ)aTaP$tQgTaIs7 z-40W=a7LDA;v$zH72nS%C2RhDbU)YYl?4q22rV1d1Od80ORW(xkrQhBj2|HxxMAj= z4_r7^=Eox}9H#QXv;0uevNwMujBC2ByX|pz=wzR9!}P#15i|2#+sx@rm>$8zo*m24 z@wU|xFWmVCmalNcBcvX3)J9pm&2p_e@#N0;!QH{?^~mn1CJ1OYL8&q(;e5h~>2o-$%#2Fq zb7cKdL(rEvR)~FqSd;sw8#YR*Dnlg^+g!N9iP|EW3Kvtj6hoF-Of1-v4zDpgWT(Cf zKAGOO9|pH&<4?0|P&IyGhwrUE()KJK1dX5DEXh|*UYwKfgYj1!rE+6oJsm4H91c^u zfAG$ggEeliA0qyk>(1>tc}Q~l`i)=K?CkE#j6V16y79zXk?B@mwQbLxUJsA^iQ#%o zx+gZBxv!Ko)-Cj|X|7IM;d+RYiE?KstIezAVexNe0YssrmZl3Qo~HQAx@(Ue&c~jU z(Wj#%j6QiId9VtF$b!-^YZTMq>LS6JUdE06RY>9uf+XR|I4e-e%qoZiqJ8Uq%Owc< zAa{+?V2qcxc5x|S`nkAR#F69xe)EMQaS?ejAkS?FS%MW&E)(g@LyPNN)wt_4$4RON z<3qb#)rf`~|5NGbDj|h89So?JM2kkd(t>~R8FHBxArwIwW8Y9zoSbLTx|=VumnEeZ z$MolfWBW1|z4w83?MjEU~*#* z4HX;g)tM=X+kSN8vcNAs;6;@@R`+i{zUOAx@I8~!jIV~#nut4SeM)k?hb>-l@>1NY z!*#mZzDqaqQqqArmBa{x-Up$u@r!b0Z#2&^9L~NRV_){xpu`PnEH-UMm9hp=lTQ{w zsc^rzi`9?|4%|1^uq1(kmEtHNpPx^r_U1k8#DzR2R+wgI9g zR;W44FP8;FxnsOtqohW5o-}B!Ci`z)+BK*tCRLY7ud#YQS7<-F+QGZMcTzdd^JlO7 zF!;Cfu<`n*9E2HPLvvc#RaSqW_m9bAig`Z0a{5nTJP5qh-a*spebVg&_SHD=us*fv z^B;V)Oqs{hAHAj`A;(^i=~+|Uwg^6P-f70EcqC(wX1Zgm2^=PwA&h5QP+|b9e^cnC z%19?WQ*j^dT4zREEW>Q58Jd~E;obr=(&r&ZWb z2K5rEJM4}0A`9*T7M(8e5bQKnvO?-D(5pVN?TL8Jt5t(%*Z6i*J|IL?SyFZOAvj3$ z@F%4I^p|+FGctSB%nbP$6NR5HS(!R51Ax#58D=jBJ>X{ULN_dc@)=`89tlQ=kJ|xi zhxG1Fn4g}>;mN&(wB5Il-y =9Q9g_mj{%R+YGmj2=$Ho4YDR$IbQ4{=6EPV>u?# zMPX*-e4K6HWAYkzjkf$mUntHhDe`O0s148Wcj=TxmP*9kP%IXq)QaL%`-kwjpfu4k zMks%wAr`AX-pjY%4(V{ToFaK59>wT1*fi4c)Zz9;WEm^oc4k$ING(v#7z&8s@bR^w z@O)6iL~SB+eQOnQZc34hjHs38A}bgepnw}yR|_MObo zQ5&CTWYg*l>uN>JmP~r0241dL7tIYWZI2mncXhEJJkDXPmbx?9V6%s8sAx+=8f(gQ zWOXy6f9>iWy*$j805x={V)v^FyJY$6_!iUp#P4pl+7}B6VYVOeNZ%+v;ah>x`S>DVS zcpQx~MB!Zw(1b+ciXiDkD3e*>x;Tvpe@1z_Lnhu=A9v5jv`OL>mfa-y_el$t^jP>{ zXpug2(gZe?AntYjyb)pwIs|c~nvaHM8K#H3VWf-KB?{@Is_|4zU7LY6Pv%#;Ht>Lp zNPiDCaC{^VMft#u+5-nU;9KE;p_=V!2zxfTafAj$K={vUYlfsZ>2rE%GckyHSu_(w zAc2OHoWs^$o!Dw}wU!FnXD&ZI;iU8Zs;PXIne`tGj0&ly;tIA{0F zSse%*bEnWDTq#^-tBOS@YVku!gxtfc;YI8Tpr+xF@QcRLzoBn9Ea-q|&vQ6WkqbvM zLJl8T+}-87K<|8uYLJv16Yn*cqBP8^BV)cS;PxexS1&YP~@j!DkT(2 zg3&=Ivss>vl+0r*g8KR0CRPOt8k83mB(pjCp4Yj9iRS;d0Fl7kctNGXYf-s04~VxN zWq1Dc2ebz-9(qlu*u{FqSY7Hz~}STh=@E3Xn*5=ZZ)l2(!oJR7*zaz*!#N- z*;pmT5On`Ws$eq-6&B;YOh2d0?leaQPugZV#S?f%42U3}f<`ga`6YD4B>h|VwU@PP z+0HGgwR8)V|I}!}W=2nKus>jsg|FD52|GK`=d!eU+hG*GpU~)7q^V`H*jdxi4+3zA zR93|PNizt>YR7D0RNNsG5xtCZBt#Urq!lrOgAli)P3QgiT-}E~&a!B$b7366Od@|f z(dgox(QNlIS;(f`EvEYvR6h zlyi#ZQPx4Qb`;zAtEJRJ!;uv??9=P{2X;?4#-F6~GJB8tPEpR*rSF#m(?FlN-1+-& zb}RIUCcY>~Tfheo~$9U|G5uN~#(Xok=$qAhl zpFb=y?Uu&!6ZQ{&6Fd;_z=hUu9#JUAY2VP=2v}c1 zKZTZc-G`L7uSclE=-KK!BA*p5|BX3(#8@!x_!SkxH=5L2hB2m!7g|xMm zraEoeW+g_Bx1>b$9_Y=P?0#^u*6t>MXjnyGz(;)s_K3-U*nV%QLCSET>!>s>p3ixm z{kGKZLcigC1CO)f18w(qzsb>Y$Ur8SW1Rsn7rAsB?WA|@c6Z=QP7r3QocX#N1~1d< z%MBQ%u}gr;sWyy)6%R*0v2wBiT8cq+kU&PU7ag>xDm3aDj(9v1e!IG>po1=Vmi)U7|5r!U3NTz8*5)v#r>xXB1R2Jb{*XQbl1-G+H}C|Kp2U8; z>f49n-$_X3_b8__sWiy`2);#G$ozwE+4zezUTdmO`!!gKTEEr=;l}gcI?BDVyefR{r%S2e1|z#_WwSTl#{zxMRW}!|Et)~tA-IJS8UFx6^;yU^ zs)#|4!WZxpAUcsyy4NZjt#0j~4f;b^ex8qZPNyXeZtVs|tw(8Et1YMyHs44@-3Y*D z0Lun*I#MATq|)ec!8~U8>xtr4uN!M0dk$(?{%_i0Iz`+Wzb49tdxu-LWk%Qdmx9i9 zuhU*%TU&M>sO{Y^4esz)@Co-)_GId)G9E^>xb;TU-&}HhCYBD}rI5!rgvh7<_-;;1 zJD=h1#nHHh8gW?f70qLw|2|Y|VuP*?aR`sKlBB_<;Sc^$c<;!#-uE6Y9~BSj3*(X3 zt&|7>HqaSBarvy4es;HgJ^fm6_2)+H(Z~-G;&O~jJ@vm$zWM|`h+Xvf+9f=NpxGv4 z@(b4E3hG(Eo&K1@_zP6&-}BM{IQ8C zmmbvfdjh_<&C2#U!g46_=7QF8r6}eDc#Lq94a0NY5^w054ebgf88c|gaGFF4K^rTw zx!*E~HNCBr0EA_AhT*DoRqj~ zx>=yRN;cwiCXc2S%^RVe$}ZG0aP|uThNtU!tNNSbzpmc4Jd}-@Um~wD&39{br-8rR zvLpQQ>)XG;)WhWR zNKtjygDG_<1G%I5(W5(t}s8S8W}&n9AV!x-7d6R>sD+SlS$d6}*+QA$={# zbhs5m{^i44%61~C%QG*;q(t(3Ib$)clgzn8N4XiU-_&;D35lqj2i6b>`dw186 z8$popL_~*vEvFCIwOl20C0T-5DB*p-7cj)Ak;7fW|62m7B%D&H7j9e#t5O|8yy}wj zbpb)geN$&eY!e-!1hHl*NUwel#B>_@YCM>Lj2j3{uzAI84?TDj`bvWH2lY)f;=hESEksaU8P%uR z<_U9Zcko!QB<_yCu1VmKV2Tn?@IrW>ho8UOmJXdxJN)nm-QW*VZim926n+X)LP%mD zQzyB;xP19H31b7dV;wEBw$Ww$=c4Lg8d(ne5rYA5uAY=C0U*yWW;7c`;{{4lP^fB_}oym-4HX zShHjLa(8xv`>OXE$`(;EXUVrC=$0FB0YDMo5+Z;uNT8W8(9+UUzj@W5ez^_Kedd2n zn!sP3+fIyxiUFa^C2HLzC%LKcK6{i-Y`y0n%e1(Awv@En^Swj@gC~az0*a9ex*@<{ zTy-Cqbl%ew0Cqhsj_+hR6}2ZzsxgYS2i z(N^cd>sM7?uEd4!b;c++uSoX)`~}%aTVaP2nmqR<^1cnxH={<=|;bpt@Wy?%va&LH zU0vH_4k~JDV0gJfDg45uYX$0H#C4tGQ`XKd-mfLz^*11q4H*m)uE#9Lrx<|^g+0`I zxefxTxukJAkr^6-Mk(O(`||K4NQcH`H4C$IsZttn=}*5>Nkns#z>a;{tsUwCXRn@_Gc{y1A2=J4>afO7IPVcHu{ z&*Wi;tejkPKV%Y?br7Qw_QjjOMlK^~($Alj7m_nT(a8bJ06E;|sxiwZI4mr4{vDFn zyQ03XZjM*3TDKDk9eqLGYyonUz6Rd+LLa;1LG8@@_E6GvG8-NN00aPko8Wz13nk0( z`)FOsX0-yY`E}aSzoOIh%oKf3NJ|R`lDc>Eqv(34@`P31iQ{7+5QwYU6^dmjraobxSa{^OXYK5noV+5 zrfu8EDVTzR0pZ8XV)st_WtWnTEZ?*7n&TL4cub56)$>6z3?%~RE(0q_9!`rwKbHV?XPMcwbTTaF53;pW<=-dG2miUxxY)&o}lBTWyUrBD^b zu`+kgzgYl$kYa-?k-G-^CMobAe3)#}y9NUsEuVvS5omjmkIOybi|g~D*Vrbcs-d<< zHV^@ZM{Eo0%aCya1M207WFJPIe|?V--;YQy12AY!C3gXd-&fBhUMy6-pO|zV`AJqH`e+n!rpFLUw^pRKb;o zipKZ#Y-6#hX$WqzKLkbSddlxHw~FnmxyEKW!BY@8JqGp>T@QUnaX3jcW}ai6{=GN& zI|wQTO3Kl(jtDY?g<%`)uR(#o_S_nW?>dg|3+UYg+ib7Jr3N;1WS2q>#$btnBjdhL zUCSUSj&oJN;%P};5WE(CVSG_gR|~+~@9DAqmzos_ZTMc1S-aDSCW3_jbzxln+5s^f z`o`601dm@DoL0A^1*npF1U>c0WwOcmaMHK#A>Tif^FK#${oVvp(XZ-&$lv+A7;JXK z*UK6UCKvQK7bY^$VsYL~a&Vg4Vg%ldB`?4L+lHbHhI(N0U& z710jrHbJkG7~1#IxLdU+^l$e|dAxs2r~0)i zoej?W$;&VWzDrGE^K0j60-PtVhwJ%-khTlt3wl-rEH5g6QBvYhc!1bp89QkCghI^B z8v&dSBd&)qTQ0%-uc1CecaZxuh#?xJCQqAnI8*Sj zip)bVHDN3Oa4w91FpM)HZ)MEbF_y*IkZPGT!M;ggIcykm)rsvjg^GrzAq47>lMW7) z!~n?|8I}VKbGLSv8=XMlVPQI2Z$ILyzN3FNv1&K~rvEV+U)V+%W}0IKM=Di=JAK;<*48!s?O<9_H4af z&Ew=MHAxcfN61%JnF5dX7qBMk0^*ZHtwrC&_|W?%6BmA)faf2(ZRBUBU6%&w z@2-=wa#Y6t!UZKc-lDU*WcQBPhcQWd96C z5UmJLVzlO9yH00o+K%Dt=Odf$yub$x=+GBXZ$ERO?A0@b*sAId`t8MI+&CUhm+*q^ z$zv845z7r*8WLOzy5-cuW|c~@Z@pM$FS;E*2+on7*{hwC-Jr>L!7N@d;G~H;Z%1Zn zER5Ha!#Z*Vm6#@)*G7G*;1Kw9sbUC|MR3TDr@=&TCbo^iv#)L4e}8E1ewSh07tskr z#8)LjMv;^zXdTPqbi&epcq+cBsGsNsrYqOR@q}jtjc@S1g<$iz*W73u@^*~(f}@}a z{&}m?sE0g*=-=InZQloASwDb_+@FL^NvMT)@~bmRF`Dkz^~+>x0xy>9-d;RGAPF1e<>9=XFY`H0GIuvDEr(|G4_{#+j z5Ogu&DPE8k_DBJPs$)^MNYI)6I$Zf!NBMWfcZUkDIleOF5X~dX6K162_kO?BWRnSd z$)w%E>4%6yp*^H4gwr;lD~w~fANO`0=ci0E1%&-qNRY*Hnt+~EHg8zwhcZ{Sk6o;{ z&kr4d1H!-=2nTe9=sWKcU+FAY?LUp;2oPwEI?qV^bw#o`UVtxm%RjWP$)NvPy~mP* zQ}`u|F>j&oSxTH_E*uQMl7lKSv*Hv!IxMep2)2~ym@jDX!rrkVzeg}+_>_g(J$}JP z^sqjY6f8+Tp5WpLTESR2`9&wJaSsrTcd?jO91M^3Ab|2*$0maOfjA>W+TGo@i%WpW5ogj zqGl%g50rz-Zlu@m(uymRmb!7-QKQ7|TqAAwrhP&|(}x)N1_!5iCVyEOfr}Gd=mrl~ zW@K8YDuRb6#$qqC%#v)+GNK?3=V<1t+m{&j4f*wLjm~JwJ*`uGFI>j-2FHD=Mg|xb zzmK=jDPZ1-D{H*8p7%8baOEYt_a_*|kF7Y(F8eebMTr@};&!2J?@Kh1|M7M^N!Zy$64aMSql_eV=QTrDtafk#dNl*y1(RHryAKxudZy*9KC{T*WM7GsjbZ@GG^CAlj zq^u~1|2F@K+2R&J{kg+RZovWU zet|u6U1%M(XAfq7nI~=iRasCPMLh=4%|Tk#(1O4w?Q}&3pb9-kn@S*gR6m|tji2!a z+|i%Tk~?(p;=cyj!5BZ%)yLI0AzO?%gu~grdY?1>e5fbp&Ta=yCyX;hG<|9`sA+EZ#|qyR z_sufO$Tbkhp#QTp?ZF2>%Ya9?afK1-4I+{cA{+7LDU&RqNQqC}Fj}c}P z%^+$Z5InDDpbiZ18|?mkw|mr?djKYk=_K-1x*Nr_L ze!+VXA|Lbv+fIkTg;Fu&vT*|=9Mg2)Udpx#i}5hh6-#iay~MXeLPMV{`;2?|LXyz) zbUe1>se9=IM&jocbbHcK&@F`Q%StZs)t=7nxJ+Ri{E!_&&4eeXW>a zR4}oQ2ok!=7ljMiLdn*EJ!ad|fzba+1XX~)f zg@lB9U~=98WR7BScML|4H`UgQUK9viygjtl-A?%-Wt2%-~kN;enwh8s&z4u3mo3>*XDutR$ zkaQiy;X{f+*0LiV3fD<-Y&RfIsHmnRs$celV1*Vc7W&Tv)SQ=Yh9i7u4RBW--%hJ~ z7Z8c2`OjxG|J7B<4)On4qKUx>6_BwrE)j0g0UAPtpC|t5zw%ZBIQx@Yx;q}A0W{?Q zeM`R(UZLFFmAY~)3;!!K#elE`c5z)$EN-%Na*Zd}&dp1`LiFty~x zs9>Kx&$fU3)F%b-P4X2Jvws(-aG+V-v=!czCZGv4O~NlTaPi0E=`=JaV~v4lrBww>+OsSR8yi35C< zatDyyS;{jk6n#-&@=|(!U%sh&JU|oOVTElye)ygX2p<@EQvJl(-dk&m4Ht4NCF!j% z&W~q^7Bsh}AJv&pL;OyTELZR0QI$6(0mq4U>11(Gy@7kOi;Plsdx* ze1`))wJde$>wYvp`9M?D85;IQGylP5{f{aAkC48+2&hcAZQtO`phZ)ih2@PR5wm(4 zs^Wd}+mg=0tXY@RF$&(PuJsGsA?VAdH}0KvY&Bm|x>f|ZVJVqeksRMt3j5RzDRdgR zb%e^7A5}eliA#d31u0 z?L_eB4Zd8?X8sWc>n`^VHd^w~I~0rY zRn3=Tg+F*yZOcDcsUl;A$|(mdNa=TF&YiQ4o{&@qmXDO0SBafhdg?WktJS-47e78Y zlT})J-!)mT>IF{yn2-d|V&f9g7h4}2J5Q1VoZL7Q9z|>*8XD<;ZIEMlN0nI8_jiOJ zDrD5dCwZw+bZEiR8X-5h8>Y0Sn+F|vPf=X|_#eRnoj~92a$q8m&*gi{#ERik5Z9yO z@=yO=4PJNCnnF<0I|_Zq?kdq&vr?b5yB+fGV|NRYOEzn5Yt(>^_NCYX!4|5ZKCr5L`5 zPS>aB=i)N^aQ=)chbNBa!Dmt9c0;{O!2TM2%E?%cq>42&^+?c(Zg$8Yz&u+(InB|E zI6ZewOJX1pMMU?sZ&bbe8q#qekr%TO$;&2af>wz1Qk~`{`dL_xGN5n)aMErBQ%Ybc zDWecv_e_GUVM>-|3Kt1mmm3mB!b3?=)MELD;c10Vz=Eh0Xeau#?wd=MZM1dLkNv|h z3`~I1u>{(LCz~SzFi#4%gO=q0=3xYUfZiSuGAyyI34Rc!jQ4d(T0-KELZYX^%q=M* zrO9JB9=Xr?9O||4)R_Kk7E2VySn8yXlf!I<<{Ubzwz{Y>|DQf%fK^rgGiQ6vi-(IA zt8XShz&w(9J;Z3Fe*7!sdghdlp?h-(a&_GoeSLT-AlocT1RYH*Lvz`3YqGjr1XG
    As%#@DjCfQNQYy(Woi_n`URS<9nJHB}D1`F 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ௐY7xG-ImZC%xQAfc05DU(7h5-m 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

    YM;@=doG`y^U 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 diff --git a/plugins/continuous-toolbox/src/ContinuousCategory.ts b/plugins/continuous-toolbox/src/ContinuousCategory.ts deleted file mode 100644 index 6a5da76c9..000000000 --- a/plugins/continuous-toolbox/src/ContinuousCategory.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Toolbox category with styling for continuous toolbox. - */ - -import * as Blockly from 'blockly/core'; - -/** Toolbox category for continuous toolbox. */ -export class ContinuousCategory extends Blockly.ToolboxCategory { - /** - * Creates a DOM element to display the category's label. - * - * @param name The name of this category. - * @returns The newly created category label DOM element. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - override createLabelDom_(name: string): Element { - const label = document.createElement('div'); - label.setAttribute('id', this.getId() + '.label'); - label.textContent = name; - label.classList.add(this.cssConfig_['label'] ?? ''); - return label; - } - - /** - * Creates a DOM element to display the category's icon. This category uses - * color swatches instead of graphical icons. - * - * @returns The newly created category icon DOM element. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - override createIconDom_(): Element { - const icon = document.createElement('div'); - icon.classList.add('categoryBubble'); - icon.style.backgroundColor = this.colour_; - return icon; - } - - /** - * Adds a color indicator to the toolbox category. Intentionally a no-op. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - override addColourBorder_() { - // No-op - } - - /** - * Sets whether or not this category is selected in the toolbox. - * - * @param isSelected True if this category is selected, otherwise false. - */ - override setSelected(isSelected: boolean) { - if (!this.rowDiv_ || !this.htmlDiv_) return; - if (isSelected) { - this.rowDiv_.style.backgroundColor = 'gray'; - Blockly.utils.dom.addClass( - this.rowDiv_, - this.cssConfig_['selected'] ?? '', - ); - } else { - this.rowDiv_.style.backgroundColor = ''; - Blockly.utils.dom.removeClass( - this.rowDiv_, - this.cssConfig_['selected'] ?? '', - ); - } - Blockly.utils.aria.setState( - this.htmlDiv_, - Blockly.utils.aria.State.SELECTED, - isSelected, - ); - } -} diff --git a/plugins/continuous-toolbox/src/ContinuousFlyout.ts b/plugins/continuous-toolbox/src/ContinuousFlyout.ts deleted file mode 100644 index 27f1c63ac..000000000 --- a/plugins/continuous-toolbox/src/ContinuousFlyout.ts +++ /dev/null @@ -1,340 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Flyout that supports always-open continuous scrolling. - */ - -import * as Blockly from 'blockly/core'; -import {ContinuousToolbox} from './ContinuousToolbox'; -import {ContinuousFlyoutMetrics} from './ContinuousFlyoutMetrics'; -import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; - -export interface LabelFlyoutItem extends Blockly.FlyoutItem { - // Blockly.FlyoutButton represents both buttons and labels; a label is just - // a borderless, non-clickable button. - getElement(): Blockly.FlyoutButton; -} - -/** - * Class for continuous flyout. - */ -export class ContinuousFlyout extends Blockly.VerticalFlyout { - /** - * Target scroll position, used to smoothly scroll to a given category - * location when selected. - */ - private scrollTarget?: number; - - /** - * Map from category name to its position in the flyout. - */ - private scrollPositions = new Map(); - - /** - * The percentage of the distance to the scrollTarget that should be - * scrolled at a time. Lower values will produce a smoother, slower scroll. - */ - protected scrollAnimationFraction = 0.3; - - /** - * Prevents the flyout from closing automatically when a block is dragged out. - */ - override autoClose = false; - - /** - * Creates a new ContinuousFlyout. - * - * @param workspaceOptions The injection options for the flyout's workspace. - */ - constructor(workspaceOptions: Blockly.Options) { - super(workspaceOptions); - - this.getWorkspace().setMetricsManager( - new ContinuousFlyoutMetrics(this.getWorkspace(), this), - ); - - this.getWorkspace().addChangeListener((e: Blockly.Events.Abstract) => { - if (e.type === Blockly.Events.VIEWPORT_CHANGE) { - this.selectCategoryByScrollPosition(-this.getWorkspace().scrollY); - } - }); - - this.setRecyclingEnabled(true); - } - - /** - * Gets parent toolbox. - * Since we registered the ContinuousToolbox, we know that's its type. - * - * @returns Toolbox that owns this flyout. - */ - private getParentToolbox(): ContinuousToolbox | null { - const toolbox = this.targetWorkspace.getToolbox(); - if (!toolbox || toolbox instanceof ContinuousToolbox) return toolbox; - - console.warn( - 'Expected a `ContinuousToolbox` instance but did not find one. ' + - 'Make sure `registerContinuousToolbox()` has been called and the ' + - 'continuous toolbox has been injected.', - ); - - return null; - } - - /** - * Records scroll position for each category in the toolbox. - * The scroll position is determined by the coordinates of each category's - * label after the entire flyout has been rendered. - */ - private recordScrollPositions() { - this.scrollPositions.clear(); - this.getContents() - .filter(this.toolboxItemIsLabel.bind(this)) - .map((item) => item.getElement()) - .forEach((label) => { - this.scrollPositions.set( - label.getButtonText(), - Math.max(0, label.getPosition().y - this.GAP_Y / 2), - ); - }); - } - - /** - * Validates and typechecks that the given toolbox item represents a label. - * - * @param item The toolbox item to check. - * @returns True if the item represents a label in the flyout, and is a - * Blockly.FlyoutButton. - */ - protected toolboxItemIsLabel( - item: Blockly.FlyoutItem, - ): item is LabelFlyoutItem { - const element = item.getElement(); - return !!( - item.getType() === 'label' && - // Note that `FlyoutButton` represents both buttons and labels. - element instanceof Blockly.FlyoutButton && - element.isLabel() && - this.getParentToolbox()?.getCategoryByName(element.getButtonText()) - ); - } - - /** - * Returns the scroll position for the given category name. - * - * @param name Category name. - * @returns Scroll position for given category in workspace units, or null if - * not found. - */ - getCategoryScrollPosition(name: string): number | null { - const position = this.scrollPositions.get(name); - if (position === undefined) { - console.warn(`Scroll position not recorded for category ${name}`); - } - return position ?? null; - } - - /** - * Selects an item in the toolbox based on the scroll position of the flyout. - * - * @param position Current scroll position of the workspace. - */ - private selectCategoryByScrollPosition(position: number) { - // If we are currently auto-scrolling, due to selecting a category by - // clicking on it, do not update the category selection. - if (this.scrollTarget) return; - - const scaledPosition = Math.round(position / this.getWorkspace().scale); - // Traverse the array of scroll positions in reverse, so we can select the - // furthest category that the scroll position is beyond. - for (const [name, position] of [ - ...this.scrollPositions.entries(), - ].reverse()) { - if (scaledPosition >= position) { - this.getParentToolbox()?.selectCategoryByName(name); - return; - } - } - } - - /** - * Scrolls the flyout to given position. - * - * @param position The Y coordinate to scroll to. - */ - scrollTo(position: number) { - // Set the scroll target to either the scaled position or the lowest - // possible scroll point, whichever is smaller. - const metrics = this.getWorkspace().getMetrics(); - this.scrollTarget = Math.min( - position * this.getWorkspace().scale, - metrics.scrollHeight - metrics.viewHeight, - ); - - this.stepScrollAnimation(); - } - - /** - * Scrolls the flyout to display the given category at the top. - * - * @param category The toolbox category to scroll to in the flyout. - */ - scrollToCategory(category: Blockly.ISelectableToolboxItem) { - const position = this.scrollPositions.get(category.getName()); - if (position === undefined) { - console.warn(`Scroll position not recorded for category ${name}`); - return; - } - this.scrollTo(position); - } - - /** - * Returns the header item in the flyout corresponding to the given - * toolbox category, if any. - * - * @param category The toolbox category to retrieve header item for. - * @returns The given category's header item, or undefined if not found. - */ - headerForCategory( - category: Blockly.ISelectableToolboxItem, - ): Blockly.IFocusableNode | undefined { - return this.getContents() - .find((item) => { - return ( - this.toolboxItemIsLabel(item) && - item.getElement().getButtonText() === category.getName() - ); - }) - ?.getElement(); - } - - /** - * Step the scrolling animation by scrolling a fraction of the way to - * a scroll target, and request the next frame if necessary. - */ - private stepScrollAnimation() { - if (this.scrollTarget === undefined) return; - const currentScrollPos = -this.getWorkspace().scrollY; - const diff = this.scrollTarget - currentScrollPos; - if (Math.abs(diff) < 1) { - this.getWorkspace().scrollbar?.setY(this.scrollTarget); - this.scrollTarget = undefined; - return; - } - this.getWorkspace().scrollbar?.setY( - currentScrollPos + diff * this.scrollAnimationFraction, - ); - - requestAnimationFrame(this.stepScrollAnimation.bind(this)); - } - - /** - * Handles mouse wheel events. - * - * @param e The mouse wheel event to handle. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override wheel_(e: WheelEvent) { - // Don't scroll in response to mouse wheel events if we're currently - // animating scrolling to a category. - if (this.scrollTarget) return; - - super.wheel_(e); - } - - /** - * Calculates the additional padding needed at the bottom of the flyout in - * order to make it possible to scroll to the top of the last category. - * - * @param contentMetrics Content metrics for the flyout. - * @param viewMetrics View metrics for the flyout. - * @returns The additional bottom padding needed. - */ - calculateBottomPadding( - contentMetrics: Blockly.MetricsManager.ContainerRegion, - viewMetrics: Blockly.MetricsManager.ContainerRegion, - ): number { - if (this.scrollPositions.size === 0) return 0; - - const lastPosition = - ([...this.scrollPositions.values()].pop() ?? 0) * - this.getWorkspace().scale; - const lastCategoryHeight = contentMetrics.height - lastPosition; - if (lastCategoryHeight < viewMetrics.height) { - return viewMetrics.height - lastCategoryHeight; - } - - return 0; - } - - /** - * Returns the X coordinate for the flyout's position. - */ - override getX(): number { - if ( - this.isVisible() && - // Make sure that this flyout is associated with a toolbox and not e.g. - // a simple flyout or the trashcan flyout. - this.targetWorkspace.toolboxPosition === this.toolboxPosition_ && - this.targetWorkspace.getToolbox() && - this.toolboxPosition_ !== Blockly.utils.toolbox.Position.LEFT - ) { - // This makes it so blocks cannot go under the flyout in RTL mode. - return this.targetWorkspace.getMetricsManager().getViewMetrics().width; - } - - return super.getX(); - } - - /** - * Displays the given contents in the flyout. - * - * @param flyoutDef A string or JSON object specifying the contents of the - * flyout. - */ - override show(flyoutDef: Blockly.utils.toolbox.FlyoutDefinition | string) { - super.show(flyoutDef); - this.recordScrollPositions(); - this.getWorkspace().resizeContents(); - if (!this.getParentToolbox()?.getSelectedItem()) { - this.selectCategoryByScrollPosition(0); - } - this.getRecyclableInflater().emptyRecycledBlocks(); - } - - /** - * Sets the function used to determine whether a block is recyclable. - * - * @param func The function used to determine if a block is recyclable. - */ - setBlockIsRecyclable(func: (block: Blockly.Block) => boolean) { - this.getRecyclableInflater().recycleEligibilityChecker = func; - } - - /** - * Set whether the flyout can recycle blocks. - * - * @param isEnabled True to allow blocks to be recycled, false otherwise. - */ - setRecyclingEnabled(isEnabled: boolean) { - this.getRecyclableInflater().recyclingEnabled = isEnabled; - } - - /** - * Returns the recyclable block flyout inflater. - * - * @returns The recyclable inflater. - */ - protected getRecyclableInflater(): RecyclableBlockFlyoutInflater { - const inflater = this.getInflaterForType('block'); - if (!(inflater instanceof RecyclableBlockFlyoutInflater)) { - throw new Error('The RecyclableBlockFlyoutInflater is not registered.'); - } - - return inflater; - } -} diff --git a/plugins/continuous-toolbox/src/ContinuousFlyoutMetrics.ts b/plugins/continuous-toolbox/src/ContinuousFlyoutMetrics.ts deleted file mode 100644 index bd5fea5cd..000000000 --- a/plugins/continuous-toolbox/src/ContinuousFlyoutMetrics.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import type {ContinuousFlyout} from './ContinuousFlyout'; - -/** Adds additional padding to the bottom of the flyout if needed. */ -export class ContinuousFlyoutMetrics extends Blockly.FlyoutMetricsManager { - /** - * Returns the metrics for the scroll area of the continuous flyout's - * workspace. Adds additional padding to the bottom of the flyout if needed in - * order to make it possible to scroll to the top of the last category. - * - * @param getWorkspaceCoordinates True to get the scroll metrics in - * workspace coordinates, false to get them in pixel coordinates. - * @param cachedViewMetrics The view metrics if they have been previously - * computed. - * @param cachedContentMetrics The content metrics if they have been - * previously computed. - * @returns The metrics for the scroll container. - */ - override getScrollMetrics( - getWorkspaceCoordinates?: boolean, - cachedViewMetrics?: Blockly.MetricsManager.ContainerRegion, - cachedContentMetrics?: Blockly.MetricsManager.ContainerRegion, - ) { - const scrollMetrics = super.getScrollMetrics( - getWorkspaceCoordinates, - cachedViewMetrics, - cachedContentMetrics, - ); - const contentMetrics = - cachedContentMetrics || this.getContentMetrics(getWorkspaceCoordinates); - const viewMetrics = - cachedViewMetrics || this.getViewMetrics(getWorkspaceCoordinates); - - if (scrollMetrics) { - scrollMetrics.height += ( - this.flyout_ as ContinuousFlyout - ).calculateBottomPadding(contentMetrics, viewMetrics); - } - return scrollMetrics; - } -} diff --git a/plugins/continuous-toolbox/src/ContinuousMetrics.ts b/plugins/continuous-toolbox/src/ContinuousMetrics.ts deleted file mode 100644 index 3355f40d0..000000000 --- a/plugins/continuous-toolbox/src/ContinuousMetrics.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Overrides metrics to exclude the flyout from the viewport. - */ - -import * as Blockly from 'blockly/core'; - -/** Computes metrics for a toolbox with an always open flyout. */ -export class ContinuousMetrics extends Blockly.MetricsManager { - /** - * Computes the viewport size to not include the toolbox and the flyout. - * The default viewport includes the flyout. - * - * @param getWorkspaceCoordinates True to get the view metrics in workspace - * coordinates, false to get them in pixel coordinates. - * @returns The width, height, top and left of the viewport in either - * workspace coordinates or pixel coordinates. - */ - override getViewMetrics( - getWorkspaceCoordinates = false, - ): Blockly.MetricsManager.ContainerRegion { - const scale = getWorkspaceCoordinates ? this.workspace_.scale : 1; - const svgMetrics = this.getSvgMetrics(); - const toolboxMetrics = this.getToolboxMetrics(); - const flyoutMetrics = this.getFlyoutMetrics(false); - const toolboxPosition = toolboxMetrics.position; - - if (this.workspace_.getToolbox()) { - // Note: Not actually supported at this time due to ContinuousToolbox - // only supporting a vertical flyout. But included for completeness. - if ( - toolboxPosition == Blockly.TOOLBOX_AT_TOP || - toolboxPosition == Blockly.TOOLBOX_AT_BOTTOM - ) { - svgMetrics.height -= toolboxMetrics.height + flyoutMetrics.height; - } else if ( - toolboxPosition == Blockly.TOOLBOX_AT_LEFT || - toolboxPosition == Blockly.TOOLBOX_AT_RIGHT - ) { - svgMetrics.width -= toolboxMetrics.width + flyoutMetrics.width; - } - } - return { - height: svgMetrics.height / scale, - width: svgMetrics.width / scale, - top: -this.workspace_.scrollY / scale, - left: -this.workspace_.scrollX / scale, - }; - } - - /** - * Gets the absolute left and absolute top in pixel coordinates. - * This is where the visible workspace starts in relation to the SVG - * container, adjusted to not include the area behind the flyout. - * - * @returns The absolute metrics for the workspace. - */ - override getAbsoluteMetrics(): Blockly.MetricsManager.AbsoluteMetrics { - const toolboxMetrics = this.getToolboxMetrics(); - const flyoutMetrics = this.getFlyoutMetrics(false); - const toolboxPosition = toolboxMetrics.position; - let absoluteLeft = 0; - - if ( - this.workspace_.getToolbox() && - toolboxPosition == Blockly.TOOLBOX_AT_LEFT - ) { - absoluteLeft = toolboxMetrics.width + flyoutMetrics.width; - } - let absoluteTop = 0; - if ( - this.workspace_.getToolbox() && - toolboxPosition == Blockly.TOOLBOX_AT_TOP - ) { - absoluteTop = toolboxMetrics.height + flyoutMetrics.height; - } - return { - top: absoluteTop, - left: absoluteLeft, - }; - } -} diff --git a/plugins/continuous-toolbox/src/ContinuousToolbox.ts b/plugins/continuous-toolbox/src/ContinuousToolbox.ts deleted file mode 100644 index 1bf4dc759..000000000 --- a/plugins/continuous-toolbox/src/ContinuousToolbox.ts +++ /dev/null @@ -1,210 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Toolbox that uses a continuous scrolling flyout. - */ - -import * as Blockly from 'blockly/core'; -import {ContinuousFlyout} from './ContinuousFlyout'; -import {ContinuousToolboxNavigator} from './ContinuousToolboxNavigator'; - -/** - * Class for continuous toolbox. - */ -export class ContinuousToolbox extends Blockly.Toolbox { - /** - * Timeout ID used to prevent refreshing the flyout during extensive block - * changes. - */ - private refreshDebouncer?: ReturnType; - - /** - * Navigator object responsible for handling keyboard navigation within this - * toolbox. - */ - private continuousToolboxNavigator = new ContinuousToolboxNavigator(this); - - /** - * Initializes the continuous toolbox. - */ - override init() { - super.init(); - - // Populate the flyout with all blocks and show it immediately. - const flyout = this.getFlyout(); - flyout.show(this.getInitialFlyoutContents()); - - this.getWorkspace().addChangeListener((e: Blockly.Events.Abstract) => { - if ( - e.type === Blockly.Events.BLOCK_CREATE || - e.type === Blockly.Events.BLOCK_DELETE || - e.type === Blockly.Events.BLOCK_CHANGE - ) { - this.refreshSelection(); - } - }); - } - - /** - * Returns the continuous toolbox's flyout. - * - * @returns The toolbox's flyout. - */ - override getFlyout(): ContinuousFlyout { - return super.getFlyout() as ContinuousFlyout; - } - - /** - * Gets the contents that should be shown in the flyout immediately. - * This includes all blocks and labels for each category of block. - * - * @returns Flyout contents. - */ - private getInitialFlyoutContents(): Blockly.utils.toolbox.FlyoutItemInfoArray { - return this.getToolboxItems().flatMap(this.convertToolboxItemToFlyoutItems); - } - - /** - * Converts a given toolbox item to an array of flyout items, generally a - * label followed by the category's blocks. - * - * @param toolboxItem The toolbox item/category to convert. - * @returns An array of flyout items contained in the given toolbox item. - */ - protected convertToolboxItemToFlyoutItems( - toolboxItem: Blockly.IToolboxItem, - ): Blockly.utils.toolbox.FlyoutItemInfoArray { - let contents: Blockly.utils.toolbox.FlyoutItemInfoArray = []; - if (toolboxItem instanceof Blockly.ToolboxCategory) { - // Create a label node to go at the top of the category - contents.push({kind: 'LABEL', text: toolboxItem.getName()}); - let itemContents = toolboxItem.getContents(); - - // Handle custom categories (e.g. variables and functions) - if (typeof itemContents === 'string') { - itemContents = [{custom: itemContents, kind: 'CATEGORY'}]; - } - contents = contents.concat(itemContents); - } - return contents; - } - - /** - * Updates the flyout's contents if it is visible. - */ - override refreshSelection() { - if (this.getFlyout().isVisible()) { - if (this.refreshDebouncer) { - clearTimeout(this.refreshDebouncer); - } - this.refreshDebouncer = setTimeout(() => { - this.getFlyout().show(this.getInitialFlyoutContents()); - }, 100); - } - } - - /** - * Scrolls the flyout to display the newly selected category's contents. - * - * @param oldItem The previously selected toolbox category. - * @param newItem The newly selected toolbox category. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - override updateFlyout_( - oldItem: Blockly.ISelectableToolboxItem | null, - newItem: Blockly.ISelectableToolboxItem | null, - ) { - if (newItem) { - this.getFlyout().scrollToCategory(newItem); - if (!this.getFlyout().isVisible()) { - this.getFlyout().show(this.getInitialFlyoutContents()); - } - } else if (this.getFlyout().autoClose) { - this.getFlyout().hide(); - } - } - - /** - * Returns whether or not the toolbox should deselect the old category. - * - * @param oldItem The previously selected toolbox category. - * @param newItem The newly selected toolbox category. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - override shouldDeselectItem_( - oldItem: Blockly.ISelectableToolboxItem | null, - newItem: Blockly.ISelectableToolboxItem | null, - ): boolean { - // Should not deselect if the same category is clicked again. - return !!(oldItem && oldItem !== newItem); - } - - /** - * Gets a category by name. - * - * @param name Name of category to get. - * @returns Category, or null if not found. - * @internal - */ - getCategoryByName(name: string): Blockly.ISelectableToolboxItem | null { - const category = this.getToolboxItems().find( - (item) => - item instanceof Blockly.ToolboxCategory && - item.isSelectable() && - name === item.getName(), - ); - if (!category) return null; - return category as Blockly.ISelectableToolboxItem; - } - - /** - * Selects the category with the given name. - * Similar to setSelectedItem, but importantly, does not call updateFlyout - * because this is called while the flyout is being scrolled. - * - * @param name Name of category to select. - * @internal - */ - selectCategoryByName(name: string) { - const newItem = this.getCategoryByName(name); - if (!newItem) return; - - const oldItem = this.selectedItem_; - - if (oldItem && this.shouldDeselectItem_(oldItem, newItem)) { - this.deselectItem_(oldItem); - } - - if (this.shouldSelectItem_(oldItem, newItem)) { - this.selectItem_(oldItem, newItem); - } - } - - /** - * Returns the bounding rectangle of the drag target/deletion area in pixels - * relative to the viewport. - * - * @returns The toolbox's bounding box. Null if drag target area should be - * ignored. - */ - override getClientRect(): Blockly.utils.Rect | null { - // If the flyout never closes, it should be the deletable area. - const flyout = this.getFlyout(); - if (flyout && !flyout.autoClose) { - return flyout.getClientRect(); - } - return super.getClientRect(); - } - - /** - * Returns the Navigator object responsible for handling keyboard navigation - * inside this toolbox. - */ - override getNavigator(): Blockly.ToolboxNavigator { - return this.continuousToolboxNavigator; - } -} diff --git a/plugins/continuous-toolbox/src/ContinuousToolboxNavigator.ts b/plugins/continuous-toolbox/src/ContinuousToolboxNavigator.ts deleted file mode 100644 index 717c7aa8c..000000000 --- a/plugins/continuous-toolbox/src/ContinuousToolboxNavigator.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright 2026 Raspberry Pi Foundation - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {ContinuousToolbox} from './ContinuousToolbox'; -import {ContinuousCategory} from './ContinuousCategory'; - -/** - * A Navigator that handles keyboard navigation within a continuous toolbox. - */ -export class ContinuousToolboxNavigator extends Blockly.ToolboxNavigator { - constructor(protected toolbox: ContinuousToolbox) { - super(toolbox); - } - - /** - * Returns the next node when navigating "in", in this case the first flyout - * item in the toolbox's currently selected category. - * - * @param node The node to navigate relative to. - * @returns The node "in" relative to the given node. - */ - override getInNode( - node = Blockly.getFocusManager().getFocusedNode(), - ): Blockly.IFocusableNode | null { - if (!(node instanceof ContinuousCategory)) return null; - return this.toolbox.getFlyout().headerForCategory(node) ?? null; - } -} diff --git a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts b/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts deleted file mode 100644 index 96b62bbf9..000000000 --- a/plugins/continuous-toolbox/src/RecyclableBlockFlyoutInflater.ts +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -/** - * A block inflater that caches and reuses blocks to improve performance. - */ -export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { - /** - * Whether or not block recycling is enabled. - */ - recyclingEnabled = false; - - /** - * Map from block type to block instance. - */ - private recycledBlocks = new Map(); - - /** - * Custom function to use for checking whether or not blocks can be recycled. - */ - recycleEligibilityChecker?: (block: Blockly.Block) => boolean; - - /** - * Creates a new block from the given block definition. - * - * @param blockDefinition The definition to create a block from. - * @param workspace The workspace to create the block on. - * @returns The newly created block. - */ - override createBlock( - blockDefinition: Blockly.utils.toolbox.BlockInfo, - workspace: Blockly.WorkspaceSvg, - ): Blockly.BlockSvg { - const blockType = this.getTypeFromDefinition(blockDefinition); - return ( - this.getRecycledBlock(blockType) ?? - super.createBlock(blockDefinition, workspace) - ); - } - - /** - * Returns the type of a block from an XML or JSON block definition. - * - * @param blockDefinition The block definition to parse. - * @returns The block type. - */ - private getTypeFromDefinition( - blockDefinition: Blockly.utils.toolbox.BlockInfo, - ): string { - let type: string | null | undefined; - if (blockDefinition['blockxml']) { - const xml = - typeof blockDefinition['blockxml'] === 'string' - ? Blockly.utils.xml.textToDom(blockDefinition['blockxml']) - : (blockDefinition['blockxml'] as Element); - type = xml.getAttribute('type'); - } else { - type = blockDefinition['type']; - } - - if (!type) { - throw new Error( - `Block type is not specified in block definition: ${JSON.stringify( - blockDefinition, - )}`, - ); - } - return type; - } - - /** - * Puts a previously created block into the recycle bin and moves it to the - * top of the workspace. Used during large workspace swaps to limit the number - * of new DOM elements we need to create. - * - * @param block The block to recycle. - */ - private recycleBlock(block: Blockly.BlockSvg) { - const xy = block.getRelativeToSurfaceXY(); - block.moveBy(-xy.x, -xy.y); - this.recycledBlocks.set(block.type, block); - } - - /** - * Returns a block from the cache of recycled blocks with the given type, or - * undefined if one cannot be found. - * - * @param blockType The type of the block to try to recycle. - * @returns The recycled block, or undefined if one could not be recycled. - */ - private getRecycledBlock(blockType: string): Blockly.BlockSvg | undefined { - const block = this.recycledBlocks.get(blockType); - this.recycledBlocks.delete(blockType); - return block; - } - - /** - * Returns whether the given block can be recycled or not. - * - * @param block The block to check for recyclability. - * @returns True if the block can be recycled. False otherwise. - */ - protected blockIsRecyclable(block: Blockly.Block): boolean { - if (!this.recyclingEnabled) return false; - - if (this.recycleEligibilityChecker) { - return this.recycleEligibilityChecker(block); - } - - // If the block needs to parse mutations, never recycle. - if ( - block.mutationToDom || - block.domToMutation || - block.saveExtraState || - block.loadExtraState - ) { - return false; - } - - if (!block.isEnabled()) return false; - - for (const input of block.inputList) { - for (const field of input.fieldRow) { - // No variables. - if (field.referencesVariables()) return false; - - if (field instanceof Blockly.FieldDropdown) { - if (field.isOptionListDynamic()) return false; - } - } - // Check children. - if (input.connection) { - const targetBlock = input.connection.targetBlock(); - if (targetBlock && !this.blockIsRecyclable(targetBlock)) { - return false; - } - } - } - return true; - } - - /** - * Disposes of the provided block. - * - * @param item The block to dispose of. - */ - override disposeItem(item: Blockly.FlyoutItem) { - const element = item.getElement(); - if ( - element instanceof Blockly.BlockSvg && - this.blockIsRecyclable(element) - ) { - this.removeListeners(element.id); - this.recycleBlock(element); - } else { - super.disposeItem(item); - } - } - - /** - * Clears the cache of recycled blocks. - */ - emptyRecycledBlocks() { - this.recycledBlocks.forEach((block) => block.dispose(false, false)); - this.recycledBlocks.clear(); - } -} diff --git a/plugins/continuous-toolbox/src/index.ts b/plugins/continuous-toolbox/src/index.ts deleted file mode 100644 index 54280cba0..000000000 --- a/plugins/continuous-toolbox/src/index.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Continuous-scroll toolbox and flyout that is always open. - */ - -import * as Blockly from 'blockly/core'; - -import {ContinuousCategory} from './ContinuousCategory'; -import {ContinuousFlyout} from './ContinuousFlyout'; -import type {LabelFlyoutItem} from './ContinuousFlyout'; -import {ContinuousMetrics} from './ContinuousMetrics'; -import {ContinuousToolbox} from './ContinuousToolbox'; -import {RecyclableBlockFlyoutInflater} from './RecyclableBlockFlyoutInflater'; - -export { - ContinuousCategory, - ContinuousFlyout, - ContinuousMetrics, - ContinuousToolbox, - LabelFlyoutItem, - RecyclableBlockFlyoutInflater, -}; - -/** - * Registers the components of the continuous toolbox, replacing Blockly's - * built-in defaults. - */ -export function registerContinuousToolbox() { - Blockly.registry.register( - Blockly.registry.Type.TOOLBOX_ITEM, - Blockly.ToolboxCategory.registrationName, - ContinuousCategory, - true, - ); - - Blockly.registry.register( - Blockly.registry.Type.METRICS_MANAGER, - 'ContinuousMetrics', - ContinuousMetrics, - true, - ); - - Blockly.registry.register( - Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX, - 'ContinuousFlyout', - ContinuousFlyout, - true, - ); - - Blockly.registry.register( - Blockly.registry.Type.TOOLBOX, - 'ContinuousToolbox', - ContinuousToolbox, - true, - ); - - Blockly.registry.register( - Blockly.registry.Type.FLYOUT_INFLATER, - 'block', - RecyclableBlockFlyoutInflater, - true, - ); - - Blockly.Css.register(` - .categoryBubble { - margin: 0 auto 0.125rem; - border-radius: 100%; - border: 1px solid; - width: 1.25rem; - height: 1.25rem; - } - .blocklyToolboxCategory { - height: initial; - padding: 3px 0; - } - .blocklyTreeRowContentContainer { - display: flex; - flex-direction: column; - } - .blocklyToolboxCategoryLabel { - margin: auto; - } - .blocklyToolboxCategoryLabel { - text-align: center; - } - `); -} diff --git a/plugins/continuous-toolbox/test/index.html b/plugins/continuous-toolbox/test/index.html deleted file mode 100644 index 1747f4463..000000000 --- a/plugins/continuous-toolbox/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Continuous Toolbox Plugin Test - - - - -

    - - - diff --git a/plugins/continuous-toolbox/test/index.js b/plugins/continuous-toolbox/test/index.js deleted file mode 100644 index f78f44a60..000000000 --- a/plugins/continuous-toolbox/test/index.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Continuous toolbox plugin test. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import {registerContinuousToolbox} from '../src/index'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - return Blockly.inject(blocklyDiv, options); -} - -document.addEventListener('DOMContentLoaded', function () { - registerContinuousToolbox(); - createPlayground(document.getElementById('root'), createWorkspace, { - plugins: { - flyoutsVerticalToolbox: 'ContinuousFlyout', - metricsManager: 'ContinuousMetrics', - toolbox: 'ContinuousToolbox', - }, - }); -}); diff --git a/plugins/continuous-toolbox/tsconfig.json b/plugins/continuous-toolbox/tsconfig.json deleted file mode 100644 index 1a913743b..000000000 --- a/plugins/continuous-toolbox/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "ES2020", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/cross-tab-copy-paste/CHANGELOG.md b/plugins/cross-tab-copy-paste/CHANGELOG.md deleted file mode 100644 index 3f9455816..000000000 --- a/plugins/cross-tab-copy-paste/CHANGELOG.md +++ /dev/null @@ -1,720 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [8.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.7...@blockly/plugin-cross-tab-copy-paste@8.0.8) (2026-04-09) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.6...@blockly/plugin-cross-tab-copy-paste@8.0.7) (2026-01-15) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.6](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.5...@blockly/plugin-cross-tab-copy-paste@8.0.6) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [8.0.5](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.4...@blockly/plugin-cross-tab-copy-paste@8.0.5) (2026-01-05) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.4](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.3...@blockly/plugin-cross-tab-copy-paste@8.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.3](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.2...@blockly/plugin-cross-tab-copy-paste@8.0.3) (2025-12-19) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.2](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.1...@blockly/plugin-cross-tab-copy-paste@8.0.2) (2025-10-02) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@8.0.0...@blockly/plugin-cross-tab-copy-paste@8.0.1) (2025-07-17) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [8.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@7.0.1...@blockly/plugin-cross-tab-copy-paste@8.0.0) (2025-07-03) - - -### ⚠ BREAKING CHANGES - -* cross-tab-copy-paste can copy more than just blocks (#2571) - -### Features - -* cross-tab-copy-paste can copy more than just blocks ([#2571](https://github.com/google/blockly-samples/issues/2571)) ([3fda886](https://github.com/google/blockly-samples/commit/3fda886d1bd39fa63f4c8fdf5ac3196b9bdcaf05)) - - - -## [7.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@7.0.0...@blockly/plugin-cross-tab-copy-paste@7.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [7.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.16...@blockly/plugin-cross-tab-copy-paste@7.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [6.0.16](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.15...@blockly/plugin-cross-tab-copy-paste@6.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.15](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.14...@blockly/plugin-cross-tab-copy-paste@6.0.15) (2025-05-15) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.14](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.13...@blockly/plugin-cross-tab-copy-paste@6.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.13](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.12...@blockly/plugin-cross-tab-copy-paste@6.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.12](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.11...@blockly/plugin-cross-tab-copy-paste@6.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.11](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.10...@blockly/plugin-cross-tab-copy-paste@6.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.10](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.9...@blockly/plugin-cross-tab-copy-paste@6.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [6.0.9](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.8...@blockly/plugin-cross-tab-copy-paste@6.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.7...@blockly/plugin-cross-tab-copy-paste@6.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.6...@blockly/plugin-cross-tab-copy-paste@6.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.5...@blockly/plugin-cross-tab-copy-paste@6.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.4...@blockly/plugin-cross-tab-copy-paste@6.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.3...@blockly/plugin-cross-tab-copy-paste@6.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.2...@blockly/plugin-cross-tab-copy-paste@6.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.1...@blockly/plugin-cross-tab-copy-paste@6.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@6.0.0...@blockly/plugin-cross-tab-copy-paste@6.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.11...@blockly/plugin-cross-tab-copy-paste@6.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.10...@blockly/plugin-cross-tab-copy-paste@5.0.11) (2024-05-16) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.9...@blockly/plugin-cross-tab-copy-paste@5.0.10) (2024-05-09) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.8...@blockly/plugin-cross-tab-copy-paste@5.0.9) (2024-04-25) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.7...@blockly/plugin-cross-tab-copy-paste@5.0.8) (2024-04-04) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.6...@blockly/plugin-cross-tab-copy-paste@5.0.7) (2024-03-28) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.5...@blockly/plugin-cross-tab-copy-paste@5.0.6) (2024-02-08) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.4...@blockly/plugin-cross-tab-copy-paste@5.0.5) (2023-12-14) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.3...@blockly/plugin-cross-tab-copy-paste@5.0.4) (2023-12-07) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.2...@blockly/plugin-cross-tab-copy-paste@5.0.3) (2023-11-09) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.1...@blockly/plugin-cross-tab-copy-paste@5.0.2) (2023-11-02) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@5.0.0...@blockly/plugin-cross-tab-copy-paste@5.0.1) (2023-10-30) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@4.0.4...@blockly/plugin-cross-tab-copy-paste@5.0.0) (2023-09-28) - - -### ⚠ BREAKING CHANGES - -* changes for v10.2.0 (#1989) - -### release - -* changes for v10.2.0 ([#1989](https://github.com/google/blockly-samples/issues/1989)) ([4d81ea7](https://github.com/google/blockly-samples/commit/4d81ea7254412ef199a270fc740c2f45755a2725)), closes [#1844](https://github.com/google/blockly-samples/issues/1844) [#1845](https://github.com/google/blockly-samples/issues/1845) [#1863](https://github.com/google/blockly-samples/issues/1863) [#1880](https://github.com/google/blockly-samples/issues/1880) [#1885](https://github.com/google/blockly-samples/issues/1885) [#1886](https://github.com/google/blockly-samples/issues/1886) [#1887](https://github.com/google/blockly-samples/issues/1887) [#1888](https://github.com/google/blockly-samples/issues/1888) [#1919](https://github.com/google/blockly-samples/issues/1919) [#1920](https://github.com/google/blockly-samples/issues/1920) [#1983](https://github.com/google/blockly-samples/issues/1983) [#1984](https://github.com/google/blockly-samples/issues/1984) [#1985](https://github.com/google/blockly-samples/issues/1985) [#1991](https://github.com/google/blockly-samples/issues/1991) - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@4.0.3...@blockly/plugin-cross-tab-copy-paste@4.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@4.0.2...@blockly/plugin-cross-tab-copy-paste@4.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@4.0.1...@blockly/plugin-cross-tab-copy-paste@4.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@4.0.0...@blockly/plugin-cross-tab-copy-paste@4.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@3.0.1...@blockly/plugin-cross-tab-copy-paste@4.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@3.0.0...@blockly/plugin-cross-tab-copy-paste@3.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.21...@blockly/plugin-cross-tab-copy-paste@3.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [2.0.21](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.20...@blockly/plugin-cross-tab-copy-paste@2.0.21) (2023-06-22) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.20](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.19...@blockly/plugin-cross-tab-copy-paste@2.0.20) (2023-05-25) - - -### Bug Fixes - -* Fix typo in cross tab copy paste plugin. ([#1703](https://github.com/google/blockly-samples/issues/1703)) ([4fbf3cf](https://github.com/google/blockly-samples/commit/4fbf3cf8a14e1a70d1368bb17da5ed0784b2d1fc)) - - - -## [2.0.19](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.18...@blockly/plugin-cross-tab-copy-paste@2.0.19) (2023-05-18) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.18](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.17...@blockly/plugin-cross-tab-copy-paste@2.0.18) (2023-05-11) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.17](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.16...@blockly/plugin-cross-tab-copy-paste@2.0.17) (2023-05-04) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.16](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.15...@blockly/plugin-cross-tab-copy-paste@2.0.16) (2023-04-27) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.15](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.14...@blockly/plugin-cross-tab-copy-paste@2.0.15) (2023-04-13) - - -### Bug Fixes - -* replace Blockly.selected to Blockly.getSelected() ([#1661](https://github.com/google/blockly-samples/issues/1661)) ([38c4504](https://github.com/google/blockly-samples/commit/38c450406e1541cd1c9c3076ae77927316c0b4cd)) - - - -## [2.0.14](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.13...@blockly/plugin-cross-tab-copy-paste@2.0.14) (2023-03-29) - - -### Bug Fixes - -* Change from Blockly.selected to Blockly.getSelected ([#1641](https://github.com/google/blockly-samples/issues/1641)) ([2e49902](https://github.com/google/blockly-samples/commit/2e49902bf528576f05f1b1eec205778086d427b2)) - - - -## [2.0.13](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.12...@blockly/plugin-cross-tab-copy-paste@2.0.13) (2023-03-23) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.12](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.11...@blockly/plugin-cross-tab-copy-paste@2.0.12) (2023-03-09) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.11](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.10...@blockly/plugin-cross-tab-copy-paste@2.0.11) (2023-03-02) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.10](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.9...@blockly/plugin-cross-tab-copy-paste@2.0.10) (2023-02-23) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.9](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.8...@blockly/plugin-cross-tab-copy-paste@2.0.9) (2023-02-23) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.8](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.7...@blockly/plugin-cross-tab-copy-paste@2.0.8) (2023-02-16) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.7](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.6...@blockly/plugin-cross-tab-copy-paste@2.0.7) (2023-02-09) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.6](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.5...@blockly/plugin-cross-tab-copy-paste@2.0.6) (2023-01-26) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.5](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.4...@blockly/plugin-cross-tab-copy-paste@2.0.5) (2023-01-05) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.4](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.3...@blockly/plugin-cross-tab-copy-paste@2.0.4) (2022-12-15) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.3](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.2...@blockly/plugin-cross-tab-copy-paste@2.0.3) (2022-11-17) - - -### Bug Fixes - -* disable copy for immovable and undeletable blocks ([#1371](https://github.com/google/blockly-samples/issues/1371)) ([5afc679](https://github.com/google/blockly-samples/commit/5afc67950643a40e913d518921c65572ba9fdeab)) - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.1...@blockly/plugin-cross-tab-copy-paste@2.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@2.0.0...@blockly/plugin-cross-tab-copy-paste@2.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/plugin-cross-tab-copy-paste@1.0.14...@blockly/plugin-cross-tab-copy-paste@2.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Features - -* add error callback to cross-tab copy-paste ([#1291](https://github.com/google/blockly-samples/issues/1291)) ([a4d6841](https://github.com/google/blockly-samples/commit/a4d68412aa3553c802f28c5e909cf58ebdbfa54d)), closes [#1218](https://github.com/google/blockly-samples/issues/1218) - - -### Bug Fixes - -* avoid copy from inside context menus ([#1304](https://github.com/google/blockly-samples/issues/1304)) ([3d4ef16](https://github.com/google/blockly-samples/commit/3d4ef169426474ffd42b39f913e0484d524d0773)), closes [#1169](https://github.com/google/blockly-samples/issues/1169) -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 1.0.14 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 1.0.13 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 1.0.11 (2022-07-21) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## 1.0.10 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 1.0.9 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 1.0.8 (2022-06-21) - -**Note:** Version bump only for package @blockly/plugin-cross-tab-copy-paste - - - - - -## 1.0.7 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 1.0.6 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/cross-tab-copy-paste/GETSTARTED.md b/plugins/cross-tab-copy-paste/GETSTARTED.md deleted file mode 100644 index 99e93c7e9..000000000 --- a/plugins/cross-tab-copy-paste/GETSTARTED.md +++ /dev/null @@ -1,24 +0,0 @@ -This package was bootstrapped with [@blockly/create-package](https://www.npmjs.com/package/@blockly/create-package). - -## Available Scripts - -In this directory, you can run: - -### `npm start` - -Runs the package in development mode. - -Open [http://localhost:3000/test](http://localhost:3000/test) to view the test -playground in the browser. The page will reload if you make edits. - -### `npm run build` - -Builds the package into the `dist` directory. - -### `npm run lint` - -Runs eslint on the `src` and `test` directories. - -### `npm run clean` - -Deletes the `dist` and `build` directories if they exist. diff --git a/plugins/cross-tab-copy-paste/README.md b/plugins/cross-tab-copy-paste/README.md deleted file mode 100644 index 921f92625..000000000 --- a/plugins/cross-tab-copy-paste/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# @blockly/plugin-cross-tab-copy-paste [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that adds context menu items and keyboard shortcuts to allow users to copy and paste a block between tabs. - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin-cross-tab-copy-paste -``` - -### npm - -``` -npm install @blockly/plugin-cross-tab-copy-paste --save -``` - -## Usage - -```js -import * as Blockly from 'blockly'; -import {CrossTabCopyPaste} from '@blockly/plugin-cross-tab-copy-paste'; - -// Inject Blockly. -const workspace = Blockly.inject('blocklyDiv', { - toolbox: toolboxCategories, -}); - -const options = { - contextMenu: true, - shortcut: true, -}; - -// Initialize plugin. -const plugin = new CrossTabCopyPaste(); -plugin.init(options, () => { - console.log('Use this error callback to handle TypeError while pasting'); -}); - -// optional: Remove the duplication command from Blockly's context menu. -Blockly.ContextMenuRegistry.registry.unregister('blockDuplicate'); - -// optional: You can change the position of the menu added to the context menu. -Blockly.ContextMenuRegistry.registry.getItem('blockCopyToStorage').weight = 2; -Blockly.ContextMenuRegistry.registry.getItem('blockPasteFromStorage').weight = - 3; -``` - -## Options - -- `contextMenu` `{boolean}`: Register copy, cut, and paste commands in the Blockly context menu. -- `shortcut` `{boolean}`: Register cut (ctr + x), copy (ctr + c) and paste (ctr + v) in the keybord shortcut. - -## Error Callback - -- `typeErrorCallback` `{Function}`: is an extra parameter to the init method, one can pass a callback to the cross-tab-copy-paste plugin that is called when the plugin triggers a TypeError error when pasting. - -## Localization - -You can change the displayed words. - -### English - -```js -Blockly.Msg['CROSS_TAB_COPY'] = 'Copy'; -Blockly.Msg['CROSS_TAB_PASTE'] = 'Paste'; -``` - -### Japanese - -```js -Blockly.Msg['CROSS_TAB_COPY'] = 'コピー'; -Blockly.Msg['CROSS_TAB_PASTE'] = '貼り付け'; -``` - -## License - -Apache 2.0 diff --git a/plugins/cross-tab-copy-paste/package.json b/plugins/cross-tab-copy-paste/package.json deleted file mode 100644 index fc2a738d4..000000000 --- a/plugins/cross-tab-copy-paste/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@blockly/plugin-cross-tab-copy-paste", - "version": "13.2.0", - "description": "Allows copying blocks between multiple tabs with Blockly editors.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "", - "keywords": [ - "blockly", - "blockly-plugin" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/cross-tab-copy-paste#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/cross-tab-copy-paste" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/cross-tab-copy-paste/src/index.ts b/plugins/cross-tab-copy-paste/src/index.ts deleted file mode 100644 index 466712414..000000000 --- a/plugins/cross-tab-copy-paste/src/index.ts +++ /dev/null @@ -1,497 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -type TypeErrorCallback = () => void; - -/** - * Checks if the copy data represents that for a block. - * - * @param obj any ICopyData. - * @returns if the ICopyData is a BlockCopyData. - */ -function isBlockCopyData( - obj: Blockly.ICopyData, -): obj is Blockly.clipboard.BlockCopyData { - return 'typeCounts' in obj; -} - -/** - * Determine if a focusable node can be copied. - * - * This will use the isCopyable method if the node implements it, otherwise - * it will fall back to checking if the node is deletable and draggable not - * considering the workspace's edit state. - * - * n.b. copied (with minor changes) from blockly/core/shortcut_items. - * - * @param focused The focused object. - */ -function isCopyable(focused: Blockly.IFocusableNode): boolean { - if ( - !Blockly.isCopyable(focused) || - !Blockly.isDeletable(focused) || - !Blockly.isDraggable(focused) - ) - return false; - // The cast is necessary while the minimum version of Blockly required is < 12.2.0 - // because that version is when `isCopyable` was introduced on the `ICopyable` interface. - /* eslint-disable @typescript-eslint/no-explicit-any */ - if ((focused as any).isCopyable) { - return (focused as any).isCopyable(); - /* eslint-enable @typescript-eslint/no-explicit-any */ - } else if ( - focused instanceof Blockly.BlockSvg || - focused instanceof Blockly.comments.RenderedWorkspaceComment - ) { - return focused.isOwnDeletable() && focused.isOwnMovable(); - } - // This isn't a class Blockly knows about, so fall back to the stricter - // checks for deletable and movable. - return focused.isDeletable() && focused.isMovable(); -} - -/** - * Determine if a focusable node can be cut. - * - * This will check if the node can be both copied and deleted in its current - * workspace. - * - * n.b. copied from blockly/core/shortcut_items. - * - * @param focused The focused object. - */ -function isCuttable(focused: Blockly.IFocusableNode): boolean { - return ( - isCopyable(focused) && Blockly.isDeletable(focused) && focused.isDeletable() - ); -} - -/** - * Return value for a context menu item's precondition. - */ -enum ContextMenuState { - ENABLED = 'enabled', - DISABLED = 'disabled', - HIDDEN = 'hidden', -} - -/** - * A Blockly plugin that adds context menu items and keyboard shortcuts - * to allow users to copy and paste copyable objects between tabs. - */ -export class CrossTabCopyPaste { - /** Key in which store copy data in the browser's local storage. */ - localStorageKey = 'blocklyStash'; - - /** - * Initializes the cross tab copy paste plugin. If no options are selected - * then both context menu items and keyboard shortcuts are added. - * - * @param options - * @param options.shortcut Register cut (ctr + x), copy (ctr + c) and paste (ctr + v) - * in the shortcut. - * @param options.contextMenu Register copy and paste in the context menu. - * @param typeErrorCallback callback function to handle type errors - * @param localStorageKey custom key for local storage - */ - init( - {contextMenu = true, shortcut = true} = { - contextMenu: true, - shortcut: true, - }, - typeErrorCallback?: TypeErrorCallback, - localStorageKey?: string, - ) { - if (localStorageKey) this.localStorageKey = localStorageKey; - if (contextMenu) { - // Register the menus - this.blockCopyToStorageContextMenu(); - this.blockPasteFromStorageContextMenu(typeErrorCallback); - } - - if (shortcut) { - // Unregister the default KeyboardShortcuts - Blockly.ShortcutRegistry.registry.unregister( - Blockly.ShortcutItems.names.COPY, - ); - Blockly.ShortcutRegistry.registry.unregister( - Blockly.ShortcutItems.names.CUT, - ); - Blockly.ShortcutRegistry.registry.unregister( - Blockly.ShortcutItems.names.PASTE, - ); - // Register the KeyboardShortcuts - this.blockCopyToStorageShortcut(); - this.blockCutToStorageShortcut(); - this.blockPasteFromStorageShortcut(typeErrorCallback); - } - } - - /** - * Parses copy data from JSON in local storage, if it exists. - * - * @returns copy data parsed from local storage, or undefined - */ - getCopyData(): Blockly.ICopyData | undefined { - const stored = localStorage.getItem(this.localStorageKey); - if (!stored) return undefined; - return JSON.parse(stored); - } - - /** - * Copy precondition called by both keyboard shortcut and context menu item. - * Allows copying out of the flyout, as long as they could be pasted - * into the main workspace. - * - * @param scope scope for copy action. - * @param workspace explicit workspace for keyboard shortcuts, - * undefined to get the workspace from the focused node. - * @returns whether the option should be shown/hidden/disabled. - */ - copyPrecondition( - scope: Blockly.ContextMenuRegistry.Scope, - workspace?: Blockly.Workspace, - ): ContextMenuState { - const focused = scope.focusedNode; - if (!focused) return ContextMenuState.HIDDEN; - if (!Blockly.isCopyable(focused)) return ContextMenuState.HIDDEN; - - if (!workspace) workspace = focused.workspace; - if (!(workspace instanceof Blockly.WorkspaceSvg)) - return ContextMenuState.HIDDEN; - const targetWorkspace = workspace.isFlyout - ? workspace.targetWorkspace - : workspace; - if ( - !!focused && - !!targetWorkspace && - !targetWorkspace.isDragging() && - !Blockly.getFocusManager().ephemeralFocusTaken() && - isCopyable(focused) - ) - return ContextMenuState.ENABLED; - return ContextMenuState.DISABLED; - } - - /** - * Copy callback called by both keyboard shortcut and context menu item. - * Copies the copy data to local storage. - * - * @param scope scope for copy action. - * @param workspace workspace where shortcut or context menu was activated. - * @returns true if copy happened, false otherwise. - */ - copyCallback( - scope: Blockly.ContextMenuRegistry.Scope, - workspace: Blockly.Workspace, - ): boolean { - const focused = scope.focusedNode; - if (!focused || !Blockly.isCopyable(focused) || !isCopyable(focused)) - return false; - - if (!(workspace instanceof Blockly.WorkspaceSvg)) return false; - - const targetWorkspace = workspace.isFlyout - ? workspace.targetWorkspace - : workspace; - if (!targetWorkspace) return false; - - if (!focused.workspace.isFlyout) { - targetWorkspace.hideChaff(); - } - const copyData = focused.toCopyData(); - if (!copyData) return false; - localStorage.setItem(this.localStorageKey, JSON.stringify(copyData)); - return true; - } - - /** - * Paste precondition called by both keyboard shortcut and context menu item. - * - * @param workspace workspace to paste in. should not be a flyout workspace. - * @returns true if paste happened, false otherwise. - */ - pastePrecondition(workspace: Blockly.WorkspaceSvg): ContextMenuState { - const copyData = this.getCopyData(); - if (!copyData) return ContextMenuState.DISABLED; - // If this is a block, make sure there's room for that type of block - if ( - isBlockCopyData(copyData) && - !workspace?.isCapacityAvailable(copyData.typeCounts) - ) - return ContextMenuState.DISABLED; - - if ( - !!workspace && - !workspace.isReadOnly() && - !workspace.isDragging() && - !Blockly.getFocusManager().ephemeralFocusTaken() - ) - return ContextMenuState.ENABLED; - return ContextMenuState.DISABLED; - } - - /** - * v12.0.0 of Blockly included the keyboard shortcut in Msg string, but - * it was removed in v12.2.0. This function can be removed when this plugin's - * minimum version of Blockly is >=12.2.0. - * - * @param labelText Blockly.Msg for the shortcut - * @returns trimmed label for the context menu item. - */ - getContextMenuText(labelText: string): string { - // TODO: Once core is updated to remove the shortcut placeholders from the - // keyboard shortcut messages, remove this. - if (labelText.indexOf(')') === labelText.length - 1) { - labelText = labelText.split(' (')[0]; - } - return labelText; - } - - /** - * Adds a copy command to the context menu for copyable items. - */ - blockCopyToStorageContextMenu() { - const copyToStorageOption: Blockly.ContextMenuRegistry.RegistryItem = { - displayText: () => { - if (Blockly.Msg['CROSS_TAB_COPY']) { - return Blockly.Msg['CROSS_TAB_COPY']; - } - return this.getContextMenuText(Blockly.Msg['COPY_SHORTCUT']); - }, - preconditionFn: (scope: Blockly.ContextMenuRegistry.Scope) => { - return this.copyPrecondition(scope); - }, - callback: (scope: Blockly.ContextMenuRegistry.Scope) => { - const focused = scope.focusedNode; - // Check Blockly.isCopyable to make sure focused.workspace exists - if (!focused || !Blockly.isCopyable(focused)) return false; - - const workspace = focused.workspace; - return this.copyCallback(scope, workspace); - }, - id: 'blockCopyToStorage', - weight: 0, - }; - Blockly.ContextMenuRegistry.registry.register(copyToStorageOption); - } - - /** - * Adds a paste command to the context menu for copyable items. - * - * @param typeErrorCallback callback function to handle type errors - */ - blockPasteFromStorageContextMenu(typeErrorCallback?: TypeErrorCallback) { - const pasteFromStorageOption: Blockly.ContextMenuRegistry.RegistryItem = { - displayText: () => { - if (Blockly.Msg['CROSS_TAB_PASTE']) { - return Blockly.Msg['CROSS_TAB_PASTE']; - } - return this.getContextMenuText(Blockly.Msg['PASTE_SHORTCUT']); - }, - preconditionFn: (scope) => { - // Only show paste option if menu was opened on a non-flyout workspace - if ( - !(scope.focusedNode instanceof Blockly.WorkspaceSvg) || - scope.focusedNode.isFlyout - ) - return ContextMenuState.HIDDEN; - const workspace = scope.focusedNode; - return this.pastePrecondition(workspace); - }, - callback: (scope, menuOpenEvent, menuSelectEvent, location) => { - const copyData = this.getCopyData(); - if (!copyData) return false; - const workspace = scope.focusedNode; - // Paste option only available if menu was opened on a workspace - if (!(workspace instanceof Blockly.WorkspaceSvg)) return false; - - const pasteLocation = Blockly.utils.svgMath.screenToWsCoordinates( - workspace, - location, - ); - try { - return !!Blockly.clipboard.paste(copyData, workspace, pasteLocation); - } catch (e) { - if (e instanceof TypeError && typeErrorCallback) { - typeErrorCallback(); - } else { - throw e; - } - } - }, - id: 'blockPasteFromStorage', - weight: 0, - }; - Blockly.ContextMenuRegistry.registry.register(pasteFromStorageOption); - } - - /** - * Adds a keyboard shortcut that will store copy information for a copyable - * in localStorage. - */ - blockCopyToStorageShortcut() { - const ctrlC = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.C, - [Blockly.utils.KeyCodes.CTRL], - ); - const metaC = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.C, - [Blockly.utils.KeyCodes.META], - ); - const copyShortcut: Blockly.ShortcutRegistry.KeyboardShortcut = { - name: Blockly.ShortcutItems.names.COPY, - keyCodes: [ctrlC, metaC], - preconditionFn: (workspace, scope) => { - const status = this.copyPrecondition(scope, workspace); - return status === ContextMenuState.ENABLED; - }, - callback: (workspace, e, shortcut, scope) => { - // Prevent the default copy behavior, - // which may beep or otherwise indicate - // an error due to the lack of a selection. - e.preventDefault(); - return this.copyCallback(scope, workspace); - }, - }; - Blockly.ShortcutRegistry.registry.register(copyShortcut); - } - - /** - * Adds a keyboard shortcut that will store copy information for copyable - * items in local storage and delete the item. - */ - blockCutToStorageShortcut() { - const ctrlX = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.X, - [Blockly.utils.KeyCodes.CTRL], - ); - const metaX = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.X, - [Blockly.utils.KeyCodes.META], - ); - - const cutShortcut: Blockly.ShortcutRegistry.KeyboardShortcut = { - name: Blockly.ShortcutItems.names.CUT, - keyCodes: [ctrlX, metaX], - preconditionFn: (workspace, scope) => { - const focused = scope.focusedNode; - return ( - !!focused && - !workspace.isReadOnly() && - !workspace.isDragging() && - !Blockly.getFocusManager().ephemeralFocusTaken() && - isCuttable(focused) - ); - }, - callback: (workspace, e, shortcut, scope) => { - // Prevent the default cut behavior, - // which may beep or otherwise indicate - // an error due to the lack of a selection. - e.preventDefault(); - - const focused = scope.focusedNode; - if (!focused || !isCuttable(focused) || !Blockly.isCopyable(focused)) { - return false; - } - const copyData = focused.toCopyData(); - if (!copyData) return false; - - if (focused instanceof Blockly.BlockSvg) { - focused.checkAndDelete(); - } else if (Blockly.isDeletable(focused)) { - // Manually handle event grouping since only blocks handle that - // automatically. - const oldGroup = Blockly.Events.getGroup(); - Blockly.Events.setGroup(true); - focused.dispose(); - Blockly.Events.setGroup(oldGroup); - } - - localStorage.setItem(this.localStorageKey, JSON.stringify(copyData)); - return true; - }, - }; - Blockly.ShortcutRegistry.registry.register(cutShortcut); - } - - /** - * Adds a keyboard shortcut that will paste the copyable stored in localStorage. - * - * @param typeErrorCallback - * callback function to handle type errors - */ - blockPasteFromStorageShortcut(typeErrorCallback?: TypeErrorCallback) { - const ctrlV = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.V, - [Blockly.utils.KeyCodes.CTRL], - ); - const metaV = Blockly.ShortcutRegistry.registry.createSerializedKey( - Blockly.utils.KeyCodes.V, - [Blockly.utils.KeyCodes.META], - ); - - const pasteShortcut: Blockly.ShortcutRegistry.KeyboardShortcut = { - name: Blockly.ShortcutItems.names.PASTE, - keyCodes: [ctrlV, metaV], - preconditionFn: (workspace) => { - const targetWorkspace = workspace.isFlyout - ? workspace.targetWorkspace - : workspace; - - if (!targetWorkspace) return false; - const status = this.pastePrecondition(targetWorkspace); - return status === ContextMenuState.ENABLED; - }, - callback: (workspace, e) => { - // Prevent the default copy behavior, - // which may beep or otherwise indicate - // an error due to the lack of a selection. - e.preventDefault(); - const copyData = this.getCopyData(); - if (!copyData) return false; - - // If paste shortcut is called while flyout is open, paste in the - // main workspace instead. - const targetWorkspace = workspace.isFlyout - ? workspace.targetWorkspace - : workspace; - if (!targetWorkspace) return false; - try { - if (e instanceof PointerEvent) { - // The event that triggers a shortcut would conventionally be a KeyboardEvent. - // However, it may be a PointerEvent if a context menu item was used as a - // wrapper for this callback, in which case the new block(s) should be pasted - // at the mouse coordinates where the menu was opened, and this PointerEvent - // is where the menu was opened. - const mouseCoords = Blockly.utils.svgMath.screenToWsCoordinates( - targetWorkspace, - new Blockly.utils.Coordinate(e.clientX, e.clientY), - ); - return !!Blockly.clipboard.paste( - copyData, - targetWorkspace, - mouseCoords, - ); - } - // If we don't have location data about the original copyable, let the - // paster determine position. - return !!Blockly.clipboard.paste(copyData, targetWorkspace); - } catch (e) { - if (e instanceof TypeError && typeErrorCallback) { - typeErrorCallback(); - } else { - throw e; - } - } - return true; - }, - }; - Blockly.ShortcutRegistry.registry.register(pasteShortcut); - } -} diff --git a/plugins/cross-tab-copy-paste/test/index.html b/plugins/cross-tab-copy-paste/test/index.html deleted file mode 100644 index 4eeec89c6..000000000 --- a/plugins/cross-tab-copy-paste/test/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Blockly Plugin Test - - - - -

    - This plugin can be tested by opening up multiple tabs of this page and - copy/pasting the block from one tab to another. You can only paste into a - workspace that also has this plugin enabled. -

    -
    - - - diff --git a/plugins/cross-tab-copy-paste/test/index.ts b/plugins/cross-tab-copy-paste/test/index.ts deleted file mode 100644 index 420838414..000000000 --- a/plugins/cross-tab-copy-paste/test/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Plugin test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import {CrossTabCopyPaste} from '../src/index'; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - }; - const rootElement = document.getElementById('root'); - if (!rootElement) { - return; - } - createPlayground(rootElement, createWorkspace, defaultOptions); - // Add workspace comments so we can test copying them - Blockly.ContextMenuItems.registerCommentOptions(); - const copyPastePlugin = new CrossTabCopyPaste(); - copyPastePlugin.init(); -}); diff --git a/plugins/cross-tab-copy-paste/tsconfig.json b/plugins/cross-tab-copy-paste/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/cross-tab-copy-paste/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/dev-create/.gitignore b/plugins/dev-create/.gitignore deleted file mode 100644 index 15ce8c38b..000000000 --- a/plugins/dev-create/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Don't commit the copy of sample-app to Git -templates/sample-app -templates/sample-app-ts diff --git a/plugins/dev-create/CHANGELOG.md b/plugins/dev-create/CHANGELOG.md deleted file mode 100644 index b5f8a933e..000000000 --- a/plugins/dev-create/CHANGELOG.md +++ /dev/null @@ -1,333 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [3.0.5](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/create-package@3.0.4...@blockly/create-package@3.0.5) (2026-04-09) - - -### Bug Fixes - -* remove eslint dependency from dev-scripts ([#2682](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2682)) ([dc6b746](https://github.com/RaspberryPiFoundation/blockly-samples/commit/dc6b7467f8960d19d7d21e6fe7b2fd14cbfff51c)) - - - -## [3.0.4](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/create-package@3.0.3...@blockly/create-package@3.0.4) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/create-package@3.0.2...@blockly/create-package@3.0.3) (2025-12-19) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/create-package@3.0.1...@blockly/create-package@3.0.2) (2024-06-20) - - -### Bug Fixes - -* check that root element exists in ts plugin template ([#2385](https://github.com/google/blockly-samples/issues/2385)) ([1644abb](https://github.com/google/blockly-samples/commit/1644abbc6da317b930b00010b653a42cc99c4f80)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/create-package@3.0.0...@blockly/create-package@3.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/create-package@2.0.5...@blockly/create-package@3.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* build for the v11 branch ([#2268](https://github.com/google/blockly-samples/issues/2268)) ([c7a4fc5](https://github.com/google/blockly-samples/commit/c7a4fc5e72c5e8d9e9bc926bbbbadd1eb31792fc)) -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) - - - -## [2.0.5](https://github.com/google/blockly-samples/compare/@blockly/create-package@2.0.4...@blockly/create-package@2.0.5) (2024-05-09) - - -### Bug Fixes - -* Fix incorrect Blockly imports ([#2339](https://github.com/google/blockly-samples/issues/2339)) ([9af40b9](https://github.com/google/blockly-samples/commit/9af40b9ca075275af2b48cedcc1750d458084eb3)) - - - -## [2.0.4](https://github.com/google/blockly-samples/compare/@blockly/create-package@2.0.3...@blockly/create-package@2.0.4) (2023-12-14) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [2.0.3](https://github.com/google/blockly-samples/compare/@blockly/create-package@2.0.2...@blockly/create-package@2.0.3) (2023-11-09) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/create-package@2.0.1...@blockly/create-package@2.0.2) (2023-10-30) - - -### Bug Fixes - -* include ts files in sample app create ([#2038](https://github.com/google/blockly-samples/issues/2038)) ([d3ea99a](https://github.com/google/blockly-samples/commit/d3ea99ad9da09c84018ba785ca7ed6ae38ce042f)) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/create-package@2.0.0...@blockly/create-package@2.0.1) (2023-09-21) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.4.1...@blockly/create-package@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [1.4.1](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.4.0...@blockly/create-package@1.4.1) (2023-06-08) - - -### Bug Fixes - -* remove types from ts templates for lint ([#1708](https://github.com/google/blockly-samples/issues/1708)) ([4029e7c](https://github.com/google/blockly-samples/commit/4029e7ced7c916ea0df335c9c930f3dbbbd2db76)) - - - -## [1.4.0](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.3.4...@blockly/create-package@1.4.0) (2023-04-13) - - -### Features - -* updated `create-package` plugin to handle generate a TS app ([#1659](https://github.com/google/blockly-samples/issues/1659)) ([c719f24](https://github.com/google/blockly-samples/commit/c719f24bc142c7a6825b81d67b1d3d59ec004374)) - - - -## [1.3.4](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.3.3...@blockly/create-package@1.3.4) (2023-03-09) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [1.3.3](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.3.2...@blockly/create-package@1.3.3) (2023-03-02) - - -### Bug Fixes - -* do not include dist script in template ([#1580](https://github.com/google/blockly-samples/issues/1580)) ([4862db5](https://github.com/google/blockly-samples/commit/4862db56e55e084f16fa52319a58ad73f47737b0)) - - - -## [1.3.2](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.3.1...@blockly/create-package@1.3.2) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [1.3.1](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.3.0...@blockly/create-package@1.3.1) (2023-02-23) - - -### Bug Fixes - -* Copy the sample-app files before publishing ([#1578](https://github.com/google/blockly-samples/issues/1578)) ([a7fd02e](https://github.com/google/blockly-samples/commit/a7fd02e1b1eea4e37cd61edab9207ae9f03d091b)) - - - -## [1.3.0](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.2.1...@blockly/create-package@1.3.0) (2023-02-23) - - -### Features - -* Add ability to create sample app ([#1553](https://github.com/google/blockly-samples/issues/1553)) ([b7aa6f4](https://github.com/google/blockly-samples/commit/b7aa6f46557ccb0e4da691b8b20f7bb2e47a1044)) - - - -## [1.2.1](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.2.0...@blockly/create-package@1.2.1) (2023-02-16) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [1.2.0](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.1.23...@blockly/create-package@1.2.0) (2023-02-09) - - -### Features - -* add option to create first party plugins, improve names ([#1547](https://github.com/google/blockly-samples/issues/1547)) ([ba1e545](https://github.com/google/blockly-samples/commit/ba1e5450923ad24f3ba886d0be901440e55cab6a)) - - - -## [1.1.23](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.1.22...@blockly/create-package@1.1.23) (2023-02-02) - - -### Bug Fixes - -* update templates to use JSON ([#1532](https://github.com/google/blockly-samples/issues/1532)) ([d4f6bbf](https://github.com/google/blockly-samples/commit/d4f6bbf38376f1ad39c9440aac7522a447c1a924)) - - - -## [1.1.22](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.1.21...@blockly/create-package@1.1.22) (2023-01-26) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [1.1.21](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.1.20...@blockly/create-package@1.1.21) (2023-01-05) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## [1.1.20](https://github.com/google/blockly-samples/compare/@blockly/create-package@1.1.19...@blockly/create-package@1.1.20) (2022-10-05) - - -### Bug Fixes - -* generator imports for use with blockly v9 ([#1305](https://github.com/google/blockly-samples/issues/1305)) ([51d59e9](https://github.com/google/blockly-samples/commit/51d59e98d172400e45fc74755f577e068df9996b)) - - - -## 1.1.19 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 1.1.18 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 1.1.17 (2022-07-21) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## 1.1.16 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 1.1.15 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 1.1.14 (2022-06-21) - -**Note:** Version bump only for package @blockly/create-package - - - - - -## 1.1.13 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 1.1.12 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/dev-create/README.md b/plugins/dev-create/README.md deleted file mode 100644 index 55107d051..000000000 --- a/plugins/dev-create/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# @blockly/create-package [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A tool for creating a Blockly plugin or application based on a pre-existing template. - -## Creating a plugin - -A plugin is a library designed to add functionality to Blockly. It is reusable -and can be added to an application that uses Blockly. For more information about -creating plugins in Blockly, see -[the developer documentation](https://developers.google.com/blockly/guides/contribute/samples/add_a_plugin). - -This script can be used to create a new Blockly plugin based on a template. - -### Usage - -``` -npx @blockly/create-package plugin my-plugin --type plugin -cd my-plugin -npm start -``` - -### Available templates - -`--type field`: A field template. - -`--type block`: A block template. - -`--type theme`: A theme template. - -`--type plugin`: A generic plugin template. (Default) - -### Options - -Run `npx @blockly/create-package plugin --help` to see the available options. - -### Adding TypeScript - -``` -npx @blockly/create-package plugin my-plugin --type plugin --typescript -``` - -## Creating a new application - -An application that uses Blockly is a standalone program, unlike a plugin. If -you're just getting started with Blockly, you can create a new application based -on our sample using this script. The app that will be generated contains basic -infrastructure for running, building, testing, etc. that you can use even if you -don't understand how to configure the related tool yet. When your needs outgrow -the functionality provided by it, you can replace the provided configuration or -tool with your own. - -### Usage - -``` -npx @blockly/create-package app hello-world -cd hello-world -npm start -``` - -See the generated `README.md` file after creation for more information. - -### Options - -Run `npx @blockly/create-package app --help` to see the available options. - -## License - -Apache 2.0 diff --git a/plugins/dev-create/bin/app.js b/plugins/dev-create/bin/app.js deleted file mode 100644 index a6b621a0a..000000000 --- a/plugins/dev-create/bin/app.js +++ /dev/null @@ -1,66 +0,0 @@ -const chalk = require('chalk'); -const fs = require('fs-extra'); -const path = require('path'); -const execSync = require('child_process').execSync; -const {checkAndCreateDir} = require('./common'); - -exports.createApp = function (name, options) { - const root = process.cwd(); - const dir = options.dir ?? name; - const appPath = path.join(root, dir); - - // Create the new directory for the app if needed. - checkAndCreateDir(appPath); - console.log( - `Creating a new Blockly application called ${name} in ${appPath}`, - ); - - // Copy over files from sample-app directory. - const sampleDir = options.typescript - ? '../templates/sample-app-ts' - : '../templates/sample-app'; - const excludes = [ - 'node_modules', - 'dist', - 'package-lock.json', - 'package.json', - ].map((file) => { - return path.resolve(__dirname, sampleDir, file); - }); - fs.copySync(path.resolve(__dirname, sampleDir), appPath, { - filter(src) { - return !excludes.includes(src); - }, - }); - - // Create package.json file for app. - const templateJson = require(path.join(sampleDir, 'package.json')); - const packageJson = { - ...templateJson, - name: name, - author: options.author || '', - }; - - // Write the package.json to the new package. - fs.writeFileSync( - path.join(appPath, 'package.json'), - JSON.stringify(packageJson, null, 2), - ); - - // Run `npm install` to get things ready for user. - if (!options.skipInstall) { - console.log('Installing packages. This might take a couple of minutes.'); - execSync(`cd ${dir} && npm install`, {stdio: 'inherit'}); - } - - // Print helpful instructions. - console.log(chalk.green('Success!')); - - console.log('You can start the development server now by typing:'); - console.log(chalk.blue(` cd ${dir}`)); - if (options.skipInstall) { - console.log(chalk.blue(' npm install')); - } - console.log(chalk.blue(' npm start')); - console.log('See README.md for more commands and information.'); -}; diff --git a/plugins/dev-create/bin/common.js b/plugins/dev-create/bin/common.js deleted file mode 100644 index 1dac2bf07..000000000 --- a/plugins/dev-create/bin/common.js +++ /dev/null @@ -1,23 +0,0 @@ -const fs = require('fs-extra'); - -/** - * Create package directory if it doesn't exist yet. - * Throws if the directory exists and isn't the current directory. - * @param {string} path Path at which to create directory. - */ -exports.checkAndCreateDir = function (path) { - const root = process.cwd(); - // If we're already in the desired directory, don't need to create it. - if (path == root) { - return; - } - if (fs.existsSync(path)) { - console.error( - `Package directory ${path} already exists. Delete it and try again.`, - ); - process.exit(1); - } else { - // Create the directory. - fs.mkdirSync(path); - } -}; diff --git a/plugins/dev-create/bin/create.js b/plugins/dev-create/bin/create.js deleted file mode 100755 index 367f180bc..000000000 --- a/plugins/dev-create/bin/create.js +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env node -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A script for creating Blockly packages based on pre-existing - * templates. - */ - -'use strict'; - -const commander = require('commander'); -const scriptPackageJson = require('../package.json'); -const {createApp} = require('./app'); -const {createPlugin} = require('./plugin'); - -const pluginTypes = ['plugin', 'field', 'block', 'theme']; -const scriptName = scriptPackageJson.name; - -const program = new commander.Command(scriptName); - -program - .command('plugin', {isDefault: true}) - .description('Create a new plugin for Blockly.') - .version(scriptPackageJson.version) - .argument('', 'Name of your plugin.') - .option( - '-d, --dir ', - 'specify the directory name to use; defaults to name of plugin', - ) - .option( - '-t, --type ', - `specify the type of the plugin. One of ${pluginTypes.join(', ')}`, - ) - .option('--typescript', 'use typescript') - .option('--author ', 'author, eg: Blockly Team') - .option('--first-party', 'create a first-party plugin') - .option('--skip-install', 'skip running `npm install` after creation') - .action((name, options) => { - createPlugin(name, options); - }); - -program - .command('application') - .alias('app') - .description('Create a new application that uses Blockly.') - .version(scriptPackageJson.version) - .argument('', 'Name of your application. You can change this later.') - .option( - '-d, --dir ', - 'specify the directory name to use; defaults to name of application', - ) - .option('--typescript', 'use typescript') - .option('--author ', 'author, eg: Blockly Team') - .option('--skip-install', 'skip running `npm install` after creation') - .action((name, options) => { - createApp(name, options); - }); - -program.parse(process.argv); diff --git a/plugins/dev-create/bin/plugin.js b/plugins/dev-create/bin/plugin.js deleted file mode 100644 index c37edc47d..000000000 --- a/plugins/dev-create/bin/plugin.js +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env node -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A script for creating Blockly plugins based on pre-existing - * templates. - */ - -'use strict'; - -const chalk = require('chalk'); -const fs = require('fs-extra'); -const path = require('path'); -const execSync = require('child_process').execSync; -const {checkAndCreateDir} = require('./common'); - -const pluginTypes = ['plugin', 'field', 'block', 'theme']; - -const root = process.cwd(); - -exports.createPlugin = function (pluginName, options) { - let gitRoot = ''; - let gitURL = ''; - try { - gitRoot = execSync(`git rev-parse --show-toplevel`).toString().trim(); - gitURL = execSync(`git config --get remote.origin.url`) - .toString() - .trim() - .replace(/\.git$/, ''); - } catch { - // NOP - } - - const isGit = !!gitURL; - const isFirstParty = - options.firstParty || - gitURL == 'https://github.com/RaspberryPiFoundation/blockly-samples'; - - /** - * Gets the name of the plugin prefixed with the type. - * Default to the plugin name if the type=plugin, otherwise use [type]-[name]. - * @param {string} name Plugin name. - * @param {string} type Plugin type. - * @returns {string} Plugin name prefixed with type. - */ - const getPrefixedName = function (name, type) { - // Don't add 'plugin' prefix for default type - if (type == 'plugin') return name; - // If the name is already prefixed, just return the name. - if (name.startsWith(`${type}-`)) return name; - // Add the prefix if not already present. - return `${type}-${name}`; - }; - - // Default to type=plugin. - const pluginType = options.type || 'plugin'; - const prefixedName = getPrefixedName(pluginName, pluginType); - const pluginDir = options.dir || prefixedName; - const pluginPath = path.join(root, pluginDir); - const pluginAuthor = options.author || (isFirstParty ? 'Blockly Team' : ''); - - const isTypescript = options.typescript; - const skipInstall = options.skipInstall; - - // Check plugin type. - if (!pluginTypes.includes(pluginType)) { - console.error(`Unknown plugin type: ${chalk.red(pluginType)}`); - console.log(`Available types: ${chalk.green(pluginTypes.join(', '))}`); - process.exit(1); - } - - // Create the new directory if needed. - checkAndCreateDir(pluginPath); - - console.log( - `Creating a new Blockly ${chalk.green(pluginType)} with name ` + - `${chalk.green(pluginName)} in ${chalk.green(pluginPath)}.\n`, - ); - - const templatesDir = `../templates`; - const templateDir = `${templatesDir}/${ - isTypescript ? 'typescript-' : '' - }${pluginType}/`; - - // Only use the @blockly scope for first party plugins. - const pluginScope = isFirstParty ? '@blockly/' : 'blockly-'; - const pluginPackageName = `${pluginScope}${prefixedName}`; - - const gitPluginPath = path.join(path.relative(gitRoot, root), pluginDir); - - const latestBlocklyVersion = execSync('npm show blockly version') - .toString() - .trim(); - - const packageJson = { - name: pluginPackageName, - version: `0.0.0`, - description: `A Blockly ${pluginType}.`, - scripts: { - 'audit:fix': 'blockly-scripts auditFix', - 'build': 'blockly-scripts build', - 'clean': 'blockly-scripts clean', - 'predeploy': 'blockly-scripts predeploy', - 'start': 'blockly-scripts start', - 'test': 'blockly-scripts test', - }, - main: './dist/index.js', - module: './src/index.js', - unpkg: './dist/index.js', - author: pluginAuthor, - keywords: [ - 'blockly', - 'blockly-plugin', - pluginType != 'plugin' && `blockly-${pluginType}`, - pluginName, - ].filter(Boolean), - homepage: isGit ? `${gitURL}/tree/master/${gitPluginPath}#readme` : '', - bugs: isGit - ? { - url: `${gitURL}/issues`, - } - : {}, - repository: isGit - ? { - type: 'git', - url: `${gitURL}.git`, - directory: gitPluginPath, - } - : {}, - license: 'Apache-2.0', - directories: { - dist: 'dist', - src: 'src', - }, - files: ['dist', 'src'], - devDependencies: {}, - peerDependencies: { - blockly: `^${latestBlocklyVersion}`, - }, - publishConfig: isFirstParty - ? { - access: 'public', - } - : {}, - }; - - // Add dev dependencies. - const devDependencies = [ - 'blockly', - '@blockly/dev-scripts', - '@blockly/dev-tools', - ]; - if (isTypescript) { - devDependencies.push('typescript'); - } - devDependencies.forEach((dep) => { - const latestVersion = execSync(`npm show ${dep} version`).toString().trim(); - packageJson.devDependencies[dep] = `^${latestVersion}`; - }); - - // Write the README.md to the new package. - let readme = fs.readFileSync( - path.resolve(__dirname, templateDir, 'README.md'), - 'utf-8', - ); - readme = readme.replace(/@blockly\/plugin/gim, `${pluginPackageName}`); - fs.writeFileSync(path.join(pluginPath, 'README.md'), readme, 'utf-8'); - - // Copy the rest of the template folder into the new package. - fs.copySync(path.resolve(__dirname, templateDir, 'template'), pluginPath); - - // Copy third party plugin files to the new package if third-party. - if (!isFirstParty) { - fs.copySync( - path.resolve(__dirname, templatesDir, 'third_party'), - pluginPath, - ); - } - - // Write the package.json to the new package. - fs.writeFileSync( - path.join(pluginPath, 'package.json'), - JSON.stringify(packageJson, null, 2), - ); - - // Run npm install. - if (!skipInstall) { - console.log('Installing packages. This might take a couple of minutes.'); - execSync(`cd ${pluginDir} && npm install`, {stdio: 'inherit'}); - } - - console.log( - `Success! Created ${pluginType} '${pluginName}' at ${pluginPath}`, - ); - console.log(`\n ${chalk.blue(` npm start`)}`); - console.log(` Starts the development server.\n`); - console.log(` ${chalk.blue(` npm run build`)}`); - console.log(` Builds a production build of the plugin.\n`); - console.log(` ${chalk.blue(` npm test`)}`); - console.log(` Runs mocha tests.\n\n`); - - console.log(`You can begin by typing:`); - console.log(chalk.blue(` cd ${pluginDir}`)); - if (skipInstall) { - console.log(chalk.blue(` npm install`)); - } - console.log(chalk.blue(` npm start`)); - console.log(`Search ${chalk.red(`'TODO'`)} to see remaining tasks.`); - - process.exit(1); -}; diff --git a/plugins/dev-create/package.json b/plugins/dev-create/package.json deleted file mode 100644 index c26c7a3f5..000000000 --- a/plugins/dev-create/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@blockly/create-package", - "version": "13.2.0", - "description": "A tool for creating a Blockly plugin based on a template.", - "bin": "./bin/create.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "dev", - "create", - "package", - "plugin", - "template" - ], - "files": [ - "*", - "templates/sample-app/*", - "templates/sample-app-ts/*" - ], - "scripts": { - "prepack": "cp -r ../../examples/sample-app ./templates && cp -r ../../examples/sample-app-ts ./templates" - }, - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/dev-create#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/dev-create" - }, - "license": "Apache-2.0", - "dependencies": { - "chalk": "^4.1.2", - "commander": "^15.0.0", - "fs-extra": "^11.3.5", - "install": "^0.13.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/dev-create/templates/block/README.md b/plugins/dev-create/templates/block/README.md deleted file mode 100644 index cddfaaab7..000000000 --- a/plugins/dev-create/templates/block/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) block that ... - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - -### Import - -```js -import * as Blockly from 'blockly'; -import '@blockly/plugin'; -``` - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/block/template/src/index.js b/plugins/dev-create/templates/block/template/src/index.js deleted file mode 100644 index 2d2a5c99c..000000000 --- a/plugins/dev-create/templates/block/template/src/index.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit block overview. -/** - * @fileoverview Block overview. - */ - -import * as Blockly from 'blockly/core'; - -// TODO: Update block definition. -Blockly.defineBlocksWithJsonArray([ - { - type: 'block_template', - message0: 'block template', - style: 'math_blocks', - }, -]); diff --git a/plugins/dev-create/templates/block/template/test/block_test.mocha.js b/plugins/dev-create/templates/block/template/test/block_test.mocha.js deleted file mode 100644 index 9115752ce..000000000 --- a/plugins/dev-create/templates/block/template/test/block_test.mocha.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const Blockly = require('blockly/core'); -const {testHelpers} = require('@blockly/dev-tools'); -const {dartGenerator} = require('blockly/dart'); -const {javascriptGenerator} = require('blockly/javascript'); -const {luaGenerator} = require('blockly/lua'); -const {phpGenerator} = require('blockly/php'); -const {pythonGenerator} = require('blockly/python'); - -require('../src/index'); - -const assert = chai.assert; - -const { - CodeGenerationTestSuite, - runCodeGenerationTestSuites, - runSerializationTestSuite, - SerializationTestCase, -} = testHelpers; - -suite('BlockTemplate', function () { - /** - * Asserts that the block has the expected inputs and fields. - * @param {!Blockly.Block} block The block to check. - */ - function assertBlockStructure(block) { - // TODO replace with meaningful assertions. - assert.exists(block); - } - - setup(function () { - this.workspace = new Blockly.Workspace(); - }); - - teardown(function () { - this.workspace.dispose(); - }); - - suite('Creation', function () { - // TODO Add basic test for creation of block using newBlock call. - const block = this.workspace.newBlock('block_type'); - assertBlockStructure(block); - }); - - suite('Code generation', function () { - const trivialCreateBlock = (workspace) => { - // TODO implement. - // return workspace.newBlock('block_type'); - }; - - /** - * Test suites for code generation tests. - * @type {Array} - */ - const testSuites = [ - // TODO Remove unsupported languages. - // TODO Update expectedCode for all test cases. - // TODO Add additional useful testCases. - { - title: 'Dart', - generator: dartGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'TODO', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'JavaScript', - generator: javascriptGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'TODO', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Lua', - generator: luaGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'TODO', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'PHP', - generator: phpGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'TODO', - createBlock: trivialCreateBlock, - }, - ], - }, - { - title: 'Python', - generator: pythonGenerator, - testCases: [ - { - title: 'Trivial', - expectedCode: 'TODO', - createBlock: trivialCreateBlock, - }, - ], - }, - ]; - runCodeGenerationTestSuites(testSuites); - }); - - /** - * Test cases for serialization tests. - * @type {Array} - */ - const testCases = [ - // TODO update xml and expectedXml. - { - title: 'Empty XML', - xml: '', - expectedXml: - '', - assertBlockStructure: (block) => { - // TODO implement. - // assertBlockStructure(block); - }, - }, - // TODO add additional test cases. - ]; - runSerializationTestSuite(testCases, Blockly); - - // TODO add any other relevant tests -}); diff --git a/plugins/dev-create/templates/block/template/test/index.html b/plugins/dev-create/templates/block/template/test/index.html deleted file mode 100644 index 1b2d48576..000000000 --- a/plugins/dev-create/templates/block/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Block Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/block/template/test/index.js b/plugins/dev-create/templates/block/template/test/index.js deleted file mode 100644 index 35fbb31e2..000000000 --- a/plugins/dev-create/templates/block/template/test/index.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Block test. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -// TODO: Edit list of blocks. -const allBlocks = ['block_template']; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: { - kind: 'flyoutToolbox', - contents: allBlocks.map((b) => { - return { - kind: 'block', - type: b, - }; - }), - }, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/field/README.md b/plugins/dev-create/templates/field/README.md deleted file mode 100644 index eb116453f..000000000 --- a/plugins/dev-create/templates/field/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) ... field. - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - - - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldTemplate} from '@blockly/plugin'; -Blockly.Blocks["test_field_template"] = { - init: function () { - this.appendDummyInput() - .appendField("template: ") - .appendField(new FieldTemplate(...), "FIELDNAME"); - } -}; -``` - -### JSON - -```js -import * as Blockly from 'blockly'; -import '@blockly/plugin'; -Blockly.defineBlocksWithJsonArray([ - { - "type": "test_field_template", - "message0": "template: %1", - "args0": [ - { - "type": "field_template", - "name": "FIELDNAME", - "value": ... - } - ] - }]); -``` - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/field/template/src/index.js b/plugins/dev-create/templates/field/template/src/index.js deleted file mode 100644 index 1d10505b5..000000000 --- a/plugins/dev-create/templates/field/template/src/index.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit field overview. -/** - * @fileoverview Field overview. - */ - -import * as Blockly from 'blockly/core'; - -// TODO: Rename field and update description. -/** - * Field description. - */ -export class FieldTemplate extends Blockly.Field { - /** - * Constructs a FieldTemplate from a JSON arg object. - * @param {!Object} options A JSON object with options. - * @returns {!FieldTemplate} The new field instance. - * @package - * @nocollapse - */ - static fromJson(options) { - // `this` might be a subclass of FieldTemplate if that class doesn't - // override the static fromJson method. - return new this(options['value']); - } -} - -// TODO: Edit field registration key. -Blockly.fieldRegistry.register('field_template', FieldTemplate); diff --git a/plugins/dev-create/templates/field/template/test/field_test.mocha.js b/plugins/dev-create/templates/field/template/test/field_test.mocha.js deleted file mode 100644 index 02cff48f8..000000000 --- a/plugins/dev-create/templates/field/template/test/field_test.mocha.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {testHelpers} = require('@blockly/dev-tools'); -const {FieldTemplate} = require('../src/index'); - -const { - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -suite('FieldTemplate', function () { - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = [ - // TODO - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = [ - // TODO - ]; - /** - * The expected default value for the field being tested. - * @type {*} - */ - const defaultFieldValue = 0; // TODO update with default value - /** - * Asserts that the field property values are set to default. - * @param {FieldTemplate} field The field to check. - */ - const assertFieldDefault = function (field) { - // TODO Recommend use of assertFieldValue from testHelpers - }; - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldTemplate} field The field to check. - * @param {FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - // TODO - }; - - runConstructorSuiteTests( - FieldTemplate, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runFromJsonSuiteTests( - FieldTemplate, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - suite('setValue', function () { - suite('Empty -> New Value', function () { - setup(function () { - this.field = new FieldTemplate(); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - defaultFieldValue, - ); - }); - suite('Value -> New Value', function () { - const initialValue = 1; // TODO update with initial value for test. - setup(function () { - this.field = new FieldTemplate(initialValue); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - initialValue, - ); - }); - }); - - suite('Validators', function () { - // TODO - }); - - // TODO add any other relevant tests -}); diff --git a/plugins/dev-create/templates/field/template/test/index.html b/plugins/dev-create/templates/field/template/test/index.html deleted file mode 100644 index 10cd0a0c1..000000000 --- a/plugins/dev-create/templates/field/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/field/template/test/index.js b/plugins/dev-create/templates/field/template/test/index.js deleted file mode 100644 index 884fc568e..000000000 --- a/plugins/dev-create/templates/field/template/test/index.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Field test. - */ - -import * as Blockly from 'blockly'; -import {generateFieldTestBlocks, createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -const toolbox = generateFieldTestBlocks('field_template', [ - { - args: { - value: 0, // TODO: change default value - }, - }, -]); - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/plugin/README.md b/plugins/dev-create/templates/plugin/README.md deleted file mode 100644 index b40da8867..000000000 --- a/plugins/dev-create/templates/plugin/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that ... - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - - - -```js -import * as Blockly from 'blockly'; -import {Plugin} from '@blockly/plugin'; - -// Inject Blockly. -const workspace = Blockly.inject('blocklyDiv', { - toolbox: toolboxCategories, -}); - -// Initialize plugin. -const plugin = new Plugin(workspace); -plugin.init(); -``` - -## API - - - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/plugin/template/src/index.js b/plugins/dev-create/templates/plugin/template/src/index.js deleted file mode 100644 index c5ada33d1..000000000 --- a/plugins/dev-create/templates/plugin/template/src/index.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit plugin overview. -/** - * @fileoverview Plugin overview. - */ - -// TODO: Rename plugin and edit plugin description. -/** - * Plugin description. - */ -export class Plugin { - /** - * Constructor for ... - * @param {!Blockly.WorkspaceSvg} workspace The workspace that the plugin will - * be added to. - */ - constructor(workspace) { - /** - * The workspace. - * @type {!Blockly.WorkspaceSvg} - * @protected - */ - this.workspace = workspace; - } - - /** - * Initialize. - */ - init() {} -} diff --git a/plugins/dev-create/templates/plugin/template/test/index.html b/plugins/dev-create/templates/plugin/template/test/index.html deleted file mode 100644 index dc96c578f..000000000 --- a/plugins/dev-create/templates/plugin/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Plugin Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/plugin/template/test/index.js b/plugins/dev-create/templates/plugin/template/test/index.js deleted file mode 100644 index 728651012..000000000 --- a/plugins/dev-create/templates/plugin/template/test/index.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Plugin test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import {Plugin} from '../src/index'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - - // TODO: Initialize your plugin here. - const plugin = new Plugin(workspace); - plugin.init(); - - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/theme/README.md b/plugins/dev-create/templates/theme/README.md deleted file mode 100644 index bf69f7196..000000000 --- a/plugins/dev-create/templates/theme/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) theme that ... - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - -```js -import * as Blockly from 'blockly'; -import Theme from '@blockly/plugin'; - -Blockly.inject('blocklyDiv', { - theme: Theme, -}); -``` - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/theme/template/src/index.js b/plugins/dev-create/templates/theme/template/src/index.js deleted file mode 100644 index a03b6b994..000000000 --- a/plugins/dev-create/templates/theme/template/src/index.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit theme overview. -/** - * @fileoverview Theme overview. - */ - -import * as Blockly from 'blockly/core'; - -// TODO: Edit theme name. -export default Blockly.Theme.defineTheme('THEME_NAME', { - base: Blockly.Themes.Classic, - blockStyles: {}, - categoryStyles: {}, - componentStyles: {}, - fontStyle: {}, - startHats: null, -}); diff --git a/plugins/dev-create/templates/theme/template/test/index.html b/plugins/dev-create/templates/theme/template/test/index.html deleted file mode 100644 index 2730c18ef..000000000 --- a/plugins/dev-create/templates/theme/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Theme Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/theme/template/test/index.js b/plugins/dev-create/templates/theme/template/test/index.js deleted file mode 100644 index de643e272..000000000 --- a/plugins/dev-create/templates/theme/template/test/index.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Theme test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import Theme from '../src/index'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - theme: Theme, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/third_party/.gitignore b/plugins/dev-create/templates/third_party/.gitignore deleted file mode 100644 index 800f3a80c..000000000 --- a/plugins/dev-create/templates/third_party/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build -/dist - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/plugins/dev-create/templates/third_party/GETSTARTED.md b/plugins/dev-create/templates/third_party/GETSTARTED.md deleted file mode 100644 index 99e93c7e9..000000000 --- a/plugins/dev-create/templates/third_party/GETSTARTED.md +++ /dev/null @@ -1,24 +0,0 @@ -This package was bootstrapped with [@blockly/create-package](https://www.npmjs.com/package/@blockly/create-package). - -## Available Scripts - -In this directory, you can run: - -### `npm start` - -Runs the package in development mode. - -Open [http://localhost:3000/test](http://localhost:3000/test) to view the test -playground in the browser. The page will reload if you make edits. - -### `npm run build` - -Builds the package into the `dist` directory. - -### `npm run lint` - -Runs eslint on the `src` and `test` directories. - -### `npm run clean` - -Deletes the `dist` and `build` directories if they exist. diff --git a/plugins/dev-create/templates/typescript-block/README.md b/plugins/dev-create/templates/typescript-block/README.md deleted file mode 100644 index cddfaaab7..000000000 --- a/plugins/dev-create/templates/typescript-block/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) block that ... - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - -### Import - -```js -import * as Blockly from 'blockly'; -import '@blockly/plugin'; -``` - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/typescript-block/template/src/index.ts b/plugins/dev-create/templates/typescript-block/template/src/index.ts deleted file mode 100644 index 2d2a5c99c..000000000 --- a/plugins/dev-create/templates/typescript-block/template/src/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit block overview. -/** - * @fileoverview Block overview. - */ - -import * as Blockly from 'blockly/core'; - -// TODO: Update block definition. -Blockly.defineBlocksWithJsonArray([ - { - type: 'block_template', - message0: 'block template', - style: 'math_blocks', - }, -]); diff --git a/plugins/dev-create/templates/typescript-block/template/test/index.html b/plugins/dev-create/templates/typescript-block/template/test/index.html deleted file mode 100644 index 1b2d48576..000000000 --- a/plugins/dev-create/templates/typescript-block/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Block Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/typescript-block/template/test/index.ts b/plugins/dev-create/templates/typescript-block/template/test/index.ts deleted file mode 100644 index 7872103b2..000000000 --- a/plugins/dev-create/templates/typescript-block/template/test/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Block test. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -// TODO: Edit list of blocks. -const allBlocks = ['block_template']; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: { - kind: 'flyoutToolbox', - contents: allBlocks.map((b) => { - return { - kind: 'block', - type: b, - }; - }), - }, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/typescript-block/template/tsconfig.json b/plugins/dev-create/templates/typescript-block/template/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/dev-create/templates/typescript-block/template/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/dev-create/templates/typescript-field/README.md b/plugins/dev-create/templates/typescript-field/README.md deleted file mode 100644 index eb116453f..000000000 --- a/plugins/dev-create/templates/typescript-field/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) ... field. - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - - - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldTemplate} from '@blockly/plugin'; -Blockly.Blocks["test_field_template"] = { - init: function () { - this.appendDummyInput() - .appendField("template: ") - .appendField(new FieldTemplate(...), "FIELDNAME"); - } -}; -``` - -### JSON - -```js -import * as Blockly from 'blockly'; -import '@blockly/plugin'; -Blockly.defineBlocksWithJsonArray([ - { - "type": "test_field_template", - "message0": "template: %1", - "args0": [ - { - "type": "field_template", - "name": "FIELDNAME", - "value": ... - } - ] - }]); -``` - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/typescript-field/template/src/index.ts b/plugins/dev-create/templates/typescript-field/template/src/index.ts deleted file mode 100644 index 389cd6f79..000000000 --- a/plugins/dev-create/templates/typescript-field/template/src/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit field overview. -/** - * @fileoverview Field overview. - */ - -import * as Blockly from 'blockly/core'; - -// TODO: Rename field and update description. -/** - * Field description. - */ -export class FieldTemplate extends Blockly.Field { - /** - * Constructs a FieldTemplate from a JSON arg object. - * - * @param options A JSON object with options. - * @returns The new field instance. - * @package - * @nocollapse - */ - static fromJson(options): Blockly.Field { - // `this` might be a subclass of FieldTemplate if that class doesn't - // override the static fromJson method. - return new this(options['value']); - } -} - -// TODO: Edit field registration key. -Blockly.fieldRegistry.register('field_template', FieldTemplate); diff --git a/plugins/dev-create/templates/typescript-field/template/test/index.html b/plugins/dev-create/templates/typescript-field/template/test/index.html deleted file mode 100644 index 10cd0a0c1..000000000 --- a/plugins/dev-create/templates/typescript-field/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/typescript-field/template/test/index.ts b/plugins/dev-create/templates/typescript-field/template/test/index.ts deleted file mode 100644 index e86fe1e3d..000000000 --- a/plugins/dev-create/templates/typescript-field/template/test/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Field test. - */ - -import * as Blockly from 'blockly'; -import {generateFieldTestBlocks, createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -const toolbox = generateFieldTestBlocks('field_template', [ - { - args: { - value: 0, // TODO: change default value - }, - }, -]); - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/typescript-field/template/tsconfig.json b/plugins/dev-create/templates/typescript-field/template/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/dev-create/templates/typescript-field/template/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/dev-create/templates/typescript-plugin/README.md b/plugins/dev-create/templates/typescript-plugin/README.md deleted file mode 100644 index b40da8867..000000000 --- a/plugins/dev-create/templates/typescript-plugin/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that ... - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - - - -```js -import * as Blockly from 'blockly'; -import {Plugin} from '@blockly/plugin'; - -// Inject Blockly. -const workspace = Blockly.inject('blocklyDiv', { - toolbox: toolboxCategories, -}); - -// Initialize plugin. -const plugin = new Plugin(workspace); -plugin.init(); -``` - -## API - - - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/typescript-plugin/template/src/index.ts b/plugins/dev-create/templates/typescript-plugin/template/src/index.ts deleted file mode 100644 index fadc340a2..000000000 --- a/plugins/dev-create/templates/typescript-plugin/template/src/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit plugin overview. -/** - * @fileoverview Plugin overview. - */ -import * as Blockly from 'blockly/core'; - -// TODO: Rename plugin and edit plugin description. -/** - * Plugin description. - */ -export class Plugin { - /** The workspace. */ - protected workspace: Blockly.WorkspaceSvg; - /** - * Constructor for ... - * - * @param workspace The workspace that the plugin will - * be added to. - */ - constructor(workspace: Blockly.WorkspaceSvg) { - this.workspace = workspace; - } - - /** - * Initialize. - */ - init(): void { - // TODO: Add initialization code. - } -} diff --git a/plugins/dev-create/templates/typescript-plugin/template/test/index.html b/plugins/dev-create/templates/typescript-plugin/template/test/index.html deleted file mode 100644 index dc96c578f..000000000 --- a/plugins/dev-create/templates/typescript-plugin/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Plugin Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/typescript-plugin/template/test/index.ts b/plugins/dev-create/templates/typescript-plugin/template/test/index.ts deleted file mode 100644 index fe68e35be..000000000 --- a/plugins/dev-create/templates/typescript-plugin/template/test/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Plugin test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import {Plugin} from '../src/index'; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - - // TODO: Initialize your plugin here. - const plugin = new Plugin(workspace); - plugin.init(); - - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - }; - const rootElement = document.getElementById('root'); - if (!rootElement) { - throw new Error(`div with id 'root' not found`); - } - createPlayground(rootElement, createWorkspace, defaultOptions); -}); diff --git a/plugins/dev-create/templates/typescript-plugin/template/tsconfig.json b/plugins/dev-create/templates/typescript-plugin/template/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/dev-create/templates/typescript-plugin/template/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/dev-create/templates/typescript-theme/README.md b/plugins/dev-create/templates/typescript-theme/README.md deleted file mode 100644 index bf69f7196..000000000 --- a/plugins/dev-create/templates/typescript-theme/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# @blockly/plugin [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - - - -A [Blockly](https://www.npmjs.com/package/blockly) theme that ... - -## Installation - -### Yarn - -``` -yarn add @blockly/plugin -``` - -### npm - -``` -npm install @blockly/plugin --save -``` - -## Usage - -```js -import * as Blockly from 'blockly'; -import Theme from '@blockly/plugin'; - -Blockly.inject('blocklyDiv', { - theme: Theme, -}); -``` - -## License - -Apache 2.0 diff --git a/plugins/dev-create/templates/typescript-theme/template/src/index.ts b/plugins/dev-create/templates/typescript-theme/template/src/index.ts deleted file mode 100644 index a03b6b994..000000000 --- a/plugins/dev-create/templates/typescript-theme/template/src/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// TODO: Edit theme overview. -/** - * @fileoverview Theme overview. - */ - -import * as Blockly from 'blockly/core'; - -// TODO: Edit theme name. -export default Blockly.Theme.defineTheme('THEME_NAME', { - base: Blockly.Themes.Classic, - blockStyles: {}, - categoryStyles: {}, - componentStyles: {}, - fontStyle: {}, - startHats: null, -}); diff --git a/plugins/dev-create/templates/typescript-theme/template/test/index.html b/plugins/dev-create/templates/typescript-theme/template/test/index.html deleted file mode 100644 index 2730c18ef..000000000 --- a/plugins/dev-create/templates/typescript-theme/template/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Theme Test - - - - -
    - - - diff --git a/plugins/dev-create/templates/typescript-theme/template/test/index.ts b/plugins/dev-create/templates/typescript-theme/template/test/index.ts deleted file mode 100644 index ffe3bc49d..000000000 --- a/plugins/dev-create/templates/typescript-theme/template/test/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Theme test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import Theme from '../src/index'; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - theme: Theme, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/dev-create/templates/typescript-theme/template/tsconfig.json b/plugins/dev-create/templates/typescript-theme/template/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/dev-create/templates/typescript-theme/template/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/dev-scripts/CHANGELOG.md b/plugins/dev-scripts/CHANGELOG.md deleted file mode 100644 index 79eb54daa..000000000 --- a/plugins/dev-scripts/CHANGELOG.md +++ /dev/null @@ -1,364 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### Bug Fixes - -* Fix JSDom whinging about its default stylesheet ([#2700](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2700)) - - -## [4.0.12](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/dev-scripts@4.0.11...@blockly/dev-scripts@4.0.12) (2026-04-09) - - -### Bug Fixes - -* remove eslint dependency from dev-scripts ([#2682](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2682)) ([dc6b746](https://github.com/RaspberryPiFoundation/blockly-samples/commit/dc6b7467f8960d19d7d21e6fe7b2fd14cbfff51c)) - - - -## [4.0.11](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/dev-scripts@4.0.10...@blockly/dev-scripts@4.0.11) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [4.0.10](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.9...@blockly/dev-scripts@4.0.10) (2025-12-19) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.9](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.8...@blockly/dev-scripts@4.0.9) (2025-05-22) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.8](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.7...@blockly/dev-scripts@4.0.8) (2025-05-15) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.6...@blockly/dev-scripts@4.0.7) (2024-12-03) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.5...@blockly/dev-scripts@4.0.6) (2024-11-07) - - -### Bug Fixes - -* Modify Webpack sourcemap parameters to account for Windows path separators ([#2465](https://github.com/google/blockly-samples/issues/2465)) ([58be365](https://github.com/google/blockly-samples/commit/58be365e6e0f859f0255df1d9380a0a58e3f233e)) - - - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.4...@blockly/dev-scripts@4.0.5) (2024-08-08) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.3...@blockly/dev-scripts@4.0.4) (2024-08-01) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.2...@blockly/dev-scripts@4.0.3) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) -* Revert "chore(deps): Bump the npm_and_yarn group across 12 directories with 8…" (#2407) ([c008407](https://github.com/google/blockly-samples/commit/c008407107a22376baa637546eb6224a9a1cc48e)), closes [#2407](https://github.com/google/blockly-samples/issues/2407) - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.1...@blockly/dev-scripts@4.0.2) (2024-07-04) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@4.0.0...@blockly/dev-scripts@4.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@3.1.1...@blockly/dev-scripts@4.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) - - - -## [3.1.1](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@3.1.0...@blockly/dev-scripts@3.1.1) (2023-12-14) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [3.1.0](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@3.0.0...@blockly/dev-scripts@3.1.0) (2023-11-09) - - -### Features - -* switch to new umd library output in webpack config ([#1973](https://github.com/google/blockly-samples/issues/1973)) ([7748c04](https://github.com/google/blockly-samples/commit/7748c0466b98099709064fba8530629814eb3333)) - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@2.0.2...@blockly/dev-scripts@3.0.0) (2023-11-02) - - -### ⚠ BREAKING CHANGES - -* remove the lint script from blockly-scripts (#2044) - -### Bug Fixes - -* remove the lint script from blockly-scripts ([#2044](https://github.com/google/blockly-samples/issues/2044)) ([a6df905](https://github.com/google/blockly-samples/commit/a6df90571182af8ed98bdf04ee317da41ea5de1c)) - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@2.0.1...@blockly/dev-scripts@2.0.2) (2023-10-30) - - -### Bug Fixes - -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@2.0.0...@blockly/dev-scripts@2.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.36...@blockly/dev-scripts@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - -### Reverts - -* Revert "chore(deps): Bump semver and fork-ts-checker-webpack-plugin (#1731)" (#1742) ([550eb33](https://github.com/google/blockly-samples/commit/550eb33ac1b88163b4f819e45d31e84f2821b6bf)), closes [#1731](https://github.com/google/blockly-samples/issues/1731) [#1742](https://github.com/google/blockly-samples/issues/1742) - - - -## [1.2.36](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.35...@blockly/dev-scripts@1.2.36) (2023-06-22) - - -### Bug Fixes - -* put eslint cache files in a better spot ([#1723](https://github.com/google/blockly-samples/issues/1723)) ([ac34524](https://github.com/google/blockly-samples/commit/ac34524e434870ffd40c9141965d6477e359967c)) - - - -## [1.2.35](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.34...@blockly/dev-scripts@1.2.35) (2023-05-18) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [1.2.34](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.33...@blockly/dev-scripts@1.2.34) (2023-05-11) - - -### Bug Fixes - -* Clean the dist directory before every build. ([#1685](https://github.com/google/blockly-samples/issues/1685)) ([71b1544](https://github.com/google/blockly-samples/commit/71b1544e1810f375798ca339b87816d6921c8ce5)) - - - -## [1.2.33](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.32...@blockly/dev-scripts@1.2.33) (2023-04-27) - - -### Bug Fixes - -* Fix compatibility with Node 18 ([#1672](https://github.com/google/blockly-samples/issues/1672)) ([df1b943](https://github.com/google/blockly-samples/commit/df1b943e42ded5cd1dfc8d83c8388116c5607a31)) - - - -## [1.2.32](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.31...@blockly/dev-scripts@1.2.32) (2023-03-23) - - -### Bug Fixes - -* eliminate faulty postinstall script ([#1630](https://github.com/google/blockly-samples/issues/1630)) ([d5efc18](https://github.com/google/blockly-samples/commit/d5efc18193d7f142329d1127ea6c8a64d24aff0c)) - - - -## [1.2.31](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.30...@blockly/dev-scripts@1.2.31) (2023-03-02) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [1.2.30](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.29...@blockly/dev-scripts@1.2.30) (2023-02-16) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [1.2.29](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.28...@blockly/dev-scripts@1.2.29) (2023-02-09) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## [1.2.28](https://github.com/google/blockly-samples/compare/@blockly/dev-scripts@1.2.27...@blockly/dev-scripts@1.2.28) (2022-10-13) - - -### Bug Fixes - -* scripts plugin now properly builds TypeScript declarations ([#1322](https://github.com/google/blockly-samples/issues/1322)) ([180cb6a](https://github.com/google/blockly-samples/commit/180cb6a431a2e9bdc1000b1521413d74625391db)) - - - -## 1.2.27 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 1.2.26 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 1.2.24 (2022-07-21) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## 1.2.23 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 1.2.22 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 1.2.21 (2022-06-21) - -**Note:** Version bump only for package @blockly/dev-scripts - - - - - -## 1.2.20 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 1.2.19 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/dev-scripts/README.md b/plugins/dev-scripts/README.md deleted file mode 100644 index e1ee8bfad..000000000 --- a/plugins/dev-scripts/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# @blockly/dev-scripts [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -This package includes scripts and configuration files used by Blockly plugins. - -## Available Scripts - -### `blockly-scripts start` - -Runs the package in development mode. - -Open [http://localhost:3000/test](http://localhost:3000/test) to view the test -playground in the browser. The page will reload if you make edits. - -### `blockly-scripts build` - -Builds the package into the `dist` directory. - -### `blockly-scripts clean` - -Deletes the `dist` and `build` directories if they exist. diff --git a/plugins/dev-scripts/bin/blockly-scripts.js b/plugins/dev-scripts/bin/blockly-scripts.js deleted file mode 100755 index ab5b52489..000000000 --- a/plugins/dev-scripts/bin/blockly-scripts.js +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env node -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Blockly dev scripts entry point. - * @author samelh@google.com (Sam El-Husseini) - */ - -const args = process.argv.slice(2); -const {spawnSync} = require('child_process'); - -const availableScripts = [ - 'build', - 'start', - 'clean', - 'predeploy', - 'test', - 'auditFix', -]; - -const script = args[0]; -if (availableScripts.includes(script)) { - const result = spawnSync( - 'node', - [].concat(require.resolve('../scripts/' + script)).concat(args.slice(1)), - {stdio: 'inherit'}, - ); - if (result.signal) { - if (result.signal === 'SIGKILL') { - console.log('The build failed because the process exited too early. '); - } else if (result.signal === 'SIGTERM') { - console.log('The build failed because the process exited too early. '); - } - process.exit(1); - } - process.exit(result.status); -} else { - console.log('Unknown script "' + script + '".'); -} diff --git a/plugins/dev-scripts/config/webpack.config.js b/plugins/dev-scripts/config/webpack.config.js deleted file mode 100644 index 3799fe891..000000000 --- a/plugins/dev-scripts/config/webpack.config.js +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -/** - * @fileoverview Webpack configuration file. - * @author samelh@google.com (Sam El-Husseini) - */ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const webpack = require('webpack'); - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); -const exists = (relativePath) => fs.existsSync(resolveApp(relativePath)); - -const packageJson = require(resolveApp('package.json')); - -module.exports = (env) => { - const mode = env.mode; - const isDevelopment = mode === 'development'; - const isProduction = mode === 'production'; - const isTest = mode === 'test'; - const isTypescript = exists('tsconfig.json'); - - let entry; - let outputFile; - let target = 'web'; - const plugins = [ - // Use DefinePlugin (https://webpack.js.org/plugins/define-plugin/) - // to pass the name of the package being built to the dev-tools - // playground (via plugins/dev-tools/src/playground/id.js). The - // "process.env." prefix is arbitrary: the stringified value - // gets substituted directly into the source code of that file - // at build time. - new webpack.DefinePlugin({ - 'process.env.PACKAGE_NAME': JSON.stringify(packageJson.name), - }), - ]; - - if (isProduction) { - // Production. - if (exists('./src/index.js')) entry = './src/index.js'; - if (exists('./src/index.ts')) entry = './src/index.ts'; - outputFile = 'index.js'; - } else if (isDevelopment) { - // Development. - if (exists('./test/index.js')) entry = './test/index.js'; - if (exists('./test/index.ts')) entry = './test/index.ts'; - outputFile = 'test_bundle.js'; - } else if (isTest) { - // Test. - // Create an entry point for each .mocha.js file. - fs.readdirSync('./test/') - .filter((file) => file.substr(-9) === '.mocha.js') - .forEach((file) => { - const entryName = file.replace(/\.mocha\.js/i, ''); - if (!entry) entry = {}; - entry[entryName] = `./test/${file}`; - }); - outputFile = '[name].mocha.js'; - target = 'node'; - // Certain optional plugins wanted by dependencies of blockly - // (jsdom want canvas, jsdom depends on ws which wants - // bufferutils and utf-8-validate) are loaded via: - // - // try {/*...*/ = require('package')} catch (e) {/*...*/} - // - // Webpack tries to satisfy the require even though it's in a - // try/catch, and issues a warning if it can't be found. - // IgnorePlugin suppresses this. - plugins.push( - new webpack.IgnorePlugin({ - resourceRegExp: /^(canvas|bufferutil|utf-8-validate)$/, - }), - ); - } - - return { - target, - mode: isProduction ? 'production' : 'development', - entry: entry, - devtool: isProduction ? 'source-map' : 'eval-source-map', - output: { - path: isProduction ? resolveApp('dist') : resolveApp('build'), - publicPath: isProduction ? '/dist/' : '/build/', - filename: outputFile, - library: { - type: 'umd', - }, - globalObject: 'this', - clean: true, - }, - resolve: { - extensions: ['.ts', '.js', '.json', '.wasm'], - // Some deps may require node.js core modules. Tell node.js what - // polyfills to use for them when building for non-node.js targets - // (Or to ignore them if the fallback is false.) - fallback: { - util: false, - }, - }, - module: { - rules: [ - // Load Blockly source maps. - { - test: /(blockly[/\\].*\.js)$/, - use: [require.resolve('source-map-loader')], - enforce: 'pre', - }, - isTypescript && { - test: /\.tsx?$/, - loader: require.resolve('ts-loader'), - options: isProduction ? {} : {compilerOptions: {rootDir: '.'}}, - }, - ].filter(Boolean), - }, - // Ignore spurious warnings from source-map-loader - // It can't find source maps for some Closure modules and that is expected - ignoreWarnings: [/Failed to parse source map.*blockly/], - plugins, - externals: isProduction - ? { - 'blockly': { - root: 'Blockly', - commonjs: 'blockly', - commonjs2: 'blockly', - amd: 'blockly', - }, - 'blockly/core': { - root: 'Blockly', - commonjs: 'blockly/core', - commonjs2: 'blockly/core', - amd: 'blockly/core', - }, - 'blockly/javascript': { - root: 'Blockly.JavaScript', - commonjs: 'blockly/javascript', - commonjs2: 'blockly/javascript', - amd: 'blockly/javascript', - }, - 'blockly/python': { - root: 'Blockly.Python', - commonjs: 'blockly/python', - commonjs2: 'blockly/python', - amd: 'blockly/python', - }, - 'blockly/dart': { - root: 'Blockly.Dart', - commonjs: 'blockly/dart', - commonjs2: 'blockly/dart', - amd: 'blockly/dart', - }, - 'blockly/php': { - root: 'Blockly.PHP', - commonjs: 'blockly/php', - commonjs2: 'blockly/php', - amd: 'blockly/php', - }, - 'blockly/lua': { - root: 'Blockly.Lua', - commonjs: 'blockly/lua', - commonjs2: 'blockly/lua', - amd: 'blockly/lua', - }, - 'jsdom': 'commonjs jsdom', - } - : {jsdom: 'commonjs jsdom'}, - }; -}; diff --git a/plugins/dev-scripts/config/webpackDevServer.config.js b/plugins/dev-scripts/config/webpackDevServer.config.js deleted file mode 100644 index 0e3d3fc47..000000000 --- a/plugins/dev-scripts/config/webpackDevServer.config.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -/** - * @fileoverview Webpack dev server configuration file. - * @author samelh@google.com (Sam El-Husseini) - */ -'use strict'; - -module.exports = () => { - return { - port: 'auto', - hot: true, - static: ['./test'], - watchFiles: { - paths: './', - options: { - ignored: 'node_modules', - }, - }, - open: true, - client: { - overlay: { - errors: true, - warnings: false, - }, - }, - }; -}; diff --git a/plugins/dev-scripts/package.json b/plugins/dev-scripts/package.json deleted file mode 100644 index dd2917b33..000000000 --- a/plugins/dev-scripts/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@blockly/dev-scripts", - "version": "13.2.0", - "description": "Configuration and scripts for Blockly plugins.", - "bin": { - "blockly-scripts": "./bin/blockly-scripts.js" - }, - "author": "Blockly Team", - "keywords": [ - "blockly", - "dev", - "scripts" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/dev-scripts#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/dev-scripts" - }, - "license": "Apache-2.0", - "dependencies": { - "@babel/code-frame": "^8.0.0", - "chalk": "^4.1.2", - "fork-ts-checker-webpack-plugin": "^9.1.0", - "install": "^0.13.0", - "mocha": "^11.7.6", - "rimraf": "^6.1.3", - "source-map-loader": "^5.0.0", - "ts-loader": "^9.6.1", - "webpack": "^5.107.2", - "webpack-cli": "^7.0.3", - "webpack-dev-server": "^5.2.6" - }, - "peerDependencies": { - "typescript": "^4.3.2 || ^5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - }, - "publishConfig": { - "access": "public" - }, - "devDependencies": { - "typescript": "^6.0.3" - } -} diff --git a/plugins/dev-scripts/scripts/auditFix.js b/plugins/dev-scripts/scripts/auditFix.js deleted file mode 100644 index f7daed5b1..000000000 --- a/plugins/dev-scripts/scripts/auditFix.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview An audit and fix script for Blockly extension packages. - * This script: - * - Runs `npm install` to get a clean (not locally linked) installation. - * - Runs `npm audit fix` to do the fixes. - * @author fenichel@google.com (Rachel Fenichel) - */ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const execSync = require('child_process').execSync; - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); - -const packageJson = require(resolveApp('package.json')); - -console.log(`Running npm audit fix steps for ${packageJson.name}`); - -// Run npm install. -execSync(`npm install`, {stdio: [0, 1, 2]}); - -// Audit fix. -execSync(`npm audit fix`, {stdio: [0, 1, 2]}); diff --git a/plugins/dev-scripts/scripts/build.js b/plugins/dev-scripts/scripts/build.js deleted file mode 100644 index 8507409bc..000000000 --- a/plugins/dev-scripts/scripts/build.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A 'build' script for Blockly extension packages. - * This script: - * - Uses webpack to build the src directory in development mode if no - * additional arguments are passed. - * - Uses webpack to build the src directory in production mode if - * ``blockly-scripts build prod`` is called. - * @author samelh@google.com (Sam El-Husseini) - */ - -'use strict'; - -const path = require('path'); -const fs = require('fs'); - -const chalk = require('chalk'); -const webpack = require('webpack'); -const webpackConfig = require('../config/webpack.config'); - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); - -const packageJson = require(resolveApp('package.json')); -console.log(`Running production build for ${packageJson.name}`); - -// Create the webpack configuration for based on the build environment. -const config = webpackConfig({ - mode: 'production', -}); -if (!config.entry) { - console.log(`${chalk.red(`Configuration error.`)} -Make sure a ${chalk.red('src/index.(js|ts)')} file is included in your package. -`); - process.exit(1); -} - -// Create and run the webpack compiler. -webpack(config, (err, stats) => { - if (err) { - console.error(err.stack || err); - if (err.details) { - console.error(err.details); - } - process.exit(1); - } - const statsData = stats.toJson({ - all: false, - warnings: true, - errors: true, - }); - - const formatWebpackMessage = (obj) => { - return obj.message.trim(); - }; - - const messages = { - errors: statsData.errors.map(formatWebpackMessage), - warnings: statsData.warnings.map(formatWebpackMessage), - }; - - if (!messages.errors.length && !messages.warnings.length) { - console.log(chalk.green('Compiled successfully!')); - } - if (messages.errors.length) { - console.log(chalk.red('Failed to compile.\n')); - console.log(messages.errors.join('\n\n')); - process.exit(1); - } - if (messages.warnings.length) { - console.log(chalk.yellow('Compiled with warnings.\n')); - console.log(messages.warnings.join('\n\n')); - } -}); diff --git a/plugins/dev-scripts/scripts/clean.js b/plugins/dev-scripts/scripts/clean.js deleted file mode 100644 index 8528fc546..000000000 --- a/plugins/dev-scripts/scripts/clean.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A 'clean' script for Blockly extension packages. - * This script: - * Deletes the dist and build directories if they exist. - * @author samelh@google.com (Sam El-Husseini) - */ - -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const rimraf = require('rimraf'); - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); - -const packageJson = require(resolveApp('package.json')); -console.log(`Running clean for ${packageJson.name}`); - -// Delete both the dist and build directories if they exist. -const dirs = ['dist', 'build']; -dirs.forEach((dir) => { - rimraf.sync(resolveApp(dir)); -}); diff --git a/plugins/dev-scripts/scripts/predeploy.js b/plugins/dev-scripts/scripts/predeploy.js deleted file mode 100644 index 922fbcf2e..000000000 --- a/plugins/dev-scripts/scripts/predeploy.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A 'predeploy' script for Blockly extension packages. - * This script: - * - Uses webpack to build the test directory in development mode in - * preparation for deployment. - * @author samelh@google.com (Sam El-Husseini) - */ - -'use strict'; - -const path = require('path'); -const fs = require('fs'); - -const chalk = require('chalk'); -const webpack = require('webpack'); -const webpackConfig = require('../config/webpack.config'); - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); - -const packageJson = require(resolveApp('package.json')); -console.log(`Running predeploy for ${packageJson.name}`); - -// Create the webpack configuration for based on the build environment. -const config = webpackConfig({ - mode: 'development', -}); -if (!config.entry) { - console.log(`${chalk.red(`Configuration error.`)} -Make sure a ${chalk.red('src/index.(js|ts)')} file is included in your package. -`); - process.exit(1); -} - -// Create and run the webpack compiler. -webpack(config, (err, stats) => { - if (err) { - console.error(err.stack || err); - if (err.details) { - console.error(err.details); - } - return; - } - console.log( - stats.toString({ - chunks: false, // Makes the build much quieter - colors: true, // Shows colors in the console - }), - ); -}); diff --git a/plugins/dev-scripts/scripts/start.js b/plugins/dev-scripts/scripts/start.js deleted file mode 100644 index 030a1fe0f..000000000 --- a/plugins/dev-scripts/scripts/start.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A 'start' script for Blockly extension packages. - * This script: - * Builds the src and test directories in development mode. - * Starts the webpack dev server which watches changes to these directories. - * Opens the test page `0.0.0.0:3000/test`. - * Hot reloads the page if any changes are made to the source files. - * @author samelh@google.com (Sam El-Husseini) - */ - -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const os = require('os'); - -const webpack = require('webpack'); -const WebpackDevServer = require('webpack-dev-server'); -const webpackConfig = require('../config/webpack.config'); -const webpackDevServerConfig = require('../config/webpackDevServer.config'); - -const chalk = require('chalk'); -const codeFrame = require('@babel/code-frame').codeFrameColumns; -const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); - -const packageJson = require(resolveApp('package.json')); -const isTypescript = fs.existsSync(resolveApp('tsconfig.json')); - -console.log(`Running start for ${packageJson.name}`); - -// Create the webpack configuration for the development environment. -// Build the test directory. -const config = webpackConfig({ - mode: 'development', -}); -if (!config.entry) { - console.log(`${chalk.red(`Configuration error.`)} -Make sure a ${chalk.red('test/index.(js|ts)')} file is included in your package. -`); - process.exit(1); -} - -let compiler; -try { - compiler = webpack(config); -} catch (err) { - console.log(`${chalk.red('Failed to compile.')}\n${err.message || err}\n`); - process.exit(1); -} - -const devSocket = { - warnings: (warnings) => - devServer.sockWrite(devServer.sockets, 'warnings', warnings), - errors: (errors) => devServer.sockWrite(devServer.sockets, 'errors', errors), -}; - -compiler.hooks.invalid.tap('invalid', () => { - console.log('Compiling...'); -}); - -let tsMessagesPromise; -let tsMessagesResolver; - -if (isTypescript) { - compiler.hooks.beforeCompile.tap('beforeCompile', () => { - tsMessagesPromise = new Promise((resolve) => { - tsMessagesResolver = (msgs) => resolve(msgs); - }); - }); - - // Register TypeScript type checker hooks. - const tsCheckerHooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(compiler); - tsCheckerHooks.issues.tap('done', (issues) => { - const formatTypecheckerMessage = (message) => { - const {severity, file, line, character} = message; - - const messageColor = severity == 'warning' ? chalk.yellow : chalk.red; - - const source = - file && fs.existsSync(file) && fs.readFileSync(file, 'utf-8'); - const frame = source - ? codeFrame( - source, - {start: {line: line, column: character}}, - {highlightCode: true, linesAbove: 2, linesBelow: 2}, - ) - .split('\n') - .map((str) => ' ' + str) - .join(os.EOL) - : ''; - - return [ - os.EOL, - messageColor.bold(`${severity.toLowerCase()} in `) + - chalk.cyan.bold(`${file}(${line},${character})`) + - messageColor(':'), - '', - frame, - ].join(os.EOL); - }; - - tsMessagesResolver({ - errors: issues - .filter((msg) => msg.severity === 'error') - .map(formatTypecheckerMessage), - warnings: issues - .filter((msg) => msg.severity === 'warning') - .map(formatTypecheckerMessage), - }); - - return issues; - }); -} - -// Register webpack compiler hooks. -compiler.hooks.done.tap('done', async (stats) => { - const statsData = stats.toJson({ - all: false, - warnings: true, - errors: true, - }); - - const formatWebpackMessage = (obj) => { - return obj.message.trim(); - }; - - const messages = { - errors: statsData.errors.map(formatWebpackMessage), - warnings: statsData.warnings.map(formatWebpackMessage), - }; - - if (isTypescript && statsData.errors.length === 0) { - const delayedMsg = setTimeout(() => { - console.log( - chalk.yellow( - 'Files successfully emitted, waiting for typecheck results...', - ), - ); - }, 100); - - const tsMessages = await tsMessagesPromise; - clearTimeout(delayedMsg); - - messages.warnings.push(...tsMessages.errors); - messages.warnings.push(...tsMessages.warnings); - - if (tsMessages.errors.length > 0) { - devSocket.warnings(tsMessages.errors); - } else if (tsMessages.warnings.length > 0) { - devSocket.warnings(tsMessages.warnings); - } - } - - // Emit compile output. - if (!messages.errors.length && !messages.warnings.length) { - console.log(chalk.green('Compiled successfully!')); - } - if (messages.errors.length) { - console.log(chalk.red('Failed to compile.\n')); - console.log(messages.errors.join('\n\n')); - return; - } - if (messages.warnings.length) { - console.log(chalk.yellow('Compiled with warnings.\n')); - console.log(messages.warnings.join('\n\n')); - } -}); - -// Read the webpack devServer configuration. -const serverConfig = webpackDevServerConfig(); - -// Start the dev server. -const devServer = new WebpackDevServer(serverConfig, compiler); -devServer.startCallback((err) => { - if (err) { - return console.log(err); - } - console.log('Starting the development server...\n'); -}); diff --git a/plugins/dev-scripts/scripts/test.js b/plugins/dev-scripts/scripts/test.js deleted file mode 100644 index 8df4aa140..000000000 --- a/plugins/dev-scripts/scripts/test.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A 'test' script for Blockly extension packages. - * This script: - * Runs mocha tests on all *.mocha.js tests in the test directory. - * @author samelh@google.com (Sam El-Husseini) - */ - -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const chalk = require('chalk'); -const Mocha = require('mocha'); -const webpack = require('webpack'); -const webpackConfig = require('../config/webpack.config'); - -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath); - -const packageJson = require(resolveApp('package.json')); -console.log(`Building tests for ${packageJson.name}`); - -const config = webpackConfig({ - mode: 'test', -}); -if (!config.entry) { - console.log( - chalk.yellow(`Warning: No tests found`) + - '\n' + - 'There were no ' + - chalk.yellow('test/*.mocha.js') + - ' files found ' + - 'in your package.\n', - ); - process.exit(0); -} - -let mochaConfig = { - ui: 'tdd', -}; -// If custom configuration exists, use that instead. -const testDir = resolveApp('test'); -if (fs.existsSync(path.join(testDir, '.mocharc.js'))) { - mochaConfig = require(path.join(testDir, '.mocharc.js')); -} - -// Create and run the webpack compiler. -webpack(config, (err, stats) => { - if (err) { - console.error(err.stack || err); - if (err.details) { - console.error(err.details); - } - return; - } - console.log( - stats.toString({ - chunks: false, // Makes the build much quieter - colors: true, // Shows colors in the console - }), - ); - - // Run mocha. - console.log(`Running tests for ${packageJson.name}`); - - // Instantiate a Mocha instance. - const mocha = new Mocha(mochaConfig); - - // Run mocha for each built mocha .js file. - const testOutputDir = 'build'; - fs.readdirSync(testOutputDir) - .filter((file) => { - // Only keep the .mocha.js files - return file.substr(-9) === '.mocha.js'; - }) - .forEach((file) => { - mocha.addFile(path.join(testOutputDir, file)); - }); - - // Run the tests. - mocha.run((failures) => { - // exit with non-zero status if there were failures. - process.exitCode = failures ? 1 : 0; - }); -}); diff --git a/plugins/dev-tools/CHANGELOG.md b/plugins/dev-tools/CHANGELOG.md deleted file mode 100644 index 9d3b4e9a0..000000000 --- a/plugins/dev-tools/CHANGELOG.md +++ /dev/null @@ -1,688 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [9.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/dev-tools@9.0.8...@blockly/dev-tools@9.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [9.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/dev-tools@9.0.7...@blockly/dev-tools@9.0.8) (2026-01-15) - - -### Bug Fixes - -* Restore `extraState` to `lists_create_with` in the sample toolbox ([#2670](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2670)) ([ecaf83f](https://github.com/RaspberryPiFoundation/blockly-samples/commit/ecaf83f1f85b67921d3463087d76b02f5e21e132)) - - - -## [9.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/dev-tools@9.0.6...@blockly/dev-tools@9.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [9.0.6](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@9.0.5...@blockly/dev-tools@9.0.6) (2026-01-05) - - -### Bug Fixes - -* Update broken links from Google repo ([#2655](https://github.com/google/blockly-samples/issues/2655)) ([8bd1177](https://github.com/google/blockly-samples/commit/8bd1177c9fa7e67be950c2be14d06a374116561a)) - - - -## [9.0.5](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@9.0.4...@blockly/dev-tools@9.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [9.0.4](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@9.0.3...@blockly/dev-tools@9.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [9.0.3](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@9.0.2...@blockly/dev-tools@9.0.3) (2025-10-02) - - -### Bug Fixes - -* Don't listen for shortcuts on the document. ([#2609](https://github.com/google/blockly-samples/issues/2609)) ([5b1a07c](https://github.com/google/blockly-samples/commit/5b1a07c3e4a4a245cecd783b3e86bc3608ee2c0d)) - - - -## [9.0.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@9.0.1...@blockly/dev-tools@9.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [9.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@9.0.0...@blockly/dev-tools@9.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [9.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.1.2...@blockly/dev-tools@9.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [8.1.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.1.1...@blockly/dev-tools@8.1.2) (2025-05-16) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.1.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.1.0...@blockly/dev-tools@8.1.1) (2025-05-15) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -# [8.1.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.13...@blockly/dev-tools@8.1.0) (2025-02-13) - - -### Features - -* Added button to Advanced Playground to import state. ([#2483](https://github.com/google/blockly-samples/issues/2483)) ([fed7ee0](https://github.com/google/blockly-samples/commit/fed7ee0e82cd0a2f3d2f00cec69abd5932feb42f)) - - - - - -## [8.0.13](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.12...@blockly/dev-tools@8.0.13) (2024-12-19) - - -### Bug Fixes - -* Update screenshot plugin for compatibility with CSS vars. ([#2472](https://github.com/google/blockly-samples/issues/2472)) ([eecfccd](https://github.com/google/blockly-samples/commit/eecfccda56027a613d76f9ace70e62d9143f1c2e)) - - - - - -## [8.0.12](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.11...@blockly/dev-tools@8.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.11](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.10...@blockly/dev-tools@8.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.10](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.9...@blockly/dev-tools@8.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [8.0.9](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.8...@blockly/dev-tools@8.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [8.0.8](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.7...@blockly/dev-tools@8.0.8) (2024-08-22) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.7](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.6...@blockly/dev-tools@8.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.6](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.5...@blockly/dev-tools@8.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.5](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.4...@blockly/dev-tools@8.0.5) (2024-07-25) - - -### Bug Fixes - -* dev-tools only set monaco model and text when changing ([#2417](https://github.com/google/blockly-samples/issues/2417)) ([20be3a3](https://github.com/google/blockly-samples/commit/20be3a3b43af41987f631b931d65121d761f6377)), closes [/github.com/mit-cml/workspace-multiselect/pull/62#issuecomment-2196819235](https://github.com/google//github.com/mit-cml/workspace-multiselect/pull/62/issues/issuecomment-2196819235) [/github.com/mit-cml/workspace-multiselect/pull/62#issuecomment-2212561339](https://github.com/google//github.com/mit-cml/workspace-multiselect/pull/62/issues/issuecomment-2212561339) [/github.com/mit-cml/workspace-multiselect/pull/62#issuecomment-2214203536](https://github.com/google//github.com/mit-cml/workspace-multiselect/pull/62/issues/issuecomment-2214203536) - - - -## [8.0.4](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.3...@blockly/dev-tools@8.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.3](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.2...@blockly/dev-tools@8.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.1...@blockly/dev-tools@8.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [8.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@8.0.0...@blockly/dev-tools@8.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [8.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.11...@blockly/dev-tools@8.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) -* Fix the instructions for configuring the debug renderer. ([#2365](https://github.com/google/blockly-samples/issues/2365)) ([ec5405a](https://github.com/google/blockly-samples/commit/ec5405a604aee28c040ebeb55a032fe8e1aafdd3)) -* Include disabled block pattern in screenshot. ([#2189](https://github.com/google/blockly-samples/issues/2189)) ([b60f7be](https://github.com/google/blockly-samples/commit/b60f7beefda331371c53a2ec183cb4e062f223af)) - - - -## [7.1.11](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.10...@blockly/dev-tools@7.1.11) (2024-05-16) - - -### Bug Fixes - -* remove keyboard nav option from dev-tools ([#2347](https://github.com/google/blockly-samples/issues/2347)) ([6215a7e](https://github.com/google/blockly-samples/commit/6215a7e92db5df0f7bca9d8e637eea179b052d54)) - - - -## [7.1.10](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.9...@blockly/dev-tools@7.1.10) (2024-05-09) - - -### Bug Fixes - -* Fix incorrect Blockly imports ([#2339](https://github.com/google/blockly-samples/issues/2339)) ([9af40b9](https://github.com/google/blockly-samples/commit/9af40b9ca075275af2b48cedcc1750d458084eb3)) - - - -## [7.1.9](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.8...@blockly/dev-tools@7.1.9) (2024-04-25) - - -### Bug Fixes - -* update screenshot.js DOM text reinterpreted as HTML ([7a5dcea](https://github.com/google/blockly-samples/commit/7a5dcea446117e632be2a10eb88c81b84c9fdd66)) -* Update screenshot.js DOM text reinterpreted as HTML ([#2328](https://github.com/google/blockly-samples/issues/2328)) ([5665493](https://github.com/google/blockly-samples/commit/5665493a10869a258d59ef561907a2fd7e9e2cca)) - - - -## [7.1.8](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.7...@blockly/dev-tools@7.1.8) (2024-04-04) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.1.7](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.6...@blockly/dev-tools@7.1.7) (2024-03-28) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.1.6](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.5...@blockly/dev-tools@7.1.6) (2024-02-08) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.1.5](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.4...@blockly/dev-tools@7.1.5) (2023-12-14) - - -### Bug Fixes - -* Fix TS errors in plugins/toolbox-search ([#2074](https://github.com/google/blockly-samples/issues/2074)) ([0d18a82](https://github.com/google/blockly-samples/commit/0d18a82137c7a88087a332ece1bb0deff386a390)) - - - -## [7.1.4](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.3...@blockly/dev-tools@7.1.4) (2023-12-07) - - -### Bug Fixes - -* Prevent advanced playground OOMing when scrolling aggressively ([#2089](https://github.com/google/blockly-samples/issues/2089)) ([a662278](https://github.com/google/blockly-samples/commit/a662278cb9c511e001ee3cd2977a891976ea06a9)) - - - -## [7.1.3](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.2...@blockly/dev-tools@7.1.3) (2023-11-09) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.1.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.1...@blockly/dev-tools@7.1.2) (2023-11-02) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.1.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.1.0...@blockly/dev-tools@7.1.1) (2023-10-30) - - -### Bug Fixes - -* Advanced playground should use JSON instead of XML on reload ([#1966](https://github.com/google/blockly-samples/issues/1966)) ([cc8b6b1](https://github.com/google/blockly-samples/commit/cc8b6b10ed6107eb270df994fdd1026e2c409a54)) - - - -## [7.1.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.0.3...@blockly/dev-tools@7.1.0) (2023-09-14) - - -### Features - -* make playground open state persistent ([#1921](https://github.com/google/blockly-samples/issues/1921)) ([#1921](https://github.com/google/blockly-samples/issues/1921)) ([f06f64f](https://github.com/google/blockly-samples/commit/f06f64f8ab2785f587dda1875d5b2b194ed7e7f3)) - - -### Bug Fixes - -* args and types for PlaygroundAPI.addGenerator ([#1889](https://github.com/google/blockly-samples/issues/1889)) ([#1889](https://github.com/google/blockly-samples/issues/1889)) ([f5598a6](https://github.com/google/blockly-samples/commit/f5598a65a26761c3854af06ee7a5a13b46d5ffdb)) - - - -## [7.0.3](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.0.2...@blockly/dev-tools@7.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.0.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.0.1...@blockly/dev-tools@7.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@7.0.0...@blockly/dev-tools@7.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [7.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@6.0.1...@blockly/dev-tools@7.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@6.0.0...@blockly/dev-tools@6.0.1) (2023-07-06) - - -### Bug Fixes - -* debug renderer for v10 ([#1747](https://github.com/google/blockly-samples/issues/1747)) ([3914045](https://github.com/google/blockly-samples/commit/3914045ab25ffbf05c25c3b7e17fee7963e4ec60)) - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.3.2...@blockly/dev-tools@6.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [5.3.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.3.1...@blockly/dev-tools@5.3.2) (2023-06-22) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.3.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.3.0...@blockly/dev-tools@5.3.1) (2023-05-18) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.3.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.6...@blockly/dev-tools@5.3.0) (2023-05-11) - - -### Features - -* Add angle, colour, and multiline fields. (Rebase of [#1674](https://github.com/google/blockly-samples/issues/1674)) ([#1693](https://github.com/google/blockly-samples/issues/1693)) ([1b447f4](https://github.com/google/blockly-samples/commit/1b447f41d6293f14e846b8a4d82d289a5637a99a)) - - - -## [5.2.6](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.5...@blockly/dev-tools@5.2.6) (2023-05-04) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.2.5](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.4...@blockly/dev-tools@5.2.5) (2023-04-27) - - -### Bug Fixes - -* Correct date field test assertions ([#1673](https://github.com/google/blockly-samples/issues/1673)) ([9974e85](https://github.com/google/blockly-samples/commit/9974e85becaa8ad17e35b588b95391c85865dafd)) - - - -## [5.2.4](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.3...@blockly/dev-tools@5.2.4) (2023-03-23) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.2.3](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.2...@blockly/dev-tools@5.2.3) (2023-03-09) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.2.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.1...@blockly/dev-tools@5.2.2) (2023-03-02) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.2.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.2.0...@blockly/dev-tools@5.2.1) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [5.2.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.1.1...@blockly/dev-tools@5.2.0) (2023-02-23) - - -### Features - -* add procedure blocks ([#1544](https://github.com/google/blockly-samples/issues/1544)) ([c190eca](https://github.com/google/blockly-samples/commit/c190eca57865090d9b6027ae4af7eecf425396e8)) - - - -## [5.1.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.1.0...@blockly/dev-tools@5.1.1) (2023-02-16) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.1.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.0.5...@blockly/dev-tools@5.1.0) (2023-02-09) - - -### Features - -* add procedure events ([#1536](https://github.com/google/blockly-samples/issues/1536)) ([05a02ae](https://github.com/google/blockly-samples/commit/05a02aed7f3f59758db83eb2d8459ce727405d4d)) - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.0.4...@blockly/dev-tools@5.0.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.0.3...@blockly/dev-tools@5.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.0.2...@blockly/dev-tools@5.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.0.1...@blockly/dev-tools@5.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@5.0.0...@blockly/dev-tools@5.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/dev-tools@4.0.3...@blockly/dev-tools@5.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* add missing removeGenerator function in Playground API type ([#1224](https://github.com/google/blockly-samples/issues/1224)) ([#1274](https://github.com/google/blockly-samples/issues/1274)) ([9e92461](https://github.com/google/blockly-samples/commit/9e9246153d4089aaa1c9ad011cf5812e3c136f13)) -* generator imports for use with blockly v9 ([#1305](https://github.com/google/blockly-samples/issues/1305)) ([51d59e9](https://github.com/google/blockly-samples/commit/51d59e98d172400e45fc74755f577e068df9996b)) -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Reverts - -* Revert "chore: fix generator imports in dev tools (#1236)" (#1266) ([4da4fd7](https://github.com/google/blockly-samples/commit/4da4fd71e9d56e78075d9809e75ab058cf0cca0e)), closes [#1236](https://github.com/google/blockly-samples/issues/1236) [#1266](https://github.com/google/blockly-samples/issues/1266) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 4.0.3 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 4.0.2 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 3.1.9 (2022-07-21) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## 3.1.8 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 3.1.7 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 3.1.6 (2022-06-21) - -**Note:** Version bump only for package @blockly/dev-tools - - - - - -## 3.1.5 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 3.1.4 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/dev-tools/README.md b/plugins/dev-tools/README.md deleted file mode 100644 index 58c8c2040..000000000 --- a/plugins/dev-tools/README.md +++ /dev/null @@ -1,216 +0,0 @@ -# @blockly/dev-tools [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A library of helpful tools for Blockly development. - -## Installation - -``` -npm install @blockly/dev-tools -D --save -``` - -## Usage - -### Playground - -The playground is a tremendously useful tool for debugging your Blockly project. As a preview, here is [one of the plugin playgrounds](https://raspberrypifoundation.github.io/blockly-samples/plugins/theme-modern/test/). The playground features are: - -- All the default blocks -- All the language generators (JavaScript, Python, PHP, Lua, and Dart) -- Switch between different Blockly options (eg: rtl, renderer, readOnly, zoom and scroll) -- Switch between different toolboxes and themes -- Import and export programs, or generate code using one of the built-in generators -- Trigger programmatic actions (eg: Show/hide, Clear, Undo/Redo, Scale) -- A debug renderer -- Stress tests for the renderer -- Log all events in the console - -```js -import {createPlayground} from '@blockly/dev-tools'; - -const defaultOptions = { - ... -}; -createPlayground(document.getElementById('blocklyDiv'), (blocklyDiv, options) => { - return Blockly.inject(blocklyDiv, options); -}, defaultOptions); -``` - -This package also exports pieces of the playground (addGUIControls, addCodeEditor) if you'd rather build your own playground. - -### Toolboxes - -Blockly built-in Simple and Category toolboxes. - -```js -import * as Blockly from 'blockly'; -import {toolboxSimple, toolboxCategories} from '@blockly/dev-tools'; - -Blockly.inject('blocklyDiv', { - toolbox: toolboxCategories, -}); -``` - -#### Test Toolbox - -The test toolbox is re-exported in this package, but can be imported as a stand-alone through [@blockly/block-test](https://www.npmjs.com/package/@blockly/block-test). See the README for details. - -### Helpers - -#### `populateRandom` - -The `populateRandom` function adds random blocks to a workspace. Blocks are selected from the full set of defined blocks. Pass in a worskpace and how many blocks should be created. - -```js -import {populateRandom} from '@blockly/dev-tools'; -// Add 10 random blocks to the workspace. -populateRandom(workspace, 10); -``` - -#### `spaghetti` - -The `spaghetti` function is a renderer stress test that populates the workspace with nested if-statements. Pass in a worskpace and how deep the nesting should be. - -```js -import {spaghetti} from '@blockly/dev-tools'; -spaghetti(workspace, 8); -``` - -#### `generateFieldTestBlocks` - -The `generateFieldTestBlocks` function automatically generates a number of field testing blocks for the passed-in field. This is useful for testing field plugins. - -```js -import {generateFieldTestBlocks} from '@blockly/dev-tools'; - -const toolbox = generateFieldTestBlocks('field_template', [ - { - args: { - value: 0, // default value - }, - }, -]); -``` - -### Test Helpers - -This package is also used in mocha tests, and exports a suite of useful test helpers. -You can find the full list of helpers [here](https://github.com/RaspberryPiFoundation/blockly-samples/blob/master/plugins/dev-tools/src/test_helpers.mocha.js). - -### Debug Renderer - -The [debug renderer][dev-tools] is a renderer plugin that wraps your normal -renderer, and visualizes the measurements the [render info][render-info] -collects. This is extremely helpful for understanding what your renderer thinks -about the block it is trying to render. - -#### What it surfaces - -The debug renderer can show you several different things. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Debug infoImageDescription
    RowsThe bounds of the individual rows in a block.
    Row spacersThe bounds of the row spacers in a block.
    ElementsThe bounds of the elements in a block.
    Element spacersThe bounds of the element spacers in a block.
    Connections - The locations of the connection points, with large circles for next and - input connections (parent connections) and small circles for output and - previous connections (child connections). -
    Block bounds - The bounds of the block, not including any child blocks. -
    Connectioned block bounds - The bounds of the block, including child blocks. -
    Render / paint - Flashes the block red when the renderer rerenders the block, equivalent - to paint flashing - in Chrome. -
    - -#### How to use it - -The debug renderer wraps your existing renderer, and then you can register and -use it just like any other renderer. - -```js -import {createNewRenderer, DebugDrawer} from '@blockly/dev-tools'; - -const DebugRenderer = createNewRenderer(YourCustomRenderer); -Blockly.blockRendering.register('debugRenderer', DebugRenderer); - -Blockly.inject('blocklyDiv', {renderer: 'debugRenderer'}); -``` - -To see the different information the debug renderer surfaces, you can modify -the config from the browser console. - -```js -DebugDrawer.config = { - rows: true, - rowSpacers: true, - elems: true, - elemSpacers: true, - connections: true, - blockBounds: true, - connectedBlockBounds: true, - render: true, -}; -``` - -[render-info]: https://developers.google.com/blocklyguides/create-custom-blocks/appearance/renderers/concepts/info -[dev-tools]: https://www.npmjs.com/package/@blockly/dev-tools - -### Logger - -A lightweight workspace console logger. - -```js -import {logger} from '@blockly/dev-tools'; - -logger.enableLogger(workspace); -logger.disableLogger(workspace); -``` - -The logger is included by default in the playground. - -## License - -Apache 2.0 diff --git a/plugins/dev-tools/package.json b/plugins/dev-tools/package.json deleted file mode 100644 index 242b133a2..000000000 --- a/plugins/dev-tools/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "@blockly/dev-tools", - "version": "13.2.0", - "description": "A library of common utilities for Blockly extension development.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "start": "blockly-scripts start" - }, - "main": "dist/index.js", - "module": "./src/index.js", - "unpkg": "./dist/index.js", - "types": "./src/index.d.ts", - "author": "Blockly Team", - "keywords": [ - "blockly", - "dev", - "tools" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/dev-tools#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/dev-tools" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "dependencies": { - "@blockly/block-test": "^13.2.0", - "@blockly/theme-dark": "^13.2.0", - "@blockly/theme-deuteranopia": "^13.2.0", - "@blockly/theme-highcontrast": "^13.2.0", - "@blockly/theme-tritanopia": "^13.2.0", - "chai": "^6.2.2", - "dat.gui": "^0.7.9", - "lodash.assign": "^4.2.0", - "lodash.merge": "^4.6.2", - "monaco-editor": "^0.57.0", - "sinon": "^22.0.0" - }, - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@types/dat.gui": "^0.7.13" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/dev-tools/readme-media/block-bounds-with-children.png b/plugins/dev-tools/readme-media/block-bounds-with-children.png deleted file mode 100644 index a2214b6eeb72160d9ac5894a6e4b19e168101da8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53906 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 diff --git a/plugins/dev-tools/readme-media/block-bounds.png b/plugins/dev-tools/readme-media/block-bounds.png deleted file mode 100644 index d41c69339fa196b1a03d014850eeeb226b9dc9f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42639 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 T3c~lWFps9Ho=UBfb;SPxQC$mL diff --git a/plugins/dev-tools/readme-media/element-spacer.png b/plugins/dev-tools/readme-media/element-spacer.png deleted file mode 100644 index d264d784fb9bd50f36f2ce261f836c6544da30f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45737 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 H+9LFSbGld> diff --git a/plugins/dev-tools/readme-media/element.png b/plugins/dev-tools/readme-media/element.png deleted file mode 100644 index 801654125a9ba617e1f0a108af7df6d6a259279d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41503 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≻5>e!YoNwpNiAnh% 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 uI{B~o2kX*$o~Ov^hL%1 diff --git a/plugins/dev-tools/readme-media/row-spacer.png b/plugins/dev-tools/readme-media/row-spacer.png deleted file mode 100644 index a400ca5dfbe2779b66f1976da7dc7b81fbd3381a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36903 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 Y4PQNDI~F6&oB%F;9TV+Jm~-_10Jr+GC;$Ke diff --git a/plugins/dev-tools/readme-media/row.png b/plugins/dev-tools/readme-media/row.png deleted file mode 100644 index 8118582386323225fd106fc767a793b6f97628ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40915 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 diff --git a/plugins/dev-tools/src/block_test_helpers.mocha.js b/plugins/dev-tools/src/block_test_helpers.mocha.js deleted file mode 100644 index 7564368aa..000000000 --- a/plugins/dev-tools/src/block_test_helpers.mocha.js +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {assert} from 'chai'; -import * as sinon from 'sinon'; -import * as commonTestHelpers from './common_test_helpers.mocha'; -import * as Blockly from 'blockly/core'; - -const {runTestCases, runTestSuites, TestCase, TestSuite} = commonTestHelpers; - -/** - * Code generation test case configuration. - * @implements {TestCase} - * @record - */ -export class CodeGenerationTestCase { - /** - * Class for a code generation test case. - */ - constructor() { - /** - * @type {string} The expected code. - */ - this.expectedCode; - /** - * @type {boolean|undefined} Whether to use workspaceToCode instead of - * blockToCode for test. - */ - this.useWorkspaceToCode; - /** - * @type {number|undefined} The expected inner order. - */ - this.expectedInnerOrder; - } - - /** - * Creates the block to use for this test case. - * @param {!Blockly.Workspace} workspace The workspace context for this - * test. - * @returns {!Blockly.Block} The block to use for the test case. - */ - createBlock(workspace) {} -} - -/** - * Code generation test suite. - * @extends {TestSuite} - * @record - */ -export class CodeGenerationTestSuite { - /** - * Class for a code generation test suite. - */ - constructor() { - /** - * @type {!Blockly.Generator} The generator to use for running test cases. - */ - this.generator; - } -} - -/** - * Serialization test case. - * @implements {TestCase} - * @record - */ -export class SerializationTestCase { - /** - * Class for a block serialization test case. - */ - constructor() { - /** - * @type {string} The block xml to use for test. Do not provide if json is - * provided. - */ - this.xml; - /** - * @type {string|undefined} The expected xml after round trip. Provided if - * it different from xml that was passed in. - */ - this.expectedXml; - /** - * @type {string} The block json to use for test. Do not provide if xml is - * provided. - */ - this.json; - /** - * @type {string|undefined} The expected json after round trip. Provided if - * it is different from json that was passed in. - */ - this.expectedJson; - } - /** - * Asserts that the block created from xml has the expected structure. - * @param {!Blockly.Block} block The block to check. - */ - assertBlockStructure(block) {} -} - -/** - * Returns mocha test callback for code generation based on provided - * generator. - * @param {!Blockly.Generator} generator The generator to use in test. - * @returns {function(!CodeGenerationTestCase):!Function} Function that - * returns mocha test callback based on test case. - * @private - */ -const createCodeGenerationTestFn_ = (generator) => { - return (testCase) => { - return function () { - const block = testCase.createBlock(this.workspace); - let code; - let innerOrder; - if (testCase.useWorkspaceToCode) { - code = generator.workspaceToCode(this.workspace); - } else { - generator.init(this.workspace); - code = generator.blockToCode(block); - if (Array.isArray(code)) { - innerOrder = code[1]; - code = code[0]; - } - } - const assertFunc = - typeof testCase.expectedCode === 'string' ? assert.equal : assert.match; - assertFunc(code, testCase.expectedCode); - if ( - !testCase.useWorkspaceToCode && - testCase.expectedInnerOrder !== undefined - ) { - assert.equal(innerOrder, testCase.expectedInnerOrder); - } - }; - }; -}; - -/** - * Runs blockToCode test suites. - * @param {!Array} testSuites The test suites to run. - */ -export const runCodeGenerationTestSuites = (testSuites) => { - /** - * Creates function used to generate mocha test callback. - * @param {!CodeGenerationTestSuite} suiteInfo The test suite information. - * @returns {function(!CodeGenerationTestCase):!Function} Function that - * creates mocha test callback. - */ - const createTestFn = (suiteInfo) => { - return createCodeGenerationTestFn_(suiteInfo.generator); - }; - - runTestSuites(testSuites, createTestFn); -}; - -/** - * Runs serialization test suite. - * @param {!Array} testCases The test cases to run. - * @param {?Blockly} blockly The instance of Blockly to use for the - * tests. Optional, but must be supplied and must correspond to - * the instance used to create this.workspace if that would not - * otherwise be the case. - */ -export const runSerializationTestSuite = (testCases, blockly = Blockly) => { - /** - * Creates test callback for xmlToBlock test. - * @param {!SerializationTestCase} testCase The test case information. - * @returns {!Function} The test callback. - */ - const createSerializedDataToBlockTestCallback = (testCase) => { - return function () { - let block; - if (testCase.json) { - block = blockly.serialization.blocks.append( - testCase.json, - this.workspace, - {recordUndo: true}, - ); - } else { - block = blockly.Xml.domToBlock( - blockly.utils.xml.textToDom(testCase.xml), - this.workspace, - ); - } - if (globalThis.clock) globalThis.clock.runAll(); - testCase.assertBlockStructure(block); - }; - }; - /** - * Creates test callback for xml round trip test. - * @param {!SerializationTestCase} testCase The test case information. - * @returns {!Function} The test callback. - */ - const createRoundTripTestCallback = (testCase) => { - return function () { - if (testCase.json) { - const block = blockly.serialization.blocks.append( - testCase.json, - this.workspace, - {recordUndo: true}, - ); - if (globalThis.clock) globalThis.clock.runAll(); - const generatedJson = blockly.serialization.blocks.save(block); - const expectedJson = testCase.expectedJson || testCase.json; - assert.deepEqual(generatedJson, expectedJson); - } else { - const block = blockly.Xml.domToBlock( - blockly.utils.xml.textToDom(testCase.xml), - this.workspace, - ); - if (globalThis.clock) globalThis.clock.runAll(); - const generatedXml = blockly.Xml.domToPrettyText( - blockly.Xml.blockToDom(block), - ); - const expectedXml = testCase.expectedXml || testCase.xml; - assert.equal(generatedXml, expectedXml); - } - }; - }; - suite('Serialization', function () { - suite('append block', function () { - runTestCases(testCases, createSerializedDataToBlockTestCallback); - }); - suite('serialization round-trip', function () { - setup(function () { - sinon.stub(blockly.utils.idGenerator.TEST_ONLY, 'genUid').returns('1'); - }); - - teardown(function () { - sinon.restore(); - }); - - runTestCases(testCases, createRoundTripTestCallback); - }); - }); -}; diff --git a/plugins/dev-tools/src/common_test_helpers.mocha.js b/plugins/dev-tools/src/common_test_helpers.mocha.js deleted file mode 100644 index 24672c5eb..000000000 --- a/plugins/dev-tools/src/common_test_helpers.mocha.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * Test case configuration. - * @record - */ -export class TestCase { - /** - * Class for a test case configuration. - */ - constructor() { - /** - * @type {string} The title for the test case. - */ - this.title; - /** - * @type {boolean|undefined} Whether this test case should be skipped. - * Used to skip buggy test case and should have an associated bug. - */ - this.skip; - /** - * @type {boolean|undefined} Whether this test case should be called as - * only. Used for debugging. - */ - this.only; - } -} - -/** - * Test suite configuration. - * @record - * @template {TestCase} T - * @template {TestSuite} U - */ -export class TestSuite { - /** - * Class for a test suite configuration. - */ - constructor() { - /** - * @type {string} The title for the test case. - */ - this.title; - /** - * @type {?Array} The associated test cases. - */ - this.testCases; - /** - * @type {?Array} List of nested inner test suites. - */ - this.testSuites; - /** - * @type {boolean|undefined} Whether this test suite should be skipped. - * Used to skip buggy test case and should have an associated bug. - */ - this.skip; - /** - * @type {boolean|undefined} Whether this test suite should be called as - * only. Used for debugging. - */ - this.only; - } -} - -/** - * Runs provided test cases. - * @template {TestCase} T - * @param {!Array} testCases The test cases to run. - * @param {function(T):Function} createTestCallback Creates test - * callback using given test case. - */ -export function runTestCases(testCases, createTestCallback) { - testCases.forEach((testCase) => { - let testCall = testCase.skip ? test.skip : test; - testCall = testCase.only ? test.only : testCall; - testCall(testCase.title, createTestCallback(testCase)); - }); -} - -/** - * Runs provided test suite. - * @template {TestCase} T - * @template {TestSuite} U - * @param {Array} testSuites The test suites to run. - * @param {function(!U):(function(T):!Function) - * } createTestCaseCallback Creates test case callback using given test - * suite. - */ -export function runTestSuites(testSuites, createTestCaseCallback) { - testSuites.forEach((testSuite) => { - let suiteCall = testSuite.skip ? suite.skip : suite; - suiteCall = testSuite.only ? suite.only : suiteCall; - suiteCall(testSuite.title, function () { - if (testSuite.testSuites && testSuite.testSuites.length) { - runTestSuites(testSuite.testSuites, createTestCaseCallback); - } - if (testSuite.testCases && testSuite.testCases.length) { - runTestCases(testSuite.testCases, createTestCaseCallback(testSuite)); - } - }); - }); -} - -/** - * Captures the strings sent to console.warn() when calling a function. - * Copies from core. - * @param {Function} innerFunc The function where warnings may called. - * @returns {Array} The warning messages (only the first arguments). - */ -export function captureWarnings(innerFunc) { - const msgs = []; - const nativeConsoleWarn = console.warn; - try { - console.warn = function (msg) { - msgs.push(msg); - }; - innerFunc(); - } finally { - console.warn = nativeConsoleWarn; - } - return msgs; -} diff --git a/plugins/dev-tools/src/debug.js b/plugins/dev-tools/src/debug.js deleted file mode 100644 index 5adbb7aa5..000000000 --- a/plugins/dev-tools/src/debug.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; -import {DebugDrawer} from './debugDrawer'; - -/** - * The name that the debug renderer is registered under. - * @type {string} - */ -export const debugRendererName = 'debugRenderer'; - -/** - * Creates and registers a renderer that draws debug rectangles on top of the - * blocks. This renderer extends the renderer with the given name. - * @param {string} name The name of the renderer we want to debug. - */ -export function registerDebugRendererFromName(name) { - if (!Blockly.registry.hasItem(Blockly.registry.Type.RENDERER, name)) { - throw Error( - 'No renderer with the name ' + - name + - ' is registered. ' + - 'Please register your renderer using Blockly.registry.register.', - ); - } - const RendererClass = Blockly.registry.getClass( - Blockly.registry.Type.RENDERER, - name, - ); - - const DebugRenderer = createNewRenderer(RendererClass); - - Blockly.registry.register( - Blockly.registry.Type.RENDERER, - debugRendererName, - DebugRenderer, - true, - ); -} - -/** - * Creates a debug renderer. - * @param {function(new: Blockly.blockRendering.Renderer)} Renderer The - * original renderer we are going to extend. - * @returns {function(new: Blockly.blockRendering.Renderer)} The renderer with - * the necessary logic to draw the debug rectangles. - */ -export function createNewRenderer(Renderer) { - /** - * The debug renderer. - */ - class DebugRenderer extends Renderer { - /** - * Maps the id of a block to the object that draws - * the debug rectangles. - * @type {!Object} - */ - blockToDebugger = Object.create(null); - - /** - * Maps the workspace to the workspace event listener. - * @type {!Object} - */ - workspaceListeners = Object.create(null); - - /** @override */ - render(block) { - super.render(block); - const debugDrawer = this.getDebugger_(block); - const info = this.makeRenderInfo_(block); - - info.measure(); - debugDrawer.drawDebug(block, info); - } - - /** - * Gets the debug renderer for the given block. - * If we have already created a debugger for this block, use that debugger - * so that it can remove any previously created html elements. - * @param {Blockly.BlockSvg} block The block that is about to be rendered. - * @returns {DebugDrawer} The object used to draw the debug rectangles - * on the block. - * @private - */ - getDebugger_(block) { - let debugDrawer = this.blockToDebugger[block.id]; - - if (!debugDrawer) { - this.regiserWorkspaceListener_(block.workspace); - debugDrawer = new DebugRenderer.DebugDrawerClass(this.getConstants()); - this.blockToDebugger[block.id] = debugDrawer; - } - return debugDrawer; - } - - /** - * Adds a change listener to the given workspace to remove the reference to - * the block's debugger when a block is deleted. - * @param {Blockly.WorkspaceSvg} workspace The workspace to add the change - * listener to. - * @private - */ - regiserWorkspaceListener_(workspace) { - const workspaceListener = this.workspaceListeners[workspace.id]; - - if (!workspaceListener) { - this.workspaceListeners[workspace.id] = workspace.addChangeListener( - (event) => { - const blockIds = event.ids; - if (event.type === Blockly.Events.DELETE) { - for (let i = 0; i < blockIds.length; i++) { - const blockId = blockIds[i]; - if (this.blockToDebugger[blockId]) { - delete this.blockToDebugger[blockId]; - } - } - } - }, - ); - } - } - } - DebugRenderer.DebugDrawerClass = DebugDrawer; - return DebugRenderer; -} diff --git a/plugins/dev-tools/src/debugDrawer.js b/plugins/dev-tools/src/debugDrawer.js deleted file mode 100644 index 4950b8abe..000000000 --- a/plugins/dev-tools/src/debugDrawer.js +++ /dev/null @@ -1,456 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Visualizer for debugging custom renderers in Blockly. - * @author fenichel@google.com (Rachel Fenichel) - */ -import * as Blockly from 'blockly/core'; - -/** - * A basic visualizer for debugging custom renderers. - */ -export class DebugDrawer { - /** - * An object that renders rectangles and dots for debugging rendering code. - * @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's - * constants. - * @package - * @constructor - */ - constructor(constants) { - /** - * An array of SVG elements that have been created by this object. - * @type {Array.} - * @private - */ - this.debugElements_ = []; - - /** - * The SVG root of the block that is being rendered. Debug elements will - * be attached to this root. - * @type {SVGElement} - * @private - */ - this.svgRoot_ = null; - - /** - * The renderer's constant provider. - * @type {!Blockly.blockRendering.ConstantProvider} - * @private - */ - this.constants_ = constants; - } - - /** - * Remove all elements the this object created on the last pass. - * @protected - */ - clearElems() { - for (let i = 0, elem; (elem = this.debugElements_[i]); i++) { - Blockly.utils.dom.removeNode(elem); - } - - this.debugElements_ = []; - } - - /** - * Draw a debug rectangle for a spacer (empty) row. - * @param {!Blockly.blockRendering.Row} row The row to render. - * @param {number} cursorY The y position of the top of the row. - * @param {boolean} isRtl Whether the block is rendered RTL. - * @protected - */ - drawSpacerRow(row, cursorY, isRtl) { - if (!DebugDrawer.config.rowSpacers) { - return; - } - - const height = Math.abs(row.height); - const isNegativeSpacing = row.height < 0; - if (isNegativeSpacing) { - cursorY -= height; - } - - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'rowSpacerRect blockRenderDebug', - 'x': isRtl ? -(row.xPos + row.width) : row.xPos, - 'y': cursorY, - 'width': row.width, - 'height': height, - 'stroke': isNegativeSpacing ? 'black' : 'blue', - 'fill': 'blue', - 'fill-opacity': '0.5', - 'stroke-width': '1px', - }, - this.svgRoot_, - ), - ); - } - - /** - * Draw a debug rectangle for a horizontal spacer. - * @param {!Blockly.blockRendering.InRowSpacer} elem The spacer to render. - * @param {number} rowHeight The height of the container row. - * @param {boolean} isRtl Whether the block is rendered RTL. - * @protected - */ - drawSpacerElem(elem, rowHeight, isRtl) { - if (!DebugDrawer.config.elemSpacers) { - return; - } - - const width = Math.abs(elem.width); - const isNegativeSpacing = elem.width < 0; - let xPos = isNegativeSpacing ? elem.xPos - width : elem.xPos; - if (isRtl) { - xPos = -(xPos + width); - } - const yPos = elem.centerline - elem.height / 2; - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'elemSpacerRect blockRenderDebug', - 'x': xPos, - 'y': yPos, - 'width': width, - 'height': elem.height, - 'stroke': 'pink', - 'fill': isNegativeSpacing ? 'black' : 'pink', - 'fill-opacity': '0.5', - 'stroke-width': '1px', - }, - this.svgRoot_, - ), - ); - } - - /** - * Draw a debug rectangle for an in-row element. - * @param {!Blockly.blockRendering.Measurable} elem The element to render. - * @param {boolean} isRtl Whether the block is rendered RTL. - * @protected - */ - drawRenderedElem(elem, isRtl) { - if (DebugDrawer.config.elems) { - let xPos = elem.xPos; - if (isRtl) { - xPos = -(xPos + elem.width); - } - const yPos = elem.centerline - elem.height / 2; - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'rowRenderingRect blockRenderDebug', - 'x': xPos, - 'y': yPos, - 'width': elem.width, - 'height': elem.height, - 'stroke': 'black', - 'fill': 'none', - 'stroke-width': '1px', - }, - this.svgRoot_, - ), - ); - - if ( - Blockly.blockRendering.Types.isField(elem) && - elem.field instanceof Blockly.FieldLabel - ) { - const baseline = this.constants_.FIELD_TEXT_BASELINE; - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'rowRenderingRect blockRenderDebug', - 'x': xPos, - 'y': yPos + baseline, - 'width': elem.width, - 'height': '0.1px', - 'stroke': 'red', - 'fill': 'none', - 'stroke-width': '0.5px', - }, - this.svgRoot_, - ), - ); - } - } - - if ( - Blockly.blockRendering.Types.isInput(elem) && - DebugDrawer.config.connections - ) { - this.drawConnection(elem.connectionModel); - } - } - - /** - * Draw a circle at the location of the given connection. Inputs and outputs - * share the same colours, as do previous and next. When positioned correctly - * a connected pair will look like a bullseye. - * @param {Blockly.RenderedConnection} conn The connection to circle. - * @protected - */ - drawConnection(conn) { - if (!DebugDrawer.config.connections) { - return; - } - - let colour; - let size; - let fill; - if (conn.type == Blockly.INPUT_VALUE) { - size = 4; - colour = 'magenta'; - fill = 'none'; - } else if (conn.type == Blockly.OUTPUT_VALUE) { - size = 2; - colour = 'magenta'; - fill = colour; - } else if (conn.type == Blockly.NEXT_STATEMENT) { - size = 4; - colour = 'goldenrod'; - fill = 'none'; - } else if (conn.type == Blockly.PREVIOUS_STATEMENT) { - size = 2; - colour = 'goldenrod'; - fill = colour; - } - // TODO(blockly/7227): This method is still internal, so we're going to - // have continual problems. We should consider making it public. - const offset = conn.getOffsetInBlock(); - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'circle', - { - class: 'blockRenderDebug', - cx: offset.x, - cy: offset.y, - r: size, - fill: fill, - stroke: colour, - }, - this.svgRoot_, - ), - ); - } - - /** - * Draw a debug rectangle for a non-empty row. - * @param {!Blockly.blockRendering.Row} row The non-empty row to render. - * @param {number} cursorY The y position of the top of the row. - * @param {boolean} isRtl Whether the block is rendered RTL. - * @protected - */ - drawRenderedRow(row, cursorY, isRtl) { - if (!DebugDrawer.config.rows) { - return; - } - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'elemRenderingRect blockRenderDebug', - 'x': isRtl ? -(row.xPos + row.width) : row.xPos, - 'y': row.yPos, - 'width': row.width, - 'height': row.height, - 'stroke': 'red', - 'fill': 'none', - 'stroke-width': '1px', - }, - this.svgRoot_, - ), - ); - - if (Blockly.blockRendering.Types.isTopOrBottomRow(row)) { - return; - } - - if (DebugDrawer.config.connectedBlockBounds) { - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'connectedBlockWidth blockRenderDebug', - 'x': isRtl ? -(row.xPos + row.widthWithConnectedBlocks) : row.xPos, - 'y': row.yPos, - 'width': row.widthWithConnectedBlocks, - 'height': row.height, - 'stroke': this.randomColour_, - 'fill': 'none', - 'stroke-width': '1px', - 'stroke-dasharray': '3,3', - }, - this.svgRoot_, - ), - ); - } - } - - /** - * Draw debug rectangles for a non-empty row and all of its subcomponents. - * @param {!Blockly.blockRendering.Row} row The non-empty row to render. - * @param {number} cursorY The y position of the top of the row. - * @param {boolean} isRtl Whether the block is rendered RTL. - * @protected - */ - drawRowWithElements(row, cursorY, isRtl) { - for (let i = 0, l = row.elements.length; i < l; i++) { - const elem = row.elements[i]; - if (!elem) { - console.warn('A row has an undefined or null element.', row, elem); - continue; - } - if (Blockly.blockRendering.Types.isSpacer(elem)) { - this.drawSpacerElem( - /** @type {!Blockly.blockRendering.InRowSpacer} */ (elem), - row.height, - isRtl, - ); - } else { - this.drawRenderedElem(elem, isRtl); - } - } - this.drawRenderedRow(row, cursorY, isRtl); - } - - /** - * Draw a debug rectangle around the entire block. - * @param {!Blockly.blockRendering.RenderInfo} info Rendering information - * about the block to debug. - * @protected - */ - drawBoundingBox(info) { - if (!DebugDrawer.config.blockBounds) { - return; - } - // Bounding box without children. - let xPos = info.RTL ? -info.width : 0; - const yPos = 0; - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'blockBoundingBox blockRenderDebug', - 'x': xPos, - 'y': yPos, - 'width': info.width, - 'height': info.height, - 'stroke': 'black', - 'fill': 'none', - 'stroke-width': '1px', - 'stroke-dasharray': '5,5', - }, - this.svgRoot_, - ), - ); - - if (DebugDrawer.config.connectedBlockBounds) { - // Bounding box with children. - xPos = info.RTL ? -info.widthWithChildren : 0; - this.debugElements_.push( - Blockly.utils.dom.createSvgElement( - 'rect', - { - 'class': 'blockRenderDebug', - 'x': xPos, - 'y': yPos, - 'width': info.widthWithChildren, - 'height': info.height, - 'stroke': '#DF57BC', - 'fill': 'none', - 'stroke-width': '1px', - 'stroke-dasharray': '3,3', - }, - this.svgRoot_, - ), - ); - } - } - - /** - * Do all of the work to draw debug information for the whole block. - * @param {!Blockly.BlockSvg} block The block to draw debug information for. - * @param {!Blockly.blockRendering.RenderInfo} info Rendering information - * about the block to debug. - */ - drawDebug(block, info) { - this.clearElems(); - this.svgRoot_ = block.getSvgRoot(); - - this.randomColour_ = - '#' + Math.floor(Math.random() * 16777215).toString(16); - - let cursorY = 0; - for (let i = 0, row; (row = info.rows[i]); i++) { - if (Blockly.blockRendering.Types.isBetweenRowSpacer(row)) { - this.drawSpacerRow(row, cursorY, info.RTL); - } else { - this.drawRowWithElements(row, cursorY, info.RTL); - } - cursorY += row.height; - } - - if (block.previousConnection) { - this.drawConnection(block.previousConnection); - } - if (block.nextConnection) { - this.drawConnection(block.nextConnection); - } - if (block.outputConnection) { - this.drawConnection(block.outputConnection); - } - if (info.rightSide) { - this.drawRenderedElem(info.rightSide, info.RTL); - } - - this.drawBoundingBox(info); - - this.drawRender(block.pathObject.svgPath); - } - - /** - * Show a debug filter to highlight that a block has been rendered. - * @param {!SVGElement} svgPath The block's svg path. - * @protected - */ - drawRender(svgPath) { - if (!DebugDrawer.config.render) { - return; - } - svgPath.setAttribute( - 'filter', - 'url(#' + this.constants_.debugFilterId + ')', - ); - setTimeout(function () { - svgPath.setAttribute('filter', ''); - }, 100); - } -} - -/** - * Configuration object containing booleans to enable and disable debug - * rendering of specific rendering components. - * @type {!Object.} - */ -DebugDrawer.config = { - rowSpacers: true, - elemSpacers: true, - rows: true, - elems: true, - connections: true, - blockBounds: true, - connectedBlockBounds: true, - render: true, -}; diff --git a/plugins/dev-tools/src/event_test_helpers.mocha.js b/plugins/dev-tools/src/event_test_helpers.mocha.js deleted file mode 100644 index eb01f6bc5..000000000 --- a/plugins/dev-tools/src/event_test_helpers.mocha.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const Blockly = require('blockly/core'); -const sinon = require('sinon'); - -/** - * Returns a matcher that asserts that the actual object has the same properties - * and values (shallowly equated) as the expected object. - * @param {!Object} expected The expected set of properties we expect the - * actual object to have. - * @returns {function(*): boolean} A matcher that returns true if the `actual` - * object has all of the properties of the `expected` param, with the same - * values. - */ -function shallowMatch(expected) { - return (actual) => { - for (const key in expected) { - if (actual[key] !== expected[key]) { - return false; - } - } - return true; - }; -} - -/** - * Asserts that an event with the given values (shallowly evaluated) was fired. - * @param {!sinon.SinonSpyCall|!sinon.SinonSpy} spy The spy or spy call to use. - * @param {function(new:Blockly.Events.Abstract)} instanceType Expected instance - * type of event fired. - * @param {!Object} expectedProperties Map of of expected properties - * to check on fired event. - * @param {string} expectedWorkspaceId Expected workspace id of event fired. - * @param {?string=} expectedBlockId Expected block id of event fired. - */ -export function assertEventFiredShallow( - spy, - instanceType, - expectedProperties, - expectedWorkspaceId, - expectedBlockId, -) { - const properties = { - ...expectedProperties, - workspaceId: expectedWorkspaceId, - blockId: expectedBlockId, - }; - sinon.assert.match( - /** @type {sinon.SinonSpy} */ (spy).getCalls()[0].firstArg, - sinon.match - .instanceOf(instanceType) - .and(sinon.match(shallowMatch(properties))), - ); - // TODO: Why does the above assert work but not this one??? - // Also it does work when it's in the other pluging - // sinon.assert.calledWith( - // spy, - // sinon.match.instanceOf(instanceType) - // .and(sinon.match(shallowMatch(properties)))); -} - -/** - * Asserts that an event with the given values was not fired. - * @param {!sinon.SinonSpy} spy The spy to use. - * @param {function(new:Blockly.Events.Abstract)} instanceType Expected instance - * type of event fired. - * @param {!Object} expectedProperties Map of of expected properties - * to check on fired event. - * @param {string=} expectedWorkspaceId Expected workspace id of event fired. - * @param {?string=} expectedBlockId Expected block id of event fired. - */ -export function assertEventNotFired( - spy, - instanceType, - expectedProperties, - expectedWorkspaceId, - expectedBlockId, -) { - if (expectedWorkspaceId !== undefined) { - expectedProperties.workspaceId = expectedWorkspaceId; - } - if (expectedBlockId !== undefined) { - expectedProperties.blockId = expectedBlockId; - } - const expectedEvent = sinon.match - .instanceOf(instanceType) - .and(sinon.match(expectedProperties)); - sinon.assert.neverCalledWith(spy, expectedEvent); -} diff --git a/plugins/dev-tools/src/field_test_helpers.mocha.js b/plugins/dev-tools/src/field_test_helpers.mocha.js deleted file mode 100644 index 1eb54fab3..000000000 --- a/plugins/dev-tools/src/field_test_helpers.mocha.js +++ /dev/null @@ -1,310 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {assert} from 'chai'; -import {runTestCases, TestCase} from './common_test_helpers.mocha'; - -/** - * Field value test case. - * @implements {TestCase} - * @record - */ -export class FieldValueTestCase { - /** - * Class for a field value test case. - */ - constructor() { - /** - * @type {*} The value to use in test. - */ - this.value; - /** - * @type {*} The expected value. - */ - this.expectedValue; - /** - * @type {string|undefined} The expected text value. Provided if different - * from String(expectedValue). - */ - this.expectedText; - /** - * @type {!RegExp|string|undefined} The optional error message matcher. - * Provided if test case is expected to throw. - */ - this.errMsgMatcher; - } -} - -/** - * Field creation test case. - * @extends {FieldValueTestCase} - * @record - */ -export class FieldCreationTestCase { - /** - * Class for a field creation test case. - */ - constructor() { - /** - * @type {Array<*>} The arguments to pass to field constructor. - */ - this.args; - /** - * @type {string} The json to use in field creation. - */ - this.json; - } -} - -/** - * Assert a field's value is the same as the expected value. - * @param {!Blockly.Field} field The field. - * @param {*} expectedValue The expected value. - * @param {string=} expectedText The expected text. - */ -export function assertFieldValue( - field, - expectedValue, - expectedText = undefined, -) { - const actualValue = field.getValue(); - const actualText = field.getText(); - if (expectedText === undefined) { - expectedText = String(expectedValue); - } - assert.equal(actualValue, expectedValue, 'Value'); - assert.equal(actualText, expectedText, 'Text'); -} - -/** - * Runs provided creation test cases. - * @param {!Array} testCases The test cases to run. - * @param {function(!Blockly.Field, !FieldCreationTestCase)} assertion The - * assertion to use. - * @param {function(new:Blockly.Field,!FieldCreationTestCase):Blockly.Field - * } creation A function that returns an instance of the field based on the - * provided test case. - * @private - */ -function runCreationTests_(testCases, assertion, creation) { - /** - * Creates test callback for creation test. - * @param {FieldCreationTestCase} testCase The test case to use. - * @returns {Function} The test callback. - */ - const createTestFn = (testCase) => { - return function () { - const field = creation.call(this, testCase); - assertion(field, testCase); - }; - }; - runTestCases(testCases, createTestFn); -} - -/** - * Runs provided creation test cases. - * @param {!Array} testCases The test cases to run. - * @param {function(new:Blockly.Field,!FieldCreationTestCase):Blockly.Field - * } creation A function that returns an instance of the field based on the - * provided test case. - * @private - */ -function runCreationTestsAssertThrows_(testCases, creation) { - /** - * Creates test callback for creation test. - * @param {!FieldCreationTestCase} testCase The test case to use. - * @returns {!Function} The test callback. - */ - const createTestFn = (testCase) => { - return function () { - assert.throws(function () { - creation.call(this, testCase); - }, testCase.errMsgMatcher); - }; - }; - runTestCases(testCases, createTestFn); -} - -/** - * Runs suite of tests for constructor for the specified field. - * @param {function(new:Blockly.Field, *=)} TestedField The class of the field - * being tested. - * @param {Array} validValueTestCases Test cases with - * valid values for given field. - * @param {Array} invalidValueTestCases Test cases with - * invalid values for given field. - * @param {function(!Blockly.Field, !FieldCreationTestCase) - * } validRunAssertField Asserts that field has expected values. - * @param {function(!Blockly.Field)=} assertFieldDefault Asserts that field has - * default values. If undefined, tests will check that field throws when - * invalid value is passed rather than asserting default. - * @param {function(!FieldCreationTestCase=)=} customCreateWithJs Custom - * creation function to use in tests. - */ -export function runConstructorSuiteTests( - TestedField, - validValueTestCases, - invalidValueTestCases, - validRunAssertField, - assertFieldDefault, - customCreateWithJs, -) { - suite('Constructor', function () { - if (assertFieldDefault) { - test('Empty', function () { - const field = customCreateWithJs - ? customCreateWithJs.call(this) - : new TestedField(); - assertFieldDefault(field); - }); - } else { - test('Empty', function () { - assert.throws(function () { - customCreateWithJs - ? customCreateWithJs.call(this) - : new TestedField(); - }); - }); - } - - /** - * Creates a field using its constructor and the provided test case. - * @param {!FieldCreationTestCase} testCase The test case information. - * @returns {!Blockly.Field} The instantiated field. - */ - const createWithJs = function (testCase) { - return customCreateWithJs - ? customCreateWithJs.call(this, testCase) - : new TestedField(...testCase.args); - }; - if (assertFieldDefault) { - runCreationTests_( - invalidValueTestCases, - assertFieldDefault, - createWithJs, - ); - } else { - runCreationTestsAssertThrows_(invalidValueTestCases, createWithJs); - } - runCreationTests_(validValueTestCases, validRunAssertField, createWithJs); - }); -} - -/** - * Runs suite of tests for fromJson creation of specified field. - * @param {function(new:Blockly.Field, *=)} TestedField The class of the field - * being tested. - * @param {!Array} validValueTestCases Test cases with - * valid values for given field. - * @param {!Array} invalidValueTestCases Test cases with - * invalid values for given field. - * @param {function(!Blockly.Field, !FieldValueTestCase) - * } validRunAssertField Asserts that field has expected values. - * @param {function(!Blockly.Field)=} assertFieldDefault Asserts that field has - * default values. If undefined, tests will check that field throws when - * invalid value is passed rather than asserting default. - * @param {function(!FieldCreationTestCase=)=} customCreateWithJson Custom - * creation function to use in tests. - */ -export function runFromJsonSuiteTests( - TestedField, - validValueTestCases, - invalidValueTestCases, - validRunAssertField, - assertFieldDefault, - customCreateWithJson, -) { - suite('fromJson', function () { - if (assertFieldDefault) { - test('Empty', function () { - const field = customCreateWithJson - ? customCreateWithJson.call(this) - : TestedField.fromJson({}); - assertFieldDefault(field); - }); - } else { - test('Empty', function () { - assert.throws(function () { - customCreateWithJson - ? customCreateWithJson.call(this) - : TestedField.fromJson({}); - }); - }); - } - - /** - * Creates a field using fromJson and the provided test case. - * @param {!FieldCreationTestCase} testCase The test case information. - * @returns {!Blockly.Field} The instantiated field. - */ - const createWithJson = function (testCase) { - return customCreateWithJson - ? customCreateWithJson.call(this, testCase) - : TestedField.fromJson(testCase.json); - }; - if (assertFieldDefault) { - runCreationTests_( - invalidValueTestCases, - assertFieldDefault, - createWithJson, - ); - } else { - runCreationTestsAssertThrows_(invalidValueTestCases, createWithJson); - } - runCreationTests_(validValueTestCases, validRunAssertField, createWithJson); - }); -} - -/** - * Runs tests for setValue calls. - * @param {!Array} validValueTestCases Test cases with - * valid values. - * @param {!Array} invalidValueTestCases Test cases with - * invalid values. - * @param {*} invalidRunExpectedValue Expected value for field after invalid - * call to setValue. - * @param {string=} invalidRunExpectedText Expected text for field after invalid - * call to setValue. - */ -export function runSetValueTests( - validValueTestCases, - invalidValueTestCases, - invalidRunExpectedValue, - invalidRunExpectedText, -) { - /** - * Creates test callback for invalid setValue test. - * @param {!FieldValueTestCase} testCase The test case information. - * @returns {!Function} The test callback. - */ - const createInvalidSetValueTestCallback = (testCase) => { - return function () { - this.field.setValue(testCase.value); - assertFieldValue( - this.field, - invalidRunExpectedValue, - invalidRunExpectedText, - ); - }; - }; - /** - * Creates test callback for valid setValue test. - * @param {!FieldValueTestCase} testCase The test case information. - * @returns {!Function} The test callback. - */ - const createValidSetValueTestCallback = (testCase) => { - return function () { - this.field.setValue(testCase.value); - assertFieldValue( - this.field, - testCase.expectedValue, - testCase.expectedText, - ); - }; - }; - runTestCases(invalidValueTestCases, createInvalidSetValueTestCallback); - runTestCases(validValueTestCases, createValidSetValueTestCallback); -} diff --git a/plugins/dev-tools/src/generateFieldTestBlocks.js b/plugins/dev-tools/src/generateFieldTestBlocks.js deleted file mode 100644 index e0ac8f0ef..000000000 --- a/plugins/dev-tools/src/generateFieldTestBlocks.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A field test helper that generates blocks with the field in - * various configurations. - * @author samelh@google.com (Sam El-Husseini) - */ - -import * as Blockly from 'blockly/core'; - -/** - * Generates a number of field testing blocks for a specific field and returns - * the toolbox xml string. - * @param {string} fieldName The name of the field. - * @param {Object|Array=} options An options object containing a label - * and an args map that is passed to the field during initialization. If an - * array is passed, multiple groups of blocks are created each with - * different initialization arguments. - * @returns {string} The toolbox XML string. - */ -export function generateFieldTestBlocks(fieldName, options) { - if (!Array.isArray(options)) { - options = [options || {}]; - } - - let id = 0; - let toolboxXml = ''; - const blocks = []; - - options.forEach((m) => { - if (m.label) { - // Add label. - toolboxXml += ``; - } - - // Define a single field block. - const singleFieldBlock = `${++id}test_${fieldName}_single`; - blocks.push({ - type: singleFieldBlock, - message0: '%1', - args0: [ - { - type: fieldName, - name: 'FIELDNAME', - ...m.args, - alt: { - type: 'field_label', - text: `No ${fieldName}`, - }, - }, - ], - output: null, - style: 'math_blocks', - }); - toolboxXml += ``; - toolboxXml += ``; - - // Define a block and add the 'single field block' as a shadow. - const parentBlock = `${++id}test_${fieldName}_parent`; - blocks.push({ - type: `${parentBlock}`, - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }); - - toolboxXml += ` - - - - - `; - toolboxXml += ``; - - // Define a block with the field on it. - const blockWithField = `${++id}test_${fieldName}_block`; - blocks.push({ - type: blockWithField, - message0: 'block %1', - args0: [ - { - type: fieldName, - name: 'FIELDNAME', - ...m.args, - alt: { - type: 'field_label', - text: `No ${fieldName}`, - }, - }, - ], - output: null, - style: 'math_blocks', - }); - toolboxXml += ``; - toolboxXml += ``; - - // Add a block that includes the 'block with the field' as a shadow. - toolboxXml += ` - - - - - `; - }); - - Blockly.defineBlocksWithJsonArray(blocks); - - return ` - ${toolboxXml} - `; -} diff --git a/plugins/dev-tools/src/index.d.ts b/plugins/dev-tools/src/index.d.ts deleted file mode 100644 index cc3a00659..000000000 --- a/plugins/dev-tools/src/index.d.ts +++ /dev/null @@ -1,120 +0,0 @@ -import * as Blockly from 'blockly/core'; -import * as dat from 'dat.gui'; - -interface FieldGeneratorOptions { - label?: string; - args: {[key: string]: unknown}; -} - -interface PlaygroundTab { - generate: () => void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - state: any; - tabElement: HTMLElement; -} - -interface PlaygroundAPI { - addAction: ( - name: string, - callback: (workspace: Blockly.Workspace) => void, - folder?: string, - ) => dat.GUIController; - addCheckboxAction: ( - name: string, - callback: (workspace: Blockly.Workspace, value: boolean) => void, - folder?: string, - defaultValue?: boolean, - ) => dat.GUIController; - addGenerator: ( - label: string, - generator: Blockly.Generator, - language?: string, - ) => void; - getCurrentTab: () => PlaygroundTab; - getGUI: () => DevTools.GUI; - getWorkspace: () => Blockly.WorkspaceSvg; - removeGenerator: (label: string) => void; -} - -declare namespace DevTools { - /** - * A basic visualizer for debugging custom renderers. - */ - export class DebugRenderer extends Blockly.blockRendering.Debug { - static init(): void; - } - - /** - * An extension of dat.GUI with additional functionality. - */ - export class GUI extends dat.GUI { - addAction( - name: string, - callback: (workspace: Blockly.Workspace) => void, - folder?: string, - ): dat.GUIController; - addCheckboxAction: ( - name: string, - callback: (workspace: Blockly.Workspace, value: boolean) => void, - folder?: string, - defaultValue?: boolean, - ) => dat.GUIController; - getWorkspace: () => Blockly.WorkspaceSvg; - } - - /** - * Create the Blockly playground. - * - * @param container - * @param createWorkspace - * @param defaultOptions - * @param vsEditorPath - * @returns A promise to the playground API. - */ - function createPlayground( - container: HTMLElement, - createWorkspace?: ( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, - ) => Blockly.Workspace, - defaultOptions?: Blockly.BlocklyOptions, - vsEditorPath?: string, - ): Promise; - - /** - * Use dat.GUI to add controls to adjust configuration of a Blockly workspace. - * - * @param createWorkspace - * @param defaultOptions - * @returns The dat.GUI instance. - */ - function addGUIControls( - createWorkspace: (options: Blockly.BlocklyOptions) => Blockly.Workspace, - defaultOptions: Blockly.BlocklyOptions, - ): GUI; - - /** - * Generates a number of field testing blocks for a specific field and returns - * the toolbox xml string. - * - * @param fieldName - * @param options - * @returns The toolbox xml string. - */ - export function generateFieldTestBlocks( - fieldName: string, - options?: FieldGeneratorOptions | FieldGeneratorOptions[], - ): string; - - /** - * A toolbox xml with built-in blocks split into categories. - */ - const toolboxCategories: Blockly.utils.toolbox.ToolboxInfo; - - /** - * A simple toolbox xml with built-in blocks and no categories. - */ - const toolboxSimple: Blockly.utils.toolbox.ToolboxInfo; -} - -export = DevTools; diff --git a/plugins/dev-tools/src/index.js b/plugins/dev-tools/src/index.js deleted file mode 100644 index 6cd083b8f..000000000 --- a/plugins/dev-tools/src/index.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -import {DebugDrawer} from './debugDrawer'; -import {createNewRenderer} from './debug'; -import {generateFieldTestBlocks} from './generateFieldTestBlocks'; -import {populateRandom} from './populateRandom'; -import {downloadWorkspaceScreenshot} from './screenshot'; -import {spaghetti} from './spaghetti'; -import * as logger from './logger'; -import * as testHelpers from './test_helpers.mocha'; -import {toolboxTestBlocksInit, toolboxTestBlocks} from '@blockly/block-test'; -import toolboxCategories from './toolboxCategories'; -import toolboxSimple from './toolboxSimple'; - -let addGUIControls; -let addCodeEditor; -let createPlayground; -if (typeof window !== 'undefined') { - addGUIControls = require('./playground/options').addGUIControls; - addCodeEditor = require('./playground/monaco').addCodeEditor; - createPlayground = require('./playground/').createPlayground; -} - -// Export Blockly into the global namespace to make it easier to debug from the -// console. -globalThis.Blockly = Blockly; - -export { - addCodeEditor, - addGUIControls, - createNewRenderer, - createPlayground, - DebugDrawer, - downloadWorkspaceScreenshot, - generateFieldTestBlocks, - populateRandom, - logger, - spaghetti, - testHelpers, - toolboxCategories, - toolboxSimple, - toolboxTestBlocks, - toolboxTestBlocksInit, -}; diff --git a/plugins/dev-tools/src/logger.js b/plugins/dev-tools/src/logger.js deleted file mode 100644 index 98d3f57e9..000000000 --- a/plugins/dev-tools/src/logger.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A workspace console logger. - * @author samelh@google.com (Sam El-Husseini) - */ - -/** - * Enables console logging of workspace events. - * @param {!Blockly.Workspace} workspace The Blockly workspace. - */ -export function enableLogger(workspace) { - workspace.addChangeListener(log); -} - -/** - * Disables console logging of workspace events. - * @param {!Blockly.Workspace} workspace The Blockly workspace. - */ -export function disableLogger(workspace) { - workspace.removeChangeListener(log); -} - -/** - * Logs a Blockly event directory to the console. - * @param {!Blockly.Events.Abstract} e The Blockly event. - */ -function log(e) { - console.log(e); -} diff --git a/plugins/dev-tools/src/playground/hash_state.js b/plugins/dev-tools/src/playground/hash_state.js deleted file mode 100644 index fb1c82c79..000000000 --- a/plugins/dev-tools/src/playground/hash_state.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview State manager for window.location.hash. - * @author samelh@google.com (Sam El-Husseini) - */ - -/** - * A class that manages loading / storing the state from a window hash. - */ -export class HashState { - /** - * Load the state from the window hash string. - * @param {string} hash The hash string. - * @param {Object} state The state. - */ - static parse(hash, state) { - decodeURIComponent(hash).replace( - /#?([^=&]+)=([^=&]+)/gm, - function (_m0, key, value) { - let current = state; - let i; - while ((i = key.indexOf('.')) > -1) { - current[key.substr(0, i)] = current[key.substr(0, i)] || {}; - current = current[key.substr(0, i)]; - key = key.substr(i + 1); - } - // Parse the value. - if (value == 'true' || value == 'false') { - // Boolean. - value = value == 'true'; - } else if (!isNaN(value)) { - // Number. - value = Number(value); - } - current[key] = value; - }, - ); - } - - /** - * Serialize the state into a hash string. - * @param {Object} state The state. - * @returns {string} The serialized state. - */ - static save(state) { - const result = {}; - const flatten = (cur, prop) => { - if (Object(cur) !== cur) { - result[prop] = cur; - } else { - let isEmpty = true; - for (const p in cur) { - if (Object.prototype.hasOwnProperty.call(cur, p)) { - isEmpty = false; - flatten(cur[p], prop ? prop + '.' + p : p); - } - } - if (isEmpty && prop != '') { - result[prop] = {}; - } - } - }; - flatten(state, ''); - return Object.keys(result) - .map((k) => `${k}=${result[k]}`) - .join('&'); - } -} diff --git a/plugins/dev-tools/src/playground/id.js b/plugins/dev-tools/src/playground/id.js deleted file mode 100644 index 2469fc843..000000000 --- a/plugins/dev-tools/src/playground/id.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Returns the package name. - * @author samelh@google.com (Sam El-Husseini) - */ - -export const id = process.env.PACKAGE_NAME; diff --git a/plugins/dev-tools/src/playground/index.js b/plugins/dev-tools/src/playground/index.js deleted file mode 100644 index 942bbc349..000000000 --- a/plugins/dev-tools/src/playground/index.js +++ /dev/null @@ -1,661 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Entry point for the Blockly playground. - * @author samelh@google.com (Sam El-Husseini) - */ - -import {toolboxTestBlocks, toolboxTestBlocksInit} from '@blockly/block-test'; -import {dartGenerator} from 'blockly/dart'; -import {javascriptGenerator} from 'blockly/javascript'; -import {luaGenerator} from 'blockly/lua'; -import {phpGenerator} from 'blockly/php'; -import {pythonGenerator} from 'blockly/python'; - -import {downloadWorkspaceScreenshot} from '../screenshot'; -import toolboxCategories from '../toolboxCategories'; -import toolboxSimple from '../toolboxSimple'; - -import {id} from './id'; -import {addCodeEditor} from './monaco'; -import {addGUIControls} from './options'; -import {LocalStorageState} from './state'; -import { - renderButton, - renderCheckbox, - renderCodeTab, - renderPlayground, -} from './ui'; - -/** - * @typedef {function(!HTMLElement,!Blockly.BlocklyOptions): - * Blockly.WorkspaceSvg} - */ -let CreateWorkspaceFn; - -/** - * @typedef {{ - * generate: function(): void, - * state: ?, - * tabElement: !HTMLElement - * }} - */ -let PlaygroundTab; - -/** - * @typedef {Blockly.utils.toolbox.ToolboxDefinition} BlocklyToolbox - */ - -/** - * @typedef {Object} PlaygroundConfig - * @property {boolean} [auto] Whether or not to automatically import, and run - * the XML and code generators. - * @property {Object} [toolboxes] The toolbox registry. - */ - -/** - * @typedef {{ - * state: ?, - * addAction:function(string,function(!Blockly.Workspace):void,string=): - * dat.GUI, - * addCheckboxAction:function(string, - * function(!Blockly.Workspace,boolean):void,string=,boolean=):dat.GUI, - * addGenerator: function(string,!Blockly.Generator,string=):void, - * getCurrentTab: function():!PlaygroundTab, - * getGUI: function():!dat.GUI, - * getWorkspace: function():!Blockly.WorkspaceSvg - * }} - */ -let PlaygroundAPI; - -/** - * Create the Blockly playground. - * @param {!HTMLElement} container Container element. - * @param {CreateWorkspaceFn=} createWorkspace A workspace creation method - * called every time the toolbox is re-configured. - * @param {Blockly.BlocklyOptions=} defaultOptions The default workspace options - * to use. - * @param {PlaygroundConfig=} config Optional Playground config. - * @param {string=} vsEditorPath Optional editor path. - * @returns {Promise} A promise to the playground API. - */ -export function createPlayground( - container, - createWorkspace = Blockly.inject, - defaultOptions = { - toolbox: toolboxCategories, - }, - config = {}, - vsEditorPath, -) { - const { - blocklyDiv, - minimizeButton, - monacoDiv, - guiContainer, - playgroundDiv, - tabButtons, - tabsDiv, - } = renderPlayground(container); - - const monacoOptions = { - model: null, - language: 'xml', - minimap: { - enabled: false, - }, - theme: 'vs-dark', - scrollBeyondLastLine: false, - automaticLayout: true, - }; - - // Load the code editor. - return addCodeEditor(monacoDiv, monacoOptions, vsEditorPath).then( - (editor) => { - let workspace; - - // Create a model for displaying errors. - const errorModel = window.monaco.editor.createModel(''); - const editorXmlContextKey = editor.createContextKey('isEditorXml', true); - const editorJsonContextKey = editor.createContextKey( - 'isEditorJson', - true, - ); - - // Load / Save playground state. - // setting active tab as JSON - const playgroundState = new LocalStorageState(`playgroundState_${id}`, { - activeTab: 'JSON', - playgroundOpen: true, - autoGenerate: config && config.auto != undefined ? config.auto : true, - workspaceJson: '', - }); - playgroundState.load(); - - /** - * Register a generator and create a new code tab for it. - * @param {string} name The generator label. - * @param {string} language The monaco language to use. - * @param {function(Blockly.WorkspaceSvg):string} generator - * The Blockly generator. - * @param {boolean=} isReadOnly Whether the editor should be set to - * read-only mode. - * @returns {!PlaygroundTab} An object that represents the newly created - * tab. - */ - function registerGenerator(name, language, generator, isReadOnly) { - const tabElement = renderCodeTab(name); - tabElement.setAttribute('data-tab', name); - tabsDiv.appendChild(tabElement); - - // Create a monaco editor model for each tab. - const model = window.monaco.editor.createModel('', language); - const state = { - name, - model, - language, - viewState: undefined, - }; - - /** - * Call the generator, displaying an error message if it fails. - */ - function generate() { - let text; - let generateModel = model; - try { - text = generator(workspace); - } catch (e) { - console.error(e); - text = e.message; - generateModel = errorModel; - editor.updateOptions({ - wordWrap: true, - }); - } - if ( - generateModel.getValue() === text && - editor.getModel() === generateModel - ) { - return; - } - generateModel.pushEditOperations( - [], - [{range: generateModel.getFullModelRange(), text}], - () => null, - ); - editor.setModel(generateModel); - editor.setSelection(new window.monaco.Range(0, 0, 0, 0)); - } - - const tab = { - generate, - state, - tabElement, - }; - return tab; - } - - /** - * Set the active tab. - * @param {!PlaygroundTab} tab The new tab. - */ - const setActiveTab = (tab) => { - currentTab = tab; - currentGenerate = tab.generate; - const isXml = tab.state.name == 'XML'; - const isJson = tab.state.name == 'JSON'; - editor.setModel(currentTab.state.model); - editor.updateOptions({ - readOnly: !isXml && !isJson, - wordWrap: false, - }); - - // Update tab UI. - Object.values(tabs).forEach( - (t) => - (t.tabElement.style.background = - t.tabElement == tab.tabElement ? '#1E1E1E' : '#2D2D2D'), - ); - // Update editor state. - editorXmlContextKey.set(isXml); - editorJsonContextKey.set(isJson); - updateImportButtonDisplay(); - playgroundState.set('activeTab', tab.state.name); - playgroundState.save(); - }; - - /** - * Call the current generate method if we are in 'auto' mode. In - * addition, persist the current workspace xml regardless of which tab - * we are in. - */ - const updateEditor = () => { - if (playgroundState.get('autoGenerate')) { - if (initialWorkspaceJson && isFirstLoad) { - isFirstLoad = false; - try { - Blockly.serialization.workspaces.load( - JSON.parse(initialWorkspaceJson), - workspace, - ); - } catch (e) { - console.warn('Failed to auto import.', e); - } - } - - if (currentGenerate) { - currentGenerate(); - } - - let code = ''; - try { - code = JSON.stringify( - Blockly.serialization.workspaces.save(workspace), - null, - 2, - ); - } catch (e) { - console.warn('Failed to auto save.', e); - } - playgroundState.set('workspaceJson', code); - playgroundState.save(); - } - }; - - // Register default tabs. - const tabs = { - JSON: registerGenerator('JSON', 'json', (ws) => { - return JSON.stringify( - Blockly.serialization.workspaces.save(ws), - null, - 2, - ); - }), - XML: registerGenerator('XML', 'xml', (ws) => { - return Blockly.Xml.domToPrettyText(Blockly.Xml.workspaceToDom(ws)); - }), - JavaScript: registerGenerator( - 'JavaScript', - 'javascript', - (ws) => - (javascriptGenerator || Blockly.JavaScript).workspaceToCode(ws), - true, - ), - Python: registerGenerator( - 'Python', - 'python', - (ws) => (pythonGenerator || Blockly.Python).workspaceToCode(ws), - true, - ), - Dart: registerGenerator( - 'Dart', - 'dart', - (ws) => (dartGenerator || Blockly.Dart).workspaceToCode(ws), - true, - ), - Lua: registerGenerator( - 'Lua', - 'lua', - (ws) => (luaGenerator || Blockly.Lua).workspaceToCode(ws), - true, - ), - PHP: registerGenerator( - 'PHP', - 'php', - (ws) => (phpGenerator || Blockly.PHP).workspaceToCode(ws), - true, - ), - }; - - // Handle tab click. - tabsDiv.addEventListener('click', (e) => { - const target = /** @type {HTMLElement} */ (e.target); - const tabName = target.getAttribute('data-tab'); - if (!tabName) { - // Not a tab. - return; - } - const tab = tabs[tabName]; - - // Save current tab state (eg: scroll position). - currentTab.state.viewState = editor.saveViewState(); - - setActiveTab(tab); - updateEditor(); - - // Restore tab state (eg: scroll position). - editor.restoreViewState(currentTab.state.viewState); - editor.focus(); - }); - - // Initialized saved JSON and bind change listener. - const initialWorkspaceJson = playgroundState.get('workspaceJson') || ''; - const jsonTab = tabs['JSON']; - const jsonModel = jsonTab.state.model; - let isFirstLoad = true; - jsonModel.setValue(initialWorkspaceJson); - jsonModel.onDidChangeContent(() => { - playgroundState.set('workspaceJson', jsonModel.getValue()); - playgroundState.save(); - }); - - // Create a button to import state from the editor tab to the workspace. - const importButton = renderButton('Import'); - tabButtons.appendChild(importButton); - importButton.addEventListener('click', (e) => { - if (editorXmlContextKey.get()) { - editor.getAction('import-xml').run(); - } - if (editorJsonContextKey.get()) { - editor.getAction('import-json').run(); - } - }); - const updateImportButtonDisplay = function () { - // The import button is only relevant for the XML and JSON tabs. - if (editorXmlContextKey.get() || editorJsonContextKey.get()) { - importButton.style.display = ''; - } else { - importButton.style.display = 'none'; - } - }; - - // Set the initial tab as active. - const activeTab = playgroundState.get('activeTab'); - let currentTab = tabs[activeTab]; - let currentGenerate; - if (currentTab) { - setActiveTab(currentTab); - } - - // Load the GUI controls. - const gui = addGUIControls( - (options) => { - workspace = createWorkspace(blocklyDiv, options); - - // Initialize the test toolbox. - toolboxTestBlocksInit( - /** @type {!Blockly.WorkspaceSvg} */ (workspace), - ); - - // Add download screenshot option. - const prevConfigureContextMenu = workspace.configureContextMenu; - workspace.configureContextMenu = (menuOptions, e) => { - prevConfigureContextMenu && - prevConfigureContextMenu.call(null, menuOptions, e); - - const screenshotOption = { - text: 'Download Screenshot', - enabled: workspace.getTopBlocks().length, - callback: function () { - downloadWorkspaceScreenshot(workspace); - }, - }; - menuOptions.push(screenshotOption); - }; - - updateEditor(); - workspace.addChangeListener((e) => { - if (e.type !== 'ui' && e.type !== 'viewport_change') { - updateEditor(); - } - }); - return workspace; - }, - defaultOptions, - { - disableResize: true, - toolboxes: config.toolboxes || { - 'categories': toolboxCategories, - 'simple': toolboxSimple, - 'test blocks': toolboxTestBlocks, - }, - }, - ); - - // Move the GUI Element to the gui container. - const guiElement = gui.domElement; - guiElement.removeChild(guiElement.firstChild); - guiElement.style.position = 'relative'; - guiElement.style.minWidth = '100%'; - guiContainer.appendChild(guiElement); - - // Click handler to toggle the playground. - const togglePlayground = (e) => { - const shouldOpen = playgroundDiv.style.display === 'none'; - if (shouldOpen) { - playgroundDiv.style.display = 'flex'; - minimizeButton.textContent = 'Collapse'; - } else { - playgroundDiv.style.display = 'none'; - minimizeButton.textContent = 'Expand'; - } - playgroundState.set('playgroundOpen', shouldOpen); - playgroundState.save(); - Blockly.svgResize(workspace); - }; - minimizeButton.addEventListener('click', togglePlayground); - - // Start minimized if the playground was previously closed. - if (playgroundState.get('playgroundOpen') === false) { - togglePlayground(); - } - - // Playground API. - - /** - * Get the current GUI controls. - * @returns {!dat.GUI} The GUI controls. - */ - const getGUI = function () { - return gui; - }; - - /** - * Get the current workspace. - * @returns {!Blockly.WorkspaceSvg} The Blockly workspace. - */ - const getWorkspace = function () { - return workspace; - }; - - /** - * Get the current tab. - * @returns {!PlaygroundTab} The current tab. - */ - const getCurrentTab = function () { - return currentTab; - }; - - /** - * Add a generator tab. - * @param {string} label The label of the generator tab. - * @param {Blockly.Generator} generator The Blockly generator. - * @param {string=} language Optional editor language, defaults to - * 'javascript'. - */ - const addGenerator = function (label, generator, language) { - if (!label || !generator) { - throw Error('usage: addGenerator(label, generator, language?);'); - } - tabs[label] = registerGenerator( - label, - language || 'javascript', - (ws) => generator.workspaceToCode(ws), - true, - ); - if (activeTab === label) { - // Set the new generator as the current tab if it is currently - // active. This occurs when a dynamically added generator is active - // and the page is reloaded. - setActiveTab(tabs[label]); - } - }; - - /** - * Removes a generator tab. - * @param {string} label The label of the generator tab to remove. - */ - const removeGenerator = function (label) { - if (!label) { - throw Error('usage: removeGenerator(label);'); - } - if (!(label in tabs)) { - throw Error('removeGenerator called on invalid label: ' + label); - } - const tab = tabs[label]; - tabsDiv.removeChild(tab.tabElement); - delete tabs[label]; - const tabsKeys = Object.keys(tabs); - if (activeTab === label && tabsKeys.length) { - // Set the active tab to another tab if the active tab corresponded - // to a removed generator. - setActiveTab(tabs[tabsKeys[0]]); - } - }; - - const playground = { - state: playgroundState, - addAction: /** @type {?} */ (gui).addAction, - addCheckboxAction: /** @type {?} */ (gui).addCheckboxAction, - addGenerator, - getCurrentTab, - getGUI, - getWorkspace, - removeGenerator, - }; - - // Add tab buttons. - registerTabButtons(editor, playground, tabButtons, updateEditor); - - // Register editor commands. - registerEditorCommands(editor, playground); - - return playground; - }, - ); -} - -/** - * Register tab buttons. - * @param {monaco.editor.IStandaloneCodeEditor} editor The monaco editor. - * @param {PlaygroundAPI} playground The current playground. - * @param {!HTMLElement} tabButtons Tab buttons element wrapper. - * @param {function():void} updateEditor Update Editor method. - */ -function registerTabButtons(editor, playground, tabButtons, updateEditor) { - const [autoGenerateCheckbox, autoGenerateLabel] = renderCheckbox( - 'autoGenerate', - 'Auto', - ); - /** @type {HTMLInputElement} */ (autoGenerateCheckbox).checked = - playground.state.get('autoGenerate'); - autoGenerateCheckbox.addEventListener('change', (e) => { - const inputTarget = /** @type {HTMLInputElement} */ (e.target); - playground.state.set('autoGenerate', !!inputTarget.checked); - playground.state.save(); - - updateEditor(); - }); - tabButtons.appendChild(autoGenerateCheckbox); - tabButtons.appendChild(autoGenerateLabel); -} - -/** - * Register editor commands / shortcuts. - * @param {monaco.editor.IStandaloneCodeEditor} editor The monaco editor. - * @param {PlaygroundAPI} playground The current playground. - */ -function registerEditorCommands(editor, playground) { - const loadXml = () => { - const xml = editor.getModel().getValue(); - const workspace = playground.getWorkspace(); - try { - Blockly.Xml.clearWorkspaceAndLoadFromXml( - Blockly.utils.xml.textToDom(xml), - workspace, - ); - } catch { - // If this fails that's fine. - return false; - } - return true; - }; - const loadJson = () => { - const json = editor.getModel().getValue(); - const workspace = playground.getWorkspace(); - try { - Blockly.serialization.workspaces.load(JSON.parse(json), workspace); - } catch { - // If this fails fall back to trying to load XML instead. - return loadXml(); - } - return true; - }; - const save = () => { - playground.getCurrentTab().generate(); - }; - - // Add XMl Import action (only available on the XML tab). - editor.addAction({ - id: 'import-xml', - label: 'Import from XML', - keybindings: [window.monaco.KeyMod.CtrlCmd | window.monaco.KeyCode.Enter], - precondition: 'isEditorXml', - contextMenuGroupId: 'playground', - contextMenuOrder: 0, - run: loadXml, - }); - // Add XMl Export action (only available on the XML tab). - editor.addAction({ - id: 'export-xml', - label: 'Export to XML', - keybindings: [window.monaco.KeyMod.CtrlCmd | window.monaco.KeyCode.KEY_S], - precondition: 'isEditorXml', - contextMenuGroupId: 'playground', - contextMenuOrder: 1, - run: save, - }); - // Add Clean XML action (only available on the XML tab). - editor.addAction({ - id: 'clean-xml', - label: 'Clean XML', - precondition: 'isEditorXml', - contextMenuGroupId: 'playground', - contextMenuOrder: 2, - run: () => { - const model = editor.getModel(); - const text = model.getValue().replace(/ (x|y|id)="[^"]*"/gim, ''); - model.pushEditOperations( - [], - [{range: model.getFullModelRange(), text}], - () => null, - ); - editor.setSelection(new window.monaco.Range(0, 0, 0, 0)); - }, - }); - // Add JSON Import action (only available on the JSON tab). - editor.addAction({ - id: 'import-json', - label: 'Import from JSON', - keybindings: [window.monaco.KeyMod.CtrlCmd | window.monaco.KeyCode.Enter], - precondition: 'isEditorJson', - contextMenuGroupId: 'playground', - contextMenuOrder: 0, - run: loadJson, - }); - // Add a Generator generate action. - editor.addAction({ - id: 'generate', - label: 'Generate', - keybindings: [window.monaco.KeyMod.CtrlCmd | window.monaco.KeyCode.KEY_S], - precondition: '!isEditorXml', - contextMenuGroupId: 'playground', - contextMenuOrder: 1, - run: save, - }); -} diff --git a/plugins/dev-tools/src/playground/monaco.js b/plugins/dev-tools/src/playground/monaco.js deleted file mode 100644 index 840ab4a31..000000000 --- a/plugins/dev-tools/src/playground/monaco.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Load the monaco editor. - * @param {!HTMLElement} container The container element. - * @param {Object} options Monaco editor options. - * @param {string=} vsEditorPath Optional VS editor path. - * @returns {Promise} A promise that resolves with the editor. - */ -export function addCodeEditor(container, options, vsEditorPath) { - return new Promise((resolve, reject) => { - if (!vsEditorPath) { - const vsEditorPaths = [ - // monaco-editor is a devDependency of @blockly/dev-tools, look for it - // there first, otherwise attempt to find it in the local node_modules - // and finally resort to an online version. - '../node_modules/@blockly/dev-tools/node_modules/monaco-editor/min/vs', - '../node_modules/monaco-editor/min/vs', - 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.19.2/min/vs', - ]; - // Find the VS loader. - for (let i = 0; i < vsEditorPaths.length; i++) { - if (checkFileExists(`${vsEditorPaths[i]}/loader.js`)) { - vsEditorPath = vsEditorPaths[i]; - break; - } - } - } - - const onLoad = () => { - const amdRequire = /** @type {?} */ (window.require); - amdRequire.config({ - paths: {vs: vsEditorPath}, - }); - - // Load the monaco editor. - amdRequire(['vs/editor/editor.main'], () => { - resolve(createEditor(container, options)); - }); - }; - - if (!window.require) { - const script = document.createElement('script'); - script.type = 'text/javascript'; - script.setAttribute('src', `${vsEditorPath}/loader.js`); - script.addEventListener('load', onLoad); - document.body.appendChild(script); - } else { - onLoad(); - } - }); -} - -/** - * Create the monaco editor. - * @param {!HTMLElement} container The container element. - * @param {Object} options Monaco editor options. - * @returns {monaco.editor.IStandaloneCodeEditor} A monaco editor. - */ -function createEditor(container, options) { - const editor = window.monaco.editor.create(container, options); - editor.layout(); - return editor; -} - -/** - * Check whether or not a JS file exists at the url specified. - * @param {string} url The url of the file. - * @returns {boolean} Whether or not the file exists. - */ -function checkFileExists(url) { - const http = new XMLHttpRequest(); - http.open('HEAD', url, false); - try { - http.send(); - } catch { - return false; - } - return http.status != 404; -} diff --git a/plugins/dev-tools/src/playground/options.js b/plugins/dev-tools/src/playground/options.js deleted file mode 100644 index 8bc47ef42..000000000 --- a/plugins/dev-tools/src/playground/options.js +++ /dev/null @@ -1,1083 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A helper to use the dat.GUI interface for configuring Blockly - * workspace options. - * @author samelh@google.com (Sam El-Husseini) - */ -import * as Blockly from 'blockly/core'; -import * as dat from 'dat.gui'; - -import {DebugDrawer} from '../debugDrawer'; -import {registerDebugRendererFromName, debugRendererName} from '../debug'; -import {disableLogger, enableLogger} from '../logger'; -import {HashState} from './hash_state'; -import {populateRandom} from '../populateRandom'; -import {spaghetti} from '../spaghetti'; -import {id} from './id'; -import toolboxCategories from '../toolboxCategories'; -import toolboxSimple from '../toolboxSimple'; -import darkTheme from '@blockly/theme-dark'; -import deuteranopiaTheme from '@blockly/theme-deuteranopia'; -import themeTritanopia from '@blockly/theme-tritanopia'; -import highContrastTheme from '@blockly/theme-highcontrast'; - -const assign = require('lodash.assign'); -const merge = require('lodash.merge'); - -/** - * @typedef {Blockly.utils.toolbox.ToolboxDefinition} BlocklyToolbox - */ - -/** - * @typedef {Object} GUIConfig - * @property {boolean} [disableResize] Whether or not to disable automatically - * resizing the GUI control. - * @property {Object} [toolboxes] The toolbox registry. - */ - -/** - * Use dat.GUI to add controls to adjust configuration of a Blockly workspace. - * @param {function(!Blockly.BlocklyOptions):Blockly.WorkspaceSvg} genWorkspace - * A workspace creation method called every time the toolbox is - * re-configured. - * @param {Blockly.BlocklyOptions} defaultOptions The default workspace options - * to use. - * @param {GUIConfig=} config Optional GUI config. - * @returns {dat.GUI} The dat.GUI instance. - */ -export function addGUIControls(genWorkspace, defaultOptions, config = {}) { - // Initialize state. - const guiState = loadGUIState(); - - // Initialize toolboxes. - const toolboxes = - /** @type {Object} */ ( - config.toolboxes || { - categories: toolboxCategories, - simple: toolboxSimple, - } - ); - const defaultToolboxName = initDefaultToolbox(defaultOptions, toolboxes); - guiState.toolboxName = guiState.toolboxName || defaultToolboxName; - guiState.options.toolbox = toolboxes[guiState.toolboxName]; - - // Initialize themes. - const themes = getThemes(defaultOptions); - const defaultThemeName = defaultOptions.theme - ? /** @type {!Blockly.Theme} */ (defaultOptions.theme).name - : 'classic'; - guiState.themeName = guiState.themeName || defaultThemeName; - guiState.options.theme = themes[guiState.themeName]; - - const defaultRendererName = defaultOptions.renderer - ? defaultOptions.renderer - : 'geras'; - guiState.renderer = guiState.renderer || defaultRendererName; - guiState.debugEnabled = guiState.debugEnabled || false; - - // Merge default and saved state. - const saveOptions = /** @type {!Blockly.BlocklyOptions} */ ({ - ...defaultOptions, - ...guiState.options, - }); - initDebugRenderer(guiState); - - let workspace = genWorkspace(saveOptions); - const resizeEnabled = !config.disableResize; - - const gui = new dat.GUI({ - autoPlace: false, - closeOnTop: true, - width: 250, - load: guiState.guiObject || {}, - }); - - const guiElement = gui.domElement; - guiElement.style.position = 'absolute'; - guiElement.style.zIndex = '1000'; - guiElement.onclick = () => { - // Save the GUI state locally. - guiState.guiObject = gui.getSaveObject(); - saveGUIState(guiState, defaultToolboxName, defaultThemeName); - }; - - const onResize = () => { - const metrics = workspace.getMetrics(); - if (workspace.RTL) { - guiElement.style.left = metrics.absoluteLeft + 'px'; - guiElement.style.right = 'auto'; - } else { - guiElement.style.left = 'auto'; - if (metrics.toolboxPosition === Blockly.TOOLBOX_AT_RIGHT) { - guiElement.style.right = metrics.toolboxWidth + 'px'; - } else { - guiElement.style.right = '0'; - } - } - guiElement.style.top = metrics.absoluteTop + 'px'; - }; - if (resizeEnabled) { - onResize(); - } - - const container = /** @type {!HTMLElement} */ ( - workspace.getInjectionDiv().parentNode - ); - container.style.position = 'relative'; - container.appendChild(guiElement); - - const options = Object.assign({}, workspace.options); - - const onChangeInternal = () => { - // Serialize current workspace state. - const state = Blockly.serialization.workspaces.save(workspace); - // Dispose of the current workspace - workspace.dispose(); - // Create a new workspace with options. - workspace = genWorkspace(saveOptions); - // Deserialize state into workspace. - Blockly.serialization.workspaces.load(state, workspace); - // Resize the gui. - if (resizeEnabled) { - onResize(); - } - // Save the GUI state locally. - guiState.guiObject = gui.getSaveObject(); - saveGUIState(guiState, defaultToolboxName, defaultThemeName); - // Update options. - merge(saveOptions, workspace.options); - gui.updateDisplay(); - }; - - const onChange = (key, value) => { - saveOptions[key] = value; - guiState.options[key] = value; - onChangeInternal(); - }; - - const reset = () => { - // Reset saved options. - Object.keys(saveOptions).forEach((k) => delete saveOptions[k]); - assign(saveOptions, defaultOptions); - Object.keys(guiState.options).forEach((k) => delete guiState.options[k]); - // Reset debug options. - guiState.renderer = defaultRendererName; - initDebugRenderer(guiState, true); - updateDebugFolder(debugOptionsFolder, false); - - // Reset toolbox selection. - guiState.toolboxName = defaultToolboxName; - guiState.themeName = defaultThemeName; - - // Close all folders. - Object.values(gui.__folders).forEach((f) => f.close()); - - onChangeInternal(); - }; - - gui.add( - { - Reset: reset, - }, - 'Reset', - ); - - // Options folder. - const optionsFolder = gui.addFolder('Options'); - setTooltip( - optionsFolder, - 'Options that affect the appearance of the workspace.', - ); - openFolderIfOptionSelected(optionsFolder, guiState, guiState.options, [ - 'rtl', - 'renderer', - 'toolboxPosition', - 'horizontalLayout', - ]); - - setTooltip( - optionsFolder - .add(options, 'RTL') - .name('rtl') - .onChange((value) => onChange('rtl', value)), - 'If true, mirror the editor (for Arabic or Hebrew locales).', - ); - - // Renderer. - populateRendererOption(optionsFolder, guiState, onChange); - - // Theme. - populateThemeOption( - optionsFolder, - guiState, - themes, - defaultThemeName, - onChange, - ); - - // Toolbox. - populateToolboxOption( - optionsFolder, - guiState, - toolboxes, - defaultToolboxName, - onChange, - ); - populateToolboxSidesOption( - optionsFolder, - options, - saveOptions, - guiState, - onChangeInternal, - ); - - // Basic options. - const basicFolder = optionsFolder.addFolder('Basic'); - setTooltip(basicFolder, 'Basic options like sound, comment etc...'); - populateBasicOptions(basicFolder, options, guiState, onChange); - - // Move options. - const moveFolder = optionsFolder.addFolder('Move'); - setTooltip(moveFolder, 'Move options like scrollbars, drag etc...'); - populateMoveOptions(moveFolder, options, saveOptions, onChange); - openFolderIfOptionSelected(moveFolder, guiState, guiState.options, ['move']); - - // Zoom options. - const zoomFolder = optionsFolder.addFolder('Zoom'); - setTooltip(zoomFolder, 'Zoom options like controls, startScale etc...'); - populateZoomOptions(zoomFolder, options, saveOptions, onChange); - openFolderIfOptionSelected(moveFolder, guiState, guiState.options, ['zoom']); - - // Grid options. - const gridFolder = optionsFolder.addFolder('Grid'); - setTooltip(gridFolder, 'Grid options like spacing, length etc...'); - populateGridOptions(gridFolder, options, saveOptions, onChange); - openFolderIfOptionSelected(moveFolder, guiState, guiState.options, ['grid']); - - // Debug renderer. - const debugFolder = gui.addFolder('Debug'); - // Adds the checkbox to toggle using the debug renderer. - const debugController = debugFolder.add(guiState, 'debugEnabled'); - // Folder with all the debug options. Hidden if the debugger is not enabled. - const debugOptionsFolder = debugFolder.addFolder('Debug Options'); - - setTooltip(debugFolder, 'Rendering debug configuration.'); - populateDebugFolder(debugController, debugOptionsFolder, guiState, onChange); - populateDebugOptionsFolder(debugOptionsFolder, guiState, onChangeInternal); - - // GUI actions. - const actionsFolder = gui.addFolder('Actions'); - const actionSubFolders = {}; - const actions = {}; - - /** - * Get the current workspace. - * @returns {!Blockly.WorkspaceSvg} The Blockly workspace. - */ - const getWorkspace = () => { - return workspace; - }; - - /** - * Add a custom action to the list of playground actions. - * @param {string} name The action label. - * @param {function(!Blockly.Workspace):void} callback The callback to call - * when the action is clicked. - * @param {string=} folderName Optional folder to place the action under. - * @param {string=} tooltip Optional tooltip to set. - * @returns {dat.GUIController} The GUI controller. - */ - const addAction = (name, callback, folderName, tooltip) => { - actions[name] = () => { - callback(workspace); - }; - let folder = actionsFolder; - if (folderName) { - if (actionSubFolders[folderName]) { - folder = actionSubFolders[folderName]; - } else { - folder = actionsFolder.addFolder(folderName); - folder.open(); - actionSubFolders[folderName] = folder; - } - } - const controller = folder.add(actions, name); - tooltip && setTooltip(controller, tooltip); - name && controller.name(name); - return controller; - }; - - /** - * Add a custom checkbox action to the list of playground actions. - * @param {string} name The action label. - * @param {function(!Blockly.Workspace,boolean):void} callback The callback to - * call when the action is clicked. - * @param {string=} folderName Optional folder to place the action under. - * @param {boolean=} defaultValue Default value. - * @param {string=} tooltip Optional tooltip to set. - * @returns {dat.GUIController} The GUI controller. - */ - const addCheckboxAction = ( - name, - callback, - folderName, - defaultValue, - tooltip, - ) => { - actions[name] = !!defaultValue; - let folder = actionsFolder; - if (folderName) { - if (actionSubFolders[folderName]) { - folder = actionSubFolders[folderName]; - } else { - folder = actionsFolder.addFolder(folderName); - folder.open(); - actionSubFolders[folderName] = folder; - } - } - const controller = folder.add(actions, name); - tooltip && setTooltip(controller, tooltip); - name && controller.name(name); - controller.listen().onFinishChange((value) => { - callback(workspace, value); - }); - - return controller; - }; - - const devGui = /** @type {?} */ (gui); - devGui.addCheckboxAction = addCheckboxAction; - devGui.addAction = addAction; - devGui.getWorkspace = getWorkspace; - - addActions(devGui, workspace); - - return devGui; -} - -/** - * Save the GUI state to local storage and the window hash. - * @param {Object} guiState The GUI State. - * @param {string} defaultToolboxName The default toolbox name. - * @param {string} defaultThemeName The default theme name. - */ -function saveGUIState(guiState, defaultToolboxName, defaultThemeName) { - // Don't save toolbox and theme, as we'll save their names instead. - delete guiState.options['toolbox']; - delete guiState.options['theme']; - - if (guiState.debugEnabled) { - // In this case guiState.options.renderer is 'debugRenderer'. Storing this - // is not helpful, so instead store the actual name of the renderer. - guiState.options.renderer = guiState.renderer; - } - - // Save GUI control options to local storage. - const guiStateKey = `guiState_${id}`; - localStorage.setItem(guiStateKey, JSON.stringify(guiState)); - - // Save GUI state into the URL: - const hashGuiState = Object.assign({}, guiState.options); - if (guiState.toolboxName !== defaultToolboxName) { - hashGuiState.toolbox = guiState.toolboxName; - } - if (guiState.themeName !== defaultThemeName) { - hashGuiState.theme = guiState.themeName; - } - - // Save whether the debug is enabled. - hashGuiState.debugEnabled = guiState.debugEnabled; - window.location.hash = HashState.save(hashGuiState); -} - -/** - * Load the GUI state from local storage and the window hash. - * @returns {Object} The GUI state. - */ -function loadGUIState() { - const defaultState = {options: {}, debug: {}, debugEnabled: false}; - const guiStateKey = `guiState_${id}`; - const guiState = - JSON.parse(localStorage.getItem(guiStateKey)) || defaultState; - if (window.location.hash) { - HashState.parse(window.location.hash, guiState.options); - } - // Move GUI toolbox state out of options, as it refers to the toolbox name - // and not the toolbox value. - if (guiState.options.toolbox) { - guiState.toolboxName = guiState.options.toolbox; - delete guiState.options.toolbox; - } - // Move GUI theme state out of options, as it refers to the theme name - // and not the theme object. - if (guiState.options.theme) { - guiState.themeName = guiState.options.theme; - delete guiState.options.theme; - } - // If we end up using the 'debugRenderer' we still need to store the name of - // the original renderer. - guiState.renderer = guiState.options.renderer; - - // Use the debug renderer. - if (guiState.debugEnabled) { - guiState.options.renderer = debugRendererName; - } - - return guiState; -} - -/** - * Open a dat.GUI folder and all of its parents if one of the options is present - * in the GUI state. - * @param {dat.GUI} folder The GUI folder. - * @param {Object} guiState GUI state. - * @param {Object} mainObj The main object to check options against. - * @param {Array} options The options to check. - */ -function openFolderIfOptionSelected(folder, guiState, mainObj, options) { - if (guiState.guiObject) { - // The GUI state is controlling the folder state. - return; - } - options.forEach((option) => { - if (mainObj[option] != undefined) { - folder.open(); - while (folder.parent) { - folder = folder.parent; - folder.open(); - } - } - }); -} - -/** - * Initialize the default toolbox. If the default toolbox is not in the list of - * toolboxes, add a "default" option to the toolbox list. - * @param {Blockly.BlocklyOptions} defaultOptions Default Blockly options. - * @param {Object} toolboxes The - * registered toolboxes. - * @returns {string} The default toolbox name. - */ -function initDefaultToolbox(defaultOptions, toolboxes) { - const defaultToolbox = defaultOptions.toolbox; - const isDefaultInToolboxes = Object.keys(toolboxes).filter( - (k) => toolboxes[k] == defaultToolbox, - ); - if (defaultToolbox && !isDefaultInToolboxes.length) { - // Default toolbox not in the toolbox list. Add a "default" option. - toolboxes['default'] = defaultToolbox; - return 'default'; - } else if (isDefaultInToolboxes.length) { - // Get the - return isDefaultInToolboxes[0]; - } else { - // No default toolbox set, choose the first one. - return Object.keys(toolboxes)[0]; - } -} - -/** - * Populate basic options. - * @param {dat.GUI} basicFolder The dat.GUI basic folder. - * @param {Blockly.Options} options Blockly options. - * @param {Object} guiState The GUI state. - * @param {function(string, *):void} onChange On Change method. - */ -function populateBasicOptions(basicFolder, options, guiState, onChange) { - setTooltip( - basicFolder - .add(options, 'readOnly') - .onChange((value) => onChange('readOnly', value)), - 'If true, prevent the user from editing. Suppresses the toolbox and' + - ' trashcan.', - ); - setTooltip( - basicFolder - .add(options, 'hasTrashcan') - .name('trashCan') - .onChange((value) => onChange('trashcan', value)), - 'Displays or hides the trashcan.', - ); - setTooltip( - basicFolder - .add(options, 'hasSounds') - .name('sounds') - .onChange((value) => onChange('sounds', value)), - `If false, don't play sounds (e.g. click and delete).`, - ); - setTooltip( - basicFolder - .add(options, 'disable') - .onChange((value) => onChange('disable', value)), - 'Allows blocks to be disabled. ', - ); - setTooltip( - basicFolder - .add(options, 'collapse') - .onChange((value) => onChange('collapse', value)), - 'Allows blocks to be collapsed or expanded.', - ); - setTooltip( - basicFolder - .add(options, 'comments') - .onChange((value) => onChange('comments', value)), - 'Allows blocks to have comments.', - ); - - openFolderIfOptionSelected(basicFolder, guiState, guiState.options, [ - 'readOnly', - 'trashcan', - 'sounds', - 'disable', - 'collapse', - 'comments', - ]); -} - -/** - * Populate the renderer option. - * @param {dat.GUI} folder The dat.GUI folder. - * @param {Object} guiState The GUI state. - * @param {function(string, *):void} onChange On Change method. - */ -function populateRendererOption(folder, guiState, onChange) { - // Get the list of renderers. Previous versions of Blockly used the - // rendererMap_, whereas newer versions that use the global registry get their - // list of renderers from somewhere else. - const renderers = - Blockly.blockRendering.rendererMap_ || - (Blockly.registry && Blockly.registry.getAllItems('renderer')); - const publicRenderers = Object.keys(renderers).filter( - (name) => name !== debugRendererName.toLowerCase(), - ); - setTooltip( - folder.add(guiState, 'renderer', publicRenderers).onChange((value) => { - guiState.renderer = value; - registerDebugRendererFromName(value); - onChange('renderer', guiState.debugEnabled ? debugRendererName : value); - }), - 'The renderer used by Blockly.', - ); -} - -/** - * Populate the toolbox option. - * @param {dat.GUI} folder The dat.GUI folder. - * @param {Object} guiState The GUI state. - * @param {Object} toolboxes The - * registered toolboxes. - * @param {string} defaultToolboxName The default toolbox name. - * @param {function(string, *):void} onChange On Change method. - */ -function populateToolboxOption( - folder, - guiState, - toolboxes, - defaultToolboxName, - onChange, -) { - setTooltip( - folder - .add(guiState, 'toolboxName') - .options(Object.keys(toolboxes)) - .name('toolbox') - .onChange((value) => { - guiState.toolboxName = value; - onChange('toolbox', toolboxes[value]); - }), - 'The toolbox used by Blockly.', - ); - if (guiState.toolboxName !== defaultToolboxName) { - openFolderIfOptionSelected(folder, guiState, guiState.options, ['toolbox']); - } -} - -/** - * Populate the toolbox sides option. - * @param {dat.GUI} folder The dat.GUI folder. - * @param {Blockly.Options} options Blockly options. - * @param {Blockly.BlocklyOptions} saveOptions Saved Blockly options. - * @param {Object} guiState GUI state. - * @param {function():void} onChangeInternal Internal on change method. - */ -function populateToolboxSidesOption( - folder, - options, - saveOptions, - guiState, - onChangeInternal, -) { - const toolboxSides = {top: 0, bottom: 1, left: 2, right: 3}; - setTooltip( - folder - .add(options, 'toolboxPosition', toolboxSides) - .name('toolboxPosition') - .onChange((value) => { - const side = Object.keys(toolboxSides).find( - (key) => toolboxSides[key] == value, - ); - saveOptions['horizontalLayout'] = side == 'top' || side == 'bottom'; - saveOptions['toolboxPosition'] = - side == 'top' || side == 'left' ? 'start' : 'end'; - guiState.options['toolboxPosition'] = saveOptions['toolboxPosition']; - guiState.options['horizontalLayout'] = saveOptions['horizontalLayout']; - onChangeInternal(); - }), - 'The toolbox position.', - ); -} - -/** - * Get the list of Blockly themes. - * @param {Blockly.BlocklyOptions} defaultOptions Default Blockly options. - * @returns {Object} The list of registered themes. - */ -function getThemes(defaultOptions) { - let themes; - if (Blockly.registry && Blockly.registry.getAllItems('theme')) { - // Using a version of Blockly that registers themes. - themes = Blockly.registry.getAllItems('theme'); - } else { - // Fall back to a pre-set list of themes. - themes = { - classic: Blockly.Themes.Classic, - dark: darkTheme, - deuteranopia: deuteranopiaTheme, - tritanopia: themeTritanopia, - highcontrast: highContrastTheme, - }; - if (defaultOptions.theme) { - themes[/** @type {!Blockly.Theme} */ (defaultOptions.theme).name] = - defaultOptions.theme; - } - } - return themes; -} - -/** - * Populate the theme option. - * @param {dat.GUI} folder The dat.GUI folder. - * @param {Object} guiState The GUI state. - * @param {Object} themes The list of - * themes. - * @param {string} defaultThemeName Default Theme name. - * @param {function(string, *):void} onChange On Change method. - */ -function populateThemeOption( - folder, - guiState, - themes, - defaultThemeName, - onChange, -) { - setTooltip( - folder - .add(guiState, 'themeName') - .options(Object.keys(themes)) - .name('theme') - .onChange((value) => { - guiState.themeName = value; - onChange('theme', themes[value]); - }), - 'The theme used by Blockly.', - ); - if (guiState.themeName !== defaultThemeName) { - openFolderIfOptionSelected(folder, guiState, guiState.options, ['theme']); - } -} - -/** - * Populate move options. - * @param {dat.GUI} moveFolder The dat.GUI move options folder. - * @param {Blockly.Options} options Blockly options. - * @param {Blockly.BlocklyOptions} saveOptions Saved Blockly options. - * @param {function(string, *):void} onChange On Change method. - */ -function populateMoveOptions(moveFolder, options, saveOptions, onChange) { - setTooltip( - moveFolder.add(options.moveOptions, 'scrollbars').onChange((value) => - onChange('move', { - ...saveOptions.move, - scrollbars: value, - }), - ), - 'True if the workspace has scrollbars.', - ); - setTooltip( - moveFolder.add(options.moveOptions, 'wheel').onChange((value) => - onChange('move', { - ...saveOptions.move, - wheel: value, - }), - ), - 'True if the workspace can be scrolled with the mouse wheel.', - ); - setTooltip( - moveFolder.add(options.moveOptions, 'drag').onChange((value) => - onChange('move', { - ...saveOptions.move, - drag: value, - }), - ), - 'True if the workspace can be dragged with the mouse.', - ); -} - -/** - * Populate zoom options. - * @param {dat.GUI} zoomFolder The dat.GUI zoom options folder. - * @param {Blockly.Options} options Blockly options. - * @param {Blockly.BlocklyOptions} saveOptions Saved Blockly options. - * @param {function(string, *):void} onChange On Change method. - */ -function populateZoomOptions(zoomFolder, options, saveOptions, onChange) { - setTooltip( - zoomFolder.add(options.zoomOptions, 'controls').onChange((value) => - onChange('zoom', { - ...saveOptions.zoom, - controls: value, - }), - ), - 'Set to true to show zoom-centre, zoom-in, and zoom-out buttons.', - ); - setTooltip( - zoomFolder.add(options.zoomOptions, 'wheel').onChange((value) => - onChange('zoom', { - ...saveOptions.zoom, - wheel: value, - }), - ), - 'Set to true to allow the mouse wheel to zoom.', - ); - setTooltip( - zoomFolder - .add(options.zoomOptions, 'startScale', 0.1, 4) - .onChange((value) => - onChange('zoom', { - ...saveOptions.zoom, - startScale: value, - }), - ), - 'Initial magnification factor. For applications with multiple levels,' + - ' startScale is often set to a higher value on the first level, then' + - ' incrementally decreased as subsequent levels become more complex.', - ); - setTooltip( - zoomFolder - .add(options.zoomOptions, 'maxScale', 1, 20) - .onChange((value) => - onChange('zoom', { - ...saveOptions.zoom, - maxScale: value, - }), - ) - .step(1), - 'Maximum multiplication factor for how far one can zoom in.', - ); - setTooltip( - zoomFolder - .add(options.zoomOptions, 'minScale', 0.1, 1) - .onChange((value) => - onChange('zoom', { - ...saveOptions.zoom, - minScale: value, - }), - ) - .step(0.05), - 'Minimum multiplication factor for how far one can zoom out.', - ); -} - -/** - * Populate grid options. - * @param {dat.GUI} gridFolder The dat.GUI grid options folder. - * @param {Blockly.Options} options Blockly options. - * @param {Blockly.BlocklyOptions} saveOptions Saved Blockly options. - * @param {function(string, *):void} onChange On Change method. - */ -function populateGridOptions(gridFolder, options, saveOptions, onChange) { - setTooltip( - gridFolder.add(options.gridOptions, 'spacing', 0, 50).onChange((value) => - onChange('grid', { - ...saveOptions.grid, - spacing: value, - }), - ), - `The distance between the grid's points.`, - ); - setTooltip( - gridFolder.add(options.gridOptions, 'length', 0, 30).onChange((value) => - onChange('grid', { - ...saveOptions.grid, - length: value, - }), - ), - 'The shape of the grid points. A length of 0 results in an invisible' + - ' grid (but still one that may be snapped to), a length of 1 (the' + - ' default value) results in dots, a longer length results in crosses, ' + - 'and a length equal or greater than the spacing results in graph paper.', - ); - setTooltip( - gridFolder.addColor(options.gridOptions, 'colour').onChange((value) => - onChange('grid', { - ...saveOptions.grid, - colour: value, - }), - ), - 'The colour of the grid points.', - ); - setTooltip( - gridFolder.add(options.gridOptions, 'snap').onChange((value) => - onChange('grid', { - ...saveOptions.grid, - snap: value, - }), - ), - 'Whether blocks should snap to the nearest grid point when placed on' + - ' the workspace.', - ); -} - -/** - * Set a tooltip on a GUI folder or controller. - * @param {dat.GUI|dat.GUIController} controller GUI folder or controller. - * @param {string} tooltip Tooltip string. - */ -function setTooltip(controller, tooltip) { - const parentElement = controller.domElement.parentElement; - parentElement.setAttribute('title', tooltip); -} - -/** - * Initialize debug renderer. - * @param {!Object} guiState The GUI State. - * @param {boolean=} reset Whether or not to reset the renderer config. - */ -function initDebugRenderer(guiState, reset) { - const guiDebugState = guiState.debug; - registerDebugRendererFromName(guiState.renderer); - Object.keys(DebugDrawer.config).map((key) => { - if (guiDebugState[key] == undefined || reset) { - guiDebugState[key] = false; - } - DebugDrawer.config[key] = guiDebugState[key]; - }); - - if (reset) { - guiState.debugEnabled = false; - } -} - -/** - * Populate the parent folder that holds the debug enabled button and the - * folder with all the debug options in it. When debug is enabled it should - * open the folder holding all the debug options. - * @param {dat.GUIController} debugController The GUI controller. - * @param {dat.GUI} debugOptionsFolder The folder that holds all the debug - * options. - * @param {Object} guiState The GUI State. - * @param {function(string, *):void} onChange On Change method. - */ -function populateDebugFolder( - debugController, - debugOptionsFolder, - guiState, - onChange, -) { - updateDebugFolder(debugOptionsFolder, guiState.debugEnabled); - - debugController.onChange((value) => { - guiState.debugEnabled = value; - onChange('renderer', value ? debugRendererName : guiState.renderer); - updateDebugFolder(debugOptionsFolder, guiState.debugEnabled); - }); -} - -/** - * Updates the debug folder to be hidden/displayed based on whether the - * rendering debugger is enabled. - * @param {dat.GUI} folder The folder that holds all the debug - * options. - * @param {boolean} isEnabled True if the debugger is enabled, false otherwise. - */ -function updateDebugFolder(folder, isEnabled) { - if (isEnabled) { - folder.show(); - folder.open(); - } else { - folder.hide(); - } -} - -/** - * Populates the folder holding all the debug renderer options. - * @param {dat.GUI} debugOptionsFolder The folder that holds all the debug - * options. - * @param {Object} guiState The GUI State. - * @param {function():void} onChangeInternal Internal on change method. - */ -function populateDebugOptionsFolder( - debugOptionsFolder, - guiState, - onChangeInternal, -) { - const debugState = guiState.debug; - Object.keys(DebugDrawer.config).map((key) => { - debugOptionsFolder.add(debugState, key, 0, 50).onChange((value) => { - debugState[key] = value; - DebugDrawer.config[key] = debugState[key]; - onChangeInternal(); - }); - }); -} - -/** - * Add default actions to the GUI instance. - * @param {?} gui The GUI instance. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -function addActions(gui, workspace) { - // Visibility actions. - gui.addAction( - 'Show', - (workspace) => { - workspace.setVisible(true); - }, - 'Visibility', - 'Show the workspace.', - ); - gui.addAction( - 'Hide', - (workspace) => { - workspace.setVisible(false); - }, - 'Visibility', - 'Hide the workspace.', - ); - - // Block actions. - gui.addAction( - 'Clear', - (workspace) => { - workspace.clear(); - }, - 'Blocks', - 'Clear all the blocks from the workspace.', - ); - gui.addAction( - 'Format', - (workspace) => { - workspace.cleanUp(); - }, - 'Blocks', - 'Format the blocks on the workspace.', - ); - - // Undo/Redo actions. - gui.addAction( - 'Undo', - (workspace) => { - workspace.undo(); - }, - 'Undo/Redo', - 'Undo last action.', - ); - gui.addAction( - 'Redo', - (workspace) => { - workspace.undo(true); - }, - 'Undo/Redo', - 'Redo last action.', - ); - gui.addAction( - 'Clear Undo Stack', - (workspace) => { - workspace.clearUndo(); - }, - 'Undo/Redo', - 'Clear the undo stack.', - ); - - // Scale actions. - gui.addAction( - 'Zoom reset', - (workspace) => { - workspace.setScale(workspace.options.zoomOptions.startScale); - workspace.scrollCenter(); - }, - 'Scale', - 'Reset zoom.', - ); - gui.addAction( - 'Zoom center', - (workspace) => { - workspace.scrollCenter(); - }, - 'Scale', - 'Center the workspace.', - ); - gui.addAction( - 'Zoom to Fit', - (workspace) => { - workspace.zoomToFit(); - }, - 'Scale', - 'Zoom the blocks to fit in the workspace if possible.', - ); - - // Stress Test. - gui.addAction( - 'Random Blocks', - (workspace) => { - populateRandom(workspace, 100); - }, - 'Stress Test', - 'Populate the workspace with a random set of blocks, for testing.', - ); - gui.addAction( - 'Spaghetti!', - (workspace) => { - spaghetti(workspace, 8); - }, - 'Stress Test', - 'Populate the workspace with nested if-statement blocks, for testing.', - ); - - // Logging. - gui.addCheckboxAction( - 'Log Events', - function (workspace, value) { - if (value) { - enableLogger(workspace); - } else { - disableLogger(workspace); - } - }, - 'Logging', - false, - 'Toggle console logging of workspace events.', - ); - gui.addCheckboxAction( - 'Log Flyout Events', - function (workspace, value) { - if (value) { - if (workspace.getFlyout()) { - enableLogger(workspace.getFlyout().getWorkspace()); - } - } else { - if (workspace.getFlyout()) { - disableLogger(workspace.getFlyout().getWorkspace()); - } - } - }, - 'Logging', - false, - 'Toggle console logging of flyout events.', - ); -} diff --git a/plugins/dev-tools/src/playground/state.js b/plugins/dev-tools/src/playground/state.js deleted file mode 100644 index f003c5f4f..000000000 --- a/plugins/dev-tools/src/playground/state.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Local storage state manager. - * @author samelh@google.com (Sam El-Husseini) - */ - -/** - * A class that manages loading / storing the local storage state. - */ -export class LocalStorageState { - /** - * Local storage state constructor. - * @param {string} key The local storage key. - * @param {Object=} defaultState The default state. - */ - constructor(key, defaultState) { - /** - * @type {string} - * @private - */ - this.key_ = key; - - /** - * @type {!Object} - * @private - */ - this.state_ = Object.create(null); - - /** - * @type {!Object} - * @private - */ - this.defaultState_ = defaultState || Object.create(null); - } - - /** - * Load the state from local storage. - */ - load() { - this.state_ = - JSON.parse(localStorage.getItem(this.key_)) || this.defaultState_; - } - - /** - * Get value of key. - * @param {string} key The key to lookup. - * @returns {*} The value. - */ - get(key) { - return this.state_[key]; - } - - /** - * Set the value of a key. - * @param {string} key The key to set. - * @param {*} value The value. - */ - set(key, value) { - this.state_[key] = value; - } - - /** - * Save and persist the current state. - */ - save() { - localStorage.setItem(this.key_, JSON.stringify(this.state_)); - } -} diff --git a/plugins/dev-tools/src/playground/ui.js b/plugins/dev-tools/src/playground/ui.js deleted file mode 100644 index 855b0becd..000000000 --- a/plugins/dev-tools/src/playground/ui.js +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Playground UI. - * @author samelh@google.com (Sam El-Husseini) - */ - -/** - * Render the playground layout. - * @param {HTMLElement} container The container to render the playground in. - * @returns {{ - * blocklyDiv: HTMLElement, - * minimizeButton: HTMLElement, - * monacoDiv: HTMLElement, - * guiContainer: HTMLElement, - * playgroundDiv: HTMLElement, - * tabsDiv: HTMLElement, - * tabButtons: HTMLElement - * }} An object with the various playground components. - */ -export function renderPlayground(container) { - container.style.display = 'flex'; - container.style.overflow = 'hidden'; - container.style.height = '100vh'; - container.style.width = '100vw'; - container.style.userSelect = 'none'; - container.style.background = '#E4E4E4'; - - // Blockly area. - - const blocklyArea = document.createElement('div'); - blocklyArea.style.flex = '2 1 0'; - container.appendChild(blocklyArea); - - const blocklyDiv = document.createElement('div'); - blocklyDiv.style.height = '100%'; - blocklyDiv.style.width = '100%'; - blocklyDiv.style.maxHeight = '100%'; - blocklyArea.appendChild(blocklyDiv); - - // Playground area. - - // Minimize button - const minimizeButton = document.createElement('div'); - minimizeButton.style.width = '18px'; - minimizeButton.style.background = 'black'; - minimizeButton.style.color = 'white'; - minimizeButton.style.font = `12px 'Lucida Grande', sans-serif`; - minimizeButton.style.writingMode = 'vertical-lr'; - minimizeButton.style.textOrientation = 'mixed'; - minimizeButton.style.textAlign = 'center'; - minimizeButton.textContent = 'Collapse'; - container.appendChild(minimizeButton); - - const playgroundDiv = document.createElement('div'); - playgroundDiv.style.flex = '1 1 1'; - playgroundDiv.style.maxWidth = '40vw'; - playgroundDiv.style.width = '100%'; - playgroundDiv.style.height = '100%'; - playgroundDiv.style.display = 'flex'; - playgroundDiv.style.background = 'grey'; - playgroundDiv.style.flexDirection = 'column'; - playgroundDiv.style.color = '#bbb'; - playgroundDiv.style.font = `11px 'Lucida Grande', sans-serif`; - container.appendChild(playgroundDiv); - - const playgroundTitle = document.createElement('span'); - playgroundTitle.textContent = 'Blockly Playground'; - playgroundTitle.style.background = '#3C3C3C'; - playgroundTitle.style.fontSize = '12px'; - playgroundTitle.style.padding = '7px'; - playgroundDiv.appendChild(playgroundTitle); - - // GUI controls area. - - const guiContainer = document.createElement('div'); - guiContainer.style.maxHeight = '50%'; - guiContainer.style.flex = '1'; - guiContainer.style.background = '#000'; - guiContainer.style.overflow = 'auto'; - playgroundDiv.appendChild(guiContainer); - - // Code area. - - const codeWrapper = document.createElement('div'); - codeWrapper.style.maxHeight = '50%'; - codeWrapper.style.background = '#1E1E1E'; - codeWrapper.style.flex = '1'; - playgroundDiv.appendChild(codeWrapper); - - // Code editor tabs. - const tabContainer = document.createElement('div'); - tabContainer.style.background = '#252526'; - tabContainer.style.height = '30px'; - tabContainer.style.lineHeight = '30px'; - tabContainer.style.position = 'relative'; - codeWrapper.appendChild(tabContainer); - - const tabsDiv = document.createElement('div'); - tabsDiv.style.overflow = 'auto hidden'; - tabsDiv.style.width = 'calc(100% - 50px)'; - tabContainer.appendChild(tabsDiv); - - // Code editor tab buttons. - const tabButtons = document.createElement('div'); - tabButtons.style.position = 'absolute'; - tabButtons.style.height = '30px'; - tabButtons.style.top = '0'; - tabButtons.style.right = '0'; - tabButtons.style.display = 'flex'; - tabButtons.style.justifyContent = 'center'; - tabButtons.style.alignItems = 'center'; - tabButtons.style.background = '#252526'; - tabContainer.appendChild(tabButtons); - - // Code editor. - const editorContainer = document.createElement('div'); - editorContainer.style.height = 'calc(100% - 30px)'; - codeWrapper.appendChild(editorContainer); - - return { - blocklyDiv, - minimizeButton, - monacoDiv: editorContainer, - guiContainer, - playgroundDiv, - tabsDiv, - tabButtons, - }; -} - -/** - * Render a code tab. - * @param {string} name Name of the tab. - * @returns {HTMLElement} The tab element. - */ -export function renderCodeTab(name) { - const tab = document.createElement('span'); - tab.style.background = '#2D2D2D'; - tab.style.color = '#969696'; - tab.style.padding = '10px 20px'; - tab.style.lineHeight = '30px'; - tab.style.cursor = 'pointer'; - tab.textContent = name; - return tab; -} - -/** - * Render a checkbox. - * @param {string} id Id to use for the checkbox element. - * @param {string} label The label string to use. - * @returns {Array} A tuple of the checkbox input element, and the - * checkbox label element. - */ -export function renderCheckbox(id, label) { - const checkbox = document.createElement('input'); - checkbox.setAttribute('type', 'checkbox'); - checkbox.setAttribute('id', id); - const checkboxLabel = document.createElement('label'); - checkboxLabel.textContent = label; - checkboxLabel.setAttribute('for', id); - return [checkbox, checkboxLabel]; -} - -/** - * Render a button. - * @param {string} label The text content of the button. - * @returns {HTMLButtonElement} The button element. - */ -export function renderButton(label) { - const button = document.createElement('button'); - button.setAttribute('type', 'button'); - button.textContent = label; - return button; -} diff --git a/plugins/dev-tools/src/populateRandom.js b/plugins/dev-tools/src/populateRandom.js deleted file mode 100644 index 422a72589..000000000 --- a/plugins/dev-tools/src/populateRandom.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Helper for randomly populating a workspace. - * @author fenichel@google.com (Rachel Fenichel) - */ -import * as Blockly from 'blockly/core'; - -/** - * Populate the workspace with a random set of blocks, for testing. - * @param {Blockly.Workspace} workspace The workspace to populate. - * @param {number} count How many blocks to create. - */ -export function populateRandom(workspace, count) { - const names = []; - for (const blockName in Blockly.Blocks) { - if ( - Object.prototype.hasOwnProperty.call(Blockly.Blocks, blockName) && - Object.prototype.hasOwnProperty.call(Blockly.Blocks[blockName], 'init') - ) { - names.push(blockName); - } - } - - for (let i = 0; i < count; i++) { - const name = names[Math.floor(Math.random() * names.length)]; - const block = workspace.newBlock(name); - block.initSvg(); - block - .getSvgRoot() - .setAttribute( - 'transform', - 'translate(' + - Math.round(Math.random() * 450 + 40) + - ', ' + - Math.round(Math.random() * 600 + 40) + - ')', - ); - block.render(); - } -} diff --git a/plugins/dev-tools/src/screenshot.js b/plugins/dev-tools/src/screenshot.js deleted file mode 100644 index 41ff4671e..000000000 --- a/plugins/dev-tools/src/screenshot.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Download screenshot. - * @author samelh@google.com (Sam El-Husseini) - */ -import * as Blockly from 'blockly/core'; - -/** - * Convert an SVG datauri into a PNG datauri. - * @param {string} data SVG datauri. - * @param {number} width Image width. - * @param {number} height Image height. - * @param {!Function} callback Callback. - */ -function svgToPng_(data, width, height, callback) { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - const img = new Image(); - - const pixelDensity = 10; - canvas.width = width * pixelDensity; - canvas.height = height * pixelDensity; - img.onload = function () { - context.drawImage( - img, - 0, - 0, - width, - height, - 0, - 0, - canvas.width, - canvas.height, - ); - try { - const dataUri = canvas.toDataURL('image/png'); - callback(dataUri); - } catch { - console.warn('Error converting the workspace svg to a png'); - callback(''); - } - }; - img.src = data; -} - -/** - * Create an SVG of the blocks on the workspace. - * @param {!Blockly.WorkspaceSvg} workspace The workspace. - * @param {!Function} callback Callback. - * @param {string=} customCss Custom CSS to append to the SVG. - */ -function workspaceToSvg_(workspace, callback, customCss) { - // Go through all text areas and set their value. - const textAreas = document.getElementsByTagName('textarea'); - for (let i = 0; i < textAreas.length; i++) { - textAreas[i].innerText = textAreas[i].value; - } - - const bBox = workspace.getBlocksBoundingBox(); - const x = bBox.x || bBox.left; - const y = bBox.y || bBox.top; - const width = bBox.width || bBox.right - x; - const height = bBox.height || bBox.bottom - y; - - const blockCanvas = workspace.getCanvas(); - const blockCanvasClone = blockCanvas.cloneNode(true); - blockCanvasClone.removeAttribute('transform'); - - const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); - svg.setAttribute('viewBox', x + ' ' + y + ' ' + width + ' ' + height); - - svg.setAttribute( - 'class', - 'blocklySvg ' + - (workspace.options.renderer || 'geras') + - '-renderer ' + - (workspace.getTheme ? workspace.getTheme().name + '-theme' : ''), - ); - svg.setAttribute('width', width); - svg.setAttribute('height', height); - svg.setAttribute( - 'style', - 'background-color: transparent; ' + - workspace.getInjectionDiv().style.cssText, // has CSS vars for SVG filters - ); - - const css = [].slice - .call(document.head.querySelectorAll('style')) - .filter(function (el) { - return ( - /\.blocklySvg/.test(el.innerText) || el.id.indexOf('blockly-') === 0 - ); - }) - .map(function (el) { - return el.innerText; - }) - .join('\n'); - const style = document.createElement('style'); - style.textContent = css + '\n' + customCss; - - svg.appendChild(style); - for (const defs of workspace.getSvgGroup().getElementsByTagName('defs')) { - svg.appendChild(defs.cloneNode(true)); - } - svg.appendChild(blockCanvasClone); - - let svgAsXML = new XMLSerializer().serializeToString(svg); - svgAsXML = svgAsXML.replace(/ /g, ' '); - const data = 'data:image/svg+xml,' + encodeURIComponent(svgAsXML); - - svgToPng_(data, width, height, callback); -} - -/** - * Download a screenshot of the blocks on a Blockly workspace. - * @param {!Blockly.WorkspaceSvg} workspace The Blockly workspace. - */ -export function downloadWorkspaceScreenshot(workspace) { - workspaceToSvg_(workspace, function (datauri) { - const a = document.createElement('a'); - a.download = 'screenshot.png'; - a.target = '_self'; - a.href = datauri; - document.body.appendChild(a); - a.click(); - a.parentNode.removeChild(a); - }); -} diff --git a/plugins/dev-tools/src/spaghetti.js b/plugins/dev-tools/src/spaghetti.js deleted file mode 100644 index bc0b52565..000000000 --- a/plugins/dev-tools/src/spaghetti.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Helper for populating the workspace with nested if-statement - * blocks, for testing. - * @author samelh@google.com (Sam El-Husseini) - */ -import * as Blockly from 'blockly/core'; - -const spaghettiXml = [ - ' ', - ' ', - ' ', - ' EQ', - ' ', - ' ', - ' MULTIPLY', - ' ', - ' ', - ' 6', - ' ', - ' ', - ' ', - ' ', - ' 7', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' 42', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', -].join('\n'); - -/** - * Populate the workspace with nested if-statement blocks, for testing. - * @param {Blockly.Workspace} workspace The workspace to populate. - * @param {number} depth How many layers of nesting to create. - */ -export function spaghetti(workspace, depth) { - let xml = spaghettiXml; - for (let i = 0; i < depth; i++) { - xml = xml.replace( - /(<(statement|next)( name="DO0")?>)<\//g, - '$1' + spaghettiXml + '' + xml + ''; - const dom = Blockly.utils.xml.textToDom(xml); - console.time('Spaghetti domToWorkspace'); - Blockly.Xml.domToWorkspace(dom, workspace); - console.timeEnd('Spaghetti domToWorkspace'); -} diff --git a/plugins/dev-tools/src/test_helpers.mocha.js b/plugins/dev-tools/src/test_helpers.mocha.js deleted file mode 100644 index c5ff8ca46..000000000 --- a/plugins/dev-tools/src/test_helpers.mocha.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as commonHelpers from './common_test_helpers.mocha'; -import * as blockTestHelpers from './block_test_helpers.mocha'; -import * as fieldTestHelpers from './field_test_helpers.mocha'; -import * as eventTestHelpers from './event_test_helpers.mocha'; - -const {TestCase, TestSuite, runTestCases, runTestSuites, captureWarnings} = - commonHelpers; - -const { - CodeGenerationTestCase, - CodeGenerationTestSuite, - runCodeGenerationTestSuites, - runSerializationTestSuite, - SerializationTestCase, -} = blockTestHelpers; - -const { - assertFieldValue, - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = fieldTestHelpers; - -const {assertEventFiredShallow, assertEventNotFired} = eventTestHelpers; - -export { - assertEventFiredShallow, - assertEventNotFired, - assertFieldValue, - CodeGenerationTestCase, - CodeGenerationTestSuite, - FieldCreationTestCase, - FieldValueTestCase, - runCodeGenerationTestSuites, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSerializationTestSuite, - runSetValueTests, - runTestCases, - runTestSuites, - captureWarnings, - SerializationTestCase, - TestCase, - TestSuite, -}; diff --git a/plugins/dev-tools/src/toolboxCategories.js b/plugins/dev-tools/src/toolboxCategories.js deleted file mode 100644 index 1f5ca4ce7..000000000 --- a/plugins/dev-tools/src/toolboxCategories.js +++ /dev/null @@ -1,786 +0,0 @@ -export default { - kind: 'categoryToolbox', - contents: [ - { - kind: 'category', - name: 'Logic', - categorystyle: 'logic_category', - contents: [ - { - type: 'controls_if', - kind: 'block', - }, - { - type: 'logic_compare', - kind: 'block', - fields: { - OP: 'EQ', - }, - }, - { - type: 'logic_operation', - kind: 'block', - fields: { - OP: 'AND', - }, - }, - { - type: 'logic_negate', - kind: 'block', - }, - { - type: 'logic_boolean', - kind: 'block', - fields: { - BOOL: 'TRUE', - }, - }, - { - type: 'logic_null', - kind: 'block', - enabled: false, - }, - { - type: 'logic_ternary', - kind: 'block', - }, - ], - }, - { - kind: 'category', - name: 'Loops', - categorystyle: 'loop_category', - contents: [ - { - type: 'controls_repeat_ext', - kind: 'block', - inputs: { - TIMES: { - shadow: { - type: 'math_number', - fields: { - NUM: 10, - }, - }, - }, - }, - }, - { - type: 'controls_repeat', - kind: 'block', - enabled: false, - fields: { - TIMES: 10, - }, - }, - { - type: 'controls_whileUntil', - kind: 'block', - fields: { - MODE: 'WHILE', - }, - }, - { - type: 'controls_for', - kind: 'block', - fields: { - VAR: { - name: 'i', - }, - }, - inputs: { - FROM: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - TO: { - shadow: { - type: 'math_number', - fields: { - NUM: 10, - }, - }, - }, - BY: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - }, - }, - { - type: 'controls_forEach', - kind: 'block', - fields: { - VAR: { - name: 'j', - }, - }, - }, - { - type: 'controls_flow_statements', - kind: 'block', - enabled: false, - fields: { - FLOW: 'BREAK', - }, - }, - ], - }, - { - kind: 'category', - name: 'Math', - categorystyle: 'math_category', - contents: [ - { - type: 'math_number', - kind: 'block', - fields: { - NUM: 123, - }, - }, - { - type: 'math_arithmetic', - kind: 'block', - fields: { - OP: 'ADD', - }, - inputs: { - A: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - B: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - }, - }, - { - type: 'math_single', - kind: 'block', - fields: { - OP: 'ROOT', - }, - inputs: { - NUM: { - shadow: { - type: 'math_number', - fields: { - NUM: 9, - }, - }, - }, - }, - }, - { - type: 'math_trig', - kind: 'block', - fields: { - OP: 'SIN', - }, - inputs: { - NUM: { - shadow: { - type: 'math_number', - fields: { - NUM: 45, - }, - }, - }, - }, - }, - { - type: 'math_constant', - kind: 'block', - fields: { - CONSTANT: 'PI', - }, - }, - { - type: 'math_number_property', - kind: 'block', - fields: { - PROPERTY: 'EVEN', - }, - inputs: { - NUMBER_TO_CHECK: { - shadow: { - type: 'math_number', - fields: { - NUM: 0, - }, - }, - }, - }, - }, - { - type: 'math_round', - kind: 'block', - fields: { - OP: 'ROUND', - }, - inputs: { - NUM: { - shadow: { - type: 'math_number', - fields: { - NUM: 3.1, - }, - }, - }, - }, - }, - { - type: 'math_on_list', - kind: 'block', - fields: { - OP: 'SUM', - }, - }, - { - type: 'math_modulo', - kind: 'block', - inputs: { - DIVIDEND: { - shadow: { - type: 'math_number', - fields: { - NUM: 64, - }, - }, - }, - DIVISOR: { - shadow: { - type: 'math_number', - fields: { - NUM: 10, - }, - }, - }, - }, - }, - { - type: 'math_constrain', - kind: 'block', - inputs: { - VALUE: { - shadow: { - type: 'math_number', - fields: { - NUM: 50, - }, - }, - }, - LOW: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - HIGH: { - shadow: { - type: 'math_number', - fields: { - NUM: 100, - }, - }, - }, - }, - }, - { - type: 'math_random_int', - kind: 'block', - inputs: { - FROM: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - TO: { - shadow: { - type: 'math_number', - fields: { - NUM: 100, - }, - }, - }, - }, - }, - { - type: 'math_random_float', - kind: 'block', - }, - { - type: 'math_atan2', - kind: 'block', - inputs: { - X: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - Y: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - }, - }, - ], - }, - { - kind: 'category', - name: 'Text', - categorystyle: 'text_category', - contents: [ - { - type: 'text', - kind: 'block', - fields: { - TEXT: '', - }, - }, - { - type: 'text_join', - kind: 'block', - }, - { - type: 'text_append', - kind: 'block', - fields: { - name: 'item', - }, - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - }, - }, - { - type: 'text_length', - kind: 'block', - inputs: { - VALUE: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - { - type: 'text_isEmpty', - kind: 'block', - inputs: { - VALUE: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - }, - }, - { - type: 'text_indexOf', - kind: 'block', - fields: { - END: 'FIRST', - }, - inputs: { - VALUE: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'text', - }, - }, - }, - }, - FIND: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - { - type: 'text_charAt', - kind: 'block', - fields: { - WHERE: 'FROM_START', - }, - inputs: { - VALUE: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'text', - }, - }, - }, - }, - }, - }, - { - type: 'text_getSubstring', - kind: 'block', - fields: { - WHERE1: 'FROM_START', - WHERE2: 'FROM_START', - }, - inputs: { - STRING: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'text', - }, - }, - }, - }, - }, - }, - { - type: 'text_changeCase', - kind: 'block', - fields: { - CASE: 'UPPERCASE', - }, - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - { - type: 'text_trim', - kind: 'block', - fields: { - MODE: 'BOTH', - }, - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - { - type: 'text_count', - kind: 'block', - inputs: { - SUB: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - }, - }, - { - type: 'text_replace', - kind: 'block', - inputs: { - FROM: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - TO: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - }, - }, - { - type: 'text_reverse', - kind: 'block', - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: '', - }, - }, - }, - }, - }, - - { - type: 'text_print', - kind: 'block', - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - { - type: 'text_prompt_ext', - kind: 'block', - fields: { - TYPE: 'TEXT', - }, - inputs: { - TEXT: { - shadow: { - type: 'text', - fields: { - TEXT: 'abc', - }, - }, - }, - }, - }, - ], - }, - { - kind: 'category', - name: 'Lists', - categorystyle: 'list_category', - contents: [ - { - type: 'lists_create_with', - kind: 'block', - extraState: { - itemCount: 0, - }, - }, - { - type: 'lists_create_with', - kind: 'block', - }, - { - type: 'lists_repeat', - kind: 'block', - inputs: { - NUM: { - shadow: { - type: 'math_number', - fields: { - NUM: 5, - }, - }, - }, - }, - }, - { - type: 'lists_length', - kind: 'block', - }, - { - type: 'lists_isEmpty', - kind: 'block', - }, - { - type: 'lists_indexOf', - kind: 'block', - - fields: { - END: 'FIRST', - }, - inputs: { - VALUE: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'list', - }, - }, - }, - }, - }, - }, - { - type: 'lists_getIndex', - kind: 'block', - fields: { - MODE: 'GET', - WHERE: 'FROM_START', - }, - inputs: { - VALUE: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'list', - }, - }, - }, - }, - }, - }, - { - type: 'lists_setIndex', - kind: 'block', - fields: { - MODE: 'SET', - WHERE: 'FROM_START', - }, - inputs: { - LIST: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'list', - }, - }, - }, - }, - }, - }, - { - type: 'lists_getSublist', - kind: 'block', - fields: { - WHERE1: 'FROM_START', - WHERE2: 'FROM_START', - }, - inputs: { - LIST: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'list', - }, - }, - }, - }, - }, - }, - { - type: 'lists_split', - kind: 'block', - - fields: { - MODE: 'SPLIT', - }, - inputs: { - DELIM: { - shadow: { - type: 'text', - fields: { - TEXT: ',', - }, - }, - }, - }, - }, - { - type: 'lists_sort', - kind: 'block', - - fields: { - TYPE: 'NUMERIC', - DIRECTION: '1', - }, - }, - { - type: 'lists_reverse', - kind: 'block', - }, - ], - }, - { - kind: 'sep', - }, - { - kind: 'category', - name: 'Variables', - custom: 'VARIABLE', - categorystyle: 'variable_category', - }, - { - kind: 'category', - name: 'Functions', - custom: 'PROCEDURE', - categorystyle: 'procedure_category', - }, - ], -}; diff --git a/plugins/dev-tools/src/toolboxSimple.js b/plugins/dev-tools/src/toolboxSimple.js deleted file mode 100644 index 278f69785..000000000 --- a/plugins/dev-tools/src/toolboxSimple.js +++ /dev/null @@ -1,83 +0,0 @@ -export default { - kind: 'flyoutToolbox', - contents: [ - { - type: 'controls_ifelse', - kind: 'block', - }, - { - type: 'logic_compare', - kind: 'block', - fields: { - OP: 'EQ', - }, - }, - { - type: 'logic_operation', - kind: 'block', - fields: { - OP: 'AND', - }, - }, - { - type: 'controls_repeat_ext', - kind: 'block', - inputs: { - TIMES: { - shadow: { - type: 'math_number', - fields: { - NUM: 10, - }, - }, - }, - }, - }, - { - type: 'logic_operation', - kind: 'block', - fields: { - OP: 'AND', - }, - }, - { - type: 'logic_negate', - kind: 'block', - }, - { - type: 'logic_boolean', - kind: 'block', - fields: { - BOOL: 'TRUE', - }, - }, - { - type: 'logic_null', - kind: 'block', - enabled: false, - }, - { - type: 'logic_ternary', - kind: 'block', - }, - { - type: 'text_charAt', - kind: 'block', - fields: { - WHERE: 'FROM_START', - }, - inputs: { - VALUE: { - block: { - type: 'variables_get', - fields: { - VAR: { - name: 'text', - }, - }, - }, - }, - }, - }, - ], -}; diff --git a/plugins/dev-tools/test/index.html b/plugins/dev-tools/test/index.html deleted file mode 100644 index 91177218a..000000000 --- a/plugins/dev-tools/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Dev-Tools Playground - - - - -
    - - - diff --git a/plugins/dev-tools/test/index.js b/plugins/dev-tools/test/index.js deleted file mode 100644 index 1443d3d4e..000000000 --- a/plugins/dev-tools/test/index.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Dev-tools Playground test. - * @author samelh@google.com (Sam El-Huseini) - */ - -import * as Blockly from 'blockly'; -import {createPlayground, toolboxCategories} from '../src/index'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/disable-top-blocks/CHANGELOG.md b/plugins/disable-top-blocks/CHANGELOG.md deleted file mode 100644 index c46314200..000000000 --- a/plugins/disable-top-blocks/CHANGELOG.md +++ /dev/null @@ -1,653 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [0.6.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/disable-top-blocks@0.6.8...@blockly/disable-top-blocks@0.6.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/disable-top-blocks@0.6.7...@blockly/disable-top-blocks@0.6.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/disable-top-blocks@0.6.6...@blockly/disable-top-blocks@0.6.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [0.6.6](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.6.5...@blockly/disable-top-blocks@0.6.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.5](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.6.4...@blockly/disable-top-blocks@0.6.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.4](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.6.3...@blockly/disable-top-blocks@0.6.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.3](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.6.2...@blockly/disable-top-blocks@0.6.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.2](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.6.1...@blockly/disable-top-blocks@0.6.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.1](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.6.0...@blockly/disable-top-blocks@0.6.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.6.0](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.16...@blockly/disable-top-blocks@0.6.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [0.5.16](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.15...@blockly/disable-top-blocks@0.5.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.15](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.14...@blockly/disable-top-blocks@0.5.15) (2025-05-15) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.14](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.13...@blockly/disable-top-blocks@0.5.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.13](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.12...@blockly/disable-top-blocks@0.5.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.12](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.11...@blockly/disable-top-blocks@0.5.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.11](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.10...@blockly/disable-top-blocks@0.5.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.10](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.9...@blockly/disable-top-blocks@0.5.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [0.5.9](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.8...@blockly/disable-top-blocks@0.5.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [0.5.8](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.7...@blockly/disable-top-blocks@0.5.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [0.5.7](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.6...@blockly/disable-top-blocks@0.5.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.6](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.5...@blockly/disable-top-blocks@0.5.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.5](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.4...@blockly/disable-top-blocks@0.5.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.4](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.3...@blockly/disable-top-blocks@0.5.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [0.5.3](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.2...@blockly/disable-top-blocks@0.5.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.2](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.1...@blockly/disable-top-blocks@0.5.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.5.1](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.5.0...@blockly/disable-top-blocks@0.5.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [0.5.0](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.15...@blockly/disable-top-blocks@0.5.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) - - - -## [0.4.15](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.14...@blockly/disable-top-blocks@0.4.15) (2024-05-16) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.14](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.13...@blockly/disable-top-blocks@0.4.14) (2024-05-09) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.13](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.12...@blockly/disable-top-blocks@0.4.13) (2024-04-25) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.12](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.11...@blockly/disable-top-blocks@0.4.12) (2024-04-04) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.11](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.10...@blockly/disable-top-blocks@0.4.11) (2024-03-28) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.10](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.9...@blockly/disable-top-blocks@0.4.10) (2024-02-08) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.9](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.8...@blockly/disable-top-blocks@0.4.9) (2023-12-14) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.8](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.7...@blockly/disable-top-blocks@0.4.8) (2023-12-07) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.7](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.6...@blockly/disable-top-blocks@0.4.7) (2023-11-09) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.6](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.5...@blockly/disable-top-blocks@0.4.6) (2023-11-02) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.5](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.4...@blockly/disable-top-blocks@0.4.5) (2023-10-30) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.4](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.3...@blockly/disable-top-blocks@0.4.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.3](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.2...@blockly/disable-top-blocks@0.4.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.2](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.1...@blockly/disable-top-blocks@0.4.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.1](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.4.0...@blockly/disable-top-blocks@0.4.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.4.0](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.3.1...@blockly/disable-top-blocks@0.4.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [0.3.1](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.3.0...@blockly/disable-top-blocks@0.3.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.3.0](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.17...@blockly/disable-top-blocks@0.3.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [0.2.17](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.16...@blockly/disable-top-blocks@0.2.17) (2023-06-22) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.16](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.15...@blockly/disable-top-blocks@0.2.16) (2023-05-18) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.15](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.14...@blockly/disable-top-blocks@0.2.15) (2023-05-11) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.14](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.13...@blockly/disable-top-blocks@0.2.14) (2023-05-04) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.13](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.12...@blockly/disable-top-blocks@0.2.13) (2023-04-27) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.12](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.11...@blockly/disable-top-blocks@0.2.12) (2023-03-23) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.11](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.10...@blockly/disable-top-blocks@0.2.11) (2023-03-09) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.10](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.9...@blockly/disable-top-blocks@0.2.10) (2023-03-02) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.9](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.8...@blockly/disable-top-blocks@0.2.9) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [0.2.8](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.7...@blockly/disable-top-blocks@0.2.8) (2023-02-23) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.7](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.6...@blockly/disable-top-blocks@0.2.7) (2023-02-16) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.6](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.5...@blockly/disable-top-blocks@0.2.6) (2023-02-09) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.5](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.4...@blockly/disable-top-blocks@0.2.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.4](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.3...@blockly/disable-top-blocks@0.2.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.3](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.2...@blockly/disable-top-blocks@0.2.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.2](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.1...@blockly/disable-top-blocks@0.2.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.1](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.2.0...@blockly/disable-top-blocks@0.2.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## [0.2.0](https://github.com/google/blockly-samples/compare/@blockly/disable-top-blocks@0.1.42...@blockly/disable-top-blocks@0.2.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 0.1.42 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 0.1.41 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 0.1.39 (2022-07-21) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## 0.1.38 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 0.1.37 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 0.1.36 (2022-06-21) - -**Note:** Version bump only for package @blockly/disable-top-blocks - - - - - -## 0.1.35 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 0.1.34 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/disable-top-blocks/README.md b/plugins/disable-top-blocks/README.md deleted file mode 100644 index 481b2fce5..000000000 --- a/plugins/disable-top-blocks/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# @blockly/disable-top-blocks [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that shows the -'disable' context menu option only on non-orphan blocks. This is useful in -conjunction with the `Blockly.Events.disableOrphans` event handler (which you -must set up yourself). - -## Installation - -### Yarn - -``` -yarn add @blockly/disable-top-blocks -``` - -### npm - -``` -npm install @blockly/disable-top-blocks --save -``` - -## Usage - -```js -import * as Blockly from 'blockly'; -import {DisableTopBlocks} from '@blockly/disable-top-blocks'; - -// Inject Blockly. -const workspace = Blockly.inject('blocklyDiv', {}; - -// Add the disableOrphans event handler. This is not done automatically by -// the plugin and should be handled by your application. -workspace.addChangeListener(Blockly.Events.disableOrphans); - -// The plugin must be initialized before it has any effect. -const disableTopBlocksPlugin = new DisableTopBlocks(); -disableTopBlocksPlugin.init(); -``` - -## API - -- `init` initializes the plugin and modifies the behavior of the 'disable' - context menu item. -- `dispose` restores the original behavior of the context menu. This is never - required to be called, but can be if you want to programmatically disable - the effects of the plugin. - -## License - -Apache 2.0 diff --git a/plugins/disable-top-blocks/package.json b/plugins/disable-top-blocks/package.json deleted file mode 100644 index f7555b8ae..000000000 --- a/plugins/disable-top-blocks/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@blockly/disable-top-blocks", - "version": "13.2.0", - "description": "A Blockly plugin that shows the 'disable' context menu option only on non-orphan blocks.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "start": "blockly-scripts start", - "predeploy": "npm run build && blockly-scripts predeploy" - }, - "main": "./dist/index.js", - "module": "./src/index.js", - "unpkg": "./dist/index.js", - "author": "", - "keywords": [ - "blockly", - "blockly-plugin", - "disable-top-blocks" - ], - "homepage": "git@github.com:RaspberryPiFoundation/blockly-samples/tree/master/plugins/disable-top-blocks#readme", - "bugs": { - "url": "git@github.com:RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "git@github.com:RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/disable-top-blocks" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/disable-top-blocks/src/index.js b/plugins/disable-top-blocks/src/index.js deleted file mode 100644 index 457c19186..000000000 --- a/plugins/disable-top-blocks/src/index.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ -/** - * @fileoverview Plugin for changing the context menu to match the - * `disableOrphans` event handler. - */ - -import * as Blockly from 'blockly/core'; - -/** - * This plugin changes the logic of the enable/disable context menu item. It is - * enabled for all blocks except top-level blocks that have output or - * previous connections. In other words, the option is disabled for orphan - * blocks. Using this plugin allows users to disable valid non-orphan blocks, - * but not re-enable blocks that have been automatically disabled by - * `disableOrphans`. - */ -export class DisableTopBlocks { - /** - * Modifies the context menu 'disable' option as described above. - */ - init() { - const disableMenuItem = - Blockly.ContextMenuRegistry.registry.getItem('blockDisable'); - this.oldPreconditionFn = disableMenuItem.preconditionFn; - disableMenuItem.preconditionFn = function ( - /** @type {!Blockly.ContextMenuRegistry.Scope} */ scope, - ) { - const block = scope.block; - if ( - !block.isInFlyout && - block.workspace.options.disable && - block.isEditable() - ) { - if (block.getInheritedDisabled() || isOrphan(block)) { - return 'disabled'; - } - return 'enabled'; - } - return 'hidden'; - }; - } - - /** - * Turn off the effects of this plugin and restore the initial behavior. - * This is never required to be called. It is optional in case you need to - * disable the plugin. - */ - dispose() { - const disableMenuItem = - Blockly.ContextMenuRegistry.registry.getItem('blockDisable'); - disableMenuItem.preconditionFn = this.oldPreconditionFn; - } -} - -/** - * A block is an orphan if its parent is an orphan, or if it doesn't have a - * parent but it does have a previous or output connection (so it expects to be - * attached to something). This means all children of orphan blocks are also - * orphans and cannot be manually re-enabled. - * @param {!Blockly.BlockSvg} block Block to check. - * @returns {boolean} Whether the block is an orphan. - */ -function isOrphan(block) { - // If the parent is an orphan block, this block should also be considered - // an orphan so it cannot be manually re-enabled. - const parent = /** @type {Blockly.BlockSvg} */ (block.getParent()); - if (parent && isOrphan(parent)) { - return true; - } - return !parent && !!(block.outputConnection || block.previousConnection); -} diff --git a/plugins/disable-top-blocks/test/index.html b/plugins/disable-top-blocks/test/index.html deleted file mode 100644 index 70aaa3122..000000000 --- a/plugins/disable-top-blocks/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly DisableTopBlocks Plugin Test - - - - -
    - - - diff --git a/plugins/disable-top-blocks/test/index.js b/plugins/disable-top-blocks/test/index.js deleted file mode 100644 index 553569f10..000000000 --- a/plugins/disable-top-blocks/test/index.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Disable top blocks plugin test. - */ - -import * as Blockly from 'blockly'; -import {toolboxCategories, createPlayground} from '@blockly/dev-tools'; -import {DisableTopBlocks} from '../src/index'; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - - // Add the disableOrphans event handler. This is not done automatically by - // the plugin and should be handled by your application. - workspace.addChangeListener(Blockly.Events.disableOrphans); - - // The plugin must be initialized before it has any effect. - const disableTopBlocksPlugin = new DisableTopBlocks(); - disableTopBlocksPlugin.init(); - - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: toolboxCategories, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/field-angle/CHANGELOG.md b/plugins/field-angle/CHANGELOG.md deleted file mode 100644 index 31010a97e..000000000 --- a/plugins/field-angle/CHANGELOG.md +++ /dev/null @@ -1,509 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* make field-multilineinput keyboard navigable and accessible (#2729) -* Bump Blockly dependency to v13 (#2704) - -### Features - -* make field-multilineinput keyboard navigable and accessible ([#2729](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2729)) - -### Bug Fixes - -* Improve accessibility of `FieldAngle` ([#2697](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2697)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [6.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-angle@6.0.8...@blockly/field-angle@6.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-angle@6.0.7...@blockly/field-angle@6.0.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-angle@6.0.6...@blockly/field-angle@6.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-angle@6.0.5...@blockly/field-angle@6.0.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-angle@6.0.4...@blockly/field-angle@6.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-angle@6.0.3...@blockly/field-angle@6.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-angle@6.0.2...@blockly/field-angle@6.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-angle@6.0.1...@blockly/field-angle@6.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@6.0.0...@blockly/field-angle@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.16...@blockly/field-angle@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.15...@blockly/field-angle@5.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.14...@blockly/field-angle@5.0.15) (2025-05-15) - - -### Bug Fixes - -* Fix ephemeral focus being taken twice ([#2521](https://github.com/google/blockly-samples/issues/2521)) ([29b5a0d](https://github.com/google/blockly-samples/commit/29b5a0d896e7e6f7eb83867bd5b2577bf808e839)), closes [#2514](https://github.com/google/blockly-samples/issues/2514) [#2515](https://github.com/google/blockly-samples/issues/2515) [#2514](https://github.com/google/blockly-samples/issues/2514) [#2515](https://github.com/google/blockly-samples/issues/2515) [#2527](https://github.com/google/blockly-samples/issues/2527) - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.13...@blockly/field-angle@5.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.12...@blockly/field-angle@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.11...@blockly/field-angle@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.10...@blockly/field-angle@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.9...@blockly/field-angle@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.8...@blockly/field-angle@5.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.7...@blockly/field-angle@5.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.6...@blockly/field-angle@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.5...@blockly/field-angle@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.4...@blockly/field-angle@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.3...@blockly/field-angle@5.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.2...@blockly/field-angle@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.1...@blockly/field-angle@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@5.0.0...@blockly/field-angle@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-angle@4.0.4...@blockly/field-angle@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* remove some uses of generateFieldTextBlocks ([#2357](https://github.com/google/blockly-samples/issues/2357)) ([53b3fa4](https://github.com/google/blockly-samples/commit/53b3fa4604aabb1fc5240d41c8d1d389d4b15301)) - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-angle@4.0.3...@blockly/field-angle@4.0.4) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-angle@4.0.2...@blockly/field-angle@4.0.3) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-angle@4.0.1...@blockly/field-angle@4.0.2) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@4.0.0...@blockly/field-angle@4.0.1) (2024-04-11) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.13...@blockly/field-angle@4.0.0) (2024-04-04) - - -### ⚠ BREAKING CHANGES - -* The multiline text input field no longer registers itself on load. The developer must either manually register the field or install blocks, which will install the field. This is part of a move to have no side effects in field and block definitions, so that tree-shaking can remove unwanted fields and blocks. -* The angle field no longer registers itself on load. The developer must manually register the field. This is part of a move to have no side effects in field and block definitions, so that tree-shaking can remove unwanted fields and blocks. - -### Features - -* add block definitions to fields ([#2299](https://github.com/google/blockly-samples/issues/2299)) ([c197af6](https://github.com/google/blockly-samples/commit/c197af6c67bc989bbdb4e83a62abc08167bcbbfe)), closes [#2162](https://github.com/google/blockly-samples/issues/2162) [#2202](https://github.com/google/blockly-samples/issues/2202) [#2221](https://github.com/google/blockly-samples/issues/2221) [#2211](https://github.com/google/blockly-samples/issues/2211) [#2220](https://github.com/google/blockly-samples/issues/2220) [#2232](https://github.com/google/blockly-samples/issues/2232) [#2233](https://github.com/google/blockly-samples/issues/2233) [#2296](https://github.com/google/blockly-samples/issues/2296) - - - -## [3.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.12...@blockly/field-angle@3.0.13) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.11...@blockly/field-angle@3.0.12) (2024-02-08) - - -### Bug Fixes - -* Display rounded number in field angle. ([#2191](https://github.com/google/blockly-samples/issues/2191)) ([68d60b7](https://github.com/google/blockly-samples/commit/68d60b7868f0a89c09afd16d64e7f2f16a719d7f)) - - - -## [3.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.10...@blockly/field-angle@3.0.11) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.9...@blockly/field-angle@3.0.10) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.8...@blockly/field-angle@3.0.9) (2023-11-09) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.7...@blockly/field-angle@3.0.8) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.6...@blockly/field-angle@3.0.7) (2023-10-30) - - -### Bug Fixes - -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* publish type for field angle ([#1956](https://github.com/google/blockly-samples/issues/1956)) ([f0e8dbf](https://github.com/google/blockly-samples/commit/f0e8dbfacfe1a7207380c83a347603a3dd845d58)) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.5...@blockly/field-angle@3.0.6) (2023-09-21) - - -### Bug Fixes - -* Fire intermediate events instead of change events while dragging angle field ([#1933](https://github.com/google/blockly-samples/issues/1933)) ([dc79b14](https://github.com/google/blockly-samples/commit/dc79b14e4bc402e76cff960a4d72d4ac3a4365a5)) - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.4...@blockly/field-angle@3.0.5) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.3...@blockly/field-angle@3.0.4) (2023-08-31) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.2...@blockly/field-angle@3.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.1...@blockly/field-angle@3.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@3.0.0...@blockly/field-angle@3.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-angle@2.0.1...@blockly/field-angle@3.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@2.0.0...@blockly/field-angle@2.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-angle@1.2.2...@blockly/field-angle@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [1.2.2](https://github.com/google/blockly-samples/compare/@blockly/field-angle@1.2.1...@blockly/field-angle@1.2.2) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [1.2.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@1.2.0...@blockly/field-angle@1.2.1) (2023-06-15) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## [1.2.0](https://github.com/google/blockly-samples/compare/@blockly/field-angle@1.1.1...@blockly/field-angle@1.2.0) (2023-05-25) - - -### Features - -* Revise fields ([#1700](https://github.com/google/blockly-samples/issues/1700)) ([c326f7b](https://github.com/google/blockly-samples/commit/c326f7b1ef54fe45387046c693ebd5afe2b2c571)) - - - -## [1.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-angle@1.1.0...@blockly/field-angle@1.1.1) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-angle - - - - - -## 1.1.0 (2023-05-11) - - -### Features - -* Add angle, colour, and multiline fields. (Rebase of [#1674](https://github.com/google/blockly-samples/issues/1674)) ([#1693](https://github.com/google/blockly-samples/issues/1693)) ([1b447f4](https://github.com/google/blockly-samples/commit/1b447f41d6293f14e846b8a4d82d289a5637a99a)) diff --git a/plugins/field-angle/README.md b/plugins/field-angle/README.md deleted file mode 100644 index d9f0b9afd..000000000 --- a/plugins/field-angle/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# @blockly/field-angle [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) angle field. - -## Installation - -### Yarn - -``` -yarn add @blockly/field-angle -``` - -### npm - -``` -npm install @blockly/field-angle --save -``` - -## Usage - -### Installation - -You must register this field with Blockly. You can do this by calling -`registerFieldAngle` before instantiating your blocks. If another field is -registered under the same name, this field will overwrite it. - -### Parameters - -This field accepts up to 9 parameters, in addition to the 4 accepted by the -[number field][number-field]: - -- "value" to specify the default value of the angle field. Defaults to 0. -- "mode" to specify the basic setup of the angle field. Either Mode.COMPASS - or Mode.PROTRACTOR. COMPASS specifies "clockwise" should be "true", and the - "offset" should be "90". PROTRACTOR specifies that "clockwise" should be - "false" and the "offset" should be 0. These settings can be overridden by - the following options. Defaults to PROTRACTOR. -- "clockwise" to specify whether the value of the angle field should increase - in the clockwise direction (if true) or in the counter-clockwise direction - (if false). Defaults to false. -- "offset" to specify where the minimum/maximum displayed value of the angle - field should be. The offset is in degree units that consider the circle to - be 360 degrees. A 0 offset (or multiple of 360) specifies the right side of - the circle as the minimum/maximum value. More positive values rotate - clockwise and more negative values rotate counter clockwise (regardless of - the "clockwise" setting). Defaults to 0. -- "displayMin" to specify the minimum displayed value of the angle field. The - minimum displayed value may not actually be a selectable value. For example, - you may have a full 0-360 degree circle ("displayMin" of 0), but only be - able to select angle values from 90-270. Defaults to 0. -- "displayMax" to specify the maximum displayed value of the angle field. The - maximum displayed value may not actually be a selectable value. For example, - you may have a full 0-360 degree circle ("displayMax" of 360), but only be - able to select angle values from 90-270. Defaults to 360. -- "minorTick" to specify the distance between small tick marks on the angle - picker. The minorTick is in units from your displayMin-displayMax. The ticks - start at your "min" rounded up to a multiple of your "minorTick". The - ticks end at you "max" rounded down to a multiple of your "minorTick". - Defaults to 15. -- "majorTick" to specify the distance between big tick marks on the angle - picker. The majorTick is in units from your displayMin-displayMax. The ticks - start at your "min" rounded up to a multiple of your "majorTick". The - ticks end at you "max" rounded down to a multiple of your "majorTick". - Defaults to 45. -- "symbol" to specify the unit symbol to append to your number. Defaults to °. - If this is used to specify "radians" or similar, - `Blockly.Msg['ARIA_LABEL_FIELD_ANGLE']` should be overridden accordingly to - ensure that the screenreader description remains consistent. - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {registerFieldAngle} from '@blockly/field-angle'; - -registerFieldAngle(); -Blockly.Blocks['test_field_angle'] = { - init: function () { - this.appendDummyInput() - .appendField('angle: ') - .appendField(new FieldAngle(90), 'FIELDNAME'); - }, -}; -``` - -### JSON - -```js -import * as Blockly from 'blockly'; -import {registerFieldAngle} from '@blockly/field-angle'; - -registerFieldAngle(); -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_field_angle', - message0: 'angle: %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - value: 50, - }, - ], - }, -]); -``` - -## License - -Apache 2.0 - -[number-field]: https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/number#creation diff --git a/plugins/field-angle/package.json b/plugins/field-angle/package.json deleted file mode 100644 index a8a8f7222..000000000 --- a/plugins/field-angle/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@blockly/field-angle", - "version": "13.2.0", - "description": "A Blockly angle field.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "field", - "angle" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-angle#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-angle" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "sinon": "^22.0.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-angle/readme-media/clockwise_false.gif b/plugins/field-angle/readme-media/clockwise_false.gif deleted file mode 100644 index daa54b7fa95114aba52ea660585cf7c439aabd30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39421 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 diff --git a/plugins/field-angle/readme-media/clockwise_true.gif b/plugins/field-angle/readme-media/clockwise_true.gif deleted file mode 100644 index 58e103c131786b7cd1390037be9992a527e800e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38124 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 diff --git a/plugins/field-angle/readme-media/collapsed.png b/plugins/field-angle/readme-media/collapsed.png deleted file mode 100644 index a84dae0d298cea143242ee20d8bb8489b52fb712..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2033 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�pdE^W+dus!E$dwyd><7~ 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 diff --git a/plugins/field-angle/readme-media/round_70.gif b/plugins/field-angle/readme-media/round_70.gif deleted file mode 100644 index 430c55be4b6590b7dd9d8b0e012cecf8f5cadf5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114103 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 g27oZ)~ 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 Am;e9( diff --git a/plugins/field-angle/readme-media/validator.gif b/plugins/field-angle/readme-media/validator.gif deleted file mode 100644 index 4257c56eafa8e1b6d3a78f5c51bba390c0a38d58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60197 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 Mb(mVUicQS_1MwO)`2YX_ diff --git a/plugins/field-angle/readme-media/wrap.gif b/plugins/field-angle/readme-media/wrap.gif deleted file mode 100644 index 146f7b29e3ee6067b45955f5898a15522f8fbd47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54192 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 this.displayMax) { - throw Error('Display min must be larger than display max'); - } - if (this.minorTick < 0 || this.majorTick < 0) { - throw Error('Ticks cannot be negative'); - } - } - - override getAriaTypeName() { - return Blockly.Msg['ARIA_TYPE_FIELD_ANGLE']; - } - - override getAriaValue() { - return Blockly.Msg['ARIA_LABEL_FIELD_ANGLE'].replace( - '%1', - super.getAriaValue() ?? '', - ); - } - - /** - * Create the block UI for this field. - * - * @internal - */ - override initView() { - super.initView(); - if (this.symbol) { - // Add the degree symbol to the left of the number, - // even in RTL (https://github.com/google/blockly/issues/2380). - this.symbolElement = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TSPAN, - {class: 'blocklyAngleSymbol'}, - ); - this.symbolElement.appendChild(document.createTextNode(this.symbol)); - this.getTextElement().appendChild(this.symbolElement); - } - } - - /** - * Updates the angle when the field rerenders. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override render_() { - super.render_(); - this.updateGraph(); - } - - /** - * Create and show the angle field's editor. - * - * @param e Optional mouse event that triggered the field to open, - * or undefined if triggered programmatically. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override showEditor_(e?: Event) { - // Mobile browsers have issues with in-line textareas (focus & keyboards). - // Also, don't let the parent take ephemeral focus since the drop-down div - // below will handle it, instead. - const noFocus = - Blockly.utils.userAgent.MOBILE || - Blockly.utils.userAgent.ANDROID || - Blockly.utils.userAgent.IPAD; - - const editor = this.dropdownCreate(); - Blockly.DropDownDiv.getContentDiv().appendChild(editor); - - const sourceBlock = this.getSourceBlock(); - if (sourceBlock instanceof Blockly.BlockSvg) { - Blockly.DropDownDiv.setColour( - sourceBlock.style.colourPrimary, - sourceBlock.style.colourTertiary, - ); - } - - Blockly.DropDownDiv.showPositionedByField( - this, - this.dropdownDispose.bind(this), - ); - - super.showEditor_(e, noFocus, false); - - this.updateGraph(); - } - - /** - * Creates the angle dropdown editor. - * - * @returns The newly created slider. - */ - private dropdownCreate(): SVGSVGElement { - const svg = Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.SVG, { - 'xmlns': Blockly.utils.dom.SVG_NS, - // eslint-disable-next-line @typescript-eslint/naming-convention - 'xmlns:html': Blockly.utils.dom.HTML_NS, - // eslint-disable-next-line @typescript-eslint/naming-convention - 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, - 'version': '1.1', - 'height': FieldAngle.HALF * 2 + 'px', - 'width': FieldAngle.HALF * 2 + 'px', - }); - svg.style.touchAction = 'none'; - const circle = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.CIRCLE, - { - cx: FieldAngle.HALF, - cy: FieldAngle.HALF, - r: FieldAngle.RADIUS, - class: 'blocklyAngleCircle', - }, - svg, - ); - this.gauge = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.PATH, - { - class: 'blocklyAngleGauge', - }, - svg, - ); - this.line = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, - { - x1: FieldAngle.HALF, - y1: FieldAngle.HALF, - class: 'blocklyAngleLine', - }, - svg, - ); - - // Draw markers around the edge. - const minValueDegrees = Blockly.utils.math.toDegrees( - this.fieldAngleToRadians(this.min_), - ); - const maxValueDegrees = Blockly.utils.math.toDegrees( - this.fieldAngleToRadians(this.max_), - ); - - /** - * Draw a set of ticks on the gauge. - * - * @param tickAngle Angle between each tick. - * @param length Length of the tick (minor=5, major=10). - */ - const drawTicks = (tickAngle: number, length: number) => { - let min = Math.ceil(minValueDegrees / tickAngle) * tickAngle; - let max = Math.floor(maxValueDegrees / tickAngle) * tickAngle; - - if (this.clockwise) { - if (min < max) { - min += 360; - } - } else { - if (min > max) { - max += 360; - } - } - if (max === min) { - // Technically this could actually be zero, but more likely it's whole. - max += 360; - } - if (min > max) { - [min, max] = [max, min]; - } - for (let angle = min; angle <= max; angle += tickAngle) { - Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.LINE, - { - x1: FieldAngle.HALF + FieldAngle.RADIUS, - y1: FieldAngle.HALF, - x2: FieldAngle.HALF + FieldAngle.RADIUS - length, - y2: FieldAngle.HALF, - class: 'blocklyAngleMarks', - transform: - 'rotate(' + - -angle + - ',' + - FieldAngle.HALF + - ',' + - FieldAngle.HALF + - ')', - }, - svg, - ); - } - }; - - const displayRange = this.displayMax - this.displayMin; - const minorTickAngle = (360 / displayRange) * this.minorTick; - if (minorTickAngle) { - drawTicks(minorTickAngle, 5); - } - const majorTickAngle = (360 / displayRange) * this.majorTick; - if (majorTickAngle) { - drawTicks(majorTickAngle, 10); - } - - // The angle picker is different from other fields in that it updates on - // mousemove even if it's not in the middle of a drag. In future we may - // change this behaviour. - this.boundEvents.push( - Blockly.browserEvents.conditionalBind(svg, 'click', this, this.hide), - ); - // On touch devices, the picker's value is only updated with a drag. Add - // a click handler on the drag surface to update the value if the surface - // is clicked. - this.boundEvents.push( - Blockly.browserEvents.conditionalBind( - circle, - 'pointerdown', - this, - this.onMouseMove_, - true, - ), - ); - this.boundEvents.push( - Blockly.browserEvents.conditionalBind( - circle, - 'pointermove', - this, - this.onMouseMove_, - true, - ), - ); - return svg; - } - - /** - * Disposes of events belonging to the angle editor. - */ - private dropdownDispose() { - for (const event of this.boundEvents) { - Blockly.browserEvents.unbind(event); - } - this.boundEvents.length = 0; - this.gauge = null; - this.line = null; - } - - /** Hide the editor. */ - private hide() { - this.recomputeAriaContext(); - Blockly.DropDownDiv.hideIfOwner(this); - Blockly.WidgetDiv.hide(); - } - - /** - * Set the angle to match the mouse's position. - * - * @param e Mouse move event. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected onMouseMove_(e: PointerEvent) { - // Calculate angle. - const bBox = this.gauge?.ownerSVGElement?.getBoundingClientRect(); - if (!bBox) { - // This can't happen, but TypeScript thinks it can and lint forbids `!.`. - return; - } - const dx = e.clientX - bBox.left - FieldAngle.HALF; - const dy = e.clientY - bBox.top - FieldAngle.HALF; - let angle = Math.atan2(-dy, dx); - if (isNaN(angle)) { - // This shouldn't happen, but let's not let this error propagate further. - return; - } - angle = this.radiansToFieldAngle(angle); - this.displayMouseOrKeyboardValue(angle); - } - - /** - * Convert an on-screen angle into a value for this field. - * - * @param angle Radians where 0: East, π/2: North, π or -π: West, -π/2: South. - * @returns Angle value for this field, scaled and offset as specified. - */ - private radiansToFieldAngle(angle: number): number { - // Convert angle from radians (-π to π) to turns (-0.5 to 0.5). - angle /= 2 * Math.PI; - // Compensate for offset. - angle -= this.offset / 360; - // Flip if clockwise. - if (this.clockwise) { - angle *= -1; - } - // Normalize to positive. - angle %= 1; - if (angle < 0) { - angle += 1; - } - // Convert angle from turns (0.0 to 1.0) to the display min/max range. - angle *= this.displayMax - this.displayMin; - angle += this.displayMin; - return angle; - } - - /** - * Convert a value for this field into an on-screen angle. - * - * @param angle Angle value for this field, scaled and offset as specified. - * @returns Radians where 0: East, π/2: North, π or -π: West, -π/2: South. - */ - private fieldAngleToRadians(angle: number): number { - // Convert angle from the display min/max range to turns (0.0 to 1.0). - angle -= this.displayMin; - angle /= this.displayMax - this.displayMin; - // Flip if clockwise. - if (this.clockwise) { - angle *= -1; - } - // Compensate for offset. - angle += this.offset / 360; - // Normalize to span equally across zero (-0.5 to 0.5). - angle %= 1; - if (angle > 0.5) { - angle -= 1; - } - if (angle < -0.5) { - angle += 1; - } - // Convert angle from turns to radians. - angle *= 2 * Math.PI; - return angle; - } - - /** - * Handles and displays values that are input via mouse or arrow key input. - * These values need to be rounded and wrapped before being displayed so - * that the text input's value is appropriate. - * - * @param angle New angle. - */ - private displayMouseOrKeyboardValue(angle: number) { - const validAngle = this.doClassValidation_(angle); - if (validAngle !== null && validAngle !== this.value_) { - // Intermediate value changes from user input are not confirmed until the - // user closes the editor, and may be numerous. Inhibit reporting these as - // normal block change events, and instead report them as special - // intermediate changes that do not get recorded in undo history. - const oldValue = this.value_; - this.setEditorValue_(validAngle, false); - if ( - this.sourceBlock_ && - Blockly.Events.isEnabled() && - this.value_ !== oldValue - ) { - Blockly.Events.fire( - new (Blockly.Events.get( - Blockly.Events.BLOCK_FIELD_INTERMEDIATE_CHANGE, - ))(this.sourceBlock_, this.name || null, oldValue, this.value_), - ); - Blockly.utils.aria.announceDynamicAriaState(this.getAriaValue()); - } - } - } - - /** Redraw the graph with the current angle. */ - private updateGraph() { - if (!this.gauge || !this.line) { - return; - } - let angle = Number(this.getText()); - if (isNaN(angle)) { - // This shouldn't happen, but let's not let this error propagate further. - return; - } - angle = this.fieldAngleToRadians(angle); - - let path = `M ${FieldAngle.HALF},${FieldAngle.HALF}`; - let x2 = FieldAngle.HALF; - let y2 = FieldAngle.HALF; - if (!isNaN(angle)) { - const angle1 = Blockly.utils.math.toRadians(this.offset); - const x1 = Math.cos(angle1) * FieldAngle.RADIUS; - const y1 = Math.sin(angle1) * -FieldAngle.RADIUS; - x2 += Math.cos(angle) * FieldAngle.RADIUS; - y2 -= Math.sin(angle) * FieldAngle.RADIUS; - // Don't ask how the flag calculations work. They just do. - const clockwiseFlag = Number(this.clockwise); - let largeFlag = Math.abs(Math.floor((angle - angle1) / Math.PI) % 2); - if (clockwiseFlag) { - largeFlag = 1 - largeFlag; - } - path += - ` l ${x1},${y1} A ${FieldAngle.RADIUS},${FieldAngle.RADIUS} 0 ` + - `${largeFlag} ${clockwiseFlag} ${x2},${y2} z`; - } - this.gauge.setAttribute('d', path); - this.line.setAttribute('x2', `${x2}`); - this.line.setAttribute('y2', `${y2}`); - } - - /** - * Handle key down to the editor. - * - * @param e Keyboard event. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override onHtmlInputKeyDown_(e: KeyboardEvent) { - super.onHtmlInputKeyDown_(e); - const block = this.getSourceBlock(); - if (!block) { - throw new Error( - 'The field has not yet been attached to its input. ' + - 'Call appendField to attach it.', - ); - } - - let multiplier = 0; - switch (e.key) { - case 'ArrowLeft': - // decrement (increment in RTL) - multiplier = block.RTL ? 1 : -1; - break; - case 'ArrowRight': - // increment (decrement in RTL) - multiplier = block.RTL ? -1 : 1; - break; - case 'ArrowDown': - // decrement - multiplier = -1; - break; - case 'ArrowUp': - // increment - multiplier = 1; - break; - } - if (multiplier) { - const value = this.getValue() as number; - this.displayMouseOrKeyboardValue(value + multiplier * this.precision_); - e.preventDefault(); - e.stopPropagation(); - } - } - - /** - * Ensure that the input value is a valid angle. - * - * @param newValue The input value. - * @returns A valid angle, or null if invalid. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue: number, - ): number | null | undefined; - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_(newValue?: number): number | null; - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue?: number, - ): number | null | undefined { - // The obvious approach would be to call super.doClassValidation_ to handle - // min/max limitations. However angle pickers out of range need to clamp - // to the closest min/max point, which may involve a wrap to the opposite - // end of the numeric scale. - // E.g. min/max is 0/180 on a 0/360 display, and value is 365. - // FieldNumber would clamp 365 to max (180), but 0 is closer on the dial. - if (newValue === null) { - return null; - } - let value = Number(newValue); - if (isNaN(value) || !isFinite(value)) { - return null; - } - // Get the value in range. - value = this.wrapValue(value); - // Round to nearest multiple of precision. - if (this.precision_) { - value = Math.round(value / this.precision_) * this.precision_; - } - // Deal with 6.6000000000000005 IEEE float errors. - // Clean up floating point errors. - value = Number(value.toFixed(10)); - // Clamp the value between min and max, noting wrapping. - const displayRange = this.displayMax - this.displayMin; - const valueRange = this.max_ - this.min_; - if (value < this.min_) { - const undershoot = this.min_ - value; - const overshoot = displayRange - undershoot - valueRange; - value = undershoot < overshoot ? this.min_ : this.max_; - } - if (value > this.max_) { - const overshoot = value - this.max_; - const undershoot = displayRange - overshoot - valueRange; - value = undershoot < overshoot ? this.min_ : this.max_; - } - return value; - } - - /** - * Wraps the value so that it is in the min/max display range (e.g. 0 to 360). - * - * @param value The value to wrap. - * @returns The wrapped value. - */ - private wrapValue(value: number): number { - const displayRange = this.displayMax - this.displayMin; - value %= displayRange; - while (value < this.displayMin) { - value += displayRange; - } - while (value >= this.displayMax) { - value -= displayRange; - } - return value; - } - - /** - * Construct a FieldAngle from a JSON arg object. - * - * @param options A JSON object with options - * (value, mode, clockwise, offset, min, max, precision). - * @returns The new field instance. - * @nocollapse - * @internal - */ - static fromJson(options: FieldAngleFromJsonConfig): FieldAngle { - // `this` might be a subclass of FieldAngle if that class doesn't override - // the static fromJson method. - return new this(options.value, undefined, options); - } - - /** - * Hides the angle editor and updates the ARIA label. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override widgetDispose_() { - super.widgetDispose_(); - this.recomputeAriaContext(); - } -} - -/** Register the field and any dependencies. */ -export function registerFieldAngle() { - Blockly.fieldRegistry.register('field_angle', FieldAngle); -} - -FieldAngle.prototype.DEFAULT_VALUE = 0; - -/** - * CSS for angle field. - */ -Blockly.Css.register(` -.blocklyAngleCircle { - stroke: #444; - stroke-width: 1; - fill: #ddd; - fill-opacity: 0.8; -} - -.blocklyAngleMarks { - stroke: #444; - stroke-width: 1; -} - -.blocklyAngleGauge { - fill: #f88; - fill-opacity: 0.8; - pointer-events: none; -} - -.blocklyAngleLine { - stroke: #f00; - stroke-width: 2; - stroke-linecap: round; - pointer-events: none; -} - -.blocklyAngleSymbol { - dominant-baseline: central; -} -`); - -/** - * The two main modes of the angle field. - * Compass specifies: - * - clockwise: true - * - offset: 90 - * - min: 0 - * - max: 360 - * - precision: 15 - * - displayMin: 0 - * - displayMax: 360 - * - minorTick: 15 - * - majorTick: 45 - * - symbol: '°' - * - * Protractor specifies: - * - clockwise: false - * - offset: 0 - * - min: 0 - * - max: 360 - * - precision: 15 - * - displayMin: 0 - * - displayMax: 360 - * - minorTick: 15 - * - majorTick: 45 - * - symbol: '°' - */ -export enum Mode { - COMPASS = 'compass', - PROTRACTOR = 'protractor', -} - -/** - * Extra configuration options for the angle field. - */ -export interface FieldAngleConfig extends Blockly.FieldNumberConfig { - mode?: Mode; - clockwise?: boolean; - offset?: number; - displayMin?: number; - displayMax?: number; - minorTick?: number; - majorTick?: number; - symbol?: string; -} - -/** - * fromJson configuration options for the angle field. - */ -export interface FieldAngleFromJsonConfig extends FieldAngleConfig { - value?: number; -} - -/** - * A function that is called to validate changes to the field's value before - * they are set. - * - * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} - * @param newValue The value to be validated. - * @returns One of three instructions for setting the new value: `T`, `null`, - * or `undefined`. - * - * - `T` to set this function's returned value instead of `newValue`. - * - * - `null` to invoke `doValueInvalid_` and not set a value. - * - * - `undefined` to set `newValue` as is. - */ -export type FieldAngleValidator = Blockly.FieldNumberValidator; diff --git a/plugins/field-angle/src/index.ts b/plugins/field-angle/src/index.ts deleted file mode 100644 index ab5c44770..000000000 --- a/plugins/field-angle/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './field_angle'; diff --git a/plugins/field-angle/test/field_angle_test.mocha.js b/plugins/field-angle/test/field_angle_test.mocha.js deleted file mode 100644 index 3b519343e..000000000 --- a/plugins/field-angle/test/field_angle_test.mocha.js +++ /dev/null @@ -1,328 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {testHelpers} = require('@blockly/dev-tools'); -const {FieldAngle, registerFieldAngle} = require('../src/index'); -const {assert} = require('chai'); - -const { - assertFieldValue, - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -suite('FieldAngle', function () { - setup(function () { - registerFieldAngle(); - }); - - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = [ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - {title: 'NaN', value: NaN}, - {title: 'Non-Parsable String', value: 'bad'}, - {title: 'Infinity', value: Infinity}, - {title: 'Negative Infinity', value: -Infinity}, - {title: 'Infinity String', value: 'Infinity'}, - {title: 'Negative Infinity String', value: '-Infinity'}, - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = [ - {title: 'Integer', value: 16, expectedValue: 15}, - {title: 'Float', value: 14.5, expectedValue: 15}, - {title: 'Integer String', value: '30', expectedValue: 30}, - {title: 'Float String', value: '0.75', expectedValue: 0}, - {title: '> 360°', value: 360 + 16, expectedValue: 15}, - {title: '< 0°', value: -16, expectedValue: 360 - 15}, - ]; - const addArgsAndJson = function (testCase) { - testCase.args = [testCase.value]; - testCase.json = {value: testCase.value}; - }; - invalidValueTestCases.forEach(addArgsAndJson); - validValueTestCases.forEach(addArgsAndJson); - - /** - * The expected default value for the field being tested. - * @type {*} - */ - const defaultFieldValue = 0; - /** - * Asserts that the field property values are set to default. - * @param {FieldAngle} field The field to check. - */ - const assertFieldDefault = function (field) { - assertFieldValue(field, defaultFieldValue); - }; - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldAngle} field The field to check. - * @param {!FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertFieldValue(field, testCase.expectedValue); - }; - - runConstructorSuiteTests( - FieldAngle, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runFromJsonSuiteTests( - FieldAngle, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - suite('setValue', function () { - /** - * Create a mock block that may be used as the source block for a field. - * @returns {!Object} Mock block. - */ - function createBlockMock() { - return { - id: 'test', - rendered: false, - workspace: { - rendered: false, - }, - renameVarById: Blockly.Block.prototype.renameVarById, - updateVarName: Blockly.Block.prototype.updateVarName, - isShadow: () => false, - isDeadOrDying: () => false, - }; - } - - suite('Empty -> New Value', function () { - setup(function () { - this.field = new FieldAngle(); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - defaultFieldValue, - ); - test('With source block', function () { - this.field.setSourceBlock(createBlockMock()); - this.field.setValue(12.5); - assertFieldValue(this.field, 15); - }); - }); - suite('Value -> New Value', function () { - setup(function () { - this.field = new FieldAngle(12.5); - }); - runSetValueTests(validValueTestCases, invalidValueTestCases, 15); - test('With source block', function () { - this.field.setSourceBlock(createBlockMock()); - this.field.setValue(-15); - assertFieldValue(this.field, 360 - 15); - }); - }); - }); - - suite('Validators', function () { - setup(function () { - this.field = new FieldAngle(15); - }); - const testSuites = [ - { - title: 'Null Validator', - validator: function () { - return null; - }, - value: 30, - expectedValue: 15, - }, - { - title: 'Force multiple of 90 Validator', - validator: function (newValue) { - return Math.round(newValue / 90) * 90; - }, - value: 60, - expectedValue: 90, - }, - { - title: 'Returns Undefined Validator', - validator: function () {}, - value: 30, - expectedValue: 30, - }, - ]; - testSuites.forEach(function (suiteInfo) { - suite(suiteInfo.title, function () { - setup(function () { - this.field.setValidator(suiteInfo.validator); - }); - test('New Value', function () { - this.field.setValue(suiteInfo.value); - assertFieldValue( - this.field, - suiteInfo.expectedValue, - suiteInfo.expectedText, - ); - }); - }); - }); - }); - - suite('Customizations', function () { - suite('Clockwise', function () { - test('JS Configuration', function () { - const field = new FieldAngle(0, null, { - clockwise: true, - }); - assert.isTrue(field.clockwise); - }); - test('JSON Definition', function () { - const field = FieldAngle.fromJson({ - value: 0, - clockwise: true, - }); - assert.isTrue(field.clockwise); - }); - }); - - suite('Offset', function () { - test('JS Configuration', function () { - const field = new FieldAngle(0, null, { - offset: 90, - }); - assert.equal(field.offset, 90); - }); - test('JSON Definition', function () { - const field = FieldAngle.fromJson({ - value: 0, - offset: 90, - }); - assert.equal(field.offset, 90); - }); - }); - - suite('Min/Max', function () { - test('JS Configuration', function () { - const field = new FieldAngle(0, null, { - min: -180, - max: 180, - }); - assert.equal(field.getMin(), -180); - assert.equal(field.getMax(), 180); - }); - test('JSON Definition', function () { - const field = FieldAngle.fromJson({ - value: 0, - min: -180, - max: 180, - }); - assert.equal(field.getMin(), -180); - assert.equal(field.getMax(), 180); - }); - }); - - suite('Precision', function () { - test('JS Configuration', function () { - const field = new FieldAngle(0, null, { - precision: 30, - }); - assert.equal(field.getPrecision(), 30); - }); - test('JSON Definition', function () { - const field = FieldAngle.fromJson({ - value: 0, - precision: 30, - }); - assert.equal(field.getPrecision(), 30); - }); - }); - - suite('Mode', function () { - suite('Compass', function () { - test('JS Configuration', function () { - const field = new FieldAngle(0, null, { - mode: 'compass', - }); - assert.equal(field.offset, 90); - assert.isTrue(field.clockwise); - }); - test('JS Configuration', function () { - const field = FieldAngle.fromJson({ - value: 0, - mode: 'compass', - }); - assert.equal(field.offset, 90); - assert.isTrue(field.clockwise); - }); - }); - suite('Protractor', function () { - test('JS Configuration', function () { - const field = new FieldAngle(0, null, { - mode: 'protractor', - }); - assert.equal(field.offset, 0); - assert.isFalse(field.clockwise); - }); - test('JS Configuration', function () { - const field = FieldAngle.fromJson({ - value: 0, - mode: 'protractor', - }); - assert.equal(field.offset, 0); - assert.isFalse(field.clockwise); - }); - }); - }); - }); - - suite('Serialization', function () { - setup(function () { - this.workspace = new Blockly.Workspace(); - Blockly.defineBlocksWithJsonArray([ - { - type: 'row_block', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - output: null, - }, - ]); - - this.assertValue = (value) => { - const block = this.workspace.newBlock('row_block'); - const field = new FieldAngle(value); - block.getInput('INPUT').appendField(field, 'ANGLE'); - const jso = Blockly.serialization.blocks.save(block); - assert.deepEqual(jso['fields'], {ANGLE: value}); - }; - }); - - teardown(function () { - this.workspace.dispose(); - }); - - test('Simple', function () { - this.assertValue(90); - }); - }); -}); diff --git a/plugins/field-angle/test/index.html b/plugins/field-angle/test/index.html deleted file mode 100644 index c6879bd86..000000000 --- a/plugins/field-angle/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Angle Playground - - - - -

    - - - diff --git a/plugins/field-angle/test/index.ts b/plugins/field-angle/test/index.ts deleted file mode 100644 index 643a45a4d..000000000 --- a/plugins/field-angle/test/index.ts +++ /dev/null @@ -1,332 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Angle field test playground. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import {registerFieldAngle} from '../src/index'; - -/** - * An array of blocks that are defined only for the purposes of - * manually and visually testing the angle field. - */ -const testBlockDefinitions = [ - { - type: 'test_standard_field_values', - message0: '%1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values', - message0: '%1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - value: 50, - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_compass', - message0: 'compass %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - mode: 'compass', - value: 90, - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_protractor', - message0: 'protractor %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - mode: 'protractor', - value: 90, - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_round', - message0: 'round %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - precision: 0.1, - value: 123, - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_radians', - message0: 'radians %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - precision: 0.1, - clockwise: true, - value: 0, - min: 0, - max: Math.PI, - displayMin: -Math.PI, - displayMax: Math.PI, - minorTick: Math.PI / 8, - majorTick: Math.PI, - symbol: ' rad', - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_quadrant', - message0: 'quadrant %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - precision: 1, - value: 0, - min: 0, - max: 2, - displayMin: 0, - displayMax: 8, - minorTick: 0, - majorTick: 1, - symbol: '', - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_standard_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_angle', - name: 'FIELDNAME', - value: 50, - alt: { - type: 'field_label', - text: `No field_angle`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_parent_block', - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }, -]; - -Blockly.defineBlocksWithJsonArray(testBlockDefinitions); - -/** - * A test toolbox containing the exported blocks and a variety of - * test blocks to exercise the angle field in different contexts - * (on a shadow block, as the only field on a block, etc). - * These are in a simple toolbox, rather than a category toolbox, so that - * they are all instantiated every time the test page is opened. - */ -const jsonToolbox = { - contents: [ - { - kind: 'label', - text: 'Test blocks: default field values', - }, - { - kind: 'block', - type: 'test_standard_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_standard_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: custom field values', - }, - { - kind: 'block', - type: 'test_custom_field_values', - }, - { - kind: 'block', - type: 'test_custom_field_values_compass', - }, - { - kind: 'block', - type: 'test_custom_field_values_protractor', - }, - { - kind: 'block', - type: 'test_custom_field_values_round', - }, - { - kind: 'block', - type: 'test_custom_field_values_radians', - }, - { - kind: 'block', - type: 'test_custom_field_values_quadrant', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values_and_label', - }, - }, - }, - }, - ], -}; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - registerFieldAngle(); - const defaultOptions: Blockly.BlocklyOptions = { - toolbox: jsonToolbox, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/field-angle/tsconfig.json b/plugins/field-angle/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/field-angle/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-bitmap/CHANGELOG.md b/plugins/field-bitmap/CHANGELOG.md deleted file mode 100644 index 0cd07ce51..000000000 --- a/plugins/field-bitmap/CHANGELOG.md +++ /dev/null @@ -1,699 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -### Features - -* **field-bitmap:** make the bitmap editor keyboard and screen-reader accessible ([#2754](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2754)) - - -## [6.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-bitmap@6.0.8...@blockly/field-bitmap@6.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-bitmap@6.0.7...@blockly/field-bitmap@6.0.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-bitmap@6.0.6...@blockly/field-bitmap@6.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@6.0.5...@blockly/field-bitmap@6.0.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@6.0.4...@blockly/field-bitmap@6.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@6.0.3...@blockly/field-bitmap@6.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@6.0.2...@blockly/field-bitmap@6.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@6.0.1...@blockly/field-bitmap@6.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@6.0.0...@blockly/field-bitmap@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.17...@blockly/field-bitmap@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.16...@blockly/field-bitmap@5.0.17) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.15...@blockly/field-bitmap@5.0.16) (2025-05-15) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.14...@blockly/field-bitmap@5.0.15) (2025-02-27) - - -### Bug Fixes - -* [#2463](https://github.com/google/blockly-samples/issues/2463) update event handling for field-bitmap to support touch ([c105002](https://github.com/google/blockly-samples/commit/c1050025e41dd456c822301555b1b3a20577d03e)) - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.13...@blockly/field-bitmap@5.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.12...@blockly/field-bitmap@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.11...@blockly/field-bitmap@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.10...@blockly/field-bitmap@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.9...@blockly/field-bitmap@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.8...@blockly/field-bitmap@5.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.7...@blockly/field-bitmap@5.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.6...@blockly/field-bitmap@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.5...@blockly/field-bitmap@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.4...@blockly/field-bitmap@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.3...@blockly/field-bitmap@5.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.2...@blockly/field-bitmap@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.1...@blockly/field-bitmap@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@5.0.0...@blockly/field-bitmap@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) -* update pixel with new values ([#2373](https://github.com/google/blockly-samples/issues/2373)) ([d387b9e](https://github.com/google/blockly-samples/commit/d387b9ebcd0b42275231815fa18f61f61eeb04e4)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.1.1...@blockly/field-bitmap@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* remove some uses of generateFieldTextBlocks ([#2357](https://github.com/google/blockly-samples/issues/2357)) ([53b3fa4](https://github.com/google/blockly-samples/commit/53b3fa4604aabb1fc5240d41c8d1d389d4b15301)) - - - -## [4.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.1.0...@blockly/field-bitmap@4.1.1) (2024-05-20) - - -### Bug Fixes - -* improve bitmap field editor styles for large images and/or no buttons ([#2360](https://github.com/google/blockly-samples/issues/2360)) ([4cc25b3](https://github.com/google/blockly-samples/commit/4cc25b3a1374936fdc8eff56d14d3f9429c56504)) - - - -## [4.1.0](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.18...@blockly/field-bitmap@4.1.0) (2024-05-16) - - -### Features - -* Allow configuration of buttons, pixel colors, and fixed field height for Bitmap field ([#2351](https://github.com/google/blockly-samples/issues/2351)) ([432e277](https://github.com/google/blockly-samples/commit/432e277687bc0883806302164054f0a7b9ac3484)) - - - -## [4.0.18](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.17...@blockly/field-bitmap@4.0.18) (2024-05-09) - - -### Bug Fixes - -* Fix incorrect Blockly imports ([#2339](https://github.com/google/blockly-samples/issues/2339)) ([9af40b9](https://github.com/google/blockly-samples/commit/9af40b9ca075275af2b48cedcc1750d458084eb3)) - - - -## [4.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.16...@blockly/field-bitmap@4.0.17) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.15...@blockly/field-bitmap@4.0.16) (2024-04-18) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.14...@blockly/field-bitmap@4.0.15) (2024-04-04) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.13...@blockly/field-bitmap@4.0.14) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.12...@blockly/field-bitmap@4.0.13) (2024-02-29) - - -### Bug Fixes - -* Fix but preventing clearing/randomizing nonsquare bitmap fields. ([#2226](https://github.com/google/blockly-samples/issues/2226)) ([c32266b](https://github.com/google/blockly-samples/commit/c32266b2b7685c0d4d6646e5bcedb085c435e0b2)) - - - -## [4.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.11...@blockly/field-bitmap@4.0.12) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.10...@blockly/field-bitmap@4.0.11) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.9...@blockly/field-bitmap@4.0.10) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.8...@blockly/field-bitmap@4.0.9) (2023-11-16) - - -### Bug Fixes - -* resolved 15 ESLint warnings ([#2065](https://github.com/google/blockly-samples/issues/2065)) ([2436337](https://github.com/google/blockly-samples/commit/243633746542bb1518fe2893c0421a5a6f79fd32)) - - - -## [4.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.7...@blockly/field-bitmap@4.0.8) (2023-11-09) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.6...@blockly/field-bitmap@4.0.7) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.5...@blockly/field-bitmap@4.0.6) (2023-10-30) - - -### Bug Fixes - -* progress for Have field-bitmap fire intermediate change events ([#2012](https://github.com/google/blockly-samples/issues/2012)) ([7050875](https://github.com/google/blockly-samples/commit/7050875971ebb038702232c5bb642a0393592ab7)) - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.4...@blockly/field-bitmap@4.0.5) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.3...@blockly/field-bitmap@4.0.4) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.2...@blockly/field-bitmap@4.0.3) (2023-07-27) - - -### Bug Fixes - -* Use the normal, non-drag cursor when hovering over a bitmap field. ([#1810](https://github.com/google/blockly-samples/issues/1810)) ([a4f8e8d](https://github.com/google/blockly-samples/commit/a4f8e8d1c22e38fa00a27bbeaca3ef9f637cbe82)) - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.1...@blockly/field-bitmap@4.0.2) (2023-07-24) - - -### Bug Fixes - -* Fix the positioning of the dropdown div relative to the bitmap field. ([#1809](https://github.com/google/blockly-samples/issues/1809)) ([54a6ee6](https://github.com/google/blockly-samples/commit/54a6ee64ff03b6cb11e070d130a88d656aeced22)) - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@4.0.0...@blockly/field-bitmap@4.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@3.0.1...@blockly/field-bitmap@4.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@3.0.0...@blockly/field-bitmap@3.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.19...@blockly/field-bitmap@3.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [2.0.19](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.18...@blockly/field-bitmap@2.0.19) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.18](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.17...@blockly/field-bitmap@2.0.18) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.16...@blockly/field-bitmap@2.0.17) (2023-05-11) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.15...@blockly/field-bitmap@2.0.16) (2023-05-04) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.14...@blockly/field-bitmap@2.0.15) (2023-04-27) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.13...@blockly/field-bitmap@2.0.14) (2023-03-23) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.12...@blockly/field-bitmap@2.0.13) (2023-03-09) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.11...@blockly/field-bitmap@2.0.12) (2023-03-02) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.10...@blockly/field-bitmap@2.0.11) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [2.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.9...@blockly/field-bitmap@2.0.10) (2023-02-23) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.8...@blockly/field-bitmap@2.0.9) (2023-02-16) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.7...@blockly/field-bitmap@2.0.8) (2023-02-09) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.6...@blockly/field-bitmap@2.0.7) (2023-01-26) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.5...@blockly/field-bitmap@2.0.6) (2023-01-05) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.4...@blockly/field-bitmap@2.0.5) (2022-12-15) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.3...@blockly/field-bitmap@2.0.4) (2022-12-01) - - -### Bug Fixes - -* **field-bitmap:** Fix crash when dismissing FieldBitmap dropdown ([#1394](https://github.com/google/blockly-samples/issues/1394)) ([9a2ea9c](https://github.com/google/blockly-samples/commit/9a2ea9cfe43bd7d87b809c0b0dc8a807e958630d)), closes [#1386](https://github.com/google/blockly-samples/issues/1386) - - - -## [2.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.2...@blockly/field-bitmap@2.0.3) (2022-11-10) - - -### Bug Fixes - -* field-bitmap now serializing correctly ([#1361](https://github.com/google/blockly-samples/issues/1361)) ([304a875](https://github.com/google/blockly-samples/commit/304a875648bac4c7d78747a298dc8b2a1d28ba5b)) - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.1...@blockly/field-bitmap@2.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@2.0.0...@blockly/field-bitmap@2.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-bitmap@1.0.7...@blockly/field-bitmap@2.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 1.0.7 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 1.0.6 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 1.0.4 (2022-07-21) - -**Note:** Version bump only for package @blockly/field-bitmap - - - - - -## 1.0.3 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 1.0.2 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 1.0.1 (2022-06-21) - -**Note:** Version bump only for package @blockly/field-bitmap diff --git a/plugins/field-bitmap/README.md b/plugins/field-bitmap/README.md deleted file mode 100644 index 3b8cee4ef..000000000 --- a/plugins/field-bitmap/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# @blockly/field-bitmap [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) field that allows for user-inputted pixel grids. The image value is stored as a 2D array of 1s and 0s, and supports any size. The user can paint over pixels with their mouse, or randomize the grid. - -Note: this field does not support serialization to XML. - -## Installation - -### Yarn - -``` -yarn add @blockly/field-bitmap -``` - -### npm - -``` -npm install @blockly/field-bitmap --save -``` - -## Usage - -This field accepts up to 6 parameters: - -- `"value"` to specify an initial value. Must be a 2D rectangular array of 1s and 0s. - If not provided, the default is an empty grid of the specified size. -- `"width"` to specify an initial width, if there is no initial value. - If not provided, the default is a width of 5. -- `"height"` to specify an initial height, if there is no initial value. - If not provided, the default is a height of 5. -- `fieldHeight"` to specify a static field height. If provided, the individual pixels - will be resized to fit inside the field. This only affects the field as it is - seen on a block and not the pop-up editor. Good for larger images. (_Note: If this - results in fractional pixel sizes, the overall field height may not exactly match - the specified value on all browsers._) -- `"colours"` to override the default colours, Default values: - `{filled: '#363d80', empty: '#fff'}` -- `"buttons"` to show or hide the "Randomize" and/or "Clear" buttons. If either is - omitted, the button will be shown. Default values: - `{randomize: true, clear: true}` - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldBitmap} from 'blockly-field-bitmap'; -Blockly.Blocks["test_field_bitmap"] = { - init: function () { - this.appendDummyInput() - .appendField("bitmap: ") - .appendField(new FieldBitmap(...), "FIELDNAME"); - } -}; -``` - -### JSON - -Example with default value: - -```js -import * as Blockly from 'blockly'; -import '@blockly/field-bitmap'; -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_field_bitmap', - message0: 'bitmap: %1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - value: [ - [0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 0, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0], - [0, 1, 0, 0, 0, 1, 0], - [0, 0, 1, 1, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0], - ], - }, - ], - }, -]); -``` - -Example with width and height: - -```js -import * as Blockly from 'blockly'; -import '@blockly/field-bitmap'; -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_field_bitmap', - message0: 'bitmap: %1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - width: 8, - height: 8, - }, - ], - }, -]); -``` - -## License - -Apache 2.0 diff --git a/plugins/field-bitmap/package.json b/plugins/field-bitmap/package.json deleted file mode 100644 index f4c37cd28..000000000 --- a/plugins/field-bitmap/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@blockly/field-bitmap", - "version": "13.2.0", - "description": "A field that lets users input a pixel grid with their mouse.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "module": "./src/index.js", - "unpkg": "./dist/index.js", - "author": "", - "keywords": [ - "blockly", - "blockly-plugin", - "blockly-field", - "bitmap" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/field-bitmap#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "field-bitmap" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "mocha": "^11.7.6", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-bitmap/src/field-bitmap.ts b/plugins/field-bitmap/src/field-bitmap.ts deleted file mode 100644 index a39737977..000000000 --- a/plugins/field-bitmap/src/field-bitmap.ts +++ /dev/null @@ -1,1006 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from 'blockly/core'; - -export const DEFAULT_HEIGHT = 5; -export const DEFAULT_WIDTH = 5; -const DEFAULT_PIXEL_SIZE = 15; -const DEFAULT_PIXEL_COLOURS: PixelColours = { - empty: '#fff', - filled: '#363d80', -}; -const DEFAULT_BUTTONS: Buttons = { - randomize: true, - clear: true, -}; - -/** - * Field for inputting a small bitmap image. - * Includes a grid of clickable pixels that's exported as a bitmap. - */ -export class FieldBitmap extends Blockly.Field { - private initialValue: number[][] | null = null; - private imgHeight: number; - private imgWidth: number; - /** - * Array holding info needed to unbind events. - * Used for disposing. - */ - private boundEvents: Blockly.browserEvents.Data[] = []; - /** References to UI elements */ - private pixelGrid: HTMLDivElement | null = null; - private editorPixels: HTMLButtonElement[][] | null = null; - private blockDisplayPixels: SVGElement[][] | null = null; - /** Index of the keyboard-focused pixel in row-major order, or -1. */ - private focusedPixelIndex = -1; - /** Stateful variables */ - private pointerIsDown = false; - private valToPaintWith?: number; - buttonOptions: Buttons; - pixelSize: number; - pixelColours: {empty: string; filled: string}; - fieldHeight?: number; - - protected override ariaTypeName = Blockly.Msg['ARIA_TYPE_FIELD_BITMAP']; - - /** - * Constructor for the bitmap field. - * - * @param value 2D rectangular array of 1s and 0s. - * @param validator A function that is called to validate. - * @param config Config A map of options used to configure the field. - */ - constructor( - value: number[][] | typeof Blockly.Field.SKIP_SETUP, - validator?: Blockly.FieldValidator, - config?: FieldBitmapFromJsonConfig, - ) { - super(value, validator, config); - - this.SERIALIZABLE = true; - this.buttonOptions = {...DEFAULT_BUTTONS, ...config?.buttons}; - this.pixelColours = {...DEFAULT_PIXEL_COLOURS, ...config?.colours}; - - // Configure value, height, and width - const currentValue = this.getValue(); - if (currentValue !== null) { - this.imgHeight = currentValue.length; - this.imgWidth = currentValue[0].length || 0; - } else { - this.imgHeight = config?.height ?? DEFAULT_HEIGHT; - this.imgWidth = config?.width ?? DEFAULT_WIDTH; - // Set a default empty value - this.setValue(this.getEmptyArray()); - } - this.fieldHeight = config?.fieldHeight; - if (this.fieldHeight) { - this.pixelSize = this.fieldHeight / this.imgHeight; - } else { - this.pixelSize = DEFAULT_PIXEL_SIZE; - } - } - - /** - * Constructs a FieldBitmap from a JSON arg object. - * - * @param options A JSON object with options. - * @returns The new field instance. - */ - static fromJson(options: FieldBitmapFromJsonConfig) { - // `this` might be a subclass of FieldBitmap if that class doesn't override the static fromJson method. - return new this( - options.value ?? Blockly.Field.SKIP_SETUP, - undefined, - options, - ); - } - - /** - * Returns the width of the image in pixels. - * - * @returns The width in pixels. - */ - getImageWidth() { - return this.imgWidth; - } - - /** - * Returns the height of the image in pixels. - * - * @returns The height in pixels. - */ - getImageHeight() { - return this.imgHeight; - } - - /** - * Updates the ARIA roles and label for this field. - */ - override recomputeAriaContext(): boolean { - const shouldCustomize = super.recomputeAriaContext(); - if (!shouldCustomize) return false; - const focusableElement = this.getFocusableElement(); - Blockly.utils.aria.setState( - focusableElement, - Blockly.utils.aria.State.HASPOPUP, - 'grid', - ); - Blockly.utils.aria.setState( - focusableElement, - Blockly.utils.aria.State.EXPANDED, - !!this.pixelGrid, - ); - return true; - } - - /** - * Validates that a new value meets the requirements for a valid bitmap array. - * - * @param newValue The new value to be tested. - * @returns The new value if it's valid, or null. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue: number[][], - ): number[][] | null | undefined; - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue?: number[][], - ): number[][] | null; - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue?: number[][], - ): number[][] | null | undefined { - if (!newValue) { - return null; - } - // Check if the new value is an array - if (!Array.isArray(newValue)) { - return null; - } - const newHeight = newValue.length; - // The empty list is not an acceptable bitmap - if (newHeight == 0) { - return null; - } - - // Check that the width matches the existing width of the image if it - // already has a value. - const newWidth = newValue[0].length; - for (const row of newValue) { - if (!Array.isArray(row)) { - return null; - } - if (row.length !== newWidth) { - return null; - } - } - - // Check if all contents of the arrays are either 0 or 1 - for (const row of newValue) { - for (const cell of row) { - if (cell !== 0 && cell !== 1) { - return null; - } - } - } - return newValue; - } - - /** - * Called when a new value has been validated and is about to be set. - * - * @param newValue The value that's about to be set. - */ - // eslint-disable-next-line - protected override doValueUpdate_(newValue: number[][]) { - super.doValueUpdate_(newValue); - if (newValue) { - this.imgHeight = newValue.length; - this.imgWidth = newValue[0] ? newValue[0].length : 0; - // If the field height is static, adjust the pixel size to fit. - if (this.fieldHeight) { - this.pixelSize = this.fieldHeight / this.imgHeight; - } else { - this.pixelSize = DEFAULT_PIXEL_SIZE; - } - } - this.recomputeAriaContext(); - } - - /** - * Show the bitmap editor dialog. - * - * @param e Optional mouse event that triggered the field to open, or - * undefined if triggered programmatically. - */ - // eslint-disable-next-line - protected override showEditor_(e?: Event) { - const editor = this.dropdownCreate(); - Blockly.DropDownDiv.getContentDiv().appendChild(editor); - Blockly.DropDownDiv.showPositionedByField( - this, - this.dropdownDispose.bind(this), - ); - this.focusPixelAt(0); - this.recomputeAriaContext(); - } - - /** - * Updates the block display and editor dropdown when the field re-renders. - */ - // eslint-disable-next-line - protected override render_() { - super.render_(); - - if (!this.getValue()) { - return; - } - - if (this.blockDisplayPixels) { - const display = this.blockDisplayPixels; - this.forAllCells((r, c) => { - const pixel = this.getPixel(r, c); - display[r][c].style.fill = pixel - ? this.pixelColours.filled - : this.pixelColours.empty; - }); - } - if (this.editorPixels) { - this.forAllCells((r, c) => { - this.updateEditorPixelDisplay(r, c, this.getPixel(r, c)); - }); - } - } - - override getAriaValue(): string | null { - // Get a label for the bitmap's dimensions and the number of pixels that are on. - const value = this.getValue(); - if (!value) { - return null; - } - const height = value.length; - const width = value[0].length; - let onCount = 0; - for (const row of value) { - for (const cell of row) { - if (cell === 1) { - onCount++; - } - } - } - - return (Blockly.Msg['FIELD_BITMAP_ARIA_VALUE'] ?? '%1 by %2, %3 pixels on') - .replace('%1', String(width)) - .replace('%2', String(height)) - .replace('%3', String(onCount)); - } - - /** - * Determines whether the field is editable. - * - * @returns True since it is always editable. - */ - override updateEditable() { - const editable = super.updateEditable(); - // Blockly.Field's implementation sets these classes as appropriate, but - // since this field has no text they just mess up the rendering of the grid - // lines. - const svgRoot = this.getSvgRoot(); - if (svgRoot) { - Blockly.utils.dom.removeClass(svgRoot, 'blocklyNonEditableField'); - Blockly.utils.dom.removeClass(svgRoot, 'blocklyEditableField'); - } - return editable; - } - - /** - * Gets the rectangle built out of dimensions matching SVG's element. - * - * @returns The newly created rectangle of same size as the SVG element. - */ - override getScaledBBox() { - const boundingBox = this.getSvgRoot()?.getBoundingClientRect(); - if (!boundingBox) { - throw new Error('Tried to retrieve a bounding box without a rect'); - } - return new Blockly.utils.Rect( - boundingBox.top, - boundingBox.bottom, - boundingBox.left, - boundingBox.right, - ); - } - - /** - * Creates the bitmap editor and add event listeners. - * - * @returns The newly created dropdown menu. - */ - private dropdownCreate() { - const dropdownEditor = this.createElementWithClassname( - 'div', - 'dropdownEditor', - ); - if (this.buttonOptions.randomize || this.buttonOptions.clear) { - dropdownEditor.classList.add('has-buttons'); - } - - // This prevents the normal max-height from adding a scroll bar for large images. - Blockly.DropDownDiv.getContentDiv().classList.add('contains-bitmap-editor'); - - this.bindEvent(dropdownEditor, 'pointermove', this.onPointerMove); - this.bindEvent(dropdownEditor, 'pointerup', this.onPointerEnd); - this.bindEvent(dropdownEditor, 'pointerleave', this.onPointerEnd); - this.bindEvent(dropdownEditor, 'pointerdown', this.onPointerStart); - this.bindEvent(dropdownEditor, 'pointercancel', this.onPointerEnd); - // Stop the browser from handling touch events and cancelling the event. - this.bindEvent(dropdownEditor, 'touchmove', (e: Event) => { - e.preventDefault(); - }); - - const rtl = !!this.getSourceBlock()?.workspace.RTL; - this.pixelGrid = this.createPixelGrid(rtl); - dropdownEditor.appendChild(this.pixelGrid); - - // Add control buttons below the pixel grid - if (this.buttonOptions.randomize) { - this.addControlButton( - dropdownEditor, - // For backwards compatibility, use the old message if it exists, otherwise use the new message. - Blockly.Msg['BUTTON_LABEL_RANDOMIZE'] ?? - Blockly.Msg['FIELD_BITMAP_BUTTON_LABEL_RANDOMIZE'], - this.randomizePixels, - ); - } - if (this.buttonOptions.clear) { - this.addControlButton( - dropdownEditor, - // For backwards compatibility, use the old message if it exists, otherwise use the new message. - Blockly.Msg['BUTTON_LABEL_CLEAR'] ?? - Blockly.Msg['FIELD_BITMAP_BUTTON_LABEL_CLEAR'], - this.clearPixels, - ); - } - - // Store the initial value at the start of the edit. - this.initialValue = this.getValue(); - - return dropdownEditor; - } - - /** - * Builds the accessible pixel grid DOM. - * - * @param rtl Whether the workspace is RTL. - * @returns The grid root element. - */ - private createPixelGrid(rtl: boolean): HTMLDivElement { - const grid = document.createElement('div'); - grid.className = 'bitmapPixelGrid'; - grid.tabIndex = 0; - Blockly.utils.aria.setRole(grid, Blockly.utils.aria.Role.GRID); - grid.style.setProperty('--bitmap-columns', `${this.imgWidth}`); - - this.boundEvents.push( - Blockly.browserEvents.bind(grid, 'keydown', this, (e: KeyboardEvent) => { - this.onPixelGridKeyDown(e, rtl); - }), - ); - - this.editorPixels = []; - for (let r = 0; r < this.imgHeight; r++) { - const row = document.createElement('div'); - row.className = 'bitmapPixelRow'; - Blockly.utils.aria.setRole(row, Blockly.utils.aria.Role.ROW); - grid.appendChild(row); - - this.editorPixels.push([]); - for (let c = 0; c < this.imgWidth; c++) { - const cell = document.createElement('div'); - Blockly.utils.aria.setRole(cell, Blockly.utils.aria.Role.GRIDCELL); - - const button = document.createElement('button'); - button.type = 'button'; - button.id = Blockly.utils.idGenerator.getNextUniqueId(); - button.className = 'pixelButton'; - button.setAttribute('data-row', r.toString()); - button.setAttribute('data-col', c.toString()); - // Keyboard activation is handled on the grid; avoid a second toggle - // from the native button click after pointer paint. - button.addEventListener('click', (e) => e.preventDefault()); - - cell.appendChild(button); - row.appendChild(cell); - this.editorPixels[r].push(button); - this.updateEditorPixelDisplay(r, c, this.getPixel(r, c)); - } - } - return grid; - } - - /** - * Handles keyboard navigation and activation inside the pixel grid. - * - * @param e The keydown event. - * @param rtl Whether the workspace is RTL. - */ - private onPixelGridKeyDown(e: KeyboardEvent, rtl: boolean) { - if ( - !this.editorPixels || - e.shiftKey || - e.ctrlKey || - e.metaKey || - e.altKey - ) { - return; - } - - const length = this.imgWidth * this.imgHeight; - if (!length) return; - - if (this.focusedPixelIndex < 0) { - this.focusedPixelIndex = 0; - } - - switch (e.key) { - case 'ArrowUp': - case 'ArrowDown': - case 'ArrowLeft': - case 'ArrowRight': { - const next = this.getNextPixelIndex(this.focusedPixelIndex, e.key, rtl); - if (next === null) { - (this.getSourceBlock()?.workspace as Blockly.WorkspaceSvg | null) - ?.getAudioManager() - .playErrorBeep(); - e.preventDefault(); - e.stopPropagation(); - return; - } - this.focusPixelAt(next); - break; - } - case 'PageUp': - case 'Home': - this.focusPixelAt(0); - break; - case 'PageDown': - case 'End': - this.focusPixelAt(length - 1); - break; - case 'Enter': - case ' ': - case 'Space': { - const [r, c] = this.indexToCoords(this.focusedPixelIndex); - this.togglePixel(r, c); - e.preventDefault(); - e.stopPropagation(); - return; - } - default: - return; - } - e.preventDefault(); - e.stopPropagation(); - } - - /** - * Returns the next pixel index for an arrow key, or null at hard edges. - * - * @param current Current focused index. - * @param key Arrow key. - * @param rtl Whether the workspace is RTL. - * @returns Next index, or null if navigation should no-op. - */ - private getNextPixelIndex( - current: number, - key: string, - rtl: boolean, - ): number | null { - const col = current % this.imgWidth; - const row = Math.floor(current / this.imgWidth); - const length = this.imgWidth * this.imgHeight; - - let effectiveKey = key; - if (rtl) { - if (key === 'ArrowLeft') effectiveKey = 'ArrowRight'; - else if (key === 'ArrowRight') effectiveKey = 'ArrowLeft'; - } - - switch (effectiveKey) { - case 'ArrowLeft': - return col > 0 ? current - 1 : null; - case 'ArrowRight': - return col < this.imgWidth - 1 && current + 1 < length - ? current + 1 - : null; - case 'ArrowUp': - return row > 0 ? current - this.imgWidth : null; - case 'ArrowDown': - return current + this.imgWidth < length - ? current + this.imgWidth - : null; - default: - return null; - } - } - - /** - * Focuses the pixel button at the given row-major index. - * - * @param index Pixel index. - */ - private focusPixelAt(index: number) { - if (!this.editorPixels || !this.pixelGrid) return; - const length = this.imgWidth * this.imgHeight; - if (index < 0 || index >= length) return; - - this.focusedPixelIndex = index; - const [r, c] = this.indexToCoords(index); - const button = this.editorPixels[r][c]; - button.focus({preventScroll: true}); - Blockly.utils.aria.setState( - this.pixelGrid, - Blockly.utils.aria.State.ACTIVEDESCENDANT, - button.id, - ); - } - - /** - * Converts a pixel index to coordinates. - * - * @param index Pixel index. - * @returns Row and column. - */ - private indexToCoords(index: number): [number, number] { - return [Math.floor(index / this.imgWidth), index % this.imgWidth]; - } - - /** - * Builds an accessible label for a pixel cell. - * - * @param r Row index (0-based). - * @param c Column index (0-based). - * @param pixelValue Pixel value (0 or 1). - * @returns Localized aria label. - */ - private getPixelAriaLabel(r: number, c: number, pixelValue: number): string { - const state = pixelValue - ? (Blockly.Msg['FIELD_BITMAP_PIXEL_ON'] ?? 'on') - : (Blockly.Msg['FIELD_BITMAP_PIXEL_OFF'] ?? 'off'); - return (Blockly.Msg['FIELD_BITMAP_PIXEL_LABEL'] ?? '%1, row %2, column %3') - .replace('%1', state) - .replace('%2', String(r + 1)) - .replace('%3', String(c + 1)); - } - - /** - * Toggles a pixel and updates the editor presentation. - * - * @param r Row index. - * @param c Column index. - * @returns The new pixel value. - */ - private togglePixel(r: number, c: number): number { - const newPixelValue = 1 - this.getPixel(r, c); - this.setPixel(r, c, newPixelValue); - return newPixelValue; - } - - /** - * Syncs one editor pixel's colour, pressed state, and aria label. - * - * @param r Row index. - * @param c Column index. - * @param pixelValue Pixel value (0 or 1). - */ - private updateEditorPixelDisplay(r: number, c: number, pixelValue: number) { - const button = this.editorPixels?.[r]?.[c]; - if (!button) return; - button.style.background = pixelValue - ? this.pixelColours.filled - : this.pixelColours.empty; - button.setAttribute('aria-pressed', String(!!pixelValue)); - Blockly.utils.aria.setState( - button, - Blockly.utils.aria.State.LABEL, - this.getPixelAriaLabel(r, c, pixelValue), - ); - } - - /** - * Initializes the on-block display. - */ - override initView() { - this.createBorderRect_(); - // Invisible fill so the rect only provides keyboard-nav focus stroke. - this.getBorderRect().style.fill = 'none'; - // Don't intercept clicks meant for the pixel rects beneath. - this.getBorderRect().style.pointerEvents = 'none'; - if (this.fieldGroup_) { - Blockly.utils.dom.addClass(this.fieldGroup_, 'blocklyField'); - } - this.blockDisplayPixels = []; - for (let r = 0; r < this.imgHeight; r++) { - const row = []; - for (let c = 0; c < this.imgWidth; c++) { - const square = Blockly.utils.dom.createSvgElement( - 'rect', - { - x: c * this.pixelSize, - y: r * this.pixelSize, - width: this.pixelSize, - height: this.pixelSize, - fill: this.pixelColours.empty, - fill_opacity: 1, // eslint-disable-line - }, - this.getSvgRoot(), - ); - row.push(square); - } - this.blockDisplayPixels.push(row); - } - // SVG strokes are centered on the path; paint the border above the - // pixels so the inner half of the focus ring isn't covered. - this.getSvgRoot()?.appendChild(this.getBorderRect()); - this.recomputeAriaContext(); - } - - /** - * Updates the size of the block based on the size of the underlying image. - */ - // eslint-disable-next-line - protected override updateSize_() { - { - const newWidth = this.pixelSize * this.imgWidth; - const newHeight = this.pixelSize * this.imgHeight; - if (this.borderRect_) { - this.borderRect_.setAttribute('width', String(newWidth)); - this.borderRect_.setAttribute('height', String(newHeight)); - } - - this.size_.width = newWidth; - this.size_.height = newHeight; - } - } - - /** - * Create control button. - * - * @param parent Parent HTML element to which control button will be added. - * @param buttonText Text of the control button. - * @param onClick Callback that will be attached to the control button. - */ - private addControlButton( - parent: HTMLElement, - buttonText: string, - onClick: () => void, - ) { - const button = this.createElementWithClassname('button', 'controlButton'); - button.innerText = buttonText; - parent.appendChild(button); - this.bindEvent(button, 'click', onClick); - } - - /** - * Disposes of events belonging to the bitmap editor. - */ - private dropdownDispose() { - if ( - this.getSourceBlock() && - this.initialValue !== null && - this.initialValue !== this.getValue() - ) { - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( - this.sourceBlock_, - 'field', - this.name || null, - this.initialValue, - this.getValue(), - ), - ); - } - - for (const event of this.boundEvents) { - Blockly.browserEvents.unbind(event); - } - this.boundEvents.length = 0; - // Keep aria-expanded accurate on later recomputes. - this.pixelGrid = null; - this.editorPixels = null; - this.focusedPixelIndex = -1; - this.pointerIsDown = false; - this.valToPaintWith = undefined; - this.initialValue = null; - - Blockly.DropDownDiv.getContentDiv().classList.remove( - 'contains-bitmap-editor', - ); - this.recomputeAriaContext(); - } - - /** - * Constructs an array of zeros with the specified width and height. - * - * @returns The new value. - */ - private getEmptyArray(): number[][] { - const newVal: number[][] = []; - for (let r = 0; r < this.imgHeight; r++) { - newVal.push([]); - for (let c = 0; c < this.imgWidth; c++) { - newVal[r].push(0); - } - } - return newVal; - } - - /** - * Toggles the pixel under the pointer and starts a drag-paint gesture. - * - * @param e The down event. - */ - private onPointerStart(e: PointerEvent) { - if (e.button !== 0) return; - const pixelCoords = this.getPixelCoordsFromElement(e.target as Element); - if (pixelCoords) { - const newPixelValue = this.togglePixel(pixelCoords.r, pixelCoords.c); - this.pointerIsDown = true; - this.valToPaintWith = newPixelValue; - this.focusPixelAt(pixelCoords.r * this.imgWidth + pixelCoords.c); - // Keep receiving move/up outside the editor so drag-paint can continue - // (and pointerleave does not end the gesture). - (e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId); - e.preventDefault(); - } - } - - /** - * Moves focus (and paints when dragging) as the pointer moves over pixels. - * - * @param e The move event. - */ - private onPointerMove(e: PointerEvent) { - // Same guard as field-grid-dropdown: ignore moves with no pointer delta - // (e.g. content scrolled under a still pointer). - if (!(e.movementX || e.movementY)) { - return; - } - const currentElement = document.elementFromPoint(e.clientX, e.clientY); - const pixelCoords = this.getPixelCoordsFromElement(currentElement); - if (pixelCoords) { - this.focusPixelAt(pixelCoords.r * this.imgWidth + pixelCoords.c); - if (this.pointerIsDown) { - this.updatePixelValue(pixelCoords.r, pixelCoords.c); - } - } - if (this.pointerIsDown) { - e.preventDefault(); - } - } - - /** - * Reads row/column indices from a pixel button or a descendant. - * - * @param element Element under the pointer. - * @returns Row and column, or null if not a pixel. - */ - private getPixelCoordsFromElement( - element: Element | null, - ): {r: number; c: number} | null { - const pixelButton = element?.closest('.pixelButton'); - const rowIndex = pixelButton?.getAttribute('data-row'); - const colIndex = pixelButton?.getAttribute('data-col'); - if (rowIndex == null || colIndex == null) { - return null; - } - return {r: parseInt(rowIndex), c: parseInt(colIndex)}; - } - - /** - * Sets the specified pixel in the editor to the current value being painted. - * - * @param r Row number of grid. - * @param c Column number of grid. - */ - private updatePixelValue(r: number, c: number) { - if ( - this.valToPaintWith !== undefined && - this.getPixel(r, c) !== this.valToPaintWith - ) { - this.setPixel(r, c, this.valToPaintWith); - } - } - - /** - * Resets pointer state (e.g. After either a pointerup event or if the - * gesture is canceled). - * - * @param e The pointer event that ended the gesture, when available. - */ - private onPointerEnd(e?: PointerEvent) { - if ( - e && - e.currentTarget instanceof HTMLElement && - e.currentTarget.hasPointerCapture?.(e.pointerId) - ) { - e.currentTarget.releasePointerCapture(e.pointerId); - } - this.pointerIsDown = false; - this.valToPaintWith = undefined; - } - - /** - * Sets all the pixels in the image to a random value. - */ - private randomizePixels() { - const getRandBinary = () => Math.floor(Math.random() * 2); - this.forAllCells((r, c) => { - this.setPixel(r, c, getRandBinary()); - }); - } - - /** - * Sets all the pixels to 0. - */ - private clearPixels() { - const cleared = this.getEmptyArray(); - this.fireIntermediateChangeEvent(cleared); - this.setValue(cleared, false); - this.forAllCells((r, c) => { - this.updateEditorPixelDisplay(r, c, 0); - }); - } - - /** - * Sets the value of a particular pixel. - * - * @param r Row number of grid. - * @param c Column number of grid. - * @param newValue Value of the pixel. - */ - private setPixel(r: number, c: number, newValue: number) { - const newGrid = JSON.parse(JSON.stringify(this.getValue())); - newGrid[r][c] = newValue; - this.fireIntermediateChangeEvent(newGrid); - this.setValue(newGrid, false); - this.updateEditorPixelDisplay(r, c, newValue); - } - - private getPixel(row: number, column: number): number { - const value = this.getValue(); - if (!value) { - throw new Error( - 'Attempted to retrieve a pixel value when no value is set', - ); - } - - return value[row][column]; - } - - /** - * Calls a given function for all cells in the image, with the cell - * coordinates as the arguments. - * - * @param func A function to be applied. - */ - private forAllCells(func: (row: number, col: number) => void) { - for (let r = 0; r < this.imgHeight; r++) { - for (let c = 0; c < this.imgWidth; c++) { - func(r, c); - } - } - } - - /** - * Creates a new element with the specified type and class. - * - * @param elementType Type of html element. - * @param className ClassName of html element. - * @returns The created element. - */ - private createElementWithClassname(elementType: string, className: string) { - const newElt = document.createElement(elementType); - newElt.className = className; - return newElt; - } - - /** - * Binds an event listener to the specified element. - * - * @param element Specified element. - * @param eventName Name of the event to bind. - * @param callback Function to be called on specified event. - */ - private bindEvent( - element: HTMLElement, - eventName: string, - callback: (e: PointerEvent) => void, - ) { - this.boundEvents.push( - Blockly.browserEvents.bind(element, eventName, this, callback), - ); - } - - private fireIntermediateChangeEvent(newValue: number[][]) { - if (this.getSourceBlock()) { - Blockly.Events.fire( - new (Blockly.Events.get( - Blockly.Events.BLOCK_FIELD_INTERMEDIATE_CHANGE, - ))(this.getSourceBlock(), this.name || null, this.getValue(), newValue), - ); - } - } -} - -interface Buttons { - readonly randomize: boolean; - readonly clear: boolean; -} -interface PixelColours { - readonly empty: string; - readonly filled: string; -} - -export interface FieldBitmapFromJsonConfig extends Blockly.FieldConfig { - value?: number[][]; - width?: number; - height?: number; - buttons?: Buttons; - fieldHeight?: number; - colours?: PixelColours; -} - -Blockly.fieldRegistry.register('field_bitmap', FieldBitmap); - -/** - * CSS for bitmap field. - */ -Blockly.Css.register(` -.dropdownEditor { - align-items: center; - flex-direction: column; - display: flex; - justify-content: center; -} -.dropdownEditor.has-buttons { - margin-bottom: 20px; -} -.bitmapPixelGrid { - display: grid; - margin: 20px; - grid-template-columns: repeat(var(--bitmap-columns), min-content); -} -.bitmapPixelRow { - display: contents; -} -.bitmapPixelGrid [role="gridcell"] { - padding: 0; - margin: 0; - line-height: 0; -} -.pixelButton { - width: ${DEFAULT_PIXEL_SIZE}px; - height: ${DEFAULT_PIXEL_SIZE}px; - border: 1px solid #000; - cursor: pointer; -} -.pixelButton:focus { - outline: var(--blockly-selection-width) solid var(--blockly-active-node-color); - outline-offset: -2px; - box-shadow: none; - position: relative; - z-index: 1; -} -.controlButton { - margin: 5px 0; -} -.blocklyDropDownContent.contains-bitmap-editor { - max-height: none; -} -`); diff --git a/plugins/field-bitmap/src/index.ts b/plugins/field-bitmap/src/index.ts deleted file mode 100644 index 1e196ea9b..000000000 --- a/plugins/field-bitmap/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './field-bitmap'; diff --git a/plugins/field-bitmap/test/field_test.mocha.js b/plugins/field-bitmap/test/field_test.mocha.js deleted file mode 100644 index d809bb21b..000000000 --- a/plugins/field-bitmap/test/field_test.mocha.js +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {testHelpers} = require('@blockly/dev-tools'); -const {assert} = require('chai'); -const {FieldBitmap, DEFAULT_HEIGHT, DEFAULT_WIDTH} = require('../src/index'); - -/** - * Helper method to reformat raw test cases to a format that the - * various tests can use. - * @param {!Array} testCases raw testcases that - * need to be reformatted - * @returns {!Array} the reformatted test cases - * that can be used by various tests - */ -function processTestCases(testCases) { - return testCases.map((x) => ({ - title: x.title, - value: x.value, - args: [x.value, null, {}], - json: {value: x.value}, - })); -} - -const { - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, -} = testHelpers; - -suite('FieldBitmap', function () { - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = processTestCases([ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - {title: 'NaN', value: NaN}, - {title: 'Non-Parsable String', value: 'bad'}, - {title: 'Not an array', value: 1}, - {title: 'Not a 2D array', value: [0, 1, 0, 1]}, - { - title: 'Not a rectangle', - value: [ - [1, 1, 1], - [1, 1, 1, 1, 1, 1], - [1, 1, 1], - ], - }, - { - title: 'Contains non-binary number', - value: [ - [1, 99, 1], - [1, 1, 1], - [1, 1, 1], - ], - }, - { - title: 'Contains bad value', - value: [ - [1, 'b', 1], - [1, 1, 1], - [1, 1, 1], - ], - }, - ]); - - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = processTestCases([ - { - title: '3x3 solid', - value: [ - [1, 1, 1], - [1, 1, 1], - [1, 1, 1], - ], - }, - { - title: '4x4 solid', - value: [ - [1, 1, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1], - [1, 1, 1, 1], - ], - }, - { - title: '3x3 checkerboard', - value: [ - [1, 0, 1], - [0, 1, 0], - [1, 0, 1], - ], - }, - { - title: '4x4 empty', - value: [ - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0], - ], - }, - ]); - - /** - * The expected default value for the field being tested. - * @type {*} - */ - const defaultFieldValue = [ - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - ]; - /** - * Asserts that the field property values are set to default. - * @param {FieldBitmap} field The field to check. - */ - const assertFieldDefault = function (field) { - assert.deepEqual(field.getValue(), defaultFieldValue); - }; - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldBitmap} field The field to check. - * @param {FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - const expectedValue = testCase.value; - assert.deepEqual(field.getValue(), expectedValue); - assert.equal(field.getImageHeight(), expectedValue.length); - assert.equal(field.getImageWidth(), expectedValue[0].length); - }; - - /** - * Reimplementation of the function from TestHelpers that supports array - * equality testing. - * @param {*} validValueTestCases test cases for valid field values - * @param {*} invalidValueTestCases test cases for invalid field values - */ - function runSetValueTests(validValueTestCases, invalidValueTestCases) { - const createFieldForTestCase = (testCase) => - FieldBitmap.fromJson(`{ - width: ${ - Array.isArray(testCase.value) ? testCase.value.length : DEFAULT_WIDTH - }, - height:${ - testCase.value && Array.isArray(testCase.value[0]) - ? testCase.value[0].length - : DEFAULT_HEIGHT - }, - }`); - - /** - * Creates test callback for invalid setValue test. - * @param {!FieldValueTestCase} testCase The test case information. - * @returns {!Function} The test callback. - */ - const createInvalidSetValueTestCallback = (testCase) => { - return function () { - const field = createFieldForTestCase(testCase); - field.setValue(testCase.value); - assertFieldDefault(field); - }; - }; - /** - * Creates test callback for valid setValue test. - * @param {!FieldValueTestCase} testCase The test case information. - * @returns {!Function} The test callback. - */ - const createValidSetValueTestCallback = (testCase) => { - return function () { - const field = createFieldForTestCase(testCase); - field.setValue(testCase.value); - validTestCaseAssertField(field, testCase); - }; - }; - - testHelpers.runTestCases( - invalidValueTestCases, - createInvalidSetValueTestCallback, - ); - testHelpers.runTestCases( - validValueTestCases, - createValidSetValueTestCallback, - ); - } - - runConstructorSuiteTests( - FieldBitmap, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runFromJsonSuiteTests( - FieldBitmap, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runSetValueTests(validValueTestCases, invalidValueTestCases); -}); diff --git a/plugins/field-bitmap/test/index.html b/plugins/field-bitmap/test/index.html deleted file mode 100644 index 10cd0a0c1..000000000 --- a/plugins/field-bitmap/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Test - - - - -
    - - - diff --git a/plugins/field-bitmap/test/index.js b/plugins/field-bitmap/test/index.js deleted file mode 100644 index 8eef0a91a..000000000 --- a/plugins/field-bitmap/test/index.js +++ /dev/null @@ -1,336 +0,0 @@ -/** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Field test. - */ - -import '../src/field-bitmap'; - -import {createPlayground} from '@blockly/dev-tools'; -import * as Blockly from 'blockly'; - -/** - * An array of blocks that are defined only for the purposes of - * manually and visually testing the bitmap field. - */ -const testBlockDefinitions = [ - { - type: 'test_standard_field_values', - message0: '%1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_bitmap`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values', - message0: '%1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - value: [ - [1, 0, 1], - [0, 1, 0], - [0, 0, 0], - ], - width: 3, - height: 3, - alt: { - type: 'field_label', - text: `No field_bitmap`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_standard_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_bitmap`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - value: [ - [1, 0, 1], - [0, 1, 0], - [0, 0, 0], - ], - width: 3, - height: 3, - alt: { - type: 'field_label', - text: `No field_bitmap`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_colours_no_buttons', - message0: '%1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - value: [ - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], - [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - ], - fieldHeight: 50, - buttons: { - randomize: false, - clear: false, - }, - colours: { - filled: '#4888f4', - empty: '#cad2dc', - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_colours_no_buttons_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_bitmap', - name: 'FIELDNAME', - value: [ - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], - [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - ], - fieldHeight: 50, - buttons: { - randomize: false, - clear: false, - }, - colours: { - filled: '#4888f4', - empty: '#cad2dc', - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_parent_block', - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }, -]; - -Blockly.defineBlocksWithJsonArray(testBlockDefinitions); - -/** - * A test toolbox containing the exported blocks and a variety of - * test blocks to exercise the bitmap field in different contexts - * (on a shadow block, as the only field on a block, etc). - * These are in a simple toolbox, rather than a category toolbox, so that - * they are all instantiated every time the test page is opened. - */ -const jsonToolbox = { - contents: [ - { - kind: 'label', - text: 'Test blocks: default field values', - }, - { - kind: 'block', - type: 'test_standard_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_standard_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: custom field values', - }, - { - kind: 'block', - type: 'test_custom_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: Static field height, custom colours, no buttons', - }, - { - kind: 'block', - type: 'test_custom_colours_no_buttons', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_colours_no_buttons', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_colours_no_buttons_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_colours_no_buttons_and_label', - }, - }, - }, - }, - ], -}; - -/** - * Create a workspace. - * @param {HTMLElement} blocklyDiv The blockly container div. - * @param {!Blockly.BlocklyOptions} options The Blockly options. - * @returns {!Blockly.WorkspaceSvg} The created workspace. - */ -function createWorkspace(blocklyDiv, options) { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions = { - toolbox: jsonToolbox, - }; - createPlayground( - document.getElementById('root'), - createWorkspace, - defaultOptions, - ); -}); diff --git a/plugins/field-bitmap/tsconfig.json b/plugins/field-bitmap/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/field-bitmap/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-colour-hsv-sliders/CHANGELOG.md b/plugins/field-colour-hsv-sliders/CHANGELOG.md deleted file mode 100644 index 4786911b3..000000000 --- a/plugins/field-colour-hsv-sliders/CHANGELOG.md +++ /dev/null @@ -1,680 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -### Bug Fixes - -* Improve accessibility of colour slider plugin ([#2745](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2745)) - - -## [6.0.12](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.11...@blockly/field-colour-hsv-sliders@6.0.12) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.11](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.10...@blockly/field-colour-hsv-sliders@6.0.11) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.10](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.9...@blockly/field-colour-hsv-sliders@6.0.10) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.8...@blockly/field-colour-hsv-sliders@6.0.9) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.7...@blockly/field-colour-hsv-sliders@6.0.8) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.6...@blockly/field-colour-hsv-sliders@6.0.7) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.5...@blockly/field-colour-hsv-sliders@6.0.6) (2025-10-30) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.4...@blockly/field-colour-hsv-sliders@6.0.5) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.3...@blockly/field-colour-hsv-sliders@6.0.4) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.2...@blockly/field-colour-hsv-sliders@6.0.3) (2025-07-03) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.1...@blockly/field-colour-hsv-sliders@6.0.2) (2025-06-19) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@6.0.0...@blockly/field-colour-hsv-sliders@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.19...@blockly/field-colour-hsv-sliders@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.19](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.18...@blockly/field-colour-hsv-sliders@5.0.19) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.18](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.17...@blockly/field-colour-hsv-sliders@5.0.18) (2025-05-15) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.16...@blockly/field-colour-hsv-sliders@5.0.17) (2025-05-08) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.15...@blockly/field-colour-hsv-sliders@5.0.16) (2025-03-27) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.14...@blockly/field-colour-hsv-sliders@5.0.15) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.13...@blockly/field-colour-hsv-sliders@5.0.14) (2025-01-23) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.12...@blockly/field-colour-hsv-sliders@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.11...@blockly/field-colour-hsv-sliders@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.10...@blockly/field-colour-hsv-sliders@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.9...@blockly/field-colour-hsv-sliders@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.8...@blockly/field-colour-hsv-sliders@5.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.7...@blockly/field-colour-hsv-sliders@5.0.8) (2024-08-22) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.6...@blockly/field-colour-hsv-sliders@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.5...@blockly/field-colour-hsv-sliders@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.4...@blockly/field-colour-hsv-sliders@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.3...@blockly/field-colour-hsv-sliders@5.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.2...@blockly/field-colour-hsv-sliders@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.1...@blockly/field-colour-hsv-sliders@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@5.0.0...@blockly/field-colour-hsv-sliders@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.7...@blockly/field-colour-hsv-sliders@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* remove some uses of generateFieldTextBlocks ([#2357](https://github.com/google/blockly-samples/issues/2357)) ([53b3fa4](https://github.com/google/blockly-samples/commit/53b3fa4604aabb1fc5240d41c8d1d389d4b15301)) - - - -## [4.2.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.6...@blockly/field-colour-hsv-sliders@4.2.7) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.5...@blockly/field-colour-hsv-sliders@4.2.6) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.4...@blockly/field-colour-hsv-sliders@4.2.5) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.3...@blockly/field-colour-hsv-sliders@4.2.4) (2024-04-11) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.2...@blockly/field-colour-hsv-sliders@4.2.3) (2024-04-04) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.1...@blockly/field-colour-hsv-sliders@4.2.2) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.2.0...@blockly/field-colour-hsv-sliders@4.2.1) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.2.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.9...@blockly/field-colour-hsv-sliders@4.2.0) (2024-02-01) - - -### Features - -* Use intermediate change events for HSV sliders. ([#2173](https://github.com/google/blockly-samples/issues/2173)) ([ed56b79](https://github.com/google/blockly-samples/commit/ed56b79be5507790572000f028a49d7bf317896d)) - - - -## [4.1.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.8...@blockly/field-colour-hsv-sliders@4.1.9) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.7...@blockly/field-colour-hsv-sliders@4.1.8) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.6...@blockly/field-colour-hsv-sliders@4.1.7) (2023-11-09) - - -### Bug Fixes - -* add types for filed-colour-hsv-sliders ([#2063](https://github.com/google/blockly-samples/issues/2063)) ([e630704](https://github.com/google/blockly-samples/commit/e6307043f812624e00207084815554c5cebe4dc9)) - - - -## [4.1.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.5...@blockly/field-colour-hsv-sliders@4.1.6) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.4...@blockly/field-colour-hsv-sliders@4.1.5) (2023-10-30) - - -### Bug Fixes - -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [4.1.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.3...@blockly/field-colour-hsv-sliders@4.1.4) (2023-09-21) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.2...@blockly/field-colour-hsv-sliders@4.1.3) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.1...@blockly/field-colour-hsv-sliders@4.1.2) (2023-08-31) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.1.0...@blockly/field-colour-hsv-sliders@4.1.1) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.1.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.0.2...@blockly/field-colour-hsv-sliders@4.1.0) (2023-08-03) - - -### Features - -* Update the field-colour-hsv-sliders package to use the field-colour package. ([#1830](https://github.com/google/blockly-samples/issues/1830)) ([e756bf4](https://github.com/google/blockly-samples/commit/e756bf488c5cf094e6fd236b70482b6bc23cae4f)) - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.0.1...@blockly/field-colour-hsv-sliders@4.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@4.0.0...@blockly/field-colour-hsv-sliders@4.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@3.0.1...@blockly/field-colour-hsv-sliders@4.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@3.0.0...@blockly/field-colour-hsv-sliders@3.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.1.5...@blockly/field-colour-hsv-sliders@3.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - -### Bug Fixes - -* renaming build problems ([7087469](https://github.com/google/blockly-samples/commit/7087469ccdaf27e040cd67a386c9284aa6b1cd67)) -* update all usages of generators in script tags for blockly v10 ([#1734](https://github.com/google/blockly-samples/issues/1734)) ([19faf29](https://github.com/google/blockly-samples/commit/19faf29428e3903a60da7c2679818cf8c63b7309)) - - - -## [2.1.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.1.4...@blockly/field-colour-hsv-sliders@2.1.5) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.1.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.1.3...@blockly/field-colour-hsv-sliders@2.1.4) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.1.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.1.2...@blockly/field-colour-hsv-sliders@2.1.3) (2023-05-11) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.1.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.1.1...@blockly/field-colour-hsv-sliders@2.1.2) (2023-05-04) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.1.0...@blockly/field-colour-hsv-sliders@2.1.1) (2023-04-27) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.1.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.12...@blockly/field-colour-hsv-sliders@2.1.0) (2023-03-23) - - -### Features - -* Create plugin for dependent dropdown fields. ([#1555](https://github.com/google/blockly-samples/issues/1555)) ([1c473d6](https://github.com/google/blockly-samples/commit/1c473d6b2c4aa3754cf332c07585af60342537ef)) - - - -## [2.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.11...@blockly/field-colour-hsv-sliders@2.0.12) (2023-03-09) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.10...@blockly/field-colour-hsv-sliders@2.0.11) (2023-03-02) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.9...@blockly/field-colour-hsv-sliders@2.0.10) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [2.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.8...@blockly/field-colour-hsv-sliders@2.0.9) (2023-02-23) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.7...@blockly/field-colour-hsv-sliders@2.0.8) (2023-02-16) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.6...@blockly/field-colour-hsv-sliders@2.0.7) (2023-02-09) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.5...@blockly/field-colour-hsv-sliders@2.0.6) (2023-01-26) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.4...@blockly/field-colour-hsv-sliders@2.0.5) (2023-01-12) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.3...@blockly/field-colour-hsv-sliders@2.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.2...@blockly/field-colour-hsv-sliders@2.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/field-colour-hsv-sliders - - - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.1...@blockly/field-colour-hsv-sliders@2.0.2) (2022-10-27) - - -### Bug Fixes - -* disable eye dropper instead of using fallback ([#1337](https://github.com/google/blockly-samples/issues/1337)) ([7fb03d9](https://github.com/google/blockly-samples/commit/7fb03d94346ada497d0822df00364c38ea9bd4ff)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@2.0.0...@blockly/field-colour-hsv-sliders@2.0.1) (2022-10-13) - - -### Bug Fixes - -* Reverting invalid changes to hsv slider css. ([#1329](https://github.com/google/blockly-samples/issues/1329)) ([925858d](https://github.com/google/blockly-samples/commit/925858dd1ab7befcf051bf64d045dc71ea4ed997)) - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour-hsv-sliders@1.1.0...@blockly/field-colour-hsv-sliders@2.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* Added css documentation for workspace search plugin. ([#1282](https://github.com/google/blockly-samples/issues/1282)) ([5dd7d2d](https://github.com/google/blockly-samples/commit/5dd7d2d2bed3d1e4920e27b795a06fff08e85297)) -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -# 1.1.0 (2022-09-08) - - -### Features - -* created plugin for colour hsv sliders field. ([#1234](https://github.com/google/blockly-samples/issues/1234)) ([d46f28e](https://github.com/google/blockly-samples/commit/d46f28e50200eb060d75171077262c071481580d)) diff --git a/plugins/field-colour-hsv-sliders/README.md b/plugins/field-colour-hsv-sliders/README.md deleted file mode 100644 index 0c4c589e6..000000000 --- a/plugins/field-colour-hsv-sliders/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# @blockly/field-colour-hsv-sliders [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) colour field using HSV sliders for editing. - -![A Blockly workspace showing the HSV sliders.](readme-media/hsv_sliders_screenshot.png) - -## Installation - -### Yarn - -``` -yarn add @blockly/field-colour-hsv-sliders -``` - -### npm - -``` -npm install @blockly/field-colour-hsv-sliders --save -``` - -## Usage - -This plugin adds a field type `FieldColourHsvSliders` that is registered to the name `'field_colour_hsv_sliders'`. This field is an extension of the `Blockly.FieldColour` field and outputs values in the same hexadecimal string format `'#rrggbb'` even though the UI represents the colour in the HSV colour space. See the [Blockly.FieldColour documentation](https://www.npmjs.com/package/@blockly/field-colour#creation) on what parameters and configurations this field supports, although unlike `Blockly.FieldColour`, this field does not use colour swatches and thus ignores options related to the swatches such as `'colourOptions'`. - -The UI also provides an eye dropper button that can be used to take a colour from anywhere on the screen [on supported platforms](https://caniuse.com/?search=eyedropper). Chrome, Edge, and Opera support the eye dropper feature, except [on Chromebooks](https://bugs.chromium.org/p/chromium/issues/detail?id=1348921) and on mobile devices. There is also [a known bug in Chrome on some versions of Linux](https://bugs.chromium.org/p/chromium/issues/detail?id=1227633) where the eye dropper may be visible but does not work correctly. - -To use it, you'll need to add this field to a block type definition, and add that block to your toolbox. See below for an example of defining a block type that uses this field. - -### JSON - -```js -import * as Blockly from 'blockly'; -import '@blockly/field-colour-hsv-sliders'; -import {javascriptGenerator, Order} from 'blockly/javascript'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'colour_hsv_sliders', - message0: 'hsv %1', - args0: [ - { - type: 'field_colour_hsv_sliders', - name: 'COLOUR', - colour: '#ff0000', - }, - ], - output: 'Colour', - style: 'colour_blocks', - }, -]); - -javascriptGenerator.forBlock['colour_hsv_sliders'] = function ( - block, - generator, -) { - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, Order.ATOMIC]; -}; -``` - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldColourHsvSliders} from '@blockly/field-colour-hsv-sliders'; -import {javascriptGenerator, Order} from 'blockly/javascript'; - -Blockly.Blocks['colour_hsv_sliders'] = { - init: function () { - this.appendDummyInput() - .appendField('hsv ') - .appendField(new FieldColourHsvSliders('#ff0000'), 'COLOUR'); - this.setOutput(true, 'Colour'); - this.setStyle('colour_blocks'); - }, -}; -javascriptGenerator.forBlock['colour_hsv_sliders'] = function ( - block, - generator, -) { - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, Order.ATOMIC]; -}; -``` - -## License - -Apache 2.0 diff --git a/plugins/field-colour-hsv-sliders/package.json b/plugins/field-colour-hsv-sliders/package.json deleted file mode 100644 index 9d89b83db..000000000 --- a/plugins/field-colour-hsv-sliders/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "@blockly/field-colour-hsv-sliders", - "version": "13.2.0", - "description": "A Blockly colour field using HSV sliders.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "colour", - "field", - "hsv", - "slider" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-colour-hsv-sliders#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-colour-hsv-sliders" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "dependencies": { - "@blockly/field-colour": "^6.0.12" - }, - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "jsdom": "^29.1.1", - "jsdom-global": "^3.0.2", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-colour-hsv-sliders/readme-media/hsv_sliders_screenshot.png b/plugins/field-colour-hsv-sliders/readme-media/hsv_sliders_screenshot.png deleted file mode 100644 index 409e5c6b80bed2ff35ae6458d11ab05e962ca7fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59431 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 diff --git a/plugins/field-colour-hsv-sliders/src/field_colour_hsv_sliders.ts b/plugins/field-colour-hsv-sliders/src/field_colour_hsv_sliders.ts deleted file mode 100644 index 2d6b8195f..000000000 --- a/plugins/field-colour-hsv-sliders/src/field_colour_hsv_sliders.ts +++ /dev/null @@ -1,864 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Colour input field with HSV sliders. - */ - -import * as Blockly from 'blockly/core'; -import {FieldColour} from '@blockly/field-colour'; - -// Experimental API: https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper -declare interface EyeDropper { - open: () => Promise<{sRGBHex: string}>; -} -declare global { - interface Window { - EyeDropper?: {new (): EyeDropper}; - } -} - -/** - * A structure with three properties r, g, and b, representing the amount of - * red, green, and blue light in the sRGB colour space where 1 is the maximum - * amount of light that can be displayed. - */ -class RgbColour { - /** The red component of the colour, ranging from 0 to 1. */ - r: number; - - /** The green component of the colour, ranging from 0 to 1. */ - g: number; - - /** The blue component of the colour, ranging from 0 to 1. */ - b: number; - - /** - * The RgbColour constructor. - * - * @param r The initial amount of red. Defaults to 0. - * @param g The initial amount of green. Defaults to 0. - * @param b The initial amount of blue. Defaults to 0. - */ - constructor(r = 0, g = 0, b = 0) { - this.r = r; - this.g = g; - this.b = b; - } - - /** - * Given a number from 0 to 1, returns a two-digit hexadecimal string from - * '00' to 'ff'. - * - * @param x The amount of light in a component from 0 to 1. - * @returns A hexadecimal representation from '00' to 'ff'. - */ - static componentToHex(x: number): string { - if (x <= 0) return '00'; - if (x >= 1) return 'ff'; - return ('0' + ((x * 255 + 0.5) >>> 0).toString(16)).slice(-2); - } - - /** - * Returns a hexadecimal string in the format #rrggbb representing the colour. - * - * @returns A hexadecimal representation of this colour. - */ - toHex(): string { - return ( - '#' + - RgbColour.componentToHex(this.r) + - RgbColour.componentToHex(this.g) + - RgbColour.componentToHex(this.b) - ); - } - - /** - * Updates the properties of this instance to represent the same colour as the - * provided string in the hexadecimal format #rrggbb. - * - * @param hex A hexadecimal string in the format '#rrggbb'. - * @returns This instance after updating it. - */ - loadFromHex(hex: string): RgbColour { - this.r = parseInt(hex.slice(1, 3), 16) / 255; - this.g = parseInt(hex.slice(3, 5), 16) / 255; - this.b = parseInt(hex.slice(5, 7), 16) / 255; - return this; - } - - /** - * Updates the properties of this instance to represent the same colour as the - * provided HsvColour but in the sRGB colour space. - * - * @param hsv An HSV representation of a colour to copy. - * @returns This instance after updating it. - */ - loadFromHsv(hsv: HsvColour): RgbColour { - const hue: number = (hsv.h - Math.floor(hsv.h)) * 6; - this.r = - hsv.v * (1 - hsv.s * Math.max(0, Math.min(1, 2 - Math.abs(hue - 3)))); - this.g = - hsv.v * (1 - hsv.s * Math.max(0, Math.min(1, Math.abs(hue - 2) - 1))); - this.b = - hsv.v * (1 - hsv.s * Math.max(0, Math.min(1, Math.abs(hue - 4) - 1))); - return this; - } -} - -/** - * A structure with three properties h, s, and v, representing the hue, - * saturation, and brightness in a colour. All three properties range from 0 - * to 1. - */ -class HsvColour { - /** The hue of the colour, ranging from 0 to 1. */ - h: number; - - /** The saturation of the colour, ranging from 0 to 1. */ - s: number; - - /** The brightness of the colour, ranging from 0 to 1. */ - v: number; - - /** - * The HsvColour constructor. - * - * @param h The initial hue of the colour. Defaults to 0. - * @param s The initial amount of saturation. Defaults to 0. - * @param v The initial amount of brightness. Defaults to 0. - */ - constructor(h = 0, s = 0, v = 0) { - this.h = h; - this.s = s; - this.v = v; - } - - /** - * Updates the properties of this instance to represent the same colour as the - * provided RgbColour but in the HSV colour space. - * - * @param rgb An RGB representation of a colour to copy. - * @returns This instance after updating it. - */ - loadFromRgb(rgb: RgbColour): HsvColour { - const max: number = Math.max(Math.max(rgb.r, rgb.g), rgb.b); - const min: number = Math.min(Math.min(rgb.r, rgb.g), rgb.b); - this.v = max; - if (min === max) { - this.h = 0; - this.s = 0; - return this; - } - - const delta: number = max - min; - this.s = delta / max; - - let hue: number; - if (rgb.r === max) { - hue = (rgb.g - rgb.b) / delta; - } else if (rgb.g === max) { - hue = 2 + (rgb.b - rgb.r) / delta; - } else { - hue = 4 + (rgb.r - rgb.g) / delta; - } - hue /= 6; - this.h = hue - Math.floor(hue); - return this; - } - - /** - * Updates the properties of this instance to copy the provided HsvColour. - * - * @param other An HSV representation of a colour to copy. - * @returns This instance after updating it. - */ - copy(other: HsvColour): HsvColour { - this.h = other.h; - this.s = other.s; - this.v = other.v; - return this; - } -} - -/** - * Class for a colour input field that displays HSV slider widgets when clicked. - */ -export class FieldColourHsvSliders extends FieldColour { - /** The maximum value of the hue slider range. */ - private static readonly HUE_SLIDER_MAX = 360; - - /** The maximum value of the saturation slider range. */ - private static readonly SATURATION_SLIDER_MAX = 100; - - /** The maximum value of the brightness slider range. */ - private static readonly BRIGHTNESS_SLIDER_MAX = 100; - - /** - * The gradient control point positions should align with the center of the - * slider thumb when the corresponding colour is selected. When the slider - * is at the minimum or maximum value, the distance of center of the thumb - * from the edge of the track will be the thumb's radius, so that's how far - * the minimum and maximum control points should be. - */ - static readonly THUMB_RADIUS = 12; - - /** Helper colour structures to allow manipulation in the HSV colour space. */ - private static readonly helperHsv: HsvColour = new HsvColour(); - - /** Helper colour structures to support conversion to the RGB colour space. */ - private static readonly helperRgb: RgbColour = new RgbColour(); - - /** - * The intial value of the field when the user opened an editor to change its - * value. When the editor is disposed, an event will be fired that uses this - * as the event's oldValue. - */ - protected valueWhenEditorWasOpened: string | null = null; - - /** Array holding info needed to unbind events. Used for disposing. */ - private hsvBoundEvents: Blockly.browserEvents.Data[] = []; - - /** HTML span element to display the current hue. */ - private hueReadout: HTMLSpanElement | null = null; - - /** HTML range input element for editing hue. */ - private hueSlider: HTMLInputElement | null = null; - - /** HTML span element to display the current saturation. */ - private saturationReadout: HTMLSpanElement | null = null; - - /** HTML range input element for editing saturation. */ - private saturationSlider: HTMLInputElement | null = null; - - /** HTML span element to display the current brightness. */ - private brightnessReadout: HTMLSpanElement | null = null; - - /** HTML range input element for editing brightness. */ - private brightnessSlider: HTMLInputElement | null = null; - - /** HTML div element containing all the labels and sliders. */ - private dropdownContainer: HTMLDivElement | null = null; - - /* eslint-disable @typescript-eslint/naming-convention */ - /** - * Create and show the colour field's editor. - * - * @override - */ - protected showEditor_(): void { - /* eslint-enable @typescript-eslint/naming-convention */ - this.createDropdownSliders(); - if (!this.dropdownContainer || !this.hueSlider) { - throw new Error('Failed to initialize the HSV sliders.'); - } - Blockly.DropDownDiv.getContentDiv().appendChild(this.dropdownContainer); - - Blockly.DropDownDiv.showPositionedByField( - this, - this.dropdownDisposeSliders.bind(this), - ); - - this.valueWhenEditorWasOpened = this.value_; - - // Focus so we can start receiving keyboard events. - setTimeout(() => { - this.hueSlider?.focus({preventScroll: true}); - }, 250); - } - - /** - * Creates a row with a slider label and a readout to display the slider - * value, appends it to the provided container, and returns the readout. - * - * @param name The display name of the slider. - * @param container Where the row will be inserted. - * @returns The readout, so that it can be updated. - */ - private static createLabelInContainer( - name: string, - container: HTMLElement, - ): HTMLSpanElement { - const label: HTMLDivElement = document.createElement('div'); - const labelText: HTMLSpanElement = document.createElement('span'); - const readout: HTMLSpanElement = document.createElement('span'); - label.classList.add('fieldColourSliderLabel'); - labelText.textContent = name; - label.appendChild(labelText); - label.appendChild(readout); - container.appendChild(label); - return readout; - } - - /** - * Creates a slider, appends it to the provided container, and returns it. - * - * @param max The maximum value of the slider. - * @param step The minimum step size of the slider. - * @param container Where the row slider be inserted. - * @returns The slider. - */ - private createSliderInContainer( - max: number, - step: number, - container: HTMLElement, - ): HTMLInputElement { - const slider: HTMLInputElement = document.createElement('input'); - slider.classList.add('fieldColourSlider'); - slider.type = 'range'; - slider.min = String(0); - slider.max = String(max); - slider.step = String(step); - slider.addEventListener('keydown', (e) => { - if (e.key === 'Enter' || e.key === ' ') { - Blockly.DropDownDiv.hideIfOwner(this); - Blockly.getFocusManager().focusNode(this); - } else if (e.key === 'Escape') { - this.setValue(this.valueWhenEditorWasOpened); - } - }); - container.appendChild(slider); - return slider; - } - - /** Creates the colour picker slider editor and adds event listeners. */ - private createDropdownSliders(): void { - const container: HTMLDivElement = document.createElement('div'); - container.classList.add('fieldColourSliderContainer'); - - this.hueReadout = FieldColourHsvSliders.createLabelInContainer( - 'Hue', - container, - ); - this.hueSlider = this.createSliderInContainer( - FieldColourHsvSliders.HUE_SLIDER_MAX, - 2, - container, - ); - Blockly.utils.aria.setState( - this.hueSlider, - Blockly.utils.aria.State.LABEL, - 'Hue', - ); - this.saturationReadout = FieldColourHsvSliders.createLabelInContainer( - 'Saturation', - container, - ); - this.saturationSlider = this.createSliderInContainer( - FieldColourHsvSliders.SATURATION_SLIDER_MAX, - 1, - container, - ); - Blockly.utils.aria.setState( - this.saturationSlider, - Blockly.utils.aria.State.LABEL, - 'Saturation', - ); - this.brightnessReadout = FieldColourHsvSliders.createLabelInContainer( - 'Brightness', - container, - ); - this.brightnessSlider = this.createSliderInContainer( - FieldColourHsvSliders.BRIGHTNESS_SLIDER_MAX, - 1, - container, - ); - Blockly.utils.aria.setState( - this.brightnessSlider, - Blockly.utils.aria.State.LABEL, - 'Brightness', - ); - - this.hsvBoundEvents.push( - Blockly.browserEvents.conditionalBind( - this.hueSlider, - 'input', - this, - this.onSliderChange, - ), - ); - this.hsvBoundEvents.push( - Blockly.browserEvents.conditionalBind( - this.saturationSlider, - 'input', - this, - this.onSliderChange, - ), - ); - this.hsvBoundEvents.push( - Blockly.browserEvents.conditionalBind( - this.brightnessSlider, - 'input', - this, - this.onSliderChange, - ), - ); - - if (window.EyeDropper) { - // If the browser supports the eyedropper API, create a button for it. - const button: HTMLButtonElement = document.createElement('button'); - button.classList.add('fieldColourEyedropper'); - button.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - this.setValue(this.valueWhenEditorWasOpened); - } - }); - container.appendChild(document.createElement('hr')); - container.appendChild(button); - this.hsvBoundEvents.push( - Blockly.browserEvents.conditionalBind( - button, - 'click', - this, - this.onEyedropperEvent, - ), - ); - } - - this.dropdownContainer = container; - - this.updateSliderValues(); - } - - /** - * Updates the ARIA roles and label for this field. - */ - override recomputeAriaContext(): boolean { - const shouldCustomize = super.recomputeAriaContext(); - if (!shouldCustomize) return false; - Blockly.utils.aria.setState( - this.getFocusableElement(), - Blockly.utils.aria.State.HASPOPUP, - 'menu', - ); - return true; - } - - /** Disposes of events and DOM-references belonging to the colour editor. */ - private dropdownDisposeSliders(): void { - for (const event of this.hsvBoundEvents) { - Blockly.browserEvents.unbind(event); - } - this.hsvBoundEvents.length = 0; - this.hueReadout = null; - this.hueSlider = null; - this.saturationReadout = null; - this.saturationSlider = null; - this.brightnessReadout = null; - this.brightnessSlider = null; - this.dropdownContainer = null; - - if ( - this.sourceBlock_ && - Blockly.Events.isEnabled() && - this.valueWhenEditorWasOpened !== null && - this.valueWhenEditorWasOpened !== this.value_ - ) { - // When closing a field input widget, fire an event indicating that the - // user has completed a sequence of changes. The value may have changed - // multiple times while the editor was open, but this will fire an event - // containing the value when the editor was opened as well as the new one. - Blockly.Events.fire( - new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))( - this.sourceBlock_, - 'field', - this.name || null, - this.valueWhenEditorWasOpened, - this.value_, - ), - ); - this.valueWhenEditorWasOpened = null; - } - } - - /** - * A helper function that converts a colour, specified by the provided hue, - * saturation, and brightness parameters, into a hexadecimal string in the - * format "#rrggbb". - * - * @param hue The hue of the colour. - * @param saturation The saturation of the colour. - * @param brightness The brightness of the colour. - * @returns A hexadecimal representation of the colour in the format "#rrggbb" - */ - private static hsvToHex( - hue: number, - saturation: number, - brightness: number, - ): string { - FieldColourHsvSliders.helperHsv.h = hue; - FieldColourHsvSliders.helperHsv.s = saturation; - FieldColourHsvSliders.helperHsv.v = brightness; - return FieldColourHsvSliders.helperRgb - .loadFromHsv(FieldColourHsvSliders.helperHsv) - .toHex(); - } - - /** - * Updates the value of this field based on the editor sliders. - * - * @param event Unused. - */ - private onSliderChange(event?: Event): void { - if (!this.hueSlider || !this.saturationSlider || !this.brightnessSlider) { - throw new Error('The HSV sliders are missing.'); - } - const hue: number = - parseFloat(this.hueSlider.value) / FieldColourHsvSliders.HUE_SLIDER_MAX; - const saturation: number = - parseFloat(this.saturationSlider.value) / - FieldColourHsvSliders.SATURATION_SLIDER_MAX; - const brightness: number = - parseFloat(this.brightnessSlider.value) / - FieldColourHsvSliders.BRIGHTNESS_SLIDER_MAX; - this.setIntermediateValue( - FieldColourHsvSliders.hsvToHex(hue, saturation, brightness), - ); - this.renderSliders(); - } - - /** - * Updates the value of this field and editor sliders using an eyedropper. - * - * @param event Unused. - */ - private onEyedropperEvent(event?: Event): void { - if (window.EyeDropper) { - const eyeDropper: EyeDropper = new window.EyeDropper(); - eyeDropper.open().then( - (result) => { - this.setIntermediateValue(result.sRGBHex); - this.updateSliderValues(); - }, - // Prevent throwing by handling promise rejection and doing nothing. - () => {}, - ); - } - } - - private setIntermediateValue(value: string): void { - // Intermediate value changes from user input are not confirmed until the - // user closes the editor, and may be numerous. Inhibit reporting these as - // normal block change events, and instead report them as special - // intermediate changes that do not get recorded in undo history. - const oldValue = this.value_; - // Change the field's value without firing the normal change event. - this.setValue(value, false); - if ( - this.sourceBlock_ && - Blockly.Events.isEnabled() && - this.value_ !== oldValue - ) { - // Fire a special event indicating that the value changed but the change - // isn't complete yet and normal field change listeners can wait. - Blockly.Events.fire( - new (Blockly.Events.get( - Blockly.Events.BLOCK_FIELD_INTERMEDIATE_CHANGE, - ))(this.sourceBlock_, this.name || null, oldValue, this.value_), - ); - } - } - - /** - * Updates the gradient backgrounds of the slider tracks and readouts based - * on the slider values. - */ - private renderSliders(): void { - if ( - !this.hueSlider || - !this.hueReadout || - !this.saturationSlider || - !this.saturationReadout || - !this.brightnessSlider || - !this.brightnessReadout - ) { - throw new Error('The HSV sliders are missing.'); - } - this.hueReadout.textContent = this.hueSlider.value; - this.saturationReadout.textContent = this.saturationSlider.value; - this.brightnessReadout.textContent = this.brightnessSlider.value; - - const h: number = - parseFloat(this.hueSlider.value) / FieldColourHsvSliders.HUE_SLIDER_MAX; - const s: number = - parseFloat(this.saturationSlider.value) / - FieldColourHsvSliders.SATURATION_SLIDER_MAX; - const v: number = - parseFloat(this.brightnessSlider.value) / - FieldColourHsvSliders.BRIGHTNESS_SLIDER_MAX; - - // The hue slider needs intermediate gradient control points to include all - // colours of the rainbow. - let hueGradient = 'linear-gradient(to right, '; - hueGradient += - FieldColourHsvSliders.hsvToHex(0 / 6, s, v) + - ` ${FieldColourHsvSliders.THUMB_RADIUS}px, `; - hueGradient += FieldColourHsvSliders.hsvToHex(1 / 6, s, v) + ', '; - hueGradient += FieldColourHsvSliders.hsvToHex(2 / 6, s, v) + ', '; - hueGradient += FieldColourHsvSliders.hsvToHex(3 / 6, s, v) + ', '; - hueGradient += FieldColourHsvSliders.hsvToHex(4 / 6, s, v) + ', '; - hueGradient += FieldColourHsvSliders.hsvToHex(5 / 6, s, v) + ', '; - hueGradient += - FieldColourHsvSliders.hsvToHex(6 / 6, s, v) + - ` calc(100% - ${FieldColourHsvSliders.THUMB_RADIUS}px))`; - this.hueSlider.style.setProperty('--slider-track-background', hueGradient); - - // The saturation slider only needs gradient control points at each end. - let saturationGradient = 'linear-gradient(to right, '; - saturationGradient += - FieldColourHsvSliders.hsvToHex(h, 0, v) + - ` ${FieldColourHsvSliders.THUMB_RADIUS}px, `; - saturationGradient += - FieldColourHsvSliders.hsvToHex(h, 1, v) + - ` calc(100% - ${FieldColourHsvSliders.THUMB_RADIUS}px))`; - this.saturationSlider.style.setProperty( - '--slider-track-background', - saturationGradient, - ); - - // The brightness slider only needs gradient control points at each end. - let brightnessGradient = 'linear-gradient(to right, '; - brightnessGradient += - FieldColourHsvSliders.hsvToHex(h, s, 0) + - ` ${FieldColourHsvSliders.THUMB_RADIUS}px, `; - brightnessGradient += - FieldColourHsvSliders.hsvToHex(h, s, 1) + - ` calc(100% - ${FieldColourHsvSliders.THUMB_RADIUS}px))`; - this.brightnessSlider.style.setProperty( - '--slider-track-background', - brightnessGradient, - ); - } - - /** Updates slider values based on the current value of the field. */ - private updateSliderValues(): void { - if (!this.hueSlider || !this.saturationSlider || !this.brightnessSlider) { - return; - } - - const hsv: HsvColour = FieldColourHsvSliders.helperHsv.loadFromRgb( - FieldColourHsvSliders.helperRgb.loadFromHex(this.getValue() ?? ''), - ); - - this.hueSlider.value = String(hsv.h * FieldColourHsvSliders.HUE_SLIDER_MAX); - this.saturationSlider.value = String( - hsv.s * FieldColourHsvSliders.SATURATION_SLIDER_MAX, - ); - this.brightnessSlider.value = String( - hsv.v * FieldColourHsvSliders.BRIGHTNESS_SLIDER_MAX, - ); - - this.renderSliders(); - } - - override getAriaValue() { - const hsv: HsvColour = FieldColourHsvSliders.helperHsv.loadFromRgb( - FieldColourHsvSliders.helperRgb.loadFromHex(this.getValue() ?? ''), - ); - - const components = []; - const brightness = hsv.v * 100; - if (brightness === 0) { - return 'black'; - } else if (brightness <= 25) { - components.push('very dark'); - } else if (brightness < 75) { - components.push('dark'); - } - - const saturation = hsv.s * 100; - if (saturation === 0) { - if (brightness === 100) { - return 'white'; - } - components.push('grey'); - return components.join(' '); - } else if (saturation <= 30) { - components.push(brightness <= 60 ? 'greyish' : 'pale'); - } else if (saturation >= 75) { - components.push('vibrant'); - } - - const hue = hsv.h * 360; - if (hue >= 330 || hue <= 10) { - components.push('red'); - } else if (hue <= 45) { - components.push('orange'); - } else if (hue <= 65) { - components.push('yellow'); - } else if (hue <= 160) { - components.push('green'); - } else if (hue <= 190) { - components.push('cyan'); - } else if (hue <= 260) { - components.push('blue'); - } else if (hue <= 290) { - components.push('purple'); - } else { - components.push('fuchsia'); - } - - return components.join(' '); - } -} - -Blockly.fieldRegistry.register( - 'field_colour_hsv_sliders', - FieldColourHsvSliders, -); - -// CSS for colour slider fields. -Blockly.Css.register(` -.fieldColourSliderContainer { - padding: 4px; - font-family: Roboto, Arial, sans-serif; - color: #5c5c5c; -} -.fieldColourSliderContainer hr { - border: none; - border-top: 1px solid #bbb; -} -.fieldColourSliderLabel { - display: flex; - justify-content: space-between; -} -.fieldColourEyedropper { - appearance: none; - position: relative; - border: none; - border-radius: 4px; - background: transparent; - font: inherit; - color: inherit; - cursor: pointer; - width: 100%; - margin: 0; - display: flex; - justify-content: center; - align-items: center; -} -.fieldColourEyedropper:hover { - background: rgba(0,0,0,0.1) -} -.fieldColourEyedropper input { - opacity: 0; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} -.fieldColourEyedropper::before { - content: "Eyedropper"; -} -.fieldColourEyedropper::after { - content: ""; - margin-left: 8px; - width: 24px; - height: 24px; - background: currentColor; - pointer-events: none; - -webkit-mask-image: var(--customize-dial-symbol); - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - mask-image: var(--customize-dial-symbol); - mask-repeat: no-repeat; - mask-position: center; - --customize-dial-symbol: url('data:image/svg+xml,\ - \ - \ - \ - '); -} -.blocklyKeyboardNavigation .fieldColourEyedropper:focus { - outline: none; - border: var(--blockly-selection-width) solid var(--blockly-active-node-color); - border-radius: 4px; -} -.fieldColourSlider { - -webkit-appearance: none; - width: 150px; - height: 24px; - margin: 4px 8px 24px 8px; - padding: 0; -} -.fieldColourSlider:last-child { - margin-bottom: 4px; -} -.fieldColourSlider:focus { - outline: none; -} -/* Webkit */ -.fieldColourSlider::-webkit-slider-runnable-track { - background: var(--slider-track-background); - border-radius: 8px; - height: 16px; -} -.fieldColourSlider::-webkit-slider-thumb { - -webkit-appearance: none; - background: #fff; - border-radius: 50%; - box-shadow: 0 0 0 4px rgba(0,0,0,.15); - cursor: pointer; - width: ${FieldColourHsvSliders.THUMB_RADIUS * 2}px; - height: ${FieldColourHsvSliders.THUMB_RADIUS * 2}px; - margin-top: -4px; -} -/* Firefox */ -.fieldColourSlider::-moz-range-track { - background: var(--slider-track-background); - border-radius: 8px; - height: 16px; -} -.fieldColourSlider::-moz-range-thumb { - background: #fff; - border: none; - border-radius: 50%; - box-shadow: 0 0 0 4px rgba(0,0,0,.15); - cursor: pointer; - width: ${FieldColourHsvSliders.THUMB_RADIUS * 2}px; - height: ${FieldColourHsvSliders.THUMB_RADIUS * 2}px; -} -.fieldColourSlider::-moz-focus-outer { - /* override the focus border style */ - border: 0; -} -/* IE */ -.fieldColourSlider::-ms-track { - background: var(--slider-track-background); - border-radius: 12px; - width: 100%; - height: 24px; - /* remove default tick marks */ - color: transparent; -} -.fieldColourSlider::-ms-fill-lower { - background: transparent; -} -.fieldColourSlider::-ms-fill-upper { - background: transparent; -} -.fieldColourSlider::-ms-thumb { - background: #fff; - border: none; - border-radius: 50%; - box-shadow: 0 0 0 4px rgba(0,0,0,.15); - cursor: pointer; - width: ${FieldColourHsvSliders.THUMB_RADIUS * 2}px; - height: ${FieldColourHsvSliders.THUMB_RADIUS * 2}px; -} -.blocklyKeyboardNavigation .fieldColourSlider:focus { - border: var(--blockly-selection-width) solid var(--blockly-active-node-color); - border-radius: 16px; - padding: 1px; -} -`); diff --git a/plugins/field-colour-hsv-sliders/src/index.ts b/plugins/field-colour-hsv-sliders/src/index.ts deleted file mode 100644 index b5899eff3..000000000 --- a/plugins/field-colour-hsv-sliders/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './field_colour_hsv_sliders'; diff --git a/plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test.mocha.js b/plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test.mocha.js deleted file mode 100644 index 352aa2744..000000000 --- a/plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test.mocha.js +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const { - assertColourHsvSlidersField, - assertColourHsvSlidersFieldDefault, -} = require('./field_colour_hsv_sliders_test_helpers.mocha'); -const {testHelpers} = require('@blockly/dev-tools'); -const {FieldColourHsvSliders} = require('../src/index'); - -const { - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -suite('FieldColourHsvSliders', function () { - setup(function () { - this.jsdomCleanup = require('jsdom-global')( - '
    ', - ); - this.field = new FieldColourHsvSliders(); - }); - - teardown(function () { - this.jsdomCleanup(); - }); - - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = [ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - {title: 'NaN', value: NaN}, - {title: 'Non-Parsable String', value: 'wrong'}, - {title: 'Integer', value: 1}, - {title: 'Float', value: 1.5}, - {title: 'Integer String', value: '1'}, - {title: 'Float String', value: '1.5'}, - {title: 'Infinity', value: Infinity}, - {title: 'Negative Infinity', value: -Infinity}, - {title: 'Infinity String', value: 'Infinity'}, - {title: 'Negative Infinity String', value: '-Infinity'}, - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = [ - { - title: 'Red', - value: '#ff0000', - expectedValue: '#ff0000', - expectedText: '#f00', - }, - { - title: 'Black', - value: '#000000', - expectedValue: '#000000', - expectedText: '#000', - }, - { - title: 'White', - value: '#ffffff', - expectedValue: '#ffffff', - expectedText: '#fff', - }, - { - title: 'Gray', - value: '#7f7f7f', - expectedValue: '#7f7f7f', - expectedText: '#7f7f7f', - }, - { - title: 'Shortened String', - value: 'bad', - expectedValue: '#bbaadd', - expectedText: '#bad', - }, - ]; - const addArgsAndJson = function (testCase) { - testCase.args = [testCase.value]; - testCase.json = {colour: testCase.value}; - }; - invalidValueTestCases.forEach(addArgsAndJson); - validValueTestCases.forEach(addArgsAndJson); - - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldColourHsvSliders} field The field to check. - * @param {FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertColourHsvSlidersField( - field, - testCase.expectedValue, - testCase.expectedText, - ); - }; - - runConstructorSuiteTests( - FieldColourHsvSliders, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertColourHsvSlidersFieldDefault, - ); - - runFromJsonSuiteTests( - FieldColourHsvSliders, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertColourHsvSlidersFieldDefault, - ); - - suite('setValue', function () { - suite('Empty -> New Value', function () { - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - '#ffffff', - '#fff', - ); - }); - suite('Value -> New Value', function () { - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - '#ffffff', - '#fff', - ); - }); - }); -}); diff --git a/plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test_helpers.mocha.js b/plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test_helpers.mocha.js deleted file mode 100644 index 74e5f80df..000000000 --- a/plugins/field-colour-hsv-sliders/test/field_colour_hsv_sliders_test_helpers.mocha.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {assertFieldValue} = require('@blockly/dev-tools').testHelpers; -const {FieldColourHsvSliders} = require('../src/index'); - -/** - * Assert the colour hsv sliders field options. - * @param {FieldColourHsvSliders} colourHsvSlidersField The colour hsv sliders - * field. - * @param {string} expectedValue The expected value. - * @param {string} expectedText The expected text. - */ -function assertColourHsvSlidersField( - colourHsvSlidersField, - expectedValue, - expectedText, -) { - assertFieldValue(colourHsvSlidersField, expectedValue, expectedText); -} - -/** - * Assert the slider field's value is the default value. - * @param {FieldColourHsvSliders} colourHsvSlidersField The slider field. - */ -function assertColourHsvSlidersFieldDefault(colourHsvSlidersField) { - assertColourHsvSlidersField(colourHsvSlidersField, '#ffffff', '#fff'); -} - -module.exports = { - assertColourHsvSlidersField, - assertColourHsvSlidersFieldDefault, -}; diff --git a/plugins/field-colour-hsv-sliders/test/index.html b/plugins/field-colour-hsv-sliders/test/index.html deleted file mode 100644 index e80b2952a..000000000 --- a/plugins/field-colour-hsv-sliders/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Colour HSV Sliders Playground - - - - -
    - - - diff --git a/plugins/field-colour-hsv-sliders/test/index.ts b/plugins/field-colour-hsv-sliders/test/index.ts deleted file mode 100644 index 0be3ab2d7..000000000 --- a/plugins/field-colour-hsv-sliders/test/index.ts +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Colour HSV Sliders field test playground. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -/** - * An array of blocks that are defined only for the purposes of - * manually and visually testing the HSV slider field. - */ -const testBlockDefinitions = [ - { - type: 'test_standard_field_values', - message0: '%1', - args0: [ - { - type: 'field_colour_hsv_sliders', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_colour_hsv_sliders`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values', - message0: '%1', - args0: [ - { - type: 'field_colour_hsv_sliders', - name: 'FIELDNAME', - colour: '#ff0000', - alt: { - type: 'field_label', - text: `No field_colour_hsv_sliders`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_standard_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_colour_hsv_sliders', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_colour_hsv_sliders`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_colour_hsv_sliders', - name: 'FIELDNAME', - colour: '#ff0000', - alt: { - type: 'field_label', - text: `No field_colour_hsv_sliders`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_parent_block', - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }, -]; - -Blockly.defineBlocksWithJsonArray(testBlockDefinitions); - -/** - * A test toolbox containing the exported blocks and a variety of - * test blocks to exercise the colour field in different contexts - * (on a shadow block, as the only field on a block, etc). - * These are in a simple toolbox, rather than a category toolbox, so that - * they are all instantiated every time the test page is opened. - */ -const jsonToolbox = { - contents: [ - { - kind: 'label', - text: 'Test blocks: default field values', - }, - { - kind: 'block', - type: 'test_standard_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_standard_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: custom field values', - }, - { - kind: 'block', - type: 'test_custom_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values_and_label', - }, - }, - }, - }, - ], -}; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions: Blockly.BlocklyOptions = { - toolbox: jsonToolbox, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/field-colour-hsv-sliders/tsconfig.json b/plugins/field-colour-hsv-sliders/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/field-colour-hsv-sliders/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-colour/CHANGELOG.md b/plugins/field-colour/CHANGELOG.md deleted file mode 100644 index 9ac7ff77c..000000000 --- a/plugins/field-colour/CHANGELOG.md +++ /dev/null @@ -1,552 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -### Bug Fixes - -* Fix positioning of dropdown on full-block color fields ([#2747](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2747)) - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Improve accessibility of grid and colour fields ([#2724](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2724)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [6.0.12](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-colour@6.0.11...@blockly/field-colour@6.0.12) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.11](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-colour@6.0.10...@blockly/field-colour@6.0.11) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.10](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-colour@6.0.9...@blockly/field-colour@6.0.10) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.8...@blockly/field-colour@6.0.9) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.7...@blockly/field-colour@6.0.8) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.6...@blockly/field-colour@6.0.7) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.5...@blockly/field-colour@6.0.6) (2025-10-30) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.4...@blockly/field-colour@6.0.5) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.3...@blockly/field-colour@6.0.4) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.2...@blockly/field-colour@6.0.3) (2025-07-03) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.1...@blockly/field-colour@6.0.2) (2025-06-19) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@6.0.0...@blockly/field-colour@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.19...@blockly/field-colour@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.19](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.18...@blockly/field-colour@5.0.19) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.18](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.17...@blockly/field-colour@5.0.18) (2025-05-15) - - -### Reverts - -* Revert "fix: Add `getClass()` to `FieldColour`. (#2506)" ([144b6d0](https://github.com/google/blockly-samples/commit/144b6d0c4b939e1f329986220e30ebdfcf93453c)), closes [#2506](https://github.com/google/blockly-samples/issues/2506) - - - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.16...@blockly/field-colour@5.0.17) (2025-05-08) - - -### Bug Fixes - -* Add `getClass()` to `FieldColour`. ([#2506](https://github.com/google/blockly-samples/issues/2506)) ([f5a577b](https://github.com/google/blockly-samples/commit/f5a577b8fe25b6fbf1502ca85902c22777fd8270)) - - - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.15...@blockly/field-colour@5.0.16) (2025-03-27) - - -### Bug Fixes - -* Don't call blur() when mouse leaves the colour picker. ([#2499](https://github.com/google/blockly-samples/issues/2499)) ([e8d4a87](https://github.com/google/blockly-samples/commit/e8d4a874c44cdb0e1ad05b08122251b9e758655c)) - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.14...@blockly/field-colour@5.0.15) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.13...@blockly/field-colour@5.0.14) (2025-01-23) - - -### Bug Fixes - -* Fix bug that prevented keyboard navigation of color swatches. ([#2479](https://github.com/google/blockly-samples/issues/2479)) ([5945e7c](https://github.com/google/blockly-samples/commit/5945e7c0412faedc08c422f9f538ef22193cc659)) - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.12...@blockly/field-colour@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.11...@blockly/field-colour@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.10...@blockly/field-colour@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.9...@blockly/field-colour@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.8...@blockly/field-colour@5.0.9) (2024-08-29) - - -### Bug Fixes - -* add documentation about locales for colour blocks ([#2452](https://github.com/google/blockly-samples/issues/2452)) ([e06f13d](https://github.com/google/blockly-samples/commit/e06f13de06cb1bea9358ad46306051f4eb1bd05a)) -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.7...@blockly/field-colour@5.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.6...@blockly/field-colour@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.5...@blockly/field-colour@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.4...@blockly/field-colour@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.3...@blockly/field-colour@5.0.4) (2024-07-11) - - -### Reverts - -* Revert "chore(deps): Bump the npm_and_yarn group across 54 directories with 19 updates (#2403)" (#2410) ([bad8ffb](https://github.com/google/blockly-samples/commit/bad8ffbf85caa4e5b68d2f010cd0deaa9e3dd98f)), closes [#2403](https://github.com/google/blockly-samples/issues/2403) [#2410](https://github.com/google/blockly-samples/issues/2410) - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.2...@blockly/field-colour@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.1...@blockly/field-colour@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@5.0.0...@blockly/field-colour@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour@4.0.4...@blockly/field-colour@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour@4.0.3...@blockly/field-colour@4.0.4) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour@4.0.2...@blockly/field-colour@4.0.3) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour@4.0.1...@blockly/field-colour@4.0.2) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@4.0.0...@blockly/field-colour@4.0.1) (2024-04-11) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.13...@blockly/field-colour@4.0.0) (2024-04-04) - - -### ⚠ BREAKING CHANGES - -* The multiline text input field no longer registers itself on load. The developer must either manually register the field or install blocks, which will install the field. This is part of a move to have no side effects in field and block definitions, so that tree-shaking can remove unwanted fields and blocks. -* The angle field no longer registers itself on load. The developer must manually register the field. This is part of a move to have no side effects in field and block definitions, so that tree-shaking can remove unwanted fields and blocks. - -### Features - -* add block definitions to fields ([#2299](https://github.com/google/blockly-samples/issues/2299)) ([c197af6](https://github.com/google/blockly-samples/commit/c197af6c67bc989bbdb4e83a62abc08167bcbbfe)), closes [#2162](https://github.com/google/blockly-samples/issues/2162) [#2202](https://github.com/google/blockly-samples/issues/2202) [#2221](https://github.com/google/blockly-samples/issues/2221) [#2211](https://github.com/google/blockly-samples/issues/2211) [#2220](https://github.com/google/blockly-samples/issues/2220) [#2232](https://github.com/google/blockly-samples/issues/2232) [#2233](https://github.com/google/blockly-samples/issues/2233) [#2296](https://github.com/google/blockly-samples/issues/2296) - - - -## [3.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.12...@blockly/field-colour@3.0.13) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.11...@blockly/field-colour@3.0.12) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.10...@blockly/field-colour@3.0.11) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.9...@blockly/field-colour@3.0.10) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.8...@blockly/field-colour@3.0.9) (2023-11-09) - - -### Bug Fixes - -* zelos full block colour field rendering incorrectly ([#1932](https://github.com/google/blockly-samples/issues/1932)) ([49fe34f](https://github.com/google/blockly-samples/commit/49fe34fa887af1c6295fbcd294839d20fb86b0c8)) - - - -## [3.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.7...@blockly/field-colour@3.0.8) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.6...@blockly/field-colour@3.0.7) (2023-10-30) - - -### Bug Fixes - -* Field Colour Plugin types ([#1964](https://github.com/google/blockly-samples/issues/1964)) ([8aee09e](https://github.com/google/blockly-samples/commit/8aee09e9375cbcff65cc7b39530daaa3bdf84182)) -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.5...@blockly/field-colour@3.0.6) (2023-09-21) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.4...@blockly/field-colour@3.0.5) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.3...@blockly/field-colour@3.0.4) (2023-08-31) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.2...@blockly/field-colour@3.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.1...@blockly/field-colour@3.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@3.0.0...@blockly/field-colour@3.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour@2.0.1...@blockly/field-colour@3.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@2.0.0...@blockly/field-colour@2.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour@1.2.1...@blockly/field-colour@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [1.2.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@1.2.0...@blockly/field-colour@1.2.1) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## [1.2.0](https://github.com/google/blockly-samples/compare/@blockly/field-colour@1.1.1...@blockly/field-colour@1.2.0) (2023-05-25) - - -### Features - -* Revise fields ([#1700](https://github.com/google/blockly-samples/issues/1700)) ([c326f7b](https://github.com/google/blockly-samples/commit/c326f7b1ef54fe45387046c693ebd5afe2b2c571)) - - - -## [1.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-colour@1.1.0...@blockly/field-colour@1.1.1) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-colour - - - - - -## 1.1.0 (2023-05-11) - - -### Features - -* Add angle, colour, and multiline fields. (Rebase of [#1674](https://github.com/google/blockly-samples/issues/1674)) ([#1693](https://github.com/google/blockly-samples/issues/1693)) ([1b447f4](https://github.com/google/blockly-samples/commit/1b447f41d6293f14e846b8a4d82d289a5637a99a)) diff --git a/plugins/field-colour/README.md b/plugins/field-colour/README.md deleted file mode 100644 index 1fb1f42fb..000000000 --- a/plugins/field-colour/README.md +++ /dev/null @@ -1,308 +0,0 @@ -# @blockly/field-colour [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) field and blocks for -choosing and combining colours. - -## Installation - -### Yarn - -``` -yarn add @blockly/field-colour -``` - -### npm - -``` -npm install @blockly/field-colour --save -``` - -## Usage - -If you want to use this field in a block definition, you must install it by -calling `registerFieldColour` before instantiating your blocks. If another -field is registered under the same name (`field_colour`), this field will -overwrite it. - -If you [install the blocks](#blocks) in this package, the field will -automatically be installed. - -### Field - -The colour field stores a string as its `value`, and a string as its `text`. Its -`value` is a string with the format `#rrggbb`, while its `text` may be a string -with the format `#rgb` if possible. - -#### Colour field - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-colour/readme-media/on_block.png) - -#### Colour field with editor open - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-colour/readme-media/with_editor.png) - -#### Colour field on collapsed block - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-colour/readme-media/collapsed.png) - -### Creation - -#### JavaScript - -```js -import * as Blockly from 'blockly'; -import {registerFieldColour} from '@blockly/field-colour'; - -registerFieldColour(); -Blockly.Blocks['test_field_colour'] = { - init: function () { - this.appendDummyInput() - .appendField('colour: ') - .appendField( - new FieldColour('#ff4040', null, { - colourOptions: [ - '#ff4040', - '#ff8080', - '#ffc0c0', - '#4040ff', - '#8080ff', - '#c0c0ff', - ], - colourTitles: [ - 'dark pink', - 'pink', - 'light pink', - 'dark blue', - 'blue', - 'light blue', - ], - columns: 3, - }), - 'FIELDNAME', - ); - }, -}; -``` - -#### JSON - -```js -import * as Blockly from 'blockly'; -import {registerFieldColour} from '@blockly/field-colour'; - -registerFieldColour(); -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_field_colour', - message0: 'colour: %1', - args0: [ - { - type: 'field_colour', - name: 'FIELDNAME', - colour: '#ff4040', - colourOptions: [ - '#ff4040', - '#ff8080', - '#ffc0c0', - '#4040ff', - '#8080ff', - '#c0c0ff', - ], - colourTitles: [ - 'dark pink', - 'pink', - 'light pink', - 'dark blue', - 'blue', - 'light blue', - ], - columns: 3, - }, - ], - }, -]); -``` - -The colour constructor takes in the following: - -- an optional `value` -- an optional [validator](#creating-a-colour-validator) -- an optional map of options, including: - - `colourOptions` - - `colourTitles` - - `columns` - -The `value` should be a string in the format `#rrggbb`. If no `value` -is given or the given `value` is invalid, the first entry in the -default colours array will be used. - -The following options can also be set in JSON: - -- `colourOptions` -- `colourTitles` -- `columns` - -Or they can be set using [JavaScript hooks](#editor-options). - -## Customization - -### Editor options - -The `setColours` -function can be used to set the colour options of a colour field. It takes in an -array of colour strings, which must be defined in `#rrggbb` format, and an -optional array of tooltips. If the tooltip array is not provided, the default -tooltip array will be used. - -Tooltips and colours are matched based on array index, not based on value. If -the colours array is longer than the tooltip array, the tooltips for the extra -colours will be their `#rrggbb` value. - -The setColumns function sets the number of columns in the colour picker. - -#### JSON - -```js -{ - "type": "example_colour", - "message0": "colour: %1", - "args0": [ - { - "type": "field_colour", - "name": "COLOUR", - "colour": "#ff4040" - } - ], - "extensions": ["set_colours_extension"] -} -``` - -```js -Blockly.Extensions.register('set_colours_extension', function () { - var field = this.getField('COLOUR'); - field.setColours( - ['#ff4040', '#ff8080', '#ffc0c0', '#4040ff', '#8080ff', '#c0c0ff'], - ['dark pink', 'pink', 'light pink', 'dark blue', 'blue', 'light blue'], - ); - field.setColumns(3); -}); -``` - -This is done using a JSON -[extension](https://developers.google.com/blockly/guides/create-custom-blocks/define/extensions). - -#### JavaScript - -```js -Blockly.Blocks['example_colour'] = { - init: function () { - var field = new Blockly.FieldColour('#ff4040'); - field.setColours( - ['#ff4040', '#ff8080', '#ffc0c0', '#4040ff', '#8080ff', '#c0c0ff'], - ['dark pink', 'pink', 'light pink', 'dark blue', 'blue', 'light blue'], - ); - field.setColumns(3); - this.appendDummyInput().appendField('colour:').appendField(field, 'COLOUR'); - }, -}; -``` - -![Customized colour field editor](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-colour/readme-media/customized.png) - -#### Creating a colour validator - -Note: For information on validators in general see [Validators](https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators). - -A colour field's value is a `#rrggbb` format string, so any validators must -accept a `#rrggbb` format string, and return a `#rrggbb` format string, `null`, -or `undefined`. - -Here is an example of a validator that changes the colour of the block to match -the colour of the field. - -``` -function(newValue) { - this.getSourceBlock().setColour(newValue); - return newValue; -} -``` - -#### Block changing colour based on its colour field - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-colour/readme-media/validator.gif) - -### Blocks - -This package also provides four blocks related to the colour field. Each block -has generators in JavaScript, Python, PHP, Lua, and Dart. - -- "colour_blend" takes in two colours and a ratio and outputs a single colour. -- "colour_picker" is a simple block with just the colour field and an output. -- "colour_random" generates a random colour. -- "colour_rgb" generates a colour based on red, green, and blue values. - -You can install all four blocks by calling `installAllBlocks`. This will -install the blocks and all of their dependencies, including the colour field. -When calling `installAllBlocks`—or any of the individual `installSomeBlock` -functions—you can supply one or more `CodeGenerator` instances (e.g. -`javascriptGenerator`), and the install function will also install the correct -generator function for each block for the corresponding language(s). - -```js -import {javascriptGenerator} from 'blockly/javascript'; -import {dartGenerator} from 'blockly/dart'; -import {phpGenerator} from 'blockly/php'; -import {pythonGenerator} from 'blockly/python'; -import {luaGenerator} from 'blockly/lua'; -import {installAllBlocks as installColourBlocks} from '@blockly/field-colour'; - -// Installs all four blocks, the colour field, and all language generators. -installColourBlocks({ - javascript: javascriptGenerator, - dart: dartGenerator, - lua: luaGenerator, - python: pythonGenerator, - php: phpGenerator, -}); -``` - -If you only want to install a single block, you can call that block's -`installBlock` function. The `generators` parameter is the same. - -```js -import {javascriptGenerator} from 'blockly/javascript'; -import {colourBlend} from '@blockly/field-colour'; - -// Installs the colour_blend block, the colour field, -// and the generator for colour_blend in JavaScript. -colourBlend.installBlock({ - javascript: javascriptGenerator, -}); -``` - -#### Message files and locales - -The blocks in this package contain text that can be localized into multiple -languages. As of August 2024, the relevant messages are included in the core -Blockly language files. For information on Blockly's approach to localization, -see [Localization](https://developers.google.com/blockly/guides/configure/web/translations) -in the developer's guide. - -If your blocks show `%{BKY_COLOUR_BLEND_TITLE}` or similar text instead -of the expected text, make sure that you either: - -- Import the default Blockly modules, which includes the English langfiles, or -- Explicitly import a language and call `setLocale` before using these blocks. - -For more information, see [Load a Blockly localization -table](https://developers.google.com/blockly/guides/configure/web/translations#load-blockly). - -### API Reference - -- `setColours`: Sets the colour options, and optionally the titles for the - options. The colours should be an array of `#rrggbb` strings. -- `setColumns`: Sets the number of columns the dropdown should have. - -## License - -Apache 2.0 diff --git a/plugins/field-colour/package.json b/plugins/field-colour/package.json deleted file mode 100644 index 869ab4789..000000000 --- a/plugins/field-colour/package.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "@blockly/field-colour", - "version": "13.2.0", - "description": "A Blockly colour field.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "field", - "colour" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-colour#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-colour" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "@typescript-eslint/parser": "^8.61.1", - "chai": "^6.2.2", - "jsdom": "^29.1.1", - "jsdom-global": "^3.0.2", - "sinon": "^22.0.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@blockly/field-grid-dropdown": "^13.2.0" - } -} diff --git a/plugins/field-colour/readme-media/collapsed.png b/plugins/field-colour/readme-media/collapsed.png deleted file mode 100644 index 3787dc73aecf791d46013185cdab1272ad6ceab6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2140 zcmV-i2&4CjP)SvOy`k5rFekRGPpGmUnXOgV? znIx-zCdsOwNwVr^lH8On!YqOd2rmmPh zsz%Ax=Qu9nzbU%=D}>hs#g%1OlBmyd+~b8yc}sufn}LvcfiC)H<-p3S{MpC$eDIU{ zYXBZB`BW7t+a^)}@#C98zF@BMeq>NtQqONTCAKAlc*`vTvW@O=sDI1aQxd1@~f33H!y^MCEv z8q*H#g~fRBgOA4E2!zDZHZz8~PPk3*T}f(7B>HA?<{bRv8;>RJf4Pu;lT&H)zF3hzwK z_}SVqxpaNA>!qVmn?Sw3n@Pgl_m2a(`%on~p#LZ80*UvL3qVtml=U$HpjVfX%!t`x zG!ON+H5)27M$8VQ+2L?Y8+-Ll0DyK&T@^EHG&_vuiD^n>>(B}g;GbXBpTBheuh&m* zJ{{L4ar*+F#5WQYB@dNVBU4XfV zhoLr=S2XQrlBW8)o>rCjs>3t@K-Xif>uGa!4(NKU8ijkp*yrLqZ5?=O0@|AG4btgB zN4FDbYqqzxbb+6MT_9Cu^Ako3?_qSSG;!0fwi+7w&SHbjJz*SF+gfE~=AnM*daU5@ z3;+P*WhG@twRj{Wv9S~zdSRVyP}b@(oFJH;c(dwe^U?pr>puJNFrhY;|7cg;dD2q9 zsiRcQK5z{1tx=PeXWoK@_AD1pu^{Q=YjY04R}> z%(Af3krF2>zka9gdc5xLr84p1_h0?-o^yVt<&x=-ELNRPayZ8{??_O!lT8Sb0+kgCQuzNPKzHP|||eCONI zrJJs&fnwdW{hLOv?i&nQS>2@v0JJqX76+%VjPe4h%XPd}V`VB+qR&@E%QvMU|&yH2=M8(waf7XBQ0G(#^SnKT8I_$XO92hd9+1_ffw<2!E z>FWMeZEMxotr~zCxyq<(cNlMTB^uv(REhbiVZ=|vHU@?qMJqx*^;3w0(oFeCC~F*A6Qm zZFVW&#G&^gOMP=003fnhEW5rL^ne)!FuQ!n<1G?4z>CBJUG%T%+C@fjK<-zPYXGn@ zhviQY_%FyxdBVyQb^JAMy%*oH=u^^czJS4ANVJFM0X$fLMfFC? zL3?BynD)?8oNz~8F%Tp*6VzF2zlciI63JVK4jw1*{aN+|XNirM` zZ)|MH<#NH5Mfb6d)GD%kbOp;YUlVsJ;B>w}s!g5Nh S@;YSz0000$3 diff --git a/plugins/field-colour/readme-media/customized.png b/plugins/field-colour/readme-media/customized.png deleted file mode 100644 index 161860b9d18df83b07b66e670f9cc71281cd5dd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2337 zcmZ{mdowUw^!%0q7T^0ZU zIjFP4xt)yJQIyQCohU$LTmt}^A5aHdSZWo&%H8e2gi1Cm)sjTvPO8ch%V5{AG9!0X zOX|+T>>S~N>do*9pBC4)7>6cN7YO&v+0?o83FIhh*hk9op|W@VOhXL3FS=4^Ild{gXyjuoDxlCGvb?H6iryb@{m@&_qY40^geng`_t64x88%&Vb$cy- zd@a88eY<@5BSuX=8$YV%7`m41^h@A+V87b4MtwN#$lk%q(=-;iG)5C6T~WE->zi=8 z(s<;u;Srl(!z0859K(rmz{yi-D_`45^w_i&)`(*_(SZdmc z#64Ay5~c$XP0g@iH+=gx|1S(L1GiUXgL#Acb-0*NH*!{^!!^f`wt{;|VOs{;@-5+zy)E5iKo3@(+iAZc!2dr@BkxJBAnWB&nk zikWujZgO0*HH&l@HnI8Si;rzIt_krv(ivNr=N2E8z1vm<3_ldfZO`KVVVnGmf3e{B;2Y4q}9lT z1UbDx!S$Hu=#rj%Z20!xUJoP@F~VyH$$*)k`ImJn-EW6;8Y#NjhWLVbx!B-3bReLbFOC24j?nHT#ESm!{hl>3|LVU_n zT0I-iEu~(;V1kt$YgqT87!&md{eFS)7*?@};p^iA^Y0p8wtUgk1BMcGq1H7D-d2|; z33bi{UFH)o6I-{vtI@om>u$!apc4e$7?)@iYK(_+A(&WL1crvzxSri?RY+5U5{C2? zU;;2Roffk5Uy`bd(_YUmHye%2j%Fo9Je#o6Vu?guqr40L`;Nz=P%B@k$#eN&^_$k2 z8=X&|?gNk&m%BSo?d>UIP7|X1`TOl_5GL;g-2GSuV5eV61OAw-WJ~B3Ui{mQ7Z7wyxppUZTPL##;^6_*`vG% zWOC-pk6{iXoSTT_*IzK?G+76mQBXr@sW}C=at<@Ra8`_r>EB+bwRDuvlgdpgM+L4yp3rRIUvil zzv?O8ee~HYRfr4zh9Dj=bPkFC>J*U(iMh9%jq8Zu9?mWPohnGq_* z$Hy;P8p-5S zBdJUJt*05@Uf>Ej^~Si6!R46Y!&PX*{CPpDe&MDj5Yhvo^?JceH{&ICH61K= zKCP>4C#R-rj5>9Fr{&+2{lEC#DcHXnqhA^~MEy&9e7c7W06|wq^|G4Wa^dHk+RNgq zwtTL!nX^`1Gfgrj%eSFbSW~O-A{2y0Q2Z=OG}rFQtonr8DmeN^rcFefJRcbJn0cdQQpb@Xr`+lA%)69hSr+5i9m diff --git a/plugins/field-colour/readme-media/on_block.png b/plugins/field-colour/readme-media/on_block.png deleted file mode 100644 index ee3a66d96e6fd1110a26cb7f635cb894d40eb20c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1464 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

    moXBdA)3Le_?rtZ0Y!J{?uw|GJNT}W#N`=nPzbb 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 diff --git a/plugins/field-colour/src/blocks/colourBlend.ts b/plugins/field-colour/src/blocks/colourBlend.ts deleted file mode 100644 index 78237c85a..000000000 --- a/plugins/field-colour/src/blocks/colourBlend.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {Block, common as BlocklyCommon} from 'blockly/core'; -import { - JavascriptGenerator, - Order as JavascriptOrder, -} from 'blockly/javascript'; -import {DartGenerator, Order as DartOrder} from 'blockly/dart'; -import {LuaGenerator, Order as LuaOrder} from 'blockly/lua'; -import {PhpGenerator, Order as PhpOrder} from 'blockly/php'; -import {PythonGenerator, Order as PythonOrder} from 'blockly/python'; -import {registerFieldColour} from '../field_colour'; -import {Generators} from './generatorsType'; - -/** The name this block is registered under. */ -export const BLOCK_NAME = 'colour_blend'; - -// Block for blending two colours together. -const jsonDefinition = { - type: BLOCK_NAME, - message0: - '%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} ' + - '%1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3', - args0: [ - { - type: 'input_value', - name: 'COLOUR1', - check: 'Colour', - align: 'RIGHT', - }, - { - type: 'input_value', - name: 'COLOUR2', - check: 'Colour', - align: 'RIGHT', - }, - { - type: 'input_value', - name: 'RATIO', - check: 'Number', - align: 'RIGHT', - }, - ], - output: 'Colour', - helpUrl: '%{BKY_COLOUR_BLEND_HELPURL}', - style: 'colour_blocks', - tooltip: '%{BKY_COLOUR_BLEND_TOOLTIP}', -}; - -/** - * Javascript block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The JavascriptGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toJavascript( - block: Block, - generator: JavascriptGenerator, -): [string, JavascriptOrder] { - // Blend two colours together. - const colour1 = - generator.valueToCode(block, 'COLOUR1', JavascriptOrder.NONE) || - "'#000000'"; - const colour2 = - generator.valueToCode(block, 'COLOUR2', JavascriptOrder.NONE) || - "'#000000'"; - const ratio = - generator.valueToCode(block, 'RATIO', JavascriptOrder.NONE) || 0.5; - const functionName = generator.provideFunction_( - 'colourBlend', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(c1, c2, ratio) { - ratio = Math.max(Math.min(Number(ratio), 1), 0); - var r1 = parseInt(c1.substring(1, 3), 16); - var g1 = parseInt(c1.substring(3, 5), 16); - var b1 = parseInt(c1.substring(5, 7), 16); - var r2 = parseInt(c2.substring(1, 3), 16); - var g2 = parseInt(c2.substring(3, 5), 16); - var b2 = parseInt(c2.substring(5, 7), 16); - var r = Math.round(r1 * (1 - ratio) + r2 * ratio); - var g = Math.round(g1 * (1 - ratio) + g2 * ratio); - var b = Math.round(b1 * (1 - ratio) + b2 * ratio); - r = ('0' + (r || 0).toString(16)).slice(-2); - g = ('0' + (g || 0).toString(16)).slice(-2); - b = ('0' + (b || 0).toString(16)).slice(-2); - return '#' + r + g + b; -} -`, - ); - const code = `${functionName}(${colour1}, ${colour2}, ${ratio})`; - return [code, JavascriptOrder.FUNCTION_CALL]; -} - -/** - * Dart block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The DartGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toDart( - block: Block, - generator: DartGenerator, -): [string, DartOrder] { - // Blend two colours together. - const colour1 = - generator.valueToCode(block, 'COLOUR1', DartOrder.NONE) || "'#000000'"; - const colour2 = - generator.valueToCode(block, 'COLOUR2', DartOrder.NONE) || "'#000000'"; - const ratio = generator.valueToCode(block, 'RATIO', DartOrder.NONE) || 0.5; - - // TODO(#7600): find better approach than casting to any to override - // CodeGenerator declaring .definitions protected. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (generator as any).definitions_['import_dart_math'] = - "import 'dart:math' as Math;"; - const functionName = generator.provideFunction_( - 'colour_blend', - ` -String ${generator.FUNCTION_NAME_PLACEHOLDER_}(String c1, String c2, num ratio) { - ratio = Math.max(Math.min(ratio, 1), 0); - int r1 = int.parse('0x\${c1.substring(1, 3)}'); - int g1 = int.parse('0x\${c1.substring(3, 5)}'); - int b1 = int.parse('0x\${c1.substring(5, 7)}'); - int r2 = int.parse('0x\${c2.substring(1, 3)}'); - int g2 = int.parse('0x\${c2.substring(3, 5)}'); - int b2 = int.parse('0x\${c2.substring(5, 7)}'); - num rn = (r1 * (1 - ratio) + r2 * ratio).round(); - String rs = rn.toInt().toRadixString(16); - num gn = (g1 * (1 - ratio) + g2 * ratio).round(); - String gs = gn.toInt().toRadixString(16); - num bn = (b1 * (1 - ratio) + b2 * ratio).round(); - String bs = bn.toInt().toRadixString(16); - rs = '0$rs'; - rs = rs.substring(rs.length - 2); - gs = '0$gs'; - gs = gs.substring(gs.length - 2); - bs = '0$bs'; - bs = bs.substring(bs.length - 2); - return '#$rs$gs$bs'; -} -`, - ); - const code = `${functionName}(${colour1}, ${colour2}, ${ratio})`; - return [code, DartOrder.UNARY_POSTFIX]; -} - -/** - * Lua generator definition. - * - * @param block The Block instance to generate code for. - * @param generator The LuaGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toLua( - block: Block, - generator: LuaGenerator, -): [string, LuaOrder] { - // Blend two colours together. - const functionName = generator.provideFunction_( - 'colour_blend', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio) - local r1 = tonumber(string.sub(colour1, 2, 3), 16) - local r2 = tonumber(string.sub(colour2, 2, 3), 16) - local g1 = tonumber(string.sub(colour1, 4, 5), 16) - local g2 = tonumber(string.sub(colour2, 4, 5), 16) - local b1 = tonumber(string.sub(colour1, 6, 7), 16) - local b2 = tonumber(string.sub(colour2, 6, 7), 16) - local ratio = math.min(1, math.max(0, ratio)) - local r = math.floor(r1 * (1 - ratio) + r2 * ratio + .5) - local g = math.floor(g1 * (1 - ratio) + g2 * ratio + .5) - local b = math.floor(b1 * (1 - ratio) + b2 * ratio + .5) - return string.format("#%02x%02x%02x", r, g, b) -end -`, - ); - const colour1 = - generator.valueToCode(block, 'COLOUR1', LuaOrder.NONE) || "'#000000'"; - const colour2 = - generator.valueToCode(block, 'COLOUR2', LuaOrder.NONE) || "'#000000'"; - const ratio = generator.valueToCode(block, 'RATIO', LuaOrder.NONE) || 0; - const code = `${functionName}(${colour1}, ${colour2}, ${ratio})`; - return [code, LuaOrder.HIGH]; -} - -/** - * PHP generator definition. - * - * @param block The Block instance to generate code for. - * @param generator The PhpGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPhp( - block: Block, - generator: PhpGenerator, -): [string, PhpOrder] { - // Blend two colours together. - const colour1 = - generator.valueToCode(block, 'COLOUR1', PhpOrder.NONE) || "'#000000'"; - const colour2 = - generator.valueToCode(block, 'COLOUR2', PhpOrder.NONE) || "'#000000'"; - const ratio = generator.valueToCode(block, 'RATIO', PhpOrder.NONE) || 0.5; - const functionName = generator.provideFunction_( - 'colour_blend', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}($c1, $c2, $ratio) { - $ratio = max(min($ratio, 1), 0); - $r1 = hexdec(substr($c1, 1, 2)); - $g1 = hexdec(substr($c1, 3, 2)); - $b1 = hexdec(substr($c1, 5, 2)); - $r2 = hexdec(substr($c2, 1, 2)); - $g2 = hexdec(substr($c2, 3, 2)); - $b2 = hexdec(substr($c2, 5, 2)); - $r = round($r1 * (1 - $ratio) + $r2 * $ratio); - $g = round($g1 * (1 - $ratio) + $g2 * $ratio); - $b = round($b1 * (1 - $ratio) + $b2 * $ratio); - $hex = '#'; - $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); - return $hex; -} -`, - ); - const code = `${functionName}(${colour1}, ${colour2}, ${ratio})`; - return [code, PhpOrder.FUNCTION_CALL]; -} - -/** - * Python generator definition. - * - * @param block The Block instance to generate code for. - * @param generator The PythonGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPython( - block: Block, - generator: PythonGenerator, -): [string, PythonOrder] { - // Blend two colours together. - const functionName = generator.provideFunction_( - 'colour_blend', - ` -def ${generator.FUNCTION_NAME_PLACEHOLDER_}(colour1, colour2, ratio): - r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16) - g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16) - b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16) - ratio = min(1, max(0, ratio)) - r = round(r1 * (1 - ratio) + r2 * ratio) - g = round(g1 * (1 - ratio) + g2 * ratio) - b = round(b1 * (1 - ratio) + b2 * ratio) - return '#%02x%02x%02x' % (r, g, b) -`, - ); - const colour1 = - generator.valueToCode(block, 'COLOUR1', PythonOrder.NONE) || "'#000000'"; - const colour2 = - generator.valueToCode(block, 'COLOUR2', PythonOrder.NONE) || "'#000000'"; - const ratio = generator.valueToCode(block, 'RATIO', PythonOrder.NONE) || 0; - const code = `${functionName}(${colour1}, ${colour2}, ${ratio})`; - return [code, PythonOrder.FUNCTION_CALL]; -} - -const definitionsDict = BlocklyCommon.createBlockDefinitionsFromJsonArray([ - jsonDefinition, -]); - -/** The colour_blend BlockDefinition. */ -export const blockDefinition = definitionsDict[BLOCK_NAME]; - -/** - * Install the `colour_blend` block and all of its dependencies. - * - * @param gens The CodeGenerators to install per-block - * generators on. - */ -export function installBlock(gens: Generators = {}) { - registerFieldColour(); - BlocklyCommon.defineBlocks(definitionsDict); - if (gens.javascript) gens.javascript.forBlock[BLOCK_NAME] = toJavascript; - if (gens.dart) { - gens.dart.forBlock[BLOCK_NAME] = toDart; - gens.dart.addReservedWords('Math'); - } - if (gens.lua) gens.lua.forBlock[BLOCK_NAME] = toLua; - if (gens.php) gens.php.forBlock[BLOCK_NAME] = toPhp; - if (gens.python) gens.python.forBlock[BLOCK_NAME] = toPython; -} diff --git a/plugins/field-colour/src/blocks/colourPicker.ts b/plugins/field-colour/src/blocks/colourPicker.ts deleted file mode 100644 index 23c6fcc95..000000000 --- a/plugins/field-colour/src/blocks/colourPicker.ts +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {Block, common as BlocklyCommon} from 'blockly/core'; -import { - JavascriptGenerator, - Order as JavascriptOrder, -} from 'blockly/javascript'; -import {DartGenerator, Order as DartOrder} from 'blockly/dart'; -import {LuaGenerator, Order as LuaOrder} from 'blockly/lua'; -import {PhpGenerator, Order as PhpOrder} from 'blockly/php'; -import {PythonGenerator, Order as PythonOrder} from 'blockly/python'; -import {registerFieldColour} from '../field_colour'; -import {Generators} from './generatorsType'; - -/** The name this block is registered under. */ -export const BLOCK_NAME = 'colour_picker'; - -// Block for colour picker. -const jsonDefinition = { - type: BLOCK_NAME, - message0: '%1', - args0: [ - { - type: 'field_colour', - name: 'COLOUR', - colour: '#ff0000', - }, - ], - output: 'Colour', - helpUrl: '%{BKY_COLOUR_PICKER_HELPURL}', - style: 'colour_blocks', - tooltip: '%{BKY_COLOUR_PICKER_TOOLTIP}', - extensions: ['parent_tooltip_when_inline'], -}; - -/** - * Javascript block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The JavascriptGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toJavascript( - block: Block, - generator: JavascriptGenerator, -): [string, JavascriptOrder] { - // Colour picker. - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, JavascriptOrder.ATOMIC]; -} - -/** - * Dart block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The DartGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toDart( - block: Block, - generator: DartGenerator, -): [string, DartOrder] { - // Colour picker. - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, DartOrder.ATOMIC]; -} - -/** - * Lua block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The LuaGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toLua( - block: Block, - generator: LuaGenerator, -): [string, LuaOrder] { - // Colour picker. - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, LuaOrder.ATOMIC]; -} - -/** - * PHP block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PhpGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPhp( - block: Block, - generator: PhpGenerator, -): [string, PhpOrder] { - // Colour picker. - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, PhpOrder.ATOMIC]; -} - -/** - * Python block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PythonGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPython( - block: Block, - generator: PythonGenerator, -): [string, PythonOrder] { - // Colour picker. - const code = generator.quote_(block.getFieldValue('COLOUR')); - return [code, PythonOrder.ATOMIC]; -} - -const definitionsDict = BlocklyCommon.createBlockDefinitionsFromJsonArray([ - jsonDefinition, -]); - -/** The colour_picker BlockDefinition. */ -export const blockDefinition = definitionsDict[BLOCK_NAME]; - -/** - * Install the `colour_picker` block and all of its dependencies. - * - * @param gens The CodeGenerators to install per-block - * generators on. - */ -export function installBlock(gens: Generators = {}) { - registerFieldColour(); - BlocklyCommon.defineBlocks(definitionsDict); - if (gens.javascript) gens.javascript.forBlock[BLOCK_NAME] = toJavascript; - if (gens.dart) gens.dart.forBlock[BLOCK_NAME] = toDart; - if (gens.lua) gens.lua.forBlock[BLOCK_NAME] = toLua; - if (gens.php) gens.php.forBlock[BLOCK_NAME] = toPhp; - if (gens.python) gens.python.forBlock[BLOCK_NAME] = toPython; -} diff --git a/plugins/field-colour/src/blocks/colourRandom.ts b/plugins/field-colour/src/blocks/colourRandom.ts deleted file mode 100644 index 687ab0216..000000000 --- a/plugins/field-colour/src/blocks/colourRandom.ts +++ /dev/null @@ -1,171 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {Block, common as BlocklyCommon} from 'blockly/core'; -import { - JavascriptGenerator, - Order as JavascriptOrder, -} from 'blockly/javascript'; -import {DartGenerator, Order as DartOrder} from 'blockly/dart'; -import {LuaGenerator, Order as LuaOrder} from 'blockly/lua'; -import {PhpGenerator, Order as PhpOrder} from 'blockly/php'; -import {PythonGenerator, Order as PythonOrder} from 'blockly/python'; -import {registerFieldColour} from '../field_colour'; -import {Generators} from './generatorsType'; - -/** The name this block is registered under. */ -export const BLOCK_NAME = 'colour_random'; - -// Block for random colour. -const jsonDefinition = { - type: BLOCK_NAME, - message0: '%{BKY_COLOUR_RANDOM_TITLE}', - output: 'Colour', - helpUrl: '%{BKY_COLOUR_RANDOM_HELPURL}', - style: 'colour_blocks', - tooltip: '%{BKY_COLOUR_RANDOM_TOOLTIP}', -}; - -/** - * Javascript block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The JavascriptGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toJavascript( - block: Block, - generator: JavascriptGenerator, -): [string, JavascriptOrder] { - // Generate a random colour. - const functionName = generator.provideFunction_( - 'colourRandom', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { - var num = Math.floor(Math.random() * 0x1000000); - return '#' + ('00000' + num.toString(16)).substr(-6); -} -`, - ); - const code = functionName + '()'; - return [code, JavascriptOrder.FUNCTION_CALL]; -} - -/** - * Dart block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The DartGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toDart( - block: Block, - generator: DartGenerator, -): [string, DartOrder] { - // Generate a random colour. - // TODO(#7600): find better approach than casting to any to override - // CodeGenerator declaring .definitions protected. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (generator as any).definitions_['import_dart_math'] = - "import 'dart:math' as Math;"; - const functionName = generator.provideFunction_( - 'colour_random', - ` -String ${generator.FUNCTION_NAME_PLACEHOLDER_}() { - String hex = '0123456789abcdef'; - var rnd = new Math.Random(); - return '#\${hex[rnd.nextInt(16)]}\${hex[rnd.nextInt(16)]}' - '\${hex[rnd.nextInt(16)]}\${hex[rnd.nextInt(16)]}' - '\${hex[rnd.nextInt(16)]}\${hex[rnd.nextInt(16)]}'; -} -`, - ); - const code = functionName + '()'; - return [code, DartOrder.UNARY_POSTFIX]; -} - -/** - * Lua block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The LuaGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toLua( - block: Block, - generator: LuaGenerator, -): [string, LuaOrder] { - // Generate a random colour. - const code = 'string.format("#%06x", math.random(0, 2^24 - 1))'; - return [code, LuaOrder.HIGH]; -} - -/** - * PHP block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PhpGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPhp( - block: Block, - generator: PhpGenerator, -): [string, PhpOrder] { - // Generate a random colour. - const functionName = generator.provideFunction_( - 'colour_random', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}() { - return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT); -} -`, - ); - const code = functionName + '()'; - return [code, PhpOrder.FUNCTION_CALL]; -} - -/** - * Python block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PythonGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPython( - block: Block, - generator: PythonGenerator, -): [string, PythonOrder] { - // Generate a random colour. - // TODO(#7600): find better approach than casting to any to override - // CodeGenerator declaring .definitions protected. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (generator as any).definitions_['import_random'] = 'import random'; - const code = "'#%06x' % random.randint(0, 2**24 - 1)"; - return [code, PythonOrder.FUNCTION_CALL]; -} - -const definitionsDict = BlocklyCommon.createBlockDefinitionsFromJsonArray([ - jsonDefinition, -]); - -/** The colour_random BlockDefinition. */ -export const blockDefinition = definitionsDict[BLOCK_NAME]; - -/** - * Install the `colour_picker` block and all of its dependencies. - * - * @param gens The CodeGenerators to install per-block - * generators on. - */ -export function installBlock(gens: Generators = {}) { - registerFieldColour(); - BlocklyCommon.defineBlocks(definitionsDict); - if (gens.javascript) gens.javascript.forBlock[BLOCK_NAME] = toJavascript; - if (gens.dart) gens.dart.forBlock[BLOCK_NAME] = toDart; - if (gens.lua) gens.lua.forBlock[BLOCK_NAME] = toLua; - if (gens.php) gens.php.forBlock[BLOCK_NAME] = toPhp; - if (gens.python) gens.python.forBlock[BLOCK_NAME] = toPython; -} diff --git a/plugins/field-colour/src/blocks/colourRgb.ts b/plugins/field-colour/src/blocks/colourRgb.ts deleted file mode 100644 index 46ee55045..000000000 --- a/plugins/field-colour/src/blocks/colourRgb.ts +++ /dev/null @@ -1,249 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {Block, common as BlocklyCommon} from 'blockly/core'; -import { - JavascriptGenerator, - Order as JavascriptOrder, -} from 'blockly/javascript'; -import {DartGenerator, Order as DartOrder} from 'blockly/dart'; -import {LuaGenerator, Order as LuaOrder} from 'blockly/lua'; -import {PhpGenerator, Order as PhpOrder} from 'blockly/php'; -import {PythonGenerator, Order as PythonOrder} from 'blockly/python'; -import {registerFieldColour} from '../field_colour'; -import {Generators} from './generatorsType'; - -/** The name this block is registered under. */ -export const BLOCK_NAME = 'colour_rgb'; - -// Block for composing a colour from RGB components. -const jsonDefinition = { - type: BLOCK_NAME, - message0: - '%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3', - args0: [ - { - type: 'input_value', - name: 'RED', - check: 'Number', - align: 'RIGHT', - }, - { - type: 'input_value', - name: 'GREEN', - check: 'Number', - align: 'RIGHT', - }, - { - type: 'input_value', - name: 'BLUE', - check: 'Number', - align: 'RIGHT', - }, - ], - output: 'Colour', - helpUrl: '%{BKY_COLOUR_RGB_HELPURL}', - style: 'colour_blocks', - tooltip: '%{BKY_COLOUR_RGB_TOOLTIP}', -}; - -/** - * Javascript block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The JavascriptGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toJavascript( - block: Block, - generator: JavascriptGenerator, -): [string, JavascriptOrder] { - // Compose a colour from RGB components expressed as percentages. - const red = generator.valueToCode(block, 'RED', JavascriptOrder.NONE) || 0; - const green = - generator.valueToCode(block, 'GREEN', JavascriptOrder.NONE) || 0; - const blue = generator.valueToCode(block, 'BLUE', JavascriptOrder.NONE) || 0; - const functionName = generator.provideFunction_( - 'colourRgb', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) { - r = Math.max(Math.min(Number(r), 100), 0) * 2.55; - g = Math.max(Math.min(Number(g), 100), 0) * 2.55; - b = Math.max(Math.min(Number(b), 100), 0) * 2.55; - r = ('0' + (Math.round(r) || 0).toString(16)).slice(-2); - g = ('0' + (Math.round(g) || 0).toString(16)).slice(-2); - b = ('0' + (Math.round(b) || 0).toString(16)).slice(-2); - return '#' + r + g + b; -} -`, - ); - const code = `${functionName}(${red}, ${green}, ${blue})`; - return [code, JavascriptOrder.FUNCTION_CALL]; -} - -/** - * Dart block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The DartGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toDart( - block: Block, - generator: DartGenerator, -): [string, DartOrder] { - // Compose a colour from RGB components expressed as percentages. - const red = generator.valueToCode(block, 'RED', DartOrder.NONE) || 0; - const green = generator.valueToCode(block, 'GREEN', DartOrder.NONE) || 0; - const blue = generator.valueToCode(block, 'BLUE', DartOrder.NONE) || 0; - - // TODO(#7600): find better approach than casting to any to override - // CodeGenerator declaring .definitions protected. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (generator as any).definitions_['import_dart_math'] = - "import 'dart:math' as Math;"; - const functionName = generator.provideFunction_( - 'colour_rgb', - ` -String ${generator.FUNCTION_NAME_PLACEHOLDER_}(num r, num g, num b) { - num rn = (Math.max(Math.min(r, 100), 0) * 2.55).round(); - String rs = rn.toInt().toRadixString(16); - rs = '0$rs'; - rs = rs.substring(rs.length - 2); - num gn = (Math.max(Math.min(g, 100), 0) * 2.55).round(); - String gs = gn.toInt().toRadixString(16); - gs = '0$gs'; - gs = gs.substring(gs.length - 2); - num bn = (Math.max(Math.min(b, 100), 0) * 2.55).round(); - String bs = bn.toInt().toRadixString(16); - bs = '0$bs'; - bs = bs.substring(bs.length - 2); - return '#$rs$gs$bs'; -} -`, - ); - const code = `${functionName}(${red}, ${green}, ${blue})`; - return [code, DartOrder.UNARY_POSTFIX]; -} - -/** - * Lua block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The LuaGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toLua( - block: Block, - generator: LuaGenerator, -): [string, LuaOrder] { - // Compose a colour from RGB components expressed as percentages. - const functionName = generator.provideFunction_( - 'colour_rgb', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b) - r = math.floor(math.min(100, math.max(0, r)) * 2.55 + .5) - g = math.floor(math.min(100, math.max(0, g)) * 2.55 + .5) - b = math.floor(math.min(100, math.max(0, b)) * 2.55 + .5) - return string.format("#%02x%02x%02x", r, g, b) -end -`, - ); - const red = generator.valueToCode(block, 'RED', LuaOrder.NONE) || 0; - const green = generator.valueToCode(block, 'GREEN', LuaOrder.NONE) || 0; - const blue = generator.valueToCode(block, 'BLUE', LuaOrder.NONE) || 0; - const code = `${functionName}(${red}, ${green}, ${blue})`; - return [code, LuaOrder.HIGH]; -} - -/** - * PHP block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PhpGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPhp( - block: Block, - generator: PhpGenerator, -): [string, PhpOrder] { - // Compose a colour from RGB components expressed as percentages. - const red = generator.valueToCode(block, 'RED', PhpOrder.NONE) || 0; - const green = generator.valueToCode(block, 'GREEN', PhpOrder.NONE) || 0; - const blue = generator.valueToCode(block, 'BLUE', PhpOrder.NONE) || 0; - const functionName = generator.provideFunction_( - 'colour_rgb', - ` -function ${generator.FUNCTION_NAME_PLACEHOLDER_}($r, $g, $b) { - $r = round(max(min($r, 100), 0) * 2.55); - $g = round(max(min($g, 100), 0) * 2.55); - $b = round(max(min($b, 100), 0) * 2.55); - $hex = '#'; - $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); - return $hex; -} -`, - ); - const code = `${functionName}(${red}, ${green}, ${blue})`; - return [code, PhpOrder.FUNCTION_CALL]; -} - -/** - * Python block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PythonGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPython( - block: Block, - generator: PythonGenerator, -): [string, PythonOrder] { - // Compose a colour from RGB components expressed as percentages. - const functionName = generator.provideFunction_( - 'colour_rgb', - ` -def ${generator.FUNCTION_NAME_PLACEHOLDER_}(r, g, b): - r = round(min(100, max(0, r)) * 2.55) - g = round(min(100, max(0, g)) * 2.55) - b = round(min(100, max(0, b)) * 2.55) - return '#%02x%02x%02x' % (r, g, b) -`, - ); - const r = generator.valueToCode(block, 'RED', PythonOrder.NONE) || 0; - const g = generator.valueToCode(block, 'GREEN', PythonOrder.NONE) || 0; - const b = generator.valueToCode(block, 'BLUE', PythonOrder.NONE) || 0; - const code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; - return [code, PythonOrder.FUNCTION_CALL]; -} - -const definitionsDict = BlocklyCommon.createBlockDefinitionsFromJsonArray([ - jsonDefinition, -]); - -/** The colour_rgb BlockDefinition. */ -export const blockDefinition = definitionsDict[BLOCK_NAME]; - -/** - * Install the `colour_rgb` block and all of its dependencies. - * - * @param gens The CodeGenerators to install per-block - * generators on. - */ -export function installBlock(gens: Generators = {}) { - registerFieldColour(); - BlocklyCommon.defineBlocks(definitionsDict); - if (gens.javascript) gens.javascript.forBlock[BLOCK_NAME] = toJavascript; - if (gens.dart) { - gens.dart.forBlock[BLOCK_NAME] = toDart; - gens.dart.addReservedWords('Math'); - } - if (gens.lua) gens.lua.forBlock[BLOCK_NAME] = toLua; - if (gens.php) gens.php.forBlock[BLOCK_NAME] = toPhp; - if (gens.python) gens.python.forBlock[BLOCK_NAME] = toPython; -} diff --git a/plugins/field-colour/src/blocks/generatorsType.ts b/plugins/field-colour/src/blocks/generatorsType.ts deleted file mode 100644 index e9d2df460..000000000 --- a/plugins/field-colour/src/blocks/generatorsType.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {JavascriptGenerator} from 'blockly/javascript'; -import type {DartGenerator} from 'blockly/dart'; -import type {LuaGenerator} from 'blockly/lua'; -import type {PhpGenerator} from 'blockly/php'; -import type {PythonGenerator} from 'blockly/python'; - -/** - * An object containing zero or more generators. This is passed - * to block installation functions so that they may install - * per-block generators on any languages they support. - */ -export interface Generators { - javascript?: JavascriptGenerator; - dart?: DartGenerator; - lua?: LuaGenerator; - php?: PhpGenerator; - python?: PythonGenerator; -} diff --git a/plugins/field-colour/src/field_colour.ts b/plugins/field-colour/src/field_colour.ts deleted file mode 100644 index adb3396de..000000000 --- a/plugins/field-colour/src/field_colour.ts +++ /dev/null @@ -1,524 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Colour input field. - */ - -import * as Blockly from 'blockly/core'; -import { - FieldGridDropdown, - FieldGridDropdownConfig, - FieldGridDropdownFromJsonConfig, -} from '@blockly/field-grid-dropdown'; - -/* eslint-disable @typescript-eslint/naming-convention */ -/** - * An array of colour strings for the palette. - * Copied from goog.ui.ColorPicker.SIMPLE_GRID_COLORS - */ -const DEFAULT_COLOURS: Record = { - // greys - '#ffffff': 'White', - '#cccccc': 'Light Grey', - '#c0c0c0': 'Silver', - '#999999': 'Grey', - '#666666': 'Dark Grey', - '#333333': 'Charcoal', - '#000000': 'Black', - // reds - '#ffcccc': 'Pale Red', - '#ff6666': 'Light Red', - '#ff0000': 'Red', - '#cc0000': 'Dark Red', - '#990000': 'Darker Red', - '#660000': 'Maroon', - '#330000': 'Darkest Red', - // oranges - '#ffcc99': 'Peach', - '#ff9966': 'Light Orange', - '#ff9900': 'Orange', - '#ff6600': 'Bright Orange', - '#cc6600': 'Dark Orange', - '#993300': 'Rust', - '#663300': 'Brown', - // yellows - '#ffff99': 'Light Yellow', - '#ffff66': 'Pale Yellow', - '#ffcc66': 'Light Gold', - '#ffcc33': 'Gold', - '#cc9933': 'Goldenrod', - '#996633': 'Light Brown', - '#663333': 'Dark Brown', - // olives - '#ffffcc': 'Cream', - '#ffff33': 'Bright Yellow', - '#ffff00': 'Yellow', - '#ffcc00': 'Amber', - '#999900': 'Olive', - '#666600': 'Dark Olive', - '#333300': 'Darkest Olive', - // greens - '#99ff99': 'Light Green', - '#66ff99': 'Mint', - '#33ff33': 'Bright Green', - '#33cc00': 'Green', - '#009900': 'Dark Green', - '#006600': 'Darker Green', - '#003300': 'Darkest Green', - // turquoises - '#99ffff': 'Pale Cyan', - '#33ffff': 'Bright Cyan', - '#66cccc': 'Light Teal', - '#00cccc': 'Turquoise', - '#339999': 'Teal', - '#336666': 'Dark Teal', - '#003333': 'Darkest Teal', - // blues - '#ccffff': 'Pale Aqua', - '#66ffff': 'Light Cyan', - '#33ccff': 'Sky Blue', - '#3366ff': 'Blue', - '#3333ff': 'Bright Blue', - '#000099': 'Dark Blue', - '#000066': 'Navy', - // purples - '#ccccff': 'Pale Periwinkle', - '#9999ff': 'Periwinkle', - '#6666cc': 'Slate Blue', - '#6633ff': 'Violet', - '#6600cc': 'Purple', - '#333399': 'Indigo', - '#330099': 'Dark Indigo', - // violets - '#ffccff': 'Pale Magenta', - '#ff99ff': 'Light Magenta', - '#cc66cc': 'Orchid', - '#cc33cc': 'Magenta', - '#993399': 'Dark Magenta', - '#663366': 'Plum', - '#330033': 'Darkest Purple', -}; -/* eslint-enable @typescript-eslint/naming-convention */ - -/** - * Class for a colour input field. - */ -export class FieldColour extends FieldGridDropdown { - /** - * Used to tell if the field needs to be rendered the next time the block is - * rendered. Colour fields are statically sized, and only need to be - * rendered at initialization. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override isDirty_ = false; - - protected override ariaTypeName = Blockly.Msg['ARIA_TYPE_FIELD_COLOUR']; - - /** - * @param value The initial value of the field. Should be in '#rrggbb' - * format. Defaults to the first value in the default colour array. Also - * accepts Field.SKIP_SETUP if you wish to skip setup (only used by - * subclasses that want to handle configuration and setting the field - * value after their own constructors have run). - * @param validator A function that is called to validate changes to the - * field's value. Takes in a colour string & returns a validated colour - * string ('#rrggbb' format), or null to abort the change. - * @param config A map of options used to configure the field. - * See the [field creation documentation]{@link - * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/colour} - * for a list of properties this parameter supports. - */ - constructor( - value?: string | typeof Blockly.Field.SKIP_SETUP, - validator?: FieldColourValidator, - config?: FieldColourConfig, - ) { - const swatches = makeSwatches( - config?.colourOptions ?? Object.keys(DEFAULT_COLOURS), - config?.colourTitles, - ); - super(swatches, validator, {...config, columns: config?.columns ?? 7}); - - if (value === Blockly.Field.SKIP_SETUP) return; - this.setValue(value); - } - - /** - * FieldDropdown has complex behaviors for normalizing options that aren't - * applicable here. Instead, just return the options as-is. - * - * @param options The options (colour swatches) to normalize. - * @returns The colour swatches as-is. - */ - protected override trimOptions(options: Blockly.MenuOption[]) { - return {options}; - } - - /** - * Configure the field based on the given map of options. - * - * @param config A map of options to configure the field based on. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override configure_(config: FieldColourConfig) { - super.configure_(config); - if (config.colourOptions) { - this.setColours(config.colourOptions, config.colourTitles); - } - } - - /** - * Create the block UI for this colour field. - * - * @internal - */ - override initView() { - const constants = this.getConstants(); - // This can't happen, but TypeScript thinks it can and lint forbids `!.`. - if (!constants) throw Error('Constants not found'); - this.size_ = new Blockly.utils.Size( - constants.FIELD_COLOUR_DEFAULT_WIDTH, - constants.FIELD_COLOUR_DEFAULT_HEIGHT, - ); - if (this.isFullBlockField()) { - this.clickTarget_ = (this.sourceBlock_ as Blockly.BlockSvg).getSvgRoot(); - } else { - this.createBorderRect_(); - this.getBorderRect().style['fillOpacity'] = '1'; - } - - if (this.fieldGroup_) { - this.fieldGroup_.classList.add('blocklyField'); - } - - this.recomputeAriaContext(); - } - - /** - * Shows the colour picker dropdown attached to the field. - * - * @param e The event that triggered display of the colour picker dropdown. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override showEditor_(e?: MouseEvent) { - super.showEditor_(e); - Blockly.DropDownDiv.getContentDiv().classList.add('blocklyFieldColour'); - Blockly.DropDownDiv.repositionForWindowResize(); - } - - /** - * Defines whether this field should take up the full block or not. - * - * @returns True if this field should take up the full block. False otherwise. - */ - override isFullBlockField(): boolean { - const block = this.getSourceBlock(); - if (!block) throw new Blockly.UnattachedFieldError(); - - const constants = this.getConstants(); - return ( - this.blockIsSimpleReporter() && - Boolean(constants?.FIELD_COLOUR_FULL_BLOCK) - ); - } - - /** - * @returns True if the source block is a value block with a single editable - * field. - * @internal - */ - blockIsSimpleReporter(): boolean { - const block = this.getSourceBlock(); - if (!block) throw new Blockly.UnattachedFieldError(); - - if (!block.outputConnection) return false; - - for (const input of block.inputList) { - if (input.connection || input.fieldRow.length > 1) return false; - } - return true; - } - - /** - * Updates text field to match the colour/style of the block. - * - * @internal - */ - override applyColour() { - const block = this.getSourceBlock() as Blockly.BlockSvg | null; - if (!block) throw new Blockly.UnattachedFieldError(); - - if (!this.fieldGroup_) return; - - const borderRect = this.borderRect_; - - if (!this.isFullBlockField()) { - if (!borderRect) { - throw new Error('The border rect has not been initialized'); - } - borderRect.style.display = 'block'; - borderRect.style.fill = this.getValue() as string; - } else { - // In general, do *not* let fields control the color of blocks. Having the - // field control the color is unexpected, and could have performance - // impacts. - block.pathObject.svgPath.setAttribute('fill', this.getValue() as string); - } - this.recomputeAriaContext(); - } - - /** - * Returns the height and width of the field. - * - * This should *in general* be the only place render_ gets called from. - * - * @returns Height and width. - */ - override getSize(): Blockly.utils.Size { - if (this.getConstants()?.FIELD_COLOUR_FULL_BLOCK) { - // In general, do *not* let fields control the color of blocks. Having the - // field control the color is unexpected, and could have performance - // impacts. - // Full block fields have more control of the block than they should - // (i.e. updating fill colour) so they always need to be rerendered. - this.render_(); - this.isDirty_ = false; - } - return super.getSize(); - } - - /** - * Updates the colour of the block to reflect whether this is a full - * block field or not. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override render_() { - this.updateSize_(); - - const block = this.getSourceBlock() as Blockly.BlockSvg | null; - if (!block) throw new Blockly.UnattachedFieldError(); - // Calling applyColour updates the UI (full-block vs non-full-block) for the - // colour field, and the colour of the field/block. - block.applyColour(); - } - - /** - * Updates the size of the field based on whether it is a full block field - * or not. - * - * @param margin margin to use when positioning the field. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected updateSize_(margin?: number) { - const constants = this.getConstants(); - if (!constants) return; - let totalWidth; - let totalHeight; - if (this.isFullBlockField()) { - const xOffset = margin ?? 0; - totalWidth = xOffset * 2; - totalHeight = constants.FIELD_TEXT_HEIGHT; - } else { - totalWidth = constants.FIELD_COLOUR_DEFAULT_WIDTH; - totalHeight = constants.FIELD_COLOUR_DEFAULT_HEIGHT; - } - - this.size_.height = totalHeight; - this.size_.width = totalWidth; - - this.positionBorderRect_(); - } - - /** - * Ensure that the input value is a valid colour. - * - * @param newValue The input value. - * @returns A valid colour, or null if invalid. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue: string, - ): string | null | undefined; - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_(newValue?: string): string | null; - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doClassValidation_( - newValue?: string, - ): string | null | undefined { - if (typeof newValue !== 'string') { - return null; - } - return Blockly.utils.colour.parse(newValue); - } - - /** - * Get the text for this field. Used when the block is collapsed. - * - * @returns Text representing the value of this field. - */ - override getText(): string { - let colour = this.value_ as string; - // Try to use #rgb format if possible, rather than #rrggbb. - if (/^#(.)\1(.)\2(.)\3$/.test(colour)) { - colour = '#' + colour[1] + colour[3] + colour[5]; - } - return colour; - } - - /** - * Set a custom colour grid for this field. - * - * @param colours Array of colours for this block, or null to use default - * (FieldColour.COLOURS). - * @param titles Optional array of colour tooltips, or null to use default - * (FieldColour.TITLES). - * @returns Returns itself (for method chaining). - */ - setColours(colours: string[], titles?: string[]): FieldColour { - const swatches = makeSwatches(colours, titles); - this.setOptions(swatches); - return this; - } - - /** - * Construct a FieldColour from a JSON arg object. - * - * @param options A JSON object with options (colour). - * @returns The new field instance. - * @nocollapse - * @internal - */ - static fromJson(options: FieldColourFromJsonConfig): FieldColour { - // `this` might be a subclass of FieldColour if that class doesn't override - // the static fromJson method. - return new this(options.colour, undefined, options); - } -} - -/** - * Creates a set of divs representing colour swatches for use in the picker. - * - * @param colours An array of colours to create swatches for. The colours must - * be any legal CSS colour specifier. - * @param titles A corresponding array of titles to be displayed as tooltips on - * the colour swatches. - * @returns An array of pairs of DOM elements representing colour swatches and - * their corresponding colour. - */ -function makeSwatches( - colours: string[], - titles?: string[], -): Blockly.MenuOption[] { - return colours.map((colour, index) => { - const swatch = document.createElement('div'); - swatch.className = 'blocklyColourSwatch'; - swatch.style.backgroundColor = colour; - - if (titles && index < titles.length) { - swatch.title = titles[index]; - } - return [swatch, colour, titles?.[index] ?? DEFAULT_COLOURS[colour]]; - }); -} - -/** The default value for this field. */ -FieldColour.prototype.DEFAULT_VALUE = '#ffffff'; - -/** - * Register the field and any dependencies. - */ -export function registerFieldColour() { - Blockly.fieldRegistry.register('field_colour', FieldColour); -} - -/** - * CSS for colour picker. - */ -Blockly.Css.register(` -.blocklyFieldColour .blocklyFieldGridItemSelected, -.blocklyFieldGridItemSelected:hover { - border-color: #eee !important; - outline: 1px solid #333; - position: relative; -} - -.blocklyColourSwatch { - width: 20px; - height: 20px; -} - -.blocklyGridContainer { - padding: 0px; -} - -.blocklyFieldColour .blocklyFieldGrid { - grid-gap: 0px; - row-gap: 4px; -} - -.blocklyFieldColour .blocklyFieldGrid .blocklyGridItem { - border-radius: 0; - padding: 0; - border: 0.5px solid #888; - cursor: pointer; -} - -.blocklyFieldColour .blocklyFieldGrid .blocklyFieldGridItem { - border: 0.5px solid #888; - padding: 0; - margin: 0; - border-radius: 0; -} - -.blocklyFieldColour .blocklyFieldGrid .blocklyFieldGridItem:focus { - border-color: #eee; - box-shadow: 2px 2px 7px 2px rgba(0, 0, 0, 0.3); - position: relative; - border-radius: 0; - outline: none; -} - -.blocklyKeyboardNavigation .blocklyFieldColour .blocklyFieldGrid .blocklyFieldGridItem:focus { - outline: var(--blockly-selection-width) solid var(--blockly-active-node-color); - outline-offset: -2px; - border: none; - box-shadow: none; - border-radius: 4px; -} -`); - -/** - * Config options for the colour field. - */ -export interface FieldColourConfig extends FieldGridDropdownConfig { - colourOptions?: string[]; - colourTitles?: string[]; -} - -/** - * fromJson config options for the colour field. - */ -export interface FieldColourFromJsonConfig extends FieldGridDropdownFromJsonConfig { - colour?: string; -} - -/** - * A function that is called to validate changes to the field's value before - * they are set. - * - * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} - * @param newValue The value to be validated. - * @returns One of three instructions for setting the new value: `T`, `null`, - * or `undefined`. - * - * - `T` to set this function's returned value instead of `newValue`. - * - * - `null` to invoke `doValueInvalid_` and not set a value. - * - * - `undefined` to set `newValue` as is. - */ -export type FieldColourValidator = Blockly.FieldValidator; diff --git a/plugins/field-colour/src/index.ts b/plugins/field-colour/src/index.ts deleted file mode 100644 index b0474b0b4..000000000 --- a/plugins/field-colour/src/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './field_colour'; - -import * as colourPicker from './blocks/colourPicker'; -import * as colourRandom from './blocks/colourRandom'; -import * as colourRgb from './blocks/colourRgb'; -import * as colourBlend from './blocks/colourBlend'; -import {Generators} from './blocks/generatorsType'; - -// Re-export all parts of the definition. -export * as colourPicker from './blocks/colourPicker'; -export * as colourRandom from './blocks/colourRandom'; -export * as colourRgb from './blocks/colourRgb'; -export * as colourBlend from './blocks/colourBlend'; - -/** - * Install all of the blocks defined in this file and all of their - * dependencies. - * - * @param generators The CodeGenerators to install per-block - * generators on. - */ -export function installAllBlocks(generators: Generators = {}) { - colourPicker.installBlock(generators); - colourRgb.installBlock(generators); - colourRandom.installBlock(generators); - colourBlend.installBlock(generators); -} diff --git a/plugins/field-colour/test/blocks_test.mocha.js b/plugins/field-colour/test/blocks_test.mocha.js deleted file mode 100644 index fea374f6e..000000000 --- a/plugins/field-colour/test/blocks_test.mocha.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import fs from 'fs'; -import * as Blockly from 'blockly/core'; -import 'blockly/blocks'; - -import {javascriptGenerator} from 'blockly/javascript'; -import {dartGenerator} from 'blockly/dart'; -import {phpGenerator} from 'blockly/php'; -import {pythonGenerator} from 'blockly/python'; -import {luaGenerator} from 'blockly/lua'; -import {installAllBlocks} from '../src/index'; -import {assert} from 'chai'; - -const blockJson = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'colour_picker', - x: 13, - y: 13, - fields: { - COLOUR: '#ff0000', - }, - }, - { - type: 'colour_random', - x: 13, - y: 113, - }, - { - type: 'colour_rgb', - x: 13, - y: 263, - inputs: { - RED: { - shadow: { - type: 'math_number', - fields: { - NUM: 0, - }, - }, - }, - GREEN: { - shadow: { - type: 'math_number', - fields: { - NUM: 1, - }, - }, - }, - BLUE: { - shadow: { - type: 'math_number', - fields: { - NUM: 20, - }, - }, - }, - }, - }, - { - type: 'colour_blend', - x: 13, - y: 363, - inputs: { - COLOUR1: { - shadow: { - type: 'colour_picker', - fields: { - COLOUR: '#ff0000', - }, - }, - }, - COLOUR2: { - shadow: { - type: 'colour_picker', - fields: { - COLOUR: '#3333ff', - }, - }, - }, - RATIO: { - shadow: { - type: 'math_number', - fields: { - NUM: 0.5, - }, - }, - }, - }, - }, - { - type: 'colour_picker', - x: 13, - y: 63, - fields: { - COLOUR: '#3333ff', - }, - }, - { - type: 'colour_rgb', - x: 13, - y: 163, - inputs: { - RED: { - shadow: { - type: 'math_number', - fields: { - NUM: 100, - }, - }, - }, - GREEN: { - shadow: { - type: 'math_number', - fields: { - NUM: 50, - }, - }, - }, - BLUE: { - shadow: { - type: 'math_number', - fields: { - NUM: 0, - }, - }, - }, - }, - }, - { - type: 'colour_blend', - x: 13, - y: 463, - inputs: { - COLOUR1: { - shadow: { - type: 'colour_picker', - fields: { - COLOUR: '#000000', - }, - }, - }, - COLOUR2: { - shadow: { - type: 'colour_picker', - fields: { - COLOUR: '#ffffff', - }, - }, - }, - RATIO: { - shadow: { - type: 'math_number', - fields: { - NUM: 0.3, - }, - }, - }, - }, - }, - ], - }, -}; - -/** - * Assert that the generated code matches the golden code for the specified - * language. - * @param {string} suffix The suffix of the golden file. - * @param {string} generated The generated code to compare against the - * golden file. - */ -function checkResult(suffix, generated) { - const fileName = `test/golden/golden.${suffix}`; - const goldenContents = fs.readFileSync(fileName); - // Normalize the line feeds. - const normalized = goldenContents.toString().replace(/(?:\r\n|\r|\n)/g, '\n'); - assert.equal(generated, normalized); -} - -suite('Colour Block Generators', function () { - suiteSetup(function () { - installAllBlocks({ - javascript: javascriptGenerator, - dart: dartGenerator, - lua: luaGenerator, - python: pythonGenerator, - php: phpGenerator, - }); - }); - setup(function () { - this.jsdomCleanup = require('jsdom-global')( - '

    ', - ); - this.workspace = new Blockly.Workspace(); - Blockly.serialization.workspaces.load(blockJson, this.workspace); - }); - test('JavaScript', function () { - const generated = javascriptGenerator.workspaceToCode(this.workspace); - checkResult('js', generated); - }); - test('Dart', function () { - const generated = dartGenerator.workspaceToCode(this.workspace); - checkResult('dart', generated); - }); - test('Lua', function () { - const generated = luaGenerator.workspaceToCode(this.workspace); - checkResult('lua', generated); - }); - test('Python', function () { - const generated = pythonGenerator.workspaceToCode(this.workspace); - checkResult('py', generated); - }); - test('PHP', function () { - const generated = phpGenerator.workspaceToCode(this.workspace); - checkResult('php', generated); - }); - teardown(function () { - this.jsdomCleanup(); - this.workspace.dispose(); - }); -}); diff --git a/plugins/field-colour/test/field_colour_test.mocha.js b/plugins/field-colour/test/field_colour_test.mocha.js deleted file mode 100644 index 057bcab12..000000000 --- a/plugins/field-colour/test/field_colour_test.mocha.js +++ /dev/null @@ -1,389 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {testHelpers} = require('@blockly/dev-tools'); -const {FieldColour, registerFieldColour} = require('../src/index'); -const {assert} = require('chai'); - -const { - assertFieldValue, - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -suite('FieldColour', function () { - setup(function () { - registerFieldColour(); - this.jsdomCleanup = require('jsdom-global')( - '
    ', - ); - }); - - teardown(function () { - this.jsdomCleanup(); - }); - - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = [ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - {title: 'NaN', value: NaN}, - {title: 'Non-Parsable String', value: 'bad-string'}, - {title: 'Integer', value: 1}, - {title: 'Float', value: 1.5}, - {title: 'Infinity', value: Infinity}, - {title: 'Negative Infinity', value: -Infinity}, - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = [ - { - title: '#AAAAAA', - value: '#AAAAAA', - expectedValue: '#aaaaaa', - expectedText: '#aaa', - }, - { - title: '#aaaaaa', - value: '#aaaaaa', - expectedValue: '#aaaaaa', - expectedText: '#aaa', - }, - { - title: '#AAAA00', - value: '#AAAA00', - expectedValue: '#aaaa00', - expectedText: '#aa0', - }, - { - title: '#aaaA00', - value: '#aaaA00', - expectedValue: '#aaaa00', - expectedText: '#aa0', - }, - { - title: '#BCBCBC', - value: '#BCBCBC', - expectedValue: '#bcbcbc', - expectedText: '#bcbcbc', - }, - { - title: '#bcbcbc', - value: '#bcbcbc', - expectedValue: '#bcbcbc', - expectedText: '#bcbcbc', - }, - { - title: '#AA0', - value: '#AA0', - expectedValue: '#aaaa00', - expectedText: '#aa0', - }, - { - title: '#aa0', - value: '#aa0', - expectedValue: '#aaaa00', - expectedText: '#aa0', - }, - { - title: 'rgb(170, 170, 0)', - value: 'rgb(170, 170, 0)', - expectedValue: '#aaaa00', - expectedText: '#aa0', - }, - { - title: 'red', - value: 'red', - expectedValue: '#ff0000', - expectedText: '#f00', - }, - ]; - const addArgsAndJson = function (testCase) { - testCase.args = [testCase.value]; - testCase.json = {colour: testCase.value}; - }; - invalidValueTestCases.forEach(addArgsAndJson); - validValueTestCases.forEach(addArgsAndJson); - - /** - * The expected default value for the field being tested. - * @type {*} - */ - const defaultFieldValue = FieldColour.prototype.DEFAULT_VALUE; - - /** - * The expected default text for the field being tested. - * @type {*} - */ - const defaultTextValue = (function () { - let expectedText = defaultFieldValue; - const m = defaultFieldValue.match(/^#(.)\1(.)\2(.)\3$/); - if (m) { - expectedText = '#' + m[1] + m[2] + m[3]; - } - return expectedText; - })(); - /** - * Asserts that the field property values are set to default. - * @param {!FieldColour} field The field to check. - */ - const assertFieldDefault = function (field) { - assertFieldValue(field, defaultFieldValue, defaultTextValue); - }; - - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldColour} field The field to check. - * @param {FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertFieldValue(field, testCase.expectedValue, testCase.expectedText); - }; - - runConstructorSuiteTests( - FieldColour, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runFromJsonSuiteTests( - FieldColour, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - suite('setValue', function () { - /** - * Create a mock block that may be used as the source block for a field. - * @returns {!Object} Mock block. - */ - function createBlockMock() { - return { - id: 'test', - rendered: false, - workspace: { - rendered: false, - }, - renameVarById: Blockly.Block.prototype.renameVarById, - updateVarName: Blockly.Block.prototype.updateVarName, - isShadow: () => false, - isDeadOrDying: () => false, - }; - } - - suite('Empty -> New Value', function () { - setup(function () { - this.field = new FieldColour(); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - defaultFieldValue, - defaultTextValue, - ); - test('With source block', function () { - this.field.setSourceBlock(createBlockMock()); - this.field.setValue('#bcbcbc'); - assertFieldValue(this.field, '#bcbcbc', '#bcbcbc'); - }); - }); - suite('Value -> New Value', function () { - setup(function () { - this.field = new FieldColour('#aaaaaa'); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - '#aaaaaa', - '#aaa', - ); - test('With source block', function () { - this.field.setSourceBlock(createBlockMock()); - this.field.setValue('#bcbcbc'); - assertFieldValue(this.field, '#bcbcbc', '#bcbcbc'); - }); - }); - }); - - suite('Validators', function () { - setup(function () { - this.field = new FieldColour('#aaaaaa'); - }); - const testSuites = [ - { - title: 'Null Validator', - validator: function () { - return null; - }, - value: '#000000', - expectedValue: '#aaaaaa', - expectedText: '#aaa', - }, - { - title: 'Force Full Red Validator', - validator: function (newValue) { - return '#ff' + newValue.substr(3, 4); - }, - value: '#000000', - expectedValue: '#ff0000', - expectedText: '#f00', - }, - { - title: 'Returns Undefined Validator', - validator: function () {}, - value: '#000000', - expectedValue: '#000000', - expectedText: '#000', - }, - ]; - testSuites.forEach(function (suiteInfo) { - suite(suiteInfo.title, function () { - setup(function () { - this.field.setValidator(suiteInfo.validator); - }); - test('New Value', function () { - this.field.setValue(suiteInfo.value); - assertFieldValue( - this.field, - suiteInfo.expectedValue, - suiteInfo.expectedText, - ); - }); - }); - }); - }); - - suite('Customizations', function () { - suite('Colours and Titles', function () { - /** - * Verify that the list of colours and titles are as expected. - * @param {!FieldColour} field Field to test. - * @param {!Array[string]} expectedColours Array of colour names. - * @param {!Array[string]} expectedTitles Array of title names. - */ - function assertColoursAndTitles(field, expectedColours, expectedTitles) { - const options = field.getOptions(); - const actualColours = options.map((option) => - Blockly.utils.colour.parse(option[0].style.backgroundColor), - ); - const actualTitles = options - .map((option) => option[0].title) - .filter((title) => !!title); - assert.equal(String(actualColours), String(expectedColours)); - assert.equal(String(actualTitles), String(expectedTitles)); - } - test('JS Constructor', function () { - const field = new FieldColour('#aaaaaa', null, { - colourOptions: ['#aaaaaa'], - colourTitles: ['grey'], - }); - assertColoursAndTitles(field, ['#aaaaaa'], ['grey']); - }); - test('JSON Definition', function () { - const field = FieldColour.fromJson({ - colour: '#aaaaaa', - colourOptions: ['#aaaaaa'], - colourTitles: ['grey'], - }); - assertColoursAndTitles(field, ['#aaaaaa'], ['grey']); - }); - test('setColours', function () { - const field = new FieldColour(); - field.setColours(['#aaaaaa'], ['grey']); - assertColoursAndTitles(field, ['#aaaaaa'], ['grey']); - }); - test('Titles Undefined', function () { - const field = new FieldColour(); - field.setColours(['#aaaaaa']); - assertColoursAndTitles(field, ['#aaaaaa'], []); - }); - test('Some Titles Undefined', function () { - const field = new FieldColour(); - field.setColours(['#aaaaaa', '#ff0000'], ['grey']); - assertColoursAndTitles(field, ['#aaaaaa', '#ff0000'], ['grey']); - }); - }); - - suite('Columns', function () { - /** - * Verify that the number of columns is as expected. - * @param {!FieldColour} field Field to test. - * @param {number} expectedColumns Number of columns field should have. - */ - function assertColumns(field, expectedColumns) { - const actualColumns = field.columns || FieldColour.COLUMNS; - assert.equal(actualColumns, expectedColumns); - } - test('JS Constructor', function () { - const field = new FieldColour('#ffffff', null, {columns: 3}); - assertColumns(field, 3); - }); - test('JSON Definition', function () { - const field = FieldColour.fromJson({ - colour: '#ffffff', - columns: 3, - }); - assertColumns(field, 3); - }); - test('setColumns', function () { - const field = new FieldColour(); - field.setColumns(3); - assertColumns(field, 3); - }); - }); - }); - - suite('Serialization', function () { - setup(function () { - this.workspace = new Blockly.Workspace(); - Blockly.defineBlocksWithJsonArray([ - { - type: 'row_block', - message0: '%1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - output: null, - }, - ]); - - this.assertValue = (value) => { - const block = this.workspace.newBlock('row_block'); - const field = new FieldColour(value); - block.getInput('INPUT').appendField(field, 'COLOUR'); - const jso = Blockly.serialization.blocks.save(block); - assert.deepEqual(jso['fields'], {COLOUR: value}); - }; - }); - - teardown(function () { - this.workspace.dispose(); - }); - - test('Three char', function () { - this.assertValue('#001122'); - }); - - test('Six char', function () { - this.assertValue('#012345'); - }); - }); -}); diff --git a/plugins/field-colour/test/golden/golden.dart b/plugins/field-colour/test/golden/golden.dart deleted file mode 100644 index 80f9f8193..000000000 --- a/plugins/field-colour/test/golden/golden.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'dart:math' as Math; - -String colour_random() { - String hex = '0123456789abcdef'; - var rnd = new Math.Random(); - return '#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}' - '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}' - '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'; -} - -String colour_rgb(num r, num g, num b) { - num rn = (Math.max(Math.min(r, 100), 0) * 2.55).round(); - String rs = rn.toInt().toRadixString(16); - rs = '0$rs'; - rs = rs.substring(rs.length - 2); - num gn = (Math.max(Math.min(g, 100), 0) * 2.55).round(); - String gs = gn.toInt().toRadixString(16); - gs = '0$gs'; - gs = gs.substring(gs.length - 2); - num bn = (Math.max(Math.min(b, 100), 0) * 2.55).round(); - String bs = bn.toInt().toRadixString(16); - bs = '0$bs'; - bs = bs.substring(bs.length - 2); - return '#$rs$gs$bs'; -} - -String colour_blend(String c1, String c2, num ratio) { - ratio = Math.max(Math.min(ratio, 1), 0); - int r1 = int.parse('0x${c1.substring(1, 3)}'); - int g1 = int.parse('0x${c1.substring(3, 5)}'); - int b1 = int.parse('0x${c1.substring(5, 7)}'); - int r2 = int.parse('0x${c2.substring(1, 3)}'); - int g2 = int.parse('0x${c2.substring(3, 5)}'); - int b2 = int.parse('0x${c2.substring(5, 7)}'); - num rn = (r1 * (1 - ratio) + r2 * ratio).round(); - String rs = rn.toInt().toRadixString(16); - num gn = (g1 * (1 - ratio) + g2 * ratio).round(); - String gs = gn.toInt().toRadixString(16); - num bn = (b1 * (1 - ratio) + b2 * ratio).round(); - String bs = bn.toInt().toRadixString(16); - rs = '0$rs'; - rs = rs.substring(rs.length - 2); - gs = '0$gs'; - gs = gs.substring(gs.length - 2); - bs = '0$bs'; - bs = bs.substring(bs.length - 2); - return '#$rs$gs$bs'; -} - - -main() { - '#ff0000'; - - '#3333ff'; - - colour_random(); - - colour_rgb(100, 50, 0); - - colour_rgb(0, 1, 20); - - colour_blend('#ff0000', '#3333ff', 0.5); - - colour_blend('#000000', '#ffffff', 0.3); -} \ No newline at end of file diff --git a/plugins/field-colour/test/golden/golden.js b/plugins/field-colour/test/golden/golden.js deleted file mode 100644 index 368b4f101..000000000 --- a/plugins/field-colour/test/golden/golden.js +++ /dev/null @@ -1,46 +0,0 @@ -function colourRandom() { - var num = Math.floor(Math.random() * 0x1000000); - return '#' + ('00000' + num.toString(16)).substr(-6); -} - -function colourRgb(r, g, b) { - r = Math.max(Math.min(Number(r), 100), 0) * 2.55; - g = Math.max(Math.min(Number(g), 100), 0) * 2.55; - b = Math.max(Math.min(Number(b), 100), 0) * 2.55; - r = ('0' + (Math.round(r) || 0).toString(16)).slice(-2); - g = ('0' + (Math.round(g) || 0).toString(16)).slice(-2); - b = ('0' + (Math.round(b) || 0).toString(16)).slice(-2); - return '#' + r + g + b; -} - -function colourBlend(c1, c2, ratio) { - ratio = Math.max(Math.min(Number(ratio), 1), 0); - var r1 = parseInt(c1.substring(1, 3), 16); - var g1 = parseInt(c1.substring(3, 5), 16); - var b1 = parseInt(c1.substring(5, 7), 16); - var r2 = parseInt(c2.substring(1, 3), 16); - var g2 = parseInt(c2.substring(3, 5), 16); - var b2 = parseInt(c2.substring(5, 7), 16); - var r = Math.round(r1 * (1 - ratio) + r2 * ratio); - var g = Math.round(g1 * (1 - ratio) + g2 * ratio); - var b = Math.round(b1 * (1 - ratio) + b2 * ratio); - r = ('0' + (r || 0).toString(16)).slice(-2); - g = ('0' + (g || 0).toString(16)).slice(-2); - b = ('0' + (b || 0).toString(16)).slice(-2); - return '#' + r + g + b; -} - - -'#ff0000'; - -'#3333ff'; - -colourRandom(); - -colourRgb(100, 50, 0); - -colourRgb(0, 1, 20); - -colourBlend('#ff0000', '#3333ff', 0.5); - -colourBlend('#000000', '#ffffff', 0.3); diff --git a/plugins/field-colour/test/golden/golden.lua b/plugins/field-colour/test/golden/golden.lua deleted file mode 100644 index 4fdf506d4..000000000 --- a/plugins/field-colour/test/golden/golden.lua +++ /dev/null @@ -1,35 +0,0 @@ -function colour_rgb(r, g, b) - r = math.floor(math.min(100, math.max(0, r)) * 2.55 + .5) - g = math.floor(math.min(100, math.max(0, g)) * 2.55 + .5) - b = math.floor(math.min(100, math.max(0, b)) * 2.55 + .5) - return string.format("#%02x%02x%02x", r, g, b) -end - -function colour_blend(colour1, colour2, ratio) - local r1 = tonumber(string.sub(colour1, 2, 3), 16) - local r2 = tonumber(string.sub(colour2, 2, 3), 16) - local g1 = tonumber(string.sub(colour1, 4, 5), 16) - local g2 = tonumber(string.sub(colour2, 4, 5), 16) - local b1 = tonumber(string.sub(colour1, 6, 7), 16) - local b2 = tonumber(string.sub(colour2, 6, 7), 16) - local ratio = math.min(1, math.max(0, ratio)) - local r = math.floor(r1 * (1 - ratio) + r2 * ratio + .5) - local g = math.floor(g1 * (1 - ratio) + g2 * ratio + .5) - local b = math.floor(b1 * (1 - ratio) + b2 * ratio + .5) - return string.format("#%02x%02x%02x", r, g, b) -end - - -local _ = '#ff0000' - -local _ = '#3333ff' - -local _ = string.format("#%06x", math.random(0, 2^24 - 1)) - -local _ = colour_rgb(100, 50, 0) - -local _ = colour_rgb(0, 1, 20) - -local _ = colour_blend('#ff0000', '#3333ff', 0.5) - -local _ = colour_blend('#000000', '#ffffff', 0.3) diff --git a/plugins/field-colour/test/golden/golden.php b/plugins/field-colour/test/golden/golden.php deleted file mode 100644 index 9f2fde50a..000000000 --- a/plugins/field-colour/test/golden/golden.php +++ /dev/null @@ -1,47 +0,0 @@ -function colour_random() { - return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT); -} - -function colour_rgb($r, $g, $b) { - $r = round(max(min($r, 100), 0) * 2.55); - $g = round(max(min($g, 100), 0) * 2.55); - $b = round(max(min($b, 100), 0) * 2.55); - $hex = '#'; - $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); - return $hex; -} - -function colour_blend($c1, $c2, $ratio) { - $ratio = max(min($ratio, 1), 0); - $r1 = hexdec(substr($c1, 1, 2)); - $g1 = hexdec(substr($c1, 3, 2)); - $b1 = hexdec(substr($c1, 5, 2)); - $r2 = hexdec(substr($c2, 1, 2)); - $g2 = hexdec(substr($c2, 3, 2)); - $b2 = hexdec(substr($c2, 5, 2)); - $r = round($r1 * (1 - $ratio) + $r2 * $ratio); - $g = round($g1 * (1 - $ratio) + $g2 * $ratio); - $b = round($b1 * (1 - $ratio) + $b2 * $ratio); - $hex = '#'; - $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT); - $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT); - return $hex; -} - - -'#ff0000'; - -'#3333ff'; - -colour_random(); - -colour_rgb(100, 50, 0); - -colour_rgb(0, 1, 20); - -colour_blend('#ff0000', '#3333ff', 0.5); - -colour_blend('#000000', '#ffffff', 0.3); diff --git a/plugins/field-colour/test/golden/golden.py b/plugins/field-colour/test/golden/golden.py deleted file mode 100644 index 7320b8624..000000000 --- a/plugins/field-colour/test/golden/golden.py +++ /dev/null @@ -1,32 +0,0 @@ -import random - -def colour_rgb(r, g, b): - r = round(min(100, max(0, r)) * 2.55) - g = round(min(100, max(0, g)) * 2.55) - b = round(min(100, max(0, b)) * 2.55) - return '#%02x%02x%02x' % (r, g, b) - -def colour_blend(colour1, colour2, ratio): - r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16) - g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16) - b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16) - ratio = min(1, max(0, ratio)) - r = round(r1 * (1 - ratio) + r2 * ratio) - g = round(g1 * (1 - ratio) + g2 * ratio) - b = round(b1 * (1 - ratio) + b2 * ratio) - return '#%02x%02x%02x' % (r, g, b) - - -'#ff0000' - -'#3333ff' - -'#%06x' % random.randint(0, 2**24 - 1) - -colour_rgb(100, 50, 0) - -colour_rgb(0, 1, 20) - -colour_blend('#ff0000', '#3333ff', 0.5) - -colour_blend('#000000', '#ffffff', 0.3) diff --git a/plugins/field-colour/test/index.html b/plugins/field-colour/test/index.html deleted file mode 100644 index 60fa9f5b2..000000000 --- a/plugins/field-colour/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Colour Playground - - - - -
    - - - diff --git a/plugins/field-colour/test/index.ts b/plugins/field-colour/test/index.ts deleted file mode 100644 index 722d0629e..000000000 --- a/plugins/field-colour/test/index.ts +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Colour field test playground. - */ - -import * as Blockly from 'blockly'; -import {javascriptGenerator} from 'blockly/javascript'; -import {dartGenerator} from 'blockly/dart'; -import {phpGenerator} from 'blockly/php'; -import {pythonGenerator} from 'blockly/python'; -import {luaGenerator} from 'blockly/lua'; - -import {createPlayground} from '@blockly/dev-tools'; -import {installAllBlocks as installColourBlocks} from '../src/index'; - -/** - * An array of blocks that are defined only for the purposes of - * manually and visually testing the colour field. - */ -const testBlockDefinitions = [ - { - type: 'test_standard_field_values', - message0: '%1', - args0: [ - { - type: 'field_colour', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_colour`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values', - message0: '%1', - args0: [ - { - type: 'field_colour', - name: 'FIELDNAME', - colour: '#ff4040', - colourOptions: [ - '#ff4040', - '#ff8080', - '#ffc0c0', - '#4040ff', - '#8080ff', - '#c0c0ff', - ], - colourTitles: [ - 'dark pink', - 'pink', - 'light pink', - 'dark blue', - 'blue', - 'light blue', - ], - columns: 3, - alt: { - type: 'field_label', - text: `No field_colour`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_standard_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_colour', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_colour`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_colour', - name: 'FIELDNAME', - colour: '#ff4040', - colourOptions: [ - '#ff4040', - '#ff8080', - '#ffc0c0', - '#4040ff', - '#8080ff', - '#c0c0ff', - ], - colourTitles: [ - 'dark pink', - 'pink', - 'light pink', - 'dark blue', - 'blue', - 'light blue', - ], - columns: 3, - alt: { - type: 'field_label', - text: `No field_colour`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_parent_block', - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }, -]; - -Blockly.defineBlocksWithJsonArray(testBlockDefinitions); - -/** - * A test toolbox containing the exported blocks and a variety of - * test blocks to exercise the colour field in different contexts - * (on a shadow block, as the only field on a block, etc). - * These are in a simple toolbox, rather than a category toolbox, so that - * they are all instantiated every time the test page is opened. - */ -const jsonToolbox = { - contents: [ - { - kind: 'label', - text: 'Exported blocks', - }, - { - kind: 'block', - type: 'colour_blend', - }, - { - kind: 'block', - type: 'colour_picker', - }, - { - kind: 'block', - type: 'colour_random', - }, - { - kind: 'block', - type: 'colour_rgb', - }, - { - kind: 'label', - text: 'Test blocks: default field values', - }, - { - kind: 'block', - type: 'test_standard_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_standard_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: custom field values', - }, - { - kind: 'block', - type: 'test_custom_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values_and_label', - }, - }, - }, - }, - ], -}; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - installColourBlocks({ - javascript: javascriptGenerator, - dart: dartGenerator, - lua: luaGenerator, - python: pythonGenerator, - php: phpGenerator, - }); - - const defaultOptions: Blockly.BlocklyOptions = { - toolbox: jsonToolbox, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/field-colour/tsconfig.json b/plugins/field-colour/tsconfig.json deleted file mode 100644 index 46b8e73f3..000000000 --- a/plugins/field-colour/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true, - "lib": ["ES2020", "dom"] - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-date/.gitignore b/plugins/field-date/.gitignore deleted file mode 100644 index 800f3a80c..000000000 --- a/plugins/field-date/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build -/dist - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/plugins/field-date/CHANGELOG.md b/plugins/field-date/CHANGELOG.md deleted file mode 100644 index bb33b4584..000000000 --- a/plugins/field-date/CHANGELOG.md +++ /dev/null @@ -1,685 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Improve accessibility of `FieldDate` ([#2698](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2698)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [10.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-date@10.0.8...@blockly/field-date@10.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-date@10.0.7...@blockly/field-date@10.0.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-date@10.0.6...@blockly/field-date@10.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [10.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-date@10.0.5...@blockly/field-date@10.0.6) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-date@10.0.4...@blockly/field-date@10.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-date@10.0.3...@blockly/field-date@10.0.4) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-date@10.0.2...@blockly/field-date@10.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-date@10.0.1...@blockly/field-date@10.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-date@10.0.0...@blockly/field-date@10.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [10.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.16...@blockly/field-date@10.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [9.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.15...@blockly/field-date@9.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.14...@blockly/field-date@9.0.15) (2025-05-15) - - -### Bug Fixes - -* Wait for an animation frame before showing the date picker ([e3b1054](https://github.com/google/blockly-samples/commit/e3b1054eb0b511aa4ab270725c989369270ee8d6)) - - - - - -## [9.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.13...@blockly/field-date@9.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.12...@blockly/field-date@9.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.11...@blockly/field-date@9.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.10...@blockly/field-date@9.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.9...@blockly/field-date@9.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [9.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.8...@blockly/field-date@9.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [9.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.7...@blockly/field-date@9.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [9.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.6...@blockly/field-date@9.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.5...@blockly/field-date@9.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.4...@blockly/field-date@9.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.3...@blockly/field-date@9.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.2...@blockly/field-date@9.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.1...@blockly/field-date@9.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [9.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-date@9.0.0...@blockly/field-date@9.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [9.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.17...@blockly/field-date@9.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* remove some uses of generateFieldTextBlocks ([#2357](https://github.com/google/blockly-samples/issues/2357)) ([53b3fa4](https://github.com/google/blockly-samples/commit/53b3fa4604aabb1fc5240d41c8d1d389d4b15301)) - - - -## [8.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.16...@blockly/field-date@8.0.17) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.15...@blockly/field-date@8.0.16) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.14...@blockly/field-date@8.0.15) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.13...@blockly/field-date@8.0.14) (2024-04-04) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.12...@blockly/field-date@8.0.13) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.11...@blockly/field-date@8.0.12) (2024-02-16) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.10...@blockly/field-date@8.0.11) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.9...@blockly/field-date@8.0.10) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.8...@blockly/field-date@8.0.9) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.7...@blockly/field-date@8.0.8) (2023-11-09) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.6...@blockly/field-date@8.0.7) (2023-11-02) - - -### Bug Fixes - -* publish types for field-date ([#2049](https://github.com/google/blockly-samples/issues/2049)) ([2086712](https://github.com/google/blockly-samples/commit/20867125156005b346056080057ba95219f73b29)) - - - -## [8.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.5...@blockly/field-date@8.0.6) (2023-10-30) - - -### Bug Fixes - -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [8.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.4...@blockly/field-date@8.0.5) (2023-09-21) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.3...@blockly/field-date@8.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.2...@blockly/field-date@8.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.1...@blockly/field-date@8.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-date@8.0.0...@blockly/field-date@8.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [8.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-date@7.0.1...@blockly/field-date@8.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [7.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-date@7.0.0...@blockly/field-date@7.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [7.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.1.2...@blockly/field-date@7.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [6.1.2](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.1.1...@blockly/field-date@6.1.2) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.1.0...@blockly/field-date@6.1.1) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.1.0](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.14...@blockly/field-date@6.1.0) (2023-05-11) - - -### Features - -* Add angle, colour, and multiline fields. (Rebase of [#1674](https://github.com/google/blockly-samples/issues/1674)) ([#1693](https://github.com/google/blockly-samples/issues/1693)) ([1b447f4](https://github.com/google/blockly-samples/commit/1b447f41d6293f14e846b8a4d82d289a5637a99a)) - - - -## [6.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.13...@blockly/field-date@6.0.14) (2023-05-04) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.12...@blockly/field-date@6.0.13) (2023-04-27) - - -### Bug Fixes - -* Correct date field test assertions ([#1673](https://github.com/google/blockly-samples/issues/1673)) ([9974e85](https://github.com/google/blockly-samples/commit/9974e85becaa8ad17e35b588b95391c85865dafd)) - - - -## [6.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.11...@blockly/field-date@6.0.12) (2023-03-23) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.10...@blockly/field-date@6.0.11) (2023-03-09) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.9...@blockly/field-date@6.0.10) (2023-03-02) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.8...@blockly/field-date@6.0.9) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [6.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.7...@blockly/field-date@6.0.8) (2023-02-23) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.6...@blockly/field-date@6.0.7) (2023-02-16) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.5...@blockly/field-date@6.0.6) (2023-02-09) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.4...@blockly/field-date@6.0.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.3...@blockly/field-date@6.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.2...@blockly/field-date@6.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.1...@blockly/field-date@6.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-date@6.0.0...@blockly/field-date@6.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-date@5.0.22...@blockly/field-date@6.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) -* update field-date to es6 class (#1295) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) -* update field-date to es6 class ([#1295](https://github.com/google/blockly-samples/issues/1295)) ([9b70b03](https://github.com/google/blockly-samples/commit/9b70b0300c625c0cddc1eea241a3d2c2200344f8)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 5.0.22 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 5.0.21 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 5.0.19 (2022-07-21) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## 5.0.18 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 5.0.17 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 5.0.16 (2022-06-21) - -**Note:** Version bump only for package @blockly/field-date - - - - - -## 5.0.15 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 5.0.14 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/field-date/README.md b/plugins/field-date/README.md deleted file mode 100644 index 8b44897f6..000000000 --- a/plugins/field-date/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# @blockly/field-date [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) plugin that uses a browser default "date" input. - -## Installation - -### Yarn - -``` -yarn add @blockly/field-date -``` - -### npm - -``` -npm install @blockly/field-date --save -``` - -## Usage - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldDate} from '@blockly/field-date'; - -Blockly.Blocks['test_fields_date'] = { - init: function () { - this.appendDummyInput() - .appendField('date: ') - .appendField(new FieldDate('2020-02-20'), 'FIELDNAME'); - }, -}; -``` - -### JSON - -```js -import * as Blockly from 'blockly'; -import '@blockly/field-date'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_fields_date', - message0: 'date: %1', - args0: [ - { - type: 'field_date', - name: 'FIELDNAME', - date: '2020-02-20', - }, - ], - }, -]); -``` - -## License - -Apache 2.0 diff --git a/plugins/field-date/package.json b/plugins/field-date/package.json deleted file mode 100644 index 805c676ca..000000000 --- a/plugins/field-date/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@blockly/field-date", - "version": "13.2.0", - "description": "A Blockly date picker field that uses the browser's date picker.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "blockly-plugin", - "field-date", - "field", - "date", - "datepicker" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-date#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-date" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "sinon": "^22.0.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-date/src/field_date.ts b/plugins/field-date/src/field_date.ts deleted file mode 100644 index cf9601b30..000000000 --- a/plugins/field-date/src/field_date.ts +++ /dev/null @@ -1,286 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Plugin overview. - */ -import * as Blockly from 'blockly/core'; -import {getLocaleDateString} from './utils'; - -/** - * Class for a date input field. - */ -export class FieldDate extends Blockly.FieldTextInput { - /** - * Serializable fields are saved by the XML renderer, non-serializable fields - * are not. Editable fields should also be serializable. - */ - SERIALIZABLE = true; - - /** - * Class for a date input field. Derived from the Closure library date - * picker. - * - * @param value The initial value of the field. Should be in - * 'YYYY-MM-DD' format. Defaults to the current date. - * @param validator A function that is called to validate - * changes to the field's value. Takes in a date string & returns a - * validated date string ('YYYY-MM-DD' format), or null to abort the - * change. - * @param config A map of options used to configure the field. - */ - constructor( - value?: string, - validator?: FieldDateValidator, - config?: FieldDateConfig, - ) { - super(value, validator, config); - } - - /** - * Constructs a FieldDate from a JSON arg object. - * - * @param options A JSON object with options (date). - * @returns The new field instance. - * @package - * @nocollapse - */ - static fromJson(options: FieldDateFromJsonConfig): FieldDate { - const {date, ...fieldDateConfig} = options; - // `this` might be a subclass of FieldDate if that class doesn't - // override the static fromJson method. - return new this(date, undefined, fieldDateConfig); - } - - /* eslint-disable @typescript-eslint/naming-convention */ - /** - * Ensures that the input value is a valid date. Additionally, if the date - * string provided includes a time, the time will be removed and the date for - * relative to the user's timezone will be used. - * - * @param newValue The input value. Ex: '2023-04-28' - * @returns A valid date string, or null if invalid. - * @override - */ - protected doClassValidation_(newValue?: string): string | null { - if (!newValue) return null; - - const newDate = typeof newValue === 'string' ? new Date(newValue) : null; - if (!newDate || isNaN(newDate.getTime())) return null; - - // NOTE: 'newValue' should be a valid date format here. - if (isISOFormat(newValue)) return newValue; - - // Assume the time needs to be corrected. - return toLocalISOString(newDate); - } - - /** - * Get the text to display on the block when the input hasn't spawned in. - * - * @returns The text to display on the block. - * @override - */ - protected getText_(): string | null { - const value = this.getValue(); - if (!value) return null; - // NOTE: There may be discrepancies between the text and the input based on - // browser. For example, 'en-US' would display the text '2/14/2020', then - // clicking in Safari on iOS would display 'Feb 14, 2020'. - return getLocaleDateString(value); - } - - /** - * Returns a description of the type of this field for screenreaders. - */ - override getAriaTypeName() { - return Blockly.Msg['ARIA_TYPE_FIELD_DATE']; - } - - /** - * Returns a description of the current date for use by screenreaders. - */ - override getAriaValue() { - const stringValue = this.getValue(); - if (!stringValue) return super.getAriaValue(); - - const date = new Date(stringValue); - // Use a localized long-form description of the date, e.g. January XX, 20XX, - // rather than a short-form/ISO version of the date which may be read out - // with slashes or the like. - return date.toLocaleDateString(undefined, { - year: 'numeric', - month: 'long', - day: 'numeric', - timeZone: 'UTC', - }); - } - - /** - * Renders the field. If the picker is shown make sure it has the current - * date selected. - */ - protected render_() { - super.render_(); - } - - /** - * Shows the inline free-text editor on top of the text along with the date - * editor. - * - * @param e Optional mouse event that triggered the field to - * open, or undefined if triggered programmatically. - * @override - */ - protected showEditor_(e?: Event) { - // Pass in `true` for `quietInput` to disable modal inputs for the date - // block without setting `this.sourceBlock_.workspace.options.modalInputs`, - // which would impact the entire workspace. - super.showEditor_(e, true); - - // Even though `quietInput` was set true, focus on the element. - this.htmlInput_?.focus({ - preventScroll: true, - }); - this.htmlInput_?.select(); - this.showDropdown(); - } - - /** - * Updates the size of the field based on the text. - * - * @param margin margin to use when positioning the text element. - * @override - */ - protected updateSize_(margin?: number) { - // Add margin so that the date input's datepicker icon doesn't clip with - // the text when sized for the date. - super.updateSize_((margin ?? 0) + 20); - } - - /** - * Shows the datepicker. - */ - private showDropdown(): void { - if (!this.htmlInput_) return; - Blockly.utils.dom.addClass(this.htmlInput_, 'blocklyDateInput'); - - // Delay showing the picker until the editor has a chance to position - window.requestAnimationFrame(() => { - // NOTE: HTMLInputElement.showPicker() is not available in earlier - // TypeScript versions (like 4.7.4), so casting to `any` to be compatible - // with dev scripts. Additionally, it's not available for date inputs for - // Safari. For browser compatibility of showPicker, see: - // https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/showPicker - /* eslint-disable @typescript-eslint/no-explicit-any */ - (this.htmlInput_ as any).showPicker(); - /* eslint-enable @typescript-eslint/no-explicit-any */ - }); - } - - /** - * Create the html input and set it to type date. - * - * @returns The newly created date input editor. - */ - protected widgetCreate_(): HTMLInputElement { - // NOTE: field_input should return HTMLInputElement for this. - const htmlInput = super.widgetCreate_() as HTMLInputElement; - htmlInput.type = 'date'; - - return htmlInput; - } - /* eslint-enable @typescript-eslint/naming-convention */ -} - -/** - * NOTE: There are a few minor ways to tweak the datepicker CSS, though they're - * not consistent across browsers. - * - * @see{@link https://developer.mozilla.org/en-US/docs/Learn/Forms/Property_compatibility_table_for_form_controls#date_pickers} - * - * Below are a few ways this can be tweaked on *some* browsers: - * Blockly.Css.register(` - * ::-webkit-datetime-edit { } - * ::-webkit-datetime-edit-fields-wrapper { } - * ::-webkit-datetime-edit-text { } - * ::-webkit-datetime-edit-month-field { } - * ::-webkit-datetime-edit-day-field { } - * ::-webkit-datetime-edit-year-field { } - * ::-webkit-inner-spin-button { } - * ::-webkit-calendar-picker-indicator { } - * `); - */ -if (Blockly.utils.userAgent.MAC) { - // NOTE: By default, 4 px padding total are added within the User Agent - // Shadow Content on Safari on MAC. Remove the padding so the inner input - // matches the outer input's height and, by extension, the height of the text - // node. - Blockly.Css.register(` -input.blocklyDateInput::-webkit-datetime-edit, -input.blocklyDateInput::-webkit-datetime-edit-month-field, -input.blocklyDateInput::-webkit-datetime-edit-day-field, -input.blocklyDateInput::-webkit-datetime-edit-year-field { - padding: 0; -} -`); -} - -Blockly.fieldRegistry.register('field_date', FieldDate); - -/** - * A config object for defining a field date. - */ -export interface FieldDateConfig extends Blockly.FieldTextInputConfig { - // NOTE: spellcheck is defined for FieldInput though irrelevant for FieldDate. - spellcheck?: never; -} - -/** - * Options used to define a field date from JSON. - */ -export interface FieldDateFromJsonConfig extends FieldDateConfig { - date?: string; -} - -export type FieldDateValidator = Blockly.FieldTextInputValidator; - -/** - * Validate a string value to see if it matches the format. - * - * @param value The value to validate the format for. - * @returns true if the value is in 'yyyy-mm-dd' format. - * @example - * isISOFormat('2000-02-20T00:00:00Z') === false - * isISOFormat('2000-02-20') === true - */ -export function isISOFormat(value: string): boolean { - const valueMatch = value.match(/\d\d\d\d-\d\d-\d\d/); - // If it matches ####-##-## and is the same as its input string, - // then assume this is the right format - return valueMatch !== null && valueMatch[0] === valueMatch.input; -} - -/** - * Convert the date to ISO format for the current timezone. - * - * @param date The date to convert to an ISO string. - * @returns The string in 'yyyy-mm-dd' format, though for the current timezone. - * Ex: new Date('2000-02-20') - */ -export function toLocalISOString(date: Date) { - // NOTE: If the date is Feb 20, 2000 at 23:00 for GMT-6, it would be - // '2000-02-21' at GMT+0, which is what `date.toISOString()` would return. - // For a user whose timezone is GMT-6, this should return '2000-02-20'. - // For a user whose timezone is GMT-5, that date should return '2000-02-21'. - return date - .toLocaleDateString('en-US') - .replace(/(\d+)\/(\d+)\/(\d+)/, '$3-$1-$2') - .replace(/-(\d)(?!\d)/g, '-0$1'); -} - -// NOTE: Set default here instead of in class so it's available at Field. -FieldDate.prototype.DEFAULT_VALUE = toLocalISOString(new Date()); diff --git a/plugins/field-date/src/index.ts b/plugins/field-date/src/index.ts deleted file mode 100644 index 480c3fe80..000000000 --- a/plugins/field-date/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './field_date'; diff --git a/plugins/field-date/src/utils.ts b/plugins/field-date/src/utils.ts deleted file mode 100644 index 7059216d2..000000000 --- a/plugins/field-date/src/utils.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Get the string formatted locally to the user. - * - * @param dateString A string in the format 'yyyy-mm-dd' - * @returns the locale date string for the date. - */ -export function getLocaleDateString(dateString: string): string { - // NOTE: `date.toLocaleDateString()` will be the day before for western dates - // due to an unspecified time & timezone assuming midnight at GMT+0. - const date = new Date(dateString); - - // NOTE: This format varies per region. - // Ex: "5/12/2023", "12/05/2023", "12.5.2023", "2023/5/12", "१२/५/२०२३" - const language = navigator.language ?? 'en-US'; - // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options - return new Intl.DateTimeFormat(language, { - // Print the date for GMT+0 since the date object assumes midnight at GMT+0. - timeZone: 'UTC', - }).format(date); -} diff --git a/plugins/field-date/test/field_date_test.mocha.js b/plugins/field-date/test/field_date_test.mocha.js deleted file mode 100644 index f818c08ce..000000000 --- a/plugins/field-date/test/field_date_test.mocha.js +++ /dev/null @@ -1,267 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {assert} from 'chai'; -import {testHelpers} from '@blockly/dev-tools'; -import {FieldDate} from '../src/index'; -import {getLocaleDateString} from '../src/utils'; - -const { - assertFieldValue, - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -// Add polyfill for global variables needed. -if (!global.navigator) { - global.navigator = { - language: 'en-US', - }; -} - -suite('FieldDate', function () { - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = [ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - {title: 'NaN', value: NaN}, - {title: 'Non-Parsable String', value: 'bad'}, - {title: 'Invalid Date - Month(2020-13-20)', value: '2020-13-20'}, - {title: 'Invalid Date - Day(2020-02-32)', value: '2020-02-32'}, - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = [ - { - title: 'String', - value: '3030-03-30', - expectedValue: '3030-03-30', - expectedText: '3/30/3030', - }, - ]; - const addArgsAndJson = function (testCase) { - testCase.args = [testCase.value]; - testCase.json = {date: testCase.value}; - }; - invalidValueTestCases.forEach(addArgsAndJson); - validValueTestCases.forEach(addArgsAndJson); - // Construct ISO string using current timezone. - // Cannot use toISOString() because it returns in UTC. - const defaultFieldValue = new Date() - .toLocaleDateString('en-US') - .replace(/(\d+)\/(\d+)\/(\d+)/, '$3-$1-$2') - .replace(/-(\d)(?!\d)/g, '-0$1'); - // NOTE: The actual text depends on system settings of the one running it. - const defaultFieldText = new Date().toLocaleDateString(); - const assertFieldDefault = function (field) { - assertFieldValue(field, defaultFieldValue, defaultFieldText); - }; - - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldDate} field The field to check. - * @param {FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertFieldValue(field, testCase.expectedValue, testCase.expectedText); - }; - - runConstructorSuiteTests( - FieldDate, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runFromJsonSuiteTests( - FieldDate, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - suite('setValue', function () { - suite('Empty -> New Value', function () { - setup(function () { - this.field = new FieldDate(); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - defaultFieldValue, - defaultFieldText, - ); - }); - suite('Value -> New Value', function () { - const initialValue = '2020-02-20'; - const initialText = getLocaleDateString(initialValue); - setup(function () { - this.field = new FieldDate(initialValue); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - initialValue, - initialText, - ); - }); - }); - - suite('Validators', function () { - setup(function () { - this.field = new FieldDate('2020-02-20'); - }); - teardown(function () { - this.field.setValidator(null); - }); - suite('when validator returns null', function () { - setup(function () { - this.field.setValidator(() => { - return null; - }); - }); - test('should not set the new value', function () { - this.field.setValue('3030-03-30'); - assertFieldValue(this.field, '2020-02-20', '2/20/2020'); - }); - }); - suite('when validator sets day to 20s', function () { - setup(function () { - this.field.setValidator(function (newValue) { - return newValue.substr(0, 8) + '2' + newValue.substr(9, 1); - }); - }); - test('should set the value to a "20s" date', function () { - this.field.setValue('3030-03-30'); - assertFieldValue(this.field, '3030-03-20', '3/20/3030'); - }); - }); - suite('when validator returns undefined', function () { - setup(function () { - this.field.setValidator(() => {}); - }); - test('should set the value without changing it', function () { - this.field.setValue('3030-03-30'); - assertFieldValue(this.field, '3030-03-30', '3/30/3030'); - }); - }); - }); - - suite('Time Zones', function () { - // https://nodejs.org/api/cli.html#tz - const INITIAL_TZ = process.env.TZ; - const TZ_STRINGS = { - WESTERN: 'America/New_York', - UNIVERSAL: 'Etc/Universal', - EASTERN: 'Europe/Paris', - }; - const TZ_OFFSET = { - WESTERN: '-05:00', - UNIVERSAL: '+00:00', - EASTERN: '+01:00', - }; - - suite('Western', () => { - setup(() => { - process.env.TZ = TZ_STRINGS.WESTERN; - }); - - test('should return the same date when provided a date string', () => { - const dateString = '2000-01-23'; - const fieldDate = new FieldDate(dateString); - assert.equal(fieldDate.getValue(), dateString); - }); - - test('should return the same date for 23:00 western datetime', () => { - const dateString = '2000-01-23'; - const dateTimeString = dateString + 'T23:00:00' + TZ_OFFSET.WESTERN; - const fieldDate = new FieldDate(dateTimeString); - assert.equal(fieldDate.getValue(), dateString); - }); - - test('should return the day before for 00:00 universal datetime', () => { - const dateString = '2000-01-23'; - const dateTimeString = dateString + 'T00:00:00' + TZ_OFFSET.UNIVERSAL; - const fieldDate = new FieldDate(dateTimeString); - assert.equal(fieldDate.getValue(), '2000-01-22'); - }); - - teardown(() => { - process.env.TSZ = INITIAL_TZ; - }); - }); - - suite('Universal', () => { - setup(() => { - process.env.TZ = TZ_STRINGS.UNIVERSAL; - }); - - test('should return the same date when provided a date string', () => { - const dateString = '2000-01-23'; - const fieldDate = new FieldDate(dateString); - assert.equal(fieldDate.getValue(), dateString); - }); - - test('should return the day after for 23:00 western datetime', () => { - const dateString = '2000-01-23'; - const dateTimeString = dateString + 'T23:00:00' + TZ_OFFSET.WESTERN; - const fieldDate = new FieldDate(dateTimeString); - assert.equal(fieldDate.getValue(), '2000-01-24'); - }); - - test('should return the same date for 00:00 universal datetime', () => { - const dateString = '2000-01-23'; - const dateTimeString = dateString + 'T00:00:00' + TZ_OFFSET.UNIVERSAL; - const fieldDate = new FieldDate(dateTimeString); - assert.equal(fieldDate.getValue(), dateString); - }); - - teardown(() => { - process.env.TSZ = INITIAL_TZ; - }); - }); - - suite('Eastern', () => { - setup(() => { - process.env.TZ = TZ_STRINGS.EASTERN; - }); - - test('should return the same date when provided a date string', () => { - const dateString = '2000-01-23'; - const fieldDate = new FieldDate(dateString); - assert.equal(fieldDate.getValue(), dateString); - }); - - test('should return the day after for 23:00 universal datetime', () => { - const dateString = '2000-01-23'; - const dateTimeString = dateString + 'T23:00:00' + TZ_OFFSET.UNIVERSAL; - const fieldDate = new FieldDate(dateTimeString); - assert.equal(fieldDate.getValue(), '2000-01-24'); - }); - - test('should return the same date for 00:00 eastern datetime', () => { - const dateString = '2000-01-23'; - const dateTimeString = dateString + 'T00:00:00' + TZ_OFFSET.EASTERN; - const fieldDate = new FieldDate(dateTimeString); - assert.equal(fieldDate.getValue(), dateString); - }); - - teardown(() => { - process.env.TSZ = INITIAL_TZ; - }); - }); - }); -}); diff --git a/plugins/field-date/test/index.html b/plugins/field-date/test/index.html deleted file mode 100644 index 1f568ca99..000000000 --- a/plugins/field-date/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Date Playground - - - - -
    - - - diff --git a/plugins/field-date/test/index.ts b/plugins/field-date/test/index.ts deleted file mode 100644 index 050763dab..000000000 --- a/plugins/field-date/test/index.ts +++ /dev/null @@ -1,231 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Plugin test. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -/** - * An array of blocks that are defined only for the purposes of - * manually and visually testing the date field. - */ -const testBlockDefinitions = [ - { - type: 'test_standard_field_values', - message0: '%1', - args0: [ - { - type: 'field_date', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_date`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values', - message0: '%1', - args0: [ - { - type: 'field_date', - name: 'FIELDNAME', - date: '2020-02-20', - alt: { - type: 'field_label', - text: `No field_date`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_standard_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_date', - name: 'FIELDNAME', - alt: { - type: 'field_label', - text: `No field_date`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_date', - name: 'FIELDNAME', - date: '2020-02-20', - alt: { - type: 'field_label', - text: `No field_date`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_parent_block', - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }, - { - type: 'test_custom_field_values_and_tooltip', - message0: 'block %1', - args0: [ - { - type: 'field_date', - name: 'FIELDNAME', - date: '2021-03-13', - tooltip: 'This date block has a tooltip!', - alt: { - type: 'field_label', - text: `No field_date`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, -]; - -Blockly.defineBlocksWithJsonArray(testBlockDefinitions); - -/** - * A test toolbox containing the exported blocks and a variety of - * test blocks to exercise the date field in different contexts - * (on a shadow block, as the only field on a block, etc). - * These are in a simple toolbox, rather than a category toolbox, so that - * they are all instantiated every time the test page is opened. - */ -const jsonToolbox = { - contents: [ - { - kind: 'label', - text: 'Test blocks: default field values', - }, - { - kind: 'block', - type: 'test_standard_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_standard_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: custom field values', - }, - { - kind: 'block', - type: 'test_custom_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values_and_label', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_tooltip', - }, - ], -}; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions: Blockly.BlocklyOptions = { - toolbox: jsonToolbox, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - // NOTE: Will need to update @blockly/dev-tools package JSON to keep it's - // version of Blockly in sync with this package's. Both call for ^9.0.0, - // though the package-locks result in each installing different versions. - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/field-date/tsconfig.json b/plugins/field-date/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/field-date/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-dependent-dropdown/CHANGELOG.md b/plugins/field-dependent-dropdown/CHANGELOG.md deleted file mode 100644 index fe7c2a383..000000000 --- a/plugins/field-dependent-dropdown/CHANGELOG.md +++ /dev/null @@ -1,508 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* make field-multilineinput keyboard navigable and accessible (#2729) -* Bump Blockly dependency to v13 (#2704) - -### Features - -* make field-multilineinput keyboard navigable and accessible ([#2729](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2729)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [5.0.10](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.9...@blockly/field-dependent-dropdown@5.0.10) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.8...@blockly/field-dependent-dropdown@5.0.9) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.7...@blockly/field-dependent-dropdown@5.0.8) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.6...@blockly/field-dependent-dropdown@5.0.7) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.5...@blockly/field-dependent-dropdown@5.0.6) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.4...@blockly/field-dependent-dropdown@5.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.3...@blockly/field-dependent-dropdown@5.0.4) (2025-10-30) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.2...@blockly/field-dependent-dropdown@5.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.1...@blockly/field-dependent-dropdown@5.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@5.0.0...@blockly/field-dependent-dropdown@5.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.16...@blockly/field-dependent-dropdown@5.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [4.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.15...@blockly/field-dependent-dropdown@4.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.14...@blockly/field-dependent-dropdown@4.0.15) (2025-05-15) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.13...@blockly/field-dependent-dropdown@4.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.12...@blockly/field-dependent-dropdown@4.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.11...@blockly/field-dependent-dropdown@4.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.10...@blockly/field-dependent-dropdown@4.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.9...@blockly/field-dependent-dropdown@4.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [4.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.8...@blockly/field-dependent-dropdown@4.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [4.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.7...@blockly/field-dependent-dropdown@4.0.8) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.6...@blockly/field-dependent-dropdown@4.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.5...@blockly/field-dependent-dropdown@4.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.4...@blockly/field-dependent-dropdown@4.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.3...@blockly/field-dependent-dropdown@4.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.2...@blockly/field-dependent-dropdown@4.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.1...@blockly/field-dependent-dropdown@4.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@4.0.0...@blockly/field-dependent-dropdown@4.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.17...@blockly/field-dependent-dropdown@4.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly -* **dev-scripts:** This PR removes the support that was added - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* **dev-scripts:** Fixes, refactoring and simplification of `webpack.config.js` and `'blockly'` imports ([#2229](https://github.com/google/blockly-samples/issues/2229)) ([f5ffdb9](https://github.com/google/blockly-samples/commit/f5ffdb961e3b60ddb164087f4bddc4e6215906b7)), closes [#335](https://github.com/google/blockly-samples/issues/335) [#335](https://github.com/google/blockly-samples/issues/335) [#1630](https://github.com/google/blockly-samples/issues/1630) [#335](https://github.com/google/blockly-samples/issues/335) [#226](https://github.com/google/blockly-samples/issues/226) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [google/blockly#7822](https://github.com/google/blockly/issues/7822) [/github.com/google/blockly-samples/pull/2229#issuecomment-1979123919](https://github.com/google//github.com/google/blockly-samples/pull/2229/issues/issuecomment-1979123919) - - - -## [3.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.16...@blockly/field-dependent-dropdown@3.0.17) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.15...@blockly/field-dependent-dropdown@3.0.16) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.14...@blockly/field-dependent-dropdown@3.0.15) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.13...@blockly/field-dependent-dropdown@3.0.14) (2024-04-04) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.12...@blockly/field-dependent-dropdown@3.0.13) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.11...@blockly/field-dependent-dropdown@3.0.12) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.10...@blockly/field-dependent-dropdown@3.0.11) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.9...@blockly/field-dependent-dropdown@3.0.10) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.8...@blockly/field-dependent-dropdown@3.0.9) (2023-11-16) - - -### Bug Fixes - -* resolved 15 ESLint warnings ([#2065](https://github.com/google/blockly-samples/issues/2065)) ([2436337](https://github.com/google/blockly-samples/commit/243633746542bb1518fe2893c0421a5a6f79fd32)) - - - -## [3.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.7...@blockly/field-dependent-dropdown@3.0.8) (2023-11-09) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.6...@blockly/field-dependent-dropdown@3.0.7) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.5...@blockly/field-dependent-dropdown@3.0.6) (2023-10-30) - - -### Bug Fixes - -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* Publish types for field-dependent-dropdown ([#1961](https://github.com/google/blockly-samples/issues/1961)) ([9c96dbe](https://github.com/google/blockly-samples/commit/9c96dbeea63b71ce0f5e8be7b8acaf44e77fc8ed)) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.4...@blockly/field-dependent-dropdown@3.0.5) (2023-09-21) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.3...@blockly/field-dependent-dropdown@3.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.2...@blockly/field-dependent-dropdown@3.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.1...@blockly/field-dependent-dropdown@3.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@3.0.0...@blockly/field-dependent-dropdown@3.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@2.0.1...@blockly/field-dependent-dropdown@3.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@2.0.0...@blockly/field-dependent-dropdown@2.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@1.1.5...@blockly/field-dependent-dropdown@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - -### Bug Fixes - -* renaming build problems ([7087469](https://github.com/google/blockly-samples/commit/7087469ccdaf27e040cd67a386c9284aa6b1cd67)) - - - -## [1.1.5](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@1.1.4...@blockly/field-dependent-dropdown@1.1.5) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [1.1.4](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@1.1.3...@blockly/field-dependent-dropdown@1.1.4) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [1.1.3](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@1.1.2...@blockly/field-dependent-dropdown@1.1.3) (2023-05-11) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [1.1.2](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@1.1.1...@blockly/field-dependent-dropdown@1.1.2) (2023-05-04) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## [1.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-dependent-dropdown@1.1.0...@blockly/field-dependent-dropdown@1.1.1) (2023-04-27) - -**Note:** Version bump only for package @blockly/field-dependent-dropdown - - - - - -## 1.1.0 (2023-03-23) - - -### Features - -* Create plugin for dependent dropdown fields. ([#1555](https://github.com/google/blockly-samples/issues/1555)) ([1c473d6](https://github.com/google/blockly-samples/commit/1c473d6b2c4aa3754cf332c07585af60342537ef)) diff --git a/plugins/field-dependent-dropdown/README.md b/plugins/field-dependent-dropdown/README.md deleted file mode 100644 index 0b342767d..000000000 --- a/plugins/field-dependent-dropdown/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# @blockly/field-dependent-dropdown [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) dropdown field where the options depend on the value of a parent field. - -## Installation - -### Yarn - -``` -yarn add @blockly/field-dependent-dropdown -``` - -### npm - -``` -npm install @blockly/field-dependent-dropdown --save -``` - -## Usage - -This plugin adds a field type `FieldDependentDropdown` that is an extension of `Blockly.FieldDropdown` and is registered as `'field_dependent_dropdown'` for the JSON API. You can associate it with a parent field that is attached to the same block, along with a mapping from the parent field's possible values to the desired menu options for this child field. Whenever the parent field's value changes, this field will automatically change its own available options to the options that correspond to the new parent value. You can also provide a set of default options that will be used if the parent field's value doesn't match any of the keys in your option mapping. - -These changes are recorded properly in the undo history, and the fields can be [serialized and later deserialized](https://developers.google.com/blockly/guides/configure/web/serialization) while preserving their options, values, and validity. You can also create chains of dependent dropdowns that depend on other dependent dropdowns. - -Note that the parent field must be attached to the block before the child field, and the child field will attach a validator function to the parent field to intercept changes to its value. If you want to add your own [custom field validator](https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators) to the parent field, you need to use [the JavaScript API to define your block](https://developers.google.com/blockly/guides/create-custom-blocks/define/json-and-js) and [pass your validator to the parent field's constructor](https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/dropdown#creating_a_dropdown_validator). If you try to set the parent's validator later, you'll overwrite the one added by this plugin. - -To create a dependent dropdown, you'll need to add this field type to a block definition, and add that block to your toolbox. See below for an example of defining a block that uses this field. - -### JSON - -```js -import * as Blockly from 'blockly'; -import '@blockly/field-dependent-dropdown'; // Import with side effects. - -Blockly.defineBlocksWithJsonArray([ - { - 'type': 'dependent_dropdown_example', - 'message0': 'Category %1 Animal %2', - 'args0': [ - { - 'type': 'field_dropdown', - 'name': 'ANIMAL_CATEGORY', - 'options': [['Mammal', 'mammal'], ['Bird', 'bird'], ['Cryptid', 'cryptid']] - }, - { - 'type': 'field_dependent_dropdown', - 'name': 'ANIMAL', - 'parentName': 'ANIMAL_CATEGORY', - 'optionMapping': { - 'mammal': [['Dog', 'dog'], ['Cat', 'cat'], ['Hamster', 'hamster']], - 'bird': [['Parakeet', 'parakeet'], ['Canary', 'canary']] - } - 'defaultOptions': [['None available', 'noneAvailable']], - } - ] - } -]); -``` - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldDependentDropdown} from '@blockly/field-dependent-dropdown'; - -Blockly.Blocks['dependent_dropdown_example'] = { - init: function () { - const parentFieldName = 'ANIMAL_CATEGORY'; - const childFieldName = 'ANIMAL'; - const parentOptions = [ - ['Mammal', 'mammal'], - ['Bird', 'bird'], - ['Cryptid', 'cryptid'], - ]; - const optionMapping = { - mammal: [ - ['Dog', 'dog'], - ['Cat', 'cat'], - ['Hamster', 'hamster'], - ], - bird: [ - ['Parakeet', 'parakeet'], - ['Canary', 'canary'], - ], - }; - const defaultOptions = [['None available', 'noneAvailable']]; - this.appendDummyInput() - .appendField('Category') - .appendField(new Blockly.FieldDropdown(parentOptions), parentFieldName) - .appendField('Animal') - .appendField( - new FieldDependentDropdown( - parentFieldName, - optionMapping, - defaultOptions, - ), - childFieldName, - ); - }, -}; -``` - -## License - -Apache 2.0 diff --git a/plugins/field-dependent-dropdown/package.json b/plugins/field-dependent-dropdown/package.json deleted file mode 100644 index bb7e11f74..000000000 --- a/plugins/field-dependent-dropdown/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@blockly/field-dependent-dropdown", - "version": "13.2.0", - "description": "A Blockly dropdown field that automatically updates its available options depending on the value of another field.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "colour", - "field", - "hsv", - "slider" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-dependent-dropdown#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-dependent-dropdown" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "sinon": "^22.0.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-dependent-dropdown/src/dependent_dropdown_options_change.ts b/plugins/field-dependent-dropdown/src/dependent_dropdown_options_change.ts deleted file mode 100644 index ec8efd5ed..000000000 --- a/plugins/field-dependent-dropdown/src/dependent_dropdown_options_change.ts +++ /dev/null @@ -1,233 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview An event representing when a dependent dropdown field changes - * state. - */ - -import * as Blockly from 'blockly/core'; -import type {FieldDependentDropdown} from './field_dependent_dropdown'; - -/** - * A deep equality comparison between the two provided arrays recursively - * comparing any child elements that are also arrays. - * - * @param a The first array to compare. - * @param b The second array to compare. - * @returns Whether the arrays are deeply equivalent. - */ -function arraysAreEquivalent(a: T[], b: T[]): boolean { - return ( - a.length === b.length && - a.every((aElement, index) => { - const bElement = b[index]; - if (Array.isArray(aElement) && Array.isArray(bElement)) { - return arraysAreEquivalent(aElement, bElement); - } - return aElement === bElement; - }) - ); -} - -/** The structure of a serialized DependentDropdownOptionsChange. */ -export interface DependentDropdownOptionsChangeJson - extends Blockly.Events.BlockBaseJson { - name: string; - newValue: string; - oldValue: string; - oldOptions: Blockly.MenuOption[]; - newOptions: Blockly.MenuOption[]; -} - -/** - * A change event representing a simultaneous change to a dropdown field's - * options and value. The old value must be one of the old options, and the new - * value must be one of the new options. Unlike a normal value change event, - * it's possible for this event to change the value to something that wasn't - * previously one of the valid options--in either direction--by also changing - * the options at the same time. - */ -export class DependentDropdownOptionsChange extends Blockly.Events.BlockBase { - /** The name to register with Blockly for the type of event. */ - - static readonly EVENT_TYPE: string = 'dropdown_options_change'; - - /** The name of the change event type for registering with Blockly. */ - readonly type = DependentDropdownOptionsChange.EVENT_TYPE; - - /** The name of the field that changed. */ - name?: string; - - /** The original value of the field. */ - oldValue?: string; - - /** The new value of the field. */ - newValue?: string; - - /** The original available options for the dropdown field. */ - oldOptions?: Blockly.MenuOption[]; - - /** The new available options for the dropdown field. */ - newOptions?: Blockly.MenuOption[]; - - /** - * Construct a new DependentDropdownOptionsChange. - * - * @param block The changed block. Undefined for a blank event. - * @param name Name of the field affected. - * @param oldValue Previous value of field. - * @param newValue New value of field. - * @param oldOptions Previous options for the dropdown. - * @param newOptions New options for the dropdown. - */ - constructor( - block?: Blockly.Block, - name?: string, - oldValue?: string, - newValue?: string, - oldOptions?: Blockly.MenuOption[], - newOptions?: Blockly.MenuOption[], - ) { - super(block); - - if ( - !block || - !name || - !oldValue || - !newValue || - !oldOptions || - !newOptions - ) { - // Blank event to be populated by fromJson. - return; - } - - this.name = name; - this.oldValue = oldValue; - this.newValue = newValue; - this.oldOptions = oldOptions; - this.newOptions = newOptions; - } - - /** - * Encode the event as JSON. - * - * @returns JSON representation. - */ - toJson(): DependentDropdownOptionsChangeJson { - const json = super.toJson() as DependentDropdownOptionsChangeJson; - if ( - !this.name || - !this.oldValue || - !this.newValue || - !this.oldOptions || - !this.newOptions - ) { - throw new Error( - 'The changed element is undefined. Either pass all needed ' + - 'parameters to the constructor, or call fromJson.', - ); - } - json['name'] = this.name; - json['oldValue'] = this.oldValue; - json['newValue'] = this.newValue; - json['oldOptions'] = this.oldOptions; - json['newOptions'] = this.newOptions; - return json; - } - - /** - * Decode the JSON event. - * - * @param json JSON representation. - * @param workspace - * @param event - * @returns The deserialized event. - */ - static fromJson( - json: DependentDropdownOptionsChangeJson, - workspace: Blockly.Workspace, - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - event?: any, - ): DependentDropdownOptionsChange { - const newEvent = super.fromJson( - json, - workspace, - event, - ) as DependentDropdownOptionsChange; - newEvent.name = json['name']; - newEvent.oldValue = json['oldValue']; - newEvent.newValue = json['newValue']; - newEvent.oldOptions = json['oldOptions']; - newEvent.newOptions = json['newOptions']; - return newEvent; - } - - /** - * Does this event leave all state as it was before? - * - * @returns False if something changed. - */ - isNull(): boolean { - const valuesAreEqual = this.oldValue === this.newValue; - const optionsAreEquivalent = - this.oldOptions === this.newOptions || - (Array.isArray(this.oldOptions) && - Array.isArray(this.newOptions) && - arraysAreEquivalent(this.oldOptions, this.newOptions)); - return valuesAreEqual && optionsAreEquivalent; - } - - /** - * Run a change event. - * - * @param forward True if run forward, false if run backward (undo). - */ - run(forward: boolean): void { - if ( - !this.blockId || - !this.name || - !this.oldValue || - !this.newValue || - !this.oldOptions || - !this.newOptions - ) { - console.warn("Can't run uninitialized event."); - return; - } - const workspace = this.getEventWorkspace_(); - const block = workspace.getBlockById(this.blockId); - if (!block) { - console.warn("Can't change non-existent block: " + this.blockId); - return; - } - - const dropdown = block.getField(this.name) as FieldDependentDropdown; - if (!dropdown) { - console.warn("Can't change non-existent dropdown field: " + this.name); - return; - } - - const value = forward ? this.newValue : this.oldValue; - const options = forward ? this.newOptions : this.oldOptions; - - // Record the options on the dropdown for the option generator to access. - dropdown.dependencyData.derivedOptions = options; - - // Re-run the option generator to update the options on the dropdown. - dropdown.getOptions(false); - - // Set the value to one of the now-available options. - dropdown.setValue(value); - } -} - -Blockly.registry.register( - Blockly.registry.Type.EVENT, - DependentDropdownOptionsChange.EVENT_TYPE, - DependentDropdownOptionsChange, -); diff --git a/plugins/field-dependent-dropdown/src/field_dependent_dropdown.ts b/plugins/field-dependent-dropdown/src/field_dependent_dropdown.ts deleted file mode 100644 index e2348bcd4..000000000 --- a/plugins/field-dependent-dropdown/src/field_dependent_dropdown.ts +++ /dev/null @@ -1,319 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A Blockly dropdown menu field where the options can change - * depending on the value of another field. - */ - -import * as Blockly from 'blockly/core'; -import {DependentDropdownOptionsChange} from './dependent_dropdown_options_change'; - -/** The type of the mapping from parent value to child options. */ -export interface ChildOptionMapping { - [key: string]: Blockly.MenuOption[]; -} - -// This type isn't exported from Blockly so we have to derive it from the API. -type FieldConfig = Exclude< - ConstructorParameters[2], - undefined ->; - -/** fromJson config for a dependent dropdown field. */ -export interface FieldDependentDropdownFromJsonConfig extends FieldConfig { - parentName: string; - optionMapping: ChildOptionMapping; - defaultOptions?: Blockly.MenuOption[]; -} - -/** - * A structure for managing data needed by the menu generator of a - * FieldDependentDropdown. - */ -interface DependencyData { - /** - * A reference to the parent field of an associated dependent dropdown. Absent - * until the parent field is initialized. This field's value determines the - * available options of the child field. - */ - parentField?: Blockly.Field; - - /** - * The child field's currently available menu options based on the current - * value of the parent field. Absent until the parent field is initialized. - */ - derivedOptions?: Blockly.MenuOption[]; -} - -/** - * A dropdown field that automatically updates its own options based on a - * mapping from a parent field's value. The parent field must be attached to the - * block before this child field. - * - * When this field is attached to a block, it will find the parent field and - * attach a validator to the parent field that intercepts changes to its value - * to update the options on this field. If the new validator is later removed\ - * or replaced, then this dependent field will no longer function. - */ -export class FieldDependentDropdown extends Blockly.FieldDropdown { - /** - * Contains data used by this dropdown field's menu generator. - * - * The menu generator cannot refer directly to this FieldDependentDropdown - * instance, because it must be created before calling the super constructor - * when the "this" reference is not yet valid. This helper structure is used - * instead. - * - * This is public so that the DependentDropdownOptionsChangeJson event can - * update it while undoing/redoing. - */ - dependencyData: DependencyData; - - /** The name of the field that determines this field's options. */ - private parentName: string; - - /** - * The mapping from the parent field's value to this field's intended - * available options. The keys are strings representing the parent's possible - * values, and the values are the corresponding options to use in this child - * field. - */ - private optionMapping: ChildOptionMapping; - - /** - * An optional fallback set of options to use if the parent field's value does - * not match any of the keys in optionMapping. - */ - private defaultOptions?: Blockly.MenuOption[]; - - /** - * Constructs a new FieldDependentDropdown. - * - * @param parentName The name of the parent field whose value determines this - * field's available options. - * @param optionMapping A mapping from the possible values of the parent field - * to the corresponding available options of this child field. The keys are - * the possible values of the parent field, and the values are the - * corresponding arrays of options for this child field. - * @param defaultOptions An optional fallback set of options to use if the - * parent field's value does not match any of the keys in optionMapping. - * @param validator An optional function that is called to validate changes to - * this field's value. - * @param config An optional map of general options used to configure the - * field, such as a tooltip. - */ - constructor( - parentName: string, - optionMapping: ChildOptionMapping, - defaultOptions?: Blockly.MenuOption[], - validator?: Blockly.FieldValidator, - config?: FieldConfig, - ) { - // A menu generator needs to be passed to the super constructor, but it - // needs to be able to reference data that hasn't been populated yet. We're - // not allowed to refer to "this" in this constructor before calling - // "super", so let's make separate structure to hold data relevant to the - // menu generator and populate that later. - const dependencyData: DependencyData = {}; - - // A menu option generator function for this child field that reads the - // derived options in the dependency data if available. - const menuGenerator: Blockly.MenuGeneratorFunction = () => { - // If derivedOptions has been initialized, use that. - if (dependencyData.derivedOptions) { - return dependencyData.derivedOptions; - } - - // Fall back on the options corresponding to the parent field's current - // value (which is fine when initializing but may be out of date when - // making changes since the parent field's validator function triggers - // this function before the parent field's value is updated). - - // If the parent field exists, and its value is a key in the provided - // option mapping, use the corresponding options. - if (dependencyData.parentField) { - const value = dependencyData.parentField.getValue(); - if (value) { - const options = optionMapping[value]; - if (options) { - return options; - } - } - } - - if (defaultOptions) { - return defaultOptions; - } - - // Fall back on basic default options. - return [['', '']]; - }; - - super(menuGenerator, validator, config); - this.parentName = parentName; - this.optionMapping = optionMapping; - this.defaultOptions = defaultOptions; - this.dependencyData = dependencyData; - } - - /** - * Constructs a FieldDependentDropdown from a JSON arg object. - * - * @param options A JSON object providing "parentName" and "optionMapping". - * @returns The new field instance. - */ - static fromJson( - options: FieldDependentDropdownFromJsonConfig, - ): FieldDependentDropdown { - return new FieldDependentDropdown( - options['parentName'], - options['optionMapping'], - options['defaultOptions'], - undefined, - options, - ); - } - - /** - * Attach this field to a block. - * - * @param block The block containing this field. - */ - setSourceBlock(block: Blockly.Block) { - super.setSourceBlock(block); - - const parentField: Blockly.Field | null = block.getField( - this.parentName, - ); - - if (!parentField) { - throw new Error( - 'Could not find a parent field with the name ' + - this.parentName + - ' for the dependent dropdown.', - ); - } - - this.dependencyData.parentField = parentField; - - const oldValidator = parentField.getValidator(); - - // A validator function for the parent field that has the side effect of - // updating the options of this child dropdown field based on the new value - // of the parent field whenever it changes. The validator function is a good - // place to do this because it is called immediately while deserializing - // workspaces before the following fields are deserialized, so when the - // child value is deserialized the appropriate options will already be - // available. If the parent already had a validator function, it will be - // composed with this one and the new value returned from it will be the - // basis for determining the new available options. - parentField.setValidator((newValue) => { - if (oldValidator) { - const validatedValue = oldValidator(newValue); - // If a validator returns null, that means the new value is invalid and - // the change should be canceled. - if (validatedValue === null) { - return null; - } - // If a validator returns undefined, that means no change. Otherwise, - // use the returned value as the new value. - if (validatedValue !== undefined) { - newValue = validatedValue; - } - } - this.updateOptionsBasedOnNewValue(newValue); - return newValue; - }); - this.updateOptionsBasedOnNewValue(parentField.getValue() ?? undefined); - } - - /** - * Updates the options of this child dropdown field based on the new value of - * the parent field. - * - * @param newValue The newly assigned value. - */ - private updateOptionsBasedOnNewValue(newValue: string | undefined): void { - if (newValue == undefined) { - return; - } - - const block = this.getSourceBlock(); - if (!block) { - throw new Error( - 'Could not validate a field that is not attached to a block: ' + - this.name, - ); - } - - const oldChildValue = this.getValue(); - const oldChildOptions = this.getOptions(false); - let newChildOptions = this.optionMapping[newValue]; - if (!newChildOptions) { - if (this.defaultOptions) { - newChildOptions = this.defaultOptions; - } else { - console.warn( - 'Could not find child options for the parent value: ' + newValue, - ); - return; - } - } - - // If the child field's value is still available in the new options, keep - // it, otherwise change the field's value to the first available option. - const newOptionsIncludeOldValue = - newChildOptions.find((option) => option[1] == oldChildValue) != undefined; - const newChildValue = newOptionsIncludeOldValue - ? oldChildValue - : newChildOptions[0][1]; - - // Record the options so that the option generator can access them. - this.dependencyData.derivedOptions = newChildOptions; - - // Re-run the option generator to update the options on the dropdown. - this.getOptions(false); - - // Update this child field's value without broadcasting the normal change - // event. The normal value change event can't be properly undone, because - // the old value may not be one of the currently valid options, so a custom - // change event will be broadcast instead that handles swapping the options - // and the value at the same time. - Blockly.Events.disable(); - this.setValue(newChildValue); - Blockly.Events.enable(); - - if (Blockly.Events.getRecordUndo()) { - if (!Blockly.Events.getGroup()) { - // Start a change group before the change event. The change event for - // the parent field value will be created after this function returns - // and will be part of the same group. - Blockly.Events.setGroup(true); - // Clear the change group later, after all related events have been - // broadcast, but before the user performs any more actions. - setTimeout(() => Blockly.Events.setGroup(false)); - } - - // Record that the child field's options and value have changed. - Blockly.Events.fire( - new DependentDropdownOptionsChange( - block, - this.name, - oldChildValue ?? undefined, - newChildValue ?? undefined, - oldChildOptions, - newChildOptions, - ), - ); - } - } -} - -Blockly.fieldRegistry.register( - 'field_dependent_dropdown', - FieldDependentDropdown, -); diff --git a/plugins/field-dependent-dropdown/src/index.ts b/plugins/field-dependent-dropdown/src/index.ts deleted file mode 100644 index e837ff51f..000000000 --- a/plugins/field-dependent-dropdown/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './field_dependent_dropdown'; diff --git a/plugins/field-dependent-dropdown/test/field_dependent_dropdown.mocha.js b/plugins/field-dependent-dropdown/test/field_dependent_dropdown.mocha.js deleted file mode 100644 index 61d32499a..000000000 --- a/plugins/field-dependent-dropdown/test/field_dependent_dropdown.mocha.js +++ /dev/null @@ -1,302 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const chai = require('chai'); -const sinon = require('sinon'); -const Blockly = require('blockly'); -require('./field_dependent_dropdown_test_block'); - -const assert = chai.assert; - -suite('fieldDependentDropdown', function () { - setup(function () { - this.workspace = new Blockly.Workspace(); - this.clock = sinon.useFakeTimers(); - }); - - teardown(function () { - this.workspace.dispose(); - // Finish any remaining queued events then dispose the sinon environment. - this.clock.runAll(); - this.clock.restore(); - }); - - test('Changing a parent value changes the child options', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['A1', 'a1'], - ['A2', 'a2'], - ['Shared', 'shared'], - ]); - parentDropdown.setValue('b'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['B1', 'b1'], - ['B2', 'b2'], - ['Shared', 'shared'], - ]); - }); - - test('Changing a parent value changes the child value', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - assert.equal(childDropdown.getValue(), 'a1'); - parentDropdown.setValue('b'); - assert.equal(childDropdown.getValue(), 'b1'); - }); - - test('Changing a parent value preserves shared child value', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - childDropdown.setValue('shared'); - parentDropdown.setValue('b'); - assert.equal(childDropdown.getValue(), 'shared'); - }); - - test('Changing a parent value changes the grandchild options', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - assert.deepEqual(grandchildDropdown.getOptions(true), [ - ['A11', 'a11'], - ['A12', 'a12'], - ]); - parentDropdown.setValue('b'); - assert.deepEqual(grandchildDropdown.getOptions(true), [ - ['B11', 'b11'], - ['B12', 'b12'], - ]); - }); - - test('Changing a parent value changes the grandchild value', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - assert.equal(grandchildDropdown.getValue(), 'a11'); - parentDropdown.setValue('b'); - assert.equal(grandchildDropdown.getValue(), 'b11'); - }); - - test('Uses default options if parent field not in mapping', function () { - const block = this.workspace.newBlock( - 'dependent_dropdown_default_options_test', - ); - const parentTextInput = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['Default Option', 'defaultOption'], - ]); - parentTextInput.setValue('a'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['A1', 'a1'], - ['A2', 'a2'], - ]); - parentTextInput.setValue('b'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['Default Option', 'defaultOption'], - ]); - }); - - test('Parent field user validator composes with new validator', function () { - const block = this.workspace.newBlock('dependent_dropdown_validation_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - assert.equal(parentDropdown.getValue(), 'initial'); - assert.equal(childDropdown.getValue(), 'initial1'); - parentDropdown.setValue('invalid'); - assert.equal(parentDropdown.getValue(), 'valid'); - assert.equal(childDropdown.getValue(), 'valid1'); - }); - - test('undoing parent change undoes child and grandchild options', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - parentDropdown.setValue('b'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['B1', 'b1'], - ['B2', 'b2'], - ['Shared', 'shared'], - ]); - assert.deepEqual(grandchildDropdown.getOptions(true), [ - ['B11', 'b11'], - ['B12', 'b12'], - ]); - // Wait for the change events to get fired and recorded in history. - this.clock.runAll(); - this.workspace.undo(false); - assert.deepEqual(childDropdown.getOptions(true), [ - ['A1', 'a1'], - ['A2', 'a2'], - ['Shared', 'shared'], - ]); - assert.deepEqual(grandchildDropdown.getOptions(true), [ - ['A11', 'a11'], - ['A12', 'a12'], - ]); - }); - - test('undoing parent change undoes child and grandchild values', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - parentDropdown.setValue('b'); - assert.equal(childDropdown.getValue(), 'b1'); - assert.equal(grandchildDropdown.getValue(), 'b11'); - // Wait for the change events to get fired and recorded in history. - this.clock.runAll(); - this.workspace.undo(false); - assert.equal(childDropdown.getValue(), 'a1'); - assert.equal(grandchildDropdown.getValue(), 'a11'); - }); - - test('redoing parent change redoes child options', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - parentDropdown.setValue('b'); - // Wait for the change events to get fired and recorded in history. - this.clock.runAll(); - this.workspace.undo(false); - assert.deepEqual(childDropdown.getOptions(true), [ - ['A1', 'a1'], - ['A2', 'a2'], - ['Shared', 'shared'], - ]); - this.workspace.undo(true); - assert.deepEqual(childDropdown.getOptions(true), [ - ['B1', 'b1'], - ['B2', 'b2'], - ['Shared', 'shared'], - ]); - }); - - test('redoing parent change redoes child values', function () { - const block = this.workspace.newBlock('dependent_dropdown_test'); - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - parentDropdown.setValue('b'); - // Wait for the change events to get fired and recorded in history. - this.clock.runAll(); - this.workspace.undo(false); - assert.equal(childDropdown.getValue(), 'a1'); - this.workspace.undo(true); - assert.equal(childDropdown.getValue(), 'b1'); - }); - - test('deserialized values affect available options', function () { - const serializedWorkspace = { - blocks: { - blocks: [ - { - type: 'dependent_dropdown_test', - fields: { - PARENT_FIELD: 'b', - CHILD_FIELD: 'b2', - GRANDCHILD_FIELD: 'b21', - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(serializedWorkspace, this.workspace); - const block = this.workspace.getBlocksByType( - 'dependent_dropdown_test', - false, - )[0]; - const childDropdown = block.getField('CHILD_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - assert.deepEqual(childDropdown.getOptions(true), [ - ['B1', 'b1'], - ['B2', 'b2'], - ['Shared', 'shared'], - ]); - assert.deepEqual(grandchildDropdown.getOptions(true), [ - ['B21', 'b21'], - ['B22', 'b22'], - ]); - }); - - test('deserializing preserves values not in default options', function () { - const serializedWorkspace = { - blocks: { - blocks: [ - { - type: 'dependent_dropdown_test', - fields: { - PARENT_FIELD: 'b', - CHILD_FIELD: 'b2', - GRANDCHILD_FIELD: 'b21', - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(serializedWorkspace, this.workspace); - const block = this.workspace.getBlocksByType( - 'dependent_dropdown_test', - false, - )[0]; - const parentDropdown = block.getField('PARENT_FIELD'); - const childDropdown = block.getField('CHILD_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - assert.equal(parentDropdown.getValue(), 'b'); - assert.equal(childDropdown.getValue(), 'b2'); - assert.equal(grandchildDropdown.getValue(), 'b21'); - }); - - test('deserializing invalid value replaces with valid value', function () { - const serializedWorkspace = { - blocks: { - blocks: [ - { - type: 'dependent_dropdown_test', - fields: { - PARENT_FIELD: 'b', - CHILD_FIELD: 'a2', - GRANDCHILD_FIELD: 'b21', - }, - }, - ], - }, - }; - Blockly.serialization.workspaces.load(serializedWorkspace, this.workspace); - const block = this.workspace.getBlocksByType( - 'dependent_dropdown_test', - false, - )[0]; - const childDropdown = block.getField('CHILD_FIELD'); - const grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - assert.equal(childDropdown.getValue(), 'b1'); - assert.equal(grandchildDropdown.getValue(), 'b11'); - }); - - test('round trip serialization/deserialization preserves values', function () { - let block = this.workspace.newBlock('dependent_dropdown_test'); - let parentDropdown = block.getField('PARENT_FIELD'); - let childDropdown = block.getField('CHILD_FIELD'); - let grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - parentDropdown.setValue('b'); - childDropdown.setValue('b2'); - grandchildDropdown.setValue('b21'); - const serializedWorkspace = Blockly.serialization.workspaces.save( - this.workspace, - ); - Blockly.serialization.workspaces.load(serializedWorkspace, this.workspace); - block = this.workspace.getBlocksByType('dependent_dropdown_test', false)[0]; - parentDropdown = block.getField('PARENT_FIELD'); - childDropdown = block.getField('CHILD_FIELD'); - grandchildDropdown = block.getField('GRANDCHILD_FIELD'); - assert.equal(parentDropdown.getValue(), 'b'); - assert.equal(childDropdown.getValue(), 'b2'); - assert.equal(grandchildDropdown.getValue(), 'b21'); - }); -}); diff --git a/plugins/field-dependent-dropdown/test/field_dependent_dropdown_test_block.ts b/plugins/field-dependent-dropdown/test/field_dependent_dropdown_test_block.ts deleted file mode 100644 index 2cf7c1804..000000000 --- a/plugins/field-dependent-dropdown/test/field_dependent_dropdown_test_block.ts +++ /dev/null @@ -1,130 +0,0 @@ -import * as Blockly from 'blockly'; -import {ChildOptionMapping, FieldDependentDropdown} from '../src/index'; - -Blockly.defineBlocksWithJsonArray([ - { - type: 'dependent_dropdown_test', - message0: 'Parent %1 Child %2 Grandchild %3', - args0: [ - { - type: 'field_dropdown', - name: 'PARENT_FIELD', - options: [ - ['A', 'a'], - ['B', 'b'], - ], - }, - { - type: 'field_dependent_dropdown', - name: 'CHILD_FIELD', - parentName: 'PARENT_FIELD', - optionMapping: { - a: [ - ['A1', 'a1'], - ['A2', 'a2'], - ['Shared', 'shared'], - ], - b: [ - ['B1', 'b1'], - ['B2', 'b2'], - ['Shared', 'shared'], - ], - }, - }, - { - type: 'field_dependent_dropdown', - name: 'GRANDCHILD_FIELD', - parentName: 'CHILD_FIELD', - optionMapping: { - a1: [ - ['A11', 'a11'], - ['A12', 'a12'], - ], - a2: [ - ['A21', 'a21'], - ['A22', 'a22'], - ], - b1: [ - ['B11', 'b11'], - ['B12', 'b12'], - ], - b2: [ - ['B21', 'b21'], - ['B22', 'b22'], - ], - shared: [['Only', 'only']], - }, - }, - ], - colour: 100, - }, - { - type: 'dependent_dropdown_default_options_test', - message0: 'Parent %1 Child %2', - args0: [ - { - type: 'field_input', - name: 'PARENT_FIELD', - }, - { - type: 'field_dependent_dropdown', - name: 'CHILD_FIELD', - parentName: 'PARENT_FIELD', - optionMapping: { - a: [ - ['A1', 'a1'], - ['A2', 'a2'], - ], - }, - defaultOptions: [['Default Option', 'defaultOption']], - }, - ], - colour: 100, - }, -]); - -Blockly.Blocks['dependent_dropdown_validation_test'] = { - init: function () { - const parentFieldName = 'PARENT_FIELD'; - const childFieldName = 'CHILD_FIELD'; - const parentOptions: Blockly.MenuOption[] = [ - ['Initial', 'initial'], - ['Invalid', 'invalid'], - ['Valid', 'valid'], - ]; - const dependentOptions: ChildOptionMapping = { - initial: [ - ['Initial1', 'initial1'], - ['Initial2', 'initial2'], - ], - invalid: [ - ['Invalid1', 'invalid1'], - ['Invalid2', 'invalid2'], - ], - valid: [ - ['Valid1', 'valid1'], - ['Valid2', 'valid2'], - ], - }; - const parentValidator: Blockly.FieldDropdownValidator = function ( - newValue, - ) { - if (newValue == 'invalid') { - return 'valid'; - } - return undefined; - }; - this.appendDummyInput() - .appendField('Parent') - .appendField( - new Blockly.FieldDropdown(parentOptions, parentValidator), - parentFieldName, - ) - .appendField('Child') - .appendField( - new FieldDependentDropdown(parentFieldName, dependentOptions), - childFieldName, - ); - this.setColour(100); - }, -}; diff --git a/plugins/field-dependent-dropdown/test/index.html b/plugins/field-dependent-dropdown/test/index.html deleted file mode 100644 index eb2b560a7..000000000 --- a/plugins/field-dependent-dropdown/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Dependent Dropdown Field Playground - - - - -
    - - - diff --git a/plugins/field-dependent-dropdown/test/index.ts b/plugins/field-dependent-dropdown/test/index.ts deleted file mode 100644 index c69b2e98c..000000000 --- a/plugins/field-dependent-dropdown/test/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Dependent dropdown field test playground. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import './field_dependent_dropdown_test_block'; - -const toolbox: Blockly.utils.toolbox.ToolboxDefinition = { - kind: 'flyoutToolbox', - contents: [ - { - kind: 'block', - type: 'dependent_dropdown_test', - fields: { - /* eslint-disable @typescript-eslint/naming-convention */ - PARENT_FIELD: 'b', - CHILD_FIELD: 'b2', - GRANDCHILD_FIELD: 'b21', - /* eslint-enable @typescript-eslint/naming-convention */ - }, - }, - { - kind: 'block', - type: 'dependent_dropdown_default_options_test', - }, - { - kind: 'block', - type: 'dependent_dropdown_validation_test', - }, - ], -}; - -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.WorkspaceSvg { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions: Blockly.BlocklyOptions = { - toolbox, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/field-dependent-dropdown/tsconfig.json b/plugins/field-dependent-dropdown/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/field-dependent-dropdown/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-grid-dropdown/CHANGELOG.md b/plugins/field-grid-dropdown/CHANGELOG.md deleted file mode 100644 index 900fcadeb..000000000 --- a/plugins/field-grid-dropdown/CHANGELOG.md +++ /dev/null @@ -1,693 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -### Features - -* **field-grid-dropdown:** wrap vertical keyboard focus across columns - -### Bug Fixes - -* **field-grid-dropdown:** announce as a grid popup instead of a listbox -* FieldGridDropdown recomputeAriaContext no longer throws an error ([#2741](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2741)) - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* Bump Blockly dependency to v13 (#2704) - -### Bug Fixes - -* Improve accessibility of grid and colour fields ([#2724](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2724)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [6.0.10](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.9...@blockly/field-grid-dropdown@6.0.10) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.8...@blockly/field-grid-dropdown@6.0.9) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.7...@blockly/field-grid-dropdown@6.0.8) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.6...@blockly/field-grid-dropdown@6.0.7) (2026-01-05) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.5...@blockly/field-grid-dropdown@6.0.6) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.4...@blockly/field-grid-dropdown@6.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.3...@blockly/field-grid-dropdown@6.0.4) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.2...@blockly/field-grid-dropdown@6.0.3) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.1...@blockly/field-grid-dropdown@6.0.2) (2025-07-03) - - -### Bug Fixes - -* prevent Enter/Space from propagating from Grid ([#2570](https://github.com/google/blockly-samples/issues/2570)) ([25ee5a9](https://github.com/google/blockly-samples/commit/25ee5a9a750d819c9dbf00d6513f3b9c6fd302fe)) - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@6.0.0...@blockly/field-grid-dropdown@6.0.1) (2025-05-22) - - -### Bug Fixes - -* **field-grid-dropdown:** add overflow:auto to enable scroll in grid dropdown container ([#2543](https://github.com/google/blockly-samples/issues/2543)) ([f38078d](https://github.com/google/blockly-samples/commit/f38078d6449e40903a4725b14d57aabf414e5bf5)) - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.16...@blockly/field-grid-dropdown@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.15...@blockly/field-grid-dropdown@5.0.16) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.14...@blockly/field-grid-dropdown@5.0.15) (2025-05-15) - - -### Bug Fixes - -* **FieldGridDropdown:** Handle presence of HTMLElement in MenuOptions ([43bdfab](https://github.com/google/blockly-samples/commit/43bdfabeb658331d3991430ec92589ba415dac75)) -* Fix the field-grid-dropdown tests. ([452051e](https://github.com/google/blockly-samples/commit/452051e02520803e7cf85e63e0bfb8191a838a98)) - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.13...@blockly/field-grid-dropdown@5.0.14) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.12...@blockly/field-grid-dropdown@5.0.13) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.11...@blockly/field-grid-dropdown@5.0.12) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.10...@blockly/field-grid-dropdown@5.0.11) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.9...@blockly/field-grid-dropdown@5.0.10) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.8...@blockly/field-grid-dropdown@5.0.9) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.7...@blockly/field-grid-dropdown@5.0.8) (2024-08-22) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.6...@blockly/field-grid-dropdown@5.0.7) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.5...@blockly/field-grid-dropdown@5.0.6) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.4...@blockly/field-grid-dropdown@5.0.5) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.3...@blockly/field-grid-dropdown@5.0.4) (2024-07-11) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.2...@blockly/field-grid-dropdown@5.0.3) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.1...@blockly/field-grid-dropdown@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@5.0.0...@blockly/field-grid-dropdown@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.16...@blockly/field-grid-dropdown@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) -* remove some uses of generateFieldTextBlocks ([#2357](https://github.com/google/blockly-samples/issues/2357)) ([53b3fa4](https://github.com/google/blockly-samples/commit/53b3fa4604aabb1fc5240d41c8d1d389d4b15301)) - - - -## [4.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.15...@blockly/field-grid-dropdown@4.0.16) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.14...@blockly/field-grid-dropdown@4.0.15) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.13...@blockly/field-grid-dropdown@4.0.14) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.12...@blockly/field-grid-dropdown@4.0.13) (2024-04-04) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.11...@blockly/field-grid-dropdown@4.0.12) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.10...@blockly/field-grid-dropdown@4.0.11) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.9...@blockly/field-grid-dropdown@4.0.10) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.8...@blockly/field-grid-dropdown@4.0.9) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.7...@blockly/field-grid-dropdown@4.0.8) (2023-11-09) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.6...@blockly/field-grid-dropdown@4.0.7) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.5...@blockly/field-grid-dropdown@4.0.6) (2023-10-30) - - -### Bug Fixes - -* add the type property to the package.json next to the "main" property: ([#1955](https://github.com/google/blockly-samples/issues/1955)) ([abc713b](https://github.com/google/blockly-samples/commit/abc713b5f3c2941dd4e3a6cbde9060a19b80d189)) -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [4.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.4...@blockly/field-grid-dropdown@4.0.5) (2023-09-21) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.3...@blockly/field-grid-dropdown@4.0.4) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.2...@blockly/field-grid-dropdown@4.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.1...@blockly/field-grid-dropdown@4.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@4.0.0...@blockly/field-grid-dropdown@4.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@3.0.1...@blockly/field-grid-dropdown@4.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@3.0.0...@blockly/field-grid-dropdown@3.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.18...@blockly/field-grid-dropdown@3.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [2.0.18](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.17...@blockly/field-grid-dropdown@2.0.18) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.16...@blockly/field-grid-dropdown@2.0.17) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.15...@blockly/field-grid-dropdown@2.0.16) (2023-05-11) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.14...@blockly/field-grid-dropdown@2.0.15) (2023-05-04) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.13...@blockly/field-grid-dropdown@2.0.14) (2023-04-27) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.12...@blockly/field-grid-dropdown@2.0.13) (2023-04-13) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.11...@blockly/field-grid-dropdown@2.0.12) (2023-03-23) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.10...@blockly/field-grid-dropdown@2.0.11) (2023-03-09) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.9...@blockly/field-grid-dropdown@2.0.10) (2023-03-02) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.8...@blockly/field-grid-dropdown@2.0.9) (2023-02-23) - - -### Bug Fixes - -* remove prepublishOnly scripts ([#1579](https://github.com/google/blockly-samples/issues/1579)) ([27da6cd](https://github.com/google/blockly-samples/commit/27da6cd04c38f6ba417f4e7446bb6218c475448d)) - - - -## [2.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.7...@blockly/field-grid-dropdown@2.0.8) (2023-02-23) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.6...@blockly/field-grid-dropdown@2.0.7) (2023-02-16) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.5...@blockly/field-grid-dropdown@2.0.6) (2023-02-09) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.4...@blockly/field-grid-dropdown@2.0.5) (2023-01-26) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.3...@blockly/field-grid-dropdown@2.0.4) (2023-01-05) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.2...@blockly/field-grid-dropdown@2.0.3) (2022-12-15) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.1...@blockly/field-grid-dropdown@2.0.2) (2022-10-27) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@2.0.0...@blockly/field-grid-dropdown@2.0.1) (2022-10-13) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-grid-dropdown@1.0.47...@blockly/field-grid-dropdown@2.0.0) (2022-10-05) - - -### ⚠ BREAKING CHANGES - -* update peer and devDependencies of all plugins to require Blockly v9 (#1314) - -### Bug Fixes - -* references to deprecated functions in v9 ([#1313](https://github.com/google/blockly-samples/issues/1313)) ([cb2e679](https://github.com/google/blockly-samples/commit/cb2e67987e0b62a77c26adc660cc6ade1ba67954)) - - -### Miscellaneous Chores - -* update peer and devDependencies of all plugins to require Blockly v9 ([#1314](https://github.com/google/blockly-samples/issues/1314)) ([03d4912](https://github.com/google/blockly-samples/commit/03d4912c42c8de0f30493037ccc28dddaea0f266)) - - - -## 1.0.47 (2022-08-11) - - -### Bug Fixes - -* Remove the deprecated block-extension-tooltip ([#1215](https://github.com/google/blockly-samples/issues/1215)) ([a044478](https://github.com/google/blockly-samples/commit/a044478c86a73e3065bc866e427f175cbec6fc13)) - - - - - -## 1.0.46 (2022-08-04) - - -### Bug Fixes - -* fix the name of the package of suggested-blocks ([#1214](https://github.com/google/blockly-samples/issues/1214)) ([35aa8ec](https://github.com/google/blockly-samples/commit/35aa8ec73a60a4eb5b1e80cb2fc71dcd83d05e27)) - - - - - -## 1.0.44 (2022-07-21) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## 1.0.43 (2022-07-06) - - -### Bug Fixes - -* Update blockly-react to use functional components instead of class components. ([#1178](https://github.com/google/blockly-samples/issues/1178)) ([fa21187](https://github.com/google/blockly-samples/commit/fa21187cdbe4ec3a5c69f185540dd68a98eb69d7)) - - - - - -## 1.0.42 (2022-06-27) - - -### Bug Fixes - -* Update package import for keyboard navigation demo ([#1170](https://github.com/google/blockly-samples/issues/1170)) ([69c1725](https://github.com/google/blockly-samples/commit/69c1725b775279fcc397dc178935208d5f42b08c)) - - - - - -## 1.0.41 (2022-06-21) - -**Note:** Version bump only for package @blockly/field-grid-dropdown - - - - - -## 1.0.40 (2022-06-08) - - -### Bug Fixes - -* package versions to support patch releases ([#1150](https://github.com/google/blockly-samples/issues/1150)) ([e1ae378](https://github.com/google/blockly-samples/commit/e1ae378d779531621c3d948566257d069002963f)) - - - - - -## 1.0.39 (2022-06-02) - - -### Bug Fixes - -* add git identity ([#1156](https://github.com/google/blockly-samples/issues/1156)) ([8d80924](https://github.com/google/blockly-samples/commit/8d809243b277375beb2ce75d4e157b5e17f78193)) diff --git a/plugins/field-grid-dropdown/README.md b/plugins/field-grid-dropdown/README.md deleted file mode 100644 index 90b8dd6ac..000000000 --- a/plugins/field-grid-dropdown/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# @blockly/field-grid-dropdown [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) dropdown field with grid layout. - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-grid-dropdown/readme-media/dropdown.png) - -![](https://github.com/RaspberryPiFoundation/blockly-samples/raw/master/plugins/field-grid-dropdown/readme-media/dropdown-images.png) - -## Installation - -### Yarn - -``` -yarn add @blockly/field-grid-dropdown -``` - -### npm - -``` -npm install @blockly/field-grid-dropdown --save -``` - -## Usage - -This field accepts the same parameters as the [Blockly.FieldDropdown](https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/dropdown#creation) -in Blockly core. The config object bag passed into this field accepts additional optional parameters: - -- `"columns"` to specify the number of columns in the dropdown field (must be an integer greater than 0). - If not provided, the default is 3 columns. -- `"primaryColour"` to specify the colour of the dropdown (must be a string CSS colour). If not provided, - the dropdown color will match the primary colour of the parent block. -- `"borderColour"` to specify the colour of the border of the dropdown (must be a string CSS colour). If - not provided, the border colour will match the tertiary colour of the parent block. - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {FieldGridDropdown} from '@blockly/field-grid-dropdown'; -Blockly.Blocks['test_field_grid_dropdown'] = { - init: function () { - this.appendDummyInput() - .appendField('grid dropdown: ') - .appendField( - new FieldGridDropdown([ - ['A', 'A'], - ['B', 'B'], - ['C', 'C'], - ['D', 'D'], - ['E', 'E'], - ['F', 'F'], - ['G', 'G'], - ['H', 'H'], - ]), - 'FIELDNAME', - ); - }, -}; -``` - -### JSON - -```js -import * as Blockly from 'blockly'; -import '@blockly/field-grid-dropdown'; -Blockly.defineBlocksWithJsonArray([ - { - type: 'test_field_grid_dropdown', - message0: 'template: %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [ - ['A', 'A'], - ['B', 'B'], - ['C', 'C'], - ['D', 'D'], - ['E', 'E'], - ['F', 'F'], - ['G', 'G'], - ['H', 'H'], - ], - }, - ], - }, -]); -``` - -## License - -Apache 2.0 diff --git a/plugins/field-grid-dropdown/package.json b/plugins/field-grid-dropdown/package.json deleted file mode 100644 index 40299c9ba..000000000 --- a/plugins/field-grid-dropdown/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "@blockly/field-grid-dropdown", - "version": "13.2.0", - "description": "A Blockly dropdown field with grid layout.", - "scripts": { - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "npm run build && blockly-scripts predeploy", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "blockly-plugin", - "blockly-field", - "grid-dropdown" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-grid-dropdown#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-grid-dropdown" - }, - "license": "Apache 2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-grid-dropdown/readme-media/dropdown-images.png b/plugins/field-grid-dropdown/readme-media/dropdown-images.png deleted file mode 100644 index c5d091dd1ee267e8c0251c6e95abce2cd23f2946..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14349 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 diff --git a/plugins/field-grid-dropdown/readme-media/dropdown.png b/plugins/field-grid-dropdown/readme-media/dropdown.png deleted file mode 100644 index 62fad4e368e22940e6f5bacc1256b28bb1262f77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8813 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 diff --git a/plugins/field-grid-dropdown/src/grid.ts b/plugins/field-grid-dropdown/src/grid.ts deleted file mode 100644 index 3266c6113..000000000 --- a/plugins/field-grid-dropdown/src/grid.ts +++ /dev/null @@ -1,391 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - browserEvents, - common, - FieldDropdown, - ImageProperties, - MenuOption, - utils, - WorkspaceSvg, -} from 'blockly/core'; -import {GridItem} from './grid_item'; - -/** - * Class for managing a group of items displayed in a grid. - */ -export class Grid { - /** Mapping from grid item ID to index in the items list. */ - private itemIndices = new Map(); - - /** List of items displayed in this grid. */ - private items = new Array(); - - /** Root DOM element of this grid. */ - private root: HTMLDivElement; - - /** Identifier for keydown handler to be unregistered in dispose(). */ - private keyDownHandler: browserEvents.Data | null = null; - - /** Identifier for pointermove handler to be unregistered in dispose(). */ - private pointerMoveHandler: browserEvents.Data | null = null; - - /** Function to be called when an item in this grid is selected. */ - private selectionCallback?: (selectedItem: GridItem) => void; - - /** - * Creates a new Grid instance. - * - * @param container The parent element of this grid in the DOM. - * @param options A list of MenuOption objects representing the items to be - * shown in this grid. - * @param columns The number of columns to display items in. - * @param rtl True if this grid is being shown in a right-to-left environment. - * @param selectionCallback Function to be called when an item in the grid is - * selected. - */ - constructor( - container: HTMLElement, - options: MenuOption[], - private readonly columns: number, - private readonly rtl: boolean, - selectionCallback: (selectedItem: GridItem) => void, - ) { - this.selectionCallback = selectionCallback; - - this.root = document.createElement('div'); - this.root.className = 'blocklyFieldGrid'; - this.root.tabIndex = 0; - utils.aria.setRole(this.root, utils.aria.Role.GRID); - container.appendChild(this.root); - - this.populateItems(options); - - this.keyDownHandler = browserEvents.conditionalBind( - this.root, - 'keydown', - this, - this.onKeyDown, - ); - - this.pointerMoveHandler = browserEvents.conditionalBind( - this.root, - 'pointermove', - this, - this.onPointerMove, - true, - ); - - if (columns >= 1) { - this.columns = columns; - this.root.style.setProperty('--grid-columns', `${this.columns}`); - } else { - throw new Error(`Number of columns must be >= 1; got ${columns}`); - } - } - - /** - * Creates grid items in the DOM given a list of model objects. - * - * @param options A list of grid item model objects. - */ - private populateItems(options: MenuOption[]) { - let row = document.createElement('div'); - for (const [index, item] of options.entries()) { - // TODO(#2507): Don't just ignore separators. - if (item === FieldDropdown.SEPARATOR) continue; - - if (index % this.columns === 0) { - row = document.createElement('div'); - row.className = 'blocklyFieldGridRow'; - utils.aria.setRole(row, utils.aria.Role.ROW); - this.root.appendChild(row); - } - - const [label, value, ariaLabel] = item; - const content = (() => { - if (isImageProperties(label)) { - // Convert ImageProperties to an HTMLImageElement. - const image = new Image(label.width, label.height); - image.src = label.src; - image.alt = label.alt || ''; - return image; - } - return label; - })(); - - const gridItem = new GridItem( - row, - content, - value, - ariaLabel, - (selectedItem: GridItem) => { - this.setSelectedValue(selectedItem.getValue()); - this.selectionCallback?.(selectedItem); - }, - ); - this.itemIndices.set(gridItem.getId(), this.itemIndices.size); - this.items.push(gridItem); - } - } - - /** - * Disposes of this grid. - */ - dispose() { - this.selectionCallback = undefined; - for (const item of this.items) { - item.dispose(); - } - this.itemIndices.clear(); - this.items.length = 0; - if (this.keyDownHandler) { - browserEvents.unbind(this.keyDownHandler); - this.keyDownHandler = null; - } - - if (this.pointerMoveHandler) { - browserEvents.unbind(this.pointerMoveHandler); - this.pointerMoveHandler = null; - } - this.root.remove(); - } - - /** - * Handles a keydown event in the grid, generally by moving focus. - * - * @param e The keydown event to handle. - */ - private onKeyDown(e: KeyboardEvent) { - if ( - !this.items.length || - e.shiftKey || - e.ctrlKey || - e.metaKey || - e.altKey - ) { - return; - } - - switch (e.key) { - case 'ArrowUp': - this.moveFocus(-1, true, false); - break; - case 'ArrowDown': - this.moveFocus(1, true, false); - break; - case 'ArrowLeft': - this.moveFocus(-1 * (this.rtl ? -1 : 1), true, true); - break; - case 'ArrowRight': - this.moveFocus(1 * (this.rtl ? -1 : 1), true, true); - break; - case 'PageUp': - case 'Home': - this.moveFocus(0, false, true); - break; - case 'PageDown': - case 'End': - this.moveFocus(this.items.length - 1, false, true); - break; - case 'Enter': - case 'Space': - // Handled via GridItem click handler, so we want its default but it - // must not propagate. - e.stopPropagation(); - return; - default: - // Not a key the grid is interested in. - return; - } - // The grid used this key, don't let it have secondary effects. - e.preventDefault(); - e.stopPropagation(); - } - - /** - * Handles a pointermove event in the grid by focusing the hovered item. - * - * @param e The pointermove event to handle. - */ - private onPointerMove(e: PointerEvent) { - // Don't highlight grid items on "pointermove" if the pointer didn't - // actually move (but the content under it did due to e.g. scrolling into - // view), or if the target isn't an Element, which should never happen, but - // TS needs to be reassured of that. - if (!(e.movementX || e.movementY) || !(e.target instanceof Element)) return; - - const gridItem = e.target.closest('.blocklyFieldGridItem'); - if (!gridItem) return; - - const targetId = gridItem.id; - const targetIndex = this.itemIndices.get(targetId); - if (targetIndex === undefined) return; - this.moveFocus(targetIndex, false, true); - } - - /** - * Selects the item with the given value in the grid. - * - * @param value The value of the grid item to select. - */ - setSelectedValue(value: string) { - for (const [index, item] of this.items.entries()) { - const selected = item.getValue() === value; - item.setSelected(selected); - if (selected) { - this.moveFocus(index, false, true); - } - } - } - - /** - * Moves browser focus to the grid item at the given index. - * - * @param movementIndex The absolute or directionally relative index of the - * item to focus. - * @param relative True to interpret the index as relative to the currently - * focused item, false to move focus to it as an absolute value. - * @param horizontal True for a left/right move. False for an up/down move. - * Vertical moves wrap to the next/previous column at column edges, but - * do not wrap around the ends of the grid. - */ - private moveFocus( - movementIndex: number, - relative: boolean, - horizontal: boolean, - ) { - let targetIndex = movementIndex; - - if (relative) { - const focusedItem = this.getFocusedItem(); - if (!focusedItem) return; - const currentIndex = this.indexOfItem(focusedItem); - - if (horizontal) { - targetIndex += currentIndex; - } else { - targetIndex = this.getVerticalTargetIndex(currentIndex, movementIndex); - } - } - - const targetItem = this.itemAtIndex(targetIndex); - if (!targetItem) { - const workspace = common.getMainWorkspace(); - if (workspace instanceof WorkspaceSvg) { - workspace.getAudioManager().playErrorBeep(); - } - return; - } - - targetItem.focus(); - utils.aria.setState( - this.root, - utils.aria.State.ACTIVEDESCENDANT, - targetItem.getId(), - ); - } - - /** - * Returns the index to focus after a vertical move from the given index. - * - * Prefers moving within the same column. At a column edge, wraps to the - * first/last item of the adjacent column. Returns an out-of-bounds index - * when movement is blocked at the start or end of the grid. - * - * @param currentIndex The currently focused item index. - * @param direction 1 to move down, -1 to move up. - * @returns The target item index. - */ - private getVerticalTargetIndex( - currentIndex: number, - direction: number, - ): number { - // First try moving to the vertically adjacent item in the same column. - const column = currentIndex % this.columns; - const row = Math.floor(currentIndex / this.columns); - const targetIndex = (row + direction) * this.columns + column; - - if (this.itemAtIndex(targetIndex)) { - return targetIndex; - } - - // We are past this column's edge, so wrap to the adjacent column. - const targetColumn = column + direction; - if (targetColumn < 0 || targetColumn >= this.columns) { - return targetIndex; - } - - const columnItems = this.items.filter( - (item, i) => i % this.columns === targetColumn, - ); - const item = - direction > 0 ? columnItems[0] : columnItems[columnItems.length - 1]; - return this.indexOfItem(item); - } - - /** - * Returns the index of the given item within the grid. - * - * @param item The item to return the index of. - * @returns The index of the given item within the grid. - */ - private indexOfItem(item: GridItem): number { - return this.itemIndices.get(item.getId()) ?? -1; - } - - /** - * Returns the GridItem object at the given index in the grid. - * - * @param index The index to retrieve the grid item at. - * @returns The GridItem at the given index, or undefined if the index is - * invalid. - */ - private itemAtIndex(index: number): GridItem | undefined { - return this.items[index]; - } - - /** - * Returns the currently focused grid item, if any. - * - * @returns The focused grid item, or undefined if no item is focused. - */ - private getFocusedItem(): GridItem | undefined { - const element = - this.root.querySelector('.blocklyFieldGridItem:focus') ?? - this.root.querySelector('.blocklyFieldGridItem'); - if (!element || !element.id) return undefined; - - const index = this.itemIndices.get(element.id); - if (index === undefined) return undefined; - - return this.itemAtIndex(index); - } -} - -/** - * Returns whether or not an object conforms to the ImageProperties - * interface. - * - * @param obj The object to test. - * @returns True iff the object conforms to ImageProperties. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isImageProperties(obj: any): obj is ImageProperties { - return ( - obj && - typeof obj === 'object' && - 'src' in obj && - typeof obj.src === 'string' && - 'alt' in obj && - typeof obj.alt === 'string' && - 'width' in obj && - typeof obj.width === 'number' && - 'height' in obj && - typeof obj.height === 'number' - ); -} diff --git a/plugins/field-grid-dropdown/src/grid_item.ts b/plugins/field-grid-dropdown/src/grid_item.ts deleted file mode 100644 index 3d78842b5..000000000 --- a/plugins/field-grid-dropdown/src/grid_item.ts +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {browserEvents, utils} from 'blockly/core'; - -/** - * Class representing an item in a grid. - */ -export class GridItem { - /** The DOM element for the grid item. */ - private element: HTMLButtonElement; - - /** Identifier for a click handler to unregister during dispose(). */ - private clickHandler: browserEvents.Data | null; - - /** Callback to invoke when this item is selected. */ - private selectionCallback: ((selectedItem: GridItem) => void) | null; - - /** Whether or not this item is currently selected. */ - private selected = false; - - /** - * Creates a new GridItem. - * - * @param container The parent element of this grid item in the DOM. - * @param content The content to display in this grid item. - * @param value The programmatic value of this grid item. - * @param ariaLabel An accessibility label that describes the contents of this - * grid item to screenreaders. - * @param selectionCallback Function to call when this item is selected. - */ - constructor( - container: HTMLElement, - content: string | HTMLElement, - private readonly value: string, - ariaLabel: string | undefined, - selectionCallback: (selectedItem: GridItem) => void, - ) { - this.selectionCallback = selectionCallback; - - const cell = document.createElement('div'); - utils.aria.setRole(cell, utils.aria.Role.GRIDCELL); - - this.element = document.createElement('button'); - this.element.id = utils.idGenerator.getNextUniqueId(); - this.element.className = 'blocklyFieldGridItem'; - this.clickHandler = browserEvents.conditionalBind( - this.element, - 'click', - this, - this.onClick, - true, - ); - cell.appendChild(this.element); - container.appendChild(cell); - - const contentDom = - typeof content === 'string' ? document.createTextNode(content) : content; - this.element.appendChild(contentDom); - - if (ariaLabel) { - utils.aria.setState(this.element, utils.aria.State.LABEL, ariaLabel); - } - } - - /** - * Disposes of this grid item. - */ - dispose() { - this.selectionCallback = null; - this.element.remove(); - if (this.clickHandler) { - browserEvents.unbind(this.clickHandler); - this.clickHandler = null; - } - } - - /** - * Gets the unique (within the grid) ID for this grid item. - * - * @returns This item's unique ID. - */ - getId(): string { - return this.element.id; - } - - /** - * Gets the value associated with this grid item. - * - * @returns Value associated with this grid item. - */ - getValue(): string { - return this.value; - } - - /** - * Returns whether or not this grid item is selected. - * - * @returns True if this grid item is selected, otherwise false. - */ - isSelected() { - return this.selected; - } - - /** - * Sets whether or not this grid item is selected. - * - * @param selected True if this grid item should be selected, otherwise false. - */ - setSelected(selected: boolean) { - this.selected = selected; - utils.aria.setState(this.element, utils.aria.State.SELECTED, this.selected); - this.element.classList.toggle( - 'blocklyFieldGridItemSelected', - this.selected, - ); - if (this.isSelected()) { - this.focus(); - } - } - - /** - * Handles clicks on this grid item by marking it as selected. - */ - private onClick() { - this.setSelected(true); - this.selectionCallback?.(this); - } - - /** - * Makes this grid item the browser focus target, and scrolls it into view - * if needed. - */ - focus() { - // Focus the element, but don't scroll the document since that's too - // aggressive. - this.element.focus({preventScroll: true}); - - const scrollingParent = this.element.offsetParent; - if (!scrollingParent) return; - const offsetTop = this.element.offsetTop; - const scrollTop = scrollingParent.scrollTop; - const spacing = this.getInterItemSpacing(); - - // Scroll the element into view if it's offscreen above the grid's viewport. - if (offsetTop < scrollTop) { - scrollingParent.scrollTo(0, offsetTop - spacing); - } else if ( - offsetTop + this.element.offsetHeight > - scrollTop + scrollingParent.clientHeight - ) { - // Scroll into view if this item is below the grid's viewport. - scrollingParent.scrollBy( - 0, - offsetTop + - this.element.clientHeight - - (scrollTop + scrollingParent.clientHeight) + - spacing, - ); - } - } - - /** - * Returns the vertical spacing between grid items in pixels. - * - * This value can be specified by the user in CSS, so we can't just use a - * hardcoded value. Moreover, while we could check our computed style, the - * grid gap can be specified in several units. Instead, this somewhat hackily - * finds all the sibling items in this grid and loops through them until it - * encounters one with a different vertical location from its predecessor, - * then computes the effective gap based on their relative position and - * height. - * - * @returns The vertical distance between items in this grid. - */ - private getInterItemSpacing() { - const grid = this.element.closest('.blocklyFieldGrid'); - if (!grid) return 0; - - const items = [ - ...grid.querySelectorAll('.blocklyFieldGridItem'), - ] as HTMLElement[]; - if (!items.length) return 0; - - const initialTop = items[0].offsetTop; - const initialHeight = items[0].offsetHeight; - for (const item of items) { - if (item.offsetTop !== initialTop) { - return item.offsetTop - initialHeight - initialTop; - } - } - - return 0; - } -} diff --git a/plugins/field-grid-dropdown/src/index.ts b/plugins/field-grid-dropdown/src/index.ts deleted file mode 100644 index f0c881045..000000000 --- a/plugins/field-grid-dropdown/src/index.ts +++ /dev/null @@ -1,283 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Grid dropdown field. - * @author kozbial@google.com (Monica Kozbial) - */ - -import * as Blockly from 'blockly/core'; -import {Grid} from './grid'; -import type {GridItem} from './grid_item'; - -/** - * A config object for defining a field grid dropdown. - */ -export interface FieldGridDropdownConfig extends Blockly.FieldDropdownConfig { - columns?: string | number; - primaryColour?: string; - borderColour?: string; -} - -/** - * Construct a FieldGridDropdown from a JSON arg object. - */ -export interface FieldGridDropdownFromJsonConfig extends FieldGridDropdownConfig { - options?: Blockly.MenuGenerator; -} - -type FieldGridDropdownValidator = Blockly.FieldDropdownValidator; - -/** - * Grid dropdown field. - */ -export class FieldGridDropdown extends Blockly.FieldDropdown { - /** - * The number of columns in the dropdown grid. Must be an integer value - * greater than 0. Defaults to 3. - */ - private columns = 3; - - private primaryColour?: string; - - private borderColour?: string; - - /** Object representing the grid of choices shown in the dropdown. */ - private grid: Grid | null = null; - - protected override ariaTypeName = Blockly.Msg['ARIA_TYPE_FIELD_GRID']; - - /** - * Class for an grid dropdown field. - * - * @param menuGenerator A non-empty array of options for a dropdown list, - * or a function which generates these options. - * @param validator A function that is called to validate - * changes to the field's value. Takes in a language-neutral dropdown - * option & returns a validated language-neutral dropdown option, or null - * to abort the change. - * @param config A map of options used to configure the field. - * See the [field creation documentation]{@link - * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/dropdown#creation} - * for a list of properties this parameter supports. - * @extends {Blockly.Field} - * @constructor - * @throws {TypeError} If `menuGenerator` options are incorrectly structured. - */ - constructor( - menuGenerator: Blockly.MenuGenerator, - validator?: FieldGridDropdownValidator, - config?: FieldGridDropdownConfig, - ) { - super(menuGenerator, validator, config); - - if (config?.columns) { - this.setColumns(parseInt(`${config.columns}`)); - } - - if (config && config.primaryColour) { - this.primaryColour = config.primaryColour; - } - - if (config && config.borderColour) { - this.borderColour = config.borderColour; - } - } - - /** - * Constructs a FieldGridDropdown from a JSON arg object. - * - * @param config A JSON object with options. - * @returns The new field instance. - * @package - * @nocollapse - */ - static fromJson(config: FieldGridDropdownFromJsonConfig) { - if (!config.options) { - throw new Error( - 'options are required for the dropdown field. The ' + - 'options property must be assigned an array of ' + - '[humanReadableValue, languageNeutralValue] tuples.', - ); - } - // `this` might be a subclass of FieldDropdown if that class doesn't - // override the static fromJson method. - return new this(config.options, undefined, config); - } - - /** - * Sets the number of columns on the grid. Updates the styling to reflect. - * - * @param columns The number of columns. Is rounded to - * an integer value and must be greater than 0. Invalid - * values are ignored. - */ - setColumns(columns: number) { - if (!isNaN(columns) && columns >= 1) { - this.columns = columns; - // If the field is currently being shown, reload the grid. - if ( - Blockly.DropDownDiv.getOwner() === this && - Blockly.DropDownDiv.isVisible() - ) { - this.grid?.dispose(); - this.showEditor_(); - } - } - } - - /** - * Updates the ARIA roles and label for this field. - */ - override recomputeAriaContext(): boolean { - const shouldCustomize = super.recomputeAriaContext(); - if (!shouldCustomize) return false; - const focusableElement = this.getFocusableElement(); - Blockly.utils.aria.setState( - focusableElement, - Blockly.utils.aria.State.HASPOPUP, - 'grid', - ); - Blockly.utils.aria.setState( - focusableElement, - Blockly.utils.aria.State.EXPANDED, - !!this.grid, - ); - return true; - } - - /* eslint-disable @typescript-eslint/naming-convention */ - /** - * Create a dropdown menu under the text. - * - * @param e Optional mouse event that triggered the field to open, or - * undefined if triggered programmatically. - */ - protected showEditor_(e?: MouseEvent) { - Blockly.DropDownDiv.clearContent(); - const rtl = !!this.getSourceBlock()?.workspace.RTL; - this.grid = new Grid( - Blockly.DropDownDiv.getContentDiv(), - this.getOptions(false), - this.columns, - rtl, - (selectedItem: GridItem) => { - Blockly.DropDownDiv.hideIfOwner(this); - this.setValue(selectedItem.getValue()); - }, - ); - - Blockly.DropDownDiv.getContentDiv().classList.add( - 'blocklyFieldGridContainer', - ); - - const colours = this.getColours(); - if (colours && colours.border) { - Blockly.DropDownDiv.setColour(colours.primary, colours.border); - } - - Blockly.DropDownDiv.showPositionedByField( - this, - this.dropdownDispose_.bind(this), - ); - - const selectedValue = this.getValue(); - if (selectedValue) { - this.grid.setSelectedValue(selectedValue); - } - this.recomputeAriaContext(); - } - - /** - * Disposes of events and DOM-references belonging to the dropdown editor. - */ - protected override dropdownDispose_() { - // Keep aria-expanded accurate on later recomputes. - this.grid = null; - super.dropdownDispose_(); - this.recomputeAriaContext(); - } - - /** - * Updates the field's value to the given value. - * - * @param newValue The new value for this field. - */ - protected override doValueUpdate_(newValue: string) { - super.doValueUpdate_(newValue); - this.grid?.setSelectedValue(newValue); - } - - /** - * Determine the colours for the dropdowndiv. The dropdown should match block - * colour unless other colours are specified in the config. - * - * @returns The colours to set for the dropdowndiv. - */ - private getColours() { - if (this.primaryColour && this.borderColour) { - return { - primary: this.primaryColour, - border: this.borderColour, - }; - } - - const sourceBlock = this.getSourceBlock(); - if (!(sourceBlock instanceof Blockly.BlockSvg)) return; - - const colourSource = sourceBlock.isShadow() - ? sourceBlock.getParent() - : sourceBlock; - if (!colourSource) return; - - return { - primary: this.primaryColour ?? colourSource.getColour(), - border: this.borderColour ?? colourSource.getColourTertiary(), - }; - } -} - -Blockly.fieldRegistry.register('field_grid_dropdown', FieldGridDropdown); - -/** - * CSS for grid field. - */ -Blockly.Css.register(` - .blocklyFieldGridContainer { - padding: 7px; - overflow: auto; - } - - .blocklyFieldGrid { - display: grid; - grid-gap: 7px; - grid-template-columns: repeat(var(--grid-columns), min-content); - } - - .blocklyFieldGrid .blocklyFieldGridItem { - border: 1px solid rgba(1, 1, 1, 0.5); - border-radius: 4px; - color: white; - min-width: auto; - background: none; - white-space: nowrap; - cursor: pointer; - padding: 6px 15px; - } - - .blocklyFieldGrid .blocklyFieldGridRow { - display: contents; - } - - .blocklyFieldGrid .blocklyFieldGridItem.blocklyFieldGridItemSelected { - background-color: rgba(1, 1, 1, 0.25); - } - - .blocklyFieldGrid .blocklyFieldGridItem:focus { - box-shadow: 0 0 0 4px hsla(0, 0%, 100%, .2); - outline: none; - } - `); diff --git a/plugins/field-grid-dropdown/test/field_test.mocha.js b/plugins/field-grid-dropdown/test/field_test.mocha.js deleted file mode 100644 index 6ba8fa1be..000000000 --- a/plugins/field-grid-dropdown/test/field_test.mocha.js +++ /dev/null @@ -1,218 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {testHelpers} = require('@blockly/dev-tools'); -const {FieldGridDropdown} = require('../src/index'); - -const { - assertFieldValue, - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -suite('FieldGridDropdown', function () { - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueCreationTestCases = [ - {title: 'Undefined', args: [undefined]}, - {title: 'Array Items not Arrays', args: [undefined]}, - { - title: 'Array Items with Invalid IDs', - args: [ - [ - ['1', 1], - ['2', 2], - ['3', 3], - ], - ], - }, - { - title: 'Array Items with Invalid Content', - args: [ - [ - [1, '1'], - [2, '2'], - [3, '3'], - ], - ], - }, - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueCreationTestCases = [ - { - title: 'Text Dropdown', - value: 'A', - expectedValue: 'A', - expectedText: 'a', - args: [ - [ - ['a', 'A'], - ['b', 'B'], - ['c', 'C'], - ], - ], - }, - { - title: 'Image Dropdown', - value: 'A', - expectedValue: 'A', - expectedText: 'a', - args: [ - [ - [{src: 'scrA', alt: 'a', width: 0, height: 0}, 'A'], - [{src: 'scrB', alt: 'b', width: 0, height: 0}, 'B'], - [{src: 'scrC', alt: 'c', width: 0, height: 0}, 'C'], - ], - ], - }, - { - title: 'Dynamic Text Dropdown', - value: 'A', - expectedValue: 'A', - expectedText: 'a', - args: [ - () => { - return [ - ['a', 'A'], - ['b', 'B'], - ['c', 'C'], - ]; - }, - ], - }, - { - title: 'Dynamic Image Dropdown', - value: 'A', - expectedValue: 'A', - expectedText: 'a', - args: [ - () => { - return [ - [{src: 'scrA', alt: 'a', width: 0, height: 0}, 'A'], - [{src: 'scrB', alt: 'b', width: 0, height: 0}, 'B'], - [{src: 'scrC', alt: 'c', width: 0, height: 0}, 'C'], - ]; - }, - ], - }, - ]; - const addJson = function (testCase) { - testCase.json = {options: testCase.args[0]}; - }; - invalidValueCreationTestCases.forEach(addJson); - validValueCreationTestCases.forEach(addJson); - - /** - * Asserts that the field properties are correct based on the test case. - * @param {!FieldGridDropdown} field The field to check. - * @param {!FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertFieldValue(field, testCase.expectedValue, testCase.expectedText); - }; - - runConstructorSuiteTests( - FieldGridDropdown, - validValueCreationTestCases, - invalidValueCreationTestCases, - validTestCaseAssertField, - ); - - runFromJsonSuiteTests( - FieldGridDropdown, - validValueCreationTestCases, - invalidValueCreationTestCases, - validTestCaseAssertField, - ); - - /** - * Configuration for field tests with invalid values. - * @type {!Array} - */ - const invalidValueSetValueTestCases = [ - {title: 'Null', value: null}, - {title: 'Undefined', value: undefined}, - {title: 'Invalid ID', value: 'bad'}, - ]; - /** - * Configuration for field tests with valid values. - * @type {!Array} - */ - const validValueSetValueTestCases = [ - {title: 'Valid ID', value: 'B', expectedValue: 'B', expectedText: 'b'}, - ]; - - suite('setValue', function () { - setup(function () { - this.field = new FieldGridDropdown([ - ['a', 'A'], - ['b', 'B'], - ['c', 'C'], - ]); - }); - runSetValueTests( - validValueSetValueTestCases, - invalidValueSetValueTestCases, - 'A', - 'a', - ); - }); - - suite('Validators', function () { - setup(function () { - this.dropdownField = new FieldGridDropdown([ - ['1a', '1A'], - ['1b', '1B'], - ['1c', '1C'], - ['2a', '2A'], - ['2b', '2B'], - ['2c', '2C'], - ]); - }); - teardown(function () { - this.dropdownField.setValidator(null); - }); - suite('Null Validator', function () { - setup(function () { - this.dropdownField.setValidator(function () { - return null; - }); - }); - test('New Value', function () { - this.dropdownField.setValue('1B'); - assertFieldValue(this.dropdownField, '1A', '1a'); - }); - }); - suite('Force 1s Validator', function () { - setup(function () { - this.dropdownField.setValidator(function (newValue) { - return '1' + newValue.charAt(1); - }); - }); - test('New Value', function () { - this.dropdownField.setValue('2B'); - assertFieldValue(this.dropdownField, '1B', '1b'); - }); - }); - suite('Returns Undefined Validator', function () { - setup(function () { - this.dropdownField.setValidator(function () {}); - }); - test('New Value', function () { - this.dropdownField.setValue('1B'); - assertFieldValue(this.dropdownField, '1B', '1b'); - }); - }); - }); -}); diff --git a/plugins/field-grid-dropdown/test/index.html b/plugins/field-grid-dropdown/test/index.html deleted file mode 100644 index 10cd0a0c1..000000000 --- a/plugins/field-grid-dropdown/test/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Blockly Field Test - - - - -
    - - - diff --git a/plugins/field-grid-dropdown/test/index.ts b/plugins/field-grid-dropdown/test/index.ts deleted file mode 100644 index 9ccc35fd8..000000000 --- a/plugins/field-grid-dropdown/test/index.ts +++ /dev/null @@ -1,468 +0,0 @@ -/** - * @license - * Copyright 2020 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Field test. - */ - -import * as Blockly from 'blockly'; -import {createPlayground} from '@blockly/dev-tools'; -import '../src/index'; - -/** - * An array of blocks that are defined only for the purposes of - * manually and visually testing the dropdown grid field. - */ -const testBlockDefinitions = [ - { - type: 'test_standard_field_values', - message0: '%1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [['A', 'A']], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values', - message0: 'Different text length %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [ - ['A', 'A'], - ['long text ', 'long text'], - ['B', 'B'], - ['C', 'C'], - [ - 'really really really loooooong text', - 'really really really loooooong text', - ], - ['D', 'D'], - ['E', 'E'], - ], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_long_text_list', - message0: 'Long text list %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [ - ['A', 'A'], - ['B', 'B'], - ['C', 'C'], - ['D', 'D'], - ['E', 'E'], - ['D', 'F'], - ['G', 'G'], - ['H', 'H'], - ['I', 'I'], - ['J', 'J'], - ['K', 'K'], - ['L', 'L'], - ['M', 'M'], - ['N', 'N'], - ['O', 'O'], - ['P', 'P'], - ['Q', 'Q'], - ['R', 'R'], - ['S', 'S'], - ['T', 'T'], - ['U', 'U'], - ['V', 'V'], - ['W', 'W'], - ['X', 'X'], - ['Y', 'Y'], - ['Z', 'Z'], - ], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_images', - message0: 'Images %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [ - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/a.png', - width: 32, - height: 32, - alt: 'A', - }, - 'A', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/b.png', - width: 32, - height: 32, - alt: 'B', - }, - 'B', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/c.png', - width: 32, - height: 32, - alt: 'C', - }, - 'C', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/d.png', - width: 32, - height: 32, - alt: 'D', - }, - 'D', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/e.png', - width: 32, - height: 32, - alt: 'E', - }, - 'E', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/f.png', - width: 32, - height: 32, - alt: 'F', - }, - 'F', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/g.png', - width: 32, - height: 32, - alt: 'G', - }, - 'G', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/h.png', - width: 32, - height: 32, - alt: 'H', - }, - 'H', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/i.png', - width: 32, - height: 32, - alt: 'I', - }, - 'I', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/j.png', - width: 32, - height: 32, - alt: 'J', - }, - 'J', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/k.png', - width: 32, - height: 32, - alt: 'K', - }, - 'K', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/l.png', - width: 32, - height: 32, - alt: 'L', - }, - 'L', - ], - [ - { - src: 'https://blockly-demo.appspot.com/static/tests/media/m.png', - width: 32, - height: 32, - alt: 'M', - }, - 'M', - ], - ], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_4_columns', - message0: '4 columns %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - columns: '4', - options: [ - ['A', 'A'], - ['B', 'B'], - ['C', 'C'], - ['D', 'D'], - ['E', 'E'], - ['F', 'F'], - ['G', 'G'], - ['H', 'H'], - ], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_custom_colours', - message0: 'Custom colours %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - primaryColour: '#783105', - borderColour: '#d6a587', - options: [ - ['A', 'A'], - ['B', 'B'], - ['C', 'C'], - ['D', 'D'], - ['E', 'E'], - ['F', 'F'], - ['G', 'G'], - ['H', 'H'], - ], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_standard_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [['A', 'A']], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_custom_field_values_and_label', - message0: 'block %1', - args0: [ - { - type: 'field_grid_dropdown', - name: 'FIELDNAME', - options: [['A', 'A']], - alt: { - type: 'field_label', - text: `No field_grid_dropdown`, - }, - }, - ], - output: null, - style: 'math_blocks', - }, - { - type: 'test_parent_block', - message0: 'parent %1', - args0: [ - { - type: 'input_value', - name: 'INPUT', - }, - ], - previousStatement: null, - nextStatement: null, - style: 'loop_blocks', - }, -]; - -Blockly.defineBlocksWithJsonArray(testBlockDefinitions); - -/** - * A test toolbox containing the exported blocks and a variety of - * test blocks to exercise the dropdown grid field in different contexts - * (on a shadow block, as the only field on a block, etc). - * These are in a simple toolbox, rather than a category toolbox, so that - * they are all instantiated every time the test page is opened. - */ -const jsonToolbox = { - contents: [ - { - kind: 'label', - text: 'Test blocks: default field values', - }, - { - kind: 'block', - type: 'test_standard_field_values', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_standard_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_standard_field_values_and_label', - }, - }, - }, - }, - { - kind: 'label', - text: 'Test blocks: custom field values', - }, - { - kind: 'block', - type: 'test_custom_field_values', - }, - { - kind: 'block', - type: 'test_custom_field_values_long_text_list', - }, - { - kind: 'block', - type: 'test_custom_field_values_images', - }, - { - kind: 'block', - type: 'test_custom_field_values_4_columns', - }, - { - kind: 'block', - type: 'test_custom_field_values_custom_colours', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values', - }, - }, - }, - }, - { - kind: 'block', - type: 'test_custom_field_values_and_label', - }, - { - kind: 'block', - type: 'test_parent_block', - inputs: { - INPUT: { - shadow: { - type: 'test_custom_field_values_and_label', - }, - }, - }, - }, - ], -}; -/** - * Create a workspace. - * - * @param blocklyDiv The blockly container div. - * @param options The Blockly options. - * @returns The created workspace. - */ -function createWorkspace( - blocklyDiv: HTMLElement, - options: Blockly.BlocklyOptions, -): Blockly.Workspace { - const workspace = Blockly.inject(blocklyDiv, options); - return workspace; -} - -document.addEventListener('DOMContentLoaded', function () { - const defaultOptions: Blockly.BlocklyOptions = { - toolbox: jsonToolbox, - }; - const rootElement = document.getElementById('root'); - if (rootElement) { - createPlayground(rootElement, createWorkspace, defaultOptions); - } -}); diff --git a/plugins/field-grid-dropdown/tsconfig.json b/plugins/field-grid-dropdown/tsconfig.json deleted file mode 100644 index 99858c525..000000000 --- a/plugins/field-grid-dropdown/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "module": "es2015", - "moduleResolution": "bundler", - "target": "es6", - "strict": true - }, - // NOTE: `test/**/*` is automatically included in `blockly-scripts start`. - // Only src matters for production builds. - "include": ["src"] -} diff --git a/plugins/field-multilineinput/CHANGELOG.md b/plugins/field-multilineinput/CHANGELOG.md deleted file mode 100644 index c1ab6b43f..000000000 --- a/plugins/field-multilineinput/CHANGELOG.md +++ /dev/null @@ -1,519 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [13.2.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.1.0...v13.2.0) (2026-07-28) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [13.1.0](https://github.com/RaspberryPiFoundation/blockly-samples/compare/v13.0.0...v13.1.0) (2026-06-30) - -### ⚠ BREAKING CHANGES - -* make field-multilineinput keyboard navigable and accessible (#2729) -* Bump Blockly dependency to v13 (#2704) - -### Features - -* make field-multilineinput keyboard navigable and accessible ([#2729](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2729)) - -### Miscellaneous Chores - -* Bump Blockly dependency to v13 ([#2704](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2704)) - - -## [6.0.9](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-multilineinput@6.0.8...@blockly/field-multilineinput@6.0.9) (2026-04-09) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [6.0.8](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-multilineinput@6.0.7...@blockly/field-multilineinput@6.0.8) (2026-01-15) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [6.0.7](https://github.com/RaspberryPiFoundation/blockly-samples/compare/@blockly/field-multilineinput@6.0.6...@blockly/field-multilineinput@6.0.7) (2026-01-05) - - -### Bug Fixes - -* update plugin URLs to RPF ([#2665](https://github.com/RaspberryPiFoundation/blockly-samples/issues/2665)) ([6c34039](https://github.com/RaspberryPiFoundation/blockly-samples/commit/6c3403960b8070eb8e576bd5702bdb53a09ac475)) - - - -## [6.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@6.0.5...@blockly/field-multilineinput@6.0.6) (2026-01-05) - - -### Bug Fixes - -* Merge multiline text readme to with pre-v11 documentation ([#2660](https://github.com/google/blockly-samples/issues/2660)) ([c8d0bd3](https://github.com/google/blockly-samples/commit/c8d0bd3b37d7e6765e7761066c4033d422ec4470)) - - - -## [6.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@6.0.4...@blockly/field-multilineinput@6.0.5) (2025-12-19) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [6.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@6.0.3...@blockly/field-multilineinput@6.0.4) (2025-12-19) - - -### Bug Fixes - -* Use getTextWidth instead of getFastTextWidth ([#2632](https://github.com/google/blockly-samples/issues/2632)) ([affcd6e](https://github.com/google/blockly-samples/commit/affcd6ed28506c3640f3a77700640d38eec43841)) - - - -## [6.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@6.0.2...@blockly/field-multilineinput@6.0.3) (2025-10-02) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [6.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@6.0.1...@blockly/field-multilineinput@6.0.2) (2025-07-17) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [6.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@6.0.0...@blockly/field-multilineinput@6.0.1) (2025-05-22) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [6.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.17...@blockly/field-multilineinput@6.0.0) (2025-05-16) - - -### ⚠ BREAKING CHANGES - -* update all plugins to blockly v12 (#2538) - -### Features - -* update all plugins to blockly v12 ([#2538](https://github.com/google/blockly-samples/issues/2538)) ([420ba31](https://github.com/google/blockly-samples/commit/420ba3124b260b2c06e8e1d61be44e870780d95f)) - - - -## [5.0.17](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.16...@blockly/field-multilineinput@5.0.17) (2025-05-16) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.16](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.15...@blockly/field-multilineinput@5.0.16) (2025-05-15) - - -### Bug Fixes - -* Fix multi-line text color by using the correct class ([91a8473](https://github.com/google/blockly-samples/commit/91a8473736b5c0cc3e04c809f4a888469bc96f77)) - - -### Reverts - -* "fix(FieldMultilineInput): Use string literal instead of Field.NBSP" ([539ae4f](https://github.com/google/blockly-samples/commit/539ae4fe4499fca3d781c29f462836ac64d45ce6)) - - - - - -## [5.0.15](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.14...@blockly/field-multilineinput@5.0.15) (2025-02-13) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.13...@blockly/field-multilineinput@5.0.14) (2024-12-19) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.12...@blockly/field-multilineinput@5.0.13) (2024-12-03) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.11...@blockly/field-multilineinput@5.0.12) (2024-11-07) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.10...@blockly/field-multilineinput@5.0.11) (2024-09-26) - - -### Bug Fixes - -* **field-*:** Remove unneeded `fieldRegistry.unregister` calls ([#2454](https://github.com/google/blockly-samples/issues/2454)) ([b3ba30e](https://github.com/google/blockly-samples/commit/b3ba30e23dddf0bd98c266659aa229ba6ba685b0)), closes [#2453](https://github.com/google/blockly-samples/issues/2453) - - - - - -## [5.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.9...@blockly/field-multilineinput@5.0.10) (2024-08-29) - - -### Bug Fixes - -* predeploy plugins ([#2449](https://github.com/google/blockly-samples/issues/2449)) ([6b36d8b](https://github.com/google/blockly-samples/commit/6b36d8b344a969f79d89bbc7dcee29ae554759f9)) - - - - - -## [5.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.8...@blockly/field-multilineinput@5.0.9) (2024-08-22) - - -### Bug Fixes - -* lerna v8 breaking our whole shebangle ([#2446](https://github.com/google/blockly-samples/issues/2446)) ([b8b4c21](https://github.com/google/blockly-samples/commit/b8b4c21d4eaf81f527336ae46f6679ff99ac23c3)) - - - - - -## [5.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.7...@blockly/field-multilineinput@5.0.8) (2024-08-08) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.6...@blockly/field-multilineinput@5.0.7) (2024-08-01) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.5...@blockly/field-multilineinput@5.0.6) (2024-07-25) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.4...@blockly/field-multilineinput@5.0.5) (2024-07-11) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.3...@blockly/field-multilineinput@5.0.4) (2024-07-04) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.2...@blockly/field-multilineinput@5.0.3) (2024-06-27) - - -### Bug Fixes - -* **docs:** Update README for multiline field ([#2394](https://github.com/google/blockly-samples/issues/2394)) ([377d38c](https://github.com/google/blockly-samples/commit/377d38c919723861aa979bdcf210bedd474c3481)) - - - -## [5.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.1...@blockly/field-multilineinput@5.0.2) (2024-06-06) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [5.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@5.0.0...@blockly/field-multilineinput@5.0.1) (2024-05-30) - - -### Bug Fixes - -* multiple blockly instances ([#2375](https://github.com/google/blockly-samples/issues/2375)) ([b231e59](https://github.com/google/blockly-samples/commit/b231e598f2f5f5b0abbfd01d981e35572ad50a26)) - - - -## [5.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@4.0.4...@blockly/field-multilineinput@5.0.0) (2024-05-21) - - -### ⚠ BREAKING CHANGES - -* update all plugins to v11 of blockly - -### Features - -* update all plugins to v11 of blockly ([5fcd3e7](https://github.com/google/blockly-samples/commit/5fcd3e7d53eaadffe9bda9a378b404d34b2f8be2)) -* upgrade ts version, fix field validators ([b2d2191](https://github.com/google/blockly-samples/commit/b2d2191ff11b30347b33f95acf6e58f7ce54d004)) - - -### Bug Fixes - -* Call blocks handle both manual disabling and disabled defs ([#2334](https://github.com/google/blockly-samples/issues/2334)) ([5eade55](https://github.com/google/blockly-samples/commit/5eade55779c4022d14ad4472ff32c93c78199887)) - - - -## [4.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@4.0.3...@blockly/field-multilineinput@4.0.4) (2024-05-16) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [4.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@4.0.2...@blockly/field-multilineinput@4.0.3) (2024-05-09) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [4.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@4.0.1...@blockly/field-multilineinput@4.0.2) (2024-04-25) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [4.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@4.0.0...@blockly/field-multilineinput@4.0.1) (2024-04-11) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [4.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.14...@blockly/field-multilineinput@4.0.0) (2024-04-04) - - -### ⚠ BREAKING CHANGES - -* The multiline text input field no longer registers itself on load. The developer must either manually register the field or install blocks, which will install the field. This is part of a move to have no side effects in field and block definitions, so that tree-shaking can remove unwanted fields and blocks. -* The angle field no longer registers itself on load. The developer must manually register the field. This is part of a move to have no side effects in field and block definitions, so that tree-shaking can remove unwanted fields and blocks. - -### Features - -* add block definitions to fields ([#2299](https://github.com/google/blockly-samples/issues/2299)) ([c197af6](https://github.com/google/blockly-samples/commit/c197af6c67bc989bbdb4e83a62abc08167bcbbfe)), closes [#2162](https://github.com/google/blockly-samples/issues/2162) [#2202](https://github.com/google/blockly-samples/issues/2202) [#2221](https://github.com/google/blockly-samples/issues/2221) [#2211](https://github.com/google/blockly-samples/issues/2211) [#2220](https://github.com/google/blockly-samples/issues/2220) [#2232](https://github.com/google/blockly-samples/issues/2232) [#2233](https://github.com/google/blockly-samples/issues/2233) [#2296](https://github.com/google/blockly-samples/issues/2296) - - - -## [3.0.14](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.13...@blockly/field-multilineinput@3.0.14) (2024-03-28) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.13](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.12...@blockly/field-multilineinput@3.0.13) (2024-02-29) - - -### Bug Fixes - -* updated field multiline to have enough width ([#2208](https://github.com/google/blockly-samples/issues/2208)) ([376691d](https://github.com/google/blockly-samples/commit/376691df5b8dad2e4bd5851f6c1d6a1fa5b6d1e3)) - - - -## [3.0.12](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.11...@blockly/field-multilineinput@3.0.12) (2024-02-08) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.11](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.10...@blockly/field-multilineinput@3.0.11) (2023-12-14) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.10](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.9...@blockly/field-multilineinput@3.0.10) (2023-12-07) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.9](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.8...@blockly/field-multilineinput@3.0.9) (2023-11-09) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.8](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.7...@blockly/field-multilineinput@3.0.8) (2023-11-02) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.7](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.6...@blockly/field-multilineinput@3.0.7) (2023-10-30) - - -### Bug Fixes - -* [#1905](https://github.com/google/blockly-samples/issues/1905) publish types for field-multiline ([#1957](https://github.com/google/blockly-samples/issues/1957)) ([4537b8c](https://github.com/google/blockly-samples/commit/4537b8c6479abf29ebb51fdccf6842c9a88e79a1)) -* **packaging:** Don't advertise non-existent ESM entrypoints ([#2022](https://github.com/google/blockly-samples/issues/2022)) ([d019198](https://github.com/google/blockly-samples/commit/d0191984399b784e2928b8fb4c58257bfa857655)), closes [#1877](https://github.com/google/blockly-samples/issues/1877) -* update tsconfigs to publish types accurately ([df4b084](https://github.com/google/blockly-samples/commit/df4b0844af712f5025a2ec842458b828f3147676)) -* use includes rather than excludes ([40efc25](https://github.com/google/blockly-samples/commit/40efc255329e3ca476ccc247b95a2d05dd77b45e)) - - - -## [3.0.6](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.5...@blockly/field-multilineinput@3.0.6) (2023-09-21) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.5](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.4...@blockly/field-multilineinput@3.0.5) (2023-09-14) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.4](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.3...@blockly/field-multilineinput@3.0.4) (2023-08-31) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.3](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.2...@blockly/field-multilineinput@3.0.3) (2023-08-17) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.2](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.1...@blockly/field-multilineinput@3.0.2) (2023-07-24) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@3.0.0...@blockly/field-multilineinput@3.0.1) (2023-07-20) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [3.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@2.0.1...@blockly/field-multilineinput@3.0.0) (2023-07-13) - - -### ⚠ BREAKING CHANGES - -* updated `plugins/field-date` to TypeScript (#1705) - -### Features - -* updated `plugins/field-date` to TypeScript ([#1705](https://github.com/google/blockly-samples/issues/1705)) ([e5531ff](https://github.com/google/blockly-samples/commit/e5531fffe188ee361a16fe48ed126b34e51a8d30)) - - - -## [2.0.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@2.0.0...@blockly/field-multilineinput@2.0.1) (2023-07-06) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [2.0.0](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@1.2.1...@blockly/field-multilineinput@2.0.0) (2023-06-28) - - -### ⚠ BREAKING CHANGES - -* update all plugins to use blockly-v10.0.0 (#1744) - -### Features - -* update all plugins to use blockly-v10.0.0 ([#1744](https://github.com/google/blockly-samples/issues/1744)) ([6cc88cb](https://github.com/google/blockly-samples/commit/6cc88cbef39d4ad664a668d3d46eb29ba7292f9c)) - - - -## [1.2.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@1.2.0...@blockly/field-multilineinput@1.2.1) (2023-06-22) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## [1.2.0](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@1.1.1...@blockly/field-multilineinput@1.2.0) (2023-05-25) - - -### Features - -* Revise fields ([#1700](https://github.com/google/blockly-samples/issues/1700)) ([c326f7b](https://github.com/google/blockly-samples/commit/c326f7b1ef54fe45387046c693ebd5afe2b2c571)) - - - -## [1.1.1](https://github.com/google/blockly-samples/compare/@blockly/field-multilineinput@1.1.0...@blockly/field-multilineinput@1.1.1) (2023-05-18) - -**Note:** Version bump only for package @blockly/field-multilineinput - - - - - -## 1.1.0 (2023-05-11) - - -### Features - -* Add angle, colour, and multiline fields. (Rebase of [#1674](https://github.com/google/blockly-samples/issues/1674)) ([#1693](https://github.com/google/blockly-samples/issues/1693)) ([1b447f4](https://github.com/google/blockly-samples/commit/1b447f41d6293f14e846b8a4d82d289a5637a99a)) diff --git a/plugins/field-multilineinput/README.md b/plugins/field-multilineinput/README.md deleted file mode 100644 index 002e50a79..000000000 --- a/plugins/field-multilineinput/README.md +++ /dev/null @@ -1,237 +0,0 @@ -# @blockly/field-multilineinput [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) - -A [Blockly](https://www.npmjs.com/package/blockly) multiline input field and -associated block. - -#### Multiline input field - -![A block with the label "multiline text input:" and a multiline input field -with the text "default text \n with newline character.](readme-media/on_block.png) - -#### Multiline input field with editor open - -![The same block with editor open.](readme-media/with_editor.png) - -#### Multiline input on collapsed block - -![The same block after being collapsed. It has the label "multiline text input: -defau..." and a jagged right edge to show it is collapsed.](readme-media/collapsed.png) - -## Installation - -### Yarn - -``` -yarn add @blockly/field-multilineinput -``` - -### npm - -``` -npm install @blockly/field-multilineinput --save -``` - -## Usage - -This plugin adds a field of type `FieldMultilineInput` that is registered with -the name `'field_multilinetext'`. It is a subclass of `Blockly.FieldInput`. - -This field stores a string as its value and a string as its text. Its value is -always a valid string, while its text could be any string entered into its -editor. Unlike a text input field, this field also supports newline characters -entered in the editor. - -#### Editor keyboard shortcuts - -The default keyboard mapping is: - -| Key | Action | -| ----------- | ------------------------------------------------- | -| Enter | Commit the value and close the editor | -| Shift+Enter | Insert a newline at the cursor | -| Escape | Revert to the original value and close the editor | - -With `FieldMultilineInput.enterCommits = false` the mapping is swapped: - -| Key | Action | -| ----------- | ------------------------------------------------- | -| Enter | Insert a newline at the cursor | -| Shift+Enter | Commit the value and close the editor | -| Escape | Revert to the original value and close the editor | - -`enterCommits` and `showHint` are global (static) settings that apply to all -fields. Set them once before creating your blocks: - -```js -import {FieldMultilineInput} from '@blockly/field-multilineinput'; - -FieldMultilineInput.enterCommits = false; // default: true -FieldMultilineInput.showHint = false; // default: true -``` - -The constructor for this field accepts three optional parameters: - -- `value`: The default text. Defaults to `""`. -- `validator`: A function that is called to validate what the user entered. -- `config`: An object with optional properties: - - `maxLines`: The maximum number of lines displayed before scrolling - functionality is enabled. Defaults to `Infinity`. - - `spellcheck`: Whether spell checking is enabled. Defaults to `true`. - - `tooltip`: A tooltip. - -If you want to use only the field, you must register it with Blockly. You can -do this by calling `registerFieldMultilineInput` before instantiating your -blocks. If another field is registered under the same name, this field will -overwrite it. - -### JavaScript - -```js -import * as Blockly from 'blockly'; -import {registerFieldMultilineInput} from '@blockly/field-multilineinput'; - -registerFieldMultilineInput(); -Blockly.Blocks['test_field_multilineinput'] = { - init: function () { - this.appendDummyInput() - .appendField('multilineinput: ') - .appendField( - new FieldMultilineInput('some text \n with newlines'), - 'FIELDNAME', - ); - }, -}; -``` - -### JSON - -```js -import * as Blockly from 'blockly'; -import {registerFieldMultilineInput} from '@blockly/field-multilineinput'; - -registerFieldMultilineInput(); -Blockly.defineBlocksWithJsonArray([ - { - "type": "test_field_multilinetext", - "message0": "multilineinput: %1", - "args0": [ - { - "type": "field_multilinetext", - "name": "FIELDNAME", - "text": "some text \n with newlines" - } - }]); -``` - -### Customization - -#### Spellcheck - -The `setSpellcheck` function can be used to set whether the field spellchecks -its input text or not. Spellchecking is on by default. - -![An animation showing multiline text input fields with and without -spellcheck.](readme-media/spellcheck.gif) - -This applies to individual fields. If you want to modify all fields change the -`Blockly.FieldMultilineInput.prototype.spellcheck_` property. - -#### Validation - -A multiline text input field's value is a string, so any validators must accept -a string and return a string, `null`, or `undefined`. - -Here is an example of a validator that removes all 'a' characters from the -string: - -``` -function(newValue) { - return newValue.replace(/a/gm, ''); -} -``` - -![An animation showing validation.](readme-media/validator.gif) - -### Serialization - -#### JSON - -The JSON for a multiline text input field looks like so: - -```json -{ - "fields": { - "FIELDNAME": "line1\nline2" - } -} -``` - -where `FIELDNAME` is a string referencing a multiline text input field, and the -value is the value to apply to the field. The value follows the same rules as -the constructor value. - -#### XML - -The XML for a multiline text input field looks like so: - -```xml -line1&#10;line2 -``` - -where the field's `name` attribute contains a string referencing a multiline -text input field, and the inner text is the value to apply to the field. The -inner text value follows the same rules as the constructor value. - -### Blocks - -This package also provides a simple block containing a multiline input -field. It has generators in JavaScript, Python, PHP, Lua, and Dart. - -You can install the block by calling `textMultiline.installBlock()`. -This will install the block and all of its dependencies, including the -multiline input field. When calling `installBlock` you can supply one or -more `CodeGenerator` instances (e.g. `javascriptGenerator`), and the install -function will also install the correct generator function for the -corresponding language(s). - -```js -import {javascriptGenerator} from 'blockly/javascript'; -import {dartGenerator} from 'blockly/dart'; -import {phpGenerator} from 'blockly/php'; -import {pythonGenerator} from 'blockly/python'; -import {luaGenerator} from 'blockly/lua'; -import {textMultiline} from '@blockly/field-multilineinput'; - -// Installs the block, the field, and all of the language generators. -textMultiline.installBlock({ - javascript: javascriptGenerator, - dart: dartGenerator, - lua: luaGenerator, - python: pythonGenerator, - php: phpGenerator, -}); -``` - -### API reference - -Instance methods: - -- `setMaxLines`: Sets the maximum number of displayed lines before - scrolling functionality is enabled. -- `getMaxLines`: Returns the maximum number of displayed lines before - scrolling functionality is enabled. -- `setSpellcheck`: Sets whether spell checking is enabled. -- `getSpellcheck`: Returns whether spell checking is enabled. - -Static (global) properties: - -- `FieldMultilineInput.enterCommits`: Whether pressing Enter commits the - value (`true`, default) or inserts a newline (`false`). Applies to all - fields. -- `FieldMultilineInput.showHint`: Whether the keyboard-shortcut hint bar is - shown in the editor. When `false`, no space is reserved for the hint bar. - Applies to all fields. - -## License - -Apache 2.0 diff --git a/plugins/field-multilineinput/package.json b/plugins/field-multilineinput/package.json deleted file mode 100644 index 1391bc8fe..000000000 --- a/plugins/field-multilineinput/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@blockly/field-multilineinput", - "version": "13.2.0", - "description": "A Blockly multilineinput field.", - "scripts": { - "audit:fix": "blockly-scripts auditFix", - "build": "blockly-scripts build", - "clean": "blockly-scripts clean", - "lint": "eslint .", - "predeploy": "blockly-scripts predeploy", - "prepublishOnly": "npm run clean && npm run build", - "start": "blockly-scripts start", - "test": "blockly-scripts test" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "unpkg": "./dist/index.js", - "author": "Blockly Team", - "keywords": [ - "blockly", - "field", - "multilineinput" - ], - "homepage": "https://github.com/RaspberryPiFoundation/blockly-samples/tree/master/plugins/field-multilineinput#readme", - "bugs": { - "url": "https://github.com/RaspberryPiFoundation/blockly-samples/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/RaspberryPiFoundation/blockly-samples.git", - "directory": "plugins/field-multilineinput" - }, - "license": "Apache-2.0", - "directories": { - "dist": "dist", - "src": "src" - }, - "files": [ - "dist", - "src" - ], - "devDependencies": { - "@blockly/dev-scripts": "^13.2.0", - "@blockly/dev-tools": "^13.2.0", - "chai": "^6.2.2", - "sinon": "^22.0.0", - "typescript": "^6.0.3" - }, - "peerDependencies": { - "blockly": "^13.2.0" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/field-multilineinput/readme-media/collapsed.png b/plugins/field-multilineinput/readme-media/collapsed.png deleted file mode 100644 index a227642a7051649b71a665d9f6fef6fa5db049db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3564 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 m 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 diff --git a/plugins/field-multilineinput/readme-media/spellcheck.gif b/plugins/field-multilineinput/readme-media/spellcheck.gif deleted file mode 100644 index 3f1ae53fa9eefa977afb7234604cbade996aa38a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255733 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 z 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%0DN>A{DY5z0&f$v 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 XFR=$o`_KR67x^0?e*^zJzk&Y)XkD!I diff --git a/plugins/field-multilineinput/readme-media/with_editor.png b/plugins/field-multilineinput/readme-media/with_editor.png deleted file mode 100644 index 98dacf3a9073d5912e7ce106176b178e0b82c3ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6690 zcmV+-8r|iIP)h=>(b1VsdC(xkV0-*27G#e1*9y%Z6Kz5lV?efHV=J7=%+ee2tM zZIxEjq(%J|;L2w}$u6D^?9R-Mrzb16`t+tR-}jU}>bU2&<_1(h0` zp4e~MCusp`fj(maE!@@BnCg-Rl{WJwElPJPL$7I4BeB83-mP$+yGeBO==vxHVoes zj_Yf-kmHpWkQV6S7BB#;#v|jj=WE>YUhY&>X{>vA*Jby*+X5CU6$U!F;jU4U2=N*U zM;lwHEiAjc8}fdAzycbr7PSraxKNUhjj4x`R&ZGvwE!oEc3&f;;=qo5;?^7 zSU?3}pp!cu88;oHy?okpsjMq4&?yTPRFvY2!#i-cFvk$EN)uzW8;eI_M_Ev(ZqVL~ zy_+Y(fs1K4a4{85w)P0}9E_ywbl6#0W74oum@;fMUf;0-0Um?!Xyivq zP~o4+yG>r=U~PkGBSNt-Y!cKK7A^JD3V?@Kn7mw805H-M`1V0*iuPJSqtzh2=nCH4 zwX%l-*6?7&_y#F}rC-RQ=mS>j0~jahctzF04qvS}=ON z(xN$lHaL}c341b5A~qllqr7~TFp6Z^k;~^{9P+U^9Xbgfp2BW&6 z4)h2``&!KOAES7NpTuv*rLrRUxOgZYT4r$`vP+8$#`S5!R%8_CwcJ-fB>e7J9HM=K zaED*8LN>C`+;nj4N+#BvOu)6;D&-kGGkHD^Wu3(s?_sdARO4J>F4mkngwpDY8-U%~ zQjLhgehOhu*LqgqSWNc|RqlVWqyX>jTaQ_R;RyEf#h-VsKtofLflb;2Sc9E`rzZku zi-3O~G5wO-sDX(?f#)Uz8UUXs09((RzOJrN#gDf=A42aiy~p4BJfaWXFp(LRAK|0bY>4jhWf!$)Jy$#@*gHRN$P z7V>E1%RV`@1z9Bp7|_oZiy~(z0Ji1K5ja@cVph;t5X3(^xEbya{giRmH8$e=WBc&4 z;Ar%>?}rZ#Y=WgqWiYNrEvM%7VhmUWsfD2vaqvPK)~6<7u(LZJ2%mzq{A~Pq;-CUp zf1G*00%)HnZdYu7Pe=^h>>csJfsGj9?$r`H(-YMPthaan2y#-w!&2evr`UAwQ^JZY5xOI|I*80aPmBpGiPYIZ#^D@t0d4u;Ma-yG8+Xf`COo+}I|cUFbmI zPqDxsw*cu^JAPkY>FEe8ilkM6zwVWQ)j4Zkzq-?aMGx!SqkBQ1V0dv)=ma?1IN;s= z>y?M4<9|Mm->i5|<^q<&Vd;fV=92F0$2}nv;AY5a_^jDTl97kqSZlYwoGL&AcJGKF-W9W)ki?_Pzf`Z}flFxLTC z5YEx`1+2GruY!%G4zRjDBy6vTHN*vY zb`o$R5BS&7&cEXA0xT5}HV}AqX4e7Mqmg0^60kb|EOjk(8nAvlVGfojY{7-%0=U{a z;I5HTu(7hjmxo1$Yq+}?o}4gOsZ-a`*e!siWZ5j$Eq(BCa8|;%!pd?aT~5c+=?mdt zWngSD*^8qNs}$F_4R z*pPZyu}4P$Ys#=-EZhDaG|-}-jU8tAhbchy?!I-(pNq%OQbM_cs&eHXgPh#(@VMzX znv;o~vZ8JStmoDPzYGWFj{=&sK;k8S41m-E5fU=wiyRCri3SKJx#hs-G~mY*fR8Ki z;oTyPVmVU)Jh4W2J@iz9Jj53KlX<}ZCIP4NM0oeobl|0*fXrgi{v9KLN5%n9t_Iv3 zL`b+d18CF$f1DxO&MpO(Z3j;2ZhgpJy|B_(eNSPgi1 z+zcFSUbet)bGg8iG4t@RqkCI8EQW-g@vsP3%qo7BB=$opfE6|og_UJEl6@Xe#mvLL z%+rcjs9zeI8c|YH*`|j@z?u^{R^fOUBI=hWjRsZqwWw*VS3UW)~`oB?*FiwXWf zIB+Bz_&ia7*wgf|a)A}c1^@HLY+&C7U{f04;RyUX0H z0WT-uRRh!f1PDE`8gRA~g!{2v;D=+tU>9J_AYey2!1h^xdUO3})&ah5<^z^V z4$CMcEUq@)->L@T<IM(%$mMhe7&w_o2IrO)E9AMUg`@PE+5#*B5{c{uqsC)XS`yL`*8~m z6Cqrqwln>h;?XigSkq9i02Z@~3r0o3$JGNXj~`HgoV;UuNq3D_gjydS1ok)QEe1IO zk53RG(vEY$(rG}HFVLu$cqGA|e+_tLD^T5V9k9Mj5rnme12EN(9}VGw@z1;p;bD>U zGS|auFJM*Ho9^$qBH>9fG-N2e;+O~}StMX}Jy@~DZUrnZ9~kQDiC=_I!7w*3C0wDm z#jF%3wr*JiL&Ad>Q{nB>Um>o^H!)4maHz9@#q1@$jH$ze6)wox&K`N?CD@g5LJ1RZ zRtO>@^XQ9R=Z|A^TCy_1?+uxNK##$wZ)#M+J}!A^&}fvbp1XsS!YkD_)++$bP?#Yn z!$^XGZe0ILiNlF27dr)5&rV*TaB~sfeo$Ll;Ba<2)}KyPmUEEH3mZ5L_lCv5&8{EL z73C`To8}jy02VWu++y=sWGu>StCUclYv0vUX2w1Msl4Y(oi?x`3(RkJ4y10!9cW+;ILfnuLBnAKQIP}_5~jQ z5opkmzY|0@mnJ;7j(Zw`WwWjm==65(3k7EQcL1=AmNk^rnC>qV3p4$JMEZnXt^5@1~}16H3DfU!IQ$h!vI8w!l~6@1jU$%60s zb2Ev)?iAqTA~JwnCI9vw5#s4MEE4!X8x7nO3cR%o$SMIQ4F{f>0F>7Nzu&-&EAW>& z3=@D=Cx8GCks+iPXY66^$pB^tir@bhC$fzd*CTP|QIQOPcLDHyipVSy5L@f-J9~gY z58#!V0+1OFlGLa7M=z_aRsbIR^x*-mazF0d)ZIsJ&FR?ekbu=OyY+~xdJG1S|BPJkIhFnz!xhea>t@n~S`2(hFgHD9zz z4~wBE$@!R}f+yp02>$y}mhg0p0qdtTBI`(xkDl7Q`$S#+!uvfrLGWy=PY4idt-lU7 zz*8|IM15hS=)W#&Nbm9W?Z6ms;N=-yIj_N@?;BxlEu@-cmayZ~M*>#IZPzESY|l#f zK4~B`1}y>03?sEtMFLjGZPzESlz`Rw$1VY@<2ICl)p6VP$txvbb^ftS!0NaSC17>j zc75_n30QsdvEPkqH;BSPbyr1%GK>ukXW)x$mejY&}-X-23U6$E+E!P_q@6dI9u3V zcW(PWrX;CN^-=AfMt%AWSurGa4P^y|AxjddT#=(+x6;5z`9N665g%{F7Io; z1Gap z?UBf+^Qw3*X9|It0fv^4 z>#)q9tFmUZI;%P768gFVf0!zCsHn_9x#7J-`Y~h$Mm-czCC)K!=liizLYU} zkSAkA$VllHsxENi-5m^ka!9C=>K6hQC-oCC;&`vG4gngv=O53FKiYH5Ul~$+jojK-`Oor z0D2${m@*uAej`xdD8Pynd-)*&!qkV47y`Vw>BeKmI4++0^Q*DIX9)ns17ib(hCMaq z?X7{&?-SC_UnT++RD38x{Q2}cp&HSe-1IYRg{J;H&HerKkWj?nhVHhmad!ZI8!f<} z&w{G3>>qXf`Jo~J=_IN7yeY-Qjqe;U`^k;v923XGjqCjTZ=!`##`@D@Gx?iyC16S5 z>4XK$@vzvuyFKt=IN)Lryc;Kk^+=vmdYIZ*MU_Ioozg6)^R5Hd_Omx~Sez7;AAWY7 zIIoZ|^0SkH^g`gvW`$4PkaU1W)d;GR7F1Hj75L>CU_^hRY|4rA%dx;ytAX-ni5c=G zRC4$tQK&gkMU=qGiT?NbKuWHVKHhppsEbnC=F^1MNp}JeJ;h^J!~|twTa>H$_@L0d zCqYluh@{KncdAtoSgA_!wV_hC^4sqx3y)3L9&JqFK!PZ>#on3=ynjGQQtRZWAC3@q z;Gr3<$xZ)mt&pdt)bsIN;G=ke8ux8URP!1tRlGh+*ntTXhNj+5z%+m1HBm`JcdVMO z|CHI$jg23p2gitUzp)FL-z?Ab9~;F1C6dGH#6*>s3JaJESe!tVg`v0d>Q>-Oy8_P821NCk+$fk^ZuVn*x^6vIZSs z(R*SjqF;0#7GM5{SBPJ9fED5eEZZTxEly^7Tl$53*tI$l(vY_*s{ynsfNHAe3PqUt zNxTSA2?7M0wg8JD%u}Yxh3NwpwZ15$OmB)pfb=GGg&`b6E8_!X8FtZQiHWVbSnX?)6-Qp&>p}dI6W360D$V9oaCbh0I$sg4qX&y3G#%U?gT6n{^Xq) zuIfAkdJ^QS$V-uLqvxjk+VjYIf<#G`m~iwY2r4}Jr>%8ZI@0}SfJI`RA@P6B13o(h zY;7jt>CN36BFJcZX8J`JQjw5n2*$$Dn2Cd9o4w2w!O>UaPiyVtSVDXu? zB~i_57?Qp*NAQ9S0a?h&5vUnjlgQVFgyao*Ul`O&sV-z+u?bQNW_+eOkT%8zv*jNii$O zWC10mmu(YaseZAy0_Fq)4@Zhnl^I877wM(aQ)FLS11z4i80FKp+%%I6`hdmuOi5Hz zO?GjV2$eYodX4vo0rYYSlDb1}DM`(b6B7;$#hHy|2AA1La)tb85!fYQb@_Ca4Ymic zm?7g~r%bo6JTAyqf(^5WTs}Zjn=iROV68oAC}m8(hv7t50+yu(5YS&_xEP)?B#F-w z%M_T+VqxSzFA=(2qK*1 z{cJ^jf+vY`{MC%8*dvO{Xo;9>D7K&13_8+5!@=`t;-Pn!!uJ>KZ%B zR!m#KY``i{jL~i_4Zx<7VAHM28hy$F4%Rl9HX;-Y!zL*wUh4`^&CzA$`jkQBU~icP zi~&od)gZm-3f|nc5-MomZ&!rZeD*+9lN6;*s_?<*`O&wmGqT~{X#rcc6{36s@L>2I zaI~@Qor93Q?v)m(YivMrP6n1A+F}S;n&b#=PMs6p&z*vThJL+raI(|4#sXXdFwn^z zkBpnH9C0s;v_N-RprE1@UmV_nvxPZ^fTc~2(AH@zk#ubcJ}a2eUHy^w=_MAhP^mD` z$qjdnibROlP{q?yTUhpz-pg+GCJSh^TGTew<3dS3Hl`j%T7lTdWDpV(u=t;)jdoab zH5hT_e!Xdovaiwt(gOeH7BB>?^ryABCYIAyH>r_u%@-@LjzP6X9JMWrw1BjLw7~7O zfFWR2p4Q^ROF(^IOP?4bUaWP+r8-wsHA&#QoexXiTUtO`Knr(uHKw{`L6w$zT03&M sBapisC~Mv#FD)c3AT1y*&;u>-|0PtsZ)|ckqyPW_07*qoM6N<$f^m_Cn*aa+ diff --git a/plugins/field-multilineinput/src/blocks/generatorsType.ts b/plugins/field-multilineinput/src/blocks/generatorsType.ts deleted file mode 100644 index e9d2df460..000000000 --- a/plugins/field-multilineinput/src/blocks/generatorsType.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type {JavascriptGenerator} from 'blockly/javascript'; -import type {DartGenerator} from 'blockly/dart'; -import type {LuaGenerator} from 'blockly/lua'; -import type {PhpGenerator} from 'blockly/php'; -import type {PythonGenerator} from 'blockly/python'; - -/** - * An object containing zero or more generators. This is passed - * to block installation functions so that they may install - * per-block generators on any languages they support. - */ -export interface Generators { - javascript?: JavascriptGenerator; - dart?: DartGenerator; - lua?: LuaGenerator; - php?: PhpGenerator; - python?: PythonGenerator; -} diff --git a/plugins/field-multilineinput/src/blocks/textMultiline.ts b/plugins/field-multilineinput/src/blocks/textMultiline.ts deleted file mode 100644 index 831c79ed1..000000000 --- a/plugins/field-multilineinput/src/blocks/textMultiline.ts +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {Block, common as BlocklyCommon} from 'blockly/core'; -import { - JavascriptGenerator, - Order as JavascriptOrder, -} from 'blockly/javascript'; -import {DartGenerator, Order as DartOrder} from 'blockly/dart'; -import {LuaGenerator, Order as LuaOrder} from 'blockly/lua'; -import {PhpGenerator, Order as PhpOrder} from 'blockly/php'; -import {PythonGenerator, Order as PythonOrder} from 'blockly/python'; -import {registerFieldMultilineInput} from '../field_multilineinput'; -import {Generators} from './generatorsType'; - -/** The name this block is registered under. */ -export const BLOCK_NAME = 'text_multiline'; - -// Block for multiline text input. -const jsonDefinition = { - type: BLOCK_NAME, - message0: '%1 %2', - args0: [ - { - type: 'field_image', - src: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAARCAYAAADpP' + - 'U2iAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAdhgAAHYYBXaITgQAAABh0RVh0' + - 'U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAAP1JREFUOE+Vks0KQUEYhjm' + - 'RIja4ABtZ2dm5A3t3Ia6AUm7CylYuQRaUhZSlLZJiQbFAyRnPN33y01HOW08z88' + - '73zpwzM4F3GWOCruvGIE4/rLaV+Nq1hVGMBqzhqlxgCys4wJA65xnogMHsQ5luj' + - 'nYHTejBBCK2mE4abjCgMGhNxHgDFWjDSG07kdfVa2pZMf4ZyMAdWmpZMfYOsLiD' + - 'MYMjlMB+K613QISRhTnITnsYg5yUd0DETmEoMlkFOeIT/A58iyK5E18BuTBfgYX' + - 'fwNJv4P9/oEBerLylOnRhygmGdPpTTBZAPkde61lbQe4moWUvYUZYLfUNftIY4z' + - 'wA5X2Z9AYnQrEAAAAASUVORK5CYII=', - width: 12, - height: 17, - alt: '\u00B6', - }, - { - type: 'field_multilinetext', - name: 'TEXT', - text: '', - }, - ], - output: 'String', - style: 'text_blocks', - helpUrl: '%{BKY_TEXT_TEXT_HELPURL}', - tooltip: '%{BKY_TEXT_TEXT_TOOLTIP}', - extensions: ['parent_tooltip_when_inline'], -}; - -/** - * Javascript block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The JavascriptGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toJavascript( - block: Block, - generator: JavascriptGenerator, -): [string, JavascriptOrder] { - // Text value. - const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('+') !== -1 - ? JavascriptOrder.ADDITION - : JavascriptOrder.ATOMIC; - return [code, order]; -} - -/** - * Dart block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The DartGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toDart( - block: Block, - generator: DartGenerator, -): [string, DartOrder] { - // Text value. - const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('+') !== -1 ? DartOrder.ADDITIVE : DartOrder.ATOMIC; - return [code, order]; -} - -/** - * Lua block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The LuaGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toLua( - block: Block, - generator: LuaGenerator, -): [string, LuaOrder] { - // Text value. - const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('..') !== -1 ? LuaOrder.CONCATENATION : LuaOrder.ATOMIC; - return [code, order]; -} - -/** - * PHP block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PhpGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPhp( - block: Block, - generator: PhpGenerator, -): [string, PhpOrder] { - // Text value. - const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('.') !== -1 ? PhpOrder.STRING_CONCAT : PhpOrder.ATOMIC; - return [code, order]; -} - -/** - * Python block generator function. - * - * @param block The Block instance to generate code for. - * @param generator The PythonGenerator calling the function. - * @returns A tuple containing the code string and precedence. - */ -export function toPython( - block: Block, - generator: PythonGenerator, -): [string, PythonOrder] { - // Text value. - const code = generator.multiline_quote_(block.getFieldValue('TEXT')); - const order = - code.indexOf('+') !== -1 ? PythonOrder.ADDITIVE : PythonOrder.ATOMIC; - return [code, order]; -} - -const definitionsDict = BlocklyCommon.createBlockDefinitionsFromJsonArray([ - jsonDefinition, -]); - -/** The text_multiline BlockDefinition. */ -export const blockDefinition = definitionsDict[BLOCK_NAME]; - -/** - * Install the `text_multiline` block and all of its dependencies. - * - * @param gens The CodeGenerators to install per-block - * generators on. - */ -export function installBlock(gens: Generators = {}) { - registerFieldMultilineInput(); - BlocklyCommon.defineBlocks(definitionsDict); - if (gens.javascript) gens.javascript.forBlock[BLOCK_NAME] = toJavascript; - if (gens.dart) gens.dart.forBlock[BLOCK_NAME] = toDart; - if (gens.lua) gens.lua.forBlock[BLOCK_NAME] = toLua; - if (gens.php) gens.php.forBlock[BLOCK_NAME] = toPhp; - if (gens.python) gens.python.forBlock[BLOCK_NAME] = toPython; -} diff --git a/plugins/field-multilineinput/src/field_multilineinput.ts b/plugins/field-multilineinput/src/field_multilineinput.ts deleted file mode 100644 index fd3f60831..000000000 --- a/plugins/field-multilineinput/src/field_multilineinput.ts +++ /dev/null @@ -1,781 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Multiline text input field. - */ - -import * as Blockly from 'blockly/core'; - -/** - * Class for an editable text area input field. - */ -export class FieldMultilineInput extends Blockly.FieldTextInput { - /** - * Minimum editor width (in SVG/workspace units) when the field is open. - * Prevents narrow editors when the initial text is very short. - */ - - static readonly EDITOR_MIN_WIDTH = 150; - - /** - * The SVG group element that will contain a text element for each text row - * when initialized. - */ - textGroup: SVGGElement | null = null; - - /** - * Defines the maximum number of lines of field. - * If exceeded, scrolling functionality is enabled. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected maxLines_ = Infinity; - - /** Whether Y overflow is currently occurring. */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected isOverflowedY_ = false; - - /** Whether pressing Enter commits the value (default) or inserts a newline. */ - static enterCommits = true; - - /** Whether to show the keyboard-shortcut hint bar in the editor. */ - static showHint = true; - - /** The hint bar DOM element while the editor is open. */ - private hintElement: HTMLDivElement | null = null; - - /** - * Cached natural width of the hint bar in px, keyed by scale. - * Invalidated when zoom changes to avoid stale measurements. - */ - private cachedHintWidth: {scale: number; widthPx: number} | null = null; - - /** - * @param value The initial content of the field. Should cast to a string. - * Defaults to an empty string if null or undefined. Also accepts - * Field.SKIP_SETUP if you wish to skip setup (only used by subclasses - * that want to handle configuration and setting the field value after - * their own constructors have run). - * @param validator An optional function that is called to validate any - * constraints on what the user entered. Takes the new text as an - * argument and returns either the accepted text, a replacement text, or - * null to abort the change. - * @param config A map of options used to configure the field. - * See the [field creation documentation]{@link - * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/multiline-text-input#creation} - * for a list of properties this parameter supports. - */ - constructor( - value?: string | typeof Blockly.Field.SKIP_SETUP, - validator?: FieldMultilineInputValidator, - config?: FieldMultilineInputConfig, - ) { - super(Blockly.Field.SKIP_SETUP); - - if (value === Blockly.Field.SKIP_SETUP) return; - if (config) { - this.configure_(config); - } - this.setValue(value); - if (validator) { - this.setValidator(validator); - } - } - - /** - * Configure the field based on the given map of options. - * - * @param config A map of options to configure the field based on. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override configure_(config: FieldMultilineInputConfig) { - super.configure_(config); - if (config.maxLines) this.setMaxLines(config.maxLines); - } - - /** - * Serializes this field's value to XML. - * Should only be called by Blockly.Xml. - * - * @param fieldElement The element to populate with info about the field's - * state. - * @returns The element containing info about the field's state. - */ - override toXml(fieldElement: Element): Element { - // Replace '\n' characters with HTML-escaped equivalent ' '. This is - // needed so the plain-text representation of the XML produced by - // `Blockly.Xml.domToText` will appear on a single line (this is a - // limitation of the plain-text format). - fieldElement.textContent = (this.getValue() as string).replace( - /\n/g, - ' ', - ); - return fieldElement; - } - - /** - * Sets the field's value based on the given XML element. Should only be - * called by Blockly.Xml. - * - * @param fieldElement The element containing info about the field's state. - */ - override fromXml(fieldElement: Element) { - this.setValue((fieldElement.textContent as string).replace(/ /g, '\n')); - } - - /** - * Saves this field's value. - * This function only exists for subclasses of FieldMultilineInput which - * predate the load/saveState API and only define to/fromXml. - * - * @returns The state of this field. - */ - override saveState() { - const legacyState = this.saveLegacyState(FieldMultilineInput); - if (legacyState !== null) { - return legacyState; - } - return this.getValue(); - } - - /** - * Sets the field's value based on the given state. - * This function only exists for subclasses of FieldMultilineInput which - * predate the load/saveState API and only define to/fromXml. - * - * @param state The state of the variable to assign to this variable field. - */ - override loadState(state: unknown) { - if (this.loadLegacyState(Blockly.Field, state)) { - return; - } - this.setValue(state); - } - - /** - * Create the block UI for this field. - */ - override initView() { - this.createBorderRect_(); - this.textGroup = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.G, - { - class: 'blocklyEditableField', - }, - this.fieldGroup_, - ); - if (this.fieldGroup_) { - Blockly.utils.dom.addClass(this.fieldGroup_, 'blocklyField'); - } - } - - /** - * Get the text from this field as displayed on screen. May differ from - * getText due to ellipsis, and other formatting. - * - * @returns Currently displayed text. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override getDisplayText_(): string { - const block = this.getSourceBlock(); - if (!block) { - throw new Error( - 'The field has not yet been attached to its input. ' + - 'Call appendField to attach it.', - ); - } - let textLines = this.getText(); - if (!textLines) { - // Prevent the field from disappearing if empty. - return Blockly.Field.NBSP; - } - const lines = textLines.split('\n'); - textLines = ''; - const displayLinesNumber = this.isOverflowedY_ - ? this.maxLines_ - : lines.length; - for (let i = 0; i < displayLinesNumber; i++) { - let text = lines[i]; - if (text.length > this.maxDisplayLength) { - // Truncate displayed string and add an ellipsis ('...'). - text = text.substring(0, this.maxDisplayLength - 4) + '...'; - } else if (this.isOverflowedY_ && i === displayLinesNumber - 1) { - text = text.substring(0, text.length - 3) + '...'; - } - // Replace whitespace with non-breaking spaces so the text doesn't - // collapse. - text = text.replace(/\s/g, Blockly.Field.NBSP); - - textLines += text; - if (i !== displayLinesNumber - 1) { - textLines += '\n'; - } - } - if (block.RTL) { - // The SVG is LTR, force value to be RTL. - textLines += '\u200F'; - } - return textLines; - } - - /** - * Called by setValue if the text input is valid. Updates the value of the - * field, and updates the text of the field if it is not currently being - * edited (i.e. handled by the htmlInput_). Is being redefined here to update - * overflow state of the field. - * - * @param newValue The value to be saved. The default validator guarantees - * that this is a string. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override doValueUpdate_(newValue: string) { - super.doValueUpdate_(newValue); - if (this.value_ !== null) { - this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_; - } - } - - /** Updates the text of the textElement. */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override render_() { - const block = this.getSourceBlock(); - if (!block) { - throw new Error( - 'The field has not yet been attached to its input. ' + - 'Call appendField to attach it.', - ); - } - // Remove all text group children. - let currentChild; - const textGroup = this.textGroup as SVGElement; - while ((currentChild = textGroup.firstChild)) { - textGroup.removeChild(currentChild); - } - - const constants = this.getConstants(); - // This can't happen, but TypeScript thinks it can and lint forbids `!.`. - if (!constants) throw Error('Constants not found'); - // Add in text elements into the group. - const lines = this.getDisplayText_().split('\n'); - let y = 0; - for (let i = 0; i < lines.length; i++) { - const lineHeight = - constants.FIELD_TEXT_HEIGHT + constants.FIELD_BORDER_RECT_Y_PADDING; - const span = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TEXT, - { - class: 'blocklyText blocklyMultilineText', - x: constants.FIELD_BORDER_RECT_X_PADDING, - y: y + constants.FIELD_BORDER_RECT_Y_PADDING, - dy: constants.FIELD_TEXT_BASELINE, - }, - textGroup, - ); - span.appendChild(document.createTextNode(lines[i])); - y += lineHeight; - } - - if (this.isBeingEdited_) { - const htmlInput = this.htmlInput_ as HTMLElement; - if (this.isOverflowedY_) { - Blockly.utils.dom.addClass( - htmlInput, - 'blocklyHtmlTextAreaInputOverflowedY', - ); - } else { - Blockly.utils.dom.removeClass( - htmlInput, - 'blocklyHtmlTextAreaInputOverflowedY', - ); - } - } - - this.updateSize_(); - - if (this.isBeingEdited_) { - if (block.RTL) { - // in RTL, we need to let the browser reflow before resizing - // in order to get the correct bounding box of the borderRect - // avoiding issue #2777. - setTimeout(this.resizeEditor_.bind(this), 0); - } else { - this.resizeEditor_(); - } - const htmlInput = this.htmlInput_ as HTMLElement; - if (!this.isTextValid_) { - Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); - Blockly.utils.aria.setState( - htmlInput, - Blockly.utils.aria.State.INVALID, - true, - ); - } else { - Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); - Blockly.utils.aria.setState( - htmlInput, - Blockly.utils.aria.State.INVALID, - false, - ); - } - } - } - - /** Updates the size of the field based on the text. */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override updateSize_() { - const constants = this.getConstants(); - // This can't happen, but TypeScript thinks it can and lint forbids `!.`. - if (!constants) throw Error('Constants not found'); - const nodes = (this.textGroup as SVGElement).childNodes; - let totalWidth = 0; - let totalHeight = 0; - for (let i = 0; i < nodes.length; i++) { - const tspan = nodes[i] as SVGTextElement; - const textWidth = Blockly.utils.dom.getTextWidth(tspan); - if (textWidth > totalWidth) { - totalWidth = textWidth; - } - totalHeight += - constants.FIELD_TEXT_HEIGHT + - (i > 0 ? constants.FIELD_BORDER_RECT_Y_PADDING : 0); - } - if (this.isBeingEdited_) { - // The default width is based on the longest line in the display text, - // but when it's being edited, width should be calculated based on the - // absolute longest line, even if it would be truncated after editing. - // Otherwise we would get wrong editor width when there are more - // lines than this.maxLines_. - const actualEditorLines = String(this.value_).split('\n'); - const dummyTextElement = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TEXT, - {class: 'blocklyText blocklyMultilineText'}, - ); - - for (let i = 0; i < actualEditorLines.length; i++) { - if (actualEditorLines[i].length > this.maxDisplayLength) { - actualEditorLines[i] = actualEditorLines[i].substring( - 0, - this.maxDisplayLength, - ); - } - dummyTextElement.textContent = actualEditorLines[i]; - const lineWidth = Blockly.utils.dom.getTextWidth(dummyTextElement); - if (lineWidth > totalWidth) { - totalWidth = lineWidth; - } - } - - const htmlInput = this.htmlInput_ as HTMLElement; - const scrollbarWidth = htmlInput.offsetWidth - htmlInput.clientWidth; - totalWidth += scrollbarWidth; - - if (FieldMultilineInput.showHint) { - // Reserve a row at the bottom of the editor for the keyboard hint bar. - // The textarea's padding-bottom (set in widgetCreate_) keeps the text - // and caret out of this reserved strip. - totalHeight += - constants.FIELD_TEXT_HEIGHT + constants.FIELD_BORDER_RECT_Y_PADDING; - } - } - if (this.borderRect_) { - totalHeight += constants.FIELD_BORDER_RECT_Y_PADDING * 2; - // NOTE: Adding 1 extra px to prevent wrapping. Based on browser zoom, - // the rounding of the calculated value can result in the line wrapping - // unintentionally. - totalWidth += constants.FIELD_BORDER_RECT_X_PADDING * 2 + 1; - } - if (this.isBeingEdited_) { - totalWidth = Math.max(totalWidth, FieldMultilineInput.EDITOR_MIN_WIDTH); - - // Measure the hint bar's natural width to make sure the editor is wide enough. - if (FieldMultilineInput.showHint && this.hintElement?.isConnected) { - const scale = (this.workspace_ as Blockly.WorkspaceSvg).getScale(); - if (!this.cachedHintWidth || this.cachedHintWidth.scale !== scale) { - // Temporarily let the element size to its content to measure its - // natural width, unaffected by the current WidgetDiv width. - this.hintElement.style.width = 'max-content'; - const widthPx = this.hintElement.offsetWidth; - this.hintElement.style.width = ''; - if (widthPx > 0) this.cachedHintWidth = {scale, widthPx}; - } - if (this.cachedHintWidth) { - totalWidth = Math.max( - totalWidth, - this.cachedHintWidth.widthPx / scale, - ); - } - } - } - if (this.borderRect_) { - this.borderRect_.setAttribute('width', `${totalWidth}`); - this.borderRect_.setAttribute('height', `${totalHeight}`); - } - this.size_.width = totalWidth; - this.size_.height = totalHeight; - - this.positionBorderRect_(); - } - - /** - * Show the inline free-text editor on top of the text. - * Overrides the default behaviour to force rerender in order to - * correct block size, based on editor text. - * - * @param e Optional mouse event that triggered the field to open, or - * undefined if triggered programmatically. - * @param quietInput True if editor should be created without focus. - * Defaults to false. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - override showEditor_(e?: Event, quietInput?: boolean) { - super.showEditor_(e, quietInput); - this.forceRerender(); - } - - /** - * Create the text input editor widget. - * - * @returns The newly created text input editor. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override widgetCreate_(): HTMLTextAreaElement { - const div = Blockly.WidgetDiv.getDiv() as HTMLDivElement; - const scale = (this.workspace_ as Blockly.WorkspaceSvg).getScale(); - const constants = this.getConstants(); - // This can't happen, but TypeScript thinks it can and lint forbids `!.`. - if (!constants) throw Error('Constants not found'); - - const htmlInput = document.createElement('textarea'); - htmlInput.className = 'blocklyHtmlInput blocklyHtmlTextAreaInput'; - htmlInput.setAttribute('spellcheck', String(this.spellcheck_)); - const fontSize = constants.FIELD_TEXT_FONTSIZE * scale + 'pt'; - div.style.fontSize = fontSize; - htmlInput.style.fontSize = fontSize; - const borderRadius = Blockly.FieldTextInput.BORDERRADIUS * scale + 'px'; - htmlInput.style.borderRadius = borderRadius; - const paddingX = constants.FIELD_BORDER_RECT_X_PADDING * scale; - const paddingY = (constants.FIELD_BORDER_RECT_Y_PADDING * scale) / 2; - const lineHeight = - constants.FIELD_TEXT_HEIGHT + constants.FIELD_BORDER_RECT_Y_PADDING; - const hintHeightPx = Math.ceil(lineHeight * scale); - // When the hint bar is visible it occupies one text row at the bottom; - // pad the textarea by that row so we don't edit text underneath it. - const paddingBottomPx = FieldMultilineInput.showHint - ? paddingY + hintHeightPx - : paddingY; - htmlInput.style.padding = `${paddingY}px ${paddingX}px ${paddingBottomPx}px ${paddingX}px`; - htmlInput.style.lineHeight = lineHeight * scale + 'px'; - div.appendChild(htmlInput); - - htmlInput.value = htmlInput.defaultValue = this.getEditorText_(this.value_); - htmlInput.setAttribute('data-untyped-default-value', String(this.value_)); - htmlInput.setAttribute('data-old-value', ''); - if (Blockly.utils.userAgent.GECKO) { - // In FF, ensure the browser reflows before resizing to avoid issue #2777. - setTimeout(this.resizeEditor_.bind(this), 0); - } else { - this.resizeEditor_(); - } - - this.bindInputEvents_(htmlInput); - - if (FieldMultilineInput.showHint) { - this.hintElement = this.createHint(hintHeightPx); - this.hintElement.style.fontFamily = constants.FIELD_TEXT_FONTFAMILY; - div.appendChild(this.hintElement); - } - - return htmlInput; - } - - /** - * Creates the keyboard hint bar shown at the bottom of the editor. - * - * Keys are rendered as keycaps (bordered boxes). - * - * @param heightPx The height of the hint bar in pixels. - * @returns The hint bar element. - */ - private createHint(heightPx: number): HTMLDivElement { - const shiftKey = '⇧'; - const enterKey = '⏎'; - const hint = document.createElement('div'); - hint.className = 'blocklyMultilineHint'; - hint.setAttribute('aria-hidden', 'true'); - hint.style.height = heightPx + 'px'; - - // Plain Enter - const enterGroup = document.createElement('div'); - enterGroup.className = 'blocklyMultilineHintGroup'; - enterGroup.appendChild(this.createHintKeycap(enterKey)); - enterGroup.appendChild(this.createHintColon()); - enterGroup.appendChild( - this.createHintLabel( - FieldMultilineInput.enterCommits ? 'commit' : 'newline', - ), - ); - hint.appendChild(enterGroup); - - // Modifier+Enter - const modEnterGroup = document.createElement('div'); - modEnterGroup.className = 'blocklyMultilineHintGroup'; - modEnterGroup.appendChild(this.createHintKeycap(shiftKey)); - modEnterGroup.appendChild(this.createHintKeycap(enterKey)); - modEnterGroup.appendChild(this.createHintColon()); - modEnterGroup.appendChild( - this.createHintLabel( - FieldMultilineInput.enterCommits ? 'newline' : 'commit', - ), - ); - hint.appendChild(modEnterGroup); - - return hint; - } - - /** - * Creates a colon separator element used between keycaps and the action icon. - * - * @returns The colon element. - */ - private createHintColon(): HTMLSpanElement { - const colon = document.createElement('span'); - colon.className = 'blocklyMultilineHintColon'; - colon.textContent = ':'; - return colon; - } - - /** - * Creates a keycap element displaying a single key label. - * - * @param label The key symbol to display. - * @returns The keycap element. - */ - private createHintKeycap(label: string): HTMLSpanElement { - const key = document.createElement('span'); - key.className = 'blocklyMultilineHintKey'; - key.textContent = label; - return key; - } - - /** - * Creates a text label describing the result of a key action. - * - * Uses Blockly.Msg for i18n with hardcoded English fallbacks. - * - * @param type Either 'commit' or 'newline'. - * @returns The label element. - */ - private createHintLabel(type: 'commit' | 'newline'): HTMLSpanElement { - const label = document.createElement('span'); - label.className = 'blocklyMultilineHintLabel'; - label.textContent = - type === 'commit' - ? Blockly.Msg['FIELD_MULTILINEINPUT_FINISH_EDITING'] || 'Finish editing' - : Blockly.Msg['FIELD_MULTILINEINPUT_NEW_LINE'] || 'New line'; - return label; - } - - /** - * Sets the maxLines config for this field. - * - * @param maxLines Defines the maximum number of lines allowed, before - * scrolling functionality is enabled. - */ - setMaxLines(maxLines: number) { - if ( - typeof maxLines === 'number' && - maxLines > 0 && - maxLines !== this.maxLines_ - ) { - this.maxLines_ = maxLines; - this.forceRerender(); - } - } - - /** - * Returns the maxLines config of this field. - * - * @returns The maxLines config value. - */ - getMaxLines(): number { - return this.maxLines_; - } - - /** - * Handle key down to the editor. - * - * Enter commits the value and closes the editor (matching FieldTextInput). - * Shift+Enter inserts a newline at the cursor. - * All other keys are handled by the parent class (Escape reverts, Tab navigates). - * - * @param e Keyboard event. - */ - // eslint-disable-next-line @typescript-eslint/naming-convention - protected override onHtmlInputKeyDown_(e: KeyboardEvent) { - if (e.key === 'Enter') { - if (e.isComposing) { - // Let the IME (input method editor) finalize its composition naturally; - // don't commit or insert a newline ourselves. - return; - } - const shiftPressed = e.shiftKey; - const shouldCommit = FieldMultilineInput.enterCommits - ? !shiftPressed - : shiftPressed; - if (shouldCommit) { - super.onHtmlInputKeyDown_(e); - } else { - this.insertNewline(); - e.preventDefault(); - e.stopPropagation(); - } - } else { - super.onHtmlInputKeyDown_(e); - } - } - - /** - * Inserts a newline character at the current cursor position in the textarea. - * - * The browser's default Enter-key behavior inserts a newline, but - * Shift+Enter has no default character-insertion action, so we handle it - * manually here. After splicing the character we dispatch an `input` event - * to trigger Blockly's onHtmlInputChange handler (programmatic `.value` - * assignment doesn't fire `input` on its own). - */ - private insertNewline() { - const htmlInput = this.htmlInput_; - if (!htmlInput) return; - const start = htmlInput.selectionStart ?? htmlInput.value.length; - const end = htmlInput.selectionEnd ?? start; - htmlInput.value = - htmlInput.value.substring(0, start) + - '\n' + - htmlInput.value.substring(end); - htmlInput.selectionStart = htmlInput.selectionEnd = start + 1; - htmlInput.dispatchEvent(new Event('input')); - } - - /** - * Construct a FieldMultilineInput from a JSON arg object, - * dereferencing any string table references. - * - * @param options A JSON object with options (text, and spellcheck). - * @returns The new field instance. - * @nocollapse - */ - static override fromJson( - options: FieldMultilineInputFromJsonConfig, - ): FieldMultilineInput { - const text = Blockly.utils.parsing.replaceMessageReferences(options.text); - // `this` might be a subclass of FieldMultilineInput if that class doesn't - // override the static fromJson method. - return new this(text, undefined, options); - } -} - -/** - * Register the field and any dependencies. - */ -export function registerFieldMultilineInput() { - Blockly.fieldRegistry.register('field_multilinetext', FieldMultilineInput); -} - -/** - * CSS for multiline field. - */ -Blockly.Css.register(` -.blocklyHtmlTextAreaInput { - font-family: monospace; - resize: none; - overflow: hidden; - height: 100%; - text-align: left; -} - -.blocklyHtmlTextAreaInputOverflowedY { - overflow-y: scroll; -} - -.blocklyMultilineHint { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - display: flex; - justify-content: space-around; - align-items: center; - padding: 0 4px; - box-sizing: border-box; - font-size: 0.85em; - color: rgba(0, 0, 0, 0.6); - background-color: white; - border-top: 1px solid rgba(0, 0, 0, 0.15); - border-radius: 0 0 4px 4px; - user-select: none; - pointer-events: none; -} - -.blocklyMultilineHintGroup { - display: inline-flex; - align-items: center; -} - -.blocklyMultilineHintKey { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 1.3em; - height: 1.3em; - padding: 0 0.25em; - margin: 0 0.1em; - border: 1px solid rgba(0, 0, 0, 0.35); - border-radius: 3px; - background-color: #f5f5f5; - line-height: 1; - box-sizing: border-box; -} - -.blocklyMultilineHintColon { - margin: 0 0.15em; -} - -.blocklyMultilineHintLabel { - white-space: nowrap; -} -`); - -/** - * Config options for the multiline input field. - */ -export interface FieldMultilineInputConfig - extends Blockly.FieldTextInputConfig { - maxLines?: number; -} - -/** - * fromJson config options for the multiline input field. - */ -export interface FieldMultilineInputFromJsonConfig extends FieldMultilineInputConfig { - text?: string; -} - -/** - * A function that is called to validate changes to the field's value before - * they are set. - * - * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} - * @param newValue The value to be validated. - * @returns One of three instructions for setting the new value: `T`, `null`, - * or `undefined`. - * - * - `T` to set this function's returned value instead of `newValue`. - * - * - `null` to invoke `doValueInvalid_` and not set a value. - * - * - `undefined` to set `newValue` as is. - */ -export type FieldMultilineInputValidator = Blockly.FieldTextInputValidator; diff --git a/plugins/field-multilineinput/src/index.ts b/plugins/field-multilineinput/src/index.ts deleted file mode 100644 index 051fded12..000000000 --- a/plugins/field-multilineinput/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as textMultiline from './blocks/textMultiline'; - -export * from './field_multilineinput'; - -// Re-export all parts of the block definition. -export * as textMultiline from './blocks/textMultiline'; - -// This package currently exports a single block. More may -// be added later. -export const installAllBlocks = textMultiline.installBlock; diff --git a/plugins/field-multilineinput/test/block_test.mocha.js b/plugins/field-multilineinput/test/block_test.mocha.js deleted file mode 100644 index d60fd2cf1..000000000 --- a/plugins/field-multilineinput/test/block_test.mocha.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import fs from 'fs'; -import * as Blockly from 'blockly/core'; -import * as en from 'blockly/msg/en'; -import 'blockly/blocks'; - -import {javascriptGenerator} from 'blockly/javascript'; -import {dartGenerator} from 'blockly/dart'; -import {phpGenerator} from 'blockly/php'; -import {pythonGenerator} from 'blockly/python'; -import {luaGenerator} from 'blockly/lua'; -import {installAllBlocks} from '../src/index'; -import {assert} from 'chai'; - -const blockJson = { - blocks: { - languageVersion: 0, - blocks: [ - { - type: 'text_print', - inputs: { - TEXT: { - block: { - type: 'text_multiline', - fields: { - TEXT: 'Picard said, "Beam me up!".\nO\'Brien made it so.', - }, - }, - }, - }, - }, - ], - }, -}; - -/** - * Assert that the generated code matches the golden code for the specified - * language. - * @param {string} suffix The suffix of the golden file. - * @param {string} generated The generated code to compare against the - * golden file. - */ -function checkResult(suffix, generated) { - const fileName = `test/golden/golden.${suffix}`; - const goldenContents = fs.readFileSync(fileName); - // Normalize the line feeds. - const normalized = goldenContents.toString().replace(/(?:\r\n|\r|\n)/g, '\n'); - assert.equal(generated, normalized); -} - -suite('Multiline Text Block Generators', function () { - suiteSetup(function () { - Blockly.setLocale(en); - installAllBlocks({ - javascript: javascriptGenerator, - dart: dartGenerator, - lua: luaGenerator, - python: pythonGenerator, - php: phpGenerator, - }); - }); - setup(function () { - this.workspace = new Blockly.Workspace(); - Blockly.serialization.workspaces.load(blockJson, this.workspace); - }); - test('JavaScript', function () { - const generated = javascriptGenerator.workspaceToCode(this.workspace); - checkResult('js', generated); - }); - test('Dart', function () { - const generated = dartGenerator.workspaceToCode(this.workspace); - checkResult('dart', generated); - }); - test('Lua', function () { - const generated = luaGenerator.workspaceToCode(this.workspace); - checkResult('lua', generated); - }); - test('Python', function () { - const generated = pythonGenerator.workspaceToCode(this.workspace); - checkResult('py', generated); - }); - test('PHP', function () { - const generated = phpGenerator.workspaceToCode(this.workspace); - checkResult('php', generated); - }); - teardown(function () { - this.workspace.dispose(); - }); -}); diff --git a/plugins/field-multilineinput/test/field_multilineinput_test.mocha.js b/plugins/field-multilineinput/test/field_multilineinput_test.mocha.js deleted file mode 100644 index ce46e94d1..000000000 --- a/plugins/field-multilineinput/test/field_multilineinput_test.mocha.js +++ /dev/null @@ -1,300 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -const {testHelpers} = require('@blockly/dev-tools'); -const { - FieldMultilineInput, - registerFieldMultilineInput, -} = require('../src/index'); -const Blockly = require('blockly'); -const {assert} = require('chai'); -const sinon = require('sinon'); - -const { - assertFieldValue, - FieldCreationTestCase, - FieldValueTestCase, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} = testHelpers; - -suite('FieldMultilineInput', function () { - setup(function () { - registerFieldMultilineInput(); - }); - /** - * Configuration for field tests with invalid values. - * @type {Array} - */ - const invalidValueTestCases = [ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - ]; - /** - * Configuration for field tests with valid values. - * @type {Array} - */ - const validValueTestCases = [ - {title: 'Empty string', value: '', expectedValue: ''}, - {title: 'String no newline', value: 'value', expectedValue: 'value'}, - { - title: 'String with newline', - value: 'bark bark\n bark bark bark\n bark bar bark bark\n', - expectedValue: 'bark bark\n bark bark bark\n bark bar bark bark\n', - }, - {title: 'Boolean true', value: true, expectedValue: 'true'}, - {title: 'Boolean false', value: false, expectedValue: 'false'}, - {title: 'Number (Truthy)', value: 1, expectedValue: '1'}, - {title: 'Number (Falsy)', value: 0, expectedValue: '0'}, - {title: 'NaN', value: NaN, expectedValue: 'NaN'}, - ]; - const addArgsAndJson = function (testCase) { - testCase.args = [testCase.value]; - testCase.json = {text: testCase.value}; - }; - invalidValueTestCases.forEach(addArgsAndJson); - validValueTestCases.forEach(addArgsAndJson); - - /** - * The expected default value for the field being tested. - * @type {*} - */ - const defaultFieldValue = ''; - /** - * Asserts that the field property values are set to default. - * @param {!FieldMultilineInput} field The field to check. - */ - const assertFieldDefault = function (field) { - assertFieldValue(field, defaultFieldValue); - }; - - /** - * Asserts that the field properties are correct based on the test case. - * @param {FieldMultilineInput} field The field to check. - * @param {FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertFieldValue(field, testCase.expectedValue); - }; - - runConstructorSuiteTests( - FieldMultilineInput, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - runFromJsonSuiteTests( - FieldMultilineInput, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault, - ); - - suite('setValue', function () { - suite('Empty -> New Value', function () { - setup(function () { - this.field = new FieldMultilineInput(); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - defaultFieldValue, - ); - }); - suite('Value -> New Value', function () { - const initialValue = 'oldValue'; - setup(function () { - this.field = new FieldMultilineInput(initialValue); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - initialValue, - ); - }); - }); - - suite('Keyboard behavior', function () { - /** - * Dispatches a keydown event on the editor's textarea, setting the - * cursor/selection beforehand. - * @param {!HTMLTextAreaElement} textarea The editor's textarea. - * @param {!Object} options KeyboardEvent options (key, shiftKey, etc.). - * @param {number} [selectionStart] Optional selection start to set first. - * @param {number} [selectionEnd] Optional selection end to set first. - */ - const pressKey = function ( - textarea, - options, - selectionStart, - selectionEnd, - ) { - if (selectionStart !== undefined) { - textarea.selectionStart = selectionStart; - textarea.selectionEnd = selectionEnd ?? selectionStart; - } - textarea.dispatchEvent( - new KeyboardEvent('keydown', { - bubbles: true, - cancelable: true, - ...options, - }), - ); - }; - - setup(function () { - this.jsdomCleanup = require('jsdom-global')( - '
    ', - ); - // See https://github.com/RaspberryPiFoundation/blockly-samples/issues/2528. - global.SVGElement = window.SVGElement; - // Blockly's focus handling constructs FocusEvent, which jsdom exposes on - // window but not as a global. - global.FocusEvent = window.FocusEvent; - // jsdom doesn't provide requestAnimationFrame/cancelAnimationFrame, which - // block rendering relies on. Route them through (faked) timers so they - // exist and can be flushed deterministically in teardown. - this.clock = sinon.useFakeTimers(); - window.requestAnimationFrame = (cb) => setTimeout(cb, 0); - window.cancelAnimationFrame = (id) => clearTimeout(id); - this.workspace = Blockly.inject('blocklyDiv'); - - if (!Blockly.Blocks['multiline_block']) { - Blockly.defineBlocksWithJsonArray([ - { - type: 'multiline_block', - message0: '%1', - args0: [ - {type: 'field_multilinetext', name: 'FIELD', text: 'hello'}, - ], - }, - ]); - } - this.block = this.workspace.newBlock('multiline_block'); - this.block.initSvg(); - this.block.render(); - this.field = this.block.getField('FIELD'); - - // Open the editor so we exercise the real +

D+Zyrx}Ldj7Ep<=aZ9xx^3jcJbLDRrg(lgf5 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%0Dd}9t9vbpf8?$kM1DsCjjl@` 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