123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850 |
- /**
- * Blockly Demos: Block Factory
- *
- * Copyright 2012 Google Inc.
- * https://developers.google.com/blockly/
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @fileoverview JavaScript for Blockly's Block Factory application.
- * @author fraser@google.com (Neil Fraser)
- */
- 'use strict';
- /**
- * Workspace for user to build block.
- * @type {Blockly.Workspace}
- */
- var mainWorkspace = null;
- /**
- * Workspace for preview of block.
- * @type {Blockly.Workspace}
- */
- var previewWorkspace = null;
- /**
- * Name of block if not named.
- */
- var UNNAMED = 'unnamed';
- /**
- * Change the language code format.
- */
- function formatChange() {
- var mask = document.getElementById('blocklyMask');
- var languagePre = document.getElementById('languagePre');
- var languageTA = document.getElementById('languageTA');
- if (document.getElementById('format').value == 'Manual') {
- Blockly.hideChaff();
- mask.style.display = 'block';
- languagePre.style.display = 'none';
- languageTA.style.display = 'block';
- var code = languagePre.textContent.trim();
- languageTA.value = code;
- languageTA.focus();
- updatePreview();
- } else {
- mask.style.display = 'none';
- languageTA.style.display = 'none';
- languagePre.style.display = 'block';
- updateLanguage();
- }
- disableEnableLink();
- }
- /**
- * Update the language code based on constructs made in Blockly.
- */
- function updateLanguage() {
- var rootBlock = getRootBlock();
- if (!rootBlock) {
- return;
- }
- var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase();
- if (!blockType) {
- blockType = UNNAMED;
- }
- blockType = blockType.replace(/\W/g, '_').replace(/^(\d)/, '_\\1');
- switch (document.getElementById('format').value) {
- case 'JSON':
- var code = formatJson_(blockType, rootBlock);
- break;
- case 'JavaScript':
- var code = formatJavaScript_(blockType, rootBlock);
- break;
- }
- injectCode(code, 'languagePre');
- updatePreview();
- }
- /**
- * Update the language code as JSON.
- * @param {string} blockType Name of block.
- * @param {!Blockly.Block} rootBlock Factory_base block.
- * @return {string} Generanted language code.
- * @private
- */
- function formatJson_(blockType, rootBlock) {
- var JS = {};
- // Type is not used by Blockly, but may be used by a loader.
- JS.type = blockType;
- // Generate inputs.
- var message = [];
- var args = [];
- var contentsBlock = rootBlock.getInputTargetBlock('INPUTS');
- var lastInput = null;
- while (contentsBlock) {
- if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) {
- var fields = getFieldsJson_(contentsBlock.getInputTargetBlock('FIELDS'));
- for (var i = 0; i < fields.length; i++) {
- if (typeof fields[i] == 'string') {
- message.push(fields[i].replace(/%/g, '%%'));
- } else {
- args.push(fields[i]);
- message.push('%' + args.length);
- }
- }
- var input = {type: contentsBlock.type};
- // Dummy inputs don't have names. Other inputs do.
- if (contentsBlock.type != 'input_dummy') {
- input.name = contentsBlock.getFieldValue('INPUTNAME');
- }
- var check = JSON.parse(getOptTypesFrom(contentsBlock, 'TYPE') || 'null');
- if (check) {
- input.check = check;
- }
- var align = contentsBlock.getFieldValue('ALIGN');
- if (align != 'LEFT') {
- input.align = align;
- }
- args.push(input);
- message.push('%' + args.length);
- lastInput = contentsBlock;
- }
- contentsBlock = contentsBlock.nextConnection &&
- contentsBlock.nextConnection.targetBlock();
- }
- // Remove last input if dummy and not empty.
- if (lastInput && lastInput.type == 'input_dummy') {
- var fields = lastInput.getInputTargetBlock('FIELDS');
- if (fields && getFieldsJson_(fields).join('').trim() != '') {
- var align = lastInput.getFieldValue('ALIGN');
- if (align != 'LEFT') {
- JS.lastDummyAlign0 = align;
- }
- args.pop();
- message.pop();
- }
- }
- JS.message0 = message.join(' ');
- if (args.length) {
- JS.args0 = args;
- }
- // Generate inline/external switch.
- if (rootBlock.getFieldValue('INLINE') == 'EXT') {
- JS.inputsInline = false;
- } else if (rootBlock.getFieldValue('INLINE') == 'INT') {
- JS.inputsInline = true;
- }
- // Generate output, or next/previous connections.
- switch (rootBlock.getFieldValue('CONNECTIONS')) {
- case 'LEFT':
- JS.output =
- JSON.parse(getOptTypesFrom(rootBlock, 'OUTPUTTYPE') || 'null');
- break;
- case 'BOTH':
- JS.previousStatement =
- JSON.parse(getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null');
- JS.nextStatement =
- JSON.parse(getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null');
- break;
- case 'TOP':
- JS.previousStatement =
- JSON.parse(getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null');
- break;
- case 'BOTTOM':
- JS.nextStatement =
- JSON.parse(getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null');
- break;
- }
- // Generate colour.
- var colourBlock = rootBlock.getInputTargetBlock('COLOUR');
- if (colourBlock && !colourBlock.disabled) {
- var hue = parseInt(colourBlock.getFieldValue('HUE'), 10);
- JS.colour = hue;
- }
- JS.tooltip = '';
- JS.helpUrl = 'http://www.example.com/';
- return JSON.stringify(JS, null, ' ');
- }
- /**
- * Update the language code as JavaScript.
- * @param {string} blockType Name of block.
- * @param {!Blockly.Block} rootBlock Factory_base block.
- * @return {string} Generanted language code.
- * @private
- */
- function formatJavaScript_(blockType, rootBlock) {
- var code = [];
- code.push("Blockly.Blocks['" + blockType + "'] = {");
- code.push(" init: function() {");
- // Generate inputs.
- var TYPES = {'input_value': 'appendValueInput',
- 'input_statement': 'appendStatementInput',
- 'input_dummy': 'appendDummyInput'};
- var contentsBlock = rootBlock.getInputTargetBlock('INPUTS');
- while (contentsBlock) {
- if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) {
- var name = '';
- // Dummy inputs don't have names. Other inputs do.
- if (contentsBlock.type != 'input_dummy') {
- name = escapeString(contentsBlock.getFieldValue('INPUTNAME'));
- }
- code.push(' this.' + TYPES[contentsBlock.type] + '(' + name + ')');
- var check = getOptTypesFrom(contentsBlock, 'TYPE');
- if (check) {
- code.push(' .setCheck(' + check + ')');
- }
- var align = contentsBlock.getFieldValue('ALIGN');
- if (align != 'LEFT') {
- code.push(' .setAlign(Blockly.ALIGN_' + align + ')');
- }
- var fields = getFieldsJs_(contentsBlock.getInputTargetBlock('FIELDS'));
- for (var i = 0; i < fields.length; i++) {
- code.push(' .appendField(' + fields[i] + ')');
- }
- // Add semicolon to last line to finish the statement.
- code[code.length - 1] += ';';
- }
- contentsBlock = contentsBlock.nextConnection &&
- contentsBlock.nextConnection.targetBlock();
- }
- // Generate inline/external switch.
- if (rootBlock.getFieldValue('INLINE') == 'EXT') {
- code.push(' this.setInputsInline(false);');
- } else if (rootBlock.getFieldValue('INLINE') == 'INT') {
- code.push(' this.setInputsInline(true);');
- }
- // Generate output, or next/previous connections.
- switch (rootBlock.getFieldValue('CONNECTIONS')) {
- case 'LEFT':
- code.push(connectionLineJs_('setOutput', 'OUTPUTTYPE'));
- break;
- case 'BOTH':
- code.push(connectionLineJs_('setPreviousStatement', 'TOPTYPE'));
- code.push(connectionLineJs_('setNextStatement', 'BOTTOMTYPE'));
- break;
- case 'TOP':
- code.push(connectionLineJs_('setPreviousStatement', 'TOPTYPE'));
- break;
- case 'BOTTOM':
- code.push(connectionLineJs_('setNextStatement', 'BOTTOMTYPE'));
- break;
- }
- // Generate colour.
- var colourBlock = rootBlock.getInputTargetBlock('COLOUR');
- if (colourBlock && !colourBlock.disabled) {
- var hue = parseInt(colourBlock.getFieldValue('HUE'), 10);
- if (!isNaN(hue)) {
- code.push(' this.setColour(' + hue + ');');
- }
- }
- code.push(" this.setTooltip('');");
- code.push(" this.setHelpUrl('http://www.example.com/');");
- code.push(' }');
- code.push('};');
- return code.join('\n');
- }
- /**
- * Create JS code required to create a top, bottom, or value connection.
- * @param {string} functionName JavaScript function name.
- * @param {string} typeName Name of type input.
- * @return {string} Line of JavaScript code to create connection.
- * @private
- */
- function connectionLineJs_(functionName, typeName) {
- var type = getOptTypesFrom(getRootBlock(), typeName);
- if (type) {
- type = ', ' + type;
- } else {
- type = '';
- }
- return ' this.' + functionName + '(true' + type + ');';
- }
- /**
- * Returns field strings and any config.
- * @param {!Blockly.Block} block Input block.
- * @return {!Array.<string>} Field strings.
- * @private
- */
- function getFieldsJs_(block) {
- var fields = [];
- while (block) {
- if (!block.disabled && !block.getInheritedDisabled()) {
- switch (block.type) {
- case 'field_static':
- // Result: 'hello'
- fields.push(escapeString(block.getFieldValue('TEXT')));
- break;
- case 'field_input':
- // Result: new Blockly.FieldTextInput('Hello'), 'GREET'
- fields.push('new Blockly.FieldTextInput(' +
- escapeString(block.getFieldValue('TEXT')) + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_number':
- // Result: new Blockly.FieldNumber(10, 0, 100, 1), 'NUMBER'
- var args = [
- Number(block.getFieldValue('VALUE')),
- Number(block.getFieldValue('MIN')),
- Number(block.getFieldValue('MAX')),
- Number(block.getFieldValue('PRECISION'))
- ];
- // Remove any trailing arguments that aren't needed.
- if (args[3] == 0) {
- args.pop();
- if (args[2] == Infinity) {
- args.pop();
- if (args[1] == -Infinity) {
- args.pop();
- }
- }
- }
- fields.push('new Blockly.FieldNumber(' + args.join(', ') + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_angle':
- // Result: new Blockly.FieldAngle(90), 'ANGLE'
- fields.push('new Blockly.FieldAngle(' +
- Number(block.getFieldValue('ANGLE')) + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_checkbox':
- // Result: new Blockly.FieldCheckbox('TRUE'), 'CHECK'
- fields.push('new Blockly.FieldCheckbox(' +
- escapeString(block.getFieldValue('CHECKED')) + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_colour':
- // Result: new Blockly.FieldColour('#ff0000'), 'COLOUR'
- fields.push('new Blockly.FieldColour(' +
- escapeString(block.getFieldValue('COLOUR')) + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_date':
- // Result: new Blockly.FieldDate('2015-02-04'), 'DATE'
- fields.push('new Blockly.FieldDate(' +
- escapeString(block.getFieldValue('DATE')) + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_variable':
- // Result: new Blockly.FieldVariable('item'), 'VAR'
- var varname = escapeString(block.getFieldValue('TEXT') || null);
- fields.push('new Blockly.FieldVariable(' + varname + '), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- break;
- case 'field_dropdown':
- // Result:
- // new Blockly.FieldDropdown([['yes', '1'], ['no', '0']]), 'TOGGLE'
- var options = [];
- for (var i = 0; i < block.optionCount_; i++) {
- options[i] = '[' + escapeString(block.getFieldValue('USER' + i)) +
- ', ' + escapeString(block.getFieldValue('CPU' + i)) + ']';
- }
- if (options.length) {
- fields.push('new Blockly.FieldDropdown([' +
- options.join(', ') + ']), ' +
- escapeString(block.getFieldValue('FIELDNAME')));
- }
- break;
- case 'field_image':
- // Result: new Blockly.FieldImage('http://...', 80, 60, '*')
- var src = escapeString(block.getFieldValue('SRC'));
- var width = Number(block.getFieldValue('WIDTH'));
- var height = Number(block.getFieldValue('HEIGHT'));
- var alt = escapeString(block.getFieldValue('ALT'));
- fields.push('new Blockly.FieldImage(' +
- src + ', ' + width + ', ' + height + ', ' + alt + ')');
- break;
- }
- }
- block = block.nextConnection && block.nextConnection.targetBlock();
- }
- return fields;
- }
- /**
- * Returns field strings and any config.
- * @param {!Blockly.Block} block Input block.
- * @return {!Array.<string|!Object>} Array of static text and field configs.
- * @private
- */
- function getFieldsJson_(block) {
- var fields = [];
- while (block) {
- if (!block.disabled && !block.getInheritedDisabled()) {
- switch (block.type) {
- case 'field_static':
- // Result: 'hello'
- fields.push(block.getFieldValue('TEXT'));
- break;
- case 'field_input':
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- text: block.getFieldValue('TEXT')
- });
- break;
- case 'field_number':
- var obj = {
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- value: parseFloat(block.getFieldValue('VALUE'))
- };
- var min = parseFloat(block.getFieldValue('MIN'));
- if (min > -Infinity) {
- obj.min = min;
- }
- var max = parseFloat(block.getFieldValue('MAX'));
- if (max < Infinity) {
- obj.max = max;
- }
- var precision = parseFloat(block.getFieldValue('PRECISION'));
- if (precision) {
- obj.precision = precision;
- }
- fields.push(obj);
- break;
- case 'field_angle':
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- angle: Number(block.getFieldValue('ANGLE'))
- });
- break;
- case 'field_checkbox':
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- checked: block.getFieldValue('CHECKED') == 'TRUE'
- });
- break;
- case 'field_colour':
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- colour: block.getFieldValue('COLOUR')
- });
- break;
- case 'field_date':
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- date: block.getFieldValue('DATE')
- });
- break;
- case 'field_variable':
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- variable: block.getFieldValue('TEXT') || null
- });
- break;
- case 'field_dropdown':
- var options = [];
- for (var i = 0; i < block.optionCount_; i++) {
- options[i] = [block.getFieldValue('USER' + i),
- block.getFieldValue('CPU' + i)];
- }
- if (options.length) {
- fields.push({
- type: block.type,
- name: block.getFieldValue('FIELDNAME'),
- options: options
- });
- }
- break;
- case 'field_image':
- fields.push({
- type: block.type,
- src: block.getFieldValue('SRC'),
- width: Number(block.getFieldValue('WIDTH')),
- height: Number(block.getFieldValue('HEIGHT')),
- alt: block.getFieldValue('ALT')
- });
- break;
- }
- }
- block = block.nextConnection && block.nextConnection.targetBlock();
- }
- return fields;
- }
- /**
- * Escape a string.
- * @param {string} string String to escape.
- * @return {string} Escaped string surrouned by quotes.
- */
- function escapeString(string) {
- return JSON.stringify(string);
- }
- /**
- * Fetch the type(s) defined in the given input.
- * Format as a string for appending to the generated code.
- * @param {!Blockly.Block} block Block with input.
- * @param {string} name Name of the input.
- * @return {?string} String defining the types.
- */
- function getOptTypesFrom(block, name) {
- var types = getTypesFrom_(block, name);
- if (types.length == 0) {
- return undefined;
- } else if (types.indexOf('null') != -1) {
- return 'null';
- } else if (types.length == 1) {
- return types[0];
- } else {
- return '[' + types.join(', ') + ']';
- }
- }
- /**
- * Fetch the type(s) defined in the given input.
- * @param {!Blockly.Block} block Block with input.
- * @param {string} name Name of the input.
- * @return {!Array.<string>} List of types.
- * @private
- */
- function getTypesFrom_(block, name) {
- var typeBlock = block.getInputTargetBlock(name);
- var types;
- if (!typeBlock || typeBlock.disabled) {
- types = [];
- } else if (typeBlock.type == 'type_other') {
- types = [escapeString(typeBlock.getFieldValue('TYPE'))];
- } else if (typeBlock.type == 'type_group') {
- types = [];
- for (var i = 0; i < typeBlock.typeCount_; i++) {
- types = types.concat(getTypesFrom_(typeBlock, 'TYPE' + i));
- }
- // Remove duplicates.
- var hash = Object.create(null);
- for (var n = types.length - 1; n >= 0; n--) {
- if (hash[types[n]]) {
- types.splice(n, 1);
- }
- hash[types[n]] = true;
- }
- } else {
- types = [escapeString(typeBlock.valueType)];
- }
- return types;
- }
- /**
- * Update the generator code.
- * @param {!Blockly.Block} block Rendered block in preview workspace.
- */
- function updateGenerator(block) {
- function makeVar(root, name) {
- name = name.toLowerCase().replace(/\W/g, '_');
- return ' var ' + root + '_' + name;
- }
- var language = document.getElementById('language').value;
- var code = [];
- code.push("Blockly." + language + "['" + block.type +
- "'] = function(block) {");
- // Generate getters for any fields or inputs.
- for (var i = 0, input; input = block.inputList[i]; i++) {
- for (var j = 0, field; field = input.fieldRow[j]; j++) {
- var name = field.name;
- if (!name) {
- continue;
- }
- if (field instanceof Blockly.FieldVariable) {
- // Subclass of Blockly.FieldDropdown, must test first.
- code.push(makeVar('variable', name) +
- " = Blockly." + language +
- ".variableDB_.getName(block.getFieldValue('" + name +
- "'), Blockly.Variables.NAME_TYPE);");
- } else if (field instanceof Blockly.FieldAngle) {
- // Subclass of Blockly.FieldTextInput, must test first.
- code.push(makeVar('angle', name) +
- " = block.getFieldValue('" + name + "');");
- } else if (Blockly.FieldDate && field instanceof Blockly.FieldDate) {
- // Blockly.FieldDate may not be compiled into Blockly.
- code.push(makeVar('date', name) +
- " = block.getFieldValue('" + name + "');");
- } else if (field instanceof Blockly.FieldColour) {
- code.push(makeVar('colour', name) +
- " = block.getFieldValue('" + name + "');");
- } else if (field instanceof Blockly.FieldCheckbox) {
- code.push(makeVar('checkbox', name) +
- " = block.getFieldValue('" + name + "') == 'TRUE';");
- } else if (field instanceof Blockly.FieldDropdown) {
- code.push(makeVar('dropdown', name) +
- " = block.getFieldValue('" + name + "');");
- } else if (field instanceof Blockly.FieldNumber) {
- code.push(makeVar('number', name) +
- " = block.getFieldValue('" + name + "');");
- } else if (field instanceof Blockly.FieldTextInput) {
- code.push(makeVar('text', name) +
- " = block.getFieldValue('" + name + "');");
- }
- }
- var name = input.name;
- if (name) {
- if (input.type == Blockly.INPUT_VALUE) {
- code.push(makeVar('value', name) +
- " = Blockly." + language + ".valueToCode(block, '" + name +
- "', Blockly." + language + ".ORDER_ATOMIC);");
- } else if (input.type == Blockly.NEXT_STATEMENT) {
- code.push(makeVar('statements', name) +
- " = Blockly." + language + ".statementToCode(block, '" +
- name + "');");
- }
- }
- }
- // Most languages end lines with a semicolon. Python does not.
- var lineEnd = {
- 'JavaScript': ';',
- 'Python': '',
- 'PHP': ';',
- 'Dart': ';'
- };
- code.push(" // TODO: Assemble " + language + " into code variable.");
- if (block.outputConnection) {
- code.push(" var code = '...';");
- code.push(" // TODO: Change ORDER_NONE to the correct strength.");
- code.push(" return [code, Blockly." + language + ".ORDER_NONE];");
- } else {
- code.push(" var code = '..." + (lineEnd[language] || '') + "\\n';");
- code.push(" return code;");
- }
- code.push("};");
- injectCode(code.join('\n'), 'generatorPre');
- }
- /**
- * Existing direction ('ltr' vs 'rtl') of preview.
- */
- var oldDir = null;
- /**
- * Update the preview display.
- */
- function updatePreview() {
- // Toggle between LTR/RTL if needed (also used in first display).
- var newDir = document.getElementById('direction').value;
- if (oldDir != newDir) {
- if (previewWorkspace) {
- previewWorkspace.dispose();
- }
- var rtl = newDir == 'rtl';
- previewWorkspace = Blockly.inject('preview',
- {rtl: rtl,
- media: '../../media/',
- scrollbars: true});
- oldDir = newDir;
- }
- previewWorkspace.clear();
- // Fetch the code and determine its format (JSON or JavaScript).
- var format = document.getElementById('format').value;
- if (format == 'Manual') {
- var code = document.getElementById('languageTA').value;
- // If the code is JSON, it will parse, otherwise treat as JS.
- try {
- JSON.parse(code);
- format = 'JSON';
- } catch (e) {
- format = 'JavaScript';
- }
- } else {
- var code = document.getElementById('languagePre').textContent;
- }
- if (!code.trim()) {
- // Nothing to render. Happens while cloud storage is loading.
- return;
- }
- // Backup Blockly.Blocks object so that main workspace and preview don't
- // collide if user creates a 'factory_base' block, for instance.
- var backupBlocks = Blockly.Blocks;
- try {
- // Make a shallow copy.
- Blockly.Blocks = {};
- for (var prop in backupBlocks) {
- Blockly.Blocks[prop] = backupBlocks[prop];
- }
- if (format == 'JSON') {
- var json = JSON.parse(code);
- Blockly.Blocks[json.type || UNNAMED] = {
- init: function() {
- this.jsonInit(json);
- }
- };
- } else if (format == 'JavaScript') {
- eval(code);
- } else {
- throw 'Unknown format: ' + format;
- }
- // Look for a block on Blockly.Blocks that does not match the backup.
- var blockType = null;
- for (var type in Blockly.Blocks) {
- if (typeof Blockly.Blocks[type].init == 'function' &&
- Blockly.Blocks[type] != backupBlocks[type]) {
- blockType = type;
- break;
- }
- }
- if (!blockType) {
- return;
- }
- // Create the preview block.
- var previewBlock = previewWorkspace.newBlock(blockType);
- previewBlock.initSvg();
- previewBlock.render();
- previewBlock.setMovable(false);
- previewBlock.setDeletable(false);
- previewBlock.moveBy(15, 10);
- previewWorkspace.clearUndo();
- updateGenerator(previewBlock);
- } finally {
- Blockly.Blocks = backupBlocks;
- }
- }
- /**
- * Inject code into a pre tag, with syntax highlighting.
- * Safe from HTML/script injection.
- * @param {string} code Lines of code.
- * @param {string} id ID of <pre> element to inject into.
- */
- function injectCode(code, id) {
- var pre = document.getElementById(id);
- pre.textContent = code;
- code = pre.textContent;
- code = prettyPrintOne(code, 'js');
- pre.innerHTML = code;
- }
- /**
- * Return the uneditable container block that everything else attaches to.
- * @return {Blockly.Block}
- */
- function getRootBlock() {
- var blocks = mainWorkspace.getTopBlocks(false);
- for (var i = 0, block; block = blocks[i]; i++) {
- if (block.type == 'factory_base') {
- return block;
- }
- }
- return null;
- }
- /**
- * Disable the link button if the format is 'Manual', enable otherwise.
- */
- function disableEnableLink() {
- var linkButton = document.getElementById('linkButton');
- linkButton.disabled = document.getElementById('format').value == 'Manual';
- }
- /**
- * Initialize Blockly and layout. Called on page load.
- */
- function init() {
- if ('BlocklyStorage' in window) {
- BlocklyStorage.HTTPREQUEST_ERROR =
- 'There was a problem with the request.\n';
- BlocklyStorage.LINK_ALERT =
- 'Share your blocks with this link:\n\n%1';
- BlocklyStorage.HASH_ERROR =
- 'Sorry, "%1" doesn\'t correspond with any saved Blockly file.';
- BlocklyStorage.XML_ERROR = 'Could not load your saved file.\n'+
- 'Perhaps it was created with a different version of Blockly?';
- var linkButton = document.getElementById('linkButton');
- linkButton.style.display = 'inline-block';
- linkButton.addEventListener('click',
- function() {BlocklyStorage.link(mainWorkspace);});
- disableEnableLink();
- }
- document.getElementById('helpButton').addEventListener('click',
- function() {
- open('https://developers.google.com/blockly/guides/create-custom-blocks/block-factory',
- 'BlockFactoryHelp');
- });
- var expandList = [
- document.getElementById('blockly'),
- document.getElementById('blocklyMask'),
- document.getElementById('preview'),
- document.getElementById('languagePre'),
- document.getElementById('languageTA'),
- document.getElementById('generatorPre')
- ];
- var onresize = function(e) {
- for (var i = 0, expand; expand = expandList[i]; i++) {
- expand.style.width = (expand.parentNode.offsetWidth - 2) + 'px';
- expand.style.height = (expand.parentNode.offsetHeight - 2) + 'px';
- }
- };
- onresize();
- window.addEventListener('resize', onresize);
- var toolbox = document.getElementById('toolbox');
- mainWorkspace = Blockly.inject('blockly',
- {collapse: false,
- toolbox: toolbox,
- media: '../../media/'});
- // Create the root block.
- if ('BlocklyStorage' in window && window.location.hash.length > 1) {
- BlocklyStorage.retrieveXml(window.location.hash.substring(1),
- mainWorkspace);
- } else {
- var xml = '<xml><block type="factory_base" deletable="false" movable="false"></block></xml>';
- Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), mainWorkspace);
- }
- mainWorkspace.clearUndo();
- mainWorkspace.addChangeListener(Blockly.Events.disableOrphans);
- mainWorkspace.addChangeListener(updateLanguage);
- document.getElementById('direction')
- .addEventListener('change', updatePreview);
- document.getElementById('languageTA')
- .addEventListener('change', updatePreview);
- document.getElementById('languageTA')
- .addEventListener('keyup', updatePreview);
- document.getElementById('format')
- .addEventListener('change', formatChange);
- document.getElementById('language')
- .addEventListener('change', updatePreview);
- }
- window.addEventListener('load', init);
|