diff --git a/demos/codelab/README.md b/demos/codelab/README.md deleted file mode 100644 index 2a5e91315..000000000 --- a/demos/codelab/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Blockly for the Web codelab - -Code for the [Blockly for the Web codelab](https://developers.google.com/TODO). - -In this codelab, you'll learn how to use Blockly JavaScript library -to add a block code editor to a web application. - -## What you'll learn - -* How to add Blockly to a sample web app. -* How to set up a Blockly workspace. -* How to create a new block in Blockly. -* How to generate and run JavaScript code from blocks. - -Example code for each step of the codelab is available from -the [completed](completed/) directory. diff --git a/demos/codelab/app-complete/index.html b/demos/codelab/app-complete/index.html deleted file mode 100644 index d5780e19d..000000000 --- a/demos/codelab/app-complete/index.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - Blockly for the Web Codelab - - - - - - -
-

Music Maker

-

Music Maker Configuration

-
- -
- - - -

Tap any button to edit its code.
When complete, press Done.

- -
-
-
1
-
2
-
3
-
-
-
4
-
5
-
6
-
-
-
7
-
8
-
9
-
-
- -
-
- -
-
- - - - - - - - - - - - diff --git a/demos/codelab/app-complete/scripts/main.js b/demos/codelab/app-complete/scripts/main.js deleted file mode 100644 index d5ebe0b3c..000000000 --- a/demos/codelab/app-complete/scripts/main.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - (function() { - - let currentButton; - - function handlePlay(event) { - loadWorkspace(event.target); - Blockly.JavaScript.addReservedWords('code'); - var code = Blockly.JavaScript.workspaceToCode(Blockly.getMainWorkspace()); - code += 'MusicMaker.play();'; - // Eval can be dangerous. For more controlled execution, check - // https://github.com/NeilFraser/JS-Interpreter. - try { - eval(code); - } catch (error) { - console.log(error); - } - } - - function loadWorkspace(button) { - let workspace = Blockly.getMainWorkspace(); - workspace.clear(); - if (button.blocklyXml) { - Blockly.Xml.domToWorkspace(button.blocklyXml, workspace); - } - } - - function save(button) { - let xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); - button.blocklyXml = xml; - } - - function handleSave() { - document.body.setAttribute('mode', 'edit'); - save(currentButton); - } - - function enableEditMode() { - document.body.setAttribute('mode', 'edit'); - document.querySelectorAll('.button').forEach(btn => { - btn.removeEventListener('click', handlePlay); - btn.addEventListener('click', enableBlocklyMode); - }); - } - - function enableMakerMode() { - document.body.setAttribute('mode', 'maker'); - document.querySelectorAll('.button').forEach(btn => { - btn.addEventListener('click', handlePlay); - btn.removeEventListener('click', enableBlocklyMode); - }); - } - - function enableBlocklyMode(e) { - document.body.setAttribute('mode', 'blockly'); - currentButton = e.target; - loadWorkspace(currentButton); - } - - document.querySelector('#edit').addEventListener('click', enableEditMode); - document.querySelector('#done').addEventListener('click', enableMakerMode); - document.querySelector('#save').addEventListener('click', handleSave); - - enableMakerMode(); - - Blockly.inject('blockly-div', { - media: '../../../media/', - toolbox: document.getElementById('toolbox'), - toolboxPosition: 'end', - horizontalLayout: true, - scrollbars: false - }); -})(); diff --git a/demos/codelab/app-complete/scripts/music_maker.js b/demos/codelab/app-complete/scripts/music_maker.js deleted file mode 100644 index adfefeddc..000000000 --- a/demos/codelab/app-complete/scripts/music_maker.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - const MusicMaker = { - queue_: [], - player_: new Audio(), - queueSound: function(soundUrl) { - this.queue_.push(soundUrl); - }, - play: function() { - let next = this.queue_.shift(); - if (next) { - this.player_.src = next; - this.player_.play(); - } - }, -}; - -MusicMaker.player_.addEventListener( - 'ended', MusicMaker.play.bind(MusicMaker)); diff --git a/demos/codelab/app-complete/scripts/sound_blocks.js b/demos/codelab/app-complete/scripts/sound_blocks.js deleted file mode 100644 index b8b851819..000000000 --- a/demos/codelab/app-complete/scripts/sound_blocks.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -Blockly.defineBlocksWithJsonArray([ - // Block for colour picker. - { - "type": "play_sound", - "message0": "Play %1", - "args0": [ - { - "type": "field_dropdown", - "name": "VALUE", - "options": [ - ["C4", "sounds/c4.m4a"], - ["D4", "sounds/d4.m4a"], - ["E4", "sounds/e4.m4a"], - ["F4", "sounds/f4.m4a"], - ["G4", "sounds/g4.m4a"], - ["A5", "sounds/a5.m4a"], - ["B5", "sounds/b5.m4a"], - ["C5", "sounds/c5.m4a"] - ] - } - ], - "previousStatement": null, - "nextStatement": null, - "colour": 355, - "tooltip": "", - "helpUrl": "" - } -]); - -Blockly.JavaScript['play_sound'] = function(block) { - var value = '\'' + block.getFieldValue('VALUE') + '\''; - return 'MusicMaker.queueSound(' + value + ');\n'; -}; diff --git a/demos/codelab/app-complete/sounds/c4.m4a b/demos/codelab/app-complete/sounds/c4.m4a deleted file mode 100644 index 33941cfae..000000000 Binary files a/demos/codelab/app-complete/sounds/c4.m4a and /dev/null differ diff --git a/demos/codelab/app-complete/sounds/c5.m4a b/demos/codelab/app-complete/sounds/c5.m4a deleted file mode 100644 index 49721cd31..000000000 Binary files a/demos/codelab/app-complete/sounds/c5.m4a and /dev/null differ diff --git a/demos/codelab/app-complete/sounds/d4.m4a b/demos/codelab/app-complete/sounds/d4.m4a deleted file mode 100644 index 51bcad6c2..000000000 Binary files a/demos/codelab/app-complete/sounds/d4.m4a and /dev/null differ diff --git a/demos/codelab/app-complete/sounds/e4.m4a b/demos/codelab/app-complete/sounds/e4.m4a deleted file mode 100644 index d910052ef..000000000 Binary files a/demos/codelab/app-complete/sounds/e4.m4a and /dev/null differ diff --git a/demos/codelab/app-complete/sounds/f4.m4a b/demos/codelab/app-complete/sounds/f4.m4a deleted file mode 100644 index c80a0bfd3..000000000 Binary files a/demos/codelab/app-complete/sounds/f4.m4a and /dev/null differ diff --git a/demos/codelab/app-complete/sounds/g4.m4a b/demos/codelab/app-complete/sounds/g4.m4a deleted file mode 100644 index 45ea44830..000000000 Binary files a/demos/codelab/app-complete/sounds/g4.m4a and /dev/null differ diff --git a/demos/codelab/app-complete/styles/index.css b/demos/codelab/app-complete/styles/index.css deleted file mode 100644 index 0ef8f3bfc..000000000 --- a/demos/codelab/app-complete/styles/index.css +++ /dev/null @@ -1,75 +0,0 @@ -main { - width: 400px; - position: relative; - margin: 0 auto; - overflow:hidden; - height: 600px; -} - -header { - background-color: green; - width: 100%; -} - -h1 { - width: 400px; - position: relative; - margin: 0 auto; - color: #fff; - font-size: 1.8em; - line-height: 2.4em; -} - -.mode-edit, -.mode-maker, -.mode-blockly { - display: none; -} - -[mode="maker"] .mode-maker, -[mode="edit"] .mode-edit, -[mode="blockly"] .mode-blockly { - display: block; -} - -.blockly-editor { - position: absolute; - top: 64px; - left: -400px; - transition: left .4s; - height: 460px; - width: 400px; - background-color: #eee; -} - -[mode="blockly"] .blockly-editor { - left: 0; -} - -.maker { - display: flex; - flex-flow: column; - justify-content: space-between; - height: 460px; - width: 400px; -} - -.maker > div { - display: flex; - justify-content: space-between; -} - -.button { - width: 120px; - height: 140px; - color: #fff; - font-size: 3em; - text-align: center; - vertical-align: middle; - line-height: 140px; -} - -.mdl-button { - margin: 1em 0; - float: right; -} diff --git a/demos/codelab/app/index.html b/demos/codelab/app/index.html deleted file mode 100644 index 31eeff776..000000000 --- a/demos/codelab/app/index.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - Blockly for the Web Codelab - - - - - - -
-

Music Maker

-

Music Maker Configuration

-
- -
- - - -

Tap any button to edit its code.
When complete, press Done.

- -
-
-
1
-
2
-
3
-
-
-
4
-
5
-
6
-
-
-
7
-
8
-
9
-
-
- -
-
-
-
- - - - - - diff --git a/demos/codelab/app/scripts/main.js b/demos/codelab/app/scripts/main.js deleted file mode 100644 index 9eef2f96a..000000000 --- a/demos/codelab/app/scripts/main.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - (function() { - - let currentButton; - - function handlePlay(event) { - // Add code for playing sound. - } - - function save(button) { - // Add code for saving the behavior of a button. - } - - function handleSave() { - document.body.setAttribute('mode', 'edit'); - save(currentButton); - } - - function enableEditMode() { - document.body.setAttribute('mode', 'edit'); - document.querySelectorAll('.button').forEach(btn => { - btn.removeEventListener('click', handlePlay); - btn.addEventListener('click', enableBlocklyMode); - }); - } - - function enableMakerMode() { - document.body.setAttribute('mode', 'maker'); - document.querySelectorAll('.button').forEach(btn => { - btn.addEventListener('click', handlePlay); - btn.removeEventListener('click', enableBlocklyMode); - }); - } - - function enableBlocklyMode(e) { - document.body.setAttribute('mode', 'blockly'); - currentButton = e.target; - } - - document.querySelector('#edit').addEventListener('click', enableEditMode); - document.querySelector('#done').addEventListener('click', enableMakerMode); - document.querySelector('#save').addEventListener('click', handleSave); - - enableMakerMode(); - -})(); diff --git a/demos/codelab/app/scripts/music_maker.js b/demos/codelab/app/scripts/music_maker.js deleted file mode 100644 index adfefeddc..000000000 --- a/demos/codelab/app/scripts/music_maker.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - const MusicMaker = { - queue_: [], - player_: new Audio(), - queueSound: function(soundUrl) { - this.queue_.push(soundUrl); - }, - play: function() { - let next = this.queue_.shift(); - if (next) { - this.player_.src = next; - this.player_.play(); - } - }, -}; - -MusicMaker.player_.addEventListener( - 'ended', MusicMaker.play.bind(MusicMaker)); diff --git a/demos/codelab/app/sounds/c4.m4a b/demos/codelab/app/sounds/c4.m4a deleted file mode 100644 index 33941cfae..000000000 Binary files a/demos/codelab/app/sounds/c4.m4a and /dev/null differ diff --git a/demos/codelab/app/sounds/c5.m4a b/demos/codelab/app/sounds/c5.m4a deleted file mode 100644 index 49721cd31..000000000 Binary files a/demos/codelab/app/sounds/c5.m4a and /dev/null differ diff --git a/demos/codelab/app/sounds/d4.m4a b/demos/codelab/app/sounds/d4.m4a deleted file mode 100644 index 51bcad6c2..000000000 Binary files a/demos/codelab/app/sounds/d4.m4a and /dev/null differ diff --git a/demos/codelab/app/sounds/e4.m4a b/demos/codelab/app/sounds/e4.m4a deleted file mode 100644 index d910052ef..000000000 Binary files a/demos/codelab/app/sounds/e4.m4a and /dev/null differ diff --git a/demos/codelab/app/sounds/f4.m4a b/demos/codelab/app/sounds/f4.m4a deleted file mode 100644 index c80a0bfd3..000000000 Binary files a/demos/codelab/app/sounds/f4.m4a and /dev/null differ diff --git a/demos/codelab/app/sounds/g4.m4a b/demos/codelab/app/sounds/g4.m4a deleted file mode 100644 index 45ea44830..000000000 Binary files a/demos/codelab/app/sounds/g4.m4a and /dev/null differ diff --git a/demos/codelab/app/styles/index.css b/demos/codelab/app/styles/index.css deleted file mode 100644 index 0ef8f3bfc..000000000 --- a/demos/codelab/app/styles/index.css +++ /dev/null @@ -1,75 +0,0 @@ -main { - width: 400px; - position: relative; - margin: 0 auto; - overflow:hidden; - height: 600px; -} - -header { - background-color: green; - width: 100%; -} - -h1 { - width: 400px; - position: relative; - margin: 0 auto; - color: #fff; - font-size: 1.8em; - line-height: 2.4em; -} - -.mode-edit, -.mode-maker, -.mode-blockly { - display: none; -} - -[mode="maker"] .mode-maker, -[mode="edit"] .mode-edit, -[mode="blockly"] .mode-blockly { - display: block; -} - -.blockly-editor { - position: absolute; - top: 64px; - left: -400px; - transition: left .4s; - height: 460px; - width: 400px; - background-color: #eee; -} - -[mode="blockly"] .blockly-editor { - left: 0; -} - -.maker { - display: flex; - flex-flow: column; - justify-content: space-between; - height: 460px; - width: 400px; -} - -.maker > div { - display: flex; - justify-content: space-between; -} - -.button { - width: 120px; - height: 140px; - color: #fff; - font-size: 3em; - text-align: center; - vertical-align: middle; - line-height: 140px; -} - -.mdl-button { - margin: 1em 0; - float: right; -} diff --git a/demos/custom-dialogs/custom-dialog.js b/demos/custom-dialogs/custom-dialog.js deleted file mode 100644 index 04793e3da..000000000 --- a/demos/custom-dialogs/custom-dialog.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @license - * Copyright 2016 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * An example implementation of how one might replace Blockly's browser - * dialogs. This is just an example, and applications are not encouraged to use - * it verbatim. - * - * @namespace - */ -CustomDialog = {}; - -/** Override Blockly.dialog.alert() with custom implementation. */ -Blockly.dialog.setAlert(function(message, callback) { - console.log('Alert: ' + message); - CustomDialog.show('Alert', message, { - onCancel: callback - }); -}); - -/** Override Blockly.dialog.confirm() with custom implementation. */ -Blockly.dialog.setConfirm(function(message, callback) { - console.log('Confirm: ' + message); - CustomDialog.show('Confirm', message, { - showOkay: true, - onOkay: function() { - callback(true); - }, - showCancel: true, - onCancel: function() { - callback(false); - } - }); -}); - -/** Override Blockly.dialog.prompt() with custom implementation. */ -Blockly.dialog.setPrompt(function(message, defaultValue, callback) { - console.log('Prompt: ' + message); - CustomDialog.show('Prompt', message, { - showInput: true, - showOkay: true, - onOkay: function() { - callback(CustomDialog.inputField.value); - }, - showCancel: true, - onCancel: function() { - callback(null); - } - }); - CustomDialog.inputField.value = defaultValue; -}); - -/** Hides any currently visible dialog. */ -CustomDialog.hide = function() { - if (CustomDialog.backdropDiv_) { - CustomDialog.backdropDiv_.style.display = 'none'; - CustomDialog.dialogDiv_.style.display = 'none'; - } -}; - -/** - * Shows the dialog. - * Allowed options: - * - showOkay: Whether to show the OK button. - * - showCancel: Whether to show the Cancel button. - * - showInput: Whether to show the text input field. - * - onOkay: Callback to handle the okay button. - * - onCancel: Callback to handle the cancel button and backdrop clicks. - */ -CustomDialog.show = function(title, message, options) { - var backdropDiv = CustomDialog.backdropDiv_; - var dialogDiv = CustomDialog.dialogDiv_; - if (!dialogDiv) { - // Generate HTML - backdropDiv = document.createElement('div'); - backdropDiv.id = 'customDialogBackdrop'; - backdropDiv.style.cssText = - 'position: absolute;' + - 'top: 0; left: 0; right: 0; bottom: 0;' + - 'background-color: rgba(0, 0, 0, .7);' + - 'z-index: 100;'; - document.body.appendChild(backdropDiv); - - dialogDiv = document.createElement('div'); - dialogDiv.id = 'customDialog'; - dialogDiv.style.cssText = - 'background-color: #fff;' + - 'width: 400px;' + - 'margin: 20px auto 0;' + - 'padding: 10px;'; - backdropDiv.appendChild(dialogDiv); - - dialogDiv.onclick = function(event) { - event.stopPropagation(); - }; - - CustomDialog.backdropDiv_ = backdropDiv; - CustomDialog.dialogDiv_ = dialogDiv; - } - backdropDiv.style.display = 'block'; - dialogDiv.style.display = 'block'; - - dialogDiv.innerHTML = - '
' + - '

' + - (options.showInput ? '
' : '') + - '
' + - (options.showCancel ? '': '') + - (options.showOkay ? '': '') + - '
'; - dialogDiv.getElementsByClassName('customDialogTitle')[0] - .appendChild(document.createTextNode(title)); - dialogDiv.getElementsByClassName('customDialogMessage')[0] - .appendChild(document.createTextNode(message)); - - var onOkay = function(event) { - CustomDialog.hide(); - options.onOkay && options.onOkay(); - event && event.stopPropagation(); - }; - var onCancel = function(event) { - CustomDialog.hide(); - options.onCancel && options.onCancel(); - event && event.stopPropagation(); - }; - - var dialogInput = document.getElementById('customDialogInput'); - CustomDialog.inputField = dialogInput; - if (dialogInput) { - dialogInput.focus(); - - dialogInput.onkeyup = function(event) { - if (event.keyCode === 13) { - // Process as OK when user hits enter. - onOkay(); - return false; - } else if (event.keyCode === 27) { - // Process as cancel when user hits esc. - onCancel(); - return false; - } - }; - } else { - var okay = document.getElementById('customDialogOkay'); - okay && okay.focus(); - } - - if (options.showOkay) { - document.getElementById('customDialogOkay') - .addEventListener('click', onOkay); - } - if (options.showCancel) { - document.getElementById('customDialogCancel') - .addEventListener('click', onCancel); - } - - backdropDiv.onclick = onCancel; -}; diff --git a/demos/custom-dialogs/icon.png b/demos/custom-dialogs/icon.png deleted file mode 100644 index ba49746e4..000000000 Binary files a/demos/custom-dialogs/icon.png and /dev/null differ diff --git a/demos/custom-dialogs/index.html b/demos/custom-dialogs/index.html deleted file mode 100644 index 9c171802e..000000000 --- a/demos/custom-dialogs/index.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - Blockly Demo: Custom Dialog - - - - - - -

Blockly > - Demos > Custom Dialog

- -

This is a simple demo of replacing modal browser dialogs with HTML. - To see how it works, see the source code in - custom-dialog.js -

- -

Try creating new variables, creating variables with names already in - use, or deleting multiple blocks on the workspace. -

- -
- - - - - - - - diff --git a/demos/custom-fields/icon.png b/demos/custom-fields/icon.png deleted file mode 100644 index e69de29bb..000000000 diff --git a/demos/custom-fields/index.html b/demos/custom-fields/index.html deleted file mode 100644 index 9e681a8b6..000000000 --- a/demos/custom-fields/index.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - Blockly Demo: Custom Fields - - - -

Blockly > - Demos > Custom Fields

- -

These demos are intended for developers who want creating custom block fields.

- - - - - - - - - - - -
- - - - -
Turtle Field
-
- - - - -
Pitch Field
-
- - diff --git a/demos/custom-fields/pitch/blocks.js b/demos/custom-fields/pitch/blocks.js deleted file mode 100644 index 75fbae2a7..000000000 --- a/demos/custom-fields/pitch/blocks.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Pitch field demo blocks. - */ - -Blockly.Blocks['test_pitch_field'] = { - init: function() { - this.appendDummyInput() - .appendField('pitch') - .appendField(new CustomFields.FieldPitch('7'), 'PITCH'); - this.setStyle('loop_blocks'); - } -}; diff --git a/demos/custom-fields/pitch/field_pitch.js b/demos/custom-fields/pitch/field_pitch.js deleted file mode 100644 index d049be2de..000000000 --- a/demos/custom-fields/pitch/field_pitch.js +++ /dev/null @@ -1,235 +0,0 @@ -/** - * @license - * Copyright 2016 Google LLC - * https://github.com/google/blockly-games - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Music pitch input field. Borrowed from Blockly Games. - */ -'use strict'; - -goog.provide('CustomFields.FieldPitch'); - -goog.require('Blockly.FieldTextInput'); -goog.require('Blockly.utils.math'); -goog.require('Blockly.utils.object'); - -var CustomFields = CustomFields || {}; - -/** - * Class for an editable pitch field. - * @param {string} text The initial content of the field. - * @extends {Blockly.FieldTextInput} - * @constructor - */ -CustomFields.FieldPitch = function(text) { - CustomFields.FieldPitch.superClass_.constructor.call(this, text); - - /** - * Click event data. - * @type {?Blockly.browserEvents.Data} - * @private - */ - this.clickWrapper_ = null; - - /** - * Move event data. - * @type {?Blockly.browserEvents.Data} - * @private - */ - this.moveWrapper_ = null; -}; -Blockly.utils.object.inherits(CustomFields.FieldPitch, Blockly.FieldTextInput); - -/** - * Construct a FieldPitch from a JSON arg object. - * @param {!Object} options A JSON object with options (pitch). - * @return {!CustomFields.FieldPitch} The new field instance. - * @package - * @nocollapse - */ -CustomFields.FieldPitch.fromJson = function(options) { - return new CustomFields.FieldPitch(options['pitch']); -}; - -/** - * All notes available for the picker. - */ -CustomFields.FieldPitch.NOTES = 'C3 D3 E3 F3 G3 A3 B3 C4 D4 E4 F4 G4 A4'.split(/ /); - -/** - * Show the inline free-text editor on top of the text and the note picker. - * @protected - */ -CustomFields.FieldPitch.prototype.showEditor_ = function() { - CustomFields.FieldPitch.superClass_.showEditor_.call(this); - - var div = Blockly.WidgetDiv.getDiv(); - if (!div.firstChild) { - // Mobile interface uses Blockly.dialog.prompt. - return; - } - // Build the DOM. - var editor = this.dropdownCreate_(); - Blockly.DropDownDiv.getContentDiv().appendChild(editor); - - Blockly.DropDownDiv.setColour(this.sourceBlock_.style.colourPrimary, - this.sourceBlock_.style.colourTertiary); - - Blockly.DropDownDiv.showPositionedByField( - this, this.dropdownDispose_.bind(this)); - - // The note 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. For now, using bindEvent_ instead of - // bindEventWithChecks_ allows it to work without a mousedown/touchstart. - this.clickWrapper_ = - Blockly.browserEvents.bind(this.imageElement_, 'click', this, this.hide_); - this.moveWrapper_ = Blockly.browserEvents.bind( - this.imageElement_, 'mousemove', this, this.onMouseMove); - - this.updateGraph_(); -}; - -/** - * Create the pitch editor. - * @return {!Element} The newly created pitch picker. - * @private - */ -CustomFields.FieldPitch.prototype.dropdownCreate_ = function() { - this.imageElement_ = document.createElement('div'); - this.imageElement_.id = 'notePicker'; - - return this.imageElement_; -}; - -/** - * Dispose of events belonging to the pitch editor. - * @private - */ -CustomFields.FieldPitch.prototype.dropdownDispose_ = function() { - if (this.clickWrapper_) { - Blockly.browserEvents.unbind(this.clickWrapper_); - this.clickWrapper_ = null; - } - if (this.moveWrapper_) { - Blockly.browserEvents.unbind(this.moveWrapper_); - this.moveWrapper_ = null; - } - this.imageElement_ = null; -}; - -/** - * Hide the editor. - * @private - */ -CustomFields.FieldPitch.prototype.hide_ = function() { - Blockly.WidgetDiv.hide(); - Blockly.DropDownDiv.hideWithoutAnimation(); -}; - -/** - * Set the note to match the mouse's position. - * @param {!Event} e Mouse move event. - */ -CustomFields.FieldPitch.prototype.onMouseMove = function(e) { - var bBox = this.imageElement_.getBoundingClientRect(); - var dy = e.clientY - bBox.top; - var note = Blockly.utils.math.clamp(Math.round(13.5 - dy / 7.5), 0, 12); - this.imageElement_.style.backgroundPosition = (-note * 37) + 'px 0'; - this.setEditorValue_(note); -}; - -/** - * Convert the machine-readable value (0-12) to human-readable text (C3-A4). - * @param {number|string} value The provided value. - * @return {string|undefined} The respective note, or undefined if invalid. - */ -CustomFields.FieldPitch.prototype.valueToNote = function(value) { - return CustomFields.FieldPitch.NOTES[Number(value)]; -}; - -/** - * Convert the human-readable text (C3-A4) to machine-readable value (0-12). - * @param {string} text The provided note. - * @return {number|undefined} The respective value, or undefined if invalid. - */ -CustomFields.FieldPitch.prototype.noteToValue = function(text) { - var normalizedText = text.trim().toUpperCase(); - var i = CustomFields.FieldPitch.NOTES.indexOf(normalizedText); - return i > -1 ? i : undefined; -}; - -/** - * Get the text to be displayed on the field node. - * @return {?string} The HTML value if we're editing, otherwise null. Null means - * the super class will handle it, likely a string cast of value. - * @protected - */ -CustomFields.FieldPitch.prototype.getText_ = function() { - if (this.isBeingEdited_) { - return CustomFields.FieldPitch.superClass_.getText_.call(this); - } - return this.valueToNote(this.getValue()) || null; -}; - -/** - * Transform the provided value into a text to show in the HTML input. - * @param {*} value The value stored in this field. - * @return {string} The text to show on the HTML input. - */ -CustomFields.FieldPitch.prototype.getEditorText_ = function(value) { - return this.valueToNote(value); -}; - -/** - * Transform the text received from the HTML input (note) into a value - * to store in this field. - * @param {string} text Text received from the HTML input. - * @return {*} The value to store. - */ -CustomFields.FieldPitch.prototype.getValueFromEditorText_ = function(text) { - return this.noteToValue(text); -}; - -/** - * Updates the graph when the field rerenders. - * @private - * @override - */ -CustomFields.FieldPitch.prototype.render_ = function() { - CustomFields.FieldPitch.superClass_.render_.call(this); - this.updateGraph_(); -}; - -/** - * Redraw the note picker with the current note. - * @private - */ -CustomFields.FieldPitch.prototype.updateGraph_ = function() { - if (!this.imageElement_) { - return; - } - var i = this.getValue(); - this.imageElement_.style.backgroundPosition = (-i * 37) + 'px 0'; -}; - -/** - * Ensure that only a valid value may be entered. - * @param {*} opt_newValue The input value. - * @return {*} A valid value, or null if invalid. - */ -CustomFields.FieldPitch.prototype.doClassValidation_ = function(opt_newValue) { - if (opt_newValue === null || opt_newValue === undefined) { - return null; - } - var note = this.valueToNote(opt_newValue); - if (note) { - return opt_newValue; - } - return null; -}; - -Blockly.fieldRegistry.register('field_pitch', CustomFields.FieldPitch); diff --git a/demos/custom-fields/pitch/index.html b/demos/custom-fields/pitch/index.html deleted file mode 100644 index 2d614f6b0..000000000 --- a/demos/custom-fields/pitch/index.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - Blockly Demo: Custom Pitch Field - - - - - - - - -

- Blockly > - Demos > - Custom Fields > Pitch Field

- - -

This is a demo of creating custom block fields. In this case the field - is used to select a note pitch. -

- -

All of the custom field implementation is in - demos/custom-fields/pitch/field_pitch.js, including comments on each required - function. -

- -

- - -

- - - - - - -
- - -
-
- - - - - - diff --git a/demos/custom-fields/pitch/media/notes.png b/demos/custom-fields/pitch/media/notes.png deleted file mode 100644 index b9a57b59e..000000000 Binary files a/demos/custom-fields/pitch/media/notes.png and /dev/null differ diff --git a/demos/custom-fields/pitch/pitch.css b/demos/custom-fields/pitch/pitch.css deleted file mode 100644 index 75d17a35d..000000000 --- a/demos/custom-fields/pitch/pitch.css +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - - -#notePicker { - background-image: url(media/notes.png); - border: 1px solid #ccc; - height: 109px; - width: 46px; -} \ No newline at end of file diff --git a/demos/custom-fields/turtle/blocks.js b/demos/custom-fields/turtle/blocks.js deleted file mode 100644 index 494b10038..000000000 --- a/demos/custom-fields/turtle/blocks.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Turtle field demo blocks. - */ - -Blockly.Blocks['turtle_basic'] = { - init: function() { - this.appendDummyInput() - .appendField('simple turtle'); - this.appendDummyInput() - .setAlign(Blockly.ALIGN_CENTRE) - .appendField(new CustomFields.FieldTurtle(), 'TURTLE'); - this.setStyle('loop_blocks'); - this.setCommentText('Demonstrates a turtle field with no validator.'); - } -}; - -Blockly.Blocks['turtle_nullifier'] = { - init: function() { - this.appendDummyInput() - .appendField('no trademarks'); - this.appendDummyInput() - .setAlign(Blockly.ALIGN_CENTRE) - .appendField(new CustomFields.FieldTurtle(null, null, null, this.validate) - , 'TURTLE'); - this.setStyle('loop_blocks'); - this.setCommentText('Validates combinations of names and hats to null' + - ' (invalid) if they could be considered infringe-y. This turns the' + - ' turtle field red. Infringe-y combinations are: (Leonardo, Mask),' + - ' (Yertle, Crown), and (Franklin, Propeller).'); - }, - - validate: function(newValue) { - this.cachedValidatedValue_ = { - turtleName: newValue.turtleName, - pattern: newValue.pattern, - hat: newValue.hat, - }; - if ((newValue.turtleName === 'Leonardo' && newValue.hat === 'Mask') || - (newValue.turtleName === 'Yertle' && newValue.hat === 'Crown') || - (newValue.turtleName === 'Franklin') && newValue.hat === 'Propeller') { - - var currentValue = this.getValue(); - if (newValue.turtleName !== currentValue.turtleName) { - // Turtle name changed. - this.cachedValidatedValue_.turtleName = null; - } else { - // Hat must have changed. - this.cachedValidatedValue_.hat = null; - } - - return null; - } - return newValue; - } -}; - -Blockly.Blocks['turtle_changer'] = { - init: function() { - this.appendDummyInput() - .setAlign(Blockly.ALIGN_CENTRE) - .appendField('force hats'); - this.appendDummyInput() - .appendField(new CustomFields.FieldTurtle( - 'Dots', 'Crown', 'Yertle', this.validate), 'TURTLE'); - this.setStyle('loop_blocks'); - this.setCommentText('Validates the input so that certain names always' + - ' have specific hats. The name-hat combinations are: (Leonardo, Mask),' + - ' (Yertle, Crown), (Franklin, Propeller).'); - }, - - validate: function(newValue) { - switch(newValue.turtleName) { - case 'Leonardo': - newValue.hat = 'Mask'; - break; - case 'Yertle': - newValue.hat = 'Crown'; - break; - case 'Franklin': - newValue.hat = 'Propeller'; - break; - } - return newValue; - } -}; diff --git a/demos/custom-fields/turtle/field_turtle.js b/demos/custom-fields/turtle/field_turtle.js deleted file mode 100644 index a24bfb7d6..000000000 --- a/demos/custom-fields/turtle/field_turtle.js +++ /dev/null @@ -1,747 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview A field used to customize a turtle. - */ -'use strict'; - -// You must provide the constructor for your custom field. -goog.provide('CustomFields.FieldTurtle'); - -// You must require the abstract field class to inherit from. -goog.require('Blockly.Field'); -goog.require('Blockly.fieldRegistry'); -goog.require('Blockly.utils'); -goog.require('Blockly.utils.dom'); -goog.require('Blockly.utils.object'); -goog.require('Blockly.utils.Size'); - -var CustomFields = CustomFields || {}; - -// Generally field's values should be optional, and have logical defaults. -// If this is not possible (for example image fields can't have logical -// defaults) the field should throw a clear error when a value is not provided. -// Editable fields also generally accept validators, so we will accept a -// validator. -CustomFields.FieldTurtle = function( - opt_pattern, opt_hat, opt_turtleName, opt_validator) { - - // The turtle field contains an object as its value, so we need to compile - // the parameters into an object. - var value = {}; - value.pattern = opt_pattern || CustomFields.FieldTurtle.PATTERNS[0]; - value.hat = opt_hat || CustomFields.FieldTurtle.HATS[0]; - value.turtleName = opt_turtleName || CustomFields.FieldTurtle.NAMES[0]; - - // A field constructor should always call its parent constructor, because - // that helps keep the code organized and DRY. - CustomFields.FieldTurtle.superClass_.constructor.call( - this, value, opt_validator); - - /** - * The size of the area rendered by the field. - * @type {Blockly.utils.Size} - * @protected - * @override - */ - this.size_ = new Blockly.utils.Size(0, 0); -}; -Blockly.utils.object.inherits(CustomFields.FieldTurtle, Blockly.Field); - -// This allows the field to be constructed using a JSON block definition. -CustomFields.FieldTurtle.fromJson = function(options) { - // In this case we simply pass the JSON options along to the constructor, - // but you can also use this to get message references, and other such things. - return new CustomFields.FieldTurtle( - options['pattern'], - options['hat'], - options['turtleName']); -}; - -// Since this field is editable we must also define serializable as true -// (for backwards compatibility reasons serializable is false by default). -CustomFields.FieldTurtle.prototype.SERIALIZABLE = true; - -// The cursor property defines what the mouse will look like when the user -// hovers over the field. By default the cursor will be whatever -// .blocklyDraggable's cursor is defined as (vis. grab). Most fields define -// this property as 'default'. -CustomFields.FieldTurtle.prototype.CURSOR = 'pointer'; - -// How far to move the text to keep it to the right of the turtle. -// May change if the turtle gets fancy enough. -CustomFields.FieldTurtle.prototype.TEXT_OFFSET_X = 80; - -// These are the different options for our turtle. Being declared this way -// means they are static, and not translatable. If you want to do something -// similar, but make it translatable you should set up your options like a -// dropdown field, with language-neutral keys and human-readable values. -CustomFields.FieldTurtle.PATTERNS = - ['Dots', 'Stripes', 'Hexagons']; -CustomFields.FieldTurtle.HATS = - ['Stovepipe', 'Crown', 'Propeller', 'Mask', 'Fedora']; -CustomFields.FieldTurtle.NAMES = - ['Yertle', 'Franklin', 'Crush', 'Leonardo', 'Bowser', 'Squirtle', 'Oogway']; - -// Used to keep track of our editor event listeners, so they can be -// properly disposed of when the field closes. You can keep track of your -// listeners however you want, just be sure to dispose of them! -CustomFields.FieldTurtle.prototype.editorListeners_ = []; - -// Used to create the DOM of our field. -CustomFields.FieldTurtle.prototype.initView = function() { - // Because we want to have both a borderRect_ (background) and a - // textElement_ (text) we can call the super-function. If we only wanted - // one or the other, we could call their individual createX functions. - CustomFields.FieldTurtle.superClass_.initView.call(this); - - // Note that the field group is created by the abstract field's init_ - // function. This means that *all elements* should be children of the - // fieldGroup_. - this.createView_(); -}; - -// Updates how the field looks depending on if it is editable or not. -CustomFields.FieldTurtle.prototype.updateEditable = function() { - if (!this.fieldGroup_) { - // Not initialized yet. - return; - } - // The default functionality just makes it so the borderRect_ does not - // highlight when hovered. - Blockly.FieldColour.superClass_.updateEditable.call(this); - // Things like this are best applied to the clickTarget_. By default the - // click target is the same as getSvgRoot, which by default is the - // fieldGroup_. - var group = this.getClickTarget_(); - if (!this.isCurrentlyEditable()) { - group.style.cursor = 'not-allowed'; - } else { - group.style.cursor = this.CURSOR; - } -}; - -// Gets the text to display when the block is collapsed -CustomFields.FieldTurtle.prototype.getText = function() { - var text = this.value_.turtleName + ' wearing a ' + this.value_.hat; - if (this.value_.hat === 'Stovepipe' || this.value_.hat === 'Propeller') { - text += ' hat'; - } - return text; -}; - -// Makes sure new field values (given to setValue) are valid, meaning -// something this field can legally "hold". Class validators can either change -// the input value, or return null if the input value is invalid. Called by -// the setValue() function. -CustomFields.FieldTurtle.prototype.doClassValidation_ = function(newValue) { - // Undefined signals that we want the value to remain unchanged. This is a - // special feature of turtle fields, but could be useful for other - // multi-part fields. - if (newValue.pattern === undefined) { - newValue.pattern = this.displayValue_ && this.displayValue_.pattern; - // We only want to allow patterns that are part of our pattern list. - // Anything else is invalid, so we return null. - } else if (CustomFields.FieldTurtle.PATTERNS.indexOf(newValue.pattern) === -1) { - newValue.pattern = null; - } - - if (newValue.hat === undefined) { - newValue.hat = this.displayValue_ && this.displayValue_.hat; - } else if (CustomFields.FieldTurtle.HATS.indexOf(newValue.hat) === -1) { - newValue.hat = null; - } - - if (newValue.turtleName === undefined) { - newValue.turtleName = this.displayValue_ && this.displayValue_.turtleName; - } else if (CustomFields.FieldTurtle.NAMES.indexOf(newValue.turtleName) === -1) { - newValue.turtleName = null; - } - - // This is a strategy for dealing with defaults on multi-part values. - // The class validator sets individual properties of the object to null - // to indicate that they are invalid, and then caches that object to the - // cachedValidatedValue_ property. This way the field can, for - // example, properly handle an invalid pattern, combined with a valid hat. - // This can also be done with local validators. - this.cachedValidatedValue_ = newValue; - - // Always be sure to return! - if (!newValue.pattern || !newValue.hat || !newValue.turtleName) { - return null; - } - return newValue; -}; - -// Saves the new field value. Called by the setValue function. -CustomFields.FieldTurtle.prototype.doValueUpdate_ = function(newValue) { - // The default function sets this field's this.value_ property to the - // newValue, and its this.isDirty_ property to true. The isDirty_ property - // tells the setValue function whether the field needs to be re-rendered. - CustomFields.FieldTurtle.superClass_.doValueUpdate_.call(this, newValue); - this.displayValue_ = newValue; - // Since this field has custom UI for invalid values, we also want to make - // sure it knows it is now valid. - this.isValueInvalid_ = false; -}; - -// Notifies that the field that the new value was invalid. Called by -// setValue function. Can either be triggered by the class validator, or the -// local validator. -CustomFields.FieldTurtle.prototype.doValueInvalid_ = function(invalidValue) { - // By default this function is no-op, meaning if the new value is invalid - // the field simply won't be updated. This field has custom UI for invalid - // values, so we override this function. - - // We want the value to be displayed like normal. - // But we want to flag it as invalid, so the render_ function knows to - // make the borderRect_ red. - this.displayValue_ = invalidValue; - this.isDirty_ = true; - this.isValueInvalid_ = true; -}; - -// Updates the field's on-block display based on the current display value. -CustomFields.FieldTurtle.prototype.render_ = function() { - var value = this.displayValue_; - - // Always do editor updates inside render. This makes sure the editor - // always displays the correct value, even if a validator changes it. - if (this.editor_) { - this.renderEditor_(); - } - - this.stovepipe_.style.display = 'none'; - this.crown_.style.display = 'none'; - this.mask_.style.display = 'none'; - this.propeller_.style.display = 'none'; - this.fedora_.style.display = 'none'; - switch(value.hat) { - case 'Stovepipe': - this.stovepipe_.style.display = ''; - this.turtleGroup_.setAttribute('transform', 'translate(0,12)'); - this.textElement_.setAttribute( - 'transform', 'translate(' + this.TEXT_OFFSET_X + ',20)'); - break; - case 'Crown': - this.crown_.style.display = ''; - this.turtleGroup_.setAttribute('transform', 'translate(0,9)'); - this.textElement_.setAttribute( - 'transform', 'translate(' + this.TEXT_OFFSET_X + ',16)'); - break; - case 'Mask': - this.mask_.style.display = ''; - this.turtleGroup_.setAttribute('transform', 'translate(0,6)'); - this.textElement_.setAttribute('transform', - 'translate(' + this.TEXT_OFFSET_X + ',12)'); - break; - case 'Propeller': - this.propeller_.style.display = ''; - this.turtleGroup_.setAttribute('transform', 'translate(0,6)'); - this.textElement_.setAttribute('transform', - 'translate(' + this.TEXT_OFFSET_X + ',12)'); - break; - case 'Fedora': - this.fedora_.style.display = ''; - this.turtleGroup_.setAttribute('transform', 'translate(0,6)'); - this.textElement_.setAttribute('transform', - 'translate(' + this.TEXT_OFFSET_X + ',12)'); - break; - } - - switch(value.pattern) { - case 'Dots': - this.shellPattern_.setAttribute('fill', 'url(#polkadots)'); - break; - case 'Stripes': - this.shellPattern_.setAttribute('fill', 'url(#stripes)'); - break; - case 'Hexagons': - this.shellPattern_.setAttribute('fill', 'url(#hexagons)'); - break; - } - - // Always modify the textContent_ rather than the textElement_. This - // allows fields to append DOM to the textElement (e.g. the angle field). - this.textContent_.nodeValue = value.turtleName; - - if (this.isValueInvalid_) { - this.borderRect_.style.fill = '#f99'; - this.borderRect_.style.fillOpacity = 1; - } else { - this.borderRect_.style.fill = '#fff'; - this.borderRect_.style.fillOpacity = 0.6; - } - - this.updateSize_(); -}; - -CustomFields.FieldTurtle.prototype.renderEditor_ = function() { - var value = this.displayValue_; - - // .textElement is a property assigned to the element. - // It allows the text to be edited without destroying the warning icon. - this.editor_.patternText.textElement.nodeValue = value.pattern; - this.editor_.hatText.textElement.nodeValue = value.hat; - this.editor_.turtleNameText.textElement.nodeValue = value.turtleName; - - this.editor_.patternText.warningIcon.style.display = - this.cachedValidatedValue_.pattern ? 'none' : ''; - this.editor_.hatText.warningIcon.style.display = - this.cachedValidatedValue_.hat ? 'none' : ''; - this.editor_.turtleNameText.warningIcon.style.display = - this.cachedValidatedValue_.turtleName ? 'none' : ''; -}; - -// Used to update the size of the field. This function's logic could be simply -// included inside render_ (it is not called anywhere else), but it is -// usually separated to keep code more organized. -CustomFields.FieldTurtle.prototype.updateSize_ = function() { - var bbox = this.movableGroup_.getBBox(); - var width = bbox.width; - var height = bbox.height; - if (this.borderRect_) { - width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; - height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2; - this.borderRect_.setAttribute('width', width); - this.borderRect_.setAttribute('height', height); - } - // Note how both the width and the height can be dynamic. - this.size_.width = width; - this.size_.height = height; -}; - -// Called when the field is clicked. It is usually used to show an editor, -// but it can also be used for other things e.g. the checkbox field uses -// this function to check/uncheck itself. -CustomFields.FieldTurtle.prototype.showEditor_ = function() { - this.editor_ = this.dropdownCreate_(); - this.renderEditor_(); - Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_); - - // These allow us to have the editor match the block's colour. - var fillColour = this.sourceBlock_.getColour(); - Blockly.DropDownDiv.setColour(fillColour, - this.sourceBlock_.style.colourTertiary); - - // Always pass the dropdown div a dispose function so that you can clean - // up event listeners when the editor closes. - Blockly.DropDownDiv.showPositionedByField( - this, this.dropdownDispose_.bind(this)); -}; - -// Creates the UI of the editor, and adds event listeners to it. -CustomFields.FieldTurtle.prototype.dropdownCreate_ = function() { - var createRow = function(table) { - var row = table.appendChild(document.createElement('tr')); - row.className = 'row'; - return row; - }; - var createLeftArrow = function(row) { - var cell = document.createElement('div'); - cell.className = 'arrow'; - var leftArrow = document.createElement('button'); - leftArrow.setAttribute('type', 'button'); - leftArrow.textContent = '<'; - cell.appendChild(leftArrow); - row.appendChild(cell); - return cell; - }; - var createTextNode = function(row, text) { - var cell = document.createElement('div'); - cell.className = 'text'; - var text = document.createTextNode(text); - cell.appendChild(text); - cell.textElement = text; - var warning = document.createElement('img'); - warning.setAttribute('src', 'media/warning.svg'); - warning.setAttribute('height', '16px'); - warning.setAttribute('width', '16px'); - warning.style.marginLeft = '4px'; - cell.appendChild(warning); - cell.warningIcon = warning; - row.appendChild(cell); - return cell; - }; - var createRightArrow = function(row) { - var cell = document.createElement('div'); - cell.className = 'arrow'; - var rightArrow = document.createElement('button'); - rightArrow.setAttribute('type', 'button'); - rightArrow.textContent = '>'; - cell.appendChild(rightArrow); - row.appendChild(cell); - return cell; - }; - var createArrowListener = function(variable, array, direction) { - return function() { - var currentIndex = array.indexOf(this.displayValue_[variable]); - currentIndex += direction; - if (currentIndex <= -1) { - currentIndex = array.length - 1; - } else if (currentIndex >= array.length) { - currentIndex = 0; - } - var value = {}; - value[variable] = array[currentIndex]; - this.setValue(value); - }; - }; - - var widget = document.createElement('div'); - widget.className = 'customFieldsTurtleWidget blocklyNonSelectable'; - - var table = document.createElement('div'); - table.className = 'table'; - widget.appendChild(table); - - var row = createRow(table); - var leftArrow = createLeftArrow(row); - widget.patternText = createTextNode(row, this.displayValue_.pattern); - var rightArrow = createRightArrow(row); - this.editorListeners_.push(Blockly.browserEvents.bind( - leftArrow, 'mouseup', this, - createArrowListener('pattern', CustomFields.FieldTurtle.PATTERNS, -1))); - this.editorListeners_.push(Blockly.browserEvents.bind( - rightArrow, 'mouseup', this, - createArrowListener('pattern', CustomFields.FieldTurtle.PATTERNS, 1))); - - row = createRow(table); - leftArrow = createLeftArrow(row); - widget.hatText = createTextNode(row, this.displayValue_.hat); - rightArrow = createRightArrow(row); - this.editorListeners_.push(Blockly.browserEvents.bind( - leftArrow, 'mouseup', this, - createArrowListener('hat', CustomFields.FieldTurtle.HATS, -1))); - this.editorListeners_.push(Blockly.browserEvents.bind( - rightArrow, 'mouseup', this, - createArrowListener('hat', CustomFields.FieldTurtle.HATS, 1))); - - row = createRow(table); - leftArrow = createLeftArrow(row); - widget.turtleNameText = createTextNode(row, this.displayValue_.turtleName); - rightArrow = createRightArrow(row); - this.editorListeners_.push(Blockly.browserEvents.bind( - leftArrow, 'mouseup', this, - createArrowListener('turtleName', CustomFields.FieldTurtle.NAMES, -1))); - this.editorListeners_.push(Blockly.browserEvents.bind( - rightArrow, 'mouseup', this, - createArrowListener('turtleName', CustomFields.FieldTurtle.NAMES, 1))); - - var randomizeButton = document.createElement('button'); - randomizeButton.className = 'randomize'; - randomizeButton.setAttribute('type', 'button'); - randomizeButton.textContent = 'randomize turtle'; - this.editorListeners_.push( - Blockly.browserEvents.bind(randomizeButton, 'mouseup', this, function() { - var value = {}; - value.pattern = CustomFields.FieldTurtle.PATTERNS[Math.floor( - Math.random() * CustomFields.FieldTurtle.PATTERNS.length)]; - - value.hat = CustomFields.FieldTurtle.HATS[Math.floor( - Math.random() * CustomFields.FieldTurtle.HATS.length)]; - - value.turtleName = CustomFields.FieldTurtle.NAMES[Math.floor( - Math.random() * CustomFields.FieldTurtle.NAMES.length)]; - - this.setValue(value); - })); - widget.appendChild(randomizeButton); - - return widget; -}; - -// Cleans up any event listeners that were attached to the now hidden editor. -CustomFields.FieldTurtle.prototype.dropdownDispose_ = function() { - for (var i = this.editorListeners_.length, listener; - listener = this.editorListeners_[i]; i--) { - Blockly.browserEvents.unbind(listener); - this.editorListeners_.pop(); - } -}; - -// Updates the field's colour based on the colour of the block. Called by -// block.applyColour. -CustomFields.FieldTurtle.prototype.applyColour = function() { - if (!this.sourceBlock_) { - return; - } - // The getColourX functions are the best way to access the colours of a block. - var isShadow = this.sourceBlock_.isShadow(); - var fillColour = isShadow ? - this.sourceBlock_.getColourShadow() : this.sourceBlock_.getColour(); - // This is technically a package function, meaning it could change. - var borderColour = isShadow ? fillColour : - this.sourceBlock_.style.colourTertiary; - - if (this.turtleGroup_) { - var child = this.turtleGroup_.firstChild; - while(child) { - // If it is a text node, continue. - if (child.nodeType === 3) { - child = child.nextSibling; - continue; - } - // Or if it is a non-turtle node, continue. - var className = child.getAttribute('class'); - if (!className || className.indexOf('turtleBody') === -1) { - child = child.nextSibling; - continue; - } - - child.style.fill = fillColour; - child.style.stroke = borderColour; - child = child.nextSibling; - } - } -}; - -// Saves the field's value to an XML node. Allows for custom serialization. -CustomFields.FieldTurtle.prototype.toXml = function(fieldElement) { - // The default implementation of this function creates a node that looks - // like this: (where value is returned by getValue()) - // value - // But this doesn't work for our field because it stores an /object/. - - fieldElement.setAttribute('pattern', this.value_.pattern); - fieldElement.setAttribute('hat', this.value_.hat); - // The textContent usually contains whatever is closest to the field's - // 'value'. The textContent doesn't need to contain anything, but saving - // something to it does aid in readability. - fieldElement.textContent = this.value_.turtleName; - - // Always return the element! - return fieldElement; -}; - -// Sets the field's value based on an XML node. Allows for custom -// de-serialization. -CustomFields.FieldTurtle.prototype.fromXml = function(fieldElement) { - // Because we had to do custom serialization for this field, we also need - // to do custom de-serialization. - - var value = {}; - value.pattern = fieldElement.getAttribute('pattern'); - value.hat = fieldElement.getAttribute('hat'); - value.turtleName = fieldElement.textContent; - // The end goal is to call this.setValue() - this.setValue(value); -}; - -// Blockly needs to know the JSON name of this field. Usually this is -// registered at the bottom of the field class. -Blockly.fieldRegistry.register('field_turtle', CustomFields.FieldTurtle); - -// Called by initView to create all of the SVGs. This is just used to keep -// the code more organized. -CustomFields.FieldTurtle.prototype.createView_ = function() { - this.movableGroup_ = Blockly.utils.dom.createSvgElement('g', - { - 'transform': 'translate(0,5)' - }, this.fieldGroup_); - var scaleGroup = Blockly.utils.dom.createSvgElement('g', - { - 'transform': 'scale(1.5)' - }, this.movableGroup_); - this.turtleGroup_ = Blockly.utils.dom.createSvgElement('g', - { - // Makes the smaller turtle graphic align with the hats. - 'class': 'turtleBody' - }, scaleGroup); - var tail = Blockly.utils.dom.createSvgElement('path', - { - 'class': 'turtleBody', - 'd': 'M7,27.5H0.188c3.959-2,6.547-2.708,8.776-5.237', - 'transform': 'translate(0.312 -12.994)' - }, this.turtleGroup_); - var legLeft = Blockly.utils.dom.createSvgElement('rect', - { - 'class': 'turtleBody', - 'x': 8.812, - 'y': 12.506, - 'width': 4, - 'height': 10 - }, this.turtleGroup_); - var legRight = Blockly.utils.dom.createSvgElement('rect', - { - 'class': 'turtleBody', - 'x': 28.812, - 'y': 12.506, - 'width': 4, - 'height': 10 - }, this.turtleGroup_); - var head = Blockly.utils.dom.createSvgElement('path', - { - 'class': 'turtleBody', - 'd': 'M47.991,17.884c0,1.92-2.144,3.477-4.788,3.477a6.262,6.262,0,0,1-2.212-.392c-0.2-.077-1.995,2.343-4.866,3.112a17.019,17.019,0,0,1-6.01.588c-4.413-.053-2.5-3.412-2.745-3.819-0.147-.242,2.232.144,6.126-0.376a7.392,7.392,0,0,0,4.919-2.588c0-1.92,2.144-3.477,4.788-3.477S47.991,15.964,47.991,17.884Z', - 'transform': 'translate(0.312 -12.994)' - }, this.turtleGroup_); - var smile = Blockly.utils.dom.createSvgElement('path', - { - 'class': 'turtleBody', - 'd': 'M42.223,18.668a3.614,3.614,0,0,0,2.728,2.38', - 'transform': 'translate(0.312 -12.994)' - }, this.turtleGroup_); - var sclera = Blockly.utils.dom.createSvgElement('ellipse', - { - 'cx': 43.435, - 'cy': 2.61, - 'rx': 2.247, - 'ry': 2.61, - 'fill': '#fff' - }, this.turtleGroup_); - var pupil = Blockly.utils.dom.createSvgElement('ellipse', - { - 'cx': 44.166, - 'cy': 3.403, - 'rx': 1.318, - 'ry': 1.62 - }, this.turtleGroup_); - var shell = Blockly.utils.dom.createSvgElement('path', - { - 'class': 'turtleBody', - 'd': 'M33.4,27.5H7.193c0-6,5.866-13.021,13.1-13.021S33.4,21.5,33.4,27.5Z', - 'transform': 'translate(0.312 -12.994)' - }, this.turtleGroup_); - this.shellPattern_ = Blockly.utils.dom.createSvgElement('path', - { - 'd': 'M33.4,27.5H7.193c0-6,5.866-13.021,13.1-13.021S33.4,21.5,33.4,27.5Z', - 'transform': 'translate(0.312 -12.994)' - }, this.turtleGroup_); - - this.stovepipe_ = Blockly.utils.dom.createSvgElement('image', - { - 'width': '50', - 'height': '18' - }, scaleGroup); - this.stovepipe_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - 'media/stovepipe.svg'); - this.crown_ = Blockly.utils.dom.createSvgElement('image', - { - 'width': '50', - 'height': '15' - }, scaleGroup); - this.crown_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - 'media/crown.svg'); - this.mask_ = Blockly.utils.dom.createSvgElement('image', - { - 'width': '50', - 'height': '24' - }, scaleGroup); - this.mask_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - 'media/mask.svg'); - this.propeller_ = Blockly.utils.dom.createSvgElement('image', - { - 'width': '50', - 'height': '11' - }, scaleGroup); - this.propeller_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - 'media/propeller.svg'); - this.fedora_ = Blockly.utils.dom.createSvgElement('image', - { - 'width': '50', - 'height': '12' - }, scaleGroup); - this.fedora_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - 'media/fedora.svg'); - - // Even if we're not going to display it right away, we want to create all - // of our DOM elements inside this function. - this.crown_.style.display = 'none'; - this.mask_.style.display = 'none'; - this.propeller_.style.display = 'none'; - this.fedora_.style.display = 'none'; - - this.movableGroup_.appendChild(this.textElement_); - this.textElement_.setAttribute( - 'transform', 'translate(' + this.TEXT_OFFSET_X + ',20)'); - - this.defs_ = Blockly.utils.dom.createSvgElement('defs', {}, this.fieldGroup_); - this.polkadotPattern_ = Blockly.utils.dom.createSvgElement('pattern', - { - 'id': 'polkadots', - 'patternUnits': 'userSpaceOnUse', - 'width': 10, - 'height': 10 - }, this.defs_); - this.polkadotGroup_ = Blockly.utils.dom.createSvgElement( - 'g', {}, this.polkadotPattern_); - Blockly.utils.dom.createSvgElement('circle', - { - 'cx': 2.5, - 'cy': 2.5, - 'r': 2.5, - 'fill': '#000', - 'fill-opacity': .3 - }, this.polkadotGroup_); - Blockly.utils.dom.createSvgElement('circle', - { - 'cx': 7.5, - 'cy': 7.5, - 'r': 2.5, - 'fill': '#000', - 'fill-opacity': .3 - }, this.polkadotGroup_); - - this.hexagonPattern_ = Blockly.utils.dom.createSvgElement('pattern', - { - 'id': 'hexagons', - 'patternUnits': 'userSpaceOnUse', - 'width': 10, - 'height': 8.68, - 'patternTransform': 'translate(2) rotate(45)' - }, this.defs_); - Blockly.utils.dom.createSvgElement('polygon', - { - 'id': 'hex', - 'points': '4.96,4.4 7.46,5.84 7.46,8.74 4.96,10.18 2.46,8.74 2.46,5.84', - 'stroke': '#000', - 'stroke-opacity': .3, - 'fill-opacity': 0 - }, this.hexagonPattern_); - var use = Blockly.utils.dom.createSvgElement('use', - { - 'x': 5, - }, this.hexagonPattern_); - use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex'); - use = Blockly.utils.dom.createSvgElement('use', - { - 'x': -5, - }, this.hexagonPattern_); - use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex'); - use = Blockly.utils.dom.createSvgElement('use', - { - 'x': 2.5, - 'y': -4.34 - }, this.hexagonPattern_); - use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex'); - use = Blockly.utils.dom.createSvgElement('use', - { - 'x': -2.5, - 'y': -4.34 - }, this.hexagonPattern_); - use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#hex'); - - this.stripesPattern_ = Blockly.utils.dom.createSvgElement('pattern', - { - 'id': 'stripes', - 'patternUnits': 'userSpaceOnUse', - 'width': 5, - 'height': 10, - 'patternTransform': 'rotate(45)' - }, this.defs_); - Blockly.utils.dom.createSvgElement('line', - { - 'x1': 0, - 'y1': 0, - 'x2': 0, - 'y2': 10, - 'stroke-width': 4, - 'stroke': '#000', - 'stroke-opacity': .3 - }, this.stripesPattern_); -}; diff --git a/demos/custom-fields/turtle/icon.png b/demos/custom-fields/turtle/icon.png deleted file mode 100644 index 3a7314ac9..000000000 Binary files a/demos/custom-fields/turtle/icon.png and /dev/null differ diff --git a/demos/custom-fields/turtle/index.html b/demos/custom-fields/turtle/index.html deleted file mode 100644 index dd8cb40af..000000000 --- a/demos/custom-fields/turtle/index.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - Blockly Demo: Custom Turtle Field - - - - - - - - -

- Blockly > - Demos > - Custom Fields > Turtle Field

- - -

This is a demo of creating custom block fields. In this case the field - is used to define a turtle. -

- -

All of the custom field implementation is in - demos/custom-fields/turtle/field_turtle.js, including comments on each required - function. -

- -

Click on the blocks' comment icons to learn what they are demonstrating. - Use the buttons below to see how the fields react to changes. -

- -

- - - - - -

- -

- - -

- - - - - - -
- - -
-
- - - - - - diff --git a/demos/custom-fields/turtle/media/crown.svg b/demos/custom-fields/turtle/media/crown.svg deleted file mode 100644 index 3eebccb92..000000000 --- a/demos/custom-fields/turtle/media/crown.svg +++ /dev/null @@ -1 +0,0 @@ -crown \ No newline at end of file diff --git a/demos/custom-fields/turtle/media/fedora.svg b/demos/custom-fields/turtle/media/fedora.svg deleted file mode 100644 index 4a354491b..000000000 --- a/demos/custom-fields/turtle/media/fedora.svg +++ /dev/null @@ -1 +0,0 @@ -fedora \ No newline at end of file diff --git a/demos/custom-fields/turtle/media/mask.svg b/demos/custom-fields/turtle/media/mask.svg deleted file mode 100644 index eb4fded1c..000000000 --- a/demos/custom-fields/turtle/media/mask.svg +++ /dev/null @@ -1 +0,0 @@ -mask \ No newline at end of file diff --git a/demos/custom-fields/turtle/media/propeller.svg b/demos/custom-fields/turtle/media/propeller.svg deleted file mode 100644 index bf0a433fd..000000000 --- a/demos/custom-fields/turtle/media/propeller.svg +++ /dev/null @@ -1 +0,0 @@ -propeller \ No newline at end of file diff --git a/demos/custom-fields/turtle/media/stovepipe.svg b/demos/custom-fields/turtle/media/stovepipe.svg deleted file mode 100644 index 6971ff7fd..000000000 --- a/demos/custom-fields/turtle/media/stovepipe.svg +++ /dev/null @@ -1 +0,0 @@ -stovepipe \ No newline at end of file diff --git a/demos/custom-fields/turtle/media/warning.svg b/demos/custom-fields/turtle/media/warning.svg deleted file mode 100644 index 11136c1ef..000000000 --- a/demos/custom-fields/turtle/media/warning.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/demos/custom-fields/turtle/turtle.css b/demos/custom-fields/turtle/turtle.css deleted file mode 100644 index ed5e9b307..000000000 --- a/demos/custom-fields/turtle/turtle.css +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -.customFieldsTurtleWidget { - width: 150px; -} - -.customFieldsTurtleWidget button { - border-radius: 4px; - border: none; - background-color: #fff; - opacity: .6; - color: #000; -} - -.customFieldsTurtleWidget .table { - width: 100%; -} - -.customFieldsTurtleWidget .row { - width: 100%; - display: flex; -} - -.customFieldsTurtleWidget .arrow { - text-align: center; - padding: 0; - flex-grow: 0; -} - -.customFieldsTurtleWidget .text { - height: 20px; - color: #fff; - flex-grow: 1; - text-align: center; -} - -.customFieldsTurtleWidget .randomize { - width: 100%; -} - -.blocklySvg .blocklyNonEditableText text, -.blocklySvg .blocklyEditableText text { - fill: #000; -} diff --git a/demos/fixed/icon.png b/demos/fixed/icon.png deleted file mode 100644 index 0a80ef9a3..000000000 Binary files a/demos/fixed/icon.png and /dev/null differ diff --git a/demos/fixed/index.html b/demos/fixed/index.html deleted file mode 100644 index 85d634608..000000000 --- a/demos/fixed/index.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Blockly Demo: Fixed Blockly - - - - - - -

Blockly > - Demos > Fixed Blockly

- -

This is a simple demo of injecting Blockly into a fixed-sized 'div' element.

- -

→ More info on injecting fixed-sized Blockly

- -
- - - - - - - diff --git a/demos/generator/icon.png b/demos/generator/icon.png deleted file mode 100644 index c1a84f034..000000000 Binary files a/demos/generator/icon.png and /dev/null differ diff --git a/demos/generator/index.html b/demos/generator/index.html deleted file mode 100644 index 127a128d8..000000000 --- a/demos/generator/index.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Blockly Demo: Generating JavaScript - - - - - - - -

Blockly > - Demos > Generating JavaScript

- -

This is a simple demo of generating code from blocks and running - the code in a sandboxed JavaScript interpreter.

- -

→ More info on Code Generators and Running JavaScript.

- -

- - -

- -
- - - - - - - - - diff --git a/demos/graph/icon.png b/demos/graph/icon.png deleted file mode 100644 index 7828463de..000000000 Binary files a/demos/graph/icon.png and /dev/null differ diff --git a/demos/graph/index.html b/demos/graph/index.html deleted file mode 100644 index 766665233..000000000 --- a/demos/graph/index.html +++ /dev/null @@ -1,364 +0,0 @@ - - - - - Blockly Demo: Graph - - - - - - - - -

Blockly > - Demos > Graph

- -

This is a demo of giving instant feedback as blocks are changed.

- -

→ More info on Realtime generation

- - - - - - -
-
-
-
-
- -
- - ... -
- - - - - - - - - diff --git a/demos/index.html b/demos/index.html index 28d6e2f1d..578874151 100644 --- a/demos/index.html +++ b/demos/index.html @@ -28,18 +28,6 @@ their own applications.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
Fixed Blockly
-
Inject Blockly into a page as a fixed element.
-
@@ -64,30 +52,6 @@
- - - - -
Maximum Block Limit
-
Limit the total number of blocks allowed (for academic exercises).
-
- - - - -
Generate JavaScript
-
Turn blocks into code and execute it.
-
@@ -100,31 +64,6 @@
- - - - -
JS Interpreter
-
Demo #1: Step by step execution in JavaScript.
-
Demo #2: Asynchronous execution in JavaScript.
-
- - - - -
Graph
-
Instant updates when blocks are changed.
-
@@ -137,30 +76,6 @@
- - - - -
Custom Dialogs
-
Override Blockly browser dialogs with custom implementations.
-
- - - - -
Custom Fields
-
Implement a custom field.
-
diff --git a/demos/interpreter/acorn_interpreter.js b/demos/interpreter/acorn_interpreter.js deleted file mode 100644 index 19db1c3ef..000000000 --- a/demos/interpreter/acorn_interpreter.js +++ /dev/null @@ -1,143 +0,0 @@ -// Acorn: Copyright 2012 Marijn Haverbeke, MIT License -var mod$$inline_58=function(a){function b(a){n=a||{};for(var b in Ua)Object.prototype.hasOwnProperty.call(n,b)||(n[b]=Ua[b]);wa=n.sourceFile||null}function c(a,b){var c=Ab(k,a);b+=" ("+c.line+":"+c.column+")";var d=new SyntaxError(b);d.pos=a;d.loc=c;d.raisedAt=f;throw d;}function d(a){function b(a){if(1==a.length)return c+="return str === "+JSON.stringify(a[0])+";";c+="switch(str){";for(var va=0;vaa)++f;else if(47===a)if(a=k.charCodeAt(f+1),42===a){var a=n.onComment&&n.locations&&new e,b=f,d=k.indexOf("*/",f+=2);-1===d&&c(f-2,"Unterminated comment"); -f=d+2;if(n.locations){Y.lastIndex=b;for(var g=void 0;(g=Y.exec(k))&&g.index=a?a=P(!0):(++f,a=g(xa)),a;case 40:return++f,g(I);case 41:return++f,g(E);case 59:return++f,g(J);case 44:return++f,g(L);case 91:return++f,g(ja); -case 93:return++f,g(ka);case 123:return++f,g(Z);case 125:return++f,g(T);case 58:return++f,g(aa);case 63:return++f,g(ya);case 48:if(a=k.charCodeAt(f+1),120===a||88===a)return f+=2,a=B(16),null==a&&c(x+2,"Expected hexadecimal number"),la(k.charCodeAt(f))&&c(f,"Identifier directly after number"),a=g(ba,a);case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return P(!1);case 34:case 39:a:{f++;for(var b="";;){f>=S&&c(x,"Unterminated string constant");var d=k.charCodeAt(f);if(d===a){++f; -a=g(da,b);break a}if(92===d){var d=k.charCodeAt(++f),e=/^[0-7]+/.exec(k.slice(f,f+3));for(e&&(e=e[0]);e&&255=S)return g(pa);var b=k.charCodeAt(f);if(la(b)||92===b)return Ya();a=m(b);if(!1===a){b=String.fromCharCode(b);if("\\"===b||Za.test(b))return Ya();c(f,"Unexpected character '"+b+"'")}return a}function t(a,b){var c=k.slice(f,f+b);f+=b;g(a,c)}function K(){for(var a,b,d=f;;){f>=S&&c(d, -"Unterminated regular expression");var e=k.charAt(f);na.test(e)&&c(d,"Unterminated regular expression");if(a)a=!1;else{if("["===e)b=!0;else if("]"===e&&b)b=!1;else if("/"===e&&!b)break;a="\\"===e}++f}a=k.slice(d,f);++f;(b=$a())&&!/^[gmsiy]*$/.test(b)&&c(d,"Invalid regexp flag");return g(Ba,new RegExp(a,b))}function B(a,b){for(var c=f,d=0,e=0,g=null==b?Infinity:b;e=h?h-48:Infinity;if(h>=a)break;++f;d=d*a+h}return f===c||null!=b&& -f-c!==b?null:d}function P(a){var b=f,d=!1,e=48===k.charCodeAt(f);a||null!==B(10)||c(b,"Invalid number");46===k.charCodeAt(f)&&(++f,B(10),d=!0);a=k.charCodeAt(f);if(69===a||101===a)a=k.charCodeAt(++f),43!==a&&45!==a||++f,null===B(10)&&c(b,"Invalid number"),d=!0;la(k.charCodeAt(f))&&c(f,"Identifier directly after number");a=k.slice(b,f);var h;d?h=parseFloat(a):e&&1!==a.length?/[89]/.test(a)||C?c(b,"Invalid number"):h=parseInt(a,8):h=parseInt(a,10);return g(ba,h)}function ma(a){a=B(16,a);null===a&&c(x, -"Bad character escape sequence");return a}function $a(){ca=!1;for(var a,b=!0,d=f;;){var e=k.charCodeAt(f);if(ab(e))ca&&(a+=k.charAt(f)),++f;else if(92===e){ca||(a=k.slice(d,f));ca=!0;117!=k.charCodeAt(++f)&&c(f,"Expecting Unicode escape sequence \\uXXXX");++f;var e=ma(4),g=String.fromCharCode(e);g||c(f-1,"Invalid Unicode escape");(b?la(e):ab(e))||c(f-4,"Invalid Unicode escape");a+=g}else break;b=!1}return ca?a:k.slice(d,f)}function Ya(){var a=$a(),b=V;ca||(Lb(a)?b=Ca[a]:(n.forbidReserved&&(3===n.ecmaVersion? -Mb:Nb)(a)||C&&bb(a))&&c(x,"The keyword '"+a+"' is reserved"));return g(b,a)}function r(){Da=x;M=X;Ea=ia;z()}function Fa(a){C=a;f=M;if(n.locations)for(;fb){var e=Q(a);e.left=a;e.operator=H;a=p;r();e.right=Ra(Sa(),d,c);d=q(e,a===Va||a===Wa?"LogicalExpression":"BinaryExpression");return Ra(d,b,c)}return a}function Sa(){if(p.prefix){var a=y(),b=p.isUpdate;a.operator=H;R=a.prefix=!0;r();a.argument= -Sa();b?ra(a.argument):C&&"delete"===a.operator&&"Identifier"===a.argument.type&&c(a.start,"Deleting local variable in strict mode");return q(a,b?"UpdateExpression":"UnaryExpression")}for(b=ha(ua());p.postfix&&!qa();)a=Q(b),a.operator=H,a.prefix=!1,a.argument=b,ra(b),r(),b=q(a,"UpdateExpression");return b}function ha(a,b){if(u(xa)){var c=Q(a);c.object=a;c.property=O(!0);c.computed=!1;return ha(q(c,"MemberExpression"),b)}return u(ja)?(c=Q(a),c.object=a,c.property=A(),c.computed=!0,v(ka),ha(q(c,"MemberExpression"), -b)):!b&&u(I)?(c=Q(a),c.callee=a,c.arguments=Ta(E,!1),ha(q(c,"CallExpression"),b)):a}function ua(){switch(p){case ub:var a=y();r();return q(a,"ThisExpression");case V:return O();case ba:case da:case Ba:return a=y(),a.value=H,a.raw=k.slice(x,X),r(),q(a,"Literal");case vb:case wb:case xb:return a=y(),a.value=p.atomValue,a.raw=p.keyword,r(),q(a,"Literal");case I:var a=oa,b=x;r();var d=A();d.start=b;d.end=X;n.locations&&(d.loc.start=a,d.loc.end=ia);n.ranges&&(d.range=[b,X]);v(E);return d;case ja:return a= -y(),r(),a.elements=Ta(ka,!0,!0),q(a,"ArrayExpression");case Z:a=y();b=!0;d=!1;a.properties=[];for(r();!u(T);){if(b)b=!1;else if(v(L),n.allowTrailingCommas&&u(T))break;var e={key:p===ba||p===da?ua():O(!0)},g=!1,h;u(aa)?(e.value=A(!0),h=e.kind="init"):5<=n.ecmaVersion&&"Identifier"===e.key.type&&("get"===e.key.name||"set"===e.key.name)?(g=d=!0,h=e.kind=e.key.name,e.key=p===ba||p===da?ua():O(!0),p!==I&&N(),e.value=Na(y(),!1)):N();if("Identifier"===e.key.type&&(C||d))for(var f=0;fd?a.id:a.params[d],(bb(e.name)||sa(e.name))&&c(e.start,"Defining '"+e.name+"' in strict mode"),0<=d)for(var g=0;ga?36===a:91>a?!0:97>a?95===a:123>a?!0:170<=a&&Za.test(String.fromCharCode(a))},ab=a.isIdentifierChar=function(a){return 48>a?36===a:58>a?!0:65>a?!1:91>a?!0:97>a?95===a:123>a?!0:170<=a&&Pb.test(String.fromCharCode(a))},ca,Ia={kind:"loop"},Ob={kind:"switch"}}; -"object"==typeof exports&&"object"==typeof module?mod$$inline_58(exports):"function"==typeof define&&define.amd?define(["exports"],mod$$inline_58):mod$$inline_58(this.acorn||(this.acorn={})); -// JS-Interpreter: Copyright 2013 Google LLC, Apache 2.0 -function u(a,b){"string"===typeof a&&(a=acorn.parse(a,ha));this.Ha=a.constructor;var c=new this.Ha({options:{}});for(d in a)c[d]="body"===d?a[d].slice():a[d];this.fa=c;this.kb=b;this.wa=!1;this.U=[];this.Sa=0;this.pb=Object.create(null);var d=/^step([A-Z]\w*)$/;var e,g;for(g in this)"function"===typeof this[g]&&(e=g.match(d))&&(this.pb[e[1]]=this[g].bind(this));this.M=ia(this,this.fa,null);this.Da=this.M.object;this.fa=acorn.parse(this.U.join("\n"),ha);this.U=void 0;ra(this.fa,void 0,void 0);e=new v(this.fa, -this.M);e.done=!1;this.j=[e];this.nb();this.value=void 0;this.fa=c;e=new v(this.fa,this.M);e.done=!1;this.j.length=0;this.j[0]=e;this.stateStack=this.j} -var ha={Ca:5},ya={configurable:!0,enumerable:!0,writable:!1},B={configurable:!0,enumerable:!1,writable:!0},E={configurable:!0,enumerable:!1,writable:!1},za={configurable:!1,enumerable:!0,writable:!0},Aa={STEP_ERROR:!0},Ba={SCOPE_REFERENCE:!0},Ia={VALUE_IN_DESCRIPTOR:!0},Ja={REGEXP_TIMEOUT:!0},Ka=[],La=null,Ma=["onmessage = function(e) {","var result;","var data = e.data;","switch (data[0]) {","case 'split':","result = data[1].split(data[2], data[3]);","break;","case 'match':","result = data[1].match(data[2]);", -"break;","case 'search':","result = data[1].search(data[2]);","break;","case 'replace':","result = data[1].replace(data[2], data[3]);","break;","case 'exec':","var regexp = data[1];","regexp.lastIndex = data[2];","result = [regexp.exec(data[3]), data[1].lastIndex];","break;","default:","throw 'Unknown RegExp operation: ' + data[0];","}","postMessage(result);","};"];function Na(a){var b=a>>>0;return b===Number(a)?b:NaN}function Oa(a){var b=a>>>0;return String(b)===String(a)&&4294967295!==b?b:NaN} -function ra(a,b,c){b?a.start=b:delete a.start;c?a.end=c:delete a.end;for(var d in a)if(a.hasOwnProperty(d)){var e=a[d];e&&"object"===typeof e&&ra(e,b,c)}}u.prototype.REGEXP_MODE=2;u.prototype.REGEXP_THREAD_TIMEOUT=1E3;q=u.prototype;q.I=!1;q.ya=!1; -q.ub=function(a){var b=this.j[0];if(!b||"Program"!==b.node.type)throw Error("Expecting original AST to start with a Program node.");"string"===typeof a&&(a=acorn.parse(a,ha));if(!a||"Program"!==a.type)throw Error("Expecting new AST to start with a Program node.");Pa(this,a,b.scope);Array.prototype.push.apply(b.node.body,a.body);b.done=!1}; -q.step=function(){var a=this.j;do{var b=a[a.length-1];if(!b)return!1;var c=b.node,d=c.type;if("Program"===d&&b.done)return!1;if(this.wa)break;try{var e=this.pb[d](a,b,c)}catch(g){if(g!==Aa)throw g;}e&&a.push(e);if(this.I)throw Error("Getter not supported in this context");if(this.ya)throw Error("Setter not supported in this context");}while(!c.end);return!0};q.nb=function(){for(;!this.wa&&this.step(););return this.wa}; -function Qa(a,b){a.setProperty(b,"NaN",NaN,ya);a.setProperty(b,"Infinity",Infinity,ya);a.setProperty(b,"undefined",void 0,ya);a.setProperty(b,"window",b,ya);a.setProperty(b,"this",b,ya);a.setProperty(b,"self",b);a.B=new F(null);a.W=new F(a.B);db(a,b);eb(a,b);b.la=a.B;a.setProperty(b,"constructor",a.m,B);Fb(a,b);Gb(a,b);Hb(a,b);Ib(a,b);Jb(a,b);Kb(a,b);Lb(a,b);Mb(a,b);Nb(a,b);var c=a.b(function(){throw EvalError("Can't happen");},!1);c.eval=!0;a.setProperty(b,"eval",c);a.setProperty(b,"parseInt",a.b(parseInt, -!1));a.setProperty(b,"parseFloat",a.b(parseFloat,!1));a.setProperty(b,"isNaN",a.b(isNaN,!1));a.setProperty(b,"isFinite",a.b(isFinite,!1));c=[[escape,"escape"],[unescape,"unescape"],[decodeURI,"decodeURI"],[decodeURIComponent,"decodeURIComponent"],[encodeURI,"encodeURI"],[encodeURIComponent,"encodeURIComponent"]];for(var d=0;d>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;", -"while (k < len) {","if (k in O && !callbackfn.call(T, O[k], k, O)) return false;","k++;","}","return true;","}","});","Object.defineProperty(Array.prototype, 'filter',","{configurable: true, writable: true, value:","function(fun/*, thisArg*/) {","if (this === void 0 || this === null || typeof fun !== 'function') throw TypeError();","var t = Object(this);","var len = t.length >>> 0;","var res = [];","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;","for (var i = 0; i < len; i++) {","if (i in t) {", -"var val = t[i];","if (fun.call(thisArg, val, i, t)) res.push(val);","}","}","return res;","}","});","Object.defineProperty(Array.prototype, 'forEach',","{configurable: true, writable: true, value:","function(callback, thisArg) {","if (!this || typeof callback !== 'function') throw TypeError();","var T, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O) callback.call(T, O[k], k, O);","k++;","}","}","});","Object.defineProperty(Array.prototype, 'map',", -"{configurable: true, writable: true, value:","function(callback, thisArg) {","if (!this || typeof callback !== 'function') new TypeError;","var T, A, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","A = new Array(len);","k = 0;","while (k < len) {","if (k in O) A[k] = callback.call(T, O[k], k, O);","k++;","}","return A;","}","});","Object.defineProperty(Array.prototype, 'reduce',","{configurable: true, writable: true, value:","function(callback /*, initialValue*/) {", -"if (!this || typeof callback !== 'function') throw TypeError();","var t = Object(this), len = t.length >>> 0, k = 0, value;","if (arguments.length === 2) {","value = arguments[1];","} else {","while (k < len && !(k in t)) k++;","if (k >= len) {","throw TypeError('Reduce of empty array with no initial value');","}","value = t[k++];","}","for (; k < len; k++) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'reduceRight',", -"{configurable: true, writable: true, value:","function(callback /*, initialValue*/) {","if (null === this || 'undefined' === typeof this || 'function' !== typeof callback) throw TypeError();","var t = Object(this), len = t.length >>> 0, k = len - 1, value;","if (arguments.length >= 2) {","value = arguments[1];","} else {","while (k >= 0 && !(k in t)) k--;","if (k < 0) {","throw TypeError('Reduce of empty array with no initial value');","}","value = t[k--];","}","for (; k >= 0; k--) {","if (k in t) value = callback(value, t[k], k, t);", -"}","return value;","}","});","Object.defineProperty(Array.prototype, 'some',","{configurable: true, writable: true, value:","function(fun/*, thisArg*/) {","if (!this || typeof fun !== 'function') throw TypeError();","var t = Object(this);","var len = t.length >>> 0;","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;","for (var i = 0; i < len; i++) {","if (i in t && fun.call(thisArg, t[i], i, t)) {","return true;","}","}","return false;","}","});","(function() {","var sort_ = Array.prototype.sort;", -"Array.prototype.sort = function(opt_comp) {","if (typeof opt_comp !== 'function') {","return sort_.call(this);","}","for (var i = 0; i < this.length; i++) {","var changes = 0;","for (var j = 0; j < this.length - i - 1; j++) {","if (opt_comp(this[j], this[j + 1]) > 0) {","var swap = this[j];","this[j] = this[j + 1];","this[j + 1] = swap;","changes++;","}","}","if (!changes) break;","}","return this;","};","})();","Object.defineProperty(Array.prototype, 'toLocaleString',","{configurable: true, writable: true, value:", -"function() {","var out = [];","for (var i = 0; i < this.length; i++) {","out[i] = (this[i] === null || this[i] === undefined) ? '' : this[i].toLocaleString();","}","return out.join(',');","}","});","")} -function Gb(a,b){var c=function(e){e=arguments.length?String(e):"";return zc(a)?(this.data=e,this):e};a.w=a.b(c,!0);a.setProperty(b,"String",a.w);a.setProperty(a.w,"fromCharCode",a.b(String.fromCharCode,!1),B);c="charAt charCodeAt concat indexOf lastIndexOf slice substr substring toLocaleLowerCase toLocaleUpperCase toLowerCase toUpperCase trim".split(" ");for(var d=0;d= 0; i--) {","str = str.substring(0, subs[i][0]) + subs[i][2] + str.substring(subs[i][0] + subs[i][1]);", -"}","} else {","var i = str.indexOf(substr);","if (i !== -1) {","var inject = newSubstr(str.substr(i, substr.length), i, str);","str = str.substring(0, i) + inject + str.substring(i + substr.length);","}","}","return str;","};","})();","")}function Hb(a,b){a.Ya=a.b(function(c){c=!!c;return zc(a)?(this.data=c,this):c},!0);a.setProperty(b,"Boolean",a.Ya)} -function Ib(a,b){var c=function(e){e=arguments.length?Number(e):0;return zc(a)?(this.data=e,this):e};a.S=a.b(c,!0);a.setProperty(b,"Number",a.S);c=["MAX_VALUE","MIN_VALUE","NaN","NEGATIVE_INFINITY","POSITIVE_INFINITY"];for(var d=0;db.charCodeAt(0)&&U(this,a,this.w)){var c=Oa(b);if(!isNaN(c)&&c>=":d>>=e;break;case ">>>=":d>>>=e;break;case "&=":d&=e;break;case "^=":d^=e;break;case "|=":d|=e;break;default:throw SyntaxError("Unknown assignment expression: "+c.operator);}if(c=cd(this,b.ra,d))return b.ia=!0,b.Wa=d,fd(this,c,b.ra,d);a.pop();a[a.length-1].value=d}}; -u.prototype.stepBinaryExpression=function(a,b,c){if(!b.Y)return b.Y=!0,new v(c.left,b.scope);if(!b.pa)return b.pa=!0,b.$=b.value,new v(c.right,b.scope);a.pop();var d=b.$;b=b.value;switch(c.operator){case "==":c=d==b;break;case "!=":c=d!=b;break;case "===":c=d===b;break;case "!==":c=d!==b;break;case ">":c=d>b;break;case ">=":c=d>=b;break;case "<":c=d>":c=d>>b;break;case ">>>":c=d>>>b;break;case "in":b instanceof F||I(this,this.g,"'in' expects an object, not '"+b+"'");c=Bc(this,b,d);break;case "instanceof":U(this,b,this.H)||I(this,this.g,"Right-hand side of instanceof is not an object");c=d instanceof F?U(this,d,b):!1;break;default:throw SyntaxError("Unknown binary operator: "+c.operator);}a[a.length-1].value=c}; -u.prototype.stepBlockStatement=function(a,b,c){var d=b.o||0;if(c=c.body[d])return b.o=d+1,new v(c,b.scope);a.pop()};u.prototype.stepBreakStatement=function(a,b,c){dd(this,1,void 0,c.label&&c.label.name)}; -u.prototype.stepCallExpression=function(a,b,c){if(!b.ha){b.ha=1;var d=new v(c.callee,b.scope);d.ga=!0;return d}if(1===b.ha){b.ha=2;d=b.value;if(Array.isArray(d)){if(b.Z=bd(this,d),d[0]===Ba?b.yb="eval"===d[1]:b.G=d[0],d=b.Z,this.I)return b.ha=1,ed(this,d,b.value)}else b.Z=d;b.A=[];b.o=0}d=b.Z;if(!b.Qa){0!==b.o&&b.A.push(b.value);if(c.arguments[b.o])return new v(c.arguments[b.o++],b.scope);if("NewExpression"===c.type){d.Hb&&I(this,this.g,d+" is not a constructor");if(d===this.l)b.G=Ac(this);else{var e= -d.a.prototype;if("object"!==typeof e||null===e)e=this.B;b.G=this.h(e)}b.isConstructor=!0}else void 0===b.G&&(b.G=b.scope.P?void 0:this.Da);b.Qa=!0}if(b.Ra)a.pop(),a[a.length-1].value=b.isConstructor&&"object"!==typeof b.value?b.G:b.value;else{b.Ra=!0;d instanceof F||I(this,this.g,d+" is not a function");if(a=d.node){c=ia(this,a.body,d.va);for(var g=0;gg?b.A[g]:void 0);e=Ac(this);for(g=0;g - - - - Blockly Demo: Asynchronous Execution with JS Interpreter - - - - - - - - - -

Blockly > - Demos > Asynchronous Execution with JS Interpreter

- -

This is a demo of executing code asynchronously (e.g., waiting for delays or user input) using the JavaScript interpreter.

- -

More info on running code with JS Interpreter

- -

- -

- -
-
- -
- - - - - - - - diff --git a/demos/interpreter/icon.png b/demos/interpreter/icon.png deleted file mode 100644 index b70d1b035..000000000 Binary files a/demos/interpreter/icon.png and /dev/null differ diff --git a/demos/interpreter/index.html b/demos/interpreter/index.html deleted file mode 100644 index 52e49eee4..000000000 --- a/demos/interpreter/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Redirecting... - - - -Redirecting to step execution JS-Interpreter demo. - - diff --git a/demos/interpreter/step-execution.html b/demos/interpreter/step-execution.html deleted file mode 100644 index 03e62aed6..000000000 --- a/demos/interpreter/step-execution.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - - Blockly Demo: Step Execution with JS Interpreter - - - - - - - - -

Blockly > - Demos > Step Execution with JS Interpreter

- -

This is a demo of executing code step-by-step with a sandboxed JavaScript interpreter.

- -

The generator's Blockly.JavaScript.STATEMENT_PREFIX is assigned 'highlightBlock(%1);\n', - where %1 is the block id. The call to highlightBlock() will highlight the identified block - and set the variable highlightPause to true.

- -

"Parse JavaScript" will generate the code and load it into the interpreter. Then, each press of the - "Step JavaScript" button will run the interpreter one step until the highlightPause is true. - That is, until highlightBlock() has highlighted the block that will be executed on the next step.

- -

More info on running code with JS Interpreter

- -

- -

- -
-
- -
- - - - - - - - diff --git a/demos/interpreter/wait_block.js b/demos/interpreter/wait_block.js deleted file mode 100644 index 10a57b482..000000000 --- a/demos/interpreter/wait_block.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Example "wait" block that will pause the interpreter for a - * number of seconds. Because wait is a blocking behavior, such blocks will - * only work in interpreted environments. - * - * See https://neil.fraser.name/software/JS-Interpreter/docs.html - */ -Blockly.defineBlocksWithJsonArray([{ - "type": "wait_seconds", - "message0": " wait %1 seconds", - "args0": [{ - "type": "field_number", - "name": "SECONDS", - "min": 0, - "max": 600, - "value": 1 - }], - "previousStatement": null, - "nextStatement": null, - "colour": "%{BKY_LOOPS_HUE}" -}]); - -/** - * Generator for wait block creates call to new method - * waitForSeconds(). - */ -Blockly.JavaScript['wait_seconds'] = function(block) { - var seconds = Number(block.getFieldValue('SECONDS')); - var code = 'waitForSeconds(' + seconds + ');\n'; - return code; -}; - -/** - * Register the interpreter asynchronous function - * waitForSeconds(). - */ -function initInterpreterWaitForSeconds(interpreter, globalObject) { - // Ensure function name does not conflict with variable names. - Blockly.JavaScript.addReservedWords('waitForSeconds'); - - var wrapper = interpreter.createAsyncFunction( - function(timeInSeconds, callback) { - // Delay the call to the callback. - setTimeout(callback, timeInSeconds * 1000); - }); - interpreter.setProperty(globalObject, 'waitForSeconds', wrapper); -} diff --git a/demos/maxBlocks/icon.png b/demos/maxBlocks/icon.png deleted file mode 100644 index b90c79615..000000000 Binary files a/demos/maxBlocks/icon.png and /dev/null differ diff --git a/demos/maxBlocks/index.html b/demos/maxBlocks/index.html deleted file mode 100644 index dc94f2f45..000000000 --- a/demos/maxBlocks/index.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - Blockly Demo: Maximum Block Limit - - - - - - -

Blockly > - Demos > Maximum Block Limit

- -

This is a demo of Blockly which has been restricted to a maximum of - five blocks.

- -

You have block(s) left.

- -
- - - - - - -