Merge pull request #1944 from google/rc/june_2018

June 2018 release
This commit is contained in:
Rachel Fenichel
2018-06-29 16:30:51 -07:00
committed by GitHub
229 changed files with 40191 additions and 35870 deletions
+4 -1
View File
@@ -1,14 +1,17 @@
*_compressed*.js
*_uncompressed*.js
blockly_node_javascript_en.js
gulpfile.js
/msg/*
/core/css.js
/tests/blocks/*
/tests/compile/*
/tests/jsunit/*
/tests/generators/*
/tests/test_runner.js
/tests/workspace_svg/*
/generators/*
/demos/*
/accessible/*
/appengine/*
/externs/svg-externs.js
/externs/*
+2 -1
View File
@@ -1,6 +1,6 @@
{
"rules": {
"curly": ["error", "multi-line"],
"curly": ["error"],
"eol-last": ["error"],
"indent": [
"error", 2, # Blockly/Google use 2-space indents
@@ -50,6 +50,7 @@
"quotes": ["off"], # Blockly uses single quotes except for JSON blobs, which must use double quotes.
"semi": ["error", "always"],
"space-before-function-paren": ["error", "never"], # Blockly doesn't have space before function paren
"space-infix-ops": ["error"],
"strict": ["off"], # Blockly uses 'use strict' in files
"no-cond-assign": ["off"], # Blockly often uses cond-assignment in loops
"no-redeclare": ["off"], # Closure style allows redeclarations
+1
View File
@@ -1,3 +1,4 @@
blockly_node_javascript_en.js
node_modules
npm-debug.log
.DS_Store
+3 -11
View File
@@ -13,21 +13,13 @@ matrix:
node_js: stable
osx_image: xcode8.3
before_install:
- npm install google-closure-library
- npm install google-closure-compiler
- npm install webdriverio
# Symlink closure library
- ln -s $(npm root)/google-closure-library ../closure-library
before_script:
# Symlink closure library used by test/jsunit
- ln -s $(npm root)/google-closure-library ../closure-library
- export DISPLAY=:99.0
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then ( tests/scripts/setup_linux_env.sh ) fi
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then ( tests/scripts/setup_osx_env.sh ) fi
- sleep 2
script:
- set -x
- npm run lint
- npm test
- cd tests/compile; compile.sh; cd ..
- tests/run_all_tests.sh
+1 -1
View File
@@ -101,7 +101,7 @@ blocklyApp.BlockConnectionService = ng.core.Class({
},
attachToMarkedConnection: function(block) {
var xml = Blockly.Xml.blockToDom(block);
var reconstitutedBlock = Blockly.Xml.domToBlock(blocklyApp.workspace, xml);
var reconstitutedBlock = Blockly.Xml.domToBlock(xml, blocklyApp.workspace);
var targetConnection = null;
if (this.markedConnection_.targetBlock() &&
+1 -1
View File
@@ -182,7 +182,7 @@ blocklyApp.FieldSegmentComponent = ng.core.Component({
},
// Sets the value on a dropdown input.
setDropdownValue: function(optionValue) {
this.optionValue = optionValue
this.optionValue = optionValue;
if (this.optionValue == 'NO_ACTION') {
return;
}
+1 -1
View File
@@ -26,7 +26,7 @@
}
.blocklySidebarButton[disabled] {
border: 1px solid #ccc;
opacity: 0.5;
opacity: .5;
}
.blocklyAriaLiveStatus {
+3 -3
View File
@@ -71,7 +71,7 @@ blocklyApp.ToolboxModalService = ng.core.Class({
this.allToolboxCategories = Array.from(toolboxCategoryElts).map(
function(categoryElt) {
var tmpWorkspace = new Blockly.Workspace();
var custom = categoryElt.attributes.custom
var custom = categoryElt.attributes.custom;
// TODO (corydiers): Implement custom flyouts once #1153 is solved.
if (custom && custom.value == Blockly.VARIABLE_CATEGORY_NAME) {
var varBlocks =
@@ -95,7 +95,7 @@ blocklyApp.ToolboxModalService = ng.core.Class({
// containing all the top-level blocks.
var tmpWorkspace = new Blockly.Workspace();
Array.from(toolboxXmlElt.children).forEach(function(topLevelNode) {
Blockly.Xml.domToBlock(tmpWorkspace, topLevelNode);
Blockly.Xml.domToBlock(topLevelNode, tmpWorkspace);
});
that.allToolboxCategories = [{
@@ -214,7 +214,7 @@ blocklyApp.ToolboxModalService = ng.core.Class({
this.showModal_(this.toolboxCategoriesForNewGroup, function(block) {
var blockDescription = that.utilsService.getBlockDescription(block);
var xml = Blockly.Xml.blockToDom(block);
var newBlockId = Blockly.Xml.domToBlock(blocklyApp.workspace, xml).id;
var newBlockId = Blockly.Xml.domToBlock(xml, blocklyApp.workspace).id;
// Invoke a digest cycle, so that the DOM settles.
setTimeout(function() {
+2 -2
View File
@@ -71,7 +71,7 @@ blocklyApp.VariableAddModalComponent = ng.core.Component({
this.workspace = blocklyApp.workspace;
this.variableModalService = variableService;
this.audioService = audioService;
this.keyboardInputService = keyboardService
this.keyboardInputService = keyboardService;
this.modalIsVisible = false;
this.activeButtonIndex = -1;
@@ -103,7 +103,7 @@ blocklyApp.VariableAddModalComponent = ng.core.Component({
getInteractiveElements: Blockly.CommonModal.getInteractiveElements,
// Gets the container with interactive elements.
getInteractiveContainer: function() {
return document.getElementById("varForm");
return document.getElementById('varForm');
},
// Submits the name change for the variable.
submit: function() {
@@ -74,17 +74,17 @@ blocklyApp.VariableRemoveModalComponent = ng.core.Component({
this.treeService = treeService;
this.variableModalService = variableService;
this.audioService = audioService;
this.keyboardInputService = keyboardService
this.keyboardInputService = keyboardService;
this.modalIsVisible = false;
this.activeButtonIndex = -1;
this.currentVariableName = "";
this.currentVariableName = '';
this.count = 0;
var that = this;
this.variableModalService.registerPreRemoveShowHook(
function(name, count) {
that.currentVariableName = name;
that.count = count
that.count = count;
that.modalIsVisible = true;
Blockly.CommonModal.setupKeyboardOverrides(that);
@@ -106,7 +106,7 @@ blocklyApp.VariableRemoveModalComponent = ng.core.Component({
getInteractiveElements: Blockly.CommonModal.getInteractiveElements,
// Gets the container with interactive elements.
getInteractiveContainer: function() {
return document.getElementById("varForm");
return document.getElementById('varForm');
},
getNumVariables: function() {
return this.variableModalService.getNumVariables(this.currentVariableName);
@@ -72,10 +72,10 @@ blocklyApp.VariableRenameModalComponent = ng.core.Component({
this.workspace = blocklyApp.workspace;
this.variableModalService = variableService;
this.audioService = audioService;
this.keyboardInputService = keyboardService
this.keyboardInputService = keyboardService;
this.modalIsVisible = false;
this.activeButtonIndex = -1;
this.currentVariableName = "";
this.currentVariableName = '';
var that = this;
this.variableModalService.registerPreRenameShowHook(
@@ -106,7 +106,7 @@ blocklyApp.VariableRenameModalComponent = ng.core.Component({
getInteractiveElements: Blockly.CommonModal.getInteractiveElements,
// Gets the container with interactive elements.
getInteractiveContainer: function() {
return document.getElementById("varForm");
return document.getElementById('varForm');
},
// Submits the name change for the variable.
submit: function() {
+2 -1
View File
@@ -1,2 +1,3 @@
print("Status: 302")
print("Status: 301")
print("Location: /static/demos/index.html")
print("")
+26 -24
View File
@@ -22,35 +22,32 @@ limitations under the License.
__author__ = "q.neutron@gmail.com (Quynh Neutron)"
import cgi
import hashlib
from random import randint
from google.appengine.ext import db
from google.appengine.api import memcache
import logging
from google.appengine.ext import ndb
print "Content-Type: text/plain\n"
def keyGen():
# Generate a random string of length KEY_LEN.
KEY_LEN = 6
CHARS = "abcdefghijkmnopqrstuvwxyz23456789" # Exclude l, 0, 1.
CHARS = "abcdefghijkmnopqrstuvwxyz23456789" # Exclude l, 0, 1.
max_index = len(CHARS) - 1
return "".join([CHARS[randint(0, max_index)] for x in range(KEY_LEN)])
class Xml(db.Model):
class Xml(ndb.Model):
# A row in the database.
xml_hash = db.IntegerProperty()
xml_content = db.TextProperty()
xml_hash = ndb.IntegerProperty()
xml_content = ndb.TextProperty()
forms = cgi.FieldStorage()
if "xml" in forms:
def xmlToKey(xml_content):
# Store XML and return a generated key.
xml_content = forms["xml"].value
xml_hash = hash(xml_content)
lookup_query = db.Query(Xml)
lookup_query.filter("xml_hash =", xml_hash)
xml_hash = long(hashlib.sha1(xml_content).hexdigest(), 16)
xml_hash = int(xml_hash % (2 ** 64) - (2 ** 63))
lookup_query = Xml.query(Xml.xml_hash == xml_hash)
lookup_result = lookup_query.get()
if lookup_result:
xml_key = lookup_result.key().name()
xml_key = lookup_result.key.string_id()
else:
trials = 0
result = True
@@ -59,27 +56,32 @@ if "xml" in forms:
if trials == 100:
raise Exception("Sorry, the generator failed to get a key for you.")
xml_key = keyGen()
result = db.get(db.Key.from_path("Xml", xml_key))
xml = db.Text(xml_content, encoding="utf_8")
row = Xml(key_name = xml_key, xml_hash = xml_hash, xml_content = xml)
result = Xml.get_by_id(xml_key)
row = Xml(id = xml_key, xml_hash = xml_hash, xml_content = xml_content)
row.put()
print xml_key
return xml_key
if "key" in forms:
def keyToXml(key_provided):
# Retrieve stored XML based on the provided key.
key_provided = forms["key"].value
# Normalize the string.
key_provided = key_provided.lower().strip()
# Check memcache for a quick match.
xml = memcache.get("XML_" + key_provided)
if xml is None:
# Check datastore for a definitive match.
result = db.get(db.Key.from_path("Xml", key_provided))
result = Xml.get_by_id(key_provided)
if not result:
xml = ""
else:
xml = result.xml_content
# Save to memcache for next hit.
if not memcache.add("XML_" + key_provided, xml, 3600):
logging.error("Memcache set failed.")
print xml.encode("utf-8")
memcache.add("XML_" + key_provided, xml, 3600)
return xml.encode("utf-8")
if __name__ == "__main__":
print("Content-Type: text/plain\n")
forms = cgi.FieldStorage()
if "xml" in forms:
print(xmlToKey(forms["xml"].value))
if "key" in forms:
print(keyToXml(forms["key"].value))
File diff suppressed because it is too large Load Diff
+24 -10
View File
@@ -61,22 +61,23 @@ goog.addDependency("../../../" + dir + "/accessible/variable-rename-modal.compon
goog.addDependency("../../../" + dir + "/accessible/workspace-block.component.js", ['blocklyApp.WorkspaceBlockComponent'], ['blocklyApp.UtilsService', 'blocklyApp.AudioService', 'blocklyApp.BlockConnectionService', 'blocklyApp.FieldSegmentComponent', 'blocklyApp.TranslatePipe', 'blocklyApp.TreeService']);
goog.addDependency("../../../" + dir + "/accessible/workspace.component.js", ['blocklyApp.WorkspaceComponent'], ['blocklyApp.NotificationsService', 'blocklyApp.ToolboxModalService', 'blocklyApp.TranslatePipe', 'blocklyApp.TreeService', 'blocklyApp.WorkspaceBlockComponent']);
goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.Workspace', 'Blockly.Xml', 'goog.array', 'goog.asserts', 'goog.math.Coordinate', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/block_animations.js", ['Blockly.BlockAnimations'], []);
goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.DraggedConnectionManager', 'Blockly.Events.BlockMove', 'goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.DraggedConnectionManager', 'Blockly.Events.BlockMove', 'goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg']);
goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.ContextMenu', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.Timer', 'goog.asserts', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.asserts', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'goog.color']);
goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []);
goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.Workspace', 'goog.dom', 'goog.math', 'goog.math.Coordinate', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events.CommentMove', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events.BlockMove', 'goog.asserts', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']);
goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []);
goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events.BlockCreate', 'Blockly.utils', 'Blockly.utils.uiMenu', 'goog.dom', 'goog.events', 'goog.style', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []);
goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.RenderedConnection', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], ['goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/events_abstract.js", ['Blockly.Events.Abstract'], ['Blockly.Events', 'goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/extensions.js", ['Blockly.Extensions'], ['Blockly.Mutator', 'Blockly.utils', 'goog.string']);
@@ -97,13 +98,13 @@ goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.Flyo
goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.FlyoutButton', 'Blockly.Flyout', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.events', 'goog.math.Rect', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.events', 'goog.math.Rect', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceDragger', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceDragger', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.utils', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.Grid', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.dom', 'goog.ui.Component', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []);
goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.WorkspaceSvg', 'goog.Timer', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.WorkspaceSvg', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/names.js", ['Blockly.Names'], []);
goog.addDependency("../../../" + dir + "/core/options.js", ['Blockly.Options'], []);
goog.addDependency("../../../" + dir + "/core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Names', 'Blockly.Workspace']);
@@ -113,7 +114,7 @@ goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'],
goog.addDependency("../../../" + dir + "/core/tooltip.js", ['Blockly.Tooltip'], ['goog.dom', 'goog.dom.TagName']);
goog.addDependency("../../../" + dir + "/core/touch.js", ['Blockly.Touch'], ['goog.events', 'goog.events.BrowserFeature', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.TouchGesture'], ['Blockly.Gesture', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['goog.Timer', 'goog.dom', 'goog.math', 'goog.math.Rect']);
goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['goog.dom', 'goog.math', 'goog.math.Rect']);
goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract', 'goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], []);
goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.Touch', 'goog.dom', 'goog.events.BrowserFeature', 'goog.math.Coordinate', 'goog.userAgent']);
@@ -124,12 +125,16 @@ goog.addDependency("../../../" + dir + "/core/variables.js", ['Blockly.Variables
goog.addDependency("../../../" + dir + "/core/variables_dynamic.js", ['Blockly.VariablesDynamic'], ['Blockly.Variables', 'Blockly.Blocks', 'Blockly.constants', 'Blockly.VariableModel', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events.Ui', 'Blockly.Icon']);
goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.dom', 'goog.dom.TagName', 'goog.style']);
goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.VariableMap', 'goog.array', 'goog.math']);
goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.VariableMap', 'Blockly.WorkspaceComment', 'goog.array', 'goog.math']);
goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.WorkspaceCommentSvg']);
goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.WorkspaceComment']);
goog.addDependency("../../../" + dir + "/core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.array', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'goog.asserts', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.array', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Touch', 'goog.dom']);
goog.addDependency("../../alltests.js", [], []);
goog.addDependency("../../browser_capabilities.js", [], []);
@@ -1751,6 +1756,7 @@ goog.addDependency("window/window_test.js", ['goog.windowTest'], ['goog.Promise'
// Load Blockly.
goog.require('Blockly');
goog.require('Blockly.Block');
goog.require('Blockly.BlockAnimations');
goog.require('Blockly.BlockDragSurfaceSvg');
goog.require('Blockly.BlockDragger');
goog.require('Blockly.BlockSvg');
@@ -1773,6 +1779,11 @@ goog.require('Blockly.Events.BlockCreate');
goog.require('Blockly.Events.BlockDelete');
goog.require('Blockly.Events.BlockMove');
goog.require('Blockly.Events.Change');
goog.require('Blockly.Events.CommentBase');
goog.require('Blockly.Events.CommentChange');
goog.require('Blockly.Events.CommentCreate');
goog.require('Blockly.Events.CommentDelete');
goog.require('Blockly.Events.CommentMove');
goog.require('Blockly.Events.Create');
goog.require('Blockly.Events.Delete');
goog.require('Blockly.Events.Move');
@@ -1824,6 +1835,9 @@ goog.require('Blockly.Warning');
goog.require('Blockly.WidgetDiv');
goog.require('Blockly.Workspace');
goog.require('Blockly.WorkspaceAudio');
goog.require('Blockly.WorkspaceComment');
goog.require('Blockly.WorkspaceCommentSvg');
goog.require('Blockly.WorkspaceCommentSvg.render');
goog.require('Blockly.WorkspaceDragSurfaceSvg');
goog.require('Blockly.WorkspaceDragger');
goog.require('Blockly.WorkspaceSvg');
+477 -394
View File
File diff suppressed because it is too large Load Diff
+24 -10
View File
@@ -35,22 +35,23 @@ this.BLOCKLY_BOOT = function(root) {
}
// Execute after Closure has loaded.
goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.Workspace', 'Blockly.Xml', 'goog.array', 'goog.asserts', 'goog.math.Coordinate', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/block_animations.js", ['Blockly.BlockAnimations'], []);
goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.DraggedConnectionManager', 'Blockly.Events.BlockMove', 'goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.DraggedConnectionManager', 'Blockly.Events.BlockMove', 'goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg']);
goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.ContextMenu', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.Timer', 'goog.asserts', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.asserts', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'goog.color']);
goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []);
goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.Workspace', 'goog.dom', 'goog.math', 'goog.math.Coordinate', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events.CommentMove', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events.BlockMove', 'goog.asserts', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']);
goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []);
goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events.BlockCreate', 'Blockly.utils', 'Blockly.utils.uiMenu', 'goog.dom', 'goog.events', 'goog.style', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []);
goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.RenderedConnection', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], ['goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/events_abstract.js", ['Blockly.Events.Abstract'], ['Blockly.Events', 'goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/extensions.js", ['Blockly.Extensions'], ['Blockly.Mutator', 'Blockly.utils', 'goog.string']);
@@ -71,13 +72,13 @@ goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.Flyo
goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.FlyoutButton', 'Blockly.Flyout', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.events', 'goog.math.Rect', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'goog.dom', 'goog.events', 'goog.math.Rect', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceDragger', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceDragger', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.utils', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.Grid', 'Blockly.Options', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.dom', 'goog.ui.Component', 'goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []);
goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.WorkspaceSvg', 'goog.Timer', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.WorkspaceSvg', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/names.js", ['Blockly.Names'], []);
goog.addDependency("../../../" + dir + "/core/options.js", ['Blockly.Options'], []);
goog.addDependency("../../../" + dir + "/core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Names', 'Blockly.Workspace']);
@@ -87,7 +88,7 @@ goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'],
goog.addDependency("../../../" + dir + "/core/tooltip.js", ['Blockly.Tooltip'], ['goog.dom', 'goog.dom.TagName']);
goog.addDependency("../../../" + dir + "/core/touch.js", ['Blockly.Touch'], ['goog.events', 'goog.events.BrowserFeature', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.TouchGesture'], ['Blockly.Gesture', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['goog.Timer', 'goog.dom', 'goog.math', 'goog.math.Rect']);
goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['goog.dom', 'goog.math', 'goog.math.Rect']);
goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract', 'goog.array', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], []);
goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.Touch', 'goog.dom', 'goog.events.BrowserFeature', 'goog.math.Coordinate', 'goog.userAgent']);
@@ -98,12 +99,16 @@ goog.addDependency("../../../" + dir + "/core/variables.js", ['Blockly.Variables
goog.addDependency("../../../" + dir + "/core/variables_dynamic.js", ['Blockly.VariablesDynamic'], ['Blockly.Variables', 'Blockly.Blocks', 'Blockly.constants', 'Blockly.VariableModel', 'goog.string']);
goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events.Ui', 'Blockly.Icon']);
goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.dom', 'goog.dom.TagName', 'goog.style']);
goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.VariableMap', 'goog.array', 'goog.math']);
goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.VariableMap', 'Blockly.WorkspaceComment', 'goog.array', 'goog.math']);
goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.WorkspaceCommentSvg']);
goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.WorkspaceComment']);
goog.addDependency("../../../" + dir + "/core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'goog.asserts', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['goog.math.Coordinate', 'goog.asserts']);
goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.array', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'goog.asserts', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.array', 'goog.dom', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'goog.math.Coordinate']);
goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'goog.dom']);
goog.addDependency("../../../" + dir + "/core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Touch', 'goog.dom']);
goog.addDependency("../../alltests.js", [], []);
goog.addDependency("../../browser_capabilities.js", [], []);
@@ -1725,6 +1730,7 @@ goog.addDependency("window/window_test.js", ['goog.windowTest'], ['goog.Promise'
// Load Blockly.
goog.require('Blockly');
goog.require('Blockly.Block');
goog.require('Blockly.BlockAnimations');
goog.require('Blockly.BlockDragSurfaceSvg');
goog.require('Blockly.BlockDragger');
goog.require('Blockly.BlockSvg');
@@ -1746,6 +1752,11 @@ goog.require('Blockly.Events.BlockCreate');
goog.require('Blockly.Events.BlockDelete');
goog.require('Blockly.Events.BlockMove');
goog.require('Blockly.Events.Change');
goog.require('Blockly.Events.CommentBase');
goog.require('Blockly.Events.CommentChange');
goog.require('Blockly.Events.CommentCreate');
goog.require('Blockly.Events.CommentDelete');
goog.require('Blockly.Events.CommentMove');
goog.require('Blockly.Events.Create');
goog.require('Blockly.Events.Delete');
goog.require('Blockly.Events.Move');
@@ -1797,6 +1808,9 @@ goog.require('Blockly.Warning');
goog.require('Blockly.WidgetDiv');
goog.require('Blockly.Workspace');
goog.require('Blockly.WorkspaceAudio');
goog.require('Blockly.WorkspaceComment');
goog.require('Blockly.WorkspaceCommentSvg');
goog.require('Blockly.WorkspaceCommentSvg.render');
goog.require('Blockly.WorkspaceDragSurfaceSvg');
goog.require('Blockly.WorkspaceDragger');
goog.require('Blockly.WorkspaceSvg');
+2 -2
View File
@@ -30,7 +30,7 @@
'use strict';
goog.provide('Blockly.Blocks.colour'); // Deprecated
goog.provide('Blockly.Constants.Colour');
goog.provide('Blockly.Constants.Colour'); // deprecated, 2018 April 5
goog.require('Blockly.Blocks');
goog.require('Blockly');
@@ -38,7 +38,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.COLOUR_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['COLOUR_HUE']. (2018 April 5)
*/
Blockly.Constants.Colour.HUE = 20;
+103 -103
View File
@@ -30,14 +30,14 @@
'use strict';
goog.provide('Blockly.Blocks.lists'); // Deprecated
goog.provide('Blockly.Constants.Lists');
goog.provide('Blockly.Constants.Lists'); // deprecated, 2018 April 5
goog.require('Blockly.Blocks');
goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.LISTS_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['LISTS_HUE']. (2018 April 5)
*/
Blockly.Constants.Lists.HUE = 260;
@@ -132,13 +132,13 @@ Blockly.Blocks['lists_create_with'] = {
* @this Blockly.Block
*/
init: function() {
this.setHelpUrl(Blockly.Msg.LISTS_CREATE_WITH_HELPURL);
this.setColour(Blockly.Msg.LISTS_HUE);
this.setHelpUrl(Blockly.Msg['LISTS_CREATE_WITH_HELPURL']);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.itemCount_ = 3;
this.updateShape_();
this.setOutput(true, 'Array');
this.setMutator(new Blockly.Mutator(['lists_create_with_item']));
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP);
this.setTooltip(Blockly.Msg['LISTS_CREATE_WITH_TOOLTIP']);
},
/**
* Create XML to represent list inputs.
@@ -231,14 +231,14 @@ Blockly.Blocks['lists_create_with'] = {
this.removeInput('EMPTY');
} else if (!this.itemCount_ && !this.getInput('EMPTY')) {
this.appendDummyInput('EMPTY')
.appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);
.appendField(Blockly.Msg['LISTS_CREATE_EMPTY_TITLE']);
}
// Add new inputs.
for (var i = 0; i < this.itemCount_; i++) {
if (!this.getInput('ADD' + i)) {
var input = this.appendValueInput('ADD' + i);
if (i == 0) {
input.appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH);
input.appendField(Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH']);
}
}
}
@@ -256,11 +256,11 @@ Blockly.Blocks['lists_create_with_container'] = {
* @this Blockly.Block
*/
init: function() {
this.setColour(Blockly.Msg.LISTS_HUE);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.appendDummyInput()
.appendField(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD);
.appendField(Blockly.Msg['LISTS_CREATE_WITH_CONTAINER_TITLE_ADD']);
this.appendStatementInput('STACK');
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP);
this.setTooltip(Blockly.Msg['LISTS_CREATE_WITH_CONTAINER_TOOLTIP']);
this.contextMenu = false;
}
};
@@ -271,12 +271,12 @@ Blockly.Blocks['lists_create_with_item'] = {
* @this Blockly.Block
*/
init: function() {
this.setColour(Blockly.Msg.LISTS_HUE);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.appendDummyInput()
.appendField(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE);
.appendField(Blockly.Msg['LISTS_CREATE_WITH_ITEM_TITLE']);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP);
this.setTooltip(Blockly.Msg['LISTS_CREATE_WITH_ITEM_TOOLTIP']);
this.contextMenu = false;
}
};
@@ -289,22 +289,22 @@ Blockly.Blocks['lists_indexOf'] = {
init: function() {
var OPERATORS =
[
[Blockly.Msg.LISTS_INDEX_OF_FIRST, 'FIRST'],
[Blockly.Msg.LISTS_INDEX_OF_LAST, 'LAST']
[Blockly.Msg['LISTS_INDEX_OF_FIRST'], 'FIRST'],
[Blockly.Msg['LISTS_INDEX_OF_LAST'], 'LAST']
];
this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL);
this.setColour(Blockly.Msg.LISTS_HUE);
this.setHelpUrl(Blockly.Msg['LISTS_INDEX_OF_HELPURL']);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.setOutput(true, 'Number');
this.appendValueInput('VALUE')
.setCheck('Array')
.appendField(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST);
.appendField(Blockly.Msg['LISTS_INDEX_OF_INPUT_IN_LIST']);
this.appendValueInput('FIND')
.appendField(new Blockly.FieldDropdown(OPERATORS), 'END');
this.setInputsInline(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function() {
return Blockly.Msg.LISTS_INDEX_OF_TOOLTIP.replace('%1',
return Blockly.Msg['LISTS_INDEX_OF_TOOLTIP'].replace('%1',
thisBlock.workspace.options.oneBasedIndex ? '0' : '-1');
});
}
@@ -318,34 +318,34 @@ Blockly.Blocks['lists_getIndex'] = {
init: function() {
var MODE =
[
[Blockly.Msg.LISTS_GET_INDEX_GET, 'GET'],
[Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE, 'GET_REMOVE'],
[Blockly.Msg.LISTS_GET_INDEX_REMOVE, 'REMOVE']
[Blockly.Msg['LISTS_GET_INDEX_GET'], 'GET'],
[Blockly.Msg['LISTS_GET_INDEX_GET_REMOVE'], 'GET_REMOVE'],
[Blockly.Msg['LISTS_GET_INDEX_REMOVE'], 'REMOVE']
];
this.WHERE_OPTIONS =
[
[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'],
[Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'],
[Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'],
[Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'],
[Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']
[Blockly.Msg['LISTS_GET_INDEX_FROM_START'], 'FROM_START'],
[Blockly.Msg['LISTS_GET_INDEX_FROM_END'], 'FROM_END'],
[Blockly.Msg['LISTS_GET_INDEX_FIRST'], 'FIRST'],
[Blockly.Msg['LISTS_GET_INDEX_LAST'], 'LAST'],
[Blockly.Msg['LISTS_GET_INDEX_RANDOM'], 'RANDOM']
];
this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL);
this.setColour(Blockly.Msg.LISTS_HUE);
this.setHelpUrl(Blockly.Msg['LISTS_GET_INDEX_HELPURL']);
this.setColour(Blockly.Msg['LISTS_HUE']);
var modeMenu = new Blockly.FieldDropdown(MODE, function(value) {
var isStatement = (value == 'REMOVE');
this.sourceBlock_.updateStatement_(isStatement);
});
this.appendValueInput('VALUE')
.setCheck('Array')
.appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);
.appendField(Blockly.Msg['LISTS_GET_INDEX_INPUT_IN_LIST']);
this.appendDummyInput()
.appendField(modeMenu, 'MODE')
.appendField('', 'SPACE');
this.appendDummyInput('AT');
if (Blockly.Msg.LISTS_GET_INDEX_TAIL) {
if (Blockly.Msg['LISTS_GET_INDEX_TAIL']) {
this.appendDummyInput('TAIL')
.appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL);
.appendField(Blockly.Msg['LISTS_GET_INDEX_TAIL']);
}
this.setInputsInline(true);
this.setOutput(true);
@@ -359,48 +359,48 @@ Blockly.Blocks['lists_getIndex'] = {
switch (mode + ' ' + where) {
case 'GET FROM_START':
case 'GET FROM_END':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_FROM'];
break;
case 'GET FIRST':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_FIRST'];
break;
case 'GET LAST':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_LAST'];
break;
case 'GET RANDOM':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_RANDOM'];
break;
case 'GET_REMOVE FROM_START':
case 'GET_REMOVE FROM_END':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM'];
break;
case 'GET_REMOVE FIRST':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST'];
break;
case 'GET_REMOVE LAST':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST'];
break;
case 'GET_REMOVE RANDOM':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM'];
break;
case 'REMOVE FROM_START':
case 'REMOVE FROM_END':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM'];
break;
case 'REMOVE FIRST':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST'];
break;
case 'REMOVE LAST':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST'];
break;
case 'REMOVE RANDOM':
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM;
tooltip = Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM'];
break;
}
if (where == 'FROM_START' || where == 'FROM_END') {
var msg = (where == 'FROM_START') ?
Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP :
Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP;
Blockly.Msg['LISTS_INDEX_FROM_START_TOOLTIP'] :
Blockly.Msg['LISTS_INDEX_FROM_END_TOOLTIP'];
tooltip += ' ' + msg.replace('%1',
thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0');
}
@@ -469,9 +469,9 @@ Blockly.Blocks['lists_getIndex'] = {
// Create either a value 'AT' input or a dummy input.
if (isAt) {
this.appendValueInput('AT').setCheck('Number');
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
if (Blockly.Msg['ORDINAL_NUMBER_SUFFIX']) {
this.appendDummyInput('ORDINAL')
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
.appendField(Blockly.Msg['ORDINAL_NUMBER_SUFFIX']);
}
} else {
this.appendDummyInput('AT');
@@ -489,7 +489,7 @@ Blockly.Blocks['lists_getIndex'] = {
return undefined;
});
this.getInput('AT').appendField(menu, 'WHERE');
if (Blockly.Msg.LISTS_GET_INDEX_TAIL) {
if (Blockly.Msg['LISTS_GET_INDEX_TAIL']) {
this.moveInputBefore('TAIL', null);
}
}
@@ -503,32 +503,32 @@ Blockly.Blocks['lists_setIndex'] = {
init: function() {
var MODE =
[
[Blockly.Msg.LISTS_SET_INDEX_SET, 'SET'],
[Blockly.Msg.LISTS_SET_INDEX_INSERT, 'INSERT']
[Blockly.Msg['LISTS_SET_INDEX_SET'], 'SET'],
[Blockly.Msg['LISTS_SET_INDEX_INSERT'], 'INSERT']
];
this.WHERE_OPTIONS =
[
[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'],
[Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'],
[Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'],
[Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'],
[Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']
[Blockly.Msg['LISTS_GET_INDEX_FROM_START'], 'FROM_START'],
[Blockly.Msg['LISTS_GET_INDEX_FROM_END'], 'FROM_END'],
[Blockly.Msg['LISTS_GET_INDEX_FIRST'], 'FIRST'],
[Blockly.Msg['LISTS_GET_INDEX_LAST'], 'LAST'],
[Blockly.Msg['LISTS_GET_INDEX_RANDOM'], 'RANDOM']
];
this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL);
this.setColour(Blockly.Msg.LISTS_HUE);
this.setHelpUrl(Blockly.Msg['LISTS_SET_INDEX_HELPURL']);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.appendValueInput('LIST')
.setCheck('Array')
.appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST);
.appendField(Blockly.Msg['LISTS_SET_INDEX_INPUT_IN_LIST']);
this.appendDummyInput()
.appendField(new Blockly.FieldDropdown(MODE), 'MODE')
.appendField('', 'SPACE');
this.appendDummyInput('AT');
this.appendValueInput('TO')
.appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO);
.appendField(Blockly.Msg['LISTS_SET_INDEX_INPUT_TO']);
this.setInputsInline(true);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP);
this.setTooltip(Blockly.Msg['LISTS_SET_INDEX_TOOLTIP']);
this.updateAt_(true);
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
@@ -539,33 +539,33 @@ Blockly.Blocks['lists_setIndex'] = {
switch (mode + ' ' + where) {
case 'SET FROM_START':
case 'SET FROM_END':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_SET_FROM'];
break;
case 'SET FIRST':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_SET_FIRST'];
break;
case 'SET LAST':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_SET_LAST'];
break;
case 'SET RANDOM':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_SET_RANDOM'];
break;
case 'INSERT FROM_START':
case 'INSERT FROM_END':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_INSERT_FROM'];
break;
case 'INSERT FIRST':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST'];
break;
case 'INSERT LAST':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_INSERT_LAST'];
break;
case 'INSERT RANDOM':
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM;
tooltip = Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM'];
break;
}
if (where == 'FROM_START' || where == 'FROM_END') {
tooltip += ' ' + Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP
tooltip += ' ' + Blockly.Msg['LISTS_INDEX_FROM_START_TOOLTIP']
.replace('%1',
thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0');
}
@@ -607,9 +607,9 @@ Blockly.Blocks['lists_setIndex'] = {
// Create either a value 'AT' input or a dummy input.
if (isAt) {
this.appendValueInput('AT').setCheck('Number');
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
if (Blockly.Msg['ORDINAL_NUMBER_SUFFIX']) {
this.appendDummyInput('ORDINAL')
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
.appendField(Blockly.Msg['ORDINAL_NUMBER_SUFFIX']);
}
} else {
this.appendDummyInput('AT');
@@ -643,32 +643,32 @@ Blockly.Blocks['lists_getSublist'] = {
init: function() {
this['WHERE_OPTIONS_1'] =
[
[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START, 'FROM_START'],
[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END, 'FROM_END'],
[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST, 'FIRST']
[Blockly.Msg['LISTS_GET_SUBLIST_START_FROM_START'], 'FROM_START'],
[Blockly.Msg['LISTS_GET_SUBLIST_START_FROM_END'], 'FROM_END'],
[Blockly.Msg['LISTS_GET_SUBLIST_START_FIRST'], 'FIRST']
];
this['WHERE_OPTIONS_2'] =
[
[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START, 'FROM_START'],
[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END, 'FROM_END'],
[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST, 'LAST']
[Blockly.Msg['LISTS_GET_SUBLIST_END_FROM_START'], 'FROM_START'],
[Blockly.Msg['LISTS_GET_SUBLIST_END_FROM_END'], 'FROM_END'],
[Blockly.Msg['LISTS_GET_SUBLIST_END_LAST'], 'LAST']
];
this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);
this.setColour(Blockly.Msg.LISTS_HUE);
this.setHelpUrl(Blockly.Msg['LISTS_GET_SUBLIST_HELPURL']);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.appendValueInput('LIST')
.setCheck('Array')
.appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);
.appendField(Blockly.Msg['LISTS_GET_SUBLIST_INPUT_IN_LIST']);
this.appendDummyInput('AT1');
this.appendDummyInput('AT2');
if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) {
if (Blockly.Msg['LISTS_GET_SUBLIST_TAIL']) {
this.appendDummyInput('TAIL')
.appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);
.appendField(Blockly.Msg['LISTS_GET_SUBLIST_TAIL']);
}
this.setInputsInline(true);
this.setOutput(true, 'Array');
this.updateAt_(1, true);
this.updateAt_(2, true);
this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP);
this.setTooltip(Blockly.Msg['LISTS_GET_SUBLIST_TOOLTIP']);
},
/**
* Create XML to represent whether there are 'AT' inputs.
@@ -710,9 +710,9 @@ Blockly.Blocks['lists_getSublist'] = {
// Create either a value 'AT' input or a dummy input.
if (isAt) {
this.appendValueInput('AT' + n).setCheck('Number');
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
if (Blockly.Msg['ORDINAL_NUMBER_SUFFIX']) {
this.appendDummyInput('ORDINAL' + n)
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
.appendField(Blockly.Msg['ORDINAL_NUMBER_SUFFIX']);
}
} else {
this.appendDummyInput('AT' + n);
@@ -740,7 +740,7 @@ Blockly.Blocks['lists_getSublist'] = {
this.moveInputBefore('ORDINAL1', 'AT2');
}
}
if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) {
if (Blockly.Msg['LISTS_GET_SUBLIST_TAIL']) {
this.moveInputBefore('TAIL', null);
}
}
@@ -753,23 +753,23 @@ Blockly.Blocks['lists_sort'] = {
*/
init: function() {
this.jsonInit({
"message0": Blockly.Msg.LISTS_SORT_TITLE,
"message0": Blockly.Msg['LISTS_SORT_TITLE'],
"args0": [
{
"type": "field_dropdown",
"name": "TYPE",
"options": [
[Blockly.Msg.LISTS_SORT_TYPE_NUMERIC, "NUMERIC"],
[Blockly.Msg.LISTS_SORT_TYPE_TEXT, "TEXT"],
[Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE, "IGNORE_CASE"]
[Blockly.Msg['LISTS_SORT_TYPE_NUMERIC'], "NUMERIC"],
[Blockly.Msg['LISTS_SORT_TYPE_TEXT'], "TEXT"],
[Blockly.Msg['LISTS_SORT_TYPE_IGNORECASE'], "IGNORE_CASE"]
]
},
{
"type": "field_dropdown",
"name": "DIRECTION",
"options": [
[Blockly.Msg.LISTS_SORT_ORDER_ASCENDING, "1"],
[Blockly.Msg.LISTS_SORT_ORDER_DESCENDING, "-1"]
[Blockly.Msg['LISTS_SORT_ORDER_ASCENDING'], "1"],
[Blockly.Msg['LISTS_SORT_ORDER_DESCENDING'], "-1"]
]
},
{
@@ -779,9 +779,9 @@ Blockly.Blocks['lists_sort'] = {
}
],
"output": "Array",
"colour": Blockly.Msg.LISTS_HUE,
"tooltip": Blockly.Msg.LISTS_SORT_TOOLTIP,
"helpUrl": Blockly.Msg.LISTS_SORT_HELPURL
"colour": Blockly.Msg['LISTS_HUE'],
"tooltip": Blockly.Msg['LISTS_SORT_TOOLTIP'],
"helpUrl": Blockly.Msg['LISTS_SORT_HELPURL']
});
}
};
@@ -796,28 +796,28 @@ Blockly.Blocks['lists_split'] = {
var thisBlock = this;
var dropdown = new Blockly.FieldDropdown(
[
[Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT, 'SPLIT'],
[Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST, 'JOIN']
[Blockly.Msg['LISTS_SPLIT_LIST_FROM_TEXT'], 'SPLIT'],
[Blockly.Msg['LISTS_SPLIT_TEXT_FROM_LIST'], 'JOIN']
],
function(newMode) {
thisBlock.updateType_(newMode);
});
this.setHelpUrl(Blockly.Msg.LISTS_SPLIT_HELPURL);
this.setColour(Blockly.Msg.LISTS_HUE);
this.setHelpUrl(Blockly.Msg['LISTS_SPLIT_HELPURL']);
this.setColour(Blockly.Msg['LISTS_HUE']);
this.appendValueInput('INPUT')
.setCheck('String')
.appendField(dropdown, 'MODE');
this.appendValueInput('DELIM')
.setCheck('String')
.appendField(Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER);
.appendField(Blockly.Msg['LISTS_SPLIT_WITH_DELIMITER']);
this.setInputsInline(true);
this.setOutput(true, 'Array');
this.setTooltip(function() {
var mode = thisBlock.getFieldValue('MODE');
if (mode == 'SPLIT') {
return Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT;
return Blockly.Msg['LISTS_SPLIT_TOOLTIP_SPLIT'];
} else if (mode == 'JOIN') {
return Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN;
return Blockly.Msg['LISTS_SPLIT_TOOLTIP_JOIN'];
}
throw 'Unknown mode: ' + mode;
});
+16 -49
View File
@@ -37,7 +37,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.LOGIC_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['LOGIC_HUE']. (2018 April 5)
*/
Blockly.Constants.Logic.HUE = 210;
@@ -133,10 +133,10 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
"options": [
["=", "EQ"],
["\u2260", "NEQ"],
["<", "LT"],
["\u2264", "LTE"],
[">", "GT"],
["\u2265", "GTE"]
["\u200F<", "LT"],
["\u200F\u2264", "LTE"],
["\u200F>", "GT"],
["\u200F\u2265", "GTE"]
]
},
{
@@ -445,13 +445,13 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = {
for (var i = 1; i <= this.elseifCount_; i++) {
this.appendValueInput('IF' + i)
.setCheck('Boolean')
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
.appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSEIF']);
this.appendStatementInput('DO' + i)
.appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
.appendField(Blockly.Msg['CONTROLS_IF_MSG_THEN']);
}
if (this.elseCount_) {
this.appendStatementInput('ELSE')
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE);
.appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSE']);
}
}
};
@@ -469,13 +469,13 @@ Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION = function() {
this.setTooltip(function() {
if (!this.elseifCount_ && !this.elseCount_) {
return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;
return Blockly.Msg['CONTROLS_IF_TOOLTIP_1'];
} else if (!this.elseifCount_ && this.elseCount_) {
return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;
return Blockly.Msg['CONTROLS_IF_TOOLTIP_2'];
} else if (this.elseifCount_ && !this.elseCount_) {
return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;
return Blockly.Msg['CONTROLS_IF_TOOLTIP_3'];
} else if (this.elseifCount_ && this.elseCount_) {
return Blockly.Msg.CONTROLS_IF_TOOLTIP_4;
return Blockly.Msg['CONTROLS_IF_TOOLTIP_4'];
}
return '';
}.bind(this));
@@ -485,35 +485,8 @@ Blockly.Extensions.register('controls_if_tooltip',
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
/**
* Corrects the logic_compare dropdown label with respect to language direction.
* @this Blockly.Block
* @package
*/
Blockly.Constants.Logic.fixLogicCompareRtlOpLabels =
function() {
var rtlOpLabels = {
'LT': '\u200F<\u200F',
'LTE': '\u200F\u2264\u200F',
'GT': '\u200F>\u200F',
'GTE': '\u200F\u2265\u200F'
};
var opDropdown = this.getField('OP');
if (opDropdown) {
var options = opDropdown.getOptions();
for (var i = 0; i < options.length; ++i) {
var tuple = options[i];
var op = tuple[1];
var rtlLabel = rtlOpLabels[op];
if (goog.isString(tuple[0]) && rtlLabel) {
// Replace LTR text label
tuple[0] = rtlLabel;
}
}
}
};
/**
* Adds dynamic type validation for the left and right sides of a logic_compare block.
* Adds dynamic type validation for the left and right sides of a logic_compare
* block.
* @mixin
* @augments Blockly.Block
* @package
@@ -564,19 +537,13 @@ Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = {
};
/**
* "logic_compare" extension function. Corrects direction of operators in the
* dropdown labels, and adds type left and right side type checking to
* "logic_compare" blocks.
* "logic_compare" extension function. Adds type left and right side type
* checking to "logic_compare" blocks.
* @this Blockly.Block
* @package
* @readonly
*/
Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION = function() {
// Fix operator labels in RTL.
if (this.RTL) {
Blockly.Constants.Logic.fixLogicCompareRtlOpLabels.apply(this);
}
// Add onchange handler to ensure types are compatible.
this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN);
};
+3 -3
View File
@@ -38,7 +38,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.LOOPS_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['LOOPS_HUE']. (2018 April 5)
*/
Blockly.Constants.Loops.HUE = 120;
@@ -266,7 +266,7 @@ Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = {
if (!this.isCollapsed() && varName != null) {
var option = {enabled: true};
option.text =
Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', varName);
Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace('%1', varName);
var xmlField = Blockly.Variables.generateVariableFieldDom(variable);
var xmlBlock = goog.dom.createDom('block', null, xmlField);
xmlBlock.setAttribute('type', 'variables_get');
@@ -330,7 +330,7 @@ Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = {
this.setDisabled(false);
}
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
this.setWarningText(Blockly.Msg['CONTROLS_FLOW_STATEMENTS_WARNING']);
if (!this.isInFlyout && !this.getInheritedDisabled()) {
this.setDisabled(true);
}
+1 -1
View File
@@ -38,7 +38,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.MATH_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['MATH_HUE']. (2018 April 5)
*/
Blockly.Constants.Math.HUE = 230;
+42 -42
View File
@@ -40,19 +40,19 @@ Blockly.Blocks['procedures_defnoreturn'] = {
Blockly.Procedures.rename);
nameField.setSpellcheck(false);
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE)
.appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_TITLE'])
.appendField(nameField, 'NAME')
.appendField('', 'PARAMS');
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
if ((this.workspace.options.comments ||
(this.workspace.options.parentWorkspace &&
this.workspace.options.parentWorkspace.options.comments)) &&
Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT) {
this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT);
Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']) {
this.setCommentText(Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']);
}
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
this.setTooltip(Blockly.Msg['PROCEDURES_DEFNORETURN_TOOLTIP']);
this.setHelpUrl(Blockly.Msg['PROCEDURES_DEFNORETURN_HELPURL']);
this.arguments_ = [];
this.argumentVarModels_ = [];
this.setStatements_(true);
@@ -69,7 +69,7 @@ Blockly.Blocks['procedures_defnoreturn'] = {
}
if (hasStatements) {
this.appendStatementInput('STACK')
.appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);
.appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_DO']);
if (this.getInput('RETURN')) {
this.moveInputBefore('STACK', 'RETURN');
}
@@ -96,14 +96,14 @@ Blockly.Blocks['procedures_defnoreturn'] = {
hash['arg_' + this.arguments_[i].toLowerCase()] = true;
}
if (badArg) {
this.setWarningText(Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING);
this.setWarningText(Blockly.Msg['PROCEDURES_DEF_DUPLICATE_WARNING']);
} else {
this.setWarningText(null);
}
// Merge the arguments into a human-readable list.
var paramString = '';
if (this.arguments_.length) {
paramString = Blockly.Msg.PROCEDURES_BEFORE_PARAMS +
paramString = Blockly.Msg['PROCEDURES_BEFORE_PARAMS'] +
' ' + this.arguments_.join(', ');
}
// The params field is deterministic based on the mutation,
@@ -356,7 +356,7 @@ Blockly.Blocks['procedures_defnoreturn'] = {
// Add option to create caller.
var option = {enabled: true};
var name = this.getFieldValue('NAME');
option.text = Blockly.Msg.PROCEDURES_CREATE_DO.replace('%1', name);
option.text = Blockly.Msg['PROCEDURES_CREATE_DO'].replace('%1', name);
var xmlMutation = goog.dom.createDom('mutation');
xmlMutation.setAttribute('name', name);
for (var i = 0; i < this.arguments_.length; i++) {
@@ -375,7 +375,7 @@ Blockly.Blocks['procedures_defnoreturn'] = {
var option = {enabled: true};
var argVar = this.argumentVarModels_[i];
var name = argVar.name;
option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', name);
option.text = Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace('%1', name);
var xmlField = Blockly.Variables.generateVariableFieldDom(argVar);
var xmlBlock = goog.dom.createDom('block', null, xmlField);
@@ -398,22 +398,22 @@ Blockly.Blocks['procedures_defreturn'] = {
Blockly.Procedures.rename);
nameField.setSpellcheck(false);
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE)
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_TITLE'])
.appendField(nameField, 'NAME')
.appendField('', 'PARAMS');
this.appendValueInput('RETURN')
.setAlign(Blockly.ALIGN_RIGHT)
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
if ((this.workspace.options.comments ||
(this.workspace.options.parentWorkspace &&
this.workspace.options.parentWorkspace.options.comments)) &&
Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT) {
this.setCommentText(Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT);
Blockly.Msg['PROCEDURES_DEFRETURN_COMMENT']) {
this.setCommentText(Blockly.Msg['PROCEDURES_DEFRETURN_COMMENT']);
}
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
this.setTooltip(Blockly.Msg['PROCEDURES_DEFRETURN_TOOLTIP']);
this.setHelpUrl(Blockly.Msg['PROCEDURES_DEFRETURN_HELPURL']);
this.arguments_ = [];
this.argumentVarModels_ = [];
this.setStatements_(true);
@@ -452,13 +452,13 @@ Blockly.Blocks['procedures_mutatorcontainer'] = {
*/
init: function() {
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);
.appendField(Blockly.Msg['PROCEDURES_MUTATORCONTAINER_TITLE']);
this.appendStatementInput('STACK');
this.appendDummyInput('STATEMENT_INPUT')
.appendField(Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS)
.appendField(Blockly.Msg['PROCEDURES_ALLOW_STATEMENTS'])
.appendField(new Blockly.FieldCheckbox('TRUE'), 'STATEMENTS');
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
this.setTooltip(Blockly.Msg['PROCEDURES_MUTATORCONTAINER_TOOLTIP']);
this.contextMenu = false;
}
};
@@ -480,12 +480,12 @@ Blockly.Blocks['procedures_mutatorarg'] = {
field.showEditor_ = newShowEditorFn;
this.appendDummyInput()
.appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE)
.appendField(Blockly.Msg['PROCEDURES_MUTATORARG_TITLE'])
.appendField(field, 'NAME');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
this.setTooltip(Blockly.Msg['PROCEDURES_MUTATORARG_TOOLTIP']);
this.contextMenu = false;
// Create the default variable when we drag the block in from the flyout.
@@ -557,9 +557,9 @@ Blockly.Blocks['procedures_callnoreturn'] = {
.appendField(this.id, 'NAME');
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
// Tooltip is set in renameProcedure.
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);
this.setHelpUrl(Blockly.Msg['PROCEDURES_CALLNORETURN_HELPURL']);
this.arguments_ = [];
this.argumentVarModels_ = [];
this.quarkConnections_ = {};
@@ -585,8 +585,8 @@ Blockly.Blocks['procedures_callnoreturn'] = {
if (Blockly.Names.equals(oldName, this.getProcedureCall())) {
this.setFieldValue(newName, 'NAME');
var baseMsg = this.outputConnection ?
Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP :
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP;
Blockly.Msg['PROCEDURES_CALLRETURN_TOOLTIP'] :
Blockly.Msg['PROCEDURES_CALLNORETURN_TOOLTIP'];
this.setTooltip(baseMsg.replace('%1', newName));
}
},
@@ -726,7 +726,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
if (topRow) {
if (this.arguments_.length) {
if (!this.getField('WITH')) {
topRow.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS, 'WITH');
topRow.appendField(Blockly.Msg['PROCEDURES_CALL_BEFORE_PARAMS'], 'WITH');
topRow.init();
}
} else {
@@ -851,7 +851,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
*/
customContextMenu: function(options) {
var option = {enabled: true};
option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;
option.text = Blockly.Msg['PROCEDURES_HIGHLIGHT_DEF'];
var name = this.getProcedureCall();
var workspace = this.workspace;
option.callback = function() {
@@ -875,9 +875,9 @@ Blockly.Blocks['procedures_callreturn'] = {
this.appendDummyInput('TOPROW')
.appendField('', 'NAME');
this.setOutput(true);
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
// Tooltip is set in domToMutation.
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);
this.setHelpUrl(Blockly.Msg['PROCEDURES_CALLRETURN_HELPURL']);
this.arguments_ = [];
this.quarkConnections_ = {};
this.quarkIds_ = null;
@@ -904,15 +904,15 @@ Blockly.Blocks['procedures_ifreturn'] = {
init: function() {
this.appendValueInput('CONDITION')
.setCheck('Boolean')
.appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
.appendField(Blockly.Msg['CONTROLS_IF_MSG_IF']);
this.appendValueInput('VALUE')
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
this.setInputsInline(true);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setColour(Blockly.Msg.PROCEDURES_HUE);
this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);
this.setHelpUrl(Blockly.Msg.PROCEDURES_IFRETURN_HELPURL);
this.setColour(Blockly.Msg['PROCEDURES_HUE']);
this.setTooltip(Blockly.Msg['PROCEDURES_IFRETURN_TOOLTIP']);
this.setHelpUrl(Blockly.Msg['PROCEDURES_IFRETURN_HELPURL']);
this.hasReturnValue_ = true;
},
/**
@@ -936,7 +936,7 @@ Blockly.Blocks['procedures_ifreturn'] = {
if (!this.hasReturnValue_) {
this.removeInput('VALUE');
this.appendDummyInput('VALUE')
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
}
},
/**
@@ -964,13 +964,13 @@ Blockly.Blocks['procedures_ifreturn'] = {
if (block.type == 'procedures_defnoreturn' && this.hasReturnValue_) {
this.removeInput('VALUE');
this.appendDummyInput('VALUE')
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
this.hasReturnValue_ = false;
} else if (block.type == 'procedures_defreturn' &&
!this.hasReturnValue_) {
this.removeInput('VALUE');
this.appendValueInput('VALUE')
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
.appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']);
this.hasReturnValue_ = true;
}
this.setWarningText(null);
@@ -978,7 +978,7 @@ Blockly.Blocks['procedures_ifreturn'] = {
this.setDisabled(false);
}
} else {
this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING);
this.setWarningText(Blockly.Msg['PROCEDURES_IFRETURN_WARNING']);
if (!this.isInFlyout && !this.getInheritedDisabled()) {
this.setDisabled(true);
}
+67 -67
View File
@@ -33,7 +33,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.TEXTS_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['TEXTS_HUE']. (2018 April 5)
*/
Blockly.Constants.Text.HUE = 160;
@@ -211,31 +211,31 @@ Blockly.Blocks['text_getSubstring'] = {
*/
init: function() {
this['WHERE_OPTIONS_1'] = [
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START, 'FROM_START'],
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END, 'FROM_END'],
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST, 'FIRST']
[Blockly.Msg['TEXT_GET_SUBSTRING_START_FROM_START'], 'FROM_START'],
[Blockly.Msg['TEXT_GET_SUBSTRING_START_FROM_END'], 'FROM_END'],
[Blockly.Msg['TEXT_GET_SUBSTRING_START_FIRST'], 'FIRST']
];
this['WHERE_OPTIONS_2'] = [
[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START, 'FROM_START'],
[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END, 'FROM_END'],
[Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST, 'LAST']
[Blockly.Msg['TEXT_GET_SUBSTRING_END_FROM_START'], 'FROM_START'],
[Blockly.Msg['TEXT_GET_SUBSTRING_END_FROM_END'], 'FROM_END'],
[Blockly.Msg['TEXT_GET_SUBSTRING_END_LAST'], 'LAST']
];
this.setHelpUrl(Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL);
this.setColour(Blockly.Msg.TEXTS_HUE);
this.setHelpUrl(Blockly.Msg['TEXT_GET_SUBSTRING_HELPURL']);
this.setColour(Blockly.Msg['TEXTS_HUE']);
this.appendValueInput('STRING')
.setCheck('String')
.appendField(Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT);
.appendField(Blockly.Msg['TEXT_GET_SUBSTRING_INPUT_IN_TEXT']);
this.appendDummyInput('AT1');
this.appendDummyInput('AT2');
if (Blockly.Msg.TEXT_GET_SUBSTRING_TAIL) {
if (Blockly.Msg['TEXT_GET_SUBSTRING_TAIL']) {
this.appendDummyInput('TAIL')
.appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);
.appendField(Blockly.Msg['TEXT_GET_SUBSTRING_TAIL']);
}
this.setInputsInline(true);
this.setOutput(true, 'String');
this.updateAt_(1, true);
this.updateAt_(2, true);
this.setTooltip(Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP);
this.setTooltip(Blockly.Msg['TEXT_GET_SUBSTRING_TOOLTIP']);
},
/**
* Create XML to represent whether there are 'AT' inputs.
@@ -277,18 +277,18 @@ Blockly.Blocks['text_getSubstring'] = {
// Create either a value 'AT' input or a dummy input.
if (isAt) {
this.appendValueInput('AT' + n).setCheck('Number');
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
if (Blockly.Msg['ORDINAL_NUMBER_SUFFIX']) {
this.appendDummyInput('ORDINAL' + n)
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
.appendField(Blockly.Msg['ORDINAL_NUMBER_SUFFIX']);
}
} else {
this.appendDummyInput('AT' + n);
}
// Move tail, if present, to end of block.
if (n == 2 && Blockly.Msg.TEXT_GET_SUBSTRING_TAIL) {
if (n == 2 && Blockly.Msg['TEXT_GET_SUBSTRING_TAIL']) {
this.removeInput('TAIL', true);
this.appendDummyInput('TAIL')
.appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);
.appendField(Blockly.Msg['TEXT_GET_SUBSTRING_TAIL']);
}
var menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n],
function(value) {
@@ -324,17 +324,17 @@ Blockly.Blocks['text_changeCase'] = {
*/
init: function() {
var OPERATORS = [
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE, 'UPPERCASE'],
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE, 'LOWERCASE'],
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE, 'TITLECASE']
[Blockly.Msg['TEXT_CHANGECASE_OPERATOR_UPPERCASE'], 'UPPERCASE'],
[Blockly.Msg['TEXT_CHANGECASE_OPERATOR_LOWERCASE'], 'LOWERCASE'],
[Blockly.Msg['TEXT_CHANGECASE_OPERATOR_TITLECASE'], 'TITLECASE']
];
this.setHelpUrl(Blockly.Msg.TEXT_CHANGECASE_HELPURL);
this.setColour(Blockly.Msg.TEXTS_HUE);
this.setHelpUrl(Blockly.Msg['TEXT_CHANGECASE_HELPURL']);
this.setColour(Blockly.Msg['TEXTS_HUE']);
this.appendValueInput('TEXT')
.setCheck('String')
.appendField(new Blockly.FieldDropdown(OPERATORS), 'CASE');
this.setOutput(true, 'String');
this.setTooltip(Blockly.Msg.TEXT_CHANGECASE_TOOLTIP);
this.setTooltip(Blockly.Msg['TEXT_CHANGECASE_TOOLTIP']);
}
};
@@ -345,17 +345,17 @@ Blockly.Blocks['text_trim'] = {
*/
init: function() {
var OPERATORS = [
[Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH, 'BOTH'],
[Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT, 'LEFT'],
[Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT, 'RIGHT']
[Blockly.Msg['TEXT_TRIM_OPERATOR_BOTH'], 'BOTH'],
[Blockly.Msg['TEXT_TRIM_OPERATOR_LEFT'], 'LEFT'],
[Blockly.Msg['TEXT_TRIM_OPERATOR_RIGHT'], 'RIGHT']
];
this.setHelpUrl(Blockly.Msg.TEXT_TRIM_HELPURL);
this.setColour(Blockly.Msg.TEXTS_HUE);
this.setHelpUrl(Blockly.Msg['TEXT_TRIM_HELPURL']);
this.setColour(Blockly.Msg['TEXTS_HUE']);
this.appendValueInput('TEXT')
.setCheck('String')
.appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE');
this.setOutput(true, 'String');
this.setTooltip(Blockly.Msg.TEXT_TRIM_TOOLTIP);
this.setTooltip(Blockly.Msg['TEXT_TRIM_TOOLTIP']);
}
};
@@ -366,7 +366,7 @@ Blockly.Blocks['text_print'] = {
*/
init: function() {
this.jsonInit({
"message0": Blockly.Msg.TEXT_PRINT_TITLE,
"message0": Blockly.Msg['TEXT_PRINT_TITLE'],
"args0": [
{
"type": "input_value",
@@ -375,9 +375,9 @@ Blockly.Blocks['text_print'] = {
],
"previousStatement": null,
"nextStatement": null,
"colour": Blockly.Msg.TEXTS_HUE,
"tooltip": Blockly.Msg.TEXT_PRINT_TOOLTIP,
"helpUrl": Blockly.Msg.TEXT_PRINT_HELPURL
"colour": Blockly.Msg['TEXTS_HUE'],
"tooltip": Blockly.Msg['TEXT_PRINT_TOOLTIP'],
"helpUrl": Blockly.Msg['TEXT_PRINT_HELPURL']
});
}
};
@@ -389,11 +389,11 @@ Blockly.Blocks['text_prompt_ext'] = {
*/
init: function() {
var TYPES = [
[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT, 'TEXT'],
[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER, 'NUMBER']
[Blockly.Msg['TEXT_PROMPT_TYPE_TEXT'], 'TEXT'],
[Blockly.Msg['TEXT_PROMPT_TYPE_NUMBER'], 'NUMBER']
];
this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);
this.setColour(Blockly.Msg.TEXTS_HUE);
this.setHelpUrl(Blockly.Msg['TEXT_PROMPT_HELPURL']);
this.setColour(Blockly.Msg['TEXTS_HUE']);
// Assign 'this' to a variable for use in the closures below.
var thisBlock = this;
var dropdown = new Blockly.FieldDropdown(TYPES, function(newOp) {
@@ -404,8 +404,8 @@ Blockly.Blocks['text_prompt_ext'] = {
this.setOutput(true, 'String');
this.setTooltip(function() {
return (thisBlock.getFieldValue('TYPE') == 'TEXT') ?
Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT :
Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
Blockly.Msg['TEXT_PROMPT_TOOLTIP_TEXT'] :
Blockly.Msg['TEXT_PROMPT_TOOLTIP_NUMBER'];
});
},
/**
@@ -446,14 +446,14 @@ Blockly.Blocks['text_prompt'] = {
init: function() {
this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);
var TYPES = [
[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT, 'TEXT'],
[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER, 'NUMBER']
[Blockly.Msg['TEXT_PROMPT_TYPE_TEXT'], 'TEXT'],
[Blockly.Msg['TEXT_PROMPT_TYPE_NUMBER'], 'NUMBER']
];
// Assign 'this' to a variable for use in the closures below.
var thisBlock = this;
this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);
this.setColour(Blockly.Msg.TEXTS_HUE);
this.setHelpUrl(Blockly.Msg['TEXT_PROMPT_HELPURL']);
this.setColour(Blockly.Msg['TEXTS_HUE']);
var dropdown = new Blockly.FieldDropdown(TYPES, function(newOp) {
thisBlock.updateType_(newOp);
});
@@ -465,8 +465,8 @@ Blockly.Blocks['text_prompt'] = {
this.setOutput(true, 'String');
this.setTooltip(function() {
return (thisBlock.getFieldValue('TYPE') == 'TEXT') ?
Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT :
Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
Blockly.Msg['TEXT_PROMPT_TOOLTIP_TEXT'] :
Blockly.Msg['TEXT_PROMPT_TOOLTIP_NUMBER'];
});
},
updateType_: Blockly.Blocks['text_prompt_ext'].updateType_,
@@ -481,7 +481,7 @@ Blockly.Blocks['text_count'] = {
*/
init: function() {
this.jsonInit({
"message0": Blockly.Msg.TEXT_COUNT_MESSAGE0,
"message0": Blockly.Msg['TEXT_COUNT_MESSAGE0'],
"args0": [
{
"type": "input_value",
@@ -496,9 +496,9 @@ Blockly.Blocks['text_count'] = {
],
"output": "Number",
"inputsInline": true,
"colour": Blockly.Msg.TEXTS_HUE,
"tooltip": Blockly.Msg.TEXT_COUNT_TOOLTIP,
"helpUrl": Blockly.Msg.TEXT_COUNT_HELPURL
"colour": Blockly.Msg['TEXTS_HUE'],
"tooltip": Blockly.Msg['TEXT_COUNT_TOOLTIP'],
"helpUrl": Blockly.Msg['TEXT_COUNT_HELPURL']
});
}
};
@@ -510,7 +510,7 @@ Blockly.Blocks['text_replace'] = {
*/
init: function() {
this.jsonInit({
"message0": Blockly.Msg.TEXT_REPLACE_MESSAGE0,
"message0": Blockly.Msg['TEXT_REPLACE_MESSAGE0'],
"args0": [
{
"type": "input_value",
@@ -530,9 +530,9 @@ Blockly.Blocks['text_replace'] = {
],
"output": "String",
"inputsInline": true,
"colour": Blockly.Msg.TEXTS_HUE,
"tooltip": Blockly.Msg.TEXT_REPLACE_TOOLTIP,
"helpUrl": Blockly.Msg.TEXT_REPLACE_HELPURL
"colour": Blockly.Msg['TEXTS_HUE'],
"tooltip": Blockly.Msg['TEXT_REPLACE_TOOLTIP'],
"helpUrl": Blockly.Msg['TEXT_REPLACE_HELPURL']
});
}
};
@@ -544,7 +544,7 @@ Blockly.Blocks['text_reverse'] = {
*/
init: function() {
this.jsonInit({
"message0": Blockly.Msg.TEXT_REVERSE_MESSAGE0,
"message0": Blockly.Msg['TEXT_REVERSE_MESSAGE0'],
"args0": [
{
"type": "input_value",
@@ -554,9 +554,9 @@ Blockly.Blocks['text_reverse'] = {
],
"output": "String",
"inputsInline": true,
"colour": Blockly.Msg.TEXTS_HUE,
"tooltip": Blockly.Msg.TEXT_REVERSE_TOOLTIP,
"helpUrl": Blockly.Msg.TEXT_REVERSE_HELPURL
"colour": Blockly.Msg['TEXTS_HUE'],
"tooltip": Blockly.Msg['TEXT_REVERSE_TOOLTIP'],
"helpUrl": Blockly.Msg['TEXT_REVERSE_HELPURL']
});
}
};
@@ -626,7 +626,7 @@ Blockly.Constants.Text.QUOTE_IMAGE_MIXIN = {
* @this Blockly.Block
*/
newQuote_: function(open) {
var isLeft = this.RTL? !open : open;
var isLeft = this.RTL ? !open : open;
var dataUri = isLeft ?
this.QUOTE_IMAGE_LEFT_DATAURI :
this.QUOTE_IMAGE_RIGHT_DATAURI;
@@ -753,7 +753,7 @@ Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = {
if (!this.getInput('ADD' + i)) {
var input = this.appendValueInput('ADD' + i);
if (i == 0) {
input.appendField(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH);
input.appendField(Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH']);
}
}
}
@@ -792,7 +792,7 @@ Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION = function() {
// Assign 'this' to a variable for use in the tooltip closure below.
var thisBlock = this;
this.setTooltip(function() {
return Blockly.Msg.TEXT_INDEXOF_TOOLTIP.replace('%1',
return Blockly.Msg['TEXT_INDEXOF_TOOLTIP'].replace('%1',
thisBlock.workspace.options.oneBasedIndex ? '0' : '-1');
});
};
@@ -838,15 +838,15 @@ Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = {
// Create either a value 'AT' input or a dummy input.
if (isAt) {
this.appendValueInput('AT').setCheck('Number');
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
if (Blockly.Msg['ORDINAL_NUMBER_SUFFIX']) {
this.appendDummyInput('ORDINAL')
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
.appendField(Blockly.Msg['ORDINAL_NUMBER_SUFFIX']);
}
}
if (Blockly.Msg.TEXT_CHARAT_TAIL) {
if (Blockly.Msg['TEXT_CHARAT_TAIL']) {
this.removeInput('TAIL', true);
this.appendDummyInput('TAIL')
.appendField(Blockly.Msg.TEXT_CHARAT_TAIL);
.appendField(Blockly.Msg['TEXT_CHARAT_TAIL']);
}
this.isAt_ = isAt;
@@ -875,11 +875,11 @@ Blockly.Constants.Text.TEXT_CHARAT_EXTENSION = function() {
var thisBlock = this;
this.setTooltip(function() {
var where = thisBlock.getFieldValue('WHERE');
var tooltip = Blockly.Msg.TEXT_CHARAT_TOOLTIP;
var tooltip = Blockly.Msg['TEXT_CHARAT_TOOLTIP'];
if (where == 'FROM_START' || where == 'FROM_END') {
var msg = (where == 'FROM_START') ?
Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP :
Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP;
Blockly.Msg['LISTS_INDEX_FROM_START_TOOLTIP'] :
Blockly.Msg['LISTS_INDEX_FROM_END_TOOLTIP'];
if (msg) {
tooltip += ' ' + msg.replace('%1',
thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0');
+3 -3
View File
@@ -38,7 +38,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.VARIABLES_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['VARIABLES_HUE']. (2018 April 5)
*/
Blockly.Constants.Variables.HUE = 330;
@@ -106,10 +106,10 @@ Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
// Getter blocks have the option to create a setter block, and vice versa.
if (this.type == 'variables_get') {
var opposite_type = 'variables_set';
var contextMenuMsg = Blockly.Msg.VARIABLES_GET_CREATE_SET;
var contextMenuMsg = Blockly.Msg['VARIABLES_GET_CREATE_SET'];
} else {
var opposite_type = 'variables_get';
var contextMenuMsg = Blockly.Msg.VARIABLES_SET_CREATE_GET;
var contextMenuMsg = Blockly.Msg['VARIABLES_SET_CREATE_GET'];
}
var option = {enabled: this.workspace.remainingCapacity() > 0};
+3 -3
View File
@@ -37,7 +37,7 @@ goog.require('Blockly');
/**
* Unused constant for the common HSV hue for all blocks in this category.
* @deprecated Use Blockly.Msg.VARIABLES_DYNAMIC_HUE. (2018 April 5)
* @deprecated Use Blockly.Msg['VARIABLES_DYNAMIC_HUE']. (2018 April 5)
*/
Blockly.Constants.VariablesDynamic.HUE = 310;
@@ -104,10 +104,10 @@ Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MI
var contextMenuMsg;
if (this.type == 'variables_get_dynamic') {
opposite_type = 'variables_set_dynamic';
contextMenuMsg = Blockly.Msg.VARIABLES_GET_CREATE_SET;
contextMenuMsg = Blockly.Msg['VARIABLES_GET_CREATE_SET'];
} else {
opposite_type = 'variables_get_dynamic';
contextMenuMsg = Blockly.Msg.VARIABLES_SET_CREATE_GET;
contextMenuMsg = Blockly.Msg['VARIABLES_SET_CREATE_GET'];
}
var option = {enabled: this.workspace.remainingCapacity() > 0};
+2 -3
View File
@@ -41,7 +41,7 @@ Blockly.Blocks.lists_split={init:function(){var a=this,b=new Blockly.FieldDropdo
this.getFieldValue("MODE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("mode"))}};Blockly.Blocks.logic={};Blockly.Constants.Logic={};Blockly.Constants.Logic.HUE=210;
Blockly.defineBlocksWithJsonArray([{type:"logic_boolean",message0:"%1",args0:[{type:"field_dropdown",name:"BOOL",options:[["%{BKY_LOGIC_BOOLEAN_TRUE}","TRUE"],["%{BKY_LOGIC_BOOLEAN_FALSE}","FALSE"]]}],output:"Boolean",colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_BOOLEAN_TOOLTIP}",helpUrl:"%{BKY_LOGIC_BOOLEAN_HELPURL}"},{type:"controls_if",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",
name:"DO0"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",mutator:"controls_if_mutator",extensions:["controls_if_tooltip"]},{type:"controls_ifelse",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",name:"DO0"}],message2:"%{BKY_CONTROLS_IF_MSG_ELSE} %1",args2:[{type:"input_statement",name:"ELSE"}],previousStatement:null,nextStatement:null,
colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKYCONTROLS_IF_TOOLTIP_2}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",extensions:["controls_if_tooltip"]},{type:"logic_compare",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A"},{type:"field_dropdown",name:"OP",options:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:"Boolean",colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",extensions:["logic_compare",
colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKYCONTROLS_IF_TOOLTIP_2}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",extensions:["controls_if_tooltip"]},{type:"logic_compare",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A"},{type:"field_dropdown",name:"OP",options:[["=","EQ"],["\u2260","NEQ"],["\u200f<","LT"],["\u200f\u2264","LTE"],["\u200f>","GT"],["\u200f\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:"Boolean",colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",extensions:["logic_compare",
"logic_op_tooltip"]},{type:"logic_operation",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:"Boolean"},{type:"field_dropdown",name:"OP",options:[["%{BKY_LOGIC_OPERATION_AND}","AND"],["%{BKY_LOGIC_OPERATION_OR}","OR"]]},{type:"input_value",name:"B",check:"Boolean"}],inputsInline:!0,output:"Boolean",colour:"%{BKY_LOGIC_HUE}",helpUrl:"%{BKY_LOGIC_OPERATION_HELPURL}",extensions:["logic_op_tooltip"]},{type:"logic_negate",message0:"%{BKY_LOGIC_NEGATE_TITLE}",args0:[{type:"input_value",name:"BOOL",
check:"Boolean"}],output:"Boolean",colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_NEGATE_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NEGATE_HELPURL}"},{type:"logic_null",message0:"%{BKY_LOGIC_NULL}",output:null,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_NULL_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NULL_HELPURL}"},{type:"logic_ternary",message0:"%{BKY_LOGIC_TERNARY_CONDITION} %1",args0:[{type:"input_value",name:"IF",check:"Boolean"}],message1:"%{BKY_LOGIC_TERNARY_IF_TRUE} %1",args1:[{type:"input_value",name:"THEN"}],
message2:"%{BKY_LOGIC_TERNARY_IF_FALSE} %1",args2:[{type:"input_value",name:"ELSE"}],output:null,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_LOGIC_TERNARY_TOOLTIP}",helpUrl:"%{BKY_LOGIC_TERNARY_HELPURL}",extensions:["logic_ternary"]}]);
@@ -54,9 +54,8 @@ break;case "controls_if_else":this.elseCount_++;d=b.statementConnection_;break;d
b);a.valueConnection_=c&&c.connection.targetConnection;a.statementConnection_=d&&d.connection.targetConnection;b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw"Unknown block type.";}a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.getInput("ELSE")&&this.removeInput("ELSE");for(var a=1;this.getInput("IF"+a);)this.removeInput("IF"+a),this.removeInput("DO"+a),a++;for(a=1;a<=this.elseifCount_;a++)this.appendValueInput("IF"+
a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);this.elseCount_&&this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)}};Blockly.Extensions.registerMutator("controls_if_mutator",Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN,null,["controls_if_elseif","controls_if_else"]);
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION=function(){this.setTooltip(function(){if(this.elseifCount_||this.elseCount_){if(!this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;if(this.elseifCount_&&!this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;if(this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_4}else return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;return""}.bind(this))};Blockly.Extensions.register("controls_if_tooltip",Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
Blockly.Constants.Logic.fixLogicCompareRtlOpLabels=function(){var a={LT:"\u200f<\u200f",LTE:"\u200f\u2264\u200f",GT:"\u200f>\u200f",GTE:"\u200f\u2265\u200f"},b=this.getField("OP");if(b){b=b.getOptions();for(var c=0;c<b.length;++c){var d=b[c],e=a[d[1]];goog.isString(d[0])&&e&&(d[0]=e)}}};
Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN={onchange:function(a){this.prevBlocks_||(this.prevBlocks_=[null,null]);var b=this.getInputTargetBlock("A"),c=this.getInputTargetBlock("B");b&&c&&!b.outputConnection.checkType_(c.outputConnection)&&(Blockly.Events.setGroup(a.group),a=this.prevBlocks_[0],a!==b&&(b.unplug(),a&&!a.isShadow()&&this.getInput("A").connection.connect(a.outputConnection)),b=this.prevBlocks_[1],b!==c&&(c.unplug(),b&&!b.isShadow()&&this.getInput("B").connection.connect(b.outputConnection)),
this.bumpNeighbours_(),Blockly.Events.setGroup(!1));this.prevBlocks_[0]=this.getInputTargetBlock("A");this.prevBlocks_[1]=this.getInputTargetBlock("B")}};Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION=function(){this.RTL&&Blockly.Constants.Logic.fixLogicCompareRtlOpLabels.apply(this);this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN)};Blockly.Extensions.register("logic_compare",Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION);
this.bumpNeighbours_(),Blockly.Events.setGroup(!1));this.prevBlocks_[0]=this.getInputTargetBlock("A");this.prevBlocks_[1]=this.getInputTargetBlock("B")}};Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION=function(){this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN)};Blockly.Extensions.register("logic_compare",Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION);
Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN={prevParentConnection_:null,onchange:function(a){var b=this.getInputTargetBlock("THEN"),c=this.getInputTargetBlock("ELSE"),d=this.outputConnection.targetConnection;if((b||c)&&d)for(var e=0;2>e;e++){var f=1==e?b:c;f&&!f.outputConnection.checkType_(d)&&(Blockly.Events.setGroup(a.group),d===this.prevParentConnection_?(this.unplug(),d.getSourceBlock().bumpNeighbours_()):(f.unplug(),f.bumpNeighbours_()),Blockly.Events.setGroup(!1))}this.prevParentConnection_=
d}};Blockly.Extensions.registerMixin("logic_ternary",Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN);Blockly.Blocks.loops={};Blockly.Constants.Loops={};Blockly.Constants.Loops.HUE=120;
Blockly.defineBlocksWithJsonArray([{type:"controls_repeat_ext",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"input_value",name:"TIMES",check:"Number"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,colour:"%{BKY_LOOPS_HUE}",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_repeat",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"field_number",name:"TIMES",
+44 -20
View File
@@ -87,13 +87,13 @@ Blockly.Block = function(workspace, prototypeName, opt_id) {
/**
* @type {Blockly.Block}
* @private
* @protected
*/
this.parentBlock_ = null;
/**
* @type {!Array.<!Blockly.Block>}
* @private
* @protected
*/
this.childBlocks_ = [];
@@ -123,7 +123,7 @@ Blockly.Block = function(workspace, prototypeName, opt_id) {
/**
* @type {boolean}
* @private
* @protected
*/
this.collapsed_ = false;
@@ -259,6 +259,10 @@ Blockly.Block.prototype.dispose = function(healStack) {
// well as corruption of the connection database. Therefore we must
// methodically step through the blocks and carefully disassemble them.
if (Blockly.selected == this) {
Blockly.selected = null;
}
// First, dispose of all my children.
for (var i = this.childBlocks_.length - 1; i >= 0; i--) {
this.childBlocks_[i].dispose(false);
@@ -365,7 +369,7 @@ Blockly.Block.prototype.getConnections_ = function(_all) {
* @return {Blockly.Connection} The last next connection on the stack, or null.
* @package
*/
Blockly.Block.prototype.lastConnectionInStack_ = function() {
Blockly.Block.prototype.lastConnectionInStack = function() {
var nextConnection = this.nextConnection;
while (nextConnection) {
var nextBlock = nextConnection.targetBlock();
@@ -382,7 +386,7 @@ Blockly.Block.prototype.lastConnectionInStack_ = function() {
/**
* Bump unconnected blocks out of alignment. Two blocks which aren't actually
* connected should not coincidentally line up on screen.
* @private
* @protected
*/
Blockly.Block.prototype.bumpNeighbours_ = function() {
console.warn('Not expected to reach this bumpNeighbours_ function. The ' +
@@ -457,12 +461,30 @@ Blockly.Block.prototype.getRootBlock = function() {
/**
* Find all the blocks that are directly nested inside this one.
* Includes value and block inputs, as well as any following statement.
* Includes value and statement inputs, as well as any following statement.
* Excludes any connection on an output tab or any preceding statement.
* Blocks are optionally sorted by position; top to bottom.
* @param {boolean} ordered Sort the list if true.
* @return {!Array.<!Blockly.Block>} Array of blocks.
*/
Blockly.Block.prototype.getChildren = function() {
return this.childBlocks_;
Blockly.Block.prototype.getChildren = function(ordered) {
if (!ordered) {
return this.childBlocks_;
}
var blocks = [];
for (var i = 0, input; input = this.inputList[i]; i++) {
if (input.connection) {
var child = input.connection.targetBlock();
if (child) {
blocks.push(child);
}
}
}
var next = this.getNextBlock();
if (next) {
blocks.push(next);
}
return blocks;
};
/**
@@ -504,14 +526,17 @@ Blockly.Block.prototype.setParent = function(newParent) {
/**
* Find all the blocks that are directly or indirectly nested inside this one.
* Includes this block in the list.
* Includes value and block inputs, as well as any following statements.
* Includes value and statement inputs, as well as any following statements.
* Excludes any connection on an output tab or any preceding statements.
* Blocks are optionally sorted by position; top to bottom.
* @param {boolean} ordered Sort the list if true.
* @return {!Array.<!Blockly.Block>} Flattened array of blocks.
*/
Blockly.Block.prototype.getDescendants = function() {
Blockly.Block.prototype.getDescendants = function(ordered) {
var blocks = [this];
for (var child, x = 0; child = this.childBlocks_[x]; x++) {
blocks.push.apply(blocks, child.getDescendants());
var childBlocks = this.getChildren(ordered);
for (var child, i = 0; child = childBlocks[i]; i++) {
blocks.push.apply(blocks, child.getDescendants(ordered));
}
return blocks;
};
@@ -730,7 +755,7 @@ Blockly.Block.prototype.getVars = function() {
var vars = [];
for (var i = 0, input; input = this.inputList[i]; i++) {
for (var j = 0, field; field = input.fieldRow[j]; j++) {
if (field instanceof Blockly.FieldVariable) {
if (field.referencesVariables()) {
vars.push(field.getValue());
}
}
@@ -747,7 +772,7 @@ Blockly.Block.prototype.getVarModels = function() {
var vars = [];
for (var i = 0, input; input = this.inputList[i]; i++) {
for (var j = 0, field; field = input.fieldRow[j]; j++) {
if (field instanceof Blockly.FieldVariable) {
if (field.referencesVariables()) {
var model = this.workspace.getVariableById(field.getValue());
// Check if the variable actually exists (and isn't just a potential
// variable).
@@ -769,7 +794,7 @@ Blockly.Block.prototype.getVarModels = function() {
Blockly.Block.prototype.updateVarName = function(variable) {
for (var i = 0, input; input = this.inputList[i]; i++) {
for (var j = 0, field; field = input.fieldRow[j]; j++) {
if (field instanceof Blockly.FieldVariable &&
if (field.referencesVariables() &&
variable.getId() == field.getValue()) {
field.setText(variable.name);
}
@@ -787,7 +812,7 @@ Blockly.Block.prototype.updateVarName = function(variable) {
Blockly.Block.prototype.renameVarById = function(oldId, newId) {
for (var i = 0, input; input = this.inputList[i]; i++) {
for (var j = 0, field; field = input.fieldRow[j]; j++) {
if (field instanceof Blockly.FieldVariable &&
if (field.referencesVariables() &&
oldId == field.getValue()) {
field.setValue(newId);
}
@@ -1125,8 +1150,8 @@ Blockly.Block.prototype.jsonInit = function(json) {
if (Array.isArray(json['extensions'])) {
var extensionNames = json['extensions'];
for (var i = 0; i < extensionNames.length; ++i) {
var extensionName = extensionNames[i];
for (var j = 0; j < extensionNames.length; ++j) {
var extensionName = extensionNames[j];
Blockly.Extensions.apply(extensionName, this, false);
}
}
@@ -1261,7 +1286,6 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign) {
case 'input_dummy':
input = this.appendDummyInput(element['name']);
break;
default:
field = Blockly.Field.fromJson(element);
@@ -1305,7 +1329,7 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign) {
* @param {string} name Language-neutral identifier which may used to find this
* input again. Should be unique to this block.
* @return {!Blockly.Input} The input object created.
* @private
* @protected
*/
Blockly.Block.prototype.appendInput_ = function(type, name) {
var connection = null;
+213
View File
@@ -0,0 +1,213 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2018 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 Methods animating a block on connection and disconnection.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.BlockAnimations');
/**
* PID of disconnect UI animation. There can only be one at a time.
* @type {number}
* @private
*/
Blockly.BlockAnimations.disconnectPid_ = 0;
/**
* SVG group of wobbling block. There can only be one at a time.
* @type {Element}
* @private
*/
Blockly.BlockAnimations.disconnectGroup_ = null;
/**
* Play some UI effects (sound, animation) when disposing of a block.
* @param {!Blockly.BlockSvg} block The block being disposed of.
* @package
*/
Blockly.BlockAnimations.disposeUiEffect = function(block) {
var workspace = block.workspace;
var svgGroup = block.getSvgRoot();
workspace.getAudioManager().play('delete');
var xy = workspace.getSvgXY(svgGroup);
// Deeply clone the current block.
var clone = svgGroup.cloneNode(true);
clone.translateX_ = xy.x;
clone.translateY_ = xy.y;
clone.setAttribute('transform', 'translate(' + xy.x + ',' + xy.y + ')');
workspace.getParentSvg().appendChild(clone);
clone.bBox_ = clone.getBBox();
// Start the animation.
Blockly.BlockAnimations.disposeUiStep_(clone, workspace.RTL, new Date,
workspace.scale);
};
/**
* Animate a cloned block and eventually dispose of it.
* This is a class method, not an instance method since the original block has
* been destroyed and is no longer accessible.
* @param {!Element} clone SVG element to animate and dispose of.
* @param {boolean} rtl True if RTL, false if LTR.
* @param {!Date} start Date of animation's start.
* @param {number} workspaceScale Scale of workspace.
* @private
*/
Blockly.BlockAnimations.disposeUiStep_ = function(clone, rtl, start,
workspaceScale) {
var ms = new Date - start;
var percent = ms / 150;
if (percent > 1) {
goog.dom.removeNode(clone);
} else {
var x = clone.translateX_ +
(rtl ? -1 : 1) * clone.bBox_.width * workspaceScale / 2 * percent;
var y = clone.translateY_ + clone.bBox_.height * workspaceScale * percent;
var scale = (1 - percent) * workspaceScale;
clone.setAttribute('transform', 'translate(' + x + ',' + y + ')' +
' scale(' + scale + ')');
setTimeout(Blockly.BlockAnimations.disposeUiStep_, 10, clone, rtl, start,
workspaceScale);
}
};
/**
* Play some UI effects (sound, ripple) after a connection has been established.
* @param {!Blockly.BlockSvg} block The block being connected.
* @package
*/
Blockly.BlockAnimations.connectionUiEffect = function(block) {
var workspace = block.workspace;
var scale = workspace.scale;
workspace.getAudioManager().play('click');
if (scale < 1) {
return; // Too small to care about visual effects.
}
// Determine the absolute coordinates of the inferior block.
var xy = workspace.getSvgXY(block.getSvgRoot());
// Offset the coordinates based on the two connection types, fix scale.
if (block.outputConnection) {
xy.x += (block.RTL ? 3 : -3) * scale;
xy.y += 13 * scale;
} else if (block.previousConnection) {
xy.x += (block.RTL ? -23 : 23) * scale;
xy.y += 3 * scale;
}
var ripple = Blockly.utils.createSvgElement('circle',
{
'cx': xy.x,
'cy': xy.y,
'r': 0,
'fill': 'none',
'stroke': '#888',
'stroke-width': 10
},
workspace.getParentSvg());
// Start the animation.
Blockly.BlockAnimations.connectionUiStep_(ripple, new Date, scale);
};
/**
* Expand a ripple around a connection.
* @param {!Element} ripple Element to animate.
* @param {!Date} start Date of animation's start.
* @param {number} scale Scale of workspace.
* @private
*/
Blockly.BlockAnimations.connectionUiStep_ = function(ripple, start, scale) {
var ms = new Date - start;
var percent = ms / 150;
if (percent > 1) {
goog.dom.removeNode(ripple);
} else {
ripple.setAttribute('r', percent * 25 * scale);
ripple.style.opacity = 1 - percent;
Blockly.BlockAnimations.disconnectPid_ = setTimeout(
Blockly.BlockAnimations.connectionUiStep_, 10, ripple, start, scale);
}
};
/**
* Play some UI effects (sound, animation) when disconnecting a block.
* @param {!Blockly.BlockSvg} block The block being disconnected.
* @package
*/
Blockly.BlockAnimations.disconnectUiEffect = function(block) {
block.workspace.getAudioManager().play('disconnect');
if (block.workspace.scale < 1) {
return; // Too small to care about visual effects.
}
// Horizontal distance for bottom of block to wiggle.
var DISPLACEMENT = 10;
// Scale magnitude of skew to height of block.
var height = block.getHeightWidth().height;
var magnitude = Math.atan(DISPLACEMENT / height) / Math.PI * 180;
if (!block.RTL) {
magnitude *= -1;
}
// Start the animation.
Blockly.BlockAnimations.disconnectUiStep_(
block.getSvgRoot(), magnitude, new Date);
};
/**
* Animate a brief wiggle of a disconnected block.
* @param {!Element} group SVG element to animate.
* @param {number} magnitude Maximum degrees skew (reversed for RTL).
* @param {!Date} start Date of animation's start.
* @private
*/
Blockly.BlockAnimations.disconnectUiStep_ = function(group, magnitude, start) {
var DURATION = 200; // Milliseconds.
var WIGGLES = 3; // Half oscillations.
var ms = new Date - start;
var percent = ms / DURATION;
if (percent > 1) {
group.skew_ = '';
} else {
var skew = Math.round(
Math.sin(percent * Math.PI * WIGGLES) * (1 - percent) * magnitude);
group.skew_ = 'skewX(' + skew + ')';
Blockly.BlockAnimations.disconnectGroup_ = group;
Blockly.BlockAnimations.disconnectPid_ =
setTimeout(Blockly.BlockAnimations.disconnectUiStep_, 10, group,
magnitude, start);
}
group.setAttribute('transform', group.translate_ + group.skew_);
};
/**
* Stop the disconnect UI animation immediately.
* @package
*/
Blockly.BlockAnimations.disconnectUiStop = function() {
if (Blockly.BlockAnimations.disconnectGroup_) {
clearTimeout(Blockly.BlockAnimations.disconnectPid_);
var group = Blockly.BlockAnimations.disconnectGroup_;
group.skew_ = '';
group.setAttribute('transform', group.translate_);
Blockly.BlockAnimations.disconnectGroup_ = null;
}
};
+1 -1
View File
@@ -135,7 +135,7 @@ Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup = function(x, y, sc
var fixedX = x.toFixed(0);
var fixedY = y.toFixed(0);
this.dragGroup_.setAttribute('transform',
'translate('+ fixedX + ','+ fixedY + ') scale(' + scale + ')');
'translate(' + fixedX + ',' + fixedY + ') scale(' + scale + ')');
};
/**
+12 -7
View File
@@ -26,6 +26,7 @@
goog.provide('Blockly.BlockDragger');
goog.require('Blockly.BlockAnimations');
goog.require('Blockly.DraggedConnectionManager');
goog.require('Blockly.Events.BlockMove');
@@ -124,7 +125,7 @@ Blockly.BlockDragger.prototype.dispose = function() {
Blockly.BlockDragger.initIconData_ = function(block) {
// Build a list of icons that need to be moved and where they started.
var dragIconData = [];
var descendants = block.getDescendants();
var descendants = block.getDescendants(false);
for (var i = 0, descendant; descendant = descendants[i]; i++) {
var icons = descendant.getIcons();
for (var j = 0; j < icons.length; j++) {
@@ -153,7 +154,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, hea
}
this.workspace_.setResizesEnabled(false);
Blockly.BlockSvg.disconnectUiStop_();
Blockly.BlockAnimations.disconnectUiStop();
if (this.draggingBlock_.getParent() ||
(healStack && this.draggingBlock_.nextConnection &&
@@ -163,7 +164,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, hea
var newLoc = goog.math.Coordinate.sum(this.startXY_, delta);
this.draggingBlock_.translate(newLoc.x, newLoc.y);
this.draggingBlock_.disconnectUiEffect();
Blockly.BlockAnimations.disconnectUiEffect(this.draggingBlock_);
}
this.draggingBlock_.setDragging(true);
// For future consideration: we may be able to put moveToDragSurface inside
@@ -212,7 +213,7 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
this.dragBlock(e, currentDragDeltaXY);
this.dragIconData_ = [];
Blockly.BlockSvg.disconnectUiStop_();
Blockly.BlockAnimations.disconnectUiStop();
var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
var newLoc = goog.math.Coordinate.sum(this.startXY_, delta);
@@ -223,9 +224,13 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
// These are expensive and don't need to be done if we're deleting.
this.draggingBlock_.moveConnections_(delta.x, delta.y);
this.draggingBlock_.setDragging(false);
this.draggedConnectionManager_.applyConnections();
this.draggingBlock_.render();
this.fireMoveEvent_();
if (this.draggedConnectionManager_.wouldConnectBlock()) {
// Applying connections also rerenders the relevant blocks.
this.draggedConnectionManager_.applyConnections();
} else {
this.draggingBlock_.render();
}
this.draggingBlock_.scheduleSnapAndBump();
}
this.workspace_.setResizesEnabled(true);
@@ -261,7 +266,7 @@ Blockly.BlockDragger.prototype.maybeDeleteBlock_ = function() {
if (this.wouldDeleteBlock_) {
if (trashcan) {
goog.Timer.callOnce(trashcan.close, 100, trashcan);
setTimeout(trashcan.close.bind(trashcan), 100);
}
// Fire a move event, so we know where to go back to for an undo.
this.fireMoveEvent_();
+2 -2
View File
@@ -145,7 +145,7 @@ Blockly.Events.Change.prototype.fromJson = function(json) {
/**
* Does this event record any change of state?
* @return {boolean} True if something changed.
* @return {boolean} False if something changed.
*/
Blockly.Events.Change.prototype.isNull = function() {
return this.oldValue == this.newValue;
@@ -470,7 +470,7 @@ Blockly.Events.Move.prototype.currentLocation_ = function() {
/**
* Does this event record any change of state?
* @return {boolean} True if something changed.
* @return {boolean} False if something changed.
*/
Blockly.Events.Move.prototype.isNull = function() {
return this.oldParentId == this.newParentId &&
+415 -258
View File
@@ -30,6 +30,40 @@ goog.provide('Blockly.BlockSvg.render');
goog.require('Blockly.BlockSvg');
/**
* An object that holds information about the paths that are used to render the
* block. Each path is built up as an array of steps during the render process.
* The arrays are then turned into strings, which are set in the block's SVG.
* @constructor
* @struct
* @private
*/
Blockly.BlockSvg.PathObject = function() {
/**
* The primary outline of the block.
* @type {!Array.<string|number>}
*/
this.steps = [];
/**
* The highlight on the primary outline of the block.
* @type {!Array.<string|number>}
*/
this.highlightSteps = [];
/**
* The holes in the block for inline inputs.
* @type {!Array.<string|number>}
*/
this.inlineSteps = [];
/**
* The highlights on holes in the block for inline inputs.
* @type {!Array.<string|number>}
*/
this.highlightInlineSteps = [];
};
// UI constants for rendering blocks.
/**
* Horizontal space between elements.
@@ -541,24 +575,34 @@ Blockly.BlockSvg.prototype.renderDraw_ = function(iconWidth, inputRows) {
}
// Assemble the block's path.
var steps = [];
var inlineSteps = [];
// The highlighting applies to edges facing the upper-left corner.
// Since highlighting is a two-pixel wide border, it would normally overhang
// the edge of the block by a pixel. So undersize all measurements by a pixel.
var highlightSteps = [];
var highlightInlineSteps = [];
/**
* @type !Blockly.BlockSvg.PathObject
*/
var pathObject = new Blockly.BlockSvg.PathObject();
this.renderDrawTop_(steps, highlightSteps, inputRows.rightEdge);
var cursorY = this.renderDrawRight_(steps, highlightSteps, inlineSteps,
highlightInlineSteps, inputRows, iconWidth);
this.renderDrawBottom_(steps, highlightSteps, cursorY);
this.renderDrawLeft_(steps, highlightSteps);
this.renderDrawTop_(pathObject, inputRows.rightEdge);
var cursorY = this.renderDrawRight_(pathObject, inputRows, iconWidth);
this.renderDrawBottom_(pathObject, cursorY);
this.renderDrawLeft_(pathObject);
var pathString = steps.join(' ') + '\n' + inlineSteps.join(' ');
this.setPaths_(pathObject);
};
/**
* Update the block's SVG paths based on the paths that were computed during
* this render pass.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @private
*/
Blockly.BlockSvg.prototype.setPaths_ = function(pathObject) {
var pathString = pathObject.steps.join(' ') + '\n' +
pathObject.inlineSteps.join(' ');
this.svgPath_.setAttribute('d', pathString);
this.svgPathDark_.setAttribute('d', pathString);
pathString = highlightSteps.join(' ') + '\n' + highlightInlineSteps.join(' ');
pathString = pathObject.highlightSteps.join(' ') + '\n' +
pathObject.highlightInlineSteps.join(' ');
this.svgPathLight_.setAttribute('d', pathString);
if (this.RTL) {
// Mirror the block's path.
@@ -601,18 +645,18 @@ Blockly.BlockSvg.prototype.renderMoveConnections_ = function() {
this.nextConnection.tighten_();
}
}
};
/**
* Render the top edge of the block.
* @param {!Array.<string|number>} steps Path of block outline.
* @param {!Array.<string|number>} highlightSteps Path of block highlights.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {number} rightEdge Minimum width of block.
* @private
*/
Blockly.BlockSvg.prototype.renderDrawTop_ = function(steps,
highlightSteps, rightEdge) {
Blockly.BlockSvg.prototype.renderDrawTop_ = function(pathObject, rightEdge) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
// Position the cursor at the top-left starting point.
if (this.squareTopLeftCorner_) {
steps.push('m 0,0');
@@ -651,269 +695,73 @@ Blockly.BlockSvg.prototype.renderDrawTop_ = function(steps,
/**
* Render the right edge of the block.
* @param {!Array.<string|number>} steps Path of block outline.
* @param {!Array.<string|number>} highlightSteps Path of block highlights.
* @param {!Array.<string|number>} inlineSteps Inline block outlines.
* @param {!Array.<string|number>} highlightInlineSteps Inline block highlights.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {!Array.<!Array.<!Object>>} inputRows 2D array of objects, each
* containing position information.
* @param {number} iconWidth Offset of first row due to icons.
* @return {number} Height of block.
* @private
*/
Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps,
inlineSteps, highlightInlineSteps, inputRows, iconWidth) {
var cursorX;
var cursorY = 0;
var connectionX, connectionY;
Blockly.BlockSvg.prototype.renderDrawRight_ = function(pathObject, inputRows,
iconWidth) {
// Objects to pass to helper functions, which encapsulate a lot of the
// information we're passing around. Helper functions will update these
// objects.
var cursor = {
x: 0,
y: 0
};
var connectionPos = {
x: 0,
y: 0
};
for (var y = 0, row; row = inputRows[y]; y++) {
cursorX = Blockly.BlockSvg.SEP_SPACE_X;
cursor.x = Blockly.BlockSvg.SEP_SPACE_X;
if (y == 0) {
cursorX += this.RTL ? -iconWidth : iconWidth;
cursor.x += this.RTL ? -iconWidth : iconWidth;
}
highlightSteps.push('M', (inputRows.rightEdge - 0.5) + ',' +
(cursorY + 0.5));
pathObject.highlightSteps.push('M', (inputRows.rightEdge - 0.5) + ',' +
(cursor.y + 0.5));
if (this.isCollapsed()) {
// Jagged right edge.
var input = row[0];
var fieldX = cursorX;
var fieldY = cursorY;
this.renderFields_(input.fieldRow, fieldX, fieldY);
steps.push(Blockly.BlockSvg.JAGGED_TEETH);
highlightSteps.push('h 8');
var remainder = row.height - Blockly.BlockSvg.JAGGED_TEETH_HEIGHT;
steps.push('v', remainder);
if (this.RTL) {
highlightSteps.push('v 3.9 l 7.2,3.4 m -14.5,8.9 l 7.3,3.5');
highlightSteps.push('v', remainder - 0.7);
}
this.width += Blockly.BlockSvg.JAGGED_TEETH_WIDTH;
this.renderJaggedEdge_(pathObject, row, cursor);
} else if (row.type == Blockly.BlockSvg.INLINE) {
// Inline inputs.
for (var x = 0, input; input = row[x]; x++) {
var fieldX = cursorX;
var fieldY = cursorY;
if (row.thicker) {
// Lower the field slightly.
fieldY += Blockly.BlockSvg.INLINE_PADDING_Y;
}
// TODO: Align inline field rows (left/right/centre).
cursorX = this.renderFields_(input.fieldRow, fieldX, fieldY);
if (input.type != Blockly.DUMMY_INPUT) {
cursorX += input.renderWidth + Blockly.BlockSvg.SEP_SPACE_X;
}
if (input.type == Blockly.INPUT_VALUE) {
inlineSteps.push('M', (cursorX - Blockly.BlockSvg.SEP_SPACE_X) +
',' + (cursorY + Blockly.BlockSvg.INLINE_PADDING_Y));
inlineSteps.push('h', Blockly.BlockSvg.TAB_WIDTH - 2 -
input.renderWidth);
inlineSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
inlineSteps.push('v', input.renderHeight + 1 -
Blockly.BlockSvg.TAB_HEIGHT);
inlineSteps.push('h', input.renderWidth + 2 -
Blockly.BlockSvg.TAB_WIDTH);
inlineSteps.push('z');
if (this.RTL) {
// Highlight right edge, around back of tab, and bottom.
highlightInlineSteps.push('M',
(cursorX - Blockly.BlockSvg.SEP_SPACE_X - 2.5 +
Blockly.BlockSvg.TAB_WIDTH - input.renderWidth) + ',' +
(cursorY + Blockly.BlockSvg.INLINE_PADDING_Y + 0.5));
highlightInlineSteps.push(
Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
highlightInlineSteps.push('v',
input.renderHeight - Blockly.BlockSvg.TAB_HEIGHT + 2.5);
highlightInlineSteps.push('h',
input.renderWidth - Blockly.BlockSvg.TAB_WIDTH + 2);
} else {
// Highlight right edge, bottom.
highlightInlineSteps.push('M',
(cursorX - Blockly.BlockSvg.SEP_SPACE_X + 0.5) + ',' +
(cursorY + Blockly.BlockSvg.INLINE_PADDING_Y + 0.5));
highlightInlineSteps.push('v', input.renderHeight + 1);
highlightInlineSteps.push('h', Blockly.BlockSvg.TAB_WIDTH - 2 -
input.renderWidth);
// Short highlight glint at bottom of tab.
highlightInlineSteps.push('M',
(cursorX - input.renderWidth - Blockly.BlockSvg.SEP_SPACE_X +
0.9) + ',' + (cursorY + Blockly.BlockSvg.INLINE_PADDING_Y +
Blockly.BlockSvg.TAB_HEIGHT - 0.7));
highlightInlineSteps.push('l',
(Blockly.BlockSvg.TAB_WIDTH * 0.46) + ',-2.1');
}
// Create inline input connection.
if (this.RTL) {
connectionX = -cursorX -
Blockly.BlockSvg.TAB_WIDTH + Blockly.BlockSvg.SEP_SPACE_X +
input.renderWidth + 1;
} else {
connectionX = cursorX +
Blockly.BlockSvg.TAB_WIDTH - Blockly.BlockSvg.SEP_SPACE_X -
input.renderWidth - 1;
}
connectionY = cursorY + Blockly.BlockSvg.INLINE_PADDING_Y + 1;
input.connection.setOffsetInBlock(connectionX, connectionY);
}
}
cursorX = Math.max(cursorX, inputRows.rightEdge);
this.width = Math.max(this.width, cursorX);
steps.push('H', cursorX);
highlightSteps.push('H', cursorX - 0.5);
steps.push('v', row.height);
if (this.RTL) {
highlightSteps.push('v', row.height - 1);
}
this.renderInlineRow_(
pathObject, row, cursor, connectionPos, inputRows.rightEdge);
} else if (row.type == Blockly.INPUT_VALUE) {
// External input.
var input = row[0];
var fieldX = cursorX;
var fieldY = cursorY;
if (input.align != Blockly.ALIGN_LEFT) {
var fieldRightX = inputRows.rightEdge - input.fieldWidth -
Blockly.BlockSvg.TAB_WIDTH - 2 * Blockly.BlockSvg.SEP_SPACE_X;
if (input.align == Blockly.ALIGN_RIGHT) {
fieldX += fieldRightX;
} else if (input.align == Blockly.ALIGN_CENTRE) {
fieldX += fieldRightX / 2;
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
var v = row.height - Blockly.BlockSvg.TAB_HEIGHT;
steps.push('v', v);
if (this.RTL) {
// Highlight around back of tab.
highlightSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
highlightSteps.push('v', v + 0.5);
} else {
// Short highlight glint at bottom of tab.
highlightSteps.push('M', (inputRows.rightEdge - 5) + ',' +
(cursorY + Blockly.BlockSvg.TAB_HEIGHT - 0.7));
highlightSteps.push('l', (Blockly.BlockSvg.TAB_WIDTH * 0.46) +
',-2.1');
}
// Create external input connection.
connectionX = this.RTL ? -inputRows.rightEdge - 1 :
inputRows.rightEdge + 1;
input.connection.setOffsetInBlock(connectionX, cursorY);
if (input.connection.isConnected()) {
this.width = Math.max(this.width, inputRows.rightEdge +
input.connection.targetBlock().getHeightWidth().width -
Blockly.BlockSvg.TAB_WIDTH + 1);
}
this.renderExternalValueInput_(
pathObject, row, cursor, connectionPos, inputRows.rightEdge);
} else if (row.type == Blockly.DUMMY_INPUT) {
// External naked field.
var input = row[0];
var fieldX = cursorX;
var fieldY = cursorY;
if (input.align != Blockly.ALIGN_LEFT) {
var fieldRightX = inputRows.rightEdge - input.fieldWidth -
2 * Blockly.BlockSvg.SEP_SPACE_X;
if (inputRows.hasValue) {
fieldRightX -= Blockly.BlockSvg.TAB_WIDTH;
}
if (input.align == Blockly.ALIGN_RIGHT) {
fieldX += fieldRightX;
} else if (input.align == Blockly.ALIGN_CENTRE) {
fieldX += fieldRightX / 2;
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
steps.push('v', row.height);
if (this.RTL) {
highlightSteps.push('v', row.height - 1);
}
this.renderDummyInput_(
pathObject, row, cursor, inputRows.rightEdge, inputRows.hasValue);
} else if (row.type == Blockly.NEXT_STATEMENT) {
// Nested statement.
var input = row[0];
if (y == 0) {
// If the first input is a statement stack, add a small row on top.
steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y);
if (this.RTL) {
highlightSteps.push('v', Blockly.BlockSvg.SEP_SPACE_Y - 1);
}
cursorY += Blockly.BlockSvg.SEP_SPACE_Y;
}
var fieldX = cursorX;
var fieldY = cursorY;
if (input.align != Blockly.ALIGN_LEFT) {
var fieldRightX = inputRows.statementEdge - input.fieldWidth -
2 * Blockly.BlockSvg.SEP_SPACE_X;
if (input.align == Blockly.ALIGN_RIGHT) {
fieldX += fieldRightX;
} else if (input.align == Blockly.ALIGN_CENTRE) {
fieldX += fieldRightX / 2;
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
cursorX = inputRows.statementEdge + Blockly.BlockSvg.NOTCH_WIDTH;
steps.push('H', cursorX);
steps.push(Blockly.BlockSvg.INNER_TOP_LEFT_CORNER);
steps.push('v', row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS);
steps.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER);
steps.push('H', inputRows.rightEdge);
if (this.RTL) {
highlightSteps.push('M',
(cursorX - Blockly.BlockSvg.NOTCH_WIDTH +
Blockly.BlockSvg.DISTANCE_45_OUTSIDE) +
',' + (cursorY + Blockly.BlockSvg.DISTANCE_45_OUTSIDE));
highlightSteps.push(
Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL);
highlightSteps.push('v',
row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS);
highlightSteps.push(
Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL);
highlightSteps.push('H', inputRows.rightEdge - 0.5);
} else {
highlightSteps.push('M',
(cursorX - Blockly.BlockSvg.NOTCH_WIDTH +
Blockly.BlockSvg.DISTANCE_45_OUTSIDE) + ',' +
(cursorY + row.height - Blockly.BlockSvg.DISTANCE_45_OUTSIDE));
highlightSteps.push(
Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_LTR);
highlightSteps.push('H', inputRows.rightEdge - 0.5);
}
// Create statement connection.
connectionX = this.RTL ? -cursorX : cursorX + 1;
input.connection.setOffsetInBlock(connectionX, cursorY + 1);
if (input.connection.isConnected()) {
this.width = Math.max(this.width, inputRows.statementEdge +
input.connection.targetBlock().getHeightWidth().width);
}
if (y == inputRows.length - 1 ||
inputRows[y + 1].type == Blockly.NEXT_STATEMENT) {
// If the final input is a statement stack, add a small row underneath.
// Consecutive statement stacks are also separated by a small divider.
steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y);
if (this.RTL) {
highlightSteps.push('v', Blockly.BlockSvg.SEP_SPACE_Y - 1);
}
cursorY += Blockly.BlockSvg.SEP_SPACE_Y;
}
this.renderStatementInput_(
pathObject, row, cursor, connectionPos, inputRows, y);
}
cursorY += row.height;
cursor.y += row.height;
}
if (!inputRows.length) {
cursorY = Blockly.BlockSvg.MIN_BLOCK_Y;
steps.push('V', cursorY);
cursor.y = Blockly.BlockSvg.MIN_BLOCK_Y;
pathObject.steps.push('V', cursor.y);
if (this.RTL) {
highlightSteps.push('V', cursorY - 1);
pathObject.highlightSteps.push('V', cursor.y - 1);
}
}
return cursorY;
return cursor.y;
};
/**
* Render the bottom edge of the block.
* @param {!Array.<string|number>} steps Path of block outline.
* @param {!Array.<string|number>} highlightSteps Path of block highlights.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {number} cursorY Height of block.
* @private
*/
Blockly.BlockSvg.prototype.renderDrawBottom_ = function(steps,
highlightSteps, cursorY) {
Blockly.BlockSvg.prototype.renderDrawBottom_ = function(pathObject, cursorY) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
this.height += cursorY + 1; // Add one for the shadow.
if (this.nextConnection) {
steps.push('H', (Blockly.BlockSvg.NOTCH_WIDTH + (this.RTL ? 0.5 : - 0.5)) +
@@ -953,11 +801,13 @@ Blockly.BlockSvg.prototype.renderDrawBottom_ = function(steps,
/**
* Render the left edge of the block.
* @param {!Array.<string|number>} steps Path of block outline.
* @param {!Array.<string|number>} highlightSteps Path of block highlights.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @private
*/
Blockly.BlockSvg.prototype.renderDrawLeft_ = function(steps, highlightSteps) {
Blockly.BlockSvg.prototype.renderDrawLeft_ = function(pathObject) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
if (this.outputConnection) {
// Create output connection.
this.outputConnection.setOffsetInBlock(0, 0);
@@ -987,3 +837,310 @@ Blockly.BlockSvg.prototype.renderDrawLeft_ = function(steps, highlightSteps) {
}
steps.push('z');
};
/**
* Render the jagged edge of an input that shows on a collapsed block.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {!Array.<!Object>} row An object containing position information about
* inputs on this row of the block.
* @param {!Object} cursor An object containing the position of the cursor,
* which determines where to start laying out fields.
* @private
*/
Blockly.BlockSvg.prototype.renderJaggedEdge_ = function(pathObject, row,
cursor) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
var input = row[0];
this.renderFields_(input.fieldRow, cursor.x, cursor.y);
steps.push(Blockly.BlockSvg.JAGGED_TEETH);
highlightSteps.push('h 8');
var remainder = row.height - Blockly.BlockSvg.JAGGED_TEETH_HEIGHT;
steps.push('v', remainder);
if (this.RTL) {
highlightSteps.push('v 3.9 l 7.2,3.4 m -14.5,8.9 l 7.3,3.5');
highlightSteps.push('v', remainder - 0.7);
}
this.width += Blockly.BlockSvg.JAGGED_TEETH_WIDTH;
};
/**
* Render the right side of an inline row on a block.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {!Array.<!Object>} row An object containing position information about
* inputs on this row of the block.
* @param {!Object} cursor An object containing the position of the cursor,
* which determines where to start laying out fields.
* @param {!Object} connectionPos An object containing the position of the
* connection on this input.
* @param {number} rightEdge The position of the right edge of the block, which
* is based on the widest row that has been encountered so far.
* @private
*/
Blockly.BlockSvg.prototype.renderInlineRow_ = function(pathObject, row, cursor,
connectionPos, rightEdge) {
var inlineSteps = pathObject.inlineSteps;
var highlightInlineSteps = pathObject.highlightInlineSteps;
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
for (var x = 0, input; input = row[x]; x++) {
var fieldX = cursor.x;
var fieldY = cursor.y;
if (row.thicker) {
// Lower the field slightly.
fieldY += Blockly.BlockSvg.INLINE_PADDING_Y;
}
// TODO: Align inline field rows (left/right/centre).
cursor.x = this.renderFields_(input.fieldRow, fieldX, fieldY);
if (input.type != Blockly.DUMMY_INPUT) {
cursor.x += input.renderWidth + Blockly.BlockSvg.SEP_SPACE_X;
}
if (input.type == Blockly.INPUT_VALUE) {
inlineSteps.push('M', (cursor.x - Blockly.BlockSvg.SEP_SPACE_X) +
',' + (cursor.y + Blockly.BlockSvg.INLINE_PADDING_Y));
inlineSteps.push('h', Blockly.BlockSvg.TAB_WIDTH - 2 -
input.renderWidth);
inlineSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
inlineSteps.push('v', input.renderHeight + 1 -
Blockly.BlockSvg.TAB_HEIGHT);
inlineSteps.push('h', input.renderWidth + 2 -
Blockly.BlockSvg.TAB_WIDTH);
inlineSteps.push('z');
if (this.RTL) {
// Highlight right edge, around back of tab, and bottom.
highlightInlineSteps.push('M',
(cursor.x - Blockly.BlockSvg.SEP_SPACE_X - 2.5 +
Blockly.BlockSvg.TAB_WIDTH - input.renderWidth) + ',' +
(cursor.y + Blockly.BlockSvg.INLINE_PADDING_Y + 0.5));
highlightInlineSteps.push(
Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
highlightInlineSteps.push('v',
input.renderHeight - Blockly.BlockSvg.TAB_HEIGHT + 2.5);
highlightInlineSteps.push('h',
input.renderWidth - Blockly.BlockSvg.TAB_WIDTH + 2);
} else {
// Highlight right edge, bottom.
highlightInlineSteps.push('M',
(cursor.x - Blockly.BlockSvg.SEP_SPACE_X + 0.5) + ',' +
(cursor.y + Blockly.BlockSvg.INLINE_PADDING_Y + 0.5));
highlightInlineSteps.push('v', input.renderHeight + 1);
highlightInlineSteps.push('h', Blockly.BlockSvg.TAB_WIDTH - 2 -
input.renderWidth);
// Short highlight glint at bottom of tab.
highlightInlineSteps.push('M',
(cursor.x - input.renderWidth - Blockly.BlockSvg.SEP_SPACE_X +
0.9) + ',' + (cursor.y + Blockly.BlockSvg.INLINE_PADDING_Y +
Blockly.BlockSvg.TAB_HEIGHT - 0.7));
highlightInlineSteps.push('l',
(Blockly.BlockSvg.TAB_WIDTH * 0.46) + ',-2.1');
}
// Create inline input connection.
if (this.RTL) {
connectionPos.x = -cursor.x -
Blockly.BlockSvg.TAB_WIDTH + Blockly.BlockSvg.SEP_SPACE_X +
input.renderWidth + 1;
} else {
connectionPos.x = cursor.x +
Blockly.BlockSvg.TAB_WIDTH - Blockly.BlockSvg.SEP_SPACE_X -
input.renderWidth - 1;
}
connectionPos.y = cursor.y + Blockly.BlockSvg.INLINE_PADDING_Y + 1;
input.connection.setOffsetInBlock(connectionPos.x, connectionPos.y);
}
}
cursor.x = Math.max(cursor.x, rightEdge);
this.width = Math.max(this.width, cursor.x);
steps.push('H', cursor.x);
highlightSteps.push('H', cursor.x - 0.5);
steps.push('v', row.height);
if (this.RTL) {
highlightSteps.push('v', row.height - 1);
}
};
/**
* Render the right side of an inline row on a block.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {!Array.<!Object>} row An object containing position information about
* inputs on this row of the block.
* @param {!Object} cursor An object containing the position of the cursor,
* which determines where to start laying out fields.
* @param {!Object} connectionPos An object containing the position of the
* connection on this input.
* @param {number} rightEdge The position of the right edge of the block, which
* is based on the widest row that has been encountered so far.
* @private
*/
Blockly.BlockSvg.prototype.renderExternalValueInput_ = function(pathObject, row,
cursor, connectionPos, rightEdge) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
// External input.
var input = row[0];
var fieldX = cursor.x;
var fieldY = cursor.y;
if (input.align != Blockly.ALIGN_LEFT) {
var fieldRightX = rightEdge - input.fieldWidth -
Blockly.BlockSvg.TAB_WIDTH - 2 * Blockly.BlockSvg.SEP_SPACE_X;
if (input.align == Blockly.ALIGN_RIGHT) {
fieldX += fieldRightX;
} else if (input.align == Blockly.ALIGN_CENTRE) {
fieldX += fieldRightX / 2;
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
steps.push(Blockly.BlockSvg.TAB_PATH_DOWN);
var v = row.height - Blockly.BlockSvg.TAB_HEIGHT;
steps.push('v', v);
if (this.RTL) {
// Highlight around back of tab.
highlightSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL);
highlightSteps.push('v', v + 0.5);
} else {
// Short highlight glint at bottom of tab.
highlightSteps.push('M', (rightEdge - 5) + ',' +
(cursor.y + Blockly.BlockSvg.TAB_HEIGHT - 0.7));
highlightSteps.push('l', (Blockly.BlockSvg.TAB_WIDTH * 0.46) +
',-2.1');
}
// Create external input connection.
connectionPos.x = this.RTL ? -rightEdge - 1 : rightEdge + 1;
input.connection.setOffsetInBlock(connectionPos.x, cursor.y);
if (input.connection.isConnected()) {
this.width = Math.max(this.width, rightEdge +
input.connection.targetBlock().getHeightWidth().width -
Blockly.BlockSvg.TAB_WIDTH + 1);
}
};
/**
* Render the right side of an inline row on a block.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {!Array.<!Object>} row An object containing position information about
* inputs on this row of the block.
* @param {!Object} cursor An object containing the position of the cursor,
* which determines where to start laying out fields.
* @param {number} rightEdge The position of the right edge of the block, which
* is based on the widest row that has been encountered so far.
* @param {boolean} hasValue True if this block has at least one value input.
* @private
*/
Blockly.BlockSvg.prototype.renderDummyInput_ = function(pathObject, row,
cursor, rightEdge, hasValue) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
var input = row[0];
var fieldX = cursor.x;
var fieldY = cursor.y;
if (input.align != Blockly.ALIGN_LEFT) {
var fieldRightX = rightEdge - input.fieldWidth -
2 * Blockly.BlockSvg.SEP_SPACE_X;
if (hasValue) {
fieldRightX -= Blockly.BlockSvg.TAB_WIDTH;
}
if (input.align == Blockly.ALIGN_RIGHT) {
fieldX += fieldRightX;
} else if (input.align == Blockly.ALIGN_CENTRE) {
fieldX += fieldRightX / 2;
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
steps.push('v', row.height);
if (this.RTL) {
highlightSteps.push('v', row.height - 1);
}
};
/**
* Render the right side of an inline row on a block.
* @param {!Blockly.BlockSvg.PathObject} pathObject The object containing
* partially constructed SVG paths, which will be modified by this function.
* @param {!Array.<!Object>} row An object containing position information about
* inputs on this row of the block.
* @param {!Object} cursor An object containing the position of the cursor,
* which determines where to start laying out fields.
* @param {!Object} connectionPos An object containing the position of the
* connection on this input.
* @param {!Array.<!Array.<!Object>>} inputRows 2D array of objects, each
* containing position information.
* @param {number} index The index of the current row in the inputRows array.
* @private
*/
Blockly.BlockSvg.prototype.renderStatementInput_ = function(pathObject, row,
cursor, connectionPos, inputRows, index) {
var steps = pathObject.steps;
var highlightSteps = pathObject.highlightSteps;
var input = row[0];
if (index == 0) {
// If the first input is a statement stack, add a small row on top.
steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y);
if (this.RTL) {
highlightSteps.push('v', Blockly.BlockSvg.SEP_SPACE_Y - 1);
}
cursor.y += Blockly.BlockSvg.SEP_SPACE_Y;
}
var fieldX = cursor.x;
var fieldY = cursor.y;
if (input.align != Blockly.ALIGN_LEFT) {
var fieldRightX = inputRows.statementEdge - input.fieldWidth -
2 * Blockly.BlockSvg.SEP_SPACE_X;
if (input.align == Blockly.ALIGN_RIGHT) {
fieldX += fieldRightX;
} else if (input.align == Blockly.ALIGN_CENTRE) {
fieldX += fieldRightX / 2;
}
}
this.renderFields_(input.fieldRow, fieldX, fieldY);
cursor.x = inputRows.statementEdge + Blockly.BlockSvg.NOTCH_WIDTH;
steps.push('H', cursor.x);
steps.push(Blockly.BlockSvg.INNER_TOP_LEFT_CORNER);
steps.push('v', row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS);
steps.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER);
steps.push('H', inputRows.rightEdge);
if (this.RTL) {
highlightSteps.push('M',
(cursor.x - Blockly.BlockSvg.NOTCH_WIDTH +
Blockly.BlockSvg.DISTANCE_45_OUTSIDE) +
',' + (cursor.y + Blockly.BlockSvg.DISTANCE_45_OUTSIDE));
highlightSteps.push(
Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL);
highlightSteps.push('v',
row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS);
highlightSteps.push(
Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL);
highlightSteps.push('H', inputRows.rightEdge - 0.5);
} else {
highlightSteps.push('M',
(cursor.x - Blockly.BlockSvg.NOTCH_WIDTH +
Blockly.BlockSvg.DISTANCE_45_OUTSIDE) + ',' +
(cursor.y + row.height - Blockly.BlockSvg.DISTANCE_45_OUTSIDE));
highlightSteps.push(
Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_LTR);
highlightSteps.push('H', inputRows.rightEdge - 0.5);
}
// Create statement connection.
connectionPos.x = this.RTL ? -cursor.x : cursor.x + 1;
input.connection.setOffsetInBlock(connectionPos.x, cursor.y + 1);
if (input.connection.isConnected()) {
this.width = Math.max(this.width, inputRows.statementEdge +
input.connection.targetBlock().getHeightWidth().width);
}
if (index == inputRows.length - 1 ||
inputRows[index + 1].type == Blockly.NEXT_STATEMENT) {
// If the final input is a statement stack, add a small row underneath.
// Consecutive statement stacks are also separated by a small divider.
steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y);
if (this.RTL) {
highlightSteps.push('v', Blockly.BlockSvg.SEP_SPACE_Y - 1);
}
cursor.y += Blockly.BlockSvg.SEP_SPACE_Y;
}
};
+34 -193
View File
@@ -27,6 +27,7 @@
goog.provide('Blockly.BlockSvg');
goog.require('Blockly.Block');
goog.require('Blockly.BlockAnimations');
goog.require('Blockly.ContextMenu');
goog.require('Blockly.Events.Ui');
goog.require('Blockly.Events.BlockMove');
@@ -35,7 +36,7 @@ goog.require('Blockly.RenderedConnection');
goog.require('Blockly.Tooltip');
goog.require('Blockly.Touch');
goog.require('Blockly.utils');
goog.require('goog.Timer');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.math.Coordinate');
@@ -250,28 +251,36 @@ Blockly.BlockSvg.prototype.getIcons = function() {
* @param {Blockly.BlockSvg} newParent New parent block.
*/
Blockly.BlockSvg.prototype.setParent = function(newParent) {
if (newParent == this.parentBlock_) {
var oldParent = this.parentBlock_;
if (newParent == oldParent) {
return;
}
var svgRoot = this.getSvgRoot();
if (this.parentBlock_ && svgRoot) {
// Move this block up the DOM. Keep track of x/y translations.
var xy = this.getRelativeToSurfaceXY();
this.workspace.getCanvas().appendChild(svgRoot);
svgRoot.setAttribute('transform', 'translate(' + xy.x + ',' + xy.y + ')');
}
Blockly.Field.startCache();
Blockly.BlockSvg.superClass_.setParent.call(this, newParent);
Blockly.Field.stopCache();
var svgRoot = this.getSvgRoot();
// Bail early if workspace is clearing, or we aren't rendered.
// We won't need to reattach ourselves anywhere.
if (this.workspace.isClearing || !svgRoot) {
return;
}
var oldXY = this.getRelativeToSurfaceXY();
if (newParent) {
var oldXY = this.getRelativeToSurfaceXY();
newParent.getSvgRoot().appendChild(svgRoot);
var newXY = this.getRelativeToSurfaceXY();
// Move the connections to match the child's new position.
this.moveConnections_(newXY.x - oldXY.x, newXY.y - oldXY.y);
}
// If we are losing a parent, we want to move our DOM element to the
// root of the workspace.
else if (oldParent) {
this.workspace.getCanvas().appendChild(svgRoot);
this.translate(oldXY.x, oldXY.y);
}
};
/**
@@ -319,13 +328,18 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() {
*/
Blockly.BlockSvg.prototype.moveBy = function(dx, dy) {
goog.asserts.assert(!this.parentBlock_, 'Block has parent.');
var event = new Blockly.Events.BlockMove(this);
var eventsEnabled = Blockly.Events.isEnabled();
if (eventsEnabled) {
var event = new Blockly.Events.BlockMove(this);
}
var xy = this.getRelativeToSurfaceXY();
this.translate(xy.x + dx, xy.y + dy);
this.moveConnections_(dx, dy);
event.recordNew();
if (eventsEnabled) {
event.recordNew();
Blockly.Events.fire(event);
}
this.workspace.resizeContents();
Blockly.Events.fire(event);
};
/**
@@ -569,7 +583,7 @@ Blockly.BlockSvg.prototype.createTabList_ = function() {
* @private
*/
Blockly.BlockSvg.prototype.onMouseDown_ = function(e) {
var gesture = this.workspace.getGesture(e);
var gesture = this.workspace && this.workspace.getGesture(e);
if (gesture) {
gesture.handleBlockStart(e, this);
}
@@ -616,7 +630,7 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) {
var inlineOption = {enabled: true};
var isInline = this.getInputsInline();
inlineOption.text = isInline ?
Blockly.Msg.EXTERNAL_INPUTS : Blockly.Msg.INLINE_INPUTS;
Blockly.Msg['EXTERNAL_INPUTS'] : Blockly.Msg['INLINE_INPUTS'];
inlineOption.callback = function() {
block.setInputsInline(!isInline);
};
@@ -630,14 +644,14 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) {
// Option to collapse/expand block.
if (this.collapsed_) {
var expandOption = {enabled: true};
expandOption.text = Blockly.Msg.EXPAND_BLOCK;
expandOption.text = Blockly.Msg['EXPAND_BLOCK'];
expandOption.callback = function() {
block.setCollapsed(false);
};
menuOptions.push(expandOption);
} else {
var collapseOption = {enabled: true};
collapseOption.text = Blockly.Msg.COLLAPSE_BLOCK;
collapseOption.text = Blockly.Msg['COLLAPSE_BLOCK'];
collapseOption.callback = function() {
block.setCollapsed(true);
};
@@ -649,7 +663,7 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) {
// Option to disable/enable block.
var disableOption = {
text: this.disabled ?
Blockly.Msg.ENABLE_BLOCK : Blockly.Msg.DISABLE_BLOCK,
Blockly.Msg['ENABLE_BLOCK'] : Blockly.Msg['DISABLE_BLOCK'],
enabled: !this.getInheritedDisabled(),
callback: function() {
block.setDisabled(!block.disabled);
@@ -807,7 +821,7 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) {
if (animate && this.rendered) {
this.unplug(healStack);
this.disposeUiEffect();
Blockly.BlockAnimations.disposeUiEffect(this);
}
// Stop rerendering.
this.rendered = false;
@@ -841,179 +855,6 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) {
Blockly.Field.stopCache();
};
/**
* Play some UI effects (sound, animation) when disposing of a block.
*/
Blockly.BlockSvg.prototype.disposeUiEffect = function() {
this.workspace.getAudioManager().play('delete');
var xy = this.workspace.getSvgXY(/** @type {!Element} */ (this.svgGroup_));
// Deeply clone the current block.
var clone = this.svgGroup_.cloneNode(true);
clone.translateX_ = xy.x;
clone.translateY_ = xy.y;
clone.setAttribute('transform',
'translate(' + clone.translateX_ + ',' + clone.translateY_ + ')');
this.workspace.getParentSvg().appendChild(clone);
clone.bBox_ = clone.getBBox();
// Start the animation.
Blockly.BlockSvg.disposeUiStep_(clone, this.RTL, new Date,
this.workspace.scale);
};
/**
* Animate a cloned block and eventually dispose of it.
* This is a class method, not an instance method since the original block has
* been destroyed and is no longer accessible.
* @param {!Element} clone SVG element to animate and dispose of.
* @param {boolean} rtl True if RTL, false if LTR.
* @param {!Date} start Date of animation's start.
* @param {number} workspaceScale Scale of workspace.
* @private
*/
Blockly.BlockSvg.disposeUiStep_ = function(clone, rtl, start, workspaceScale) {
var ms = new Date - start;
var percent = ms / 150;
if (percent > 1) {
goog.dom.removeNode(clone);
} else {
var x = clone.translateX_ +
(rtl ? -1 : 1) * clone.bBox_.width * workspaceScale / 2 * percent;
var y = clone.translateY_ + clone.bBox_.height * workspaceScale * percent;
var scale = (1 - percent) * workspaceScale;
clone.setAttribute('transform', 'translate(' + x + ',' + y + ')' +
' scale(' + scale + ')');
setTimeout(
Blockly.BlockSvg.disposeUiStep_, 10, clone, rtl, start, workspaceScale);
}
};
/**
* Play some UI effects (sound, ripple) after a connection has been established.
*/
Blockly.BlockSvg.prototype.connectionUiEffect = function() {
this.workspace.getAudioManager().play('click');
if (this.workspace.scale < 1) {
return; // Too small to care about visual effects.
}
// Determine the absolute coordinates of the inferior block.
var xy = this.workspace.getSvgXY(/** @type {!Element} */ (this.svgGroup_));
// Offset the coordinates based on the two connection types, fix scale.
if (this.outputConnection) {
xy.x += (this.RTL ? 3 : -3) * this.workspace.scale;
xy.y += 13 * this.workspace.scale;
} else if (this.previousConnection) {
xy.x += (this.RTL ? -23 : 23) * this.workspace.scale;
xy.y += 3 * this.workspace.scale;
}
var ripple = Blockly.utils.createSvgElement('circle',
{
'cx': xy.x,
'cy': xy.y,
'r': 0,
'fill': 'none',
'stroke': '#888',
'stroke-width': 10
},
this.workspace.getParentSvg());
// Start the animation.
Blockly.BlockSvg.connectionUiStep_(ripple, new Date, this.workspace.scale);
};
/**
* Expand a ripple around a connection.
* @param {!Element} ripple Element to animate.
* @param {!Date} start Date of animation's start.
* @param {number} workspaceScale Scale of workspace.
* @private
*/
Blockly.BlockSvg.connectionUiStep_ = function(ripple, start, workspaceScale) {
var ms = new Date - start;
var percent = ms / 150;
if (percent > 1) {
goog.dom.removeNode(ripple);
} else {
ripple.setAttribute('r', percent * 25 * workspaceScale);
ripple.style.opacity = 1 - percent;
Blockly.BlockSvg.disconnectUiStop_.pid_ = setTimeout(
Blockly.BlockSvg.connectionUiStep_, 10, ripple, start, workspaceScale);
}
};
/**
* Play some UI effects (sound, animation) when disconnecting a block.
*/
Blockly.BlockSvg.prototype.disconnectUiEffect = function() {
this.workspace.getAudioManager().play('disconnect');
if (this.workspace.scale < 1) {
return; // Too small to care about visual effects.
}
// Horizontal distance for bottom of block to wiggle.
var DISPLACEMENT = 10;
// Scale magnitude of skew to height of block.
var height = this.getHeightWidth().height;
var magnitude = Math.atan(DISPLACEMENT / height) / Math.PI * 180;
if (!this.RTL) {
magnitude *= -1;
}
// Start the animation.
Blockly.BlockSvg.disconnectUiStep_(this.svgGroup_, magnitude, new Date);
};
/**
* Animate a brief wiggle of a disconnected block.
* @param {!Element} group SVG element to animate.
* @param {number} magnitude Maximum degrees skew (reversed for RTL).
* @param {!Date} start Date of animation's start.
* @private
*/
Blockly.BlockSvg.disconnectUiStep_ = function(group, magnitude, start) {
var DURATION = 200; // Milliseconds.
var WIGGLES = 3; // Half oscillations.
var ms = new Date - start;
var percent = ms / DURATION;
if (percent > 1) {
group.skew_ = '';
} else {
var skew = Math.round(
Math.sin(percent * Math.PI * WIGGLES) * (1 - percent) * magnitude);
group.skew_ = 'skewX(' + skew + ')';
Blockly.BlockSvg.disconnectUiStop_.group = group;
Blockly.BlockSvg.disconnectUiStop_.pid =
setTimeout(
Blockly.BlockSvg.disconnectUiStep_, 10, group, magnitude, start);
}
group.setAttribute('transform', group.translate_ + group.skew_);
};
/**
* Stop the disconnect UI animation immediately.
* @private
*/
Blockly.BlockSvg.disconnectUiStop_ = function() {
if (Blockly.BlockSvg.disconnectUiStop_.group) {
clearTimeout(Blockly.BlockSvg.disconnectUiStop_.pid);
var group = Blockly.BlockSvg.disconnectUiStop_.group;
group.skew_ = '';
group.setAttribute('transform', group.translate_);
Blockly.BlockSvg.disconnectUiStop_.group = null;
}
};
/**
* PID of disconnect UI animation. There can only be one at a time.
* @type {number}
*/
Blockly.BlockSvg.disconnectUiStop_.pid = 0;
/**
* SVG group of wobbling block. There can only be one at a time.
* @type {Element}
*/
Blockly.BlockSvg.disconnectUiStop_.group = null;
/**
* Change the colour of a block.
*/
@@ -1070,7 +911,7 @@ Blockly.BlockSvg.prototype.updateDisabled = function() {
this.updateColour();
}
}
var children = this.getChildren();
var children = this.getChildren(false);
for (var i = 0, child; child = children[i]; i++) {
child.updateDisabled();
}
+29 -21
View File
@@ -246,35 +246,41 @@ Blockly.onKeyDown_ = function(e) {
};
/**
* Copy a block onto the local clipboard.
* @param {!Blockly.Block} block Block to be copied.
* Copy a block or workspace comment onto the local clipboard.
* @param {!Blockly.Block | !Blockly.WorkspaceComment} toCopy Block or Workspace Comment
* to be copied.
* @private
*/
Blockly.copy_ = function(block) {
var xmlBlock = Blockly.Xml.blockToDom(block);
// Copy only the selected block and internal blocks.
Blockly.Xml.deleteNext(xmlBlock);
// Encode start position in XML.
var xy = block.getRelativeToSurfaceXY();
xmlBlock.setAttribute('x', block.RTL ? -xy.x : xy.x);
xmlBlock.setAttribute('y', xy.y);
Blockly.clipboardXml_ = xmlBlock;
Blockly.clipboardSource_ = block.workspace;
Blockly.copy_ = function(toCopy) {
if (toCopy.isComment) {
var xml = toCopy.toXmlWithXY();
} else {
var xml = Blockly.Xml.blockToDom(toCopy);
// Copy only the selected block and internal blocks.
Blockly.Xml.deleteNext(xml);
// Encode start position in XML.
var xy = toCopy.getRelativeToSurfaceXY();
xml.setAttribute('x', toCopy.RTL ? -xy.x : xy.x);
xml.setAttribute('y', xy.y);
}
Blockly.clipboardXml_ = xml;
Blockly.clipboardSource_ = toCopy.workspace;
};
/**
* Duplicate this block and its children.
* @param {!Blockly.Block} block Block to be copied.
* Duplicate this block and its children, or a workspace comment.
* @param {!Blockly.Block | !Blockly.WorkspaceComment} toDuplicate Block or
* Workspace Comment to be copied.
* @private
*/
Blockly.duplicate_ = function(block) {
Blockly.duplicate_ = function(toDuplicate) {
// Save the clipboard.
var clipboardXml = Blockly.clipboardXml_;
var clipboardSource = Blockly.clipboardSource_;
// Create a duplicate via a copy/paste operation.
Blockly.copy_(block);
block.workspace.paste(Blockly.clipboardXml_);
Blockly.copy_(toDuplicate);
toDuplicate.workspace.paste(Blockly.clipboardXml_);
// Restore the clipboard.
Blockly.clipboardXml_ = clipboardXml;
@@ -380,6 +386,7 @@ Blockly.prompt = function(message, defaultValue, callback) {
* @private
*/
Blockly.jsonInitFactory_ = function(jsonDef) {
/** @this Blockly.Block */
return function() {
this.jsonInit(jsonDef);
};
@@ -457,7 +464,7 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func,
};
var bindData = [];
if (window && window.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) {
if (goog.global.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) {
for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) {
node.addEventListener(type, wrapFunc, false);
bindData.push([node, type, wrapFunc]);
@@ -509,6 +516,7 @@ Blockly.bindEvent_ = function(node, name, thisObject, func) {
};
var bindData = [];
var window = goog.global['window'];
if (window && window.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) {
for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) {
node.addEventListener(type, wrapFunc, false);
@@ -624,7 +632,7 @@ Blockly.checkBlockColourConstant_ = function(
msgName, blocklyNamePath, expectedValue) {
var namePath = 'Blockly';
var value = Blockly;
for (var i =0; i < blocklyNamePath.length; ++i) {
for (var i = 0; i < blocklyNamePath.length; ++i) {
namePath += '.' + blocklyNamePath[i];
if (value) {
value = value[blocklyNamePath[i]];
@@ -633,8 +641,8 @@ Blockly.checkBlockColourConstant_ = function(
if (value && value !== expectedValue) {
var warningPattern = (expectedValue === undefined) ?
'%1 has been removed. Use Blockly.Msg.%2.' :
'%1 is deprecated and unused. Override Blockly.Msg.%2.';
'%1 has been removed. Use Blockly.Msg["%2"].' :
'%1 is deprecated and unused. Override Blockly.Msg["%2"].';
var warning = warningPattern.replace('%1', namePath).replace('%2', msgName);
console.warn(warning);
}
+19
View File
@@ -304,6 +304,25 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) {
}
};
/**
* Show the context menu for this bubble.
* @param {!Event} _e Mouse event.
* @private
*/
Blockly.Bubble.prototype.showContextMenu_ = function(_e) {
// NOP on bubbles, but used by the bubble dragger to pass events to
// workspace comments.
};
/**
* Get whether this bubble is deletable or not.
* @return {boolean} True if deletable.
* @package
*/
Blockly.Bubble.prototype.isDeletable = function() {
return false;
};
/**
* Handle a mouse-down on bubble's resize corner.
* @param {!Event} e Mouse down event.
+106 -12
View File
@@ -26,21 +26,27 @@
goog.provide('Blockly.BubbleDragger');
goog.require('Blockly.Bubble');
goog.require('Blockly.Events.CommentMove');
goog.require('Blockly.WorkspaceCommentSvg');
goog.require('goog.math.Coordinate');
goog.require('goog.asserts');
/**
* Class for a bubble dragger. It moves bubbles around the workspace when they
* are being dragged by a mouse or touch.
* @param {!Blockly.Bubble} bubble The bubble to drag.
* Class for a bubble dragger. It moves things on the bubble canvas around the
* workspace when they are being dragged by a mouse or touch. These can be
* block comments, mutators, warnings, or workspace comments.
* @param {!Blockly.Bubble|!Blockly.WorkspaceCommentSvg} bubble The item on the
* bubble canvas to drag.
* @param {!Blockly.WorkspaceSvg} workspace The workspace to drag on.
* @constructor
*/
Blockly.BubbleDragger = function(bubble, workspace) {
/**
* The bubble that is being dragged.
* @type {!Blockly.Bubble}
* The item on the bubble canvas that is being dragged.
* @type {!Blockly.Bubble|!Blockly.WorkspaceCommentSvg}
* @private
*/
this.draggingBubble_ = bubble;
@@ -52,6 +58,22 @@ Blockly.BubbleDragger = function(bubble, workspace) {
*/
this.workspace_ = workspace;
/**
* Which delete area the mouse pointer is over, if any.
* One of {@link Blockly.DELETE_AREA_TRASH},
* {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}.
* @type {?number}
* @private
*/
this.deleteArea_ = null;
/**
* Whether the bubble would be deleted if dropped immediately.
* @type {boolean}
* @private
*/
this.wouldDeleteBubble_ = false;
/**
* The location of the top left corner of the dragging bubble's body at the
* beginning of the drag, in workspace coordinates.
@@ -95,6 +117,15 @@ Blockly.BubbleDragger.prototype.startBubbleDrag = function() {
if (this.dragSurface_) {
this.moveToDragSurface_();
}
this.draggingBubble_.setDragging && this.draggingBubble_.setDragging(true);
var toolbox = this.workspace_.getToolbox();
if (toolbox) {
var style = this.draggingBubble_.isDeletable() ? 'blocklyToolboxDelete' :
'blocklyToolboxGrab';
toolbox.addStyle(style);
}
};
/**
@@ -110,8 +141,55 @@ Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) {
var newLoc = goog.math.Coordinate.sum(this.startXY_, delta);
this.draggingBubble_.moveDuringDrag(this.dragSurface_, newLoc);
// TODO (fenichel): Possibly update the cursor if dragging to the trash can
// is allowed.
if (this.draggingBubble_.isDeletable()) {
this.deleteArea_ = this.workspace_.isDeleteArea(e);
this.updateCursorDuringBubbleDrag_();
}
};
/**
* Shut the trash can and, if necessary, delete the dragging bubble.
* Should be called at the end of a bubble drag.
* @return {boolean} whether the bubble was deleted.
* @private
*/
Blockly.BubbleDragger.prototype.maybeDeleteBubble_ = function() {
var trashcan = this.workspace_.trashcan;
if (this.wouldDeleteBubble_) {
if (trashcan) {
setTimeout(trashcan.close.bind(trashcan), 100);
}
// Fire a move event, so we know where to go back to for an undo.
this.fireMoveEvent_();
this.draggingBubble_.dispose(false, true);
} else if (trashcan) {
// Make sure the trash can is closed.
trashcan.close();
}
return this.wouldDeleteBubble_;
};
/**
* Update the cursor (and possibly the trash can lid) to reflect whether the
* dragging bubble would be deleted if released immediately.
* @private
*/
Blockly.BubbleDragger.prototype.updateCursorDuringBubbleDrag_ = function() {
this.wouldDeleteBubble_ = this.deleteArea_ != Blockly.DELETE_AREA_NONE;
var trashcan = this.workspace_.trashcan;
if (this.wouldDeleteBubble_) {
this.draggingBubble_.setDeleteStyle(true);
if (this.deleteArea_ == Blockly.DELETE_AREA_TRASH && trashcan) {
trashcan.setOpen_(true);
}
} else {
this.draggingBubble_.setDeleteStyle(false);
if (trashcan) {
trashcan.setOpen_(false);
}
}
};
/**
@@ -131,14 +209,24 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function(
// Move the bubble to its final location.
this.draggingBubble_.moveTo(newLoc.x, newLoc.y);
// Put everything back onto the bubble canvas.
if (this.dragSurface_) {
this.dragSurface_.clearAndHide(this.workspace_.getBubbleCanvas());
}
var deleted = this.maybeDeleteBubble_();
this.fireMoveEvent_();
if (!deleted) {
// Put everything back onto the bubble canvas.
if (this.dragSurface_) {
this.dragSurface_.clearAndHide(this.workspace_.getBubbleCanvas());
}
this.draggingBubble_.setDragging && this.draggingBubble_.setDragging(false);
this.fireMoveEvent_();
}
this.workspace_.setResizesEnabled(true);
if (this.workspace_.toolbox_) {
var style = this.draggingBubble_.isDeletable() ? 'blocklyToolboxDelete' :
'blocklyToolboxGrab';
this.workspace_.toolbox_.removeStyle(style);
}
Blockly.Events.setGroup(false);
};
@@ -147,6 +235,12 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function(
* @private
*/
Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() {
if (this.draggingBubble_.isComment) {
var event = new Blockly.Events.CommentMove(this.draggingBubble_);
event.setOldCoordinate(this.startXY_);
event.recordNew();
Blockly.Events.fire(event);
}
// TODO (fenichel): move events for comments.
return;
};
+11 -11
View File
@@ -41,7 +41,7 @@ goog.require('goog.dom');
Blockly.Connection = function(source, type) {
/**
* @type {!Blockly.Block}
* @private
* @protected
*/
this.sourceBlock_ = source;
/** @type {number} */
@@ -89,28 +89,28 @@ Blockly.Connection.prototype.shadowDom_ = null;
/**
* Horizontal location of this connection.
* @type {number}
* @private
* @protected
*/
Blockly.Connection.prototype.x_ = 0;
/**
* Vertical location of this connection.
* @type {number}
* @private
* @protected
*/
Blockly.Connection.prototype.y_ = 0;
/**
* Has this connection been added to the connection database?
* @type {boolean}
* @private
* @protected
*/
Blockly.Connection.prototype.inDB_ = false;
/**
* Connection database for connections of this type on the current workspace.
* @type {Blockly.ConnectionDB}
* @private
* @protected
*/
Blockly.Connection.prototype.db_ = null;
@@ -118,14 +118,14 @@ Blockly.Connection.prototype.db_ = null;
* Connection database for connections compatible with this type on the
* current workspace.
* @type {Blockly.ConnectionDB}
* @private
* @protected
*/
Blockly.Connection.prototype.dbOpposite_ = null;
/**
* Whether this connections is hidden (not tracked in a database) or not.
* @type {boolean}
* @private
* @protected
*/
Blockly.Connection.prototype.hidden_ = null;
@@ -133,7 +133,7 @@ Blockly.Connection.prototype.hidden_ = null;
* Connect two connections together. This is the connection on the superior
* block.
* @param {!Blockly.Connection} childConnection Connection on inferior block.
* @private
* @protected
*/
Blockly.Connection.prototype.connect_ = function(childConnection) {
var parentConnection = this;
@@ -498,7 +498,7 @@ Blockly.Connection.prototype.disconnect = function() {
* Disconnect two blocks that are connected by this connection.
* @param {!Blockly.Block} parentBlock The superior block.
* @param {!Blockly.Block} childBlock The inferior block.
* @private
* @protected
*/
Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
childBlock) {
@@ -518,7 +518,7 @@ Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
/**
* Respawn the shadow block if there was one connected to the this connection.
* @private
* @protected
*/
Blockly.Connection.prototype.respawnShadow_ = function() {
var parentBlock = this.getSourceBlock();
@@ -552,7 +552,7 @@ Blockly.Connection.prototype.targetBlock = function() {
* value type system. E.g. square_root("Hello") is not compatible.
* @param {!Blockly.Connection} otherConnection Connection to compare against.
* @return {boolean} True if the connections share a type.
* @private
* @protected
*/
Blockly.Connection.prototype.checkType_ = function(otherConnection) {
if (!this.check_ || !otherConnection.check_) {
+109 -9
View File
@@ -215,15 +215,15 @@ Blockly.ContextMenu.callbackFactory = function(block, xml) {
Blockly.ContextMenu.blockDeleteOption = function(block) {
// Option to delete this block but not blocks lower in the stack.
// Count the number of blocks that are nested in this block.
var descendantCount = block.getDescendants(true).length;
var descendantCount = block.getDescendants(false).length;
var nextBlock = block.getNextBlock();
if (nextBlock) {
// Blocks in the current stack would survive this block's deletion.
descendantCount -= nextBlock.getDescendants(true).length;
descendantCount -= nextBlock.getDescendants(false).length;
}
var deleteOption = {
text: descendantCount == 1 ? Blockly.Msg.DELETE_BLOCK :
Blockly.Msg.DELETE_X_BLOCKS.replace('%1', String(descendantCount)),
text: descendantCount == 1 ? Blockly.Msg['DELETE_BLOCK'] :
Blockly.Msg['DELETE_X_BLOCKS'].replace('%1', String(descendantCount)),
enabled: true,
callback: function() {
Blockly.Events.setGroup(true);
@@ -244,7 +244,7 @@ Blockly.ContextMenu.blockHelpOption = function(block) {
var url = goog.isFunction(block.helpUrl) ? block.helpUrl() : block.helpUrl;
var helpOption = {
enabled: !!url,
text: Blockly.Msg.HELP,
text: Blockly.Msg['HELP'],
callback: function() {
block.showHelp_();
}
@@ -260,11 +260,12 @@ Blockly.ContextMenu.blockHelpOption = function(block) {
*/
Blockly.ContextMenu.blockDuplicateOption = function(block) {
var enabled = true;
if (block.getDescendants().length > block.workspace.remainingCapacity()) {
if (block.getDescendants(false).length >
block.workspace.remainingCapacity()) {
enabled = false;
}
var duplicateOption = {
text: Blockly.Msg.DUPLICATE_BLOCK,
text: Blockly.Msg['DUPLICATE_BLOCK'],
enabled: enabled,
callback: function() {
Blockly.duplicate_(block);
@@ -286,16 +287,115 @@ Blockly.ContextMenu.blockCommentOption = function(block) {
};
// If there's already a comment, add an option to delete it.
if (block.comment) {
commentOption.text = Blockly.Msg.REMOVE_COMMENT;
commentOption.text = Blockly.Msg['REMOVE_COMMENT'];
commentOption.callback = function() {
block.setCommentText(null);
};
} else {
// If there's no comment, add an option to create a comment.
commentOption.text = Blockly.Msg.ADD_COMMENT;
commentOption.text = Blockly.Msg['ADD_COMMENT'];
commentOption.callback = function() {
block.setCommentText('');
};
}
return commentOption;
};
/**
* Make a context menu option for deleting the current workspace comment.
* @param {!Blockly.WorkspaceCommentSvg} comment The workspace comment where the
* right-click originated.
* @return {!Object} A menu option, containing text, enabled, and a callback.
* @package
*/
Blockly.ContextMenu.commentDeleteOption = function(comment) {
var deleteOption = {
text: Blockly.Msg.REMOVE_COMMENT,
enabled: true,
callback: function() {
Blockly.Events.setGroup(true);
comment.dispose(true, true);
Blockly.Events.setGroup(false);
}
};
return deleteOption;
};
/**
* Make a context menu option for duplicating the current workspace comment.
* @param {!Blockly.WorkspaceCommentSvg} comment The workspace comment where the
* right-click originated.
* @return {!Object} A menu option, containing text, enabled, and a callback.
* @package
*/
Blockly.ContextMenu.commentDuplicateOption = function(comment) {
var duplicateOption = {
text: Blockly.Msg.DUPLICATE_COMMENT,
enabled: true,
callback: function() {
Blockly.duplicate_(comment);
}
};
return duplicateOption;
};
/**
* Make a context menu option for adding a comment on the workspace.
* @param {!Blockly.WorkspaceSvg} ws The workspace where the right-click
* originated.
* @param {!Event} e The right-click mouse event.
* @return {!Object} A menu option, containing text, enabled, and a callback.
* @package
*/
Blockly.ContextMenu.workspaceCommentOption = function(ws, e) {
// Helper function to create and position a comment correctly based on the
// location of the mouse event.
var addWsComment = function() {
var comment = new Blockly.WorkspaceCommentSvg(
ws, Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,
Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,
Blockly.WorkspaceCommentSvg.DEFAULT_SIZE);
var injectionDiv = ws.getInjectionDiv();
// Bounding rect coordinates are in client coordinates, meaning that they
// are in pixels relative to the upper left corner of the visible browser
// window. These coordinates change when you scroll the browser window.
var boundingRect = injectionDiv.getBoundingClientRect();
// The client coordinates offset by the injection div's upper left corner.
var clientOffsetPixels = new goog.math.Coordinate(
e.clientX - boundingRect.left, e.clientY - boundingRect.top);
// The offset in pixels between the main workspace's origin and the upper
// left corner of the injection div.
var mainOffsetPixels = ws.getOriginOffsetInPixels();
// The position of the new comment in pixels relative to the origin of the
// main workspace.
var finalOffsetPixels = goog.math.Coordinate.difference(clientOffsetPixels,
mainOffsetPixels);
// The position of the new comment in main workspace coordinates.
var finalOffsetMainWs = finalOffsetPixels.scale(1 / ws.scale);
var commentX = finalOffsetMainWs.x;
var commentY = finalOffsetMainWs.y;
comment.moveBy(commentX, commentY);
if (ws.rendered) {
comment.initSvg();
comment.render(false);
comment.select();
}
};
var wsCommentOption = {
// Foreign objects don't work in IE. Don't let the user create comments
// that they won't be able to edit.
enabled: !goog.userAgent.IE
};
wsCommentOption.text = Blockly.Msg.ADD_COMMENT;
wsCommentOption.callback = function() {
addWsComment();
};
return wsCommentOption;
};
+62 -6
View File
@@ -189,7 +189,7 @@ Blockly.Css.CONTENT = [
'}',
'.blocklyResizeLine {',
'stroke: #888;',
'stroke: #515A5A;',
'stroke-width: 1;',
'}',
@@ -383,17 +383,76 @@ Blockly.Css.CONTENT = [
'padding: 0;',
'}',
'.blocklyCommentForeignObject {',
'position: relative;',
'z-index: 0;',
'}',
'.blocklyCommentRect {',
'fill: #E7DE8E;',
'stroke: #bcA903;',
'stroke-width: 1px',
'}',
'.blocklyCommentTarget {',
'fill: transparent;',
'stroke: #bcA903;',
'}',
'.blocklyCommentTargetFocused {',
'fill: none;',
'}',
'.blocklyCommentHandleTarget {',
'fill: none;',
'}',
'.blocklyCommentHandleTargetFocused {',
'fill: transparent;',
'}',
'.blocklyFocused>.blocklyCommentRect {',
'fill: #B9B272;',
'stroke: #B9B272;',
'}',
'.blocklySelected>.blocklyCommentTarget {',
'stroke: #fc3;',
'stroke-width: 3px;',
'}',
'.blocklyCommentTextarea {',
'background-color: #ffc;',
'background-color: #fef49c;',
'border: 0;',
'outline: 0;',
'margin: 0;',
'padding: 2px;',
'padding: 3px;',
'resize: none;',
'display: block;',
'overflow: hidden;',
'}',
'.blocklyCommentDeleteIcon {',
'cursor: pointer;',
'fill: #000;',
'display: none',
'}',
'.blocklySelected > .blocklyCommentDeleteIcon {',
'display: block',
'}',
'.blocklyDeleteIconShape {',
'fill: #000;',
'stroke: #000;',
'stroke-width: 1px;',
'}',
'.blocklyDeleteIconShape.blocklyDeleteIconHighlighted {',
'stroke: #fc3;',
'}',
'.blocklyHtmlInput {',
'border: none;',
'border-radius: 4px;',
@@ -508,9 +567,6 @@ Blockly.Css.CONTENT = [
'.blocklyDropdownMenu {',
'padding: 0 !important;',
/* max-height value is same as the constant
* Blockly.FieldDropdown.MAX_MENU_HEIGHT defined in field_dropdown.js. */
'max-height: 300px !important;',
'}',
/* Override the default Closure URL. */
+14 -2
View File
@@ -26,6 +26,7 @@
goog.provide('Blockly.DraggedConnectionManager');
goog.require('Blockly.BlockAnimations');
goog.require('Blockly.RenderedConnection');
goog.require('goog.math.Coordinate');
@@ -124,6 +125,16 @@ Blockly.DraggedConnectionManager.prototype.wouldDeleteBlock = function() {
return this.wouldDeleteBlock_;
};
/**
* Return whether the block would be connected if dropped immediately, based on
* information from the most recent move event.
* @return {boolean} true if the block would be connected if dropped immediately.
* @package
*/
Blockly.DraggedConnectionManager.prototype.wouldConnectBlock = function() {
return !!this.closestConnection_;
};
/**
* Connect to the closest connection and render the results.
* This should be called at the end of a drag.
@@ -138,7 +149,8 @@ Blockly.DraggedConnectionManager.prototype.applyConnections = function() {
// Determine which connection is inferior (lower in the source stack).
var inferiorConnection = this.localConnection_.isSuperior() ?
this.closestConnection_ : this.localConnection_;
inferiorConnection.getSourceBlock().connectionUiEffect();
Blockly.BlockAnimations.connectionUiEffect(
inferiorConnection.getSourceBlock());
// Bring the just-edited stack to the front.
var rootBlock = this.topBlock_.getRootBlock();
rootBlock.bringToFront();
@@ -213,7 +225,7 @@ Blockly.DraggedConnectionManager.prototype.addHighlighting_ = function() {
Blockly.DraggedConnectionManager.prototype.initAvailableConnections_ = function() {
var available = this.topBlock_.getConnections_(false);
// Also check the last connection on this stack
var lastOnStack = this.topBlock_.lastConnectionInStack_();
var lastOnStack = this.topBlock_.lastConnectionInStack();
if (lastOnStack && lastOnStack != this.topBlock_.nextConnection) {
available.push(lastOnStack);
}
+50 -7
View File
@@ -126,6 +126,30 @@ Blockly.Events.VAR_RENAME = 'var_rename';
*/
Blockly.Events.UI = 'ui';
/**
* Name of event that creates a comment.
* @const
*/
Blockly.Events.COMMENT_CREATE = 'comment_create';
/**
* Name of event that deletes a comment.
* @const
*/
Blockly.Events.COMMENT_DELETE = 'comment_delete';
/**
* Name of event that changes a comment.
* @const
*/
Blockly.Events.COMMENT_CHANGE = 'comment_change';
/**
* Name of event that moves a comment.
* @const
*/
Blockly.Events.COMMENT_MOVE = 'comment_move';
/**
* List of events queued for firing.
* @private
@@ -180,15 +204,22 @@ Blockly.Events.filter = function(queueIn, forward) {
for (var i = 0, event; event = queue[i]; i++) {
if (!event.isNull()) {
var key = [event.type, event.blockId, event.workspaceId].join(' ');
var lastEvent = hash[key];
if (!lastEvent) {
hash[key] = event;
var lastEntry = hash[key];
var lastEvent = lastEntry ? lastEntry.event : null;
if (!lastEntry) {
// Each item in the hash table has the event and the index of that event
// in the input array. This lets us make sure we only merge adjacent
// move events.
hash[key] = { event: event, index: i};
mergedQueue.push(event);
} else if (event.type == Blockly.Events.MOVE) {
} else if (event.type == Blockly.Events.MOVE &&
lastEntry.index == i - 1) {
// Merge move events.
lastEvent.newParentId = event.newParentId;
lastEvent.newInputName = event.newInputName;
lastEvent.newCoordinate = event.newCoordinate;
lastEntry.index = i;
} else if (event.type == Blockly.Events.CHANGE &&
event.element == lastEvent.element &&
event.name == lastEvent.name) {
@@ -203,7 +234,7 @@ Blockly.Events.filter = function(queueIn, forward) {
lastEvent.newValue = event.newValue;
} else {
// Collision: newer events should merge into this event to maintain order
hash[key] = event;
hash[key] = { event: event, index: 1};
mergedQueue.push(event);
}
}
@@ -287,7 +318,7 @@ Blockly.Events.setGroup = function(state) {
*/
Blockly.Events.getDescendantIds_ = function(block) {
var ids = [];
var descendants = block.getDescendants();
var descendants = block.getDescendants(false);
for (var i = 0, descendant; descendant = descendants[i]; i++) {
ids[i] = descendant.id;
}
@@ -328,6 +359,18 @@ Blockly.Events.fromJson = function(json, workspace) {
case Blockly.Events.UI:
event = new Blockly.Events.Ui(null);
break;
case Blockly.Events.COMMENT_CREATE:
event = new Blockly.Events.CommentCreate(null);
break;
case Blockly.Events.COMMENT_CHANGE:
event = new Blockly.Events.CommentChange(null);
break;
case Blockly.Events.COMMENT_MOVE:
event = new Blockly.Events.CommentMove(null);
break;
case Blockly.Events.COMMENT_DELETE:
event = new Blockly.Events.CommentDelete(null);
break;
default:
throw 'Unknown event type.';
}
@@ -350,7 +393,7 @@ Blockly.Events.disableOrphans = function(event) {
var block = workspace.getBlockById(event.blockId);
if (block) {
if (block.getParent() && !block.getParent().disabled) {
var children = block.getDescendants();
var children = block.getDescendants(false);
for (var i = 0, child; child = children[i]; i++) {
child.setDisabled(false);
}
+12 -4
View File
@@ -360,10 +360,7 @@ Blockly.Field.prototype.render_ = function() {
}
// Replace the text.
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
var textNode = document.createTextNode(this.getDisplayText_());
this.textElement_.appendChild(textNode);
this.textElement_.textContent = this.getDisplayText_();
this.updateWidth();
};
@@ -604,3 +601,14 @@ Blockly.Field.prototype.setTooltip = function(_newTip) {
Blockly.Field.prototype.getAbsoluteXY_ = function() {
return goog.style.getPageOffset(this.borderRect_);
};
/**
* Whether this field references any Blockly variables. If true it may need to
* be handled differently during serialization and deserialization. Subclasses
* may override this.
* @return {boolean} True if this field has any variable references.
* @package
*/
Blockly.Field.prototype.referencesVariables = function() {
return false;
};
+51 -50
View File
@@ -53,7 +53,11 @@ goog.require('goog.userAgent');
* @constructor
*/
Blockly.FieldDropdown = function(menuGenerator, opt_validator) {
if (!goog.isFunction(menuGenerator)) {
Blockly.FieldDropdown.validateOptions_(menuGenerator);
}
this.menuGenerator_ = menuGenerator;
this.trimOptions_();
var firstTuple = this.getOptions()[0];
@@ -80,10 +84,9 @@ Blockly.FieldDropdown.fromJson = function(options) {
Blockly.FieldDropdown.CHECKMARK_OVERHANG = 25;
/**
* Maximum height of the dropdown menu,it's also referenced in css.js as
* part of .blocklyDropdownMenu.
* Maximum height of the dropdown menu, as a percentage of the viewport height.
*/
Blockly.FieldDropdown.MAX_MENU_HEIGHT = 300;
Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45;
/**
* Android can't (in 2014) display "▾", so use "▼" instead.
@@ -141,19 +144,8 @@ Blockly.FieldDropdown.prototype.init = function() {
Blockly.FieldDropdown.prototype.showEditor_ = function() {
Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, null);
var menu = this.createMenu_();
this.addEventListeners_(menu);
this.positionMenu_(menu);
};
/**
* Add event listeners for actions on the items in the dropdown menu.
* @param {!goog.ui.Menu} menu The menu to add listeners to.
* @private
*/
Blockly.FieldDropdown.prototype.addEventListeners_ = function(menu) {
this.addActionListener_(menu);
this.addTouchStartListener_(menu);
this.addTouchEndListener_(menu);
this.positionMenu_(menu);
};
/**
@@ -177,38 +169,6 @@ Blockly.FieldDropdown.prototype.addActionListener_ = function(menu) {
goog.events.listen(menu, goog.ui.Component.EventType.ACTION, callback);
};
/**
* Add a listener for touch start events on menu items.
* @param {!goog.ui.Menu} menu The menu to add the listener to.
* @private
*/
Blockly.FieldDropdown.prototype.addTouchStartListener_ = function(menu) {
// Listen for touch events (why doesn't Closure handle this already?).
function callback(e) {
var control = this.getOwnerControl(/** @type {Node} */ (e.target));
// Highlight the menu item.
control.handleMouseDown(e);
}
menu.getHandler().listen(
menu.getElement(), goog.events.EventType.TOUCHSTART, callback);
};
/**
* Add a listener for touch end events on menu items.
* @param {!goog.ui.Menu} menu The menu to add the listener to.
* @private
*/
Blockly.FieldDropdown.prototype.addTouchEndListener_ = function(menu) {
// Listen for touch events (why doesn't Closure handle this already?).
function callbackTouchEnd(e) {
var control = this.getOwnerControl(/** @type {Node} */ (e.target));
// Activate the menu item.
control.performActionInternal(e);
}
menu.getHandler().listen(
menu.getElement(), goog.events.EventType.TOUCHEND, callbackTouchEnd);
};
/**
* Create and populate the menu and menu items for this dropdown, based on
* the options list.
@@ -254,8 +214,10 @@ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) {
this.createWidget_(menu);
var menuSize = Blockly.utils.uiMenu.getSize(menu);
if (menuSize.height > Blockly.FieldDropdown.MAX_MENU_HEIGHT) {
menuSize.height = Blockly.FieldDropdown.MAX_MENU_HEIGHT;
var menuMaxHeightPx = Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH
* document.documentElement.clientHeight;
if (menuSize.height > menuMaxHeightPx) {
menuSize.height = menuMaxHeightPx;
}
if (this.sourceBlock_.RTL) {
@@ -407,10 +369,13 @@ Blockly.FieldDropdown.prototype.isOptionListDynamic = function() {
* Return a list of the options for this dropdown.
* @return {!Array.<!Array>} Array of option tuples:
* (human-readable text or image, language-neutral name).
* @throws If generated options are incorrectly structured.
*/
Blockly.FieldDropdown.prototype.getOptions = function() {
if (goog.isFunction(this.menuGenerator_)) {
return this.menuGenerator_.call(this);
var generatedOptions = this.menuGenerator_.call(this);
Blockly.FieldDropdown.validateOptions_(generatedOptions);
return generatedOptions;
}
return /** @type {!Array.<!Array.<string>>} */ (this.menuGenerator_);
};
@@ -565,4 +530,40 @@ Blockly.FieldDropdown.prototype.dispose = function() {
Blockly.FieldDropdown.superClass_.dispose.call(this);
};
/**
* Validates the data structure to be processed as an options list.
* @param {?} options The proposed dropdown options.
* @throws If proposed options are incorrectly structured.
* @private
*/
Blockly.FieldDropdown.validateOptions_ = function(options) {
if (!goog.isArray(options)) {
throw 'FieldDropdown options must be an array.';
}
var foundError = false;
for (var i = 0; i < options.length; ++i) {
var tuple = options[i];
if (!goog.isArray(options)) {
foundError = true;
console.error(
'Invalid option[' + i + ']: Each FieldDropdown option must be an ' +
'array. Found: ', tuple);
} else if (!goog.isString(tuple[1])) {
foundError = true;
console.error(
'Invalid option[' + i + ']: Each FieldDropdown option id must be ' +
'a string. Found ' + tuple[1] + ' in: ', tuple);
} else if (!goog.isString(tuple[0]) && !goog.isString(tuple[0].src)) {
foundError = true;
console.error(
'Invalid option[' + i + ']: Each FieldDropdown option must have a ' +
'string label or image description. Found' + tuple[0] + ' in: ',
tuple);
}
}
if (foundError) {
throw 'Found invalid FieldDropdown options.';
}
};
Blockly.Field.register('field_dropdown', Blockly.FieldDropdown);
+1 -1
View File
@@ -173,7 +173,7 @@ Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) {
*/
Blockly.FieldTextInput.prototype.showPromptEditor_ = function() {
var fieldText = this;
Blockly.prompt(Blockly.Msg.CHANGE_VALUE_TITLE, this.text_,
Blockly.prompt(Blockly.Msg['CHANGE_VALUE_TITLE'], this.text_,
function(newValue) {
if (fieldText.sourceBlock_) {
newValue = fieldText.callValidator(newValue);
+13 -3
View File
@@ -314,11 +314,11 @@ Blockly.FieldVariable.dropdownCreate = function() {
// Set the UUID as the internal representation of the variable.
options[i] = [variableModelList[i].name, variableModelList[i].getId()];
}
options.push([Blockly.Msg.RENAME_VARIABLE, Blockly.RENAME_VARIABLE_ID]);
if (Blockly.Msg.DELETE_VARIABLE) {
options.push([Blockly.Msg['RENAME_VARIABLE'], Blockly.RENAME_VARIABLE_ID]);
if (Blockly.Msg['DELETE_VARIABLE']) {
options.push(
[
Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
Blockly.Msg['DELETE_VARIABLE'].replace('%1', name),
Blockly.DELETE_VARIABLE_ID
]
);
@@ -353,4 +353,14 @@ Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) {
this.setValue(id);
};
/**
* Overrides referencesVariables(), indicating this field refers to a variable.
* @return {boolean} True.
* @package
* @override
*/
Blockly.FieldVariable.prototype.referencesVariables = function() {
return true;
};
Blockly.Field.register('field_variable', Blockly.FieldVariable);
+21 -14
View File
@@ -50,7 +50,7 @@ Blockly.Flyout = function(workspaceOptions) {
/**
* @type {!Blockly.Workspace}
* @private
* @protected
*/
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
this.workspace_.isFlyout = true;
@@ -64,7 +64,7 @@ Blockly.Flyout = function(workspaceOptions) {
/**
* Position of the toolbox and flyout relative to the workspace.
* @type {number}
* @private
* @protected
*/
this.toolboxPosition_ = workspaceOptions.toolboxPosition;
@@ -86,7 +86,7 @@ Blockly.Flyout = function(workspaceOptions) {
/**
* List of visible buttons.
* @type {!Array.<!Blockly.FlyoutButton>}
* @private
* @protected
*/
this.buttons_ = [];
@@ -165,14 +165,14 @@ Blockly.Flyout.prototype.SCROLLBAR_PADDING = 2;
/**
* Width of flyout.
* @type {number}
* @private
* @protected
*/
Blockly.Flyout.prototype.width_ = 0;
/**
* Height of flyout.
* @type {number}
* @private
* @protected
*/
Blockly.Flyout.prototype.height_ = 0;
@@ -190,7 +190,7 @@ Blockly.Flyout.prototype.height_ = 0;
* This is used to know when to create a new block and when to scroll the
* flyout. Setting it to 360 means that all drags create a new block.
* @type {number}
* @private
* @protected
*/
Blockly.Flyout.prototype.dragAngleRange_ = 70;
@@ -366,13 +366,20 @@ Blockly.Flyout.prototype.updateDisplay_ = function() {
* @param {number} height The computed height of the flyout's SVG group.
* @param {number} x The computed x origin of the flyout's SVG group.
* @param {number} y The computed y origin of the flyout's SVG group.
* @private
* @protected
*/
Blockly.Flyout.prototype.positionAt_ = function(width, height, x, y) {
this.svgGroup_.setAttribute("width", width);
this.svgGroup_.setAttribute("height", height);
var transform = 'translate(' + x + 'px,' + y + 'px)';
Blockly.utils.setCssTransform(this.svgGroup_, transform);
if (this.svgGroup_.tagName == 'svg') {
var transform = 'translate(' + x + 'px,' + y + 'px)';
Blockly.utils.setCssTransform(this.svgGroup_, transform);
} else {
// IE and Edge don't support CSS transforms on SVG elements so
// it's important to set the transform on the SVG element itself
var transform = 'translate(' + x + ',' + y + ')';
this.svgGroup_.setAttribute("transform", transform);
}
// Update the scrollbar (if one exists).
if (this.scrollbar_) {
@@ -537,7 +544,7 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() {
* @param {!Blockly.Block} block The block to add listeners for.
* @param {!Element} rect The invisible rectangle under the block that acts as
* a mat for that block.
* @private
* @protected
*/
Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) {
this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mousedown', null,
@@ -629,7 +636,7 @@ Blockly.Flyout.prototype.createBlock = function(originalBlock) {
* @param {!Blockly.FlyoutButton} button The button to initialize and place.
* @param {number} x The x position of the cursor during this layout pass.
* @param {number} y The y position of the cursor during this layout pass.
* @private
* @protected
*/
Blockly.Flyout.prototype.initFlyoutButton_ = function(button, x, y) {
var buttonSvg = button.createDom();
@@ -655,7 +662,7 @@ Blockly.Flyout.prototype.initFlyoutButton_ = function(button, x, y) {
* placed.
* @return {!SVGElement} Newly created SVG element for the rectangle behind the
* block.
* @private
* @protected
*/
Blockly.Flyout.prototype.createRect_ = function(block, x, y, blockHW, index) {
// Create an invisible rectangle under the block to act as a button. Just
@@ -683,7 +690,7 @@ Blockly.Flyout.prototype.createRect_ = function(block, x, y, blockHW, index) {
* hats, and any other protrusions we invent.
* @param {!SVGElement} rect The rectangle to move directly behind the block.
* @param {!Blockly.BlockSvg} block The block the rectangle should be behind.
* @private
* @protected
*/
Blockly.Flyout.prototype.moveRectToBlock_ = function(rect, block) {
var blockHW = block.getHeightWidth();
@@ -717,7 +724,7 @@ Blockly.Flyout.prototype.filterForCapacity_ = function() {
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; block = blocks[i]; i++) {
if (this.permanentlyDisabled_.indexOf(block) == -1) {
var allBlocks = block.getDescendants();
var allBlocks = block.getDescendants(false);
block.setDisabled(allBlocks.length > remainingCapacity);
}
}
+3 -3
View File
@@ -161,7 +161,7 @@ Blockly.FlyoutButton.prototype.createDom = function() {
'text-anchor': 'middle'
},
this.svgGroup_);
svgText.textContent = this.text_;
svgText.textContent = Blockly.utils.replaceMessageReferences(this.text_);
this.width = Blockly.Field.getCachedWidth(svgText);
this.height = 20; // Can't compute it :(
@@ -179,8 +179,8 @@ Blockly.FlyoutButton.prototype.createDom = function() {
this.updateTransform_();
this.mouseUpWrapper_ = Blockly.bindEventWithChecks_(this.svgGroup_, 'mouseup',
this, this.onMouseUp_);
this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
this.svgGroup_, 'mouseup', this, this.onMouseUp_);
return this.svgGroup_;
};
+1 -1
View File
@@ -261,7 +261,7 @@ Blockly.HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
for (var i = 0, item; item = contents[i]; i++) {
if (item.type == 'block') {
var block = item.block;
var allBlocks = block.getDescendants();
var allBlocks = block.getDescendants(false);
for (var j = 0, child; child = allBlocks[j]; j++) {
// Mark blocks as being inside a flyout. This is used to detect and
// prevent the closure of the flyout if the user right-clicks on such a
+4 -3
View File
@@ -212,8 +212,9 @@ Blockly.VerticalFlyout.prototype.wheel_ = function(e) {
var delta = e.deltaY;
if (delta) {
if (goog.userAgent.GECKO) {
// Firefox's deltas are a tenth that of Chrome/Safari.
// Firefox's mouse wheel deltas are a tenth that of Chrome/Safari.
// DeltaMode is 1 for a mouse wheel, but not for a trackpad scroll event
if (goog.userAgent.GECKO && (e.deltaMode === 1)) {
delta *= 10;
}
var metrics = this.getMetrics_();
@@ -247,7 +248,7 @@ Blockly.VerticalFlyout.prototype.layout_ = function(contents, gaps) {
for (var i = 0, item; item = contents[i]; i++) {
if (item.type == 'block') {
var block = item.block;
var allBlocks = block.getDescendants();
var allBlocks = block.getDescendants(false);
for (var j = 0, child; child = allBlocks[j]; j++) {
// Mark blocks as being inside a flyout. This is used to detect and
// prevent the closure of the flyout if the user right-clicks on such a
+1 -1
View File
@@ -142,7 +142,7 @@ Blockly.Generator.prototype.prefixLines = function(text, prefix) {
*/
Blockly.Generator.prototype.allNestedComments = function(block) {
var comments = [];
var blocks = block.getDescendants();
var blocks = block.getDescendants(true);
for (var i = 0; i < blocks.length; i++) {
var comment = blocks[i].getCommentText();
if (comment) {
+14 -7
View File
@@ -27,6 +27,7 @@
goog.provide('Blockly.Gesture');
goog.require('Blockly.BlockAnimations');
goog.require('Blockly.BlockDragger');
goog.require('Blockly.BubbleDragger');
goog.require('Blockly.constants');
@@ -68,7 +69,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
* @type {goog.math.Coordinate}
* @private
*/
this.currentDragDeltaXY_ = 0;
this.currentDragDeltaXY_ = null;
/**
* The bubble that the gesture started on, or null if it did not start on a
@@ -468,7 +469,6 @@ Blockly.Gesture.prototype.startDraggingBubble_ = function() {
this.bubbleDragger_.dragBubble(this.mostRecentEvent_,
this.currentDragDeltaXY_);
};
/**
* Start a gesture: update the workspace to indicate that a gesture is in
* progress and bind mousemove and mouseup handlers.
@@ -482,7 +482,7 @@ Blockly.Gesture.prototype.doStart = function(e) {
}
this.hasStarted_ = true;
Blockly.BlockSvg.disconnectUiStop_();
Blockly.BlockAnimations.disconnectUiStop();
this.startWorkspace_.updateScreenCalculationsIfScrolled();
if (this.startWorkspace_.isMutator) {
// Mutator's coordinate system could be out of date because the bubble was
@@ -627,6 +627,8 @@ Blockly.Gesture.prototype.handleRightClick = function(e) {
this.bringBlockToFront_();
Blockly.hideChaff(this.flyout_);
this.targetBlock_.showContextMenu_(e);
} else if (this.startBubble_) {
this.startBubble_.showContextMenu_(e);
} else if (this.startWorkspace_ && !this.flyout_) {
Blockly.hideChaff();
this.startWorkspace_.showContextMenu_(e);
@@ -705,8 +707,9 @@ Blockly.Gesture.prototype.handleBubbleStart = function(e, bubble) {
* @private
*/
Blockly.Gesture.prototype.doBubbleClick_ = function() {
// TODO: This isn't really enough, is it.
this.startBubble_.promote_();
// TODO (#1673): Consistent handling of single clicks.
this.startBubble_.setFocus && this.startBubble_.setFocus();
this.startBubble_.select && this.startBubble_.select();
};
/**
@@ -751,6 +754,7 @@ Blockly.Gesture.prototype.doWorkspaceClick_ = function() {
}
};
/* End functions defining what actions to take to execute clicks on each type
* of target. */
@@ -801,7 +805,8 @@ Blockly.Gesture.prototype.setStartBubble = function(bubble) {
* @package
*/
Blockly.Gesture.prototype.setStartBlock = function(block) {
if (!this.startBlock_) {
// If the gesture already went through a bubble, don't set the start block.
if (!this.startBlock_ && !this.startBubble_) {
this.startBlock_ = block;
if (block.isInFlyout && block != block.getRootBlock()) {
this.setTargetBlock_(block.getRootBlock());
@@ -848,6 +853,7 @@ Blockly.Gesture.prototype.setStartFlyout_ = function(flyout) {
}
};
/* End functions for populating a gesture at mouse down. */
/* Begin helper functions defining types of clicks. Any developer wanting
@@ -898,7 +904,8 @@ Blockly.Gesture.prototype.isFieldClick_ = function() {
* @private
*/
Blockly.Gesture.prototype.isWorkspaceClick_ = function() {
var onlyTouchedWorkspace = !this.startBlock_ && !this.startField_;
var onlyTouchedWorkspace = !this.startBlock_ && !this.startBubble_ &&
!this.startField_;
return onlyTouchedWorkspace && !this.hasExceededDragRadius_;
};
+1 -2
View File
@@ -32,7 +32,6 @@ goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.Events.Ui');
goog.require('Blockly.Icon');
goog.require('Blockly.WorkspaceSvg');
goog.require('goog.Timer');
goog.require('goog.dom');
@@ -258,7 +257,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
}
this.rootBlock_ = this.block_.decompose(this.workspace_);
var blocks = this.rootBlock_.getDescendants();
var blocks = this.rootBlock_.getDescendants(false);
for (var i = 0, child; child = blocks[i]; i++) {
child.render();
}
+2 -2
View File
@@ -188,7 +188,7 @@ Blockly.Procedures.flyoutCategory = function(workspace) {
block.setAttribute('type', 'procedures_defnoreturn');
block.setAttribute('gap', 16);
var nameField = goog.dom.createDom('field', null,
Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE);
Blockly.Msg['PROCEDURES_DEFNORETURN_PROCEDURE']);
nameField.setAttribute('name', 'NAME');
block.appendChild(nameField);
xmlList.push(block);
@@ -201,7 +201,7 @@ Blockly.Procedures.flyoutCategory = function(workspace) {
block.setAttribute('type', 'procedures_defreturn');
block.setAttribute('gap', 16);
var nameField = goog.dom.createDom('field', null,
Blockly.Msg.PROCEDURES_DEFRETURN_PROCEDURE);
Blockly.Msg['PROCEDURES_DEFRETURN_PROCEDURE']);
nameField.setAttribute('name', 'NAME');
block.appendChild(nameField);
xmlList.push(block);
+4 -6
View File
@@ -180,16 +180,14 @@ Blockly.RenderedConnection.prototype.tighten_ = function() {
* Find the closest compatible connection to this connection.
* All parameters are in workspace units.
* @param {number} maxLimit The maximum radius to another connection.
* @param {number} dx Horizontal offset between this connection's location
* in the database and the current location (as a result of dragging).
* @param {number} dy Vertical offset between this connection's location
* @param {!goog.math.Coordinate} dxy Offset between this connection's location
* in the database and the current location (as a result of dragging).
* @return {!{connection: ?Blockly.Connection, radius: number}} Contains two
* properties: 'connection' which is either another connection or null,
* and 'radius' which is the distance.
*/
Blockly.RenderedConnection.prototype.closest = function(maxLimit, dx, dy) {
return this.dbOpposite_.searchForClosest(this, maxLimit, dx, dy);
Blockly.RenderedConnection.prototype.closest = function(maxLimit, dxy) {
return this.dbOpposite_.searchForClosest(this, maxLimit, dxy);
};
/**
@@ -286,7 +284,7 @@ Blockly.RenderedConnection.prototype.setHidden = function(hidden) {
Blockly.RenderedConnection.prototype.hideAll = function() {
this.setHidden(true);
if (this.targetConnection) {
var blocks = this.targetBlock().getDescendants();
var blocks = this.targetBlock().getDescendants(false);
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
// Hide all connections of all children.
+11 -7
View File
@@ -334,15 +334,19 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
// (eg. `%{BKY_MATH_HUE}`).
var colour = Blockly.utils.replaceMessageReferences(
childIn.getAttribute('colour'));
if (goog.isString(colour)) {
if (/^#[0-9a-fA-F]{6}$/.test(colour)) {
childOut.hexColour = colour;
} else {
childOut.hexColour = Blockly.hueToRgb(Number(colour));
}
if (colour === null || colour === '') {
// No attribute. No colour.
childOut.hexColour = '';
} else if (/^#[0-9a-fA-F]{6}$/.test(colour)) {
childOut.hexColour = colour;
this.hasColours_ = true;
} else if (typeof colour === 'number'
|| (typeof colour === 'string' && !isNaN(Number(colour)))) {
childOut.hexColour = Blockly.hueToRgb(Number(colour));
this.hasColours_ = true;
} else {
childOut.hexColour = '';
console.warn('Toolbox category "' + categoryName + '" has unrecognized colour attribute: ' + colour);
}
if (childIn.getAttribute('expanded') == 'true') {
if (childOut.blocks.length) {
@@ -396,7 +400,7 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
*/
Blockly.Toolbox.prototype.addColour_ = function(opt_tree) {
var tree = opt_tree || this.tree_;
var children = tree.getChildren();
var children = tree.getChildren(false);
for (var i = 0, child; child = children[i]; i++) {
var element = child.getRowElement();
if (element) {
+1 -1
View File
@@ -48,7 +48,7 @@ Blockly.Touch.touchIdentifier_ = null;
* @type {Object}
*/
Blockly.Touch.TOUCH_MAP = {};
if (window && window.PointerEvent) {
if (goog.global.PointerEvent) {
Blockly.Touch.TOUCH_MAP = {
'mousedown': ['pointerdown'],
'mouseenter': ['pointerenter'],
+3 -4
View File
@@ -26,7 +26,6 @@
goog.provide('Blockly.Trashcan');
goog.require('goog.Timer');
goog.require('goog.dom');
goog.require('goog.math');
goog.require('goog.math.Rect');
@@ -234,7 +233,7 @@ Blockly.Trashcan.prototype.dispose = function() {
}
this.svgLid_ = null;
this.workspace_ = null;
goog.Timer.clear(this.lidTask_);
clearTimeout(this.lidTask_);
};
/**
@@ -299,7 +298,7 @@ Blockly.Trashcan.prototype.setOpen_ = function(state) {
if (this.isOpen == state) {
return;
}
goog.Timer.clear(this.lidTask_);
clearTimeout(this.lidTask_);
this.isOpen = state;
this.animateLid_();
};
@@ -319,7 +318,7 @@ Blockly.Trashcan.prototype.animateLid_ = function() {
var opacity = goog.math.lerp(0.4, 0.8, this.lidOpen_);
this.svgGroup_.style.opacity = opacity;
if (this.lidOpen_ > 0 && this.lidOpen_ < 1) {
this.lidTask_ = goog.Timer.callOnce(this.animateLid_, 20, this);
this.lidTask_ = setTimeout(this.animateLid_.bind(this), 20);
}
};
+7 -6
View File
@@ -34,6 +34,10 @@ goog.require('goog.math.Coordinate');
/**
* Class for a UI event.
* UI events are events that don't need to be sent over the wire for multi-user
* editing to work (e.g. scrolling the workspace, zooming, opening toolbox
* categories).
* UI events do not undo or redo.
* @param {Blockly.Block} block The affected block.
* @param {string} element One of 'selected', 'comment', 'mutator', etc.
* @param {*} oldValue Previous value of element.
@@ -42,16 +46,13 @@ goog.require('goog.math.Coordinate');
* @constructor
*/
Blockly.Events.Ui = function(block, element, oldValue, newValue) {
if (!block) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.Ui.superClass_.constructor.call(this);
this.blockId = block.id;
this.workspaceId = block.workspace.id;
this.blockId = block ? block.id : null;
this.workspaceId = block ? block.workspace.id : null;
this.element = element;
this.oldValue = oldValue;
this.newValue = newValue;
// UI events do not undo or redo.
this.recordUndo = false;
};
goog.inherits(Blockly.Events.Ui, Blockly.Events.Abstract);
+5 -47
View File
@@ -39,19 +39,6 @@ goog.require('goog.math.Coordinate');
goog.require('goog.userAgent');
/**
* To allow ADVANCED_OPTIMIZATIONS, combining variable.name and variable['name']
* is not possible. To access the exported Blockly.Msg.Something it needs to be
* accessed through the exact name that was exported. Note, that all the exports
* are happening as the last thing in the generated js files, so they won't be
* accessible before JavaScript loads!
* @return {!Object.<string, string>} The message array.
* @private
*/
Blockly.utils.getMessageArray_ = function() {
return goog.global['Blockly']['Msg'];
};
/**
* Remove an attribute from a element even if it's in IE 10.
* Similar to Element.removeAttribute() but it works on SVG elements in IE 10.
@@ -210,9 +197,8 @@ Blockly.utils.getInjectionDivXY_ = function(element) {
var y = 0;
while (element) {
var xy = Blockly.utils.getRelativeXY(element);
var scale = Blockly.utils.getScale_(element);
x = (x * scale) + xy.x;
y = (y * scale) + xy.y;
x = x + xy.x;
y = y + xy.y;
var classes = element.getAttribute('class') || '';
if ((' ' + classes + ' ').indexOf(' injectionDiv ') != -1) {
break;
@@ -222,25 +208,6 @@ Blockly.utils.getInjectionDivXY_ = function(element) {
return new goog.math.Coordinate(x, y);
};
/**
* Return the scale of this element.
* @param {!Element} element The element to find the coordinates of.
* @return {!number} number represending the scale applied to the element.
* @private
*/
Blockly.utils.getScale_ = function(element) {
var scale = 1;
var transform = element.getAttribute('transform');
if (transform) {
var transformComponents =
transform.match(Blockly.utils.getScale_.REGEXP_);
if (transformComponents && transformComponents[0]) {
scale = parseFloat(transformComponents[0]);
}
}
return scale;
};
/**
* Static regex to pull the x,y values out of an SVG translate() directive.
* Note that Firefox and IE (9,10) return 'translate(12)' instead of
@@ -253,15 +220,6 @@ Blockly.utils.getScale_ = function(element) {
Blockly.utils.getRelativeXY.XY_REGEX_ =
/translate\(\s*([-+\d.e]+)([ ,]\s*([-+\d.e]+)\s*\))?/;
/**
* Static regex to pull the scale values out of a transform style property.
* Accounts for same exceptions as XY_REGEXP_.
* @type {!RegExp}
* @private
*/
Blockly.utils.getScale_REGEXP_ = /scale\(\s*([-+\d.e]+)\s*\)/;
/**
* Static regex to pull the x,y,z values out of a translate3d() style property.
* Accounts for same exceptions as XY_REGEXP_.
@@ -464,7 +422,7 @@ Blockly.utils.replaceMessageReferences = function(message) {
Blockly.utils.checkMessageReferences = function(message) {
var validSoFar = true;
var msgTable = Blockly.utils.getMessageArray_();
var msgTable = Blockly.Msg;
// TODO(#1169): Implement support for other string tables, prefixes other than BKY_.
var regex = /%{(BKY_[A-Z][A-Z0-9_]*)}/gi;
@@ -569,8 +527,8 @@ Blockly.utils.tokenizeInterpolation_ = function(message,
// are defined in ../msgs/ files.
var bklyKey = goog.string.startsWith(keyUpper, 'BKY_') ?
keyUpper.substring(4) : null;
if (bklyKey && bklyKey in Blockly.utils.getMessageArray_()) {
var rawValue = Blockly.utils.getMessageArray_()[bklyKey];
if (bklyKey && bklyKey in Blockly.Msg) {
var rawValue = Blockly.Msg[bklyKey];
if (goog.isString(rawValue)) {
// Attempt to dereference substrings, too, appending to the end.
Array.prototype.push.apply(tokens,
+2 -2
View File
@@ -230,7 +230,7 @@ Blockly.VariableMap.prototype.deleteVariableById = function(id) {
if (block.type == 'procedures_defnoreturn' ||
block.type == 'procedures_defreturn') {
var procedureName = block.getFieldValue('NAME');
var deleteText = Blockly.Msg.CANNOT_DELETE_VARIABLE_PROCEDURE.
var deleteText = Blockly.Msg['CANNOT_DELETE_VARIABLE_PROCEDURE'].
replace('%1', variableName).
replace('%2', procedureName);
Blockly.alert(deleteText);
@@ -241,7 +241,7 @@ Blockly.VariableMap.prototype.deleteVariableById = function(id) {
var map = this;
if (uses.length > 1) {
// Confirm before deleting multiple blocks.
var confirmText = Blockly.Msg.DELETE_VARIABLE_CONFIRMATION.
var confirmText = Blockly.Msg['DELETE_VARIABLE_CONFIRMATION'].
replace('%1', String(uses.length)).
replace('%2', variableName);
Blockly.confirm(confirmText,
+8 -8
View File
@@ -129,7 +129,7 @@ Blockly.Variables.allDeveloperVariables = function(workspace) {
Blockly.Variables.flyoutCategory = function(workspace) {
var xmlList = [];
var button = goog.dom.createDom('button');
button.setAttribute('text', Blockly.Msg.NEW_VARIABLE);
button.setAttribute('text', '%{BKY_NEW_VARIABLE}');
button.setAttribute('callbackKey', 'CREATE_VARIABLE');
workspace.registerButtonCallback('CREATE_VARIABLE', function(button) {
@@ -267,7 +267,7 @@ Blockly.Variables.createVariableButtonHandler = function(
var type = opt_type || '';
// This function needs to be named so it can be called recursively.
var promptAndCheckWithAlert = function(defaultName) {
Blockly.Variables.promptName(Blockly.Msg.NEW_VARIABLE_TITLE, defaultName,
Blockly.Variables.promptName(Blockly.Msg['NEW_VARIABLE_TITLE'], defaultName,
function(text) {
if (text) {
var existing =
@@ -275,10 +275,10 @@ Blockly.Variables.createVariableButtonHandler = function(
if (existing) {
var lowerCase = text.toLowerCase();
if (existing.type == type) {
var msg = Blockly.Msg.VARIABLE_ALREADY_EXISTS.replace(
var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS'].replace(
'%1', lowerCase);
} else {
var msg = Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE;
var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE'];
msg = msg.replace('%1', lowerCase).replace('%2', existing.type);
}
Blockly.alert(msg,
@@ -336,14 +336,14 @@ Blockly.Variables.renameVariable = function(workspace, variable,
// This function needs to be named so it can be called recursively.
var promptAndCheckWithAlert = function(defaultName) {
var promptText =
Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', variable.name);
Blockly.Msg['RENAME_VARIABLE_TITLE'].replace('%1', variable.name);
Blockly.Variables.promptName(promptText, defaultName,
function(newName) {
if (newName) {
var existing = Blockly.Variables.nameUsedWithOtherType_(newName,
variable.type, workspace);
if (existing) {
var msg = Blockly.Msg.VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE
var msg = Blockly.Msg['VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE']
.replace('%1', newName.toLowerCase())
.replace('%2', existing.type);
Blockly.alert(msg,
@@ -380,8 +380,8 @@ Blockly.Variables.promptName = function(promptText, defaultText, callback) {
// Beyond this, all names are legal.
if (newVar) {
newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
if (newVar == Blockly.Msg.RENAME_VARIABLE ||
newVar == Blockly.Msg.NEW_VARIABLE) {
if (newVar == Blockly.Msg['RENAME_VARIABLE'] ||
newVar == Blockly.Msg['NEW_VARIABLE']) {
// Ok, not ALL names are legal...
newVar = null;
}
+3 -3
View File
@@ -54,14 +54,14 @@ Blockly.VariablesDynamic.onCreateVariableButtonClick_Colour = function(button) {
Blockly.VariablesDynamic.flyoutCategory = function(workspace) {
var xmlList = [];
var button = goog.dom.createDom('button');
button.setAttribute('text', Blockly.Msg.NEW_STRING_VARIABLE);
button.setAttribute('text', Blockly.Msg['NEW_STRING_VARIABLE']);
button.setAttribute('callbackKey', 'CREATE_VARIABLE_STRING');
xmlList.push(button);
button = goog.dom.createDom('button');
button.setAttribute('text', Blockly.Msg.NEW_NUMBER_VARIABLE);
button.setAttribute('text', Blockly.Msg['NEW_NUMBER_VARIABLE']);
button.setAttribute('callbackKey', 'CREATE_VARIABLE_NUMBER');
xmlList.push(button);button = goog.dom.createDom('button');
button.setAttribute('text', Blockly.Msg.NEW_COLOUR_VARIABLE);
button.setAttribute('text', Blockly.Msg['NEW_COLOUR_VARIABLE']);
button.setAttribute('callbackKey', 'CREATE_VARIABLE_COLOUR');
xmlList.push(button);
+123 -19
View File
@@ -27,6 +27,7 @@
goog.provide('Blockly.Workspace');
goog.require('Blockly.VariableMap');
goog.require('Blockly.WorkspaceComment');
goog.require('goog.array');
goog.require('goog.math');
@@ -55,6 +56,16 @@ Blockly.Workspace = function(opt_options) {
* @private
*/
this.topBlocks_ = [];
/**
* @type {!Array.<!Blockly.WorkspaceComment>}
* @private
*/
this.topComments_ = [];
/**
* @type {!Object}
* @private
*/
this.commentDB_ = Object.create(null);
/**
* @type {!Array.<!Function>}
* @private
@@ -104,6 +115,13 @@ Blockly.Workspace = function(opt_options) {
*/
Blockly.Workspace.prototype.rendered = false;
/**
* Returns `true` if the workspace is currently in the process of a bulk clear.
* @type {boolean}
* @package
*/
Blockly.Workspace.prototype.isClearing = false;
/**
* Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets it to unlimited.
* @type {number}
@@ -171,34 +189,109 @@ Blockly.Workspace.prototype.getTopBlocks = function(ordered) {
};
/**
* Find all blocks in workspace. No particular order.
* Add a comment to the list of top comments.
* @param {!Blockly.WorkspaceComment} comment comment to add.
* @package
*/
Blockly.Workspace.prototype.addTopComment = function(comment) {
this.topComments_.push(comment);
// Note: If the comment database starts to hold block comments, this may need
// to move to a separate function.
if (this.commentDB_[comment.id]) {
console.warn('Overriding an existing comment on this workspace, with id "' +
comment.id + '"');
}
this.commentDB_[comment.id] = comment;
};
/**
* Remove a comment from the list of top comments.
* @param {!Blockly.WorkspaceComment} comment comment to remove.
* @package
*/
Blockly.Workspace.prototype.removeTopComment = function(comment) {
if (!goog.array.remove(this.topComments_, comment)) {
throw 'Comment not present in workspace\'s list of top-most comments.';
}
// Note: If the comment database starts to hold block comments, this may need
// to move to a separate function.
delete this.commentDB_[comment.id];
};
/**
* Finds the top-level comments and returns them. Comments are optionally sorted
* by position; top to bottom (with slight LTR or RTL bias).
* @param {boolean} ordered Sort the list if true.
* @return {!Array.<!Blockly.WorkspaceComment>} The top-level comment objects.
* @package
*/
Blockly.Workspace.prototype.getTopComments = function(ordered) {
// Copy the topComments_ list.
var comments = [].concat(this.topComments_);
if (ordered && comments.length > 1) {
var offset = Math.sin(goog.math.toRadians(Blockly.Workspace.SCAN_ANGLE));
if (this.RTL) {
offset *= -1;
}
comments.sort(function(a, b) {
var aXY = a.getRelativeToSurfaceXY();
var bXY = b.getRelativeToSurfaceXY();
return (aXY.y + offset * aXY.x) - (bXY.y + offset * bXY.x);
});
}
return comments;
};
/**
* Find all blocks in workspace. Blocks are optionally sorted
* by position; top to bottom (with slight LTR or RTL bias).
* @param {boolean} ordered Sort the list if true.
* @return {!Array.<!Blockly.Block>} Array of blocks.
*/
Blockly.Workspace.prototype.getAllBlocks = function() {
var blocks = this.getTopBlocks(false);
for (var i = 0; i < blocks.length; i++) {
blocks.push.apply(blocks, blocks[i].getChildren());
Blockly.Workspace.prototype.getAllBlocks = function(ordered) {
if (ordered) {
// Slow, but ordered.
var topBlocks = this.getTopBlocks(true);
var blocks = [];
for (var i = 0; i < topBlocks.length; i++) {
blocks.push.apply(blocks, topBlocks[i].getDescendants(true));
}
} else {
// Fast, but in no particular order.
var blocks = this.getTopBlocks(false);
for (var i = 0; i < blocks.length; i++) {
blocks.push.apply(blocks, blocks[i].getChildren(false));
}
}
return blocks;
};
/**
* Dispose of all blocks in workspace.
* Dispose of all blocks and comments in workspace.
*/
Blockly.Workspace.prototype.clear = function() {
var existingGroup = Blockly.Events.getGroup();
if (!existingGroup) {
Blockly.Events.setGroup(true);
}
while (this.topBlocks_.length) {
this.topBlocks_[0].dispose();
}
if (!existingGroup) {
Blockly.Events.setGroup(false);
}
this.variableMap_.clear();
if (this.potentialVariableMap_) {
this.potentialVariableMap_.clear();
this.isClearing = true;
try {
var existingGroup = Blockly.Events.getGroup();
if (!existingGroup) {
Blockly.Events.setGroup(true);
}
while (this.topBlocks_.length) {
this.topBlocks_[0].dispose();
}
while (this.topComments_.length) {
this.topComments_[this.topComments_.length - 1].dispose();
}
if (!existingGroup) {
Blockly.Events.setGroup(false);
}
this.variableMap_.clear();
if (this.potentialVariableMap_) {
this.potentialVariableMap_.clear();
}
} finally {
this.isClearing = false;
}
};
@@ -446,6 +539,17 @@ Blockly.Workspace.prototype.getBlockById = function(id) {
return this.blockDB_[id] || null;
};
/**
* Find the comment on this workspace with the specified ID.
* @param {string} id ID of comment to find.
* @return {Blockly.WorkspaceComment} The sought after comment or null if not
* found.
* @package
*/
Blockly.Workspace.prototype.getCommentById = function(id) {
return this.commentDB_[id] || null;
};
/**
* Checks whether all value and statement inputs in the workspace are filled
* with blocks.
+370
View File
@@ -0,0 +1,370 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 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 Object representing a code comment on the workspace.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.WorkspaceComment');
goog.require('Blockly.Events.CommentChange');
goog.require('Blockly.Events.CommentCreate');
goog.require('Blockly.Events.CommentDelete');
goog.require('Blockly.Events.CommentMove');
goog.require('goog.math.Coordinate');
/**
* Class for a workspace comment.
* @param {!Blockly.Workspace} workspace The block's workspace.
* @param {string} content The content of this workspace comment.
* @param {number} height Height of the comment.
* @param {number} width Width of the comment.
* @param {string=} opt_id Optional ID. Use this ID if provided, otherwise
* create a new ID.
* @constructor
*/
Blockly.WorkspaceComment = function(workspace, content, height, width, opt_id) {
/** @type {string} */
this.id = (opt_id && !workspace.getCommentById(opt_id)) ?
opt_id : Blockly.utils.genUid();
workspace.addTopComment(this);
/**
* The comment's position in workspace units. (0, 0) is at the workspace's
* origin; scale does not change this value.
* @type {!goog.math.Coordinate}
* @protected
*/
this.xy_ = new goog.math.Coordinate(0, 0);
/**
* The comment's height in workspace units. Scale does not change this value.
* @type {number}
* @private
*/
this.height_ = height;
/**
* The comment's width in workspace units. Scale does not change this value.
* @type {number}
* @private
*/
this.width_ = width;
/**
* @type {!Blockly.Workspace}
*/
this.workspace = workspace;
/**
* @protected
* @type {boolean}
*/
this.RTL = workspace.RTL;
/**
* @type {boolean}
* @private
*/
this.deletable_ = true;
/**
* @type {boolean}
* @private
*/
this.movable_ = true;
/**
* @protected
* @type {!string}
*/
this.content_ = content;
/**
* @package
* @type {boolean}
*/
this.isComment = true;
Blockly.WorkspaceComment.fireCreateEvent(this);
};
/**
* Dispose of this comment.
* @package
*/
Blockly.WorkspaceComment.prototype.dispose = function() {
if (!this.workspace) {
// The comment has already been deleted.
return;
}
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.CommentDelete(this));
}
// Remove from the list of top comments and the comment database.
this.workspace.removeTopComment(this);
this.workspace = null;
};
// Height, width, x, and y are all stored on even non-rendered comments, to
// preserve state if you pass the contents through a headless workspace.
/**
* Get comment height.
* @return {number} comment height.
* @package
*/
Blockly.WorkspaceComment.prototype.getHeight = function() {
return this.height_;
};
/**
* Set comment height.
* @param {number} height comment height.
* @package
*/
Blockly.WorkspaceComment.prototype.setHeight = function(height) {
this.height_ = height;
};
/**
* Get comment width.
* @return {number} comment width.
* @package
*/
Blockly.WorkspaceComment.prototype.getWidth = function() {
return this.width_;
};
/**
* Set comment width.
* @param {number} width comment width.
* @package
*/
Blockly.WorkspaceComment.prototype.setWidth = function(width) {
this.width_ = width;
};
/**
* Get stored location.
* @return {!goog.math.Coordinate} The comment's stored location. This is not
* valid if the comment is currently being dragged.
* @package
*/
Blockly.WorkspaceComment.prototype.getXY = function() {
return this.xy_.clone();
};
/**
* Move a comment by a relative offset.
* @param {number} dx Horizontal offset, in workspace units.
* @param {number} dy Vertical offset, in workspace units.
* @package
*/
Blockly.WorkspaceComment.prototype.moveBy = function(dx, dy) {
var event = new Blockly.Events.CommentMove(this);
this.xy_.translate(dx, dy);
event.recordNew();
Blockly.Events.fire(event);
};
/**
* Get whether this comment is deletable or not.
* @return {boolean} True if deletable.
* @package
*/
Blockly.WorkspaceComment.prototype.isDeletable = function() {
return this.deletable_ &&
!(this.workspace && this.workspace.options.readOnly);
};
/**
* Set whether this comment is deletable or not.
* @param {boolean} deletable True if deletable.
* @package
*/
Blockly.WorkspaceComment.prototype.setDeletable = function(deletable) {
this.deletable_ = deletable;
};
/**
* Get whether this comment is movable or not.
* @return {boolean} True if movable.
* @package
*/
Blockly.WorkspaceComment.prototype.isMovable = function() {
return this.movable_ &&
!(this.workspace && this.workspace.options.readOnly);
};
/**
* Set whether this comment is movable or not.
* @param {boolean} movable True if movable.
* @package
*/
Blockly.WorkspaceComment.prototype.setMovable = function(movable) {
this.movable_ = movable;
};
/**
* Returns this comment's text.
* @return {string} Comment text.
* @package
*/
Blockly.WorkspaceComment.prototype.getContent = function() {
return this.content_;
};
/**
* Set this comment's content.
* @param {string} content Comment content.
* @package
*/
Blockly.WorkspaceComment.prototype.setContent = function(content) {
if (this.content_ != content) {
Blockly.Events.fire(
new Blockly.Events.CommentChange(this, this.content_, content));
this.content_ = content;
}
};
/**
* Encode a comment subtree as XML with XY coordinates.
* @param {boolean=} opt_noId True if the encoder should skip the comment id.
* @return {!Element} Tree of XML elements.
* @package
*/
Blockly.WorkspaceComment.prototype.toXmlWithXY = function(opt_noId) {
var element = this.toXml(opt_noId);
element.setAttribute('x', Math.round(this.xy_.x));
element.setAttribute('y', Math.round(this.xy_.y));
element.setAttribute('h', this.height_);
element.setAttribute('w', this.width_);
return element;
};
/**
* Encode a comment subtree as XML, but don't serialize the XY coordinates.
* This method avoids some expensive metrics-related calls that are made in
* toXmlWithXY().
* @param {boolean=} opt_noId True if the encoder should skip the comment id.
* @return {!Element} Tree of XML elements.
* @package
*/
Blockly.WorkspaceComment.prototype.toXml = function(opt_noId) {
var commentElement = goog.dom.createDom('comment');
if (!opt_noId) {
commentElement.setAttribute('id', this.id);
}
commentElement.textContent = this.getContent();
return commentElement;
};
/**
* Fire a create event for the given workspace comment, if comments are enabled.
* @param {!Blockly.WorkspaceComment} comment The comment that was just created.
* @package
*/
Blockly.WorkspaceComment.fireCreateEvent = function(comment) {
if (Blockly.Events.isEnabled()) {
var existingGroup = Blockly.Events.getGroup();
if (!existingGroup) {
Blockly.Events.setGroup(true);
}
try {
Blockly.Events.fire(new Blockly.Events.CommentCreate(comment));
} finally {
if (!existingGroup) {
Blockly.Events.setGroup(false);
}
}
}
};
/**
* Decode an XML comment tag and create a comment on the workspace.
* @param {!Element} xmlComment XML comment element.
* @param {!Blockly.Workspace} workspace The workspace.
* @return {!Blockly.WorkspaceComment} The created workspace comment.
* @package
*/
Blockly.WorkspaceComment.fromXml = function(xmlComment, workspace) {
var info = Blockly.WorkspaceComment.parseAttributes(xmlComment);
var comment = new Blockly.WorkspaceComment(
workspace, info.content, info.h, info.w, info.id);
var commentX = parseInt(xmlComment.getAttribute('x'), 10);
var commentY = parseInt(xmlComment.getAttribute('y'), 10);
if (!isNaN(commentX) && !isNaN(commentY)) {
comment.moveBy(commentX, commentY);
}
Blockly.WorkspaceComment.fireCreateEvent(comment);
return comment;
};
/**
* Decode an XML comment tag and return the results in an object.
* @param {!Element} xml XML comment element.
* @return {!Object} An object containing the information about the comment.
* @package
*/
Blockly.WorkspaceComment.parseAttributes = function(xml) {
var xmlH = xml.getAttribute('h');
var xmlW = xml.getAttribute('w');
return {
/* @type {string} */
id: xml.getAttribute('id'),
/**
* The height of the comment in workspace units, or 100 if not specified.
* @type {number}
*/
h: xmlH ? parseInt(xmlH, 10) : 100,
/**
* The width of the comment in workspace units, or 100 if not specified.
* @type {number}
*/
w: xmlW ? parseInt(xmlW, 10) : 100,
/**
* The x position of the comment in workspace coordinates, or NaN if not
* specified in the XML.
* @type {number}
*/
x: parseInt(xml.getAttribute('x'), 10),
/**
* The y position of the comment in workspace coordinates, or NaN if not
* specified in the XML.
* @type {number}
*/
y: parseInt(xml.getAttribute('y'), 10),
/* @type {string} */
content: xml.textContent
};
};
+463
View File
@@ -0,0 +1,463 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 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 Methods for rendering a workspace comment as SVG
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.WorkspaceCommentSvg.render');
goog.require('Blockly.WorkspaceCommentSvg');
/**
* Size of the resize icon.
* @type {number}
* @const
* @private
*/
Blockly.WorkspaceCommentSvg.RESIZE_SIZE = 8;
/**
* Radius of the border around the comment.
* @type {number}
* @const
* @private
*/
Blockly.WorkspaceCommentSvg.BORDER_RADIUS = 3;
/**
* Offset from the foreignobject edge to the textarea edge.
* @type {number}
* @const
* @private
*/
Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET = 2;
/**
* Offset from the top to make room for a top bar.
* @type {number}
* @const
* @private
*/
Blockly.WorkspaceCommentSvg.TOP_OFFSET = 10;
/**
* Returns a bounding box describing the dimensions of this comment.
* @return {!{height: number, width: number}} Object with height and width
* properties in workspace units.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.getHeightWidth = function() {
return { width: this.getWidth(), height: this.getHeight() };
};
/**
* Renders the workspace comment.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.render = function() {
if (this.rendered_) {
return;
}
var size = this.getHeightWidth();
// Add text area
this.createEditor_();
this.svgGroup_.appendChild(this.foreignObject_);
this.svgHandleTarget_ = Blockly.utils.createSvgElement('rect',
{
'class': 'blocklyCommentHandleTarget',
'x': 0,
'y': 0
});
this.svgGroup_.appendChild(this.svgHandleTarget_);
this.svgRectTarget_ = Blockly.utils.createSvgElement('rect',
{
'class': 'blocklyCommentTarget',
'x': 0,
'y': 0,
'rx': Blockly.WorkspaceCommentSvg.BORDER_RADIUS,
'ry': Blockly.WorkspaceCommentSvg.BORDER_RADIUS
});
this.svgGroup_.appendChild(this.svgRectTarget_);
// Add the resize icon
this.addResizeDom_();
if (this.isDeletable()) {
// Add the delete icon
this.addDeleteDom_();
}
this.setSize_(size.width, size.height);
// Set the content
this.textarea_.value = this.content_;
this.rendered_ = true;
if (this.resizeGroup_) {
Blockly.bindEventWithChecks_(
this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_);
}
if (this.isDeletable()) {
Blockly.bindEventWithChecks_(
this.deleteGroup_, 'mousedown', this, this.deleteMouseDown_);
Blockly.bindEventWithChecks_(
this.deleteGroup_, 'mouseout', this, this.deleteMouseOut_);
Blockly.bindEventWithChecks_(
this.deleteGroup_, 'mouseup', this, this.deleteMouseUp_);
}
};
/**
* Create the text area for the comment.
* @return {!Element} The top-level node of the editor.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() {
/* Create the editor. Here's the markup that will be generated:
<foreignObject class="blocklyCommentForeignObject" x="0" y="10" width="164" height="164">
<body xmlns="http://www.w3.org/1999/xhtml" class="blocklyMinimalBody">
<textarea xmlns="http://www.w3.org/1999/xhtml"
class="blocklyCommentTextarea"
style="height: 164px; width: 164px;"></textarea>
</body>
</foreignObject>
*/
this.foreignObject_ = Blockly.utils.createSvgElement(
'foreignObject',
{
'x': 0,
'y': Blockly.WorkspaceCommentSvg.TOP_OFFSET,
'class': 'blocklyCommentForeignObject'
},
null);
var body = document.createElementNS(Blockly.HTML_NS, 'body');
body.setAttribute('xmlns', Blockly.HTML_NS);
body.className = 'blocklyMinimalBody';
var textarea = document.createElementNS(Blockly.HTML_NS, 'textarea');
textarea.className = 'blocklyCommentTextarea';
textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
body.appendChild(textarea);
this.textarea_ = textarea;
this.foreignObject_.appendChild(body);
// Don't zoom with mousewheel.
Blockly.bindEventWithChecks_(textarea, 'wheel', this, function(e) {
e.stopPropagation();
});
Blockly.bindEventWithChecks_(textarea, 'change', this, function(
/* eslint-disable no-unused-vars */ e
/* eslint-enable no-unused-vars */) {
this.setContent(textarea.value);
});
return this.foreignObject_;
};
/**
* Add the resize icon to the DOM
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() {
this.resizeGroup_ = Blockly.utils.createSvgElement(
'g',
{
'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'
},
this.svgGroup_);
var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE;
Blockly.utils.createSvgElement(
'polygon',
{'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())},
this.resizeGroup_);
Blockly.utils.createSvgElement(
'line',
{
'class': 'blocklyResizeLine',
'x1': resizeSize / 3, 'y1': resizeSize - 1,
'x2': resizeSize - 1, 'y2': resizeSize / 3
}, this.resizeGroup_);
Blockly.utils.createSvgElement(
'line',
{
'class': 'blocklyResizeLine',
'x1': resizeSize * 2 / 3, 'y1': resizeSize - 1,
'x2': resizeSize - 1, 'y2': resizeSize * 2 / 3
}, this.resizeGroup_);
};
/**
* Add the delete icon to the DOM
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() {
this.deleteGroup_ = Blockly.utils.createSvgElement(
'g',
{
'class': 'blocklyCommentDeleteIcon'
},
this.svgGroup_);
this.deleteIconBorder_ = Blockly.utils.createSvgElement('circle',
{
'class': 'blocklyDeleteIconShape',
'r': '7',
'cx': '7.5',
'cy': '7.5'
},
this.deleteGroup_);
// x icon.
Blockly.utils.createSvgElement(
'line',
{
'x1': '5', 'y1': '10',
'x2': '10', 'y2': '5',
'stroke': '#fff',
'stroke-width': '2'
},
this.deleteGroup_);
Blockly.utils.createSvgElement(
'line',
{
'x1': '5', 'y1': '5',
'x2': '10', 'y2': '10',
'stroke': '#fff',
'stroke-width': '2'
},
this.deleteGroup_);
};
/**
* Handle a mouse-down on comment's resize corner.
* @param {!Event} e Mouse down event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_ = function(e) {
//this.promote_();
this.unbindDragEvents_();
if (Blockly.utils.isRightButton(e)) {
// No right-click.
e.stopPropagation();
return;
}
// Left-click (or middle click)
this.workspace.startDrag(e, new goog.math.Coordinate(
this.workspace.RTL ? -this.width_ : this.width_, this.height_));
this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
document, 'mouseup', this, this.resizeMouseUp_);
this.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(
document, 'mousemove', this, this.resizeMouseMove_);
Blockly.hideChaff();
// This event has been handled. No need to bubble up to the document.
e.stopPropagation();
};
/**
* Handle a mouse-down on comment's delete icon.
* @param {!Event} e Mouse down event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) {
// highlight the delete icon
Blockly.utils.addClass(
/** @type {!Element} */ (this.deleteIconBorder_), 'blocklyDeleteIconHighlighted');
// This event has been handled. No need to bubble up to the document.
e.stopPropagation();
};
/**
* Handle a mouse-out on comment's delete icon.
* @param {!Event} e Mouse out event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(/*e*/) {
// restore highlight on the delete icon
Blockly.utils.removeClass(
/** @type {!Element} */ (this.deleteIconBorder_), 'blocklyDeleteIconHighlighted');
};
/**
* Handle a mouse-up on comment's delete icon.
* @param {!Event} e Mouse up event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_ = function(e) {
// Delete this comment
this.dispose(true, true);
// This event has been handled. No need to bubble up to the document.
e.stopPropagation();
};
/**
* Stop binding to the global mouseup and mousemove events.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.unbindDragEvents_ = function() {
if (this.onMouseUpWrapper_) {
Blockly.unbindEvent_(this.onMouseUpWrapper_);
this.onMouseUpWrapper_ = null;
}
if (this.onMouseMoveWrapper_) {
Blockly.unbindEvent_(this.onMouseMoveWrapper_);
this.onMouseMoveWrapper_ = null;
}
};
/*
* Handle a mouse-up event while dragging a comment's border or resize handle.
* @param {!Event} e Mouse up event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.resizeMouseUp_ = function(/*e*/) {
Blockly.Touch.clearTouchIdentifier();
this.unbindDragEvents_();
};
/**
* Resize this comment to follow the mouse.
* @param {!Event} e Mouse move event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.resizeMouseMove_ = function(e) {
this.autoLayout_ = false;
var newXY = this.workspace.moveDrag(e);
this.setSize_(this.RTL ? -newXY.x : newXY.x, newXY.y);
};
/**
* Callback function triggered when the comment has resized.
* Resize the text area accordingly.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.resizeComment_ = function() {
var size = this.getHeightWidth();
var topOffset = Blockly.WorkspaceCommentSvg.TOP_OFFSET;
var textOffset = Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET * 2;
this.foreignObject_.setAttribute('width',
size.width);
this.foreignObject_.setAttribute('height',
size.height - topOffset);
if (this.RTL) {
this.foreignObject_.setAttribute('x',
-size.width);
}
this.textarea_.style.width =
(size.width - textOffset) + 'px';
this.textarea_.style.height =
(size.height - textOffset - topOffset) + 'px';
};
/**
* Set size
* @param {number} width width of the container
* @param {number} height height of the container
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.setSize_ = function(width, height) {
// Minimum size of a comment.
width = Math.max(width, 45);
height = Math.max(height, 20 + Blockly.WorkspaceCommentSvg.TOP_OFFSET);
this.width_ = width;
this.height_ = height;
this.svgRect_.setAttribute('width', width);
this.svgRect_.setAttribute('height', height);
this.svgRectTarget_.setAttribute('width', width);
this.svgRectTarget_.setAttribute('height', height);
this.svgHandleTarget_.setAttribute('width', width);
this.svgHandleTarget_.setAttribute('height', Blockly.WorkspaceCommentSvg.TOP_OFFSET);
if (this.RTL) {
this.svgRect_.setAttribute('transform', 'scale(-1 1)');
this.svgRectTarget_.setAttribute('transform', 'scale(-1 1)');
}
var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE;
if (this.resizeGroup_) {
if (this.RTL) {
// Mirror the resize group.
this.resizeGroup_.setAttribute('transform', 'translate(' +
(-width + resizeSize) + ',' + (height - resizeSize) + ') scale(-1 1)');
this.deleteGroup_.setAttribute('transform', 'translate(' +
(-width + resizeSize) + ',' + (-resizeSize) + ') scale(-1 1)');
} else {
this.resizeGroup_.setAttribute('transform', 'translate(' +
(width - resizeSize) + ',' +
(height - resizeSize) + ')');
this.deleteGroup_.setAttribute('transform', 'translate(' +
(width - resizeSize) + ',' +
(-resizeSize) + ')');
}
}
// Allow the contents to resize.
this.resizeComment_();
};
/**
* Dispose of any rendered comment components.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.disposeInternal_ = function() {
this.textarea_ = null;
this.foreignObject_ = null;
this.svgRectTarget_ = null;
this.svgHandleTarget_ = null;
};
/**
* Set the focus on the text area.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.setFocus = function() {
var comment = this;
this.focused_ = true;
// Defer CSS changes.
setTimeout(function() {
comment.textarea_.focus();
comment.addFocus();
Blockly.utils.addClass(
comment.svgRectTarget_, 'blocklyCommentTargetFocused');
Blockly.utils.addClass(
comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused');
}, 0);
};
/**
* Remove focus from the text area.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.blurFocus = function() {
var comment = this;
this.focused_ = false;
// Defer CSS changes.
setTimeout(function() {
comment.textarea_.blur();
comment.removeFocus();
Blockly.utils.removeClass(
comment.svgRectTarget_, 'blocklyCommentTargetFocused');
Blockly.utils.removeClass(
comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused');
}, 0);
};
+591
View File
@@ -0,0 +1,591 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2017 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 Object representing a code comment on a rendered workspace.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.WorkspaceCommentSvg');
goog.require('Blockly.Events.CommentCreate');
goog.require('Blockly.Events.CommentDelete');
goog.require('Blockly.Events.CommentMove');
goog.require('Blockly.WorkspaceComment');
/**
* Class for a workspace comment's SVG representation.
* @param {!Blockly.Workspace} workspace The block's workspace.
* @param {string} content The content of this workspace comment.
* @param {number} height Height of the comment.
* @param {number} width Width of the comment.
* @param {string=} opt_id Optional ID. Use this ID if provided, otherwise
* create a new ID.
* @extends {Blockly.WorkspaceComment}
* @constructor
*/
Blockly.WorkspaceCommentSvg = function(workspace, content, height, width,
opt_id) {
// Create core elements for the block.
/**
* @type {SVGElement}
* @private
*/
this.svgGroup_ = Blockly.utils.createSvgElement(
'g', {'class': 'blocklyComment'}, null);
this.svgGroup_.translate_ = '';
this.svgRect_ = Blockly.utils.createSvgElement(
'rect',
{
'class': 'blocklyCommentRect',
'x': 0,
'y': 0,
'rx': Blockly.WorkspaceCommentSvg.BORDER_RADIUS,
'ry': Blockly.WorkspaceCommentSvg.BORDER_RADIUS
});
this.svgGroup_.appendChild(this.svgRect_);
/**
* Whether the comment is rendered onscreen and is a part of the DOM.
* @type {boolean}
* @private
*/
this.rendered_ = false;
/**
* Whether to move the comment to the drag surface when it is dragged.
* True if it should move, false if it should be translated directly.
* @type {boolean}
* @private
*/
this.useDragSurface_ =
Blockly.utils.is3dSupported() && !!workspace.blockDragSurface_;
Blockly.WorkspaceCommentSvg.superClass_.constructor.call(this,
workspace, content, height, width, opt_id);
this.render();
}; goog.inherits(Blockly.WorkspaceCommentSvg, Blockly.WorkspaceComment);
/**
* The width and height to use to size a workspace comment when it is first
* added, before it has been edited by the user.
* @type {number}
* @package
*/
Blockly.WorkspaceCommentSvg.DEFAULT_SIZE = 100;
/**
* Dispose of this comment.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.dispose = function() {
if (!this.workspace) {
// The comment has already been deleted.
return;
}
// If this comment is being dragged, unlink the mouse events.
if (Blockly.selected == this) {
this.unselect();
this.workspace.cancelCurrentGesture();
}
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.CommentDelete(this));
}
goog.dom.removeNode(this.svgGroup_);
// Sever JavaScript to DOM connections.
this.svgGroup_ = null;
this.svgRect_ = null;
// Dispose of any rendered components
this.disposeInternal_();
Blockly.Events.disable();
Blockly.WorkspaceCommentSvg.superClass_.dispose.call(this);
Blockly.Events.enable();
};
/**
* Create and initialize the SVG representation of a workspace comment.
* May be called more than once.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.initSvg = function() {
goog.asserts.assert(this.workspace.rendered, 'Workspace is headless.');
if (!this.workspace.options.readOnly && !this.eventsInit_) {
Blockly.bindEventWithChecks_(
this.svgRectTarget_, 'mousedown', this, this.pathMouseDown_);
Blockly.bindEventWithChecks_(
this.svgHandleTarget_, 'mousedown', this, this.pathMouseDown_);
}
this.eventsInit_ = true;
this.updateMovable();
if (!this.getSvgRoot().parentNode) {
this.workspace.getBubbleCanvas().appendChild(this.getSvgRoot());
}
};
/**
* Handle a mouse-down on an SVG comment.
* @param {!Event} e Mouse down event or touch start event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.pathMouseDown_ = function(e) {
var gesture = this.workspace.getGesture(e);
if (gesture) {
gesture.handleBubbleStart(e, this);
}
};
/**
* Show the context menu for this workspace comment.
* @param {!Event} e Mouse event.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.showContextMenu_ = function(e) {
if (this.workspace.options.readOnly) {
return;
}
// Save the current workspace comment in a variable for use in closures.
var comment = this;
var menuOptions = [];
if (this.isDeletable() && this.isMovable()) {
menuOptions.push(Blockly.ContextMenu.commentDuplicateOption(comment));
menuOptions.push(Blockly.ContextMenu.commentDeleteOption(comment));
}
Blockly.ContextMenu.show(e, menuOptions, this.RTL);
};
/**
* Select this comment. Highlight it visually.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.select = function() {
if (Blockly.selected == this) {
return;
}
var oldId = null;
if (Blockly.selected) {
oldId = Blockly.selected.id;
// Unselect any previously selected block.
Blockly.Events.disable();
try {
Blockly.selected.unselect();
} finally {
Blockly.Events.enable();
}
}
var event = new Blockly.Events.Ui(null, 'selected', oldId, this.id);
event.workspaceId = this.workspace.id;
Blockly.Events.fire(event);
Blockly.selected = this;
this.addSelect();
};
/**
* Unselect this comment. Remove its highlighting.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.unselect = function() {
if (Blockly.selected != this) {
return;
}
var event = new Blockly.Events.Ui(null, 'selected', this.id, null);
event.workspaceId = this.workspace.id;
Blockly.Events.fire(event);
Blockly.selected = null;
this.removeSelect();
this.blurFocus();
};
/**
* Select this comment. Highlight it visually.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.addSelect = function() {
Blockly.utils.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
this.setFocus();
};
/**
* Unselect this comment. Remove its highlighting.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.removeSelect = function() {
Blockly.utils.removeClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
this.blurFocus();
};
/**
* Focus this comment. Highlight it visually.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.addFocus = function() {
Blockly.utils.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
};
/**
* Unfocus this comment. Remove its highlighting.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.removeFocus = function() {
Blockly.utils.removeClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
};
/**
* Return the coordinates of the top-left corner of this comment relative to the
* drawing surface's origin (0,0), in workspace units.
* If the comment is on the workspace, (0, 0) is the origin of the workspace
* coordinate system.
* This does not change with workspace scale.
* @return {!goog.math.Coordinate} Object with .x and .y properties in
* workspace coordinates.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() {
var x = 0;
var y = 0;
var dragSurfaceGroup = this.useDragSurface_ ?
this.workspace.blockDragSurface_.getGroup() : null;
var element = this.getSvgRoot();
if (element) {
do {
// Loop through this comment and every parent.
var xy = Blockly.utils.getRelativeXY(element);
x += xy.x;
y += xy.y;
// If this element is the current element on the drag surface, include
// the translation of the drag surface itself.
if (this.useDragSurface_ &&
this.workspace.blockDragSurface_.getCurrentBlock() == element) {
var surfaceTranslation =
this.workspace.blockDragSurface_.getSurfaceTranslation();
x += surfaceTranslation.x;
y += surfaceTranslation.y;
}
element = element.parentNode;
} while (element && element != this.workspace.getBubbleCanvas() &&
element != dragSurfaceGroup);
}
this.xy_ = new goog.math.Coordinate(x, y);
return this.xy_;
};
/**
* Move a comment by a relative offset.
* @param {number} dx Horizontal offset, in workspace units.
* @param {number} dy Vertical offset, in workspace units.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) {
var event = new Blockly.Events.CommentMove(this);
// TODO: Do I need to look up the relative to surface XY position here?
var xy = this.getRelativeToSurfaceXY();
this.translate(xy.x + dx, xy.y + dy);
this.xy_ = new goog.math.Coordinate(xy.x + dx, xy.y + dy);
event.recordNew();
Blockly.Events.fire(event);
this.workspace.resizeContents();
};
/**
* Transforms a comment by setting the translation on the transform attribute
* of the block's SVG.
* @param {number} x The x coordinate of the translation in workspace units.
* @param {number} y The y coordinate of the translation in workspace units.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) {
this.xy_ = new goog.math.Coordinate(x, y);
this.getSvgRoot().setAttribute('transform',
'translate(' + x + ',' + y + ')');
};
/**
* Move this comment to its workspace's drag surface, accounting for positioning.
* Generally should be called at the same time as setDragging(true).
* Does nothing if useDragSurface_ is false.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface_ = function() {
if (!this.useDragSurface_) {
return;
}
// The translation for drag surface blocks,
// is equal to the current relative-to-surface position,
// to keep the position in sync as it move on/off the surface.
// This is in workspace coordinates.
var xy = this.getRelativeToSurfaceXY();
this.clearTransformAttributes_();
this.workspace.blockDragSurface_.translateSurface(xy.x, xy.y);
// Execute the move on the top-level SVG component
this.workspace.blockDragSurface_.setBlocksAndShow(this.getSvgRoot());
};
/**
* Move this comment back to the workspace block canvas.
* Generally should be called at the same time as setDragging(false).
* Does nothing if useDragSurface_ is false.
* @param {!goog.math.Coordinate} newXY The position the comment should take on
* on the workspace canvas, in workspace coordinates.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface_ = function(newXY) {
if (!this.useDragSurface_) {
return;
}
// Translate to current position, turning off 3d.
this.translate(newXY.x, newXY.y);
this.workspace.blockDragSurface_.clearAndHide(this.workspace.getCanvas());
};
/**
* Move this comment during a drag, taking into account whether we are using a
* drag surface to translate blocks.
* @param {?Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries
* rendered items during a drag, or null if no drag surface is in use.
* @param {!goog.math.Coordinate} newLoc The location to translate to, in
* workspace coordinates.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.moveDuringDrag = function(dragSurface, newLoc) {
if (dragSurface) {
dragSurface.translateSurface(newLoc.x, newLoc.y);
} else {
this.svgGroup_.translate_ = 'translate(' + newLoc.x + ',' + newLoc.y + ')';
this.svgGroup_.setAttribute('transform',
this.svgGroup_.translate_ + this.svgGroup_.skew_);
}
};
/**
* Move the bubble group to the specified location in workspace coordinates.
* @param {number} x The x position to move to.
* @param {number} y The y position to move to.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.moveTo = function(x, y) {
this.translate(x, y);
};
/**
* Clear the comment of transform="..." attributes.
* Used when the comment is switching from 3d to 2d transform or vice versa.
* @private
*/
Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() {
Blockly.utils.removeAttribute(this.getSvgRoot(), 'transform');
};
/**
* Returns the coordinates of a bounding box describing the dimensions of this
* comment.
* Coordinate system: workspace coordinates.
* @return {!{topLeft: goog.math.Coordinate, bottomRight: goog.math.Coordinate}}
* Object with top left and bottom right coordinates of the bounding box.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() {
var blockXY = this.getRelativeToSurfaceXY();
var commentBounds = this.getHeightWidth();
var topLeft;
var bottomRight;
if (this.RTL) {
topLeft = new goog.math.Coordinate(blockXY.x - (commentBounds.width),
blockXY.y);
// Add the width of the tab/puzzle piece knob to the x coordinate
// since X is the corner of the rectangle, not the whole puzzle piece.
bottomRight = new goog.math.Coordinate(blockXY.x,
blockXY.y + commentBounds.height);
} else {
// Subtract the width of the tab/puzzle piece knob to the x coordinate
// since X is the corner of the rectangle, not the whole puzzle piece.
topLeft = new goog.math.Coordinate(blockXY.x, blockXY.y);
bottomRight = new goog.math.Coordinate(blockXY.x + commentBounds.width,
blockXY.y + commentBounds.height);
}
return {topLeft: topLeft, bottomRight: bottomRight};
};
/**
* Add or remove the UI indicating if this comment is movable or not.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.updateMovable = function() {
if (this.isMovable()) {
Blockly.utils.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
} else {
Blockly.utils.removeClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
}
};
/**
* Set whether this comment is movable or not.
* @param {boolean} movable True if movable.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.setMovable = function(movable) {
Blockly.WorkspaceCommentSvg.superClass_.setMovable.call(this, movable);
this.updateMovable();
};
/**
* Recursively adds or removes the dragging class to this node and its children.
* @param {boolean} adding True if adding, false if removing.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.setDragging = function(adding) {
if (adding) {
var group = this.getSvgRoot();
group.translate_ = '';
group.skew_ = '';
Blockly.utils.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
} else {
Blockly.utils.removeClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
}
};
/**
* Return the root node of the SVG or null if none exists.
* @return {Element} The root SVG node (probably a group).
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.getSvgRoot = function() {
return this.svgGroup_;
};
/**
* Returns this comment's text.
* @return {string} Comment text.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.getContent = function() {
return this.textarea_ ? this.textarea_.value : this.content_;
};
/**
* Set this comment's content.
* @param {string} content Comment content.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.setContent = function(content) {
Blockly.WorkspaceCommentSvg.superClass_.setContent.call(this, content);
if (this.textarea_) {
this.textarea_.value = content;
}
};
/**
* Update the cursor over this comment by adding or removing a class.
* @param {boolean} enable True if the delete cursor should be shown, false
* otherwise.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) {
if (enable) {
Blockly.utils.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete');
} else {
Blockly.utils.removeClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete');
}
};
Blockly.WorkspaceCommentSvg.prototype.setAutoLayout = function() {
// NOP for compatibility with the bubble dragger.
};
/**
* Decode an XML comment tag and create a rendered comment on the workspace.
* @param {!Element} xmlComment XML comment element.
* @param {!Blockly.Workspace} workspace The workspace.
* @param {number=} opt_wsWidth The width of the workspace, which is used to
* position comments correctly in RTL.
* @return {!Blockly.WorkspaceCommentSvg} The created workspace comment.
* @package
*/
Blockly.WorkspaceCommentSvg.fromXml = function(xmlComment, workspace,
opt_wsWidth) {
Blockly.Events.disable();
try {
var info = Blockly.WorkspaceComment.parseAttributes(xmlComment);
var comment = new Blockly.WorkspaceCommentSvg(workspace,
info.content, info.h, info.w, info.id);
if (workspace.rendered) {
comment.initSvg();
comment.render(false);
}
// Position the comment correctly, taking into account the width of a
// rendered RTL workspace.
if (!isNaN(info.x) && !isNaN(info.y)) {
if (workspace.RTL) {
var wsWidth = opt_wsWidth || workspace.getWidth();
comment.moveBy(wsWidth - info.x, info.y);
} else {
comment.moveBy(info.x, info.y);
}
}
} finally {
Blockly.Events.enable();
}
Blockly.WorkspaceComment.fireCreateEvent(comment);
return comment;
};
/**
* Encode a comment subtree as XML with XY coordinates.
* @param {boolean=} opt_noId True if the encoder should skip the comment id.
* @return {!Element} Tree of XML elements.
* @package
*/
Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) {
var width; // Not used in LTR.
if (this.workspace.RTL) {
// Here be performance dragons: This calls getMetrics().
width = this.workspace.getWidth();
}
var element = this.toXml(opt_noId);
var xy = this.getRelativeToSurfaceXY();
element.setAttribute('x',
Math.round(this.workspace.RTL ? width - xy.x : xy.x));
element.setAttribute('y', Math.round(xy.y));
element.setAttribute('h', this.getHeight());
element.setAttribute('w', this.getWidth());
return element;
};
+113 -19
View File
@@ -41,6 +41,9 @@ goog.require('Blockly.Trashcan');
goog.require('Blockly.VariablesDynamic');
goog.require('Blockly.Workspace');
goog.require('Blockly.WorkspaceAudio');
goog.require('Blockly.WorkspaceComment');
goog.require('Blockly.WorkspaceCommentSvg');
goog.require('Blockly.WorkspaceCommentSvg.render');
goog.require('Blockly.WorkspaceDragSurfaceSvg');
goog.require('Blockly.Xml');
goog.require('Blockly.ZoomControls');
@@ -243,6 +246,14 @@ Blockly.WorkspaceSvg.prototype.useWorkspaceDragSurface_ = false;
*/
Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_ = false;
/**
* The first parent div with 'injectionDiv' in the name, or null if not set.
* Access this with getInjectionDiv.
* @type {!Element}
* @private
*/
Blockly.WorkspaceSvg.prototype.injectionDiv_ = null;
/**
* Last known position of the page scroll.
* This is used to determine whether we have recalculated screen coordinate
@@ -290,22 +301,37 @@ Blockly.WorkspaceSvg.prototype.targetWorkspace = null;
*/
Blockly.WorkspaceSvg.prototype.inverseScreenCTM_ = null;
/**
* Inverted screen CTM is dirty, recalculate it.
* @type {Boolean}
* @private
*/
Blockly.WorkspaceSvg.prototype.inverseScreenCTMDirty_ = true;
/**
* Getter for the inverted screen CTM.
* @return {SVGMatrix} The matrix to use in mouseToSvg
*/
Blockly.WorkspaceSvg.prototype.getInverseScreenCTM = function() {
// Defer getting the screen CTM until we actually need it, this should
// avoid forced reflows from any calls to updateInverseScreenCTM.
if (this.inverseScreenCTMDirty_) {
var ctm = this.getParentSvg().getScreenCTM();
if (ctm) {
this.inverseScreenCTM_ = ctm.inverse();
this.inverseScreenCTMDirty_ = false;
}
}
return this.inverseScreenCTM_;
};
/**
* Update the inverted screen CTM.
* Mark the inverse screen CTM as dirty.
*/
Blockly.WorkspaceSvg.prototype.updateInverseScreenCTM = function() {
var ctm = this.getParentSvg().getScreenCTM();
if (ctm) {
this.inverseScreenCTM_ = ctm.inverse();
}
this.inverseScreenCTMDirty_ = true;
};
/**
@@ -352,6 +378,29 @@ Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() {
return Blockly.utils.getInjectionDivXY_(this.svgBlockCanvas_);
};
/**
* Return the injection div that is a parent of this workspace.
* Walks the DOM the first time it's called, then returns a cached value.
* @return {!Element} The first parent div with 'injectionDiv' in the name.
* @package
*/
Blockly.WorkspaceSvg.prototype.getInjectionDiv = function() {
// NB: it would be better to pass this in at createDom, but is more likely to
// break existing uses of Blockly.
if (!this.injectionDiv_) {
var element = this.svgGroup_;
while (element) {
var classes = element.getAttribute('class') || '';
if ((' ' + classes + ' ').indexOf(' injectionDiv ') != -1) {
this.injectionDiv_ = element;
break;
}
element = element.parentNode;
}
}
return this.injectionDiv_;
};
/**
* Save resize handler data so we can delete it later in dispose.
* @param {!Array.<!Array>} handler Data that can be passed to unbindEvent_.
@@ -897,6 +946,18 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) {
if (this.currentGesture_) {
this.currentGesture_.cancel(); // Dragging while pasting? No.
}
if (xmlBlock.tagName.toLowerCase() == 'comment') {
this.pasteWorkspaceComment_(xmlBlock);
} else {
this.pasteBlock_(xmlBlock);
}
};
/**
* Paste the provided block onto the workspace.
* @param {!Element} xmlBlock XML block element.
*/
Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) {
Blockly.Events.disable();
try {
var block = Blockly.Xml.domToBlock(xmlBlock, this);
@@ -952,6 +1013,37 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) {
block.select();
};
/**
* Paste the provided comment onto the workspace.
* @param {!Element} xmlComment XML workspace comment element.
* @private
*/
Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) {
Blockly.Events.disable();
try {
var comment = Blockly.WorkspaceCommentSvg.fromXml(xmlComment, this);
// Move the duplicate to original position.
var commentX = parseInt(xmlComment.getAttribute('x'), 10);
var commentY = parseInt(xmlComment.getAttribute('y'), 10);
if (!isNaN(commentX) && !isNaN(commentY)) {
if (this.RTL) {
commentX = -commentX;
}
// Offset workspace comment.
// TODO: #1719 properly offset comment such that it's not interfereing with any blocks
commentX += 50;
commentY += 50;
comment.moveBy(commentX, commentY);
}
} finally {
Blockly.Events.enable();
}
if (Blockly.Events.isEnabled()) {
// TODO: Fire a Workspace Comment Create event
}
comment.select();
};
/**
* Refresh the toolbox unless there's a drag in progress.
* @package
@@ -1126,17 +1218,19 @@ Blockly.WorkspaceSvg.prototype.onMouseWheel_ = function(e) {
*/
Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() {
var topBlocks = this.getTopBlocks(false);
var topComments = this.getTopComments(false);
var topElements = topBlocks.concat(topComments);
// There are no blocks, return empty rectangle.
if (!topBlocks.length) {
if (!topElements.length) {
return {x: 0, y: 0, width: 0, height: 0};
}
// Initialize boundary using the first block.
var boundary = topBlocks[0].getBoundingRectangle();
var boundary = topElements[0].getBoundingRectangle();
// Start at 1 since the 0th block was used for initialization
for (var i = 1; i < topBlocks.length; i++) {
var blockBoundary = topBlocks[i].getBoundingRectangle();
for (var i = 1; i < topElements.length; i++) {
var blockBoundary = topElements[i].getBoundingRectangle();
if (blockBoundary.topLeft.x < boundary.topLeft.x) {
boundary.topLeft.x = blockBoundary.topLeft.x;
}
@@ -1193,12 +1287,12 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
// Options to undo/redo previous action.
var undoOption = {};
undoOption.text = Blockly.Msg.UNDO;
undoOption.text = Blockly.Msg['UNDO'];
undoOption.enabled = this.undoStack_.length > 0;
undoOption.callback = this.undo.bind(this, false);
menuOptions.push(undoOption);
var redoOption = {};
redoOption.text = Blockly.Msg.REDO;
redoOption.text = Blockly.Msg['REDO'];
redoOption.enabled = this.redoStack_.length > 0;
redoOption.callback = this.undo.bind(this, true);
menuOptions.push(redoOption);
@@ -1206,7 +1300,7 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
// Option to clean up blocks.
if (this.scrollbar) {
var cleanOption = {};
cleanOption.text = Blockly.Msg.CLEAN_UP;
cleanOption.text = Blockly.Msg['CLEAN_UP'];
cleanOption.enabled = topBlocks.length > 1;
cleanOption.callback = this.cleanUp.bind(this);
menuOptions.push(cleanOption);
@@ -1248,7 +1342,7 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
// Option to collapse top blocks.
var collapseOption = {enabled: hasExpandedBlocks};
collapseOption.text = Blockly.Msg.COLLAPSE_ALL;
collapseOption.text = Blockly.Msg['COLLAPSE_ALL'];
collapseOption.callback = function() {
toggleOption(true);
};
@@ -1256,7 +1350,7 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
// Option to expand top blocks.
var expandOption = {enabled: hasCollapsedBlocks};
expandOption.text = Blockly.Msg.EXPAND_ALL;
expandOption.text = Blockly.Msg['EXPAND_ALL'];
expandOption.callback = function() {
toggleOption(false);
};
@@ -1268,9 +1362,9 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
var deleteList = [];
function addDeletableBlocks(block) {
if (block.isDeletable()) {
deleteList = deleteList.concat(block.getDescendants());
deleteList = deleteList.concat(block.getDescendants(false));
} else {
var children = block.getChildren();
var children = block.getChildren(false);
for (var i = 0; i < children.length; i++) {
addDeletableBlocks(children[i]);
}
@@ -1295,8 +1389,8 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
}
var deleteOption = {
text: deleteList.length == 1 ? Blockly.Msg.DELETE_BLOCK :
Blockly.Msg.DELETE_X_BLOCKS.replace('%1', String(deleteList.length)),
text: deleteList.length == 1 ? Blockly.Msg['DELETE_BLOCK'] :
Blockly.Msg['DELETE_X_BLOCKS'].replace('%1', String(deleteList.length)),
enabled: deleteList.length > 0,
callback: function() {
if (ws.currentGesture_) {
@@ -1306,7 +1400,7 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) {
deleteNext();
} else {
Blockly.confirm(
Blockly.Msg.DELETE_ALL_BLOCKS.replace('%1', deleteList.length),
Blockly.Msg['DELETE_ALL_BLOCKS'].replace('%1', deleteList.length),
function(ok) {
if (ok) {
deleteNext();
+410
View File
@@ -0,0 +1,410 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2018 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 Classes for all comment events.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.Events.CommentBase');
goog.provide('Blockly.Events.CommentChange');
goog.provide('Blockly.Events.CommentCreate');
goog.provide('Blockly.Events.CommentDelete');
goog.provide('Blockly.Events.CommentMove');
goog.require('Blockly.Events');
goog.require('Blockly.Events.Abstract');
goog.require('goog.math.Coordinate');
/**
* Abstract class for a comment event.
* @param {Blockly.WorkspaceComment} comment The comment this event corresponds
* to.
* @extends {Blockly.Events.Abstract}
* @constructor
*/
Blockly.Events.CommentBase = function(comment) {
/**
* The ID of the comment this event pertains to.
* @type {string}
*/
this.commentId = comment.id;
/**
* The workspace identifier for this event.
* @type {string}
*/
this.workspaceId = comment.workspace.id;
/**
* The event group id for the group this event belongs to. Groups define
* events that should be treated as an single action from the user's
* perspective, and should be undone together.
* @type {string}
*/
this.group = Blockly.Events.group_;
/**
* Sets whether the event should be added to the undo stack.
* @type {boolean}
*/
this.recordUndo = Blockly.Events.recordUndo;
};
goog.inherits(Blockly.Events.CommentBase, Blockly.Events.Abstract);
/**
* Encode the event as JSON.
* @return {!Object} JSON representation.
*/
Blockly.Events.CommentBase.prototype.toJson = function() {
var json = {
'type': this.type
};
if (this.group) {
json['group'] = this.group;
}
if (this.commentId) {
json['commentId'] = this.commentId;
}
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.CommentBase.prototype.fromJson = function(json) {
this.commentId = json['commentId'];
this.group = json['group'];
};
/**
* Class for a comment change event.
* @param {Blockly.WorkspaceComment} comment The comment that is being changed.
* Null for a blank event.
* @param {string} oldContents Previous contents of the comment.
* @param {string} newContents New contents of the comment.
* @extends {Blockly.Events.CommentBase}
* @constructor
*/
Blockly.Events.CommentChange = function(comment, oldContents, newContents) {
if (!comment) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.CommentChange.superClass_.constructor.call(this, comment);
this.oldContents_ = oldContents;
this.newContents_ = newContents;
};
goog.inherits(Blockly.Events.CommentChange, Blockly.Events.CommentBase);
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.CommentChange.prototype.type = Blockly.Events.COMMENT_CHANGE;
/**
* Encode the event as JSON.
* @return {!Object} JSON representation.
*/
Blockly.Events.CommentChange.prototype.toJson = function() {
var json = Blockly.Events.CommentChange.superClass_.toJson.call(this);
json['newContents'] = this.newContents_;
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.CommentChange.prototype.fromJson = function(json) {
Blockly.Events.CommentChange.superClass_.fromJson.call(this, json);
this.newContents_ = json['newValue'];
};
/**
* Does this event record any change of state?
* @return {boolean} False if something changed.
*/
Blockly.Events.CommentChange.prototype.isNull = function() {
return this.oldContents_ == this.newContents_;
};
/**
* Run a change event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.CommentChange.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
var comment = workspace.getCommentById(this.commentId);
if (!comment) {
console.warn('Can\'t change non-existent comment: ' + this.commentId);
return;
}
var contents = forward ? this.newContents_ : this.oldContents_;
comment.setContent(contents);
};
/**
* Class for a comment creation event.
* @param {Blockly.WorkspaceComment} comment The created comment.
* Null for a blank event.
* @extends {Blockly.Events.CommentBase}
* @constructor
*/
Blockly.Events.CommentCreate = function(comment) {
if (!comment) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.CommentCreate.superClass_.constructor.call(this, comment);
this.xml = comment.toXmlWithXY();
};
goog.inherits(Blockly.Events.CommentCreate, Blockly.Events.CommentBase);
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.CommentCreate.prototype.type = Blockly.Events.COMMENT_CREATE;
/**
* Encode the event as JSON.
* TODO (#1266): "Full" and "minimal" serialization.
* @return {!Object} JSON representation.
*/
Blockly.Events.CommentCreate.prototype.toJson = function() {
var json = Blockly.Events.CommentCreate.superClass_.toJson.call(this);
json['xml'] = Blockly.Xml.domToText(this.xml);
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.CommentCreate.prototype.fromJson = function(json) {
Blockly.Events.CommentCreate.superClass_.fromJson.call(this, json);
this.xml = Blockly.Xml.textToDom('<xml>' + json['xml'] + '</xml>').firstChild;
};
/**
* Run a creation event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.CommentCreate.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
if (forward) {
var xml = goog.dom.createDom('xml');
xml.appendChild(this.xml);
Blockly.Xml.domToWorkspace(xml, workspace);
} else {
var comment = workspace.getCommentById(this.commentId);
if (comment) {
comment.dispose(false, false);
} else {
// Only complain about root-level block.
console.warn("Can't uncreate non-existent comment: " + this.commentId);
}
}
};
/**
* Class for a comment deletion event.
* @param {Blockly.WorkspaceComment} comment The deleted comment.
* Null for a blank event.
* @extends {Blockly.Events.CommentBase}
* @constructor
*/
Blockly.Events.CommentDelete = function(comment) {
if (!comment) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.CommentDelete.superClass_.constructor.call(this, comment);
this.xml = comment.toXmlWithXY();
};
goog.inherits(Blockly.Events.CommentDelete, Blockly.Events.CommentBase);
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.CommentDelete.prototype.type = Blockly.Events.COMMENT_DELETE;
/**
* Encode the event as JSON.
* TODO (#1266): "Full" and "minimal" serialization.
* @return {!Object} JSON representation.
*/
Blockly.Events.CommentDelete.prototype.toJson = function() {
var json = Blockly.Events.CommentDelete.superClass_.toJson.call(this);
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.CommentDelete.prototype.fromJson = function(json) {
Blockly.Events.CommentDelete.superClass_.fromJson.call(this, json);
};
/**
* Run a creation event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.CommentDelete.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
if (forward) {
var comment = workspace.getCommentById(this.commentId);
if (comment) {
comment.dispose(false, false);
} else {
// Only complain about root-level block.
console.warn("Can't uncreate non-existent comment: " + this.commentId);
}
} else {
var xml = goog.dom.createDom('xml');
xml.appendChild(this.xml);
Blockly.Xml.domToWorkspace(xml, workspace);
}
};
/**
* Class for a comment move event. Created before the move.
* @param {Blockly.WorkspaceComment} comment The comment that is being moved.
* Null for a blank event.
* @extends {Blockly.Events.CommentBase}
* @constructor
*/
Blockly.Events.CommentMove = function(comment) {
if (!comment) {
return; // Blank event to be populated by fromJson.
}
Blockly.Events.CommentMove.superClass_.constructor.call(this, comment);
/**
* The comment that is being moved. Will be cleared after recording the new
* location.
* @type {?Blockly.WorkspaceComment}
*/
this.comment_ = comment;
/**
* The location before the move, in workspace coordinates.
* @type {!goog.math.Coordinate}
*/
this.oldCoordinate_ = comment.getXY();
/**
* The location after the move, in workspace coordinates.
* @type {!goog.math.Coordinate}
*/
this.newCoordinate_ = null;
};
goog.inherits(Blockly.Events.CommentMove, Blockly.Events.CommentBase);
/**
* Record the comment's new location. Called after the move. Can only be
* called once.
*/
Blockly.Events.CommentMove.prototype.recordNew = function() {
if (!this.comment_) {
throw new Error('Tried to record the new position of a comment on the ' +
'same event twice.');
}
this.newCoordinate_ = this.comment_.getXY();
this.comment_ = null;
};
/**
* Type of this event.
* @type {string}
*/
Blockly.Events.CommentMove.prototype.type = Blockly.Events.COMMENT_MOVE;
/**
* Override the location before the move. Use this if you don't create the
* event until the end of the move, but you know the original location.
* @param {!goog.math.Coordinate} xy The location before the move, in workspace
* coordinates.
*/
Blockly.Events.CommentMove.prototype.setOldCoordinate = function(xy) {
this.oldCoordinate_ = xy;
};
/**
* Encode the event as JSON.
* TODO (#1266): "Full" and "minimal" serialization.
* @return {!Object} JSON representation.
*/
Blockly.Events.CommentMove.prototype.toJson = function() {
var json = Blockly.Events.CommentMove.superClass_.toJson.call(this);
if (this.newCoordinate_) {
json['newCoordinate'] = Math.round(this.newCoordinate_.x) + ',' +
Math.round(this.newCoordinate_.y);
}
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
Blockly.Events.CommentMove.prototype.fromJson = function(json) {
Blockly.Events.CommentMove.superClass_.fromJson.call(this, json);
if (json['newCoordinate']) {
var xy = json['newCoordinate'].split(',');
this.newCoordinate_ =
new goog.math.Coordinate(parseFloat(xy[0]), parseFloat(xy[1]));
}
};
/**
* Does this event record any change of state?
* @return {boolean} False if something changed.
*/
Blockly.Events.CommentMove.prototype.isNull = function() {
return goog.math.Coordinate.equals(this.oldCoordinate_, this.newCoordinate_);
};
/**
* Run a move event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
Blockly.Events.CommentMove.prototype.run = function(forward) {
var workspace = this.getEventWorkspace_();
var comment = workspace.getCommentById(this.commentId);
if (!comment) {
console.warn('Can\'t move non-existent comment: ' + this.commentId);
return;
}
var target = forward ? this.newCoordinate_ : this.oldCoordinate_;
// TODO: Check if the comment is being dragged, and give up if so.
var current = comment.getXY();
comment.moveBy(target.x - current.x, target.y - current.y);
};
+77 -36
View File
@@ -33,7 +33,6 @@ goog.provide('Blockly.Xml');
goog.require('Blockly.Events.BlockCreate');
goog.require('Blockly.Events.VarCreate');
goog.require('goog.asserts');
goog.require('goog.dom');
@@ -45,9 +44,11 @@ goog.require('goog.dom');
*/
Blockly.Xml.workspaceToDom = function(workspace, opt_noId) {
var xml = goog.dom.createDom('xml');
var variables = Blockly.Variables.allUsedVarModels(workspace);
if (variables.length) {
xml.appendChild(Blockly.Xml.variablesToDom(variables));
xml.appendChild(Blockly.Xml.variablesToDom(
Blockly.Variables.allUsedVarModels(workspace)));
var comments = workspace.getTopComments(true);
for (var i = 0, comment; comment = comments[i]; i++) {
xml.appendChild(comment.toXmlWithXY(opt_noId));
}
var blocks = workspace.getTopBlocks(true);
for (var i = 0, block; block = blocks[i]; i++) {
@@ -136,7 +137,7 @@ Blockly.Xml.fieldToDomVariable_ = function(field) {
*/
Blockly.Xml.fieldToDom_ = function(field) {
if (field.name && field.EDITABLE) {
if (field instanceof Blockly.FieldVariable) {
if (field.referencesVariables()) {
return Blockly.Xml.fieldToDomVariable_(field);
} else {
var container = goog.dom.createDom('field', null, field.getValue());
@@ -344,22 +345,49 @@ Blockly.Xml.domToPrettyText = function(dom) {
};
/**
* Converts plain text into a DOM structure.
* Throws an error if XML doesn't parse.
* @param {string} text Text representation.
* @return {!Element} A tree of XML elements.
* Converts an XML string into a DOM tree. This method will be overridden in
* the Node.js build of Blockly. See gulpfile.js, blockly_javascript_en task.
* @param {string} text XML string.
* @return {!Element} The DOM document.
* @throws if XML doesn't parse.
* @private
*/
Blockly.Xml.textToDomDocument_ = function(text) {
var oParser = new DOMParser();
return oParser.parseFromString(text, 'text/xml');
};
/**
* Converts an XML string into a DOM structure. It requires the XML to have a
* root element of <xml>. Other XML string will result in throwing an error.
* @param {string} text An XML string.
* @return {!Element} A DOM object representing the singular child of the document element.
* @throws if XML doesn't parse or is not the expected structure.
*/
Blockly.Xml.textToDom = function(text) {
var oParser = new DOMParser();
var dom = oParser.parseFromString(text, 'text/xml');
// The DOM should have one and only one top-level node, an XML tag.
if (!dom || !dom.firstChild ||
dom.firstChild.nodeName.toLowerCase() != 'xml' ||
dom.firstChild !== dom.lastChild) {
// Whatever we got back from the parser is not XML.
goog.asserts.fail('Blockly.Xml.textToDom did not obtain a valid XML tree.');
var doc = Blockly.Xml.textToDomDocument_(text);
// This function only accepts <xml> documents.
if (!doc || !doc.documentElement ||
doc.documentElement.nodeName.toLowerCase() != 'xml') {
// Whatever we got back from the parser is not the expected structure.
throw Error('Blockly.Xml.textToDom expected an <xml> document.');
}
return dom.firstChild;
return doc.documentElement;
};
/**
* Clear the given workspace then decode an XML DOM and
* create blocks on the workspace.
* @param {!Element} xml XML DOM.
* @param {!Blockly.Workspace} workspace The workspace.
* @return {Array.<string>} An array containing new block ids.
*/
Blockly.Xml.clearWorkspaceAndLoadFromXml = function(xml, workspace) {
workspace.setResizesEnabled(false);
workspace.clear();
var blockIds = Blockly.Xml.domToWorkspace(xml, workspace);
workspace.setResizesEnabled(true);
return blockIds;
};
/**
@@ -376,6 +404,7 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) {
console.warn('Deprecated call to Blockly.Xml.domToWorkspace, ' +
'swap the arguments.');
}
var width; // Not used in LTR.
if (workspace.RTL) {
width = workspace.getWidth();
@@ -416,8 +445,13 @@ Blockly.Xml.domToWorkspace = function(xml, workspace) {
}
variablesFirst = false;
} else if (name == 'shadow') {
goog.asserts.fail('Shadow block cannot be a top-level block.');
variablesFirst = false;
throw Error('Shadow block cannot be a top-level block.');
} else if (name == 'comment') {
if (workspace.rendered) {
Blockly.WorkspaceCommentSvg.fromXml(xmlChild, workspace, width);
} else {
Blockly.WorkspaceComment.fromXml(xmlChild, workspace);
}
} else if (name == 'variables') {
if (variablesFirst) {
Blockly.Xml.domToVariables(xmlChild, workspace);
@@ -517,7 +551,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) {
try {
var topBlock = Blockly.Xml.domToBlockHeadless_(xmlBlock, workspace);
// Generate list of all blocks.
var blocks = topBlock.getDescendants();
var blocks = topBlock.getDescendants(false);
if (workspace.rendered) {
// Hide connections to speed up assembly.
topBlock.setConnectionsHidden(true);
@@ -562,6 +596,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) {
return topBlock;
};
/**
* Decode an XML list of variables and add the variables to the workspace.
* @param {!Element} xmlVariables List of XML variable elements.
@@ -592,8 +627,9 @@ Blockly.Xml.domToVariables = function(xmlVariables, workspace) {
Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
var block = null;
var prototypeName = xmlBlock.getAttribute('type');
goog.asserts.assert(
prototypeName, 'Block type unspecified: %s', xmlBlock.outerHTML);
if (!prototypeName) {
throw Error('Block type unspecified: ' + xmlBlock.outerHTML);
}
var id = xmlBlock.getAttribute('id');
block = workspace.newBlock(prototypeName, id);
@@ -681,7 +717,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
} else if (blockChild.previousConnection) {
input.connection.connect(blockChild.previousConnection);
} else {
goog.asserts.fail(
throw Error(
'Child block does not have output or previous statement.');
}
}
@@ -691,15 +727,18 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
block.nextConnection.setShadowDom(childShadowElement);
}
if (childBlockElement) {
goog.asserts.assert(block.nextConnection,
'Next statement does not exist.');
if (!block.nextConnection) {
throw Error('Next statement does not exist.');
}
// If there is more than one XML 'next' tag.
goog.asserts.assert(!block.nextConnection.isConnected(),
'Next statement is already connected.');
if (block.nextConnection.isConnected()) {
throw Error('Next statement is already connected.');
}
blockChild = Blockly.Xml.domToBlockHeadless_(childBlockElement,
workspace);
goog.asserts.assert(blockChild.previousConnection,
'Next block does not have previous statement.');
if (!blockChild.previousConnection) {
throw Error('Next block does not have previous statement.');
}
block.nextConnection.connect(blockChild.previousConnection);
}
break;
@@ -735,14 +774,16 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) {
}
if (xmlBlock.nodeName.toLowerCase() == 'shadow') {
// Ensure all children are also shadows.
var children = block.getChildren();
var children = block.getChildren(false);
for (var i = 0, child; child = children[i]; i++) {
goog.asserts.assert(
child.isShadow(), 'Shadow block not allowed non-shadow child.');
if (child.isShadow()) {
throw Error('Shadow block not allowed non-shadow child.');
}
}
// Ensure this block doesn't have any variable inputs.
goog.asserts.assert(block.getVarModels().length == 0,
'Shadow blocks cannot have variable references.');
if (block.getVarModels().length) {
throw Error('Shadow blocks cannot have variable references.');
}
block.setShadow(true);
}
return block;
@@ -796,7 +837,7 @@ Blockly.Xml.domToField_ = function(block, fieldName, xml) {
var workspace = block.workspace;
var text = xml.textContent;
if (field instanceof Blockly.FieldVariable) {
if (field.referencesVariables()) {
Blockly.Xml.domToFieldVariable_(workspace, xml, text, field);
} else {
field.setValue(text);
+156 -99
View File
@@ -93,106 +93,16 @@ Blockly.ZoomControls.prototype.top_ = 0;
* @return {!Element} The zoom controls SVG group.
*/
Blockly.ZoomControls.prototype.createDom = function() {
var workspace = this.workspace_;
/* Here's the markup that will be generated:
<g class="blocklyZoom">
<clippath id="blocklyZoomoutClipPath837493">
<rect width="32" height="32" y="77"></rect>
</clippath>
<image width="96" height="124" x="-64" y="-15" xlink:href="media/sprites.png"
clip-path="url(#blocklyZoomoutClipPath837493)"></image>
<clippath id="blocklyZoominClipPath837493">
<rect width="32" height="32" y="43"></rect>
</clippath>
<image width="96" height="124" x="-32" y="-49" xlink:href="media/sprites.png"
clip-path="url(#blocklyZoominClipPath837493)"></image>
<clippath id="blocklyZoomresetClipPath837493">
<rect width="32" height="32"></rect>
</clippath>
<image width="96" height="124" y="-92" xlink:href="media/sprites.png"
clip-path="url(#blocklyZoomresetClipPath837493)"></image>
</g>
*/
this.svgGroup_ = Blockly.utils.createSvgElement('g',
{'class': 'blocklyZoom'}, null);
var clip;
this.svgGroup_ =
Blockly.utils.createSvgElement('g', {'class': 'blocklyZoom'}, null);
// Each filter/pattern needs a unique ID for the case of multiple Blockly
// instances on a page. Browser behaviour becomes undefined otherwise.
// https://neil.fraser.name/news/2015/11/01/
var rnd = String(Math.random()).substring(2);
clip = Blockly.utils.createSvgElement('clipPath',
{'id': 'blocklyZoomoutClipPath' + rnd},
this.svgGroup_);
Blockly.utils.createSvgElement('rect',
{'width': 32, 'height': 32, 'y': 77},
clip);
var zoomoutSvg = Blockly.utils.createSvgElement('image',
{
'width': Blockly.SPRITE.width,
'height': Blockly.SPRITE.height, 'x': -64,
'y': -15,
'clip-path': 'url(#blocklyZoomoutClipPath' + rnd + ')'
},
this.svgGroup_);
zoomoutSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
workspace.options.pathToMedia + Blockly.SPRITE.url);
clip = Blockly.utils.createSvgElement('clipPath',
{'id': 'blocklyZoominClipPath' + rnd},
this.svgGroup_);
Blockly.utils.createSvgElement('rect',
{'width': 32, 'height': 32, 'y': 43},
clip);
var zoominSvg = Blockly.utils.createSvgElement('image',
{
'width': Blockly.SPRITE.width,
'height': Blockly.SPRITE.height,
'x': -32,
'y': -49,
'clip-path': 'url(#blocklyZoominClipPath' + rnd + ')'
},
this.svgGroup_);
zoominSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
workspace.options.pathToMedia + Blockly.SPRITE.url);
clip = Blockly.utils.createSvgElement('clipPath',
{'id': 'blocklyZoomresetClipPath' + rnd},
this.svgGroup_);
Blockly.utils.createSvgElement('rect',
{'width': 32, 'height': 32},
clip);
var zoomresetSvg = Blockly.utils.createSvgElement('image',
{
'width': Blockly.SPRITE.width,
'height': Blockly.SPRITE.height, 'y': -92,
'clip-path': 'url(#blocklyZoomresetClipPath' + rnd + ')'
},
this.svgGroup_);
zoomresetSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
workspace.options.pathToMedia + Blockly.SPRITE.url);
// Attach event listeners.
Blockly.bindEventWithChecks_(zoomresetSvg, 'mousedown', null, function(e) {
workspace.markFocused();
workspace.setScale(workspace.options.zoomOptions.startScale);
workspace.scrollCenter();
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
Blockly.bindEventWithChecks_(zoominSvg, 'mousedown', null, function(e) {
workspace.markFocused();
workspace.zoomCenter(1);
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
Blockly.bindEventWithChecks_(zoomoutSvg, 'mousedown', null, function(e) {
workspace.markFocused();
workspace.zoomCenter(-1);
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
this.createZoomOutSvg_(rnd);
this.createZoomInSvg_(rnd);
this.createZoomResetSvg_(rnd);
return this.svgGroup_;
};
@@ -251,3 +161,150 @@ Blockly.ZoomControls.prototype.position = function() {
this.svgGroup_.setAttribute('transform',
'translate(' + this.left_ + ',' + this.top_ + ')');
};
/**
* Create the zoom in icon and its event handler.
* @param {string} rnd The random string to use as a suffix in the clip path's
* ID. These IDs must be unique in case there are multiple Blockly
* instances on the same page.
* @private
*/
Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) {
/* This markup will be generated and added to the "blocklyZoom" group:
<clippath id="blocklyZoomoutClipPath837493">
<rect width="32" height="32" y="77"></rect>
</clippath>
<image width="96" height="124" x="-64" y="-15" xlink:href="media/sprites.png"
clip-path="url(#blocklyZoomoutClipPath837493)"></image>
*/
var ws = this.workspace_;
var clip = Blockly.utils.createSvgElement('clipPath',
{
'id': 'blocklyZoomoutClipPath' + rnd
},
this.svgGroup_);
Blockly.utils.createSvgElement('rect',
{
'width': 32,
'height': 32,
'y': 77
},
clip);
var zoomoutSvg = Blockly.utils.createSvgElement('image',
{
'width': Blockly.SPRITE.width,
'height': Blockly.SPRITE.height, 'x': -64,
'y': -15,
'clip-path': 'url(#blocklyZoomoutClipPath' + rnd + ')'
},
this.svgGroup_);
zoomoutSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
ws.options.pathToMedia + Blockly.SPRITE.url);
// Attach listener.
Blockly.bindEventWithChecks_(zoomoutSvg, 'mousedown', null, function(e) {
ws.markFocused();
ws.zoomCenter(-1);
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
};
/**
* Create the zoom out icon and its event handler.
* @param {string} rnd The random string to use as a suffix in the clip path's
* ID. These IDs must be unique in case there are multiple Blockly
* instances on the same page.
* @private
*/
Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) {
/* This markup will be generated and added to the "blocklyZoom" group:
<clippath id="blocklyZoominClipPath837493">
<rect width="32" height="32" y="43"></rect>
</clippath>
<image width="96" height="124" x="-32" y="-49" xlink:href="media/sprites.png"
clip-path="url(#blocklyZoominClipPath837493)"></image>
*/
var ws = this.workspace_;
var clip = Blockly.utils.createSvgElement('clipPath',
{
'id': 'blocklyZoominClipPath' + rnd
},
this.svgGroup_);
Blockly.utils.createSvgElement('rect',
{
'width': 32,
'height': 32,
'y': 43
},
clip);
var zoominSvg = Blockly.utils.createSvgElement('image',
{
'width': Blockly.SPRITE.width,
'height': Blockly.SPRITE.height,
'x': -32,
'y': -49,
'clip-path': 'url(#blocklyZoominClipPath' + rnd + ')'
},
this.svgGroup_);
zoominSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
ws.options.pathToMedia + Blockly.SPRITE.url);
// Attach listener.
Blockly.bindEventWithChecks_(zoominSvg, 'mousedown', null, function(e) {
ws.markFocused();
ws.zoomCenter(1);
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
};
/**
* Create the zoom reset icon and its event handler.
* @param {string} rnd The random string to use as a suffix in the clip path's
* ID. These IDs must be unique in case there are multiple Blockly
* instances on the same page.
* @private
*/
Blockly.ZoomControls.prototype.createZoomResetSvg_ = function(rnd) {
/* This markup will be generated and added to the "blocklyZoom" group:
<clippath id="blocklyZoomresetClipPath837493">
<rect width="32" height="32"></rect>
</clippath>
<image width="96" height="124" y="-92" xlink:href="media/sprites.png"
clip-path="url(#blocklyZoomresetClipPath837493)"></image>
*/
var ws = this.workspace_;
var clip = Blockly.utils.createSvgElement('clipPath',
{
'id': 'blocklyZoomresetClipPath' + rnd
},
this.svgGroup_);
Blockly.utils.createSvgElement('rect',
{
'width': 32,
'height': 32
},
clip);
var zoomresetSvg = Blockly.utils.createSvgElement('image',
{
'width': Blockly.SPRITE.width,
'height': Blockly.SPRITE.height, 'y': -92,
'clip-path': 'url(#blocklyZoomresetClipPath' + rnd + ')'
},
this.svgGroup_);
zoomresetSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href',
ws.options.pathToMedia + Blockly.SPRITE.url);
// Attach event listeners.
Blockly.bindEventWithChecks_(zoomresetSvg, 'mousedown', null, function(e) {
ws.markFocused();
ws.setScale(ws.options.zoomOptions.startScale);
ws.scrollCenter();
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
e.stopPropagation(); // Don't start a workspace scroll.
e.preventDefault(); // Stop double-clicking from selecting text.
});
};
+2 -1
View File
@@ -22,7 +22,8 @@
* @fileoverview Stubbed interface functions for analytics integration.
*/
goog.provide('BlocklyDevTools.Analytics');
var BlocklyDevTools = BlocklyDevTools || Object.create(null);
BlocklyDevTools.Analytics = BlocklyDevTools.Analytics || Object.create(null);
/**
* Whether these stub methods should log analytics calls to the console.
+13 -28
View File
@@ -25,17 +25,8 @@
*
* @author quachtina96 (Tina Quach)
*/
goog.provide('AppController');
goog.require('BlockFactory');
goog.require('BlocklyDevTools.Analytics');
goog.require('FactoryUtils');
goog.require('BlockLibraryController');
goog.require('BlockExporterController');
goog.require('goog.dom.classlist');
goog.require('goog.ui.PopupColorPicker');
goog.require('goog.ui.ColorPicker');
goog.require('goog.dom.xml'); // Used to detect Closure
/**
* Controller for the Blockly Factory
@@ -161,9 +152,7 @@ AppController.prototype.exportBlockLibraryToFile = function() {
*/
AppController.prototype.formatBlockLibraryForExport_ = function(blockXmlMap) {
// Create DOM for XML.
var xmlDom = goog.dom.createDom('xml', {
'xmlns':"http://www.w3.org/1999/xhtml"
});
var xmlDom = document.createElementNS('http://www.w3.org/1999/xhtml', 'xml');
// Append each block node to XML DOM.
for (var blockType in blockXmlMap) {
@@ -184,29 +173,25 @@ AppController.prototype.formatBlockLibraryForExport_ = function(blockXmlMap) {
* @private
*/
AppController.prototype.formatBlockLibraryForImport_ = function(xmlText) {
var xmlDom = Blockly.Xml.textToDom(xmlText);
// Get array of XMLs. Use an asterisk (*) instead of a tag name for the XPath
// selector, to match all elements at that level and get all factory_base
// blocks.
var blockNodes = goog.dom.xml.selectNodes(xmlDom, '*');
var inputXml = Blockly.Xml.textToDom(xmlText);
// Convert the live HTMLCollection of child Elements into a static array,
// since the addition to editorWorkspaceXml below removes it from inputXml.
var inputChildren = Array.from(inputXml.children);
// Create empty map. The line below creates a truly empy object. It doesn't
// have built-in attributes/functions such as length or toString.
var blockXmlTextMap = Object.create(null);
// Populate map.
for (var i = 0, blockNode; blockNode = blockNodes[i]; i++) {
for (var i = 0, blockNode; blockNode = inputChildren[i]; i++) {
// Add outer XML tag to the block for proper injection in to the
// main workspace.
// Create DOM for XML.
var xmlDom = goog.dom.createDom('xml', {
'xmlns':"http://www.w3.org/1999/xhtml"
});
xmlDom.appendChild(blockNode);
var editorWorkspaceXml =
document.createElementNS('http://www.w3.org/1999/xhtml', 'xml');
editorWorkspaceXml.appendChild(blockNode);
xmlText = Blockly.Xml.domToText(xmlDom);
xmlText = Blockly.Xml.domToText(editorWorkspaceXml);
// All block types should be lowercase.
var blockType = this.getBlockTypeFromXml_(xmlText).toLowerCase();
// Some names are invalid so fix them up.
@@ -376,9 +361,9 @@ AppController.prototype.onTab = function() {
AppController.prototype.styleTabs_ = function() {
for (var tabName in this.tabMap) {
if (this.selectedTab == tabName) {
goog.dom.classlist.addRemove(this.tabMap[tabName], 'taboff', 'tabon');
this.tabMap[tabName].classList.replace('taboff', 'tabon');
} else {
goog.dom.classlist.addRemove(this.tabMap[tabName], 'tabon', 'taboff');
this.tabMap[tabName].classList.replace('tabon', 'taboff');
}
}
};
@@ -23,21 +23,15 @@
'use strict';
/**
* Namespace for BlockDefinitionExtractor.
*/
goog.provide('BlockDefinitionExtractor');
/**
* Class to contain all functions needed to extract block definition from
* Namespace to contain all functions needed to extract block definition from
* the block preview data structure.
* @namespace
*/
BlockDefinitionExtractor = BlockDefinitionExtractor || Object.create(null);
var BlockDefinitionExtractor = BlockDefinitionExtractor || Object.create(null);
/**
* Builds a BlockFactory workspace that reflects the block structure of the
* exmaple block.
* example block.
*
* @param {!Blockly.Block} block The reference block from which the definition
* will be extracted.
@@ -45,7 +39,7 @@ BlockDefinitionExtractor = BlockDefinitionExtractor || Object.create(null);
* workspace.
*/
BlockDefinitionExtractor.buildBlockFactoryWorkspace = function(block) {
var workspaceXml = goog.dom.createDom('xml');
var workspaceXml = document.createElement('xml');
workspaceXml.append(
BlockDefinitionExtractor.factoryBase_(block, block.type));
@@ -64,7 +58,7 @@ BlockDefinitionExtractor.buildBlockFactoryWorkspace = function(block) {
*/
BlockDefinitionExtractor.newDomElement_ = function(name, opt_attrs, opt_text) {
// Avoid createDom(..)'s attributes argument for being too HTML specific.
var elem = goog.dom.createDom(name);
var elem = document.createElement(name);
if (opt_attrs) {
for (var key in opt_attrs) {
elem.setAttribute(key, opt_attrs[key]);
@@ -164,16 +158,17 @@ BlockDefinitionExtractor.factoryBase_ = function(block, name) {
factoryBaseEl.append(helpUrlValue);
// Convert colour_ to hue value 0-360 degrees
// TODO(#1247): Solve off-by-one errors.
// TODO: Deal with colors that don't map to standard hues. (Needs improved
// block definitions.)
var colour_hue = Math.floor(
goog.color.hexToHsv(block.colour_)[0]); // Off by one... sometimes
var colourBlock = BlockDefinitionExtractor.colourBlockFromHue_(colour_hue);
var colourInputValue =
BlockDefinitionExtractor.newDomElement_('value', {name: 'COLOUR'});
colourInputValue.append(colourBlock);
factoryBaseEl.append(colourInputValue);
var colour_hue = block.getHue(); // May be null if not set via hue.
if (colour_hue) {
var colourBlock = BlockDefinitionExtractor.colourBlockFromHue_(colour_hue);
var colourInputValue =
BlockDefinitionExtractor.newDomElement_('value', {name: 'COLOUR'});
colourInputValue.append(colourBlock);
factoryBaseEl.append(colourInputValue);
} else {
// Editor will not have a colour block and preview will render black.
// TODO: Support RGB colours in the block editor.
}
return factoryBaseEl;
};
@@ -480,7 +475,7 @@ BlockDefinitionExtractor.buildFieldDropdown_ = function(dropdown) {
var menuGenerator = dropdown.menuGenerator_;
if (typeof menuGenerator === 'function') {
var options = menuGenerator();
} else if (goog.isArray(menuGenerator)) {
} else if (Array.isArray(menuGenerator)) {
var options = menuGenerator;
} else {
throw new Error('Unrecognized type of menuGenerator: ' + menuGenerator);
@@ -29,22 +29,12 @@
'use strict';
goog.provide('BlockExporterController');
goog.require('BlocklyDevTools.Analytics');
goog.require('FactoryUtils');
goog.require('StandardCategories');
goog.require('BlockExporterView');
goog.require('BlockExporterTools');
goog.require('goog.dom.xml');
/**
* BlockExporter Controller Class
* @param {!BlockLibrary.Storage} blockLibStorage Block Library Storage.
* @constructor
*/
BlockExporterController = function(blockLibStorage) {
function BlockExporterController(blockLibStorage) {
// BlockLibrary.Storage object containing user's saved blocks.
this.blockLibStorage = blockLibStorage;
// Utils for generating code to export.
@@ -132,11 +122,11 @@ BlockExporterController.prototype.export = function() {
BlocklyDevTools.Analytics.onWarning(msg);
alert(msg);
} else {
// Get generator stub code in the selected language for the blocks.
var genStubs = this.tools.getGeneratorCode(blockXmlMap,
language);
// Download the file.
FactoryUtils.createAndDownloadFile(
genStubs, generatorStub_filename + '.js', 'javascript');
+4 -53
View File
@@ -28,25 +28,15 @@
*/
'use strict';
goog.provide('BlockExporterTools');
goog.require('FactoryUtils');
goog.require('BlockOption');
goog.require('goog.dom');
goog.require('goog.dom.xml');
/**
* Block Exporter Tools Class
* @constructor
*/
BlockExporterTools = function() {
function BlockExporterTools() {
// Create container for hidden workspace.
this.container = goog.dom.createDom('div', {
'id': 'blockExporterTools_hiddenWorkspace'
}, ''); // Empty quotes for empty div.
// Hide hidden workspace.
this.container.style.display = 'none';
this.container = document.createElement('div');
this.container.id = 'blockExporterTools_hiddenWorkspace';
this.container.style.display = 'none'; // Hide the hidden workspace.
document.body.appendChild(this.container);
/**
* Hidden workspace for the Block Exporter that holds pieces that make
@@ -167,45 +157,6 @@ BlockExporterTools.prototype.addBlockDefinitions = function(blockXmlMap) {
eval(blockDefs);
};
/**
* Pulls information about all blocks in the block library to generate XML
* for the selector workpace's toolbox.
* @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object.
* @return {!Element} XML representation of the toolbox.
*/
BlockExporterTools.prototype.generateToolboxFromLibrary
= function(blockLibStorage) {
// Create DOM for XML.
var xmlDom = goog.dom.createDom('xml', {
'id' : 'blockExporterTools_toolbox',
'style' : 'display:none'
});
var allBlockTypes = blockLibStorage.getBlockTypes();
// Object mapping block type to XML.
var blockXmlMap = blockLibStorage.getBlockXmlMap(allBlockTypes);
// Define the custom blocks in order to be able to create instances of
// them in the exporter workspace.
this.addBlockDefinitions(blockXmlMap);
for (var blockType in blockXmlMap) {
// Get block.
var block = FactoryUtils.getDefinedBlock(blockType, this.hiddenWorkspace);
var category = FactoryUtils.generateCategoryXml([block], blockType);
xmlDom.appendChild(category);
}
// If there are no blocks in library and the map is empty, append dummy
// category.
if (Object.keys(blockXmlMap).length == 0) {
var category = goog.dom.createDom('category');
category.setAttribute('name','Next Saved Block');
xmlDom.appendChild(category);
}
return xmlDom;
};
/**
* Generate XML for the workspace factory's category from imported block
* definitions.
+1 -8
View File
@@ -27,19 +27,12 @@
'use strict';
goog.provide('BlockExporterView');
goog.require('BlockExporterTools');
goog.require('BlockOption');
goog.require('goog.dom');
/**
* BlockExporter View Class
* @param {!Object} blockOptions Map of block types to BlockOption objects.
* @constructor
*/
BlockExporterView = function(blockOptions) {
function BlockExporterView(blockOptions) {
// Map of block types to BlockOption objects to select from.
this.blockOptions = blockOptions;
};
+2 -10
View File
@@ -32,14 +32,6 @@
*/
'use strict';
goog.provide('BlockLibraryController');
goog.require('BlocklyDevTools.Analytics');
goog.require('BlockLibraryStorage');
goog.require('BlockLibraryView');
goog.require('BlockFactory');
/**
* Block Library Controller Class
* @param {string} blockLibraryName Desired name of Block Library, also used
@@ -48,7 +40,7 @@ goog.require('BlockFactory');
* object that allows user to import a block library.
* @constructor
*/
BlockLibraryController = function(blockLibraryName, opt_blockLibraryStorage) {
function BlockLibraryController(blockLibraryName, opt_blockLibraryStorage) {
this.name = blockLibraryName;
// Create a new, empty Block Library Storage object, or load existing one.
this.storage = opt_blockLibraryStorage || new BlockLibraryStorage(this.name);
@@ -144,7 +136,7 @@ BlockLibraryController.prototype.saveToBlockLibrary = function() {
}
// Create block XML.
var xmlElement = goog.dom.createDom('xml');
var xmlElement = document.createElement('xml');
var block = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace);
xmlElement.appendChild(Blockly.Xml.blockToDomWithXY(block));
+3 -8
View File
@@ -27,9 +27,6 @@
'use strict';
goog.provide('BlockLibraryStorage');
/**
* Represents a block library's storage.
* @param {string} blockLibraryName Desired name of Block Library, also used
@@ -37,7 +34,7 @@ goog.provide('BlockLibraryStorage');
* @param {Object} opt_blocks Object mapping block type to XML.
* @constructor
*/
BlockLibraryStorage = function(blockLibraryName, opt_blocks) {
function BlockLibraryStorage(blockLibraryName, opt_blocks) {
// Add prefix to this.name to avoid collisions in local storage.
this.name = 'BlockLibraryStorage.' + blockLibraryName;
if (!opt_blocks) {
@@ -60,9 +57,7 @@ BlockLibraryStorage = function(blockLibraryName, opt_blocks) {
* Reads the named block library from local storage and saves it in this.blocks.
*/
BlockLibraryStorage.prototype.loadFromLocalStorage = function() {
// goog.global is synonymous to window, and allows for flexibility
// between browsers.
var object = goog.global.localStorage[this.name];
var object = localStorage[this.name];
this.blocks = object ? JSON.parse(object) : null;
};
@@ -70,7 +65,7 @@ BlockLibraryStorage.prototype.loadFromLocalStorage = function() {
* Writes the current block library (this.blocks) to local storage.
*/
BlockLibraryStorage.prototype.saveToLocalStorage = function() {
goog.global.localStorage[this.name] = JSON.stringify(this.blocks);
localStorage[this.name] = JSON.stringify(this.blocks);
};
/**
+8 -15
View File
@@ -27,12 +27,6 @@
'use strict';
goog.provide('BlockLibraryView');
goog.require('goog.dom');
goog.require('goog.dom.classlist');
/**
* BlockLibraryView Class
* @constructor
@@ -59,10 +53,10 @@ var BlockLibraryView = function() {
*/
BlockLibraryView.prototype.addOption = function(blockType, selected) {
// Create option.
var option = goog.dom.createDom('a', {
'id': 'dropdown_' + blockType,
'class': 'blockLibOpt'
}, blockType);
var option = document.createElement('a');
option.id ='dropdown_' + blockType;
option.classList.add('blockLibOpt');
option.textContent = blockType;
// Add option to dropdown.
this.dropdown.appendChild(option);
@@ -99,7 +93,7 @@ BlockLibraryView.prototype.setSelectedBlockType = function(blockTypeToSelect) {
* @private
*/
BlockLibraryView.prototype.selectOption_ = function(option) {
goog.dom.classlist.add(option, 'dropdown-content-selected');
option.classList.add('dropdown-content-selected');
};
/**
@@ -109,7 +103,7 @@ BlockLibraryView.prototype.selectOption_ = function(option) {
* @private
*/
BlockLibraryView.prototype.deselectOption_ = function(option) {
goog.dom.classlist.remove(option, 'dropdown-content-selected');
option.classList.remove('dropdown-content-selected');
};
/**
@@ -150,13 +144,12 @@ BlockLibraryView.prototype.updateButtons =
if (blockType == 'block_type') {
buttonFormatClass = 'button_alert';
}
goog.dom.classlist.add(this.saveButton, buttonFormatClass);
this.saveButton.classList.add(buttonFormatClass);
this.saveButton.disabled = false;
} else {
// No changes to save.
var classesToRemove = ['button_alert', 'button_warn'];
goog.dom.classlist.removeAll(this.saveButton, classesToRemove);
this.saveButton.classList.remove('button_alert', 'button_warn');
this.saveButton.disabled = true;
}
+22 -31
View File
@@ -19,18 +19,15 @@
*/
/**
* @fileoverview Javascript for the BlockOption class, used to represent each of
* the various blocks that you may select. Each block option has a checkbox,
* a label, and a preview workspace through which to view the block.
* @fileoverview Javascript for the BlockOption class, used to represent each
* of the various blocks that you may select in the Block Selector. Each block
* option has a checkbox, a label, and a preview workspace through which to
* view the block.
*
* @author quachtina96 (Tina Quach)
*/
'use strict';
goog.provide('BlockOption');
goog.require('goog.dom');
/**
* BlockOption Class
* A block option includes checkbox, label, and div element that shows a preview
@@ -70,48 +67,42 @@ var BlockOption = function(blockSelector, blockType, previewBlockXml) {
*/
BlockOption.prototype.createDom = function() {
// Create the div for the block option.
var blockOptContainer = goog.dom.createDom('div', {
'id': this.blockType,
'class': 'blockOption'
}, ''); // Empty quotes for empty div.
var blockOptContainer = document.createElement('div');
blockOptContainer.id = this.blockType;
blockOptContainer.classList.add('blockOption');
// Create and append div in which to inject the workspace for viewing the
// block option.
var blockOptionPreview = goog.dom.createDom('div', {
'id' : this.blockType + '_workspace',
'class': 'blockOption_preview'
}, '');
var blockOptionPreview = document.createElement('div');
blockOptionPreview.id = this.blockType + '_workspace';
blockOptionPreview.classList.add('blockOption_preview');
blockOptContainer.appendChild(blockOptionPreview);
// Create and append container to hold checkbox and label.
var checkLabelContainer = goog.dom.createDom('div', {
'class': 'blockOption_checkLabel'
}, '');
var checkLabelContainer = document.createElement('div');
checkLabelContainer.classList.add('blockOption_checkLabel');
blockOptContainer.appendChild(checkLabelContainer);
// Create and append container for checkbox.
var checkContainer = goog.dom.createDom('div', {
'class': 'blockOption_check'
}, '');
var checkContainer = document.createElement('div');
checkContainer.classList.add('blockOption_check');
checkLabelContainer.appendChild(checkContainer);
// Create and append checkbox.
this.checkbox = goog.dom.createDom('input', {
'type': 'checkbox',
'id': this.blockType + '_check'
}, '');
this.checkbox = document.createElement('input');
this.checkbox.id = this.blockType + '_check';
this.checkbox.setAttribute('type', 'checkbox');
checkContainer.appendChild(this.checkbox);
// Create and append container for block label.
var labelContainer = goog.dom.createDom('div', {
'class': 'blockOption_label'
}, '');
var labelContainer = document.createElement('div');
labelContainer.classList.add('blockOption_label');
checkLabelContainer.appendChild(labelContainer);
// Create and append text node for the label.
var labelText = goog.dom.createDom('p', {
'id': this.blockType + '_text'
}, this.blockType);
var labelText = document.createElement('p');
labelText.id = this.blockType + '_text';
labelText.textContent = this.blockType;
labelContainer.appendChild(labelText);
this.dom = blockOptContainer;
+2 -5
View File
@@ -32,10 +32,7 @@
/**
* Namespace for Block Factory.
*/
goog.provide('BlockFactory');
goog.require('FactoryUtils');
goog.require('StandardCategories');
var BlockFactory = BlockFactory || Object.create(null);
/**
* Workspace for user to build block.
@@ -151,7 +148,7 @@ BlockFactory.updateLanguage = function() {
if (!BlockFactory.updateBlocksFlagDelayed) {
var languagePre = document.getElementById('languagePre');
var languageTA = document.getElementById('languageTA');
code = languagePre.textContent.trim();
code = languagePre.innerText.trim();
languageTA.value = code;
}
}
+2 -5
View File
@@ -32,10 +32,7 @@
/**
* Namespace for FactoryUtils.
*/
goog.provide('FactoryUtils');
goog.require('BlockDefinitionExtractor');
var FactoryUtils = FactoryUtils || Object.create(null);
/**
* Get block definition code for the current block.
@@ -768,7 +765,7 @@ FactoryUtils.getBlockTypeFromJsDefinition = function(blockDef) {
*/
FactoryUtils.generateCategoryXml = function(blocks, categoryName) {
// Create category DOM element.
var categoryElement = goog.dom.createDom('category');
var categoryElement = document.createElement('category');
categoryElement.setAttribute('name', categoryName);
// For each block, add block element to category.
+1 -1
View File
@@ -32,7 +32,7 @@
/**
* Namespace for StandardCategories
*/
goog.provide('StandardCategories');
var StandardCategories = StandardCategories || Object.create(null);
// Map of standard category information necessary to add a standard category
@@ -34,11 +34,6 @@
* @author Emma Dauterman (evd2014)
*/
goog.require('BlocklyDevTools.Analytics');
goog.require('FactoryUtils');
goog.require('StandardCategories');
/**
* Class for a WorkspaceFactoryController
* @param {string} toolboxName Name of workspace toolbox XML.
@@ -28,8 +28,6 @@
* @author Emma Dauterman (evd2014)
*/
goog.require('FactoryUtils');
/**
* Class for a WorkspaceFactoryGenerator
@@ -61,11 +59,10 @@ WorkspaceFactoryGenerator = function(model) {
*/
WorkspaceFactoryGenerator.prototype.generateToolboxXml = function() {
// Create DOM for XML.
var xmlDom = goog.dom.createDom('xml',
{
'id' : 'toolbox',
'style' : 'display:none'
});
var xmlDom = document.createElement('xml');
xmlDom.id = 'toolbox';
xmlDom.style.display = 'none';
if (!this.model.hasElements()) {
// Toolbox has no categories. Use XML directly from workspace.
this.loadToHiddenWorkspace_(this.model.getSelectedXml());
@@ -88,10 +85,10 @@ WorkspaceFactoryGenerator.prototype.generateToolboxXml = function() {
var element = toolboxList[i];
if (element.type == ListElement.TYPE_SEPARATOR) {
// If the next element is a separator.
var nextElement = goog.dom.createDom('sep');
var nextElement = document.createElement('sep');
} else if (element.type == ListElement.TYPE_CATEGORY) {
// If the next element is a category.
var nextElement = goog.dom.createDom('category');
var nextElement = document.createElement('category');
nextElement.setAttribute('name', element.name);
// Add a colour attribute if one exists.
if (element.color != null) {
@@ -27,7 +27,8 @@
* @author Emma Dauterman (evd2014)
*/
goog.require('FactoryUtils');
goog.require('goog.ui.PopupColorPicker');
goog.require('goog.ui.ColorPicker');
/**
* Namespace for workspace factory initialization methods.
@@ -28,7 +28,6 @@
* @author Emma Dauterman (edauterman)
*/
goog.require('FactoryUtils');
/**
* Class for a WorkspaceFactoryView
+1 -1
View File
@@ -538,7 +538,7 @@ Code.runJS = function() {
Code.discard = function() {
var count = Code.workspace.getAllBlocks().length;
if (count < 2 ||
window.confirm(Blockly.Msg.DELETE_ALL_BLOCKS.replace('%1', count))) {
window.confirm(Blockly.Msg['DELETE_ALL_BLOCKS'].replace('%1', count))) {
Code.workspace.clear();
if (window.location.hash) {
window.location.hash = '';
+3 -3
View File
@@ -33,7 +33,7 @@
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml id="toolbox" style="display: none">
<category name="Inputs" colour="230">
<category name="Inputs" colour="%{BKY_MATH_HUE}">
<block type="math_number" gap="32">
<field name="NUM">123</field>
</block>
@@ -47,8 +47,8 @@
</block>
</category>
<sep></sep>
<category name="Variables" colour="330" custom="VARIABLE"></category>
<category name="Functions" colour="290" custom="PROCEDURE"></category>
<category name="Variables" colour="%{BKY_VARIABLES_HUE}" custom="VARIABLE"></category>
<category name="Functions" colour="%{BKY_PROCEDURES_HUE}" custom="PROCEDURE"></category>
</xml>
<script>
+7 -6
View File
@@ -22,9 +22,10 @@
<h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
<a href="../index.html">Demos</a> &gt; Generating JavaScript</h1>
<p>This is a simple demo of generating code from blocks.</p>
<p>This is a simple demo of generating code from blocks and running
the code in a sandboxed JavaScript interpreter.</p>
<p>&rarr; More info on <a href="https://developers.google.com/blockly/guides/configure/web/code-generators">Code Generators</a>&hellip;</p>
<p>&rarr; More info on <a href="https://developers.google.com/blockly/guides/configure/web/code-generators">Code Generators</a> and <a href="https://developers.google.com/blockly/guides/app-integration/running-javascript">Running JavaScript</a>.</p>
<p>
<button onclick="showCode()">Show JavaScript</button>
@@ -34,14 +35,14 @@
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml id="toolbox" style="display: none">
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops">
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -51,14 +52,14 @@
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text">
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
+9 -9
View File
@@ -58,7 +58,7 @@
</div>
<xml id="toolbox" style="display: none">
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
@@ -146,10 +146,10 @@
</block>
<block type="math_random_float"></block>
</category>
<category name="Variables">
<category name="Variables" colour="%{BKY_VARIABLES_HUE}">
<block type="graph_get_x"></block>
</category>
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
@@ -196,9 +196,9 @@ Blockly.defineBlocksWithJsonArray([{
"type": "graph_get_x",
"message0": "x",
"output": "Number",
"colour": Blockly.Msg.VARIABLES_HUE,
"tooltip": Blockly.Msg.VARIABLES_GET_TOOLTIP,
"helpUrl": Blockly.Msg.VARIABLES_GET_HELPURL
"colour": Blockly.Msg['VARIABLES_HUE'],
"tooltip": Blockly.Msg['VARIABLES_GET_TOOLTIP'],
"helpUrl": Blockly.Msg['VARIABLES_GET_HELPURL']
}]);
Blockly.JavaScript['graph_get_x'] = function(block) {
@@ -216,9 +216,9 @@ Blockly.defineBlocksWithJsonArray([{
"check": "Number"
}
],
"colour": Blockly.Msg.VARIABLES_HUE,
"tooltip": Blockly.Msg.VARIABLES_SET_TOOLTIP,
"helpUrl": Blockly.Msg.VARIABLES_SET_HELPURL
"colour": Blockly.Msg['VARIABLES_HUE'],
"tooltip": Blockly.Msg['VARIABLES_SET_TOOLTIP'],
"helpUrl": Blockly.Msg['VARIABLES_SET_HELPURL']
}]);
Blockly.JavaScript['graph_set_y'] = function(block) {
+9 -6
View File
@@ -41,14 +41,14 @@
</div>
<xml id="toolbox" style="display: none">
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops">
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -58,14 +58,14 @@
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text">
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
@@ -75,8 +75,11 @@
</value>
</block>
</category>
<category name="Variables" custom="VARIABLE"></category>
<category name="Functions" custom="PROCEDURE"></category>
<sep></sep>
<category name="Variables" custom="VARIABLE" colour="%{BKY_VARIABLES_HUE}">
</category>
<category name="Functions" custom="PROCEDURE" colour="%{BKY_PROCEDURES_HUE}">
</category>
</xml>
<xml id="startBlocks" style="display: none">
+9 -6
View File
@@ -48,14 +48,14 @@
</div>
<xml id="toolbox" style="display: none">
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops">
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -65,14 +65,14 @@
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text">
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
@@ -82,8 +82,11 @@
</value>
</block>
</category>
<category name="Variables" custom="VARIABLE"></category>
<category name="Functions" custom="PROCEDURE"></category>
<sep></sep>
<category name="Variables" custom="VARIABLE" colour="%{BKY_VARIABLES_HUE}">
</category>
<category name="Functions" custom="PROCEDURE" colour="%{BKY_PROCEDURES_HUE}">
</category>
</xml>
<xml id="startBlocks" style="display: none">
+4 -4
View File
@@ -32,14 +32,14 @@
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml id="toolbox" style="display: none">
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops">
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -67,14 +67,14 @@
</value>
</block>
</category>
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text">
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
+5 -5
View File
@@ -26,11 +26,11 @@
Blockly.Blocks['plane_set_seats'] = {
// Block seat variable setter.
init: function() {
this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL);
this.setHelpUrl(Blockly.Msg['VARIABLES_SET_HELPURL']);
this.setColour(330);
this.appendValueInput('VALUE')
.appendField(Plane.getMsg('Plane_setSeats'));
this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP);
this.setTooltip(Blockly.Msg['VARIABLES_SET_TOOLTIP']);
this.setDeletable(false);
}
};
@@ -45,7 +45,7 @@ Blockly.JavaScript['plane_set_seats'] = function(block) {
Blockly.Blocks['plane_get_rows'] = {
// Block for row variable getter.
init: function() {
this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL);
this.setHelpUrl(Blockly.Msg['VARIABLES_GET_HELPURL']);
this.setColour(330);
this.appendDummyInput()
.appendField(Plane.getMsg('Plane_getRows'), 'title');
@@ -65,7 +65,7 @@ Blockly.JavaScript['plane_get_rows'] = function(block) {
Blockly.Blocks['plane_get_rows1st'] = {
// Block for first class row variable getter.
init: function() {
this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL);
this.setHelpUrl(Blockly.Msg['VARIABLES_GET_HELPURL']);
this.setColour(330);
this.appendDummyInput()
.appendField(Plane.getMsg('Plane_getRows1'), 'title');
@@ -85,7 +85,7 @@ Blockly.JavaScript['plane_get_rows1st'] = function(block) {
Blockly.Blocks['plane_get_rows2nd'] = {
// Block for second class row variable getter.
init: function() {
this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL);
this.setHelpUrl(Blockly.Msg['VARIABLES_GET_HELPURL']);
this.setColour(330);
this.appendDummyInput()
.appendField(Plane.getMsg('Plane_getRows2'), 'title');
+11 -8
View File
@@ -42,7 +42,7 @@
<div id="blocklyDiv"></div>
<xml id="toolbox" style="display: none">
<category name="منطق">
<category name="منطق" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
@@ -51,7 +51,7 @@
<block type="logic_null"></block>
<block type="logic_ternary"></block>
</category>
<category name="الحلقات">
<category name="الحلقات" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -80,7 +80,7 @@
<block type="controls_forEach"></block>
<block type="controls_flow_statements"></block>
</category>
<category name="رياضيات">
<category name="رياضيات" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
@@ -118,7 +118,7 @@
</block>
<block type="math_random_float"></block>
</category>
<category name="نص">
<category name="نص" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_join"></block>
<block type="text_append">
@@ -139,7 +139,7 @@
</value>
</block>
</category>
<category name="قوائم">
<category name="قوائم" colour="%{BKY_LISTS_HUE}">
<block type="lists_create_empty"></block>
<block type="lists_create_with"></block>
<block type="lists_repeat">
@@ -155,13 +155,16 @@
<block type="lists_getIndex"></block>
<block type="lists_setIndex"></block>
</category>
<category name="لون">
<category name="لون" colour="%{BKY_COLOUR_HUE}">
<block type="colour_picker"></block>
<block type="colour_rgb"></block>
<block type="colour_blend"></block>
</category>
<category name="متغيرات" custom="VARIABLE"></category>
<category name="إجراءات" custom="PROCEDURE"></category>
<sep></sep>
<category name="متغيرات" custom="VARIABLE" colour="%{BKY_VARIABLES_HUE}">
</category>
<category name="إجراءات" custom="PROCEDURE" colour="%{BKY_PROCEDURES_HUE}">
</category>
</xml>
<xml id="startBlocks" style="display: none">
+4 -4
View File
@@ -50,14 +50,14 @@
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml id="toolbox" style="display: none">
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
</category>
<category name="Loops">
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -67,14 +67,14 @@
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
</category>
<category name="Text">
<category name="Text" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
+10 -7
View File
@@ -28,7 +28,7 @@
<div id="blocklyDiv" style="height: 600px; width: 800px;"></div>
<xml id="toolbox" style="display: none">
<category name="Logic">
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
<category name="If">
<block type="controls_if"></block>
<block type="controls_if">
@@ -38,7 +38,7 @@
<mutation elseif="1" else="1"></mutation>
</block>
</category>
<category name="Boolean">
<category name="Boolean" colour="%{BKY_LOGIC_HUE}">
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
@@ -47,7 +47,7 @@
<block type="logic_ternary"></block>
</category>
</category>
<category name="Loops">
<category name="Loops" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
@@ -77,7 +77,7 @@
<block type="controls_forEach"></block>
<block type="controls_flow_statements"></block>
</category>
<category name="Math">
<category name="Math" colour="%{BKY_MATH_HUE}">
<block type="math_number">
<field name="NUM">123</field>
</block>
@@ -115,7 +115,7 @@
</block>
<block type="math_random_float"></block>
</category>
<category name="Lists">
<category name="Lists" colour="%{BKY_LISTS_HUE}">
<block type="lists_create_empty"></block>
<block type="lists_create_with"></block>
<block type="lists_repeat">
@@ -131,8 +131,11 @@
<block type="lists_getIndex"></block>
<block type="lists_setIndex"></block>
</category>
<category name="Variables" custom="VARIABLE"></category>
<category name="Functions" custom="PROCEDURE"></category>
<sep></sep>
<category name="Variables" custom="VARIABLE" colour="%{BKY_VARIABLES_HUE}">
</category>
<category name="Functions" custom="PROCEDURE" colour="%{BKY_PROCEDURES_HUE}">
</category>
<sep></sep>
<category name="Library" expanded="true">
<category name="Randomize">
+110
View File
@@ -0,0 +1,110 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2018 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 Gulp script to build Blockly for Node & NPM.
* Run this script by calling "npm install" in this directory.
*/
var gulp = require('gulp');
gulp.shell = require('gulp-shell');
gulp.concat = require('gulp-concat');
var insert = require('gulp-insert');
// Rebuilds Blockly, including the following:
// - blockly_compressed.js
// - blocks_compressed.js
// - Localization string tables in msg/js/*.js
// - Generators in generators/*.js
// These files are already up-to-date in the master branch.
gulp.task('build', gulp.shell.task([
'python build.py'
]));
// Concatenates the necessary files to load Blockly in a Node.js VM. Blockly's
// individual libraries target use in a browser, where globals (via the window
// objects) are used to share state and APIs. By concatenating all the
// necessary components into a single file, Blockly can be loaded as a Node.js
// module.
//
// This task builds Node with the assumption that the app needs English blocks
// and JavaScript code generation. If you need another localization or
// generator language, just copy and edit the srcs. Only one localization
// language can be included.
gulp.task('blockly_javascript_en', function() {
var srcs = [
'blockly_compressed.js',
'blocks_compressed.js',
'javascript_compressed.js',
'msg/js/en.js'
];
// Concatenate the sources, appending the module export at the bottom.
// Override textToDomDocument_, providing Node alternative to DOMParser.
return gulp.src(srcs)
.pipe(gulp.concat('blockly_node_javascript_en.js'))
.pipe(insert.append(`
if (typeof DOMParser !== 'function') {
var JSDOM = require('jsdom').JSDOM;
Blockly.Xml.textToDomDocument_ = function(text) {
var jsdom = new JSDOM(text, { contentType: 'text/xml' });
return jsdom.window.document;
};
}
if (typeof module === 'object') { module.exports = Blockly; }
if (typeof window === 'object') { window.Blockly = Blockly; }\n`))
.pipe(gulp.dest(''));
});
/**
* Task-builder for the watch function. Currently any change invokes the whole
* build script. Invoke with "gulp watch".
*
* @param {?string=} concatTask Name of the concatenating task for node usage.
*/
// TODO: Only run the necessary phases of the build script for a given change.
function buildWatchTaskFn(concatTask) {
return function() {
// Tasks to trigger.
var tasks = ['build'];
if (concatTask) {
tasks.push(concatTask);
}
// Currently any changes invokes the whole build script. (To fix.)
var srcs = [
'core/**/*.js', // Blockly core code
'blocks/*.js', // Block definitions
'generators/**/*.js', // Code generation
'msg/messages.js', 'msg/json/*.json' // Localization data
];
var options = {
debounceDelay: 2000 // Milliseconds to delay rebuild.
};
gulp.watch(srcs, options, tasks);
};
}
// Watch Blockly files for changes and trigger automatic rebuilds, including
// the Node-ready blockly_node_javascript_en.js file.
gulp.task('watch', buildWatchTaskFn('blockly_javascript_en'));
// The default task concatenates files for Node.js, using English language
// blocks and the JavaScript generator.
gulp.task('default', ['build', 'blockly_javascript_en']);

Some files were not shown because too many files have changed in this diff Show More