Merge branch 'develop' into build-elsewhere

This commit is contained in:
Christopher Allen
2021-06-29 16:22:13 +01:00
46 changed files with 2077 additions and 1177 deletions

View File

@@ -37,7 +37,7 @@ jobs:
run: source ./tests/scripts/setup_osx_env.sh
- name: Run
run: npm run test:run
run: npm run test
env:
CI: true

View File

@@ -11,7 +11,6 @@ deploy
/static/scripts/
/static/typings/
/static/build.py
/static/eslintrc.json
/static/gulpfile.js
/static/jsconfig.json

View File

@@ -165,14 +165,16 @@ goog.addDependency('../../core/renderers/zelos/measurables/row_elements.js', ['B
goog.addDependency('../../core/renderers/zelos/measurables/rows.js', ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.utils.object']);
goog.addDependency('../../core/renderers/zelos/path_object.js', ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider']);
goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']);
goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer']);
goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer']);
goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Events', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Svg', 'Blockly.utils.dom']);
goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly.Gesture', 'Blockly.ShortcutRegistry', 'Blockly.utils.KeyCodes']);
goog.addDependency('../../core/shortcut_registry.js', ['Blockly.ShortcutRegistry'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object']);
goog.addDependency('../../core/theme.js', ['Blockly.Theme'], ['Blockly.registry', 'Blockly.utils', 'Blockly.utils.object']);
goog.addDependency('../../core/theme/classic.js', ['Blockly.Themes.Classic'], ['Blockly.Theme']);
goog.addDependency('../../core/theme/dark.js', ['Blockly.Themes.Dark'], ['Blockly.Theme']);
goog.addDependency('../../core/theme/deuteranopia.js', ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']);
goog.addDependency('../../core/theme/highcontrast.js', ['Blockly.Themes.HighContrast'], ['Blockly.Theme']);
goog.addDependency('../../core/theme/modern.js', ['Blockly.Themes.Modern'], ['Blockly.Theme']);
goog.addDependency('../../core/theme/tritanopia.js', ['Blockly.Themes.Tritanopia'], ['Blockly.Theme']);
goog.addDependency('../../core/theme/zelos.js', ['Blockly.Themes.Zelos'], ['Blockly.Theme']);
goog.addDependency('../../core/theme_manager.js', ['Blockly.ThemeManager'], ['Blockly.Theme']);

507
build.py
View File

@@ -1,507 +0,0 @@
#!/usr/bin/python2.7
#
# Deprecation warning: (July 2020)
# This build script has been deprecated, please use 'npm run build' instead.
# The script will be removed from Blockly core in Q4 of 2020.
#
# Compresses the core Blockly files into a single JavaScript file.
#
# Copyright 2012 Google LLC
#
# 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.
# Usage: build.py <0 or more of core, generators, langfiles>
# build.py with no parameters builds all files.
# core builds blockly_compressed, blockly_uncompressed, and blocks_compressed.
# generators builds every <language>_compressed.js.
# langfiles builds every msg/js/<LANG>.js file.
# This script generates two versions of Blockly's core files:
# blockly_compressed.js
# blockly_uncompressed.js
# The compressed file is a concatenation of all of Blockly's core files which
# have been run through Google's Closure Compiler. This is done using the
# online API (which takes a few seconds and requires an Internet connection).
# The uncompressed file is a script that loads in each of Blockly's core files
# one by one. This takes much longer for a browser to load, but is useful
# when debugging code since line numbers are meaningful and variables haven't
# been renamed. The uncompressed file also allows for a faster development
# cycle since there is no need to rebuild or recompile, just reload.
#
# This script also generates:
# blocks_compressed.js: The compressed Blockly language blocks.
# javascript_compressed.js: The compressed JavaScript generator.
# python_compressed.js: The compressed Python generator.
# php_compressed.js: The compressed PHP generator.
# lua_compressed.js: The compressed Lua generator.
# dart_compressed.js: The compressed Dart generator.
# msg/js/<LANG>.js for every language <LANG> defined in msg/js/<LANG>.json.
import argparse
import codecs
import glob
import json
import os
import re
import subprocess
import sys
import threading
if sys.version_info[0] == 2:
import httplib
from urllib import urlencode
else:
import http.client as httplib
from urllib.parse import urlencode
from importlib import reload
# Read package.json and extract the current Blockly version.
blocklyVersion = json.loads(open('package.json', 'r').read())['version']
def import_path(fullpath):
"""Import a file with full path specification.
Allows one to import from any directory, something __import__ does not do.
Args:
fullpath: Path and filename of import.
Returns:
An imported module.
"""
path, filename = os.path.split(fullpath)
filename, ext = os.path.splitext(filename)
sys.path.append(path)
module = __import__(filename)
reload(module) # Might be out of date.
del sys.path[-1]
return module
HEADER = ("// Do not edit this file; automatically generated by build.py.\n"
"'use strict';\n")
class Gen_uncompressed(threading.Thread):
"""Generate a JavaScript file that loads Blockly's raw files.
Runs in a separate thread.
"""
def __init__(self, search_paths, target_filename):
threading.Thread.__init__(self)
self.search_paths = search_paths
self.target_filename = target_filename
def run(self):
f = open(self.target_filename, 'w')
f.write(HEADER)
f.write("""
this.IS_NODE_JS = !!(typeof module !== 'undefined' && module.exports);
this.BLOCKLY_DIR = (function(root) {
if (!root.IS_NODE_JS) {
// Find name of current directory.
var scripts = document.getElementsByTagName('script');
var re = new RegExp('(.+)[\/]blockly_(.*)uncompressed\.js$');
for (var i = 0, script; script = scripts[i]; i++) {
var match = re.exec(script.src);
if (match) {
return match[1];
}
}
alert('Could not detect Blockly\\'s directory name.');
}
return '';
})(this);
this.BLOCKLY_BOOT = function(root) {
// Execute after Closure has loaded.
""")
add_dependency = []
base_path = calcdeps.FindClosureBasePath(self.search_paths)
for dep in calcdeps.BuildDependenciesFromFiles(self.search_paths):
add_dependency.append(calcdeps.GetDepsLine(dep, base_path))
add_dependency.sort() # Deterministic build.
add_dependency = '\n'.join(add_dependency)
f.write(add_dependency + '\n')
f.write('\n')
f.write('// Load Blockly.\n')
f.write('goog.require(\'Blockly.requires\');\n')
f.write("""
delete root.BLOCKLY_DIR;
delete root.BLOCKLY_BOOT;
delete root.IS_NODE_JS;
};
if (this.IS_NODE_JS) {
this.BLOCKLY_BOOT(this);
module.exports = Blockly;
} else {
document.write('<script src="' + this.BLOCKLY_DIR +
'/closure/goog/base.js"></script>');
document.write('<script>this.BLOCKLY_BOOT(this);</script>');
}
""")
f.close()
print("SUCCESS: " + self.target_filename)
class Gen_compressed(threading.Thread):
"""Generate a JavaScript file that contains all of Blockly's core and all
required parts of Closure, compiled together.
Uses the Closure Compiler's online API.
Runs in a separate thread.
"""
def __init__(self, search_paths, bundles):
threading.Thread.__init__(self)
self.search_paths = search_paths
self.bundles = bundles
def run(self):
if (self.bundles.core):
self.gen_core()
self.gen_blocks()
if (self.bundles.generators):
self.gen_generator("javascript")
self.gen_generator("python")
self.gen_generator("php")
self.gen_generator("lua")
self.gen_generator("dart")
def gen_core(self):
target_filename = "blockly_compressed.js"
# Define the parameters for the POST request.
params = [
("compilation_level", "SIMPLE_OPTIMIZATIONS"),
("use_closure_library", "false"),
("output_format", "json"),
("output_info", "compiled_code"),
("output_info", "warnings"),
("output_info", "errors"),
("output_info", "statistics"),
("warning_level", "DEFAULT"),
]
# Read in all the source files.
filenames = calcdeps.CalculateDependencies(self.search_paths,
[os.path.join("core", "requires.js")])
filenames.sort() # Deterministic build.
for filename in filenames:
# Filter out the Closure files (the compiler will add them).
if filename.startswith("closure"):
continue
f = codecs.open(filename, encoding="utf-8")
code = "".join(f.readlines())
# Inject the Blockly version.
if filename == "core/blockly.js":
code = code.replace("Blockly.VERSION = 'uncompiled';",
"Blockly.VERSION = '%s';" % blocklyVersion)
# Strip out all requireType calls.
code = re.sub(r"goog.requireType(.*)", "", code)
params.append(("js_code", code.encode("utf-8")))
f.close()
self.do_compile(params, target_filename, filenames, "")
def gen_blocks(self):
target_filename = "blocks_compressed.js"
# Define the parameters for the POST request.
params = [
("compilation_level", "SIMPLE_OPTIMIZATIONS"),
("output_format", "json"),
("output_info", "compiled_code"),
("output_info", "warnings"),
("output_info", "errors"),
("output_info", "statistics"),
("warning_level", "DEFAULT"),
]
# Add Blockly, Blockly.Blocks, and all fields to be compatible with the compiler.
params.append(("js_code", """
goog.provide('Blockly');
goog.provide('Blockly.Blocks');
goog.provide('Blockly.Comment');
goog.provide('Blockly.FieldCheckbox');
goog.provide('Blockly.FieldColour');
goog.provide('Blockly.FieldDropdown');
goog.provide('Blockly.FieldImage');
goog.provide('Blockly.FieldLabel');
goog.provide('Blockly.FieldMultilineInput');
goog.provide('Blockly.FieldNumber');
goog.provide('Blockly.FieldTextInput');
goog.provide('Blockly.FieldVariable');
goog.provide('Blockly.Mutator');
goog.provide('Blockly.Warning');
"""))
# Read in all the source files.
filenames = glob.glob(os.path.join("blocks", "*.js"))
filenames.sort() # Deterministic build.
for filename in filenames:
f = codecs.open(filename, encoding="utf-8")
params.append(("js_code", "".join(f.readlines()).encode("utf-8")))
f.close()
# Remove Blockly, Blockly.Blocks and all fields to be compatible with Blockly.
remove = r"var Blockly=\{[^;]*\};\n?"
self.do_compile(params, target_filename, filenames, remove)
def gen_generator(self, language):
target_filename = language + "_compressed.js"
# Define the parameters for the POST request.
params = [
("compilation_level", "SIMPLE_OPTIMIZATIONS"),
("output_format", "json"),
("output_info", "compiled_code"),
("output_info", "warnings"),
("output_info", "errors"),
("output_info", "statistics"),
("warning_level", "DEFAULT"),
]
# Read in all the source files.
# Add Blockly.Generator and Blockly.utils.string to be compatible
# with the compiler.
params.append(("js_code", """
goog.provide('Blockly.Generator');
goog.provide('Blockly.utils.global');
goog.provide('Blockly.utils.string');
"""))
filenames = glob.glob(
os.path.join("generators", language, "*.js"))
filenames.sort() # Deterministic build.
filenames.insert(0, os.path.join("generators", language + ".js"))
for filename in filenames:
f = codecs.open(filename, encoding="utf-8")
params.append(("js_code", "".join(f.readlines()).encode("utf-8")))
f.close()
filenames.insert(0, "[goog.provide]")
# Remove Blockly.Generator and Blockly.utils.string to be compatible
# with Blockly.
remove = r"var Blockly=\{[^;]*\};\s*Blockly.utils.global={};\s*Blockly.utils.string={};\n?"
self.do_compile(params, target_filename, filenames, remove)
def do_compile(self, params, target_filename, filenames, remove):
# Send the request to Google.
headers = {"Content-type": "application/x-www-form-urlencoded"}
conn = httplib.HTTPSConnection("closure-compiler.appspot.com")
conn.request("POST", "/compile", urlencode(params), headers)
response = conn.getresponse()
# Decode is necessary for Python 3.4 compatibility
json_str = response.read().decode("utf-8")
conn.close()
# Parse the JSON response.
try:
json_data = json.loads(json_str)
except ValueError:
print("ERROR: Could not parse JSON for %s. Raw data:" % target_filename)
print(json_str)
return
def file_lookup(name):
if not name.startswith("Input_"):
return "???"
n = int(name[6:])
return filenames[n]
if "serverErrors" in json_data:
errors = json_data["serverErrors"]
for error in errors:
print("SERVER ERROR: %s" % target_filename)
print(error["error"])
elif "errors" in json_data:
errors = json_data["errors"]
for error in errors:
print("FATAL ERROR")
print(error["error"])
if error["file"]:
print("%s at line %d:" % (
file_lookup(error["file"]), error["lineno"]))
print(error["line"])
print((" " * error["charno"]) + "^")
sys.exit(1)
else:
if "warnings" in json_data:
warnings = json_data["warnings"]
for warning in warnings:
print("WARNING")
print(warning["warning"])
if warning["file"]:
print("%s at line %d:" % (
file_lookup(warning["file"]), warning["lineno"]))
print(warning["line"])
print((" " * warning["charno"]) + "^")
print()
if not "compiledCode" in json_data:
print("FATAL ERROR: Compiler did not return compiledCode.")
sys.exit(1)
code = HEADER + "\n" + json_data["compiledCode"]
# Remove Blockly definitions to be compatible with Blockly.
code = re.sub(remove, "", code)
code = self.trim_licence(code)
stats = json_data["statistics"]
original_b = stats["originalSize"]
compressed_b = stats["compressedSize"]
if original_b > 0 and compressed_b > 0:
f = open(target_filename, "w")
f.write(code)
f.close()
original_kb = int(original_b / 1024 + 0.5)
compressed_kb = int(compressed_b / 1024 + 0.5)
ratio = int(float(compressed_b) / float(original_b) * 100 + 0.5)
print("SUCCESS: " + target_filename)
print("Size changed from %d KB to %d KB (%d%%)." % (
original_kb, compressed_kb, ratio))
else:
print("UNKNOWN ERROR")
def trim_licence(self, code):
"""Strip out Google's and MIT's Apache licences.
JS Compiler preserves dozens of Apache licences in the Blockly code.
Remove these if they belong to Google or MIT.
MIT's permission to do this is logged in Blockly issue 2412.
Args:
code: Large blob of compiled source code.
Returns:
Code with Google's and MIT's Apache licences trimmed.
"""
apache2 = re.compile("""/\\*
(Copyright \\d+ (Google LLC|Massachusetts Institute of Technology))
( All rights reserved.
)? SPDX-License-Identifier: Apache-2.0
\\*/""")
return re.sub(apache2, "", code)
class Gen_langfiles(threading.Thread):
"""Generate JavaScript file for each natural language supported.
Runs in a separate thread.
"""
def __init__(self):
threading.Thread.__init__(self)
def run(self):
# The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js.
try:
subprocess.check_call([
"python",
os.path.join("scripts", "i18n", "js_to_json.py"),
"--input_file", "msg/messages.js",
"--output_dir", "msg/json/",
"--quiet"])
except (subprocess.CalledProcessError, OSError) as e:
# Documentation for subprocess.check_call says that CalledProcessError
# will be raised on failure, but I found that OSError is also possible.
print("Error running scripts/i18n/js_to_json.py: ", e)
sys.exit(1)
# Checking whether it is necessary to rebuild the js files would be a lot of
# work since we would have to compare each <lang>.json file with each
# <lang>.js file. Rebuilding is easy and cheap, so just go ahead and do it.
try:
# Use create_messages.py to create .js files from .json files.
cmd = [
"python",
os.path.join("scripts", "i18n", "create_messages.py"),
"--source_lang_file", os.path.join("msg", "json", "en.json"),
"--source_synonym_file", os.path.join("msg", "json", "synonyms.json"),
"--source_constants_file", os.path.join("msg", "json", "constants.json"),
"--key_file", os.path.join("msg", "json", "keys.json"),
"--output_dir", os.path.join("msg", "js"),
"--quiet"]
json_files = glob.glob(os.path.join("msg", "json", "*.json"))
json_files = [file for file in json_files if not
(file.endswith(("keys.json", "synonyms.json", "qqq.json", "constants.json")))]
cmd.extend(json_files)
subprocess.check_call(cmd)
except (subprocess.CalledProcessError, OSError) as e:
print("Error running scripts/i18n/create_messages.py: ", e)
sys.exit(1)
# Output list of .js files created.
for f in json_files:
# This assumes the path to the current directory does not contain "json".
f = f.replace("json", "js")
if os.path.isfile(f):
print("SUCCESS: " + f)
else:
print("FAILED to create " + f)
# Class to hold arguments if user passes in old argument style.
class Arguments:
def __init__(self):
self.core = False
self.generators = False
self.langfiles = False
# Gets the command line arguments.
def get_args():
parser = argparse.ArgumentParser(description="Decide which files to build.")
parser.add_argument('-core', action="store_true", default=False, help="Build core")
parser.add_argument('-generators', action="store_true", default=False, help="Build the generators")
parser.add_argument('-langfiles', action="store_true", default=False, help="Build all the language files")
# New argument style: ./build.py -core
# Old argument style: ./build.py core
# Changed as of July 2019.
try:
args = parser.parse_args()
if (not args.core) and (not args.generators) and (not args.langfiles):
# No arguments, use these defaults:
args.core = True
args.generators = True
args.langfiles = True
except SystemExit:
# Fall back to old argument style.
args = Arguments()
args.core = 'core' in sys.argv
args.generators = 'generators' in sys.argv
args.langfiles = 'langfiles' in sys.argv
if 'accessible' in sys.argv:
print("The Blockly accessibility demo has moved to https://github.com/google/blockly-experimental")
return args
if __name__ == "__main__":
args = get_args()
calcdeps = import_path(os.path.join("closure", "bin", "calcdeps.py"))
full_search_paths = calcdeps.ExpandDirectories(["core", "closure"])
full_search_paths = sorted(full_search_paths) # Deterministic build.
print("Deprecation Warning: (July 2020)\n This build script has been " +
"deprecated, please use 'npm run build' instead. \n The script will be " +
"removed from Blockly core in Q4 of 2020.\n")
# Uncompressed and compressed are run in parallel threads.
# Uncompressed is limited by processor speed.
if (args.core):
Gen_uncompressed(full_search_paths, 'blockly_uncompressed.js').start()
# Compressed is limited by network and server speed.
Gen_compressed(full_search_paths, args).start()
# This is run locally in a separate thread
if (args.langfiles):
Gen_langfiles().start()

View File

@@ -575,20 +575,21 @@ Blockly.Block.prototype.getConnections_ = function(_all) {
/**
* Walks down a stack of blocks and finds the last next connection on the stack.
* @param {boolean} ignoreShadows If true,the last connection on a non-shadow
* block will be returned. If false, this will follow shadows to find the
* last connection.
* @return {?Blockly.Connection} The last next connection on the stack, or null.
* @package
*/
Blockly.Block.prototype.lastConnectionInStack = function() {
Blockly.Block.prototype.lastConnectionInStack = function(ignoreShadows) {
var nextConnection = this.nextConnection;
while (nextConnection) {
var nextBlock = nextConnection.targetBlock();
if (!nextBlock) {
// Found a next connection with nothing on the other side.
if (!nextBlock || (ignoreShadows && nextBlock.isShadow())) {
return nextConnection;
}
nextConnection = nextBlock.nextConnection;
}
// Ran out of next connections.
return null;
};
@@ -607,7 +608,6 @@ Blockly.Block.prototype.bumpNeighbours = function() {
* @return {?Blockly.Block} The block (if any) that holds the current block.
*/
Blockly.Block.prototype.getParent = function() {
// Look at the DOM to see if we are nested in another block.
return this.parentBlock_;
};
@@ -1024,9 +1024,15 @@ Blockly.Block.prototype.setOnChange = function(onchangeFn) {
* @return {?Blockly.Field} Named field, or null if field does not exist.
*/
Blockly.Block.prototype.getField = function(name) {
if (typeof name !== 'string') {
throw TypeError('Blockly.Block.prototype.getField expects a string ' +
'with the field name but received ' +
(name === undefined ? 'nothing' : name + ' of type ' + typeof name) +
' instead');
}
for (var i = 0, input; (input = this.inputList[i]); i++) {
for (var j = 0, field; (field = input.fieldRow[j]); j++) {
if (field.name == name) {
if (field.name === name) {
return field;
}
}
@@ -1124,7 +1130,7 @@ Blockly.Block.prototype.getFieldValue = function(name) {
/**
* Sets the value of the given field for this block.
* @param {*} newValue The value to set.
* @param {!string} name The name of the field to set the value of.
* @param {string} name The name of the field to set the value of.
*/
Blockly.Block.prototype.setFieldValue = function(newValue, name) {
var field = this.getField(name);

View File

@@ -1475,14 +1475,18 @@ Blockly.BlockSvg.prototype.getConnections_ = function(all) {
/**
* Walks down a stack of blocks and finds the last next connection on the stack.
* @param {boolean} ignoreShadows If true,the last connection on a non-shadow
* block will be returned. If false, this will follow shadows to find the
* last connection.
* @return {?Blockly.RenderedConnection} The last next connection on the stack,
* or null.
* @package
* @override
*/
Blockly.BlockSvg.prototype.lastConnectionInStack = function() {
Blockly.BlockSvg.prototype.lastConnectionInStack = function(ignoreShadows) {
return /** @type {Blockly.RenderedConnection} */ (
Blockly.BlockSvg.superClass_.lastConnectionInStack.call(this));
Blockly.BlockSvg.superClass_
.lastConnectionInStack.call(this, ignoreShadows));
};
/**

View File

@@ -61,10 +61,11 @@ goog.requireType('Blockly.Workspace');
/**
* Blockly core version.
* This constant is overridden by the build script (build.py) to the value of the version
* in package.json. This is done during the gen_core build step.
* For local builds, you can pass --define='Blockly.VERSION=X.Y.Z' to the compiler
* to override this constant.
* This constant is overridden by the build script (npm run build) to the value
* of the version in package.json. This is done by the Closure Compiler in the
* buildCompressed gulp task.
* For local builds, you can pass --define='Blockly.VERSION=X.Y.Z' to the
* compiler to override this constant.
* @define {string}
*/
Blockly.VERSION = 'uncompiled';

View File

@@ -104,106 +104,58 @@ Blockly.Connection.prototype.y = 0;
* @protected
*/
Blockly.Connection.prototype.connect_ = function(childConnection) {
var INPUT = Blockly.connectionTypes.INPUT_VALUE;
var parentConnection = this;
var parentBlock = parentConnection.getSourceBlock();
var childBlock = childConnection.getSourceBlock();
// Disconnect any existing parent on the child connection.
// Make sure the childConnection is available.
if (childConnection.isConnected()) {
childConnection.disconnect();
}
// Make sure the parentConnection is available.
var orphan;
if (parentConnection.isConnected()) {
// Other connection is already connected to something.
// Disconnect it and reattach it or bump it as needed.
var orphanBlock = parentConnection.targetBlock();
var shadowDom = parentConnection.getShadowDom();
// Temporarily set the shadow DOM to null so it does not respawn.
parentConnection.shadowDom_ = null;
// Displaced shadow blocks dissolve rather than reattaching or bumping.
if (orphanBlock.isShadow()) {
// Save the shadow block so that field values are preserved.
// This cast assumes that a block can not be both a shadow block and an insertion marker.
shadowDom = /** @type {!Element} */ (Blockly.Xml.blockToDom(orphanBlock));
orphanBlock.dispose(false);
orphanBlock = null;
} else if (parentConnection.type == Blockly.connectionTypes.INPUT_VALUE) {
// Value connections.
// If female block is already connected, disconnect and bump the male.
if (!orphanBlock.outputConnection) {
throw Error('Orphan block does not have an output connection.');
}
// Attempt to reattach the orphan at the end of the newly inserted
// block. Since this block may be a row, walk down to the end
// or to the first (and only) shadow block.
var connection = Blockly.Connection.getConnectionForOrphanedOutput(
childBlock, orphanBlock);
if (connection) {
orphanBlock.outputConnection.connect(connection);
orphanBlock = null;
}
} else if (
parentConnection.type == Blockly.connectionTypes.NEXT_STATEMENT) {
// Statement connections.
// Statement blocks may be inserted into the middle of a stack.
// Split the stack.
if (!orphanBlock.previousConnection) {
throw Error('Orphan block does not have a previous connection.');
}
// Attempt to reattach the orphan at the bottom of the newly inserted
// block. Since this block may be a stack, walk down to the end.
var newBlock = childBlock;
while (newBlock.nextConnection) {
var nextBlock = newBlock.getNextBlock();
if (nextBlock && !nextBlock.isShadow()) {
newBlock = nextBlock;
} else {
var checker = orphanBlock.workspace.connectionChecker;
if (checker.canConnect(
orphanBlock.previousConnection, newBlock.nextConnection, false)) {
newBlock.nextConnection.connect(orphanBlock.previousConnection);
orphanBlock = null;
}
break;
}
}
}
if (orphanBlock) {
// Unable to reattach orphan.
var shadowDom = parentConnection.getShadowDom(true);
parentConnection.shadowDom_ = null; // Set to null so it doesn't respawn.
var target = parentConnection.targetBlock();
if (target.isShadow()) {
target.dispose(false);
} else {
parentConnection.disconnect();
if (Blockly.Events.recordUndo) {
// Bump it off to the side after a moment.
var group = Blockly.Events.getGroup();
setTimeout(function() {
// Verify orphan hasn't been deleted or reconnected.
if (orphanBlock.workspace && !orphanBlock.getParent()) {
Blockly.Events.setGroup(group);
if (orphanBlock.outputConnection) {
orphanBlock.outputConnection.onFailedConnect(parentConnection);
} else if (orphanBlock.previousConnection) {
orphanBlock.previousConnection.onFailedConnect(parentConnection);
}
Blockly.Events.setGroup(false);
}
}, Blockly.BUMP_DELAY);
}
orphan = target;
}
// Restore the shadow DOM.
parentConnection.shadowDom_ = shadowDom;
}
// Connect the new connection to the parent.
var event;
if (Blockly.Events.isEnabled()) {
event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(childBlock);
}
// Establish the connections.
Blockly.Connection.connectReciprocally_(parentConnection, childConnection);
// Demote the inferior block so that one is a child of the superior one.
childBlock.setParent(parentBlock);
if (event) {
event.recordNew();
Blockly.Events.fire(event);
}
// Deal with the orphan if it exists.
if (orphan) {
var orphanConnection = parentConnection.type === INPUT ?
orphan.outputConnection : orphan.previousConnection;
var connection = Blockly.Connection.getConnectionForOrphanedConnection(
childBlock, /** @type {!Blockly.Connection} */ (orphanConnection));
if (connection) {
orphanConnection.connect(connection);
} else {
orphanConnection.onFailedConnect(parentConnection);
}
}
};
/**
* Dispose of this connection and deal with connected blocks.
* @package
@@ -318,7 +270,8 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) {
};
/**
* Behavior after a connection attempt fails.
* Called when an attempted connection fails. NOP by default (i.e. for headless
* workspaces).
* @param {!Blockly.Connection} _otherConnection Connection that this connection
* failed to connect to.
* @package
@@ -409,9 +362,9 @@ Blockly.Connection.getSingleConnection_ = function(block, orphanBlock) {
* @param {!Blockly.Block} orphanBlock The block that is looking for a home.
* @return {?Blockly.Connection} The suitable connection point on the chain
* of blocks, or null.
* @package
* @private
*/
Blockly.Connection.getConnectionForOrphanedOutput =
Blockly.Connection.getConnectionForOrphanedOutput_ =
function(startBlock, orphanBlock) {
var newBlock = startBlock;
var connection;
@@ -425,6 +378,32 @@ Blockly.Connection.getConnectionForOrphanedOutput =
return null;
};
/**
* Returns the connection (starting at the startBlock) which will accept
* the given connection. This includes compatible connection types and
* connection checks.
* @param {!Blockly.Block} startBlock The block on which to start the search.
* @param {!Blockly.Connection} orphanConnection The connection that is looking
* for a home.
* @return {?Blockly.Connection} The suitable connection point on the chain of
* blocks, or null.
*/
Blockly.Connection.getConnectionForOrphanedConnection =
function(startBlock, orphanConnection) {
if (orphanConnection.type === Blockly.connectionTypes.OUTPUT_VALUE) {
return Blockly.Connection.getConnectionForOrphanedOutput_(
startBlock, orphanConnection.getSourceBlock());
}
// Otherwise we're dealing with a stack.
var connection = startBlock.lastConnectionInStack(true);
var checker = orphanConnection.getConnectionChecker();
if (connection &&
checker.canConnect(orphanConnection, connection, false)) {
return connection;
}
return null;
};
/**
* Disconnect this connection.
*/
@@ -614,11 +593,18 @@ Blockly.Connection.prototype.setShadowDom = function(shadow) {
};
/**
* Returns the XML representation of the connection's shadow block.
* Returns the xml representation of the connection's shadow block.
* @param {boolean=} returnCurrent If true, and the shadow block is currently
* attached to this connection, this serializes the state of that block
* and returns it (so that field values are correct). Otherwise the saved
* shadowDom is just returned.
* @return {?Element} Shadow DOM representation of a block or null.
*/
Blockly.Connection.prototype.getShadowDom = function() {
return this.shadowDom_;
Blockly.Connection.prototype.getShadowDom = function(returnCurrent) {
return (returnCurrent && this.targetBlock().isShadow()) ?
/** @type {!Element} */ (Blockly.Xml.blockToDom(
/** @type {!Blockly.Block} */ (this.targetBlock()))) :
this.shadowDom_;
};
/**

View File

@@ -397,14 +397,12 @@ Blockly.ContextMenuItems.registerCollapseExpandBlock = function() {
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
var collapseExpandOption = {
displayText: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
if (scope.block.isCollapsed()) {
return Blockly.Msg['EXPAND_BLOCK'];
}
return Blockly.Msg['COLLAPSE_BLOCK'];
return scope.block.isCollapsed() ?
Blockly.Msg['EXPAND_BLOCK'] : Blockly.Msg['COLLAPSE_BLOCK'];
},
preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
var block = scope.block;
if (!block.isInFlyout && block.isMovable()) {
if (!block.isInFlyout && block.isMovable() && block.workspace.options.collapse) {
return 'enabled';
}
return 'hidden';

View File

@@ -77,15 +77,22 @@ Blockly.FieldAngle = function(opt_value, opt_validator, opt_config) {
Blockly.FieldAngle.superClass_.constructor.call(
this, opt_value, opt_validator, opt_config);
/**
* The angle picker's SVG element.
* @type {?SVGElement}
* @private
*/
this.editor_ = null;
/**
* The angle picker's gauge path depending on the value.
* @type {SVGElement}
* @type {?SVGElement}
*/
this.gauge_ = null;
/**
* The angle picker's line drawn representing the value's angle.
* @type {SVGElement}
* @type {?SVGElement}
*/
this.line_ = null;
@@ -271,8 +278,8 @@ Blockly.FieldAngle.prototype.showEditor_ = function(opt_e) {
Blockly.utils.userAgent.IPAD;
Blockly.FieldAngle.superClass_.showEditor_.call(this, opt_e, noFocus);
var editor = this.dropdownCreate_();
Blockly.DropDownDiv.getContentDiv().appendChild(editor);
this.dropdownCreate_();
Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_);
Blockly.DropDownDiv.setColour(this.sourceBlock_.style.colourPrimary,
this.sourceBlock_.style.colourTertiary);
@@ -285,7 +292,6 @@ Blockly.FieldAngle.prototype.showEditor_ = function(opt_e) {
/**
* Create the angle dropdown editor.
* @return {!SVGElement} The newly created angle picker.
* @private
*/
Blockly.FieldAngle.prototype.dropdownCreate_ = function() {
@@ -343,7 +349,7 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() {
circle, 'click', this, this.onMouseMove_, true, true);
this.moveSurfaceWrapper_ = Blockly.browserEvents.conditionalBind(
circle, 'mousemove', this, this.onMouseMove_, true, true);
return svg;
this.editor_ = svg;
};
/**

View File

@@ -47,7 +47,7 @@ Blockly.FieldColour = function(opt_value, opt_validator, opt_config) {
/**
* The field's colour picker element.
* @type {Element}
* @type {?Element}
* @private
*/
this.picker_ = null;
@@ -321,7 +321,7 @@ Blockly.FieldColour.prototype.setColumns = function(columns) {
* @protected
*/
Blockly.FieldColour.prototype.showEditor_ = function() {
this.picker_ = this.dropdownCreate_();
this.dropdownCreate_();
Blockly.DropDownDiv.getContentDiv().appendChild(this.picker_);
Blockly.DropDownDiv.showPositionedByField(
@@ -512,7 +512,6 @@ Blockly.FieldColour.prototype.setHighlightedCell_ = function(cell, index) {
/**
* Create a colour picker dropdown editor.
* @return {!Element} The newly created colour picker.
* @private
*/
Blockly.FieldColour.prototype.dropdownCreate_ = function() {
@@ -568,7 +567,7 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() {
this.onKeyDownWrapper_ = Blockly.browserEvents.conditionalBind(
table, 'keydown', this, this.onKeyDown_);
return table;
this.picker_ = table;
};
/**

View File

@@ -95,35 +95,35 @@ Blockly.FieldDropdown = function(menuGenerator, opt_validator, opt_config) {
/**
* A reference to the currently selected menu item.
* @type {Blockly.MenuItem}
* @type {?Blockly.MenuItem}
* @private
*/
this.selectedMenuItem_ = null;
/**
* The dropdown menu.
* @type {Blockly.Menu}
* @type {?Blockly.Menu}
* @protected
*/
this.menu_ = null;
/**
* SVG image element if currently selected option is an image, or null.
* @type {SVGImageElement}
* @type {?SVGImageElement}
* @private
*/
this.imageElement_ = null;
/**
* Tspan based arrow element.
* @type {SVGTSpanElement}
* @type {?SVGTSpanElement}
* @private
*/
this.arrow_ = null;
/**
* SVG based arrow element.
* @type {SVGElement}
* @type {?SVGElement}
* @private
*/
this.svgArrow_ = null;
@@ -288,7 +288,7 @@ Blockly.FieldDropdown.prototype.createSVGArrow_ = function() {
* @protected
*/
Blockly.FieldDropdown.prototype.showEditor_ = function(opt_e) {
this.menu_ = this.dropdownCreate_();
this.dropdownCreate_();
if (opt_e && typeof opt_e.clientX === 'number') {
this.menu_.openingCoords =
new Blockly.utils.Coordinate(opt_e.clientX, opt_e.clientY);
@@ -327,12 +327,12 @@ Blockly.FieldDropdown.prototype.showEditor_ = function(opt_e) {
/**
* Create the dropdown editor.
* @return {!Blockly.Menu} The newly created dropdown menu.
* @private
*/
Blockly.FieldDropdown.prototype.dropdownCreate_ = function() {
var menu = new Blockly.Menu();
menu.setRole(Blockly.utils.aria.Role.LISTBOX);
this.menu_ = menu;
var options = this.getOptions(false);
this.selectedMenuItem_ = null;
@@ -357,8 +357,6 @@ Blockly.FieldDropdown.prototype.dropdownCreate_ = function() {
}
menuItem.onAction(this.handleMenuActionEvent_, this);
}
return menu;
};
/**

View File

@@ -456,7 +456,7 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) {
Blockly.WidgetDiv.hide();
Blockly.DropDownDiv.hideWithoutAnimation();
} else if (e.keyCode == Blockly.utils.KeyCodes.ESC) {
this.htmlInput_.value = this.htmlInput_.defaultValue;
this.setValue(this.htmlInput_.untypedDefaultValue_);
Blockly.WidgetDiv.hide();
Blockly.DropDownDiv.hideWithoutAnimation();
} else if (e.keyCode == Blockly.utils.KeyCodes.TAB) {

View File

@@ -72,7 +72,8 @@ Blockly.Flyout = function(workspaceOptions) {
this.workspace_.setVisible(this.isVisible_);
/**
* The unique id for this component.
* The unique id for this component that is used to register with the
* ComponentManager.
* @type {string}
*/
this.id = Blockly.utils.genUid();

View File

@@ -367,6 +367,7 @@ Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
// Record the height for workspace metrics and .position.
this.height_ = flyoutHeight;
this.position();
this.targetWorkspace.recordDragTargets();
}
};

View File

@@ -375,6 +375,7 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
// Record the width for workspace metrics and .position.
this.width_ = flyoutWidth;
this.position();
this.targetWorkspace.recordDragTargets();
}
};

View File

@@ -331,7 +331,7 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo
Blockly.InsertionMarkerManager.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(true);
if (lastOnStack && lastOnStack != this.topBlock_.nextConnection) {
available.push(lastOnStack);
this.lastOnStack_ = lastOnStack;
@@ -674,7 +674,10 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
}
this.markerConnection_ = null;
imBlock.getSvgRoot().setAttribute('visibility', 'hidden');
var svg = imBlock.getSvgRoot();
if (svg) {
svg.setAttribute('visibility', 'hidden');
}
};
/**

View File

@@ -23,7 +23,8 @@ goog.provide('Blockly.IComponent');
Blockly.IComponent = function() {};
/**
* The unique id for this component.
* The unique id for this component that is used to register with the
* ComponentManager.
* @type {string}
*/
Blockly.IComponent.id;

View File

@@ -30,7 +30,8 @@ Blockly.IDragTarget = function() {};
/**
* Returns the bounding rectangle of the drag target area in pixel units
* relative to viewport.
* @return {Blockly.utils.Rect} The component's bounding box.
* @return {?Blockly.utils.Rect} The component's bounding box. Null if drag
* target area should be ignored.
*/
Blockly.IDragTarget.prototype.getClientRect;

View File

@@ -37,6 +37,7 @@ Blockly.IPositionable.prototype.position;
/**
* Returns the bounding rectangle of the UI element in pixel units relative to
* the Blockly injection div.
* @return {!Blockly.utils.Rect} The UI elementss bounding box.
* @return {?Blockly.utils.Rect} The UI elementss bounding box. Null if
* bounding box should be ignored by other UI elements.
*/
Blockly.IPositionable.prototype.getBoundingRectangle;

View File

@@ -449,14 +449,26 @@ Blockly.RenderedConnection.prototype.isConnectionAllowed = function(candidate,
/**
* Behavior after a connection attempt fails.
* Bumps this connection away from the other connection. Called when an
* attempted connection fails.
* @param {!Blockly.Connection} otherConnection Connection that this connection
* failed to connect to.
* @package
*/
Blockly.RenderedConnection.prototype.onFailedConnect = function(
otherConnection) {
this.bumpAwayFrom(otherConnection);
};
Blockly.RenderedConnection.prototype.onFailedConnect =
function(otherConnection) {
var block = this.getSourceBlock();
if (Blockly.Events.recordUndo) {
var group = Blockly.Events.getGroup();
setTimeout(function() {
if (!block.isDisposed() && !block.getParent()) {
Blockly.Events.setGroup(group);
this.bumpAwayFrom(otherConnection);
Blockly.Events.setGroup(false);
}
}.bind(this), Blockly.BUMP_DELAY);
}
};
/**

View File

@@ -246,23 +246,11 @@ Blockly.blockRendering.Renderer.prototype.shouldHighlightConnection =
*/
Blockly.blockRendering.Renderer.prototype.orphanCanConnectAtEnd =
function(topBlock, orphanBlock, localType) {
var orphanConnection = null;
var lastConnection = null;
if (localType == Blockly.connectionTypes.OUTPUT_VALUE) {
orphanConnection = orphanBlock.outputConnection;
lastConnection =
Blockly.Connection.getConnectionForOrphanedOutput(
/** @type {!Blockly.Block} **/ (topBlock), orphanBlock);
} else {
orphanConnection = orphanBlock.previousConnection;
lastConnection = topBlock.lastConnectionInStack();
}
if (!lastConnection) {
return false;
}
return orphanConnection.getConnectionChecker().canConnect(
lastConnection, orphanConnection, false);
var orphanConnection = localType === Blockly.connectionTypes.OUTPUT_VALUE ?
orphanBlock.outputConnection : orphanBlock.previousConnection;
return !!Blockly.Connection.getConnectionForOrphanedConnection(
/** @type {!Blockly.Block} **/ (topBlock),
/** @type {!Blockly.Connection} **/ (orphanConnection));
};
/**

View File

@@ -82,6 +82,8 @@ goog.require('Blockly.zelos.Renderer');
// Blockly Themes.
// Classic is the default theme.
goog.require('Blockly.Themes.Classic');
goog.require('Blockly.Themes.Dark');
goog.require('Blockly.Themes.Deuteranopia');
goog.require('Blockly.Themes.HighContrast');
goog.require('Blockly.Themes.Tritanopia');
// goog.require('Blockly.Themes.Modern');

View File

@@ -99,7 +99,10 @@ Blockly.ShortcutItems.registerCopy = function() {
Blockly.selected.isDeletable() &&
Blockly.selected.isMovable();
},
callback: function() {
callback: function(workspace, e) {
// Prevent the default copy behavior, which may beep or otherwise indicate
// an error due to the lack of a selection.
e.preventDefault();
Blockly.hideChaff();
Blockly.copy(/** @type {!Blockly.ICopyable} */ (Blockly.selected));
return true;

33
core/theme/dark.js Normal file
View File

@@ -0,0 +1,33 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Dark theme.
* @author samelh@google.com (Sam El-Husseini)
*/
'use strict';
goog.provide('Blockly.Themes.Dark');
goog.require('Blockly.Theme');
Blockly.Themes.Dark = Blockly.Theme.defineTheme('dark', {
'base': Blockly.Themes.Classic,
'componentStyles': {
'workspaceBackgroundColour': '#1e1e1e',
'toolboxBackgroundColour': 'blackBackground',
'toolboxForegroundColour': '#fff',
'flyoutBackgroundColour': '#252526',
'flyoutForegroundColour': '#ccc',
'flyoutOpacity': 1,
'scrollbarColour': '#797979',
'insertionMarkerColour': '#fff',
'insertionMarkerOpacity': 0.3,
'scrollbarOpacity': 0.4,
'cursorColour': '#d0d0d0',
'blackBackground': '#333'
}
});

108
core/theme/modern.js Normal file
View File

@@ -0,0 +1,108 @@
/**
* @license
* Copyright 2018 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Modern theme.
* Same colours as classic, but single coloured border.
*/
'use strict';
goog.provide('Blockly.Themes.Modern');
goog.require('Blockly.Theme');
// Temporary holding object.
Blockly.Themes.Modern = {};
Blockly.Themes.Modern.defaultBlockStyles = {
"colour_blocks": {
"colourPrimary": "#a5745b",
"colourSecondary": "#dbc7bd",
"colourTertiary": "#845d49"
},
"list_blocks": {
"colourPrimary": "#745ba5",
"colourSecondary": "#c7bddb",
"colourTertiary": "#5d4984"
},
"logic_blocks": {
"colourPrimary": "#5b80a5",
"colourSecondary": "#bdccdb",
"colourTertiary": "#496684"
},
"loop_blocks": {
"colourPrimary": "#5ba55b",
"colourSecondary": "#bddbbd",
"colourTertiary": "#498449"
},
"math_blocks": {
"colourPrimary": "#5b67a5",
"colourSecondary": "#bdc2db",
"colourTertiary": "#495284"
},
"procedure_blocks": {
"colourPrimary": "#995ba5",
"colourSecondary": "#d6bddb",
"colourTertiary": "#7a4984"
},
"text_blocks": {
"colourPrimary": "#5ba58c",
"colourSecondary": "#bddbd1",
"colourTertiary": "#498470"
},
"variable_blocks": {
"colourPrimary": "#a55b99",
"colourSecondary": "#dbbdd6",
"colourTertiary": "#84497a"
},
"variable_dynamic_blocks": {
"colourPrimary": "#a55b99",
"colourSecondary": "#dbbdd6",
"colourTertiary": "#84497a"
},
"hat_blocks": {
"colourPrimary": "#a55b99",
"colourSecondary": "#dbbdd6",
"colourTertiary": "#84497a",
"hat": "cap"
}
};
Blockly.Themes.Modern.categoryStyles = {
"colour_category": {
"colour": "#a5745b"
},
"list_category": {
"colour": "#745ba5"
},
"logic_category": {
"colour": "#5b80a5"
},
"loop_category": {
"colour": "#5ba55b"
},
"math_category": {
"colour": "#5b67a5"
},
"procedure_category": {
"colour": "#995ba5"
},
"text_category": {
"colour": "#5ba58c"
},
"variable_category": {
"colour": "#a55b99"
},
"variable_dynamic_category": {
"colour": "#a55b99"
}
};
// This style is still being fleshed out and may change.
Blockly.Themes.Modern =
new Blockly.Theme('modern', Blockly.Themes.Modern.defaultBlockStyles,
Blockly.Themes.Modern.categoryStyles);

View File

@@ -67,10 +67,11 @@ Blockly.Toolbox = function(workspace) {
this.workspace_ = workspace;
/**
* The unique id for this component.
* The unique id for this component that is used to register with the
* ComponentManager.
* @type {string}
*/
this.id = Blockly.utils.genUid();
this.id = 'toolbox';
/**
* The JSON describing the contents of this toolbox.
@@ -99,6 +100,13 @@ Blockly.Toolbox = function(workspace) {
*/
this.contentsDiv_ = null;
/**
* Whether the Toolbox is visible.
* @type {boolean}
* @protected
*/
this.isVisible_ = false;
/**
* The list of items in the toolbox.
* @type {!Array<!Blockly.IToolboxItem>}
@@ -193,6 +201,7 @@ Blockly.Toolbox.prototype.init = function() {
this.HtmlDiv = this.createDom_(this.workspace_);
Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), svg);
this.setVisible(true);
this.flyout_.init(workspace);
this.render(this.toolboxDef_);
@@ -407,6 +416,7 @@ Blockly.Toolbox.prototype.render = function(toolboxDef) {
this.contentMap_ = Object.create(null);
this.renderContents_(toolboxDef['contents']);
this.position();
this.handleToolboxItemResize();
};
/**
@@ -513,7 +523,7 @@ Blockly.Toolbox.prototype.removeStyle = function(style) {
* target area should be ignored.
*/
Blockly.Toolbox.prototype.getClientRect = function() {
if (!this.HtmlDiv) {
if (!this.HtmlDiv || !this.isVisible_) {
return null;
}
@@ -809,7 +819,15 @@ Blockly.Toolbox.prototype.refreshSelection = function() {
* @public
*/
Blockly.Toolbox.prototype.setVisible = function(isVisible) {
if (this.isVisible_ === isVisible) {
return;
}
this.HtmlDiv.style.display = isVisible ? 'block' : 'none';
this.isVisible_ = isVisible;
// Invisible toolbox is ignored as drag targets and must have the drag target
// updated.
this.workspace_.recordDragTargets();
};
/**

View File

@@ -57,10 +57,11 @@ Blockly.Trashcan = function(workspace) {
this.workspace_ = workspace;
/**
* The unique id for this component.
* The unique id for this component that is used to register with the
* ComponentManager.
* @type {string}
*/
this.id = Blockly.utils.genUid();
this.id = 'trashcan';
/**
* A list of XML (stored as strings) representing blocks in the trashcan.
@@ -506,7 +507,8 @@ Blockly.Trashcan.prototype.position = function(metrics, savedPositions) {
/**
* Returns the bounding rectangle of the UI element in pixel units relative to
* the Blockly injection div.
* @return {!Blockly.utils.Rect} The UI elementss bounding box.
* @return {?Blockly.utils.Rect} The UI elementss bounding box. Null if
* bounding box should be ignored by other UI elements.
*/
Blockly.Trashcan.prototype.getBoundingRectangle = function() {
var bottom = this.top_ + this.BODY_HEIGHT_ + this.LID_HEIGHT_;

View File

@@ -93,9 +93,13 @@ Blockly.utils.userAgent.MOBILE;
!Blockly.utils.userAgent.EDGE;
// Platforms. Logic from:
// https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js
// https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js and
// https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/extra.js
Blockly.utils.userAgent.ANDROID = has('Android');
Blockly.utils.userAgent.IPAD = has('iPad');
var maxTouchPoints = Blockly.utils.global['navigator'] &&
Blockly.utils.global['navigator']['maxTouchPoints'];
Blockly.utils.userAgent.IPAD = has('iPad') ||
has('Macintosh') && maxTouchPoints > 0;
Blockly.utils.userAgent.IPOD = has('iPod');
Blockly.utils.userAgent.IPHONE = has('iPhone') &&
!Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD;

View File

@@ -1148,7 +1148,10 @@ Blockly.WorkspaceSvg.prototype.resize = function() {
var savedPositions = [];
for (var i = 0, positionable; (positionable = positionables[i]); i++) {
positionable.position(metrics, savedPositions);
savedPositions.push(positionable.getBoundingRectangle());
var boundingRect = positionable.getBoundingRectangle();
if (boundingRect) {
savedPositions.push(boundingRect);
}
}
if (this.scrollbar) {

View File

@@ -45,10 +45,11 @@ Blockly.ZoomControls = function(workspace) {
this.workspace_ = workspace;
/**
* The unique id for this component.
* The unique id for this component that is used to register with the
* ComponentManager.
* @type {string}
*/
this.id = Blockly.utils.genUid();
this.id = 'zoomControls';
/**
* A handle to use to unbind the mouse down event handler for zoom reset
@@ -228,7 +229,8 @@ Blockly.ZoomControls.prototype.dispose = function() {
/**
* Returns the bounding rectangle of the UI element in pixel units relative to
* the Blockly injection div.
* @return {!Blockly.utils.Rect} The UI elementss bounding box.
* @return {?Blockly.utils.Rect} The UI elementss bounding box. Null if
* bounding box should be ignored by other UI elements.
*/
Blockly.ZoomControls.prototype.getBoundingRectangle = function() {
var height = this.SMALL_SPACING_ + 2 * this.HEIGHT_;

434
msg/js/bs.js Normal file
View File

@@ -0,0 +1,434 @@
// This file was automatically generated. Do not modify.
'use strict';
Blockly.Msg["ADD_COMMENT"] = "Dodaj komentar";
Blockly.Msg["CANNOT_DELETE_VARIABLE_PROCEDURE"] = "Ne mogu izbrisati varijablu \"%1\" jer je dio definicije funckije \"%2\"";
Blockly.Msg["CHANGE_VALUE_TITLE"] = "Promijeni vrijednost:";
Blockly.Msg["CLEAN_UP"] = "Očisti blokove";
Blockly.Msg["COLLAPSED_WARNINGS_WARNING"] = "Collapsed blocks contain warnings."; // untranslated
Blockly.Msg["COLLAPSE_ALL"] = "Skupi blokove";
Blockly.Msg["COLLAPSE_BLOCK"] = "Skupi blok";
Blockly.Msg["COLOUR_BLEND_COLOUR1"] = "boju 1";
Blockly.Msg["COLOUR_BLEND_COLOUR2"] = "boju 2";
Blockly.Msg["COLOUR_BLEND_HELPURL"] = "https://meyerweb.com/eric/tools/color-blend/#:::rgbp"; // untranslated
Blockly.Msg["COLOUR_BLEND_RATIO"] = "odnos";
Blockly.Msg["COLOUR_BLEND_TITLE"] = "pomiješaj";
Blockly.Msg["COLOUR_BLEND_TOOLTIP"] = "Pomiješaj dvije boje zajedno sa zadanim odnosom (0.0 - 1.0).";
Blockly.Msg["COLOUR_PICKER_HELPURL"] = "https://bs.wikipedia.org/wiki/Boja";
Blockly.Msg["COLOUR_PICKER_TOOLTIP"] = "Izaberi boju sa palete.";
Blockly.Msg["COLOUR_RANDOM_HELPURL"] = "http://randomcolour.com"; // untranslated
Blockly.Msg["COLOUR_RANDOM_TITLE"] = "nasumična boja";
Blockly.Msg["COLOUR_RANDOM_TOOLTIP"] = "Odaberi boju nasumično.";
Blockly.Msg["COLOUR_RGB_BLUE"] = "plavom";
Blockly.Msg["COLOUR_RGB_GREEN"] = "zelenom";
Blockly.Msg["COLOUR_RGB_HELPURL"] = "https://www.december.com/html/spec/colorpercompact.html"; // untranslated
Blockly.Msg["COLOUR_RGB_RED"] = "crvenom";
Blockly.Msg["COLOUR_RGB_TITLE"] = "boja sa";
Blockly.Msg["COLOUR_RGB_TOOLTIP"] = "Napravi boju s određenom količinom crvene, zelene i plave boje. Sve vrijednosti moraju biti između 0 i 100.";
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#loop-termination-blocks"; // untranslated
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK"] = "izađi iz petlje";
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE"] = "nastavi sa sljedećom iteracijom petlje";
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK"] = "Napusti petlju koja sadrži ovaj blok.";
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE"] = "Preskoči ostatak ove petlje i nastavi sa sljedećom iteracijom.";
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_WARNING"] = "Upozorenje: Ovaj blok se može koristiti samo unutar petlje.";
Blockly.Msg["CONTROLS_FOREACH_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#for-each"; // untranslated
Blockly.Msg["CONTROLS_FOREACH_TITLE"] = "za svaku stavku %1 na spisku %2";
Blockly.Msg["CONTROLS_FOREACH_TOOLTIP"] = "Za svaku stavku na spisku, dodjeljuje vrijednost stavke varijabli \"%1\", a zatim izvršava neke naredbe.";
Blockly.Msg["CONTROLS_FOR_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#count-with"; // untranslated
Blockly.Msg["CONTROLS_FOR_TITLE"] = "broji sa %1 od %2 do %3 po %4";
Blockly.Msg["CONTROLS_FOR_TOOLTIP"] = "Neka varijabla \"%1\" uzima vrijednosti od početnog do krajnjeg broja, brojeći po određenom intervalu i neka izvršava određene blokove.";
Blockly.Msg["CONTROLS_IF_ELSEIF_TOOLTIP"] = "Dodajte uslov bloku \"ako\".";
Blockly.Msg["CONTROLS_IF_ELSE_TOOLTIP"] = "Add a final, catch-all condition to the if block."; // untranslated
Blockly.Msg["CONTROLS_IF_HELPURL"] = "https://github.com/google/blockly/wiki/IfElse"; // untranslated
Blockly.Msg["CONTROLS_IF_IF_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this if block."; // untranslated
Blockly.Msg["CONTROLS_IF_MSG_ELSE"] = "inače";
Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"] = "inače ako";
Blockly.Msg["CONTROLS_IF_MSG_IF"] = "ako";
Blockly.Msg["CONTROLS_IF_TOOLTIP_1"] = "Ako je vrijednost tačna, izvršava neke naredbe.";
Blockly.Msg["CONTROLS_IF_TOOLTIP_2"] = "Ako je vrijednost tačna, izvršava neke naredbe. U suprotnom, izvršava drugi blok naredbi.";
Blockly.Msg["CONTROLS_IF_TOOLTIP_3"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements."; // untranslated
Blockly.Msg["CONTROLS_IF_TOOLTIP_4"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements."; // untranslated
Blockly.Msg["CONTROLS_REPEAT_HELPURL"] = "https://en.wikipedia.org/wiki/For_loop"; // untranslated
Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"] = "izvrši";
Blockly.Msg["CONTROLS_REPEAT_TITLE"] = "ponovi %1 puta";
Blockly.Msg["CONTROLS_REPEAT_TOOLTIP"] = "Izvrši neku naredbu nekoliko puta.";
Blockly.Msg["CONTROLS_WHILEUNTIL_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#repeat"; // untranslated
Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_UNTIL"] = "ponavljati do";
Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_WHILE"] = "ponavljati dok";
Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL"] = "Dok je vrijednost netačna, izvršava neke naredbe.";
Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_WHILE"] = "Dok je vrijednost tačna, izvršava neke naredbe.";
Blockly.Msg["DELETE_ALL_BLOCKS"] = "Izbrisati svih %1 blokova?";
Blockly.Msg["DELETE_BLOCK"] = "Obriši blok";
Blockly.Msg["DELETE_VARIABLE"] = "Izbriši varijablu \"%1\"";
Blockly.Msg["DELETE_VARIABLE_CONFIRMATION"] = "Izbrisati %1 upotrebu varijable \"%2\"?";
Blockly.Msg["DELETE_X_BLOCKS"] = "Obriši %1 blokova";
Blockly.Msg["DISABLE_BLOCK"] = "Onemogući blok";
Blockly.Msg["DUPLICATE_BLOCK"] = "Dupliciraj";
Blockly.Msg["DUPLICATE_COMMENT"] = "Kopiraj komentar";
Blockly.Msg["ENABLE_BLOCK"] = "Omogući blok";
Blockly.Msg["EXPAND_ALL"] = "Proširi blokove";
Blockly.Msg["EXPAND_BLOCK"] = "Proširi blok";
Blockly.Msg["EXTERNAL_INPUTS"] = "Vanjski ulazi";
Blockly.Msg["HELP"] = "Pomoć";
Blockly.Msg["INLINE_INPUTS"] = "Redni ulazi";
Blockly.Msg["IOS_CANCEL"] = "Otkaži";
Blockly.Msg["IOS_ERROR"] = "Greška";
Blockly.Msg["IOS_OK"] = "U redu";
Blockly.Msg["IOS_PROCEDURES_ADD_INPUT"] = "+ Dodaj ulaz";
Blockly.Msg["IOS_PROCEDURES_ALLOW_STATEMENTS"] = "Dozvoli naredbe";
Blockly.Msg["IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR"] = "This function has duplicate inputs."; // untranslated
Blockly.Msg["IOS_PROCEDURES_INPUTS"] = "ULAZI";
Blockly.Msg["IOS_VARIABLES_ADD_BUTTON"] = "Dodaj";
Blockly.Msg["IOS_VARIABLES_ADD_VARIABLE"] = "+ Dodaj varijablu";
Blockly.Msg["IOS_VARIABLES_DELETE_BUTTON"] = "Obriši";
Blockly.Msg["IOS_VARIABLES_EMPTY_NAME_ERROR"] = "Ne možete koristiti prazno ime varijable.";
Blockly.Msg["IOS_VARIABLES_RENAME_BUTTON"] = "Preimenuj";
Blockly.Msg["IOS_VARIABLES_VARIABLE_NAME"] = "Ime varijable";
Blockly.Msg["LISTS_CREATE_EMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-empty-list"; // untranslated
Blockly.Msg["LISTS_CREATE_EMPTY_TITLE"] = "create empty list"; // untranslated
Blockly.Msg["LISTS_CREATE_EMPTY_TOOLTIP"] = "Returns a list, of length 0, containing no data records"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TITLE_ADD"] = "list"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this list block."; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_INPUT_WITH"] = "create list with"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_ITEM_TOOLTIP"] = "Add an item to the list."; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_TOOLTIP"] = "Create a list with any number of items."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_FIRST"] = "first"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_FROM_END"] = "# from end"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_FROM_START"] = "#"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_GET"] = "get"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_GET_REMOVE"] = "get and remove"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_LAST"] = "last"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_RANDOM"] = "random"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_REMOVE"] = "remove"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TAIL"] = ""; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FIRST"] = "Returns the first item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FROM"] = "Returns the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_LAST"] = "Returns the last item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_RANDOM"] = "Returns a random item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST"] = "Removes and returns the first item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM"] = "Removes and returns the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST"] = "Removes and returns the last item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM"] = "Removes and returns a random item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST"] = "Removes the first item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM"] = "Removes the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST"] = "Removes the last item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM"] = "Removes a random item in a list."; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_END"] = "to # from end"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_START"] = "to #"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_END_LAST"] = "to last"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-a-sublist"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_START_FIRST"] = "get sub-list from first"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_END"] = "get sub-list from # from end"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_START"] = "get sub-list from #"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_TAIL"] = ""; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_TOOLTIP"] = "Creates a copy of the specified portion of a list."; // untranslated
Blockly.Msg["LISTS_INDEX_FROM_END_TOOLTIP"] = "%1 is the last item."; // untranslated
Blockly.Msg["LISTS_INDEX_FROM_START_TOOLTIP"] = "%1 is the first item."; // untranslated
Blockly.Msg["LISTS_INDEX_OF_FIRST"] = "pronađi prvo pojavljivanje stavke";
Blockly.Msg["LISTS_INDEX_OF_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list"; // untranslated
Blockly.Msg["LISTS_INDEX_OF_LAST"] = "pronađi posljednje pojavljivanje stavke";
Blockly.Msg["LISTS_INDEX_OF_TOOLTIP"] = "Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found."; // untranslated
Blockly.Msg["LISTS_INLIST"] = "na spisku";
Blockly.Msg["LISTS_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#is-empty"; // untranslated
Blockly.Msg["LISTS_ISEMPTY_TITLE"] = "%1 je prazan";
Blockly.Msg["LISTS_ISEMPTY_TOOLTIP"] = "Vraća \"tačno\" ako je spisak prazan.";
Blockly.Msg["LISTS_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#length-of"; // untranslated
Blockly.Msg["LISTS_LENGTH_TITLE"] = "dužina spiska %1";
Blockly.Msg["LISTS_LENGTH_TOOLTIP"] = "Vraća dužinu spiska.";
Blockly.Msg["LISTS_REPEAT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated
Blockly.Msg["LISTS_REPEAT_TITLE"] = "create list with item %1 repeated %2 times"; // untranslated
Blockly.Msg["LISTS_REPEAT_TOOLTIP"] = "Creates a list consisting of the given value repeated the specified number of times."; // untranslated
Blockly.Msg["LISTS_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#reversing-a-list"; // untranslated
Blockly.Msg["LISTS_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated
Blockly.Msg["LISTS_REVERSE_TOOLTIP"] = "Reverse a copy of a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#in-list--set"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_INPUT_TO"] = "as"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_INSERT"] = "insert at"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_SET"] = "set"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST"] = "Inserts the item at the start of a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FROM"] = "Inserts the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_LAST"] = "Append the item to the end of a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM"] = "Inserts the item randomly in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FIRST"] = "Sets the first item in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FROM"] = "Sets the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_LAST"] = "Sets the last item in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_RANDOM"] = "Sets a random item in a list."; // untranslated
Blockly.Msg["LISTS_SORT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#sorting-a-list"; // untranslated
Blockly.Msg["LISTS_SORT_ORDER_ASCENDING"] = "ascending"; // untranslated
Blockly.Msg["LISTS_SORT_ORDER_DESCENDING"] = "descending"; // untranslated
Blockly.Msg["LISTS_SORT_TITLE"] = "sort %1 %2 %3"; // untranslated
Blockly.Msg["LISTS_SORT_TOOLTIP"] = "Sort a copy of a list."; // untranslated
Blockly.Msg["LISTS_SORT_TYPE_IGNORECASE"] = "alphabetic, ignore case"; // untranslated
Blockly.Msg["LISTS_SORT_TYPE_NUMERIC"] = "numeric"; // untranslated
Blockly.Msg["LISTS_SORT_TYPE_TEXT"] = "alphabetic"; // untranslated
Blockly.Msg["LISTS_SPLIT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists"; // untranslated
Blockly.Msg["LISTS_SPLIT_LIST_FROM_TEXT"] = "make list from text"; // untranslated
Blockly.Msg["LISTS_SPLIT_TEXT_FROM_LIST"] = "make text from list"; // untranslated
Blockly.Msg["LISTS_SPLIT_TOOLTIP_JOIN"] = "Join a list of texts into one text, separated by a delimiter."; // untranslated
Blockly.Msg["LISTS_SPLIT_TOOLTIP_SPLIT"] = "Split text into a list of texts, breaking at each delimiter."; // untranslated
Blockly.Msg["LISTS_SPLIT_WITH_DELIMITER"] = "with delimiter"; // untranslated
Blockly.Msg["LOGIC_BOOLEAN_FALSE"] = "netačno";
Blockly.Msg["LOGIC_BOOLEAN_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#values"; // untranslated
Blockly.Msg["LOGIC_BOOLEAN_TOOLTIP"] = "Vraća ili tačno ili netačno.";
Blockly.Msg["LOGIC_BOOLEAN_TRUE"] = "tačno";
Blockly.Msg["LOGIC_COMPARE_HELPURL"] = "https://bs.wikipedia.org/wiki/Nejednakost";
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_EQ"] = "Return true if both inputs equal each other."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GT"] = "Return true if the first input is greater than the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GTE"] = "Return true if the first input is greater than or equal to the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LT"] = "Return true if the first input is smaller than the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LTE"] = "Return true if the first input is smaller than or equal to the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_NEQ"] = "Return true if both inputs are not equal to each other."; // untranslated
Blockly.Msg["LOGIC_NEGATE_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#not"; // untranslated
Blockly.Msg["LOGIC_NEGATE_TITLE"] = "nije %1";
Blockly.Msg["LOGIC_NEGATE_TOOLTIP"] = "Returns true if the input is false. Returns false if the input is true."; // untranslated
Blockly.Msg["LOGIC_NULL"] = "bez vrijednosti";
Blockly.Msg["LOGIC_NULL_HELPURL"] = "https://en.wikipedia.org/wiki/Nullable_type"; // untranslated
Blockly.Msg["LOGIC_NULL_TOOLTIP"] = "Vraća \"bez vrijednosti\".";
Blockly.Msg["LOGIC_OPERATION_AND"] = "i";
Blockly.Msg["LOGIC_OPERATION_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#logical-operations"; // untranslated
Blockly.Msg["LOGIC_OPERATION_OR"] = "ili";
Blockly.Msg["LOGIC_OPERATION_TOOLTIP_AND"] = "Return true if both inputs are true."; // untranslated
Blockly.Msg["LOGIC_OPERATION_TOOLTIP_OR"] = "Return true if at least one of the inputs is true."; // untranslated
Blockly.Msg["LOGIC_TERNARY_CONDITION"] = "test";
Blockly.Msg["LOGIC_TERNARY_HELPURL"] = "https://en.wikipedia.org/wiki/%3F:"; // untranslated
Blockly.Msg["LOGIC_TERNARY_IF_FALSE"] = "ako je netačno";
Blockly.Msg["LOGIC_TERNARY_IF_TRUE"] = "ako je tačno";
Blockly.Msg["LOGIC_TERNARY_TOOLTIP"] = "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value."; // untranslated
Blockly.Msg["MATH_ADDITION_SYMBOL"] = "+"; // untranslated
Blockly.Msg["MATH_ARITHMETIC_HELPURL"] = "https://bs.wikipedia.org/wiki/Aritmetika";
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_ADD"] = "Vraća zbir dva broja.";
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_DIVIDE"] = "Vraća količnik dva broja.";
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MINUS"] = "Vraća razliku dva broja.";
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MULTIPLY"] = "Vraća proizvod dva broja.";
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_POWER"] = "Vraća prvi broj na eksponent drugog broja.";
Blockly.Msg["MATH_ATAN2_HELPURL"] = "https://en.wikipedia.org/wiki/Atan2"; // untranslated
Blockly.Msg["MATH_ATAN2_TITLE"] = "atan2 of X:%1 Y:%2"; // untranslated
Blockly.Msg["MATH_ATAN2_TOOLTIP"] = "Return the arctangent of point (X, Y) in degrees from -180 to 180."; // untranslated
Blockly.Msg["MATH_CHANGE_HELPURL"] = "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter"; // untranslated
Blockly.Msg["MATH_CHANGE_TITLE"] = "promijeni %1 za %2";
Blockly.Msg["MATH_CHANGE_TOOLTIP"] = "Dodaj broj varijabli \"%1\".";
Blockly.Msg["MATH_CONSTANT_HELPURL"] = "https://bs.wikipedia.org/wiki/Matemati%C4%8Dka_konstanta";
Blockly.Msg["MATH_CONSTANT_TOOLTIP"] = "Vraća jednu od uobičajenih konstanti: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…) ili ∞ (beskonačnost).";
Blockly.Msg["MATH_CONSTRAIN_HELPURL"] = "https://en.wikipedia.org/wiki/Clamping_(graphics)"; // untranslated
Blockly.Msg["MATH_CONSTRAIN_TITLE"] = "constrain %1 low %2 high %3"; // untranslated
Blockly.Msg["MATH_CONSTRAIN_TOOLTIP"] = "Constrain a number to be between the specified limits (inclusive)."; // untranslated
Blockly.Msg["MATH_DIVISION_SYMBOL"] = "÷"; // untranslated
Blockly.Msg["MATH_IS_DIVISIBLE_BY"] = "je djeljiv sa";
Blockly.Msg["MATH_IS_EVEN"] = "je paran";
Blockly.Msg["MATH_IS_NEGATIVE"] = "je negativan";
Blockly.Msg["MATH_IS_ODD"] = "je neparan";
Blockly.Msg["MATH_IS_POSITIVE"] = "je pozitivan";
Blockly.Msg["MATH_IS_PRIME"] = "je prost";
Blockly.Msg["MATH_IS_TOOLTIP"] = "Provjerava da li je broj paran, neparan, prost, cijeli, pozitivan, negativan ili je djeljiv s određenim brojem. Vraća tačno ili netačno.";
Blockly.Msg["MATH_IS_WHOLE"] = "je cijeli";
Blockly.Msg["MATH_MODULO_HELPURL"] = "https://en.wikipedia.org/wiki/Modulo_operation"; // untranslated
Blockly.Msg["MATH_MODULO_TITLE"] = "remainder of %1 ÷ %2"; // untranslated
Blockly.Msg["MATH_MODULO_TOOLTIP"] = "Return the remainder from dividing the two numbers."; // untranslated
Blockly.Msg["MATH_MULTIPLICATION_SYMBOL"] = "×"; // untranslated
Blockly.Msg["MATH_NUMBER_HELPURL"] = "https://bs.wikipedia.org/wiki/Broj";
Blockly.Msg["MATH_NUMBER_TOOLTIP"] = "Broj.";
Blockly.Msg["MATH_ONLIST_HELPURL"] = ""; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_AVERAGE"] = "average of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MAX"] = "max of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MEDIAN"] = "median of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MIN"] = "min of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MODE"] = "modes of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_RANDOM"] = "random item of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_STD_DEV"] = "standard deviation of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_SUM"] = "zbir spiska";
Blockly.Msg["MATH_ONLIST_TOOLTIP_AVERAGE"] = "Return the average (arithmetic mean) of the numeric values in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MAX"] = "Return the largest number in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MEDIAN"] = "Return the median number in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MIN"] = "Return the smallest number in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MODE"] = "Return a list of the most common item(s) in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_RANDOM"] = "Return a random element from the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_STD_DEV"] = "Return the standard deviation of the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_SUM"] = "Vraća zbir svih brojeva sa spiska.";
Blockly.Msg["MATH_POWER_SYMBOL"] = "^"; // untranslated
Blockly.Msg["MATH_RANDOM_FLOAT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated
Blockly.Msg["MATH_RANDOM_FLOAT_TITLE_RANDOM"] = "random fraction"; // untranslated
Blockly.Msg["MATH_RANDOM_FLOAT_TOOLTIP"] = "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive)."; // untranslated
Blockly.Msg["MATH_RANDOM_INT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated
Blockly.Msg["MATH_RANDOM_INT_TITLE"] = "random integer from %1 to %2"; // untranslated
Blockly.Msg["MATH_RANDOM_INT_TOOLTIP"] = "Return a random integer between the two specified limits, inclusive."; // untranslated
Blockly.Msg["MATH_ROUND_HELPURL"] = "https://en.wikipedia.org/wiki/Rounding"; // untranslated
Blockly.Msg["MATH_ROUND_OPERATOR_ROUND"] = "zaokruži";
Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDDOWN"] = "zaokruži naniže";
Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDUP"] = "zaokruži naviše";
Blockly.Msg["MATH_ROUND_TOOLTIP"] = "Zaokružuje broj na veću ili manju vrijednost.";
Blockly.Msg["MATH_SINGLE_HELPURL"] = "https://bs.wikipedia.org/wiki/Kvadratni_korijen";
Blockly.Msg["MATH_SINGLE_OP_ABSOLUTE"] = "apsolutno";
Blockly.Msg["MATH_SINGLE_OP_ROOT"] = "kvadratni korijen";
Blockly.Msg["MATH_SINGLE_TOOLTIP_ABS"] = "Vraća absolutnu vrijednost broja.";
Blockly.Msg["MATH_SINGLE_TOOLTIP_EXP"] = "Vraća e na eksponent broja.";
Blockly.Msg["MATH_SINGLE_TOOLTIP_LN"] = "Vraća prirodni logoritam broja.";
Blockly.Msg["MATH_SINGLE_TOOLTIP_LOG10"] = "Vraća logoritam broja za bazu 10.";
Blockly.Msg["MATH_SINGLE_TOOLTIP_NEG"] = "Vraća negaciju broja.";
Blockly.Msg["MATH_SINGLE_TOOLTIP_POW10"] = "Vraća 10 na eksponent broja.";
Blockly.Msg["MATH_SINGLE_TOOLTIP_ROOT"] = "Vraća kvadratni korijen broja";
Blockly.Msg["MATH_SUBTRACTION_SYMBOL"] = "-"; // untranslated
Blockly.Msg["MATH_TRIG_ACOS"] = "acos"; // untranslated
Blockly.Msg["MATH_TRIG_ASIN"] = "asin"; // untranslated
Blockly.Msg["MATH_TRIG_ATAN"] = "atan"; // untranslated
Blockly.Msg["MATH_TRIG_COS"] = "cos"; // untranslated
Blockly.Msg["MATH_TRIG_HELPURL"] = "https://bs.wikipedia.org/wiki/Trigonometrijska_funkcija";
Blockly.Msg["MATH_TRIG_SIN"] = "sin"; // untranslated
Blockly.Msg["MATH_TRIG_TAN"] = "tan"; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_ACOS"] = "Vraća arkuskosinus broja.";
Blockly.Msg["MATH_TRIG_TOOLTIP_ASIN"] = "Vraća arkussinus broja.";
Blockly.Msg["MATH_TRIG_TOOLTIP_ATAN"] = "Vraća arkustangens broja.";
Blockly.Msg["MATH_TRIG_TOOLTIP_COS"] = "Vraća kosinus stepena (ne radijana).";
Blockly.Msg["MATH_TRIG_TOOLTIP_SIN"] = "Vraća sinus stepena (ne radijana).";
Blockly.Msg["MATH_TRIG_TOOLTIP_TAN"] = "Vraća tangens stepena (ne radijana).";
Blockly.Msg["NEW_COLOUR_VARIABLE"] = "Napravi varijablu boje...";
Blockly.Msg["NEW_NUMBER_VARIABLE"] = "Napravi varijablu broja...";
Blockly.Msg["NEW_STRING_VARIABLE"] = "Napravi varijablu niza...";
Blockly.Msg["NEW_VARIABLE"] = "Napravi varijablu...";
Blockly.Msg["NEW_VARIABLE_TITLE"] = "Ime nove varijable:";
Blockly.Msg["NEW_VARIABLE_TYPE_TITLE"] = "Vrsta nove varijable:";
Blockly.Msg["ORDINAL_NUMBER_SUFFIX"] = ""; // untranslated
Blockly.Msg["PROCEDURES_ALLOW_STATEMENTS"] = "allow statements"; // untranslated
Blockly.Msg["PROCEDURES_BEFORE_PARAMS"] = "with:"; // untranslated
Blockly.Msg["PROCEDURES_CALLNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated
Blockly.Msg["PROCEDURES_CALLNORETURN_TOOLTIP"] = "Run the user-defined function '%1'."; // untranslated
Blockly.Msg["PROCEDURES_CALLRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated
Blockly.Msg["PROCEDURES_CALLRETURN_TOOLTIP"] = "Run the user-defined function '%1' and use its output."; // untranslated
Blockly.Msg["PROCEDURES_CALL_BEFORE_PARAMS"] = "with:"; // untranslated
Blockly.Msg["PROCEDURES_CREATE_DO"] = "Create '%1'"; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"] = "Describe this function..."; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_DO"] = ""; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"] = "do something"; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"] = "to"; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_TOOLTIP"] = "Creates a function with no output."; // untranslated
Blockly.Msg["PROCEDURES_DEFRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated
Blockly.Msg["PROCEDURES_DEFRETURN_RETURN"] = "return"; // untranslated
Blockly.Msg["PROCEDURES_DEFRETURN_TOOLTIP"] = "Creates a function with an output."; // untranslated
Blockly.Msg["PROCEDURES_DEF_DUPLICATE_WARNING"] = "Warning: This function has duplicate parameters."; // untranslated
Blockly.Msg["PROCEDURES_HIGHLIGHT_DEF"] = "Highlight function definition"; // untranslated
Blockly.Msg["PROCEDURES_IFRETURN_HELPURL"] = "http://c2.com/cgi/wiki?GuardClause"; // untranslated
Blockly.Msg["PROCEDURES_IFRETURN_TOOLTIP"] = "If a value is true, then return a second value."; // untranslated
Blockly.Msg["PROCEDURES_IFRETURN_WARNING"] = "Warning: This block may be used only within a function definition."; // untranslated
Blockly.Msg["PROCEDURES_MUTATORARG_TITLE"] = "ime ulaza:";
Blockly.Msg["PROCEDURES_MUTATORARG_TOOLTIP"] = "Add an input to the function."; // untranslated
Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TITLE"] = "inputs"; // untranslated
Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TOOLTIP"] = "Add, remove, or reorder inputs to this function."; // untranslated
Blockly.Msg["REDO"] = "Ponovi";
Blockly.Msg["REMOVE_COMMENT"] = "Ukloni komentare";
Blockly.Msg["RENAME_VARIABLE"] = "Preimenuj varijablu...";
Blockly.Msg["RENAME_VARIABLE_TITLE"] = "Preimenuj sve \"%1\" varijable u:";
Blockly.Msg["TEXT_APPEND_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated
Blockly.Msg["TEXT_APPEND_TITLE"] = "to %1 append text %2"; // untranslated
Blockly.Msg["TEXT_APPEND_TOOLTIP"] = "Append some text to variable '%1'."; // untranslated
Blockly.Msg["TEXT_CHANGECASE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#adjusting-text-case"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_LOWERCASE"] = "to lower case"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_TITLECASE"] = "to Title Case"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_UPPERCASE"] = "to UPPER CASE"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_TOOLTIP"] = "Return a copy of the text in a different case."; // untranslated
Blockly.Msg["TEXT_CHARAT_FIRST"] = "get first letter"; // untranslated
Blockly.Msg["TEXT_CHARAT_FROM_END"] = "get letter # from end"; // untranslated
Blockly.Msg["TEXT_CHARAT_FROM_START"] = "get letter #"; // untranslated
Blockly.Msg["TEXT_CHARAT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-text"; // untranslated
Blockly.Msg["TEXT_CHARAT_LAST"] = "get last letter"; // untranslated
Blockly.Msg["TEXT_CHARAT_RANDOM"] = "get random letter"; // untranslated
Blockly.Msg["TEXT_CHARAT_TAIL"] = ""; // untranslated
Blockly.Msg["TEXT_CHARAT_TITLE"] = "in text %1 %2"; // untranslated
Blockly.Msg["TEXT_CHARAT_TOOLTIP"] = "Returns the letter at the specified position."; // untranslated
Blockly.Msg["TEXT_COUNT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#counting-substrings"; // untranslated
Blockly.Msg["TEXT_COUNT_MESSAGE0"] = "count %1 in %2"; // untranslated
Blockly.Msg["TEXT_COUNT_TOOLTIP"] = "Count how many times some text occurs within some other text."; // untranslated
Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TOOLTIP"] = "Add an item to the text."; // untranslated
Blockly.Msg["TEXT_CREATE_JOIN_TITLE_JOIN"] = "join"; // untranslated
Blockly.Msg["TEXT_CREATE_JOIN_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this text block."; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_END"] = "to letter # from end"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_START"] = "to letter #"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_END_LAST"] = "to last letter"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_INPUT_IN_TEXT"] = "in text"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_START_FIRST"] = "get substring from first letter"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_END"] = "get substring from letter # from end"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_START"] = "get substring from letter #"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_TAIL"] = ""; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_TOOLTIP"] = "Returns a specified portion of the text."; // untranslated
Blockly.Msg["TEXT_INDEXOF_HELPURL"] = "https://github.com/google/blockly/wiki/Text#finding-text"; // untranslated
Blockly.Msg["TEXT_INDEXOF_OPERATOR_FIRST"] = "find first occurrence of text"; // untranslated
Blockly.Msg["TEXT_INDEXOF_OPERATOR_LAST"] = "find last occurrence of text"; // untranslated
Blockly.Msg["TEXT_INDEXOF_TITLE"] = "in text %1 %2 %3"; // untranslated
Blockly.Msg["TEXT_INDEXOF_TOOLTIP"] = "Returns the index of the first/last occurrence of the first text in the second text. Returns %1 if text is not found."; // untranslated
Blockly.Msg["TEXT_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Text#checking-for-empty-text"; // untranslated
Blockly.Msg["TEXT_ISEMPTY_TITLE"] = "%1 je prazan";
Blockly.Msg["TEXT_ISEMPTY_TOOLTIP"] = "Returns true if the provided text is empty."; // untranslated
Blockly.Msg["TEXT_JOIN_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-creation"; // untranslated
Blockly.Msg["TEXT_JOIN_TITLE_CREATEWITH"] = "create text with"; // untranslated
Blockly.Msg["TEXT_JOIN_TOOLTIP"] = "Create a piece of text by joining together any number of items."; // untranslated
Blockly.Msg["TEXT_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated
Blockly.Msg["TEXT_LENGTH_TITLE"] = "dužina teksta %1";
Blockly.Msg["TEXT_LENGTH_TOOLTIP"] = "Returns the number of letters (including spaces) in the provided text."; // untranslated
Blockly.Msg["TEXT_PRINT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#printing-text"; // untranslated
Blockly.Msg["TEXT_PRINT_TITLE"] = "print %1"; // untranslated
Blockly.Msg["TEXT_PRINT_TOOLTIP"] = "Print the specified text, number or other value."; // untranslated
Blockly.Msg["TEXT_PROMPT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#getting-input-from-the-user"; // untranslated
Blockly.Msg["TEXT_PROMPT_TOOLTIP_NUMBER"] = "Prompt for user for a number."; // untranslated
Blockly.Msg["TEXT_PROMPT_TOOLTIP_TEXT"] = "Prompt for user for some text."; // untranslated
Blockly.Msg["TEXT_PROMPT_TYPE_NUMBER"] = "prompt for number with message"; // untranslated
Blockly.Msg["TEXT_PROMPT_TYPE_TEXT"] = "prompt for text with message"; // untranslated
Blockly.Msg["TEXT_REPLACE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#replacing-substrings"; // untranslated
Blockly.Msg["TEXT_REPLACE_MESSAGE0"] = "replace %1 with %2 in %3"; // untranslated
Blockly.Msg["TEXT_REPLACE_TOOLTIP"] = "Replace all occurances of some text within some other text."; // untranslated
Blockly.Msg["TEXT_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#reversing-text"; // untranslated
Blockly.Msg["TEXT_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated
Blockly.Msg["TEXT_REVERSE_TOOLTIP"] = "Reverses the order of the characters in the text."; // untranslated
Blockly.Msg["TEXT_TEXT_HELPURL"] = "https://en.wikipedia.org/wiki/String_(computer_science)"; // untranslated
Blockly.Msg["TEXT_TEXT_TOOLTIP"] = "A letter, word, or line of text."; // untranslated
Blockly.Msg["TEXT_TRIM_HELPURL"] = "https://github.com/google/blockly/wiki/Text#trimming-removing-spaces"; // untranslated
Blockly.Msg["TEXT_TRIM_OPERATOR_BOTH"] = "trim spaces from both sides of"; // untranslated
Blockly.Msg["TEXT_TRIM_OPERATOR_LEFT"] = "trim spaces from left side of"; // untranslated
Blockly.Msg["TEXT_TRIM_OPERATOR_RIGHT"] = "trim spaces from right side of"; // untranslated
Blockly.Msg["TEXT_TRIM_TOOLTIP"] = "Return a copy of the text with spaces removed from one or both ends."; // untranslated
Blockly.Msg["TODAY"] = "Danas";
Blockly.Msg["UNDO"] = "Poništi";
Blockly.Msg["UNNAMED_KEY"] = "neimenovano";
Blockly.Msg["VARIABLES_DEFAULT_NAME"] = "stavka";
Blockly.Msg["VARIABLES_GET_CREATE_SET"] = "Create 'set %1'"; // untranslated
Blockly.Msg["VARIABLES_GET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#get"; // untranslated
Blockly.Msg["VARIABLES_GET_TOOLTIP"] = "Returns the value of this variable."; // untranslated
Blockly.Msg["VARIABLES_SET"] = "set %1 to %2"; // untranslated
Blockly.Msg["VARIABLES_SET_CREATE_GET"] = "Create 'get %1'"; // untranslated
Blockly.Msg["VARIABLES_SET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#set"; // untranslated
Blockly.Msg["VARIABLES_SET_TOOLTIP"] = "Sets this variable to be equal to the input."; // untranslated
Blockly.Msg["VARIABLE_ALREADY_EXISTS"] = "Varijabla s imenom \"%1\" već postoji.";
Blockly.Msg["VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE"] = "Varijabla s imenom \"%1\" već postoji za drugu vrstu: \"%2\".";
Blockly.Msg["WORKSPACE_ARIA_LABEL"] = "Blockly Workspace"; // untranslated
Blockly.Msg["WORKSPACE_COMMENT_DEFAULT_TEXT"] = "Say something..."; // untranslated
Blockly.Msg["CONTROLS_FOREACH_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["CONTROLS_FOR_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["CONTROLS_IF_ELSEIF_TITLE_ELSEIF"] = Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"];
Blockly.Msg["CONTROLS_IF_ELSE_TITLE_ELSE"] = Blockly.Msg["CONTROLS_IF_MSG_ELSE"];
Blockly.Msg["CONTROLS_IF_IF_TITLE_IF"] = Blockly.Msg["CONTROLS_IF_MSG_IF"];
Blockly.Msg["CONTROLS_IF_MSG_THEN"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["CONTROLS_WHILEUNTIL_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["LISTS_CREATE_WITH_ITEM_TITLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["LISTS_GET_INDEX_HELPURL"] = Blockly.Msg["LISTS_INDEX_OF_HELPURL"];
Blockly.Msg["LISTS_GET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["LISTS_GET_SUBLIST_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["LISTS_INDEX_OF_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["LISTS_SET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["MATH_CHANGE_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["PROCEDURES_DEFRETURN_COMMENT"] = Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"];
Blockly.Msg["PROCEDURES_DEFRETURN_DO"] = Blockly.Msg["PROCEDURES_DEFNORETURN_DO"];
Blockly.Msg["PROCEDURES_DEFRETURN_PROCEDURE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"];
Blockly.Msg["PROCEDURES_DEFRETURN_TITLE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"];
Blockly.Msg["TEXT_APPEND_VARIABLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["MATH_HUE"] = "230";
Blockly.Msg["LOOPS_HUE"] = "120";
Blockly.Msg["LISTS_HUE"] = "260";
Blockly.Msg["LOGIC_HUE"] = "210";
Blockly.Msg["VARIABLES_HUE"] = "330";
Blockly.Msg["TEXTS_HUE"] = "160";
Blockly.Msg["PROCEDURES_HUE"] = "290";
Blockly.Msg["COLOUR_HUE"] = "20";
Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";

434
msg/js/zgh.js Normal file
View File

@@ -0,0 +1,434 @@
// This file was automatically generated. Do not modify.
'use strict';
Blockly.Msg["ADD_COMMENT"] = "ⵔⵏⵓ ⴰⵅⴼⴰⵡⴰⵍ";
Blockly.Msg["CANNOT_DELETE_VARIABLE_PROCEDURE"] = "Can't delete the variable '%1' because it's part of the definition of the function '%2'"; // untranslated
Blockly.Msg["CHANGE_VALUE_TITLE"] = "ⵙⵏⴼⵍ ⴰⵣⴰⵍ:";
Blockly.Msg["CLEAN_UP"] = "Clean up Blocks"; // untranslated
Blockly.Msg["COLLAPSED_WARNINGS_WARNING"] = "Collapsed blocks contain warnings."; // untranslated
Blockly.Msg["COLLAPSE_ALL"] = "Collapse Blocks"; // untranslated
Blockly.Msg["COLLAPSE_BLOCK"] = "Collapse Block"; // untranslated
Blockly.Msg["COLOUR_BLEND_COLOUR1"] = "ⴰⴽⵍⵓ 1";
Blockly.Msg["COLOUR_BLEND_COLOUR2"] = "ⴰⴽⵍⵓ 2";
Blockly.Msg["COLOUR_BLEND_HELPURL"] = "https://meyerweb.com/eric/tools/color-blend/#:::rgbp"; // untranslated
Blockly.Msg["COLOUR_BLEND_RATIO"] = "ⴰⵙⵙⴰⵖ";
Blockly.Msg["COLOUR_BLEND_TITLE"] = "ⵙⵎⵔⴽⵙ";
Blockly.Msg["COLOUR_BLEND_TOOLTIP"] = "Blends two colours together with a given ratio (0.0 - 1.0)."; // untranslated
Blockly.Msg["COLOUR_PICKER_HELPURL"] = "https://en.wikipedia.org/wiki/Color";
Blockly.Msg["COLOUR_PICKER_TOOLTIP"] = "Choose a colour from the palette."; // untranslated
Blockly.Msg["COLOUR_RANDOM_HELPURL"] = "http://randomcolour.com"; // untranslated
Blockly.Msg["COLOUR_RANDOM_TITLE"] = "random colour"; // untranslated
Blockly.Msg["COLOUR_RANDOM_TOOLTIP"] = "Choose a colour at random."; // untranslated
Blockly.Msg["COLOUR_RGB_BLUE"] = "ⴰⵏⵉⵍⵉ";
Blockly.Msg["COLOUR_RGB_GREEN"] = "ⴰⵣⴳⵣⴰ";
Blockly.Msg["COLOUR_RGB_HELPURL"] = "https://www.december.com/html/spec/colorpercompact.html"; // untranslated
Blockly.Msg["COLOUR_RGB_RED"] = "ⴰⵣⴳⴳⵯⴰⵖ";
Blockly.Msg["COLOUR_RGB_TITLE"] = "ⴽⵍⵓ ⵙ";
Blockly.Msg["COLOUR_RGB_TOOLTIP"] = "ⴰⵣⴰⵍⵏ ⵉⴼⵓⴽⴽ ⴰⴷ ⵉⵍⵉⵏ ⴳⵔ 0 ⴷ 100.";
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#loop-termination-blocks"; // untranslated
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK"] = "break out of loop"; // untranslated
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE"] = "continue with next iteration of loop"; // untranslated
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK"] = "Break out of the containing loop."; // untranslated
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE"] = "Skip the rest of this loop, and continue with the next iteration."; // untranslated
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_WARNING"] = "Warning: This block may only be used within a loop."; // untranslated
Blockly.Msg["CONTROLS_FOREACH_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#for-each"; // untranslated
Blockly.Msg["CONTROLS_FOREACH_TITLE"] = "for each item %1 in list %2"; // untranslated
Blockly.Msg["CONTROLS_FOREACH_TOOLTIP"] = "For each item in a list, set the variable '%1' to the item, and then do some statements."; // untranslated
Blockly.Msg["CONTROLS_FOR_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#count-with"; // untranslated
Blockly.Msg["CONTROLS_FOR_TITLE"] = "count with %1 from %2 to %3 by %4"; // untranslated
Blockly.Msg["CONTROLS_FOR_TOOLTIP"] = "Have the variable '%1' take on the values from the start number to the end number, counting by the specified interval, and do the specified blocks."; // untranslated
Blockly.Msg["CONTROLS_IF_ELSEIF_TOOLTIP"] = "Add a condition to the if block."; // untranslated
Blockly.Msg["CONTROLS_IF_ELSE_TOOLTIP"] = "Add a final, catch-all condition to the if block."; // untranslated
Blockly.Msg["CONTROLS_IF_HELPURL"] = "https://github.com/google/blockly/wiki/IfElse"; // untranslated
Blockly.Msg["CONTROLS_IF_IF_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this if block."; // untranslated
Blockly.Msg["CONTROLS_IF_MSG_ELSE"] = "ⵎⴽ ⴷ ⵓⵀⵓ";
Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"] = "ⵉⵙ";
Blockly.Msg["CONTROLS_IF_MSG_IF"] = "ⵎⴽ";
Blockly.Msg["CONTROLS_IF_TOOLTIP_1"] = "If a value is true, then do some statements."; // untranslated
Blockly.Msg["CONTROLS_IF_TOOLTIP_2"] = "If a value is true, then do the first block of statements. Otherwise, do the second block of statements."; // untranslated
Blockly.Msg["CONTROLS_IF_TOOLTIP_3"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements."; // untranslated
Blockly.Msg["CONTROLS_IF_TOOLTIP_4"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements."; // untranslated
Blockly.Msg["CONTROLS_REPEAT_HELPURL"] = "https://en.wikipedia.org/wiki/For_loop";
Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"] = "ⴳ";
Blockly.Msg["CONTROLS_REPEAT_TITLE"] = "ⴰⵍⵙ ⴷⴰⵖ %1 ⵜⴽⴽⵍⵜ";
Blockly.Msg["CONTROLS_REPEAT_TOOLTIP"] = "Do some statements several times."; // untranslated
Blockly.Msg["CONTROLS_WHILEUNTIL_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#repeat"; // untranslated
Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_UNTIL"] = "ⴰⵍⵙ ⴰⵔⴷ";
Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_WHILE"] = "ⴰⵍⵙ ⴰⴷⴷⴰⴳ";
Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL"] = "While a value is false, then do some statements."; // untranslated
Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_WHILE"] = "ⴽⵓⴷ ⵉⴷⵜⵜⴰ ⵡⴰⵣⴰⵍ, ⵙⵙⵍⴽⵎ ⴽⵔⴰ ⵡⴰⵏⴰⴹⵏ.";
Blockly.Msg["DELETE_ALL_BLOCKS"] = "ⴽⴽⵙ %1 ⵉⴱⵍⵓⴽⵏ ⵎⴰⵕⵕⴰ?";
Blockly.Msg["DELETE_BLOCK"] = "ⴽⴽⵙ ⴰⴱⵍⵓⴽ";
Blockly.Msg["DELETE_VARIABLE"] = "ⴽⴽⵙ ⴰⵎⵙⴽⵉⵍ '%1'";
Blockly.Msg["DELETE_VARIABLE_CONFIRMATION"] = "Delete %1 uses of the '%2' variable?"; // untranslated
Blockly.Msg["DELETE_X_BLOCKS"] = "ⴽⴽⵙ %1 ⵉⴱⵍⵓⴽⵏ";
Blockly.Msg["DISABLE_BLOCK"] = "Disable Block"; // untranslated
Blockly.Msg["DUPLICATE_BLOCK"] = "Duplicate"; // untranslated
Blockly.Msg["DUPLICATE_COMMENT"] = "Duplicate Comment"; // untranslated
Blockly.Msg["ENABLE_BLOCK"] = "Enable Block"; // untranslated
Blockly.Msg["EXPAND_ALL"] = "Expand Blocks"; // untranslated
Blockly.Msg["EXPAND_BLOCK"] = "Expand Block"; // untranslated
Blockly.Msg["EXTERNAL_INPUTS"] = "External Inputs"; // untranslated
Blockly.Msg["HELP"] = "ⵜⵉⵡⵉⵙⵉ";
Blockly.Msg["INLINE_INPUTS"] = "Inline Inputs"; // untranslated
Blockly.Msg["IOS_CANCEL"] = "ⵙⵔ";
Blockly.Msg["IOS_ERROR"] = "ⴰⵣⴳⴰⵍ";
Blockly.Msg["IOS_OK"] = "ⵡⴰⵅⵅⴰ";
Blockly.Msg["IOS_PROCEDURES_ADD_INPUT"] = "+ ⵔⵏⵓ ⵢⴰⵜ ⵜⵏⴽⵛⵓⵎⵜ";
Blockly.Msg["IOS_PROCEDURES_ALLOW_STATEMENTS"] = "Allow statements"; // untranslated
Blockly.Msg["IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR"] = "This function has duplicate inputs."; // untranslated
Blockly.Msg["IOS_PROCEDURES_INPUTS"] = "ⵉⵏⴽⵛⵓⵎⵏ";
Blockly.Msg["IOS_VARIABLES_ADD_BUTTON"] = "ⵔⵏⵓ";
Blockly.Msg["IOS_VARIABLES_ADD_VARIABLE"] = "+ ⵔⵏⵓ ⴰⵎⵙⴽⵉⵍ";
Blockly.Msg["IOS_VARIABLES_DELETE_BUTTON"] = "ⴽⴽⵙ";
Blockly.Msg["IOS_VARIABLES_EMPTY_NAME_ERROR"] = "ⵓⵔ ⵜⵓⴼⵉⴷ ⴰⴷ ⵜⵙⵙⵎⵔⵙⴷ ⵢⴰⵏ ⵢⵉⵙⵎ ⵓⵎⵙⴽⵉⵍ ⵢⵓⵔⴰⵏ.";
Blockly.Msg["IOS_VARIABLES_RENAME_BUTTON"] = "ⵙⵏⴼⵍ ⵉⵙⵎ";
Blockly.Msg["IOS_VARIABLES_VARIABLE_NAME"] = "ⵉⵙⵎ ⵓⵎⵙⴽⵉⵍ";
Blockly.Msg["LISTS_CREATE_EMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-empty-list"; // untranslated
Blockly.Msg["LISTS_CREATE_EMPTY_TITLE"] = "create empty list"; // untranslated
Blockly.Msg["LISTS_CREATE_EMPTY_TOOLTIP"] = "Returns a list, of length 0, containing no data records"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TITLE_ADD"] = "list"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this list block."; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_INPUT_WITH"] = "create list with"; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_ITEM_TOOLTIP"] = "Add an item to the list."; // untranslated
Blockly.Msg["LISTS_CREATE_WITH_TOOLTIP"] = "Create a list with any number of items."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_FIRST"] = "ⴰⵎⵣⵡⴰⵔⵓ";
Blockly.Msg["LISTS_GET_INDEX_FROM_END"] = "# ⵙⴳ ⵜⵉⴳⵉⵔⴰ";
Blockly.Msg["LISTS_GET_INDEX_FROM_START"] = "#"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_GET"] = "get"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_GET_REMOVE"] = "get and remove"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_LAST"] = "ⴰⵎⴳⴳⴰⵔⵓ";
Blockly.Msg["LISTS_GET_INDEX_RANDOM"] = "random"; // untranslated
Blockly.Msg["LISTS_GET_INDEX_REMOVE"] = "ⵙⵉⵜⵜⵢ";
Blockly.Msg["LISTS_GET_INDEX_TAIL"] = ""; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FIRST"] = "Returns the first item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FROM"] = "Returns the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_LAST"] = "Returns the last item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_RANDOM"] = "Returns a random item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST"] = "Removes and returns the first item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM"] = "Removes and returns the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST"] = "Removes and returns the last item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM"] = "Removes and returns a random item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST"] = "Removes the first item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM"] = "Removes the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST"] = "Removes the last item in a list."; // untranslated
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM"] = "Removes a random item in a list."; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_END"] = "to # from end"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_START"] = "ⴰⵔ #";
Blockly.Msg["LISTS_GET_SUBLIST_END_LAST"] = "ⴰⵔ ⵜⴳⵉⵔⴰ";
Blockly.Msg["LISTS_GET_SUBLIST_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-a-sublist"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_START_FIRST"] = "get sub-list from first"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_END"] = "get sub-list from # from end"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_START"] = "get sub-list from #"; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_TAIL"] = ""; // untranslated
Blockly.Msg["LISTS_GET_SUBLIST_TOOLTIP"] = "Creates a copy of the specified portion of a list."; // untranslated
Blockly.Msg["LISTS_INDEX_FROM_END_TOOLTIP"] = "%1 is the last item."; // untranslated
Blockly.Msg["LISTS_INDEX_FROM_START_TOOLTIP"] = "%1 is the first item."; // untranslated
Blockly.Msg["LISTS_INDEX_OF_FIRST"] = "find first occurrence of item"; // untranslated
Blockly.Msg["LISTS_INDEX_OF_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list"; // untranslated
Blockly.Msg["LISTS_INDEX_OF_LAST"] = "find last occurrence of item"; // untranslated
Blockly.Msg["LISTS_INDEX_OF_TOOLTIP"] = "Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found."; // untranslated
Blockly.Msg["LISTS_INLIST"] = "ⴳ ⵜⵍⴳⴰⵎⵜ";
Blockly.Msg["LISTS_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#is-empty"; // untranslated
Blockly.Msg["LISTS_ISEMPTY_TITLE"] = "%1 is empty"; // untranslated
Blockly.Msg["LISTS_ISEMPTY_TOOLTIP"] = "Returns true if the list is empty."; // untranslated
Blockly.Msg["LISTS_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#length-of"; // untranslated
Blockly.Msg["LISTS_LENGTH_TITLE"] = "ⵜⵉⵖⵣⵉ %1";
Blockly.Msg["LISTS_LENGTH_TOOLTIP"] = "Returns the length of a list."; // untranslated
Blockly.Msg["LISTS_REPEAT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated
Blockly.Msg["LISTS_REPEAT_TITLE"] = "create list with item %1 repeated %2 times"; // untranslated
Blockly.Msg["LISTS_REPEAT_TOOLTIP"] = "Creates a list consisting of the given value repeated the specified number of times."; // untranslated
Blockly.Msg["LISTS_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#reversing-a-list"; // untranslated
Blockly.Msg["LISTS_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated
Blockly.Msg["LISTS_REVERSE_TOOLTIP"] = "Reverse a copy of a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#in-list--set"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_INPUT_TO"] = "ⴰⵎ";
Blockly.Msg["LISTS_SET_INDEX_INSERT"] = "insert at"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_SET"] = "set"; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST"] = "Inserts the item at the start of a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FROM"] = "Inserts the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_LAST"] = "Append the item to the end of a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM"] = "Inserts the item randomly in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FIRST"] = "Sets the first item in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FROM"] = "Sets the item at the specified position in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_LAST"] = "Sets the last item in a list."; // untranslated
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_RANDOM"] = "Sets a random item in a list."; // untranslated
Blockly.Msg["LISTS_SORT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#sorting-a-list"; // untranslated
Blockly.Msg["LISTS_SORT_ORDER_ASCENDING"] = "ascending"; // untranslated
Blockly.Msg["LISTS_SORT_ORDER_DESCENDING"] = "descending"; // untranslated
Blockly.Msg["LISTS_SORT_TITLE"] = "sort %1 %2 %3"; // untranslated
Blockly.Msg["LISTS_SORT_TOOLTIP"] = "Sort a copy of a list."; // untranslated
Blockly.Msg["LISTS_SORT_TYPE_IGNORECASE"] = "alphabetic, ignore case"; // untranslated
Blockly.Msg["LISTS_SORT_TYPE_NUMERIC"] = "ⴰⵎⵓⵟⵟⵓⵏ";
Blockly.Msg["LISTS_SORT_TYPE_TEXT"] = "alphabetic"; // untranslated
Blockly.Msg["LISTS_SPLIT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists"; // untranslated
Blockly.Msg["LISTS_SPLIT_LIST_FROM_TEXT"] = "make list from text"; // untranslated
Blockly.Msg["LISTS_SPLIT_TEXT_FROM_LIST"] = "make text from list"; // untranslated
Blockly.Msg["LISTS_SPLIT_TOOLTIP_JOIN"] = "Join a list of texts into one text, separated by a delimiter."; // untranslated
Blockly.Msg["LISTS_SPLIT_TOOLTIP_SPLIT"] = "Split text into a list of texts, breaking at each delimiter."; // untranslated
Blockly.Msg["LISTS_SPLIT_WITH_DELIMITER"] = "with delimiter"; // untranslated
Blockly.Msg["LOGIC_BOOLEAN_FALSE"] = "ⴰⵔⵎⵉⴷⵉ";
Blockly.Msg["LOGIC_BOOLEAN_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#values"; // untranslated
Blockly.Msg["LOGIC_BOOLEAN_TOOLTIP"] = "Returns either true or false."; // untranslated
Blockly.Msg["LOGIC_BOOLEAN_TRUE"] = "ⴰⵎⵉⴷⵉ";
Blockly.Msg["LOGIC_COMPARE_HELPURL"] = "https://en.wikipedia.org/wiki/Inequality_(mathematics)";
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_EQ"] = "Return true if both inputs equal each other."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GT"] = "Return true if the first input is greater than the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GTE"] = "Return true if the first input is greater than or equal to the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LT"] = "Return true if the first input is smaller than the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LTE"] = "Return true if the first input is smaller than or equal to the second input."; // untranslated
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_NEQ"] = "Return true if both inputs are not equal to each other."; // untranslated
Blockly.Msg["LOGIC_NEGATE_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#not"; // untranslated
Blockly.Msg["LOGIC_NEGATE_TITLE"] = "ⵓⵔ ⴷ %1";
Blockly.Msg["LOGIC_NEGATE_TOOLTIP"] = "Returns true if the input is false. Returns false if the input is true."; // untranslated
Blockly.Msg["LOGIC_NULL"] = "ⵢⵓⵔⴰ";
Blockly.Msg["LOGIC_NULL_HELPURL"] = "https://en.wikipedia.org/wiki/Nullable_type"; // untranslated
Blockly.Msg["LOGIC_NULL_TOOLTIP"] = "Returns null."; // untranslated
Blockly.Msg["LOGIC_OPERATION_AND"] = "ⴷ";
Blockly.Msg["LOGIC_OPERATION_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#logical-operations"; // untranslated
Blockly.Msg["LOGIC_OPERATION_OR"] = "ⵏⵖ";
Blockly.Msg["LOGIC_OPERATION_TOOLTIP_AND"] = "Return true if both inputs are true."; // untranslated
Blockly.Msg["LOGIC_OPERATION_TOOLTIP_OR"] = "Return true if at least one of the inputs is true."; // untranslated
Blockly.Msg["LOGIC_TERNARY_CONDITION"] = "ⴰⵔⵎ";
Blockly.Msg["LOGIC_TERNARY_HELPURL"] = "https://en.wikipedia.org/wiki/%3F:"; // untranslated
Blockly.Msg["LOGIC_TERNARY_IF_FALSE"] = "ⵎⴽ ⵓⵔ ⵉⴷⵜⵜⵉ";
Blockly.Msg["LOGIC_TERNARY_IF_TRUE"] = "ⵎⴽ ⵉⴷⵜⵜⴰ";
Blockly.Msg["LOGIC_TERNARY_TOOLTIP"] = "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value."; // untranslated
Blockly.Msg["MATH_ADDITION_SYMBOL"] = "+"; // untranslated
Blockly.Msg["MATH_ARITHMETIC_HELPURL"] = "https://en.wikipedia.org/wiki/Arithmetic";
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_ADD"] = "Return the sum of the two numbers."; // untranslated
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_DIVIDE"] = "Return the quotient of the two numbers."; // untranslated
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MINUS"] = "Return the difference of the two numbers."; // untranslated
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MULTIPLY"] = "Return the product of the two numbers."; // untranslated
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_POWER"] = "Return the first number raised to the power of the second number."; // untranslated
Blockly.Msg["MATH_ATAN2_HELPURL"] = "https://en.wikipedia.org/wiki/Atan2";
Blockly.Msg["MATH_ATAN2_TITLE"] = "atan2 ⵙⴳ X:%1 Y:%2";
Blockly.Msg["MATH_ATAN2_TOOLTIP"] = "Return the arctangent of point (X, Y) in degrees from -180 to 180."; // untranslated
Blockly.Msg["MATH_CHANGE_HELPURL"] = "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter"; // untranslated
Blockly.Msg["MATH_CHANGE_TITLE"] = "ⵙⵏⴼⵍ %1 ⵙ %2";
Blockly.Msg["MATH_CHANGE_TOOLTIP"] = "ⵔⵏⵓ ⵢⴰⵏ ⵓⵎⴹⴰⵏ ⵖⵔ ⵓⵎⵙⴽⵉⵍ '%1'";
Blockly.Msg["MATH_CONSTANT_HELPURL"] = "https://en.wikipedia.org/wiki/Mathematical_constant"; // untranslated
Blockly.Msg["MATH_CONSTANT_TOOLTIP"] = "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity)."; // untranslated
Blockly.Msg["MATH_CONSTRAIN_HELPURL"] = "https://en.wikipedia.org/wiki/Clamping_(graphics)"; // untranslated
Blockly.Msg["MATH_CONSTRAIN_TITLE"] = "constrain %1 low %2 high %3"; // untranslated
Blockly.Msg["MATH_CONSTRAIN_TOOLTIP"] = "Constrain a number to be between the specified limits (inclusive)."; // untranslated
Blockly.Msg["MATH_DIVISION_SYMBOL"] = "÷"; // untranslated
Blockly.Msg["MATH_IS_DIVISIBLE_BY"] = "is divisible by"; // untranslated
Blockly.Msg["MATH_IS_EVEN"] = "is even"; // untranslated
Blockly.Msg["MATH_IS_NEGATIVE"] = "is negative"; // untranslated
Blockly.Msg["MATH_IS_ODD"] = "is odd"; // untranslated
Blockly.Msg["MATH_IS_POSITIVE"] = "is positive"; // untranslated
Blockly.Msg["MATH_IS_PRIME"] = "is prime"; // untranslated
Blockly.Msg["MATH_IS_TOOLTIP"] = "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false."; // untranslated
Blockly.Msg["MATH_IS_WHOLE"] = "is whole"; // untranslated
Blockly.Msg["MATH_MODULO_HELPURL"] = "https://en.wikipedia.org/wiki/Modulo_operation";
Blockly.Msg["MATH_MODULO_TITLE"] = "remainder of %1 ÷ %2"; // untranslated
Blockly.Msg["MATH_MODULO_TOOLTIP"] = "Return the remainder from dividing the two numbers."; // untranslated
Blockly.Msg["MATH_MULTIPLICATION_SYMBOL"] = "×"; // untranslated
Blockly.Msg["MATH_NUMBER_HELPURL"] = "https://en.wikipedia.org/wiki/Number";
Blockly.Msg["MATH_NUMBER_TOOLTIP"] = "ⴽⵔⴰ ⵓⵎⴹⴰⵏ.";
Blockly.Msg["MATH_ONLIST_HELPURL"] = ""; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_AVERAGE"] = "average of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MAX"] = "max of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MEDIAN"] = "median of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MIN"] = "min of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_MODE"] = "modes of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_RANDOM"] = "random item of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_STD_DEV"] = "standard deviation of list"; // untranslated
Blockly.Msg["MATH_ONLIST_OPERATOR_SUM"] = "sum of list"; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_AVERAGE"] = "Return the average (arithmetic mean) of the numeric values in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MAX"] = "Return the largest number in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MEDIAN"] = "Return the median number in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MIN"] = "Return the smallest number in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_MODE"] = "Return a list of the most common item(s) in the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_RANDOM"] = "Return a random element from the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_STD_DEV"] = "Return the standard deviation of the list."; // untranslated
Blockly.Msg["MATH_ONLIST_TOOLTIP_SUM"] = "Return the sum of all the numbers in the list."; // untranslated
Blockly.Msg["MATH_POWER_SYMBOL"] = "^"; // untranslated
Blockly.Msg["MATH_RANDOM_FLOAT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated
Blockly.Msg["MATH_RANDOM_FLOAT_TITLE_RANDOM"] = "random fraction"; // untranslated
Blockly.Msg["MATH_RANDOM_FLOAT_TOOLTIP"] = "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive)."; // untranslated
Blockly.Msg["MATH_RANDOM_INT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated
Blockly.Msg["MATH_RANDOM_INT_TITLE"] = "random integer from %1 to %2"; // untranslated
Blockly.Msg["MATH_RANDOM_INT_TOOLTIP"] = "Return a random integer between the two specified limits, inclusive."; // untranslated
Blockly.Msg["MATH_ROUND_HELPURL"] = "https://en.wikipedia.org/wiki/Rounding";
Blockly.Msg["MATH_ROUND_OPERATOR_ROUND"] = "round"; // untranslated
Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDDOWN"] = "round down"; // untranslated
Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDUP"] = "round up"; // untranslated
Blockly.Msg["MATH_ROUND_TOOLTIP"] = "Round a number up or down."; // untranslated
Blockly.Msg["MATH_SINGLE_HELPURL"] = "https://en.wikipedia.org/wiki/Square_root"; // untranslated
Blockly.Msg["MATH_SINGLE_OP_ABSOLUTE"] = "absolute"; // untranslated
Blockly.Msg["MATH_SINGLE_OP_ROOT"] = "square root"; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_ABS"] = "Return the absolute value of a number."; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_EXP"] = "Return e to the power of a number."; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_LN"] = "Return the natural logarithm of a number."; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_LOG10"] = "Return the base 10 logarithm of a number."; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_NEG"] = "Return the negation of a number."; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_POW10"] = "Return 10 to the power of a number."; // untranslated
Blockly.Msg["MATH_SINGLE_TOOLTIP_ROOT"] = "Return the square root of a number."; // untranslated
Blockly.Msg["MATH_SUBTRACTION_SYMBOL"] = "-"; // untranslated
Blockly.Msg["MATH_TRIG_ACOS"] = "acos"; // untranslated
Blockly.Msg["MATH_TRIG_ASIN"] = "asin"; // untranslated
Blockly.Msg["MATH_TRIG_ATAN"] = "atan"; // untranslated
Blockly.Msg["MATH_TRIG_COS"] = "cos"; // untranslated
Blockly.Msg["MATH_TRIG_HELPURL"] = "https://en.wikipedia.org/wiki/Trigonometric_functions";
Blockly.Msg["MATH_TRIG_SIN"] = "sin"; // untranslated
Blockly.Msg["MATH_TRIG_TAN"] = "tan"; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_ACOS"] = "Return the arccosine of a number."; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_ASIN"] = "Return the arcsine of a number."; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_ATAN"] = "Return the arctangent of a number."; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_COS"] = "Return the cosine of a degree (not radian)."; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_SIN"] = "Return the sine of a degree (not radian)."; // untranslated
Blockly.Msg["MATH_TRIG_TOOLTIP_TAN"] = "Return the tangent of a degree (not radian)."; // untranslated
Blockly.Msg["NEW_COLOUR_VARIABLE"] = "ⵙⴽⵔ ⴰⴽⵍⵓ ⴰⵎⵙⴽⵉⵍ...";
Blockly.Msg["NEW_NUMBER_VARIABLE"] = "ⵙⴽⵔ ⴰⵎⴹⴰⵏ ⴰⵎⵙⴽⵉⵍ...";
Blockly.Msg["NEW_STRING_VARIABLE"] = "Create string variable..."; // untranslated
Blockly.Msg["NEW_VARIABLE"] = "ⵙⴽⵔ ⴰⵎⵙⴽⵉⵍ...";
Blockly.Msg["NEW_VARIABLE_TITLE"] = "ⵉⵙⵎ ⵓⵎⵙⴽⵉⵍ ⴰⵎⴰⵢⵏⵓ:";
Blockly.Msg["NEW_VARIABLE_TYPE_TITLE"] = "ⴰⵏⴰⵡ ⴰⵎⴰⵢⵏⵓ ⵓⵎⵙⴽⵉⵍ:";
Blockly.Msg["ORDINAL_NUMBER_SUFFIX"] = ""; // untranslated
Blockly.Msg["PROCEDURES_ALLOW_STATEMENTS"] = "allow statements"; // untranslated
Blockly.Msg["PROCEDURES_BEFORE_PARAMS"] = "ⵙ:";
Blockly.Msg["PROCEDURES_CALLNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine";
Blockly.Msg["PROCEDURES_CALLNORETURN_TOOLTIP"] = "Run the user-defined function '%1'."; // untranslated
Blockly.Msg["PROCEDURES_CALLRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine";
Blockly.Msg["PROCEDURES_CALLRETURN_TOOLTIP"] = "Run the user-defined function '%1' and use its output."; // untranslated
Blockly.Msg["PROCEDURES_CALL_BEFORE_PARAMS"] = "ⵙ:";
Blockly.Msg["PROCEDURES_CREATE_DO"] = "Create '%1'"; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"] = "Describe this function..."; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_DO"] = ""; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated
Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"] = "ⴳ ⴽⵔⴰ";
Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"] = "ⵉ";
Blockly.Msg["PROCEDURES_DEFNORETURN_TOOLTIP"] = "Creates a function with no output."; // untranslated
Blockly.Msg["PROCEDURES_DEFRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated
Blockly.Msg["PROCEDURES_DEFRETURN_RETURN"] = "return"; // untranslated
Blockly.Msg["PROCEDURES_DEFRETURN_TOOLTIP"] = "Creates a function with an output."; // untranslated
Blockly.Msg["PROCEDURES_DEF_DUPLICATE_WARNING"] = "Warning: This function has duplicate parameters."; // untranslated
Blockly.Msg["PROCEDURES_HIGHLIGHT_DEF"] = "Highlight function definition"; // untranslated
Blockly.Msg["PROCEDURES_IFRETURN_HELPURL"] = "http://c2.com/cgi/wiki?GuardClause"; // untranslated
Blockly.Msg["PROCEDURES_IFRETURN_TOOLTIP"] = "If a value is true, then return a second value."; // untranslated
Blockly.Msg["PROCEDURES_IFRETURN_WARNING"] = "Warning: This block may be used only within a function definition."; // untranslated
Blockly.Msg["PROCEDURES_MUTATORARG_TITLE"] = "input name:"; // untranslated
Blockly.Msg["PROCEDURES_MUTATORARG_TOOLTIP"] = "ⵔⵏⵓ ⴰⵏⴽⵛⴰⵎ ⵖⵔ ⵜⵙⵖⵏⵜ.";
Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TITLE"] = "inputs"; // untranslated
Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TOOLTIP"] = "Add, remove, or reorder inputs to this function."; // untranslated
Blockly.Msg["REDO"] = "ⴰⵍⵙ";
Blockly.Msg["REMOVE_COMMENT"] = "ⴽⴽⵙ ⴰⵅⴼⴰⵡⴰⵍ";
Blockly.Msg["RENAME_VARIABLE"] = "ⵙⵏⴼⵍ ⵉⵙⵎ ⵓⵎⵙⴽⵉⵍ...";
Blockly.Msg["RENAME_VARIABLE_TITLE"] = "ⵙⵏⴼⵍ ⵉⵎⵙⴽⵉⵍⵏ ⴰⴽⴽ '%1' ⵖⵔ:";
Blockly.Msg["TEXT_APPEND_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated
Blockly.Msg["TEXT_APPEND_TITLE"] = "to %1 append text %2"; // untranslated
Blockly.Msg["TEXT_APPEND_TOOLTIP"] = "Append some text to variable '%1'."; // untranslated
Blockly.Msg["TEXT_CHANGECASE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#adjusting-text-case"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_LOWERCASE"] = "to lower case"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_TITLECASE"] = "to Title Case"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_UPPERCASE"] = "to UPPER CASE"; // untranslated
Blockly.Msg["TEXT_CHANGECASE_TOOLTIP"] = "Return a copy of the text in a different case."; // untranslated
Blockly.Msg["TEXT_CHARAT_FIRST"] = "get first letter"; // untranslated
Blockly.Msg["TEXT_CHARAT_FROM_END"] = "get letter # from end"; // untranslated
Blockly.Msg["TEXT_CHARAT_FROM_START"] = "get letter #"; // untranslated
Blockly.Msg["TEXT_CHARAT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-text"; // untranslated
Blockly.Msg["TEXT_CHARAT_LAST"] = "get last letter"; // untranslated
Blockly.Msg["TEXT_CHARAT_RANDOM"] = "get random letter"; // untranslated
Blockly.Msg["TEXT_CHARAT_TAIL"] = ""; // untranslated
Blockly.Msg["TEXT_CHARAT_TITLE"] = "in text %1 %2"; // untranslated
Blockly.Msg["TEXT_CHARAT_TOOLTIP"] = "Returns the letter at the specified position."; // untranslated
Blockly.Msg["TEXT_COUNT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#counting-substrings"; // untranslated
Blockly.Msg["TEXT_COUNT_MESSAGE0"] = "count %1 in %2"; // untranslated
Blockly.Msg["TEXT_COUNT_TOOLTIP"] = "Count how many times some text occurs within some other text."; // untranslated
Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TOOLTIP"] = "Add an item to the text."; // untranslated
Blockly.Msg["TEXT_CREATE_JOIN_TITLE_JOIN"] = "ⵍⴽⵎ";
Blockly.Msg["TEXT_CREATE_JOIN_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this text block."; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_END"] = "to letter # from end"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_START"] = "to letter #"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_END_LAST"] = "ⴰⵔ ⵓⵙⴽⴽⵉⵍ ⴰⵎⴳⴳⴰⵔⵓ";
Blockly.Msg["TEXT_GET_SUBSTRING_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_INPUT_IN_TEXT"] = "ⴳ ⵓⴹⵕⵉⵚ";
Blockly.Msg["TEXT_GET_SUBSTRING_START_FIRST"] = "get substring from first letter"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_END"] = "get substring from letter # from end"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_START"] = "get substring from letter #"; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_TAIL"] = ""; // untranslated
Blockly.Msg["TEXT_GET_SUBSTRING_TOOLTIP"] = "Returns a specified portion of the text."; // untranslated
Blockly.Msg["TEXT_INDEXOF_HELPURL"] = "https://github.com/google/blockly/wiki/Text#finding-text"; // untranslated
Blockly.Msg["TEXT_INDEXOF_OPERATOR_FIRST"] = "find first occurrence of text"; // untranslated
Blockly.Msg["TEXT_INDEXOF_OPERATOR_LAST"] = "find last occurrence of text"; // untranslated
Blockly.Msg["TEXT_INDEXOF_TITLE"] = "ⴳ ⵓⴹⵕⵉⵚ %1 %2 %3";
Blockly.Msg["TEXT_INDEXOF_TOOLTIP"] = "Returns the index of the first/last occurrence of the first text in the second text. Returns %1 if text is not found."; // untranslated
Blockly.Msg["TEXT_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Text#checking-for-empty-text"; // untranslated
Blockly.Msg["TEXT_ISEMPTY_TITLE"] = "%1 is empty"; // untranslated
Blockly.Msg["TEXT_ISEMPTY_TOOLTIP"] = "Returns true if the provided text is empty."; // untranslated
Blockly.Msg["TEXT_JOIN_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-creation"; // untranslated
Blockly.Msg["TEXT_JOIN_TITLE_CREATEWITH"] = "ⵙⵏⴼⵍⵓⵍ ⴰⴹⵕⵉⵚ ⵙ";
Blockly.Msg["TEXT_JOIN_TOOLTIP"] = "Create a piece of text by joining together any number of items."; // untranslated
Blockly.Msg["TEXT_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated
Blockly.Msg["TEXT_LENGTH_TITLE"] = "ⵜⵉⵖⵣⵉ %1";
Blockly.Msg["TEXT_LENGTH_TOOLTIP"] = "Returns the number of letters (including spaces) in the provided text."; // untranslated
Blockly.Msg["TEXT_PRINT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#printing-text"; // untranslated
Blockly.Msg["TEXT_PRINT_TITLE"] = "print %1"; // untranslated
Blockly.Msg["TEXT_PRINT_TOOLTIP"] = "Print the specified text, number or other value."; // untranslated
Blockly.Msg["TEXT_PROMPT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#getting-input-from-the-user"; // untranslated
Blockly.Msg["TEXT_PROMPT_TOOLTIP_NUMBER"] = "Prompt for user for a number."; // untranslated
Blockly.Msg["TEXT_PROMPT_TOOLTIP_TEXT"] = "Prompt for user for some text."; // untranslated
Blockly.Msg["TEXT_PROMPT_TYPE_NUMBER"] = "prompt for number with message"; // untranslated
Blockly.Msg["TEXT_PROMPT_TYPE_TEXT"] = "prompt for text with message"; // untranslated
Blockly.Msg["TEXT_REPLACE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#replacing-substrings"; // untranslated
Blockly.Msg["TEXT_REPLACE_MESSAGE0"] = "replace %1 with %2 in %3"; // untranslated
Blockly.Msg["TEXT_REPLACE_TOOLTIP"] = "Replace all occurances of some text within some other text."; // untranslated
Blockly.Msg["TEXT_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#reversing-text"; // untranslated
Blockly.Msg["TEXT_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated
Blockly.Msg["TEXT_REVERSE_TOOLTIP"] = "Reverses the order of the characters in the text."; // untranslated
Blockly.Msg["TEXT_TEXT_HELPURL"] = "https://en.wikipedia.org/wiki/String_(computer_science)"; // untranslated
Blockly.Msg["TEXT_TEXT_TOOLTIP"] = "A letter, word, or line of text."; // untranslated
Blockly.Msg["TEXT_TRIM_HELPURL"] = "https://github.com/google/blockly/wiki/Text#trimming-removing-spaces"; // untranslated
Blockly.Msg["TEXT_TRIM_OPERATOR_BOTH"] = "trim spaces from both sides of"; // untranslated
Blockly.Msg["TEXT_TRIM_OPERATOR_LEFT"] = "trim spaces from left side of"; // untranslated
Blockly.Msg["TEXT_TRIM_OPERATOR_RIGHT"] = "trim spaces from right side of"; // untranslated
Blockly.Msg["TEXT_TRIM_TOOLTIP"] = "Return a copy of the text with spaces removed from one or both ends."; // untranslated
Blockly.Msg["TODAY"] = "ⴰⵙⵙⴰ";
Blockly.Msg["UNDO"] = "ⵙⵔ";
Blockly.Msg["UNNAMED_KEY"] = "ⴰⵔⵉⵙⵎ";
Blockly.Msg["VARIABLES_DEFAULT_NAME"] = "ⴰⴼⵔⴷⵉⵙ";
Blockly.Msg["VARIABLES_GET_CREATE_SET"] = "Create 'set %1'"; // untranslated
Blockly.Msg["VARIABLES_GET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#get"; // untranslated
Blockly.Msg["VARIABLES_GET_TOOLTIP"] = "Returns the value of this variable."; // untranslated
Blockly.Msg["VARIABLES_SET"] = "set %1 to %2"; // untranslated
Blockly.Msg["VARIABLES_SET_CREATE_GET"] = "Create 'get %1'"; // untranslated
Blockly.Msg["VARIABLES_SET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#set"; // untranslated
Blockly.Msg["VARIABLES_SET_TOOLTIP"] = "Sets this variable to be equal to the input."; // untranslated
Blockly.Msg["VARIABLE_ALREADY_EXISTS"] = "A variable named '%1' already exists."; // untranslated
Blockly.Msg["VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE"] = "A variable named '%1' already exists for another type: '%2'."; // untranslated
Blockly.Msg["WORKSPACE_ARIA_LABEL"] = "Blockly Workspace"; // untranslated
Blockly.Msg["WORKSPACE_COMMENT_DEFAULT_TEXT"] = "Say something..."; // untranslated
Blockly.Msg["CONTROLS_FOREACH_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["CONTROLS_FOR_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["CONTROLS_IF_ELSEIF_TITLE_ELSEIF"] = Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"];
Blockly.Msg["CONTROLS_IF_ELSE_TITLE_ELSE"] = Blockly.Msg["CONTROLS_IF_MSG_ELSE"];
Blockly.Msg["CONTROLS_IF_IF_TITLE_IF"] = Blockly.Msg["CONTROLS_IF_MSG_IF"];
Blockly.Msg["CONTROLS_IF_MSG_THEN"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["CONTROLS_WHILEUNTIL_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
Blockly.Msg["LISTS_CREATE_WITH_ITEM_TITLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["LISTS_GET_INDEX_HELPURL"] = Blockly.Msg["LISTS_INDEX_OF_HELPURL"];
Blockly.Msg["LISTS_GET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["LISTS_GET_SUBLIST_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["LISTS_INDEX_OF_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["LISTS_SET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
Blockly.Msg["MATH_CHANGE_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["PROCEDURES_DEFRETURN_COMMENT"] = Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"];
Blockly.Msg["PROCEDURES_DEFRETURN_DO"] = Blockly.Msg["PROCEDURES_DEFNORETURN_DO"];
Blockly.Msg["PROCEDURES_DEFRETURN_PROCEDURE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"];
Blockly.Msg["PROCEDURES_DEFRETURN_TITLE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"];
Blockly.Msg["TEXT_APPEND_VARIABLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
Blockly.Msg["MATH_HUE"] = "230";
Blockly.Msg["LOOPS_HUE"] = "120";
Blockly.Msg["LISTS_HUE"] = "260";
Blockly.Msg["LOGIC_HUE"] = "210";
Blockly.Msg["VARIABLES_HUE"] = "330";
Blockly.Msg["TEXTS_HUE"] = "160";
Blockly.Msg["PROCEDURES_HUE"] = "290";
Blockly.Msg["COLOUR_HUE"] = "20";
Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";

574
package-lock.json generated
View File

@@ -213,18 +213,22 @@
}
},
"@blockly/block-test": {
"version": "1.0.14",
"resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-1.0.14.tgz",
"integrity": "sha512-vLvlrqTUHTXUTtGJg/xrcZ+Nlv+j+h+76Qq7XtQZk4U6Fp0zyc5Zm+vVv5wvtxmxx+50wk35gKkj514Qrgmlwg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-1.1.0.tgz",
"integrity": "sha512-CxIgs1R+7G4ulPf+Op6q3JzpDMVUvQ8vZBQsbarDyC4vFkie1wU1gF0sweobiSPi6TvhZKtLokj6PctuEiveeA==",
"dev": true
},
"@blockly/dev-tools": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-2.3.0.tgz",
"integrity": "sha512-1zHbPRLrJGjoPDO8N157esf6yfGYD3V30NpK8sEmItZLNaJkpg8Dn01rSasYAuuNPJuRLKM4q0miMDP/r8aLeg==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@blockly/dev-tools/-/dev-tools-2.4.0.tgz",
"integrity": "sha512-47bSJzuBl2I7oKeVcCAuwrGYsk7GbDCh2Vmy0rUnPE4S/J8otnA1DEHT6x1xzl/o7nNG0D76QE+hYAuFdgpxAQ==",
"dev": true,
"requires": {
"@blockly/block-test": "^1.0.14",
"@blockly/block-test": "^1.1.0",
"@blockly/theme-dark": "^2.0.0",
"@blockly/theme-deuteranopia": "^1.0.1",
"@blockly/theme-highcontrast": "^1.0.1",
"@blockly/theme-tritanopia": "^1.0.1",
"chai": "^4.2.0",
"dat.gui": "^0.7.7",
"lodash.assign": "^4.2.0",
@@ -234,35 +238,53 @@
},
"dependencies": {
"@blockly/block-test": {
"version": "1.0.14",
"resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-1.0.14.tgz",
"integrity": "sha512-vLvlrqTUHTXUTtGJg/xrcZ+Nlv+j+h+76Qq7XtQZk4U6Fp0zyc5Zm+vVv5wvtxmxx+50wk35gKkj514Qrgmlwg==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@blockly/block-test/-/block-test-1.1.0.tgz",
"integrity": "sha512-CxIgs1R+7G4ulPf+Op6q3JzpDMVUvQ8vZBQsbarDyC4vFkie1wU1gF0sweobiSPi6TvhZKtLokj6PctuEiveeA==",
"dev": true
}
}
},
"@blockly/theme-dark": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-1.0.7.tgz",
"integrity": "sha512-ohZRlrbKnRtzp63mDh/9XRFnTnnpyG110ff2UjGYmEuBcWeazgY1aISufrPbOANnPDfVV5SZI9DQnNvXjdmP9w==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-2.0.0.tgz",
"integrity": "sha512-7kGMYpHRQN94eXy98M+n3XeLDxEgMrGNYUuGiW/6j9PJeyKPf172oVG9qUz7mmdGK+zqe7wuVrJ+huHxKzNXog==",
"dev": true
},
"@blockly/theme-deuteranopia": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@blockly/theme-deuteranopia/-/theme-deuteranopia-1.0.1.tgz",
"integrity": "sha512-68dsW6YqDroT1Yz3pZRcC7DvsZL7Ae5XXFSGG6t/y2HceD5COoHdSaLssTReAhZdlO2lUQcyXVKMpns+R6GzWg==",
"dev": true
},
"@blockly/theme-highcontrast": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@blockly/theme-highcontrast/-/theme-highcontrast-1.0.1.tgz",
"integrity": "sha512-t3Ss8vLuxRAi9fxZ/gqJSAY82z/O+q2L9VFNTl80Yf3JgVMEwOB0kTnQettuBx9pMFKTBhlgrBB1L4UmWHx6Iw==",
"dev": true
},
"@blockly/theme-modern": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-2.1.17.tgz",
"integrity": "sha512-zVqZK0uX9mmyaAToovOkojyHH5o0JciJGKZdC2New6a2hilBCdOAaF36/xQpscaczMrNPiOpFJvtmbT4aM90rQ==",
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-2.1.18.tgz",
"integrity": "sha512-x7XVy8iNn8eykWAuWyasRkDgbGNW/BHs5ZYFfXhwdYcytJ76XlbqrOEzinNF6sApZWsm37Toe5rxJVUhBYnNGw==",
"dev": true
},
"@blockly/theme-tritanopia": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@blockly/theme-tritanopia/-/theme-tritanopia-1.0.1.tgz",
"integrity": "sha512-/EdNgcf/zSJjrOSzh5JIRBfIYiAQhApp6/Aq6xSqmid3qXChLllgCoSoHpktBD91qoJReHjN6WWOczeQHLMN0g==",
"dev": true
},
"@eslint/eslintrc": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
"integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==",
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz",
"integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
"debug": "^4.1.1",
"espree": "^7.3.0",
"globals": "^12.1.0",
"globals": "^13.9.0",
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
@@ -271,12 +293,12 @@
},
"dependencies": {
"globals": {
"version": "12.4.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
"integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
"version": "13.9.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz",
"integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
"type-fest": "^0.20.2"
}
}
}
@@ -414,6 +436,15 @@
"integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==",
"dev": true
},
"@types/fs-extra": {
"version": "9.0.11",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz",
"integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/http-cache-semantics": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
@@ -456,6 +487,15 @@
"@types/node": "*"
}
},
"@types/selenium-standalone": {
"version": "6.15.2",
"resolved": "https://registry.npmjs.org/@types/selenium-standalone/-/selenium-standalone-6.15.2.tgz",
"integrity": "sha512-Jnt4AHHcUOPGuZ5cJRYfP3IpPalNc/o1BmFvuFFmLtU2PtvEGvyyJPdpErqzZDxsP8E4yjTst0GL+QMJiEWuBA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/vinyl": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.4.tgz",
@@ -593,6 +633,316 @@
"@wdio/utils": "7.6.0"
}
},
"@wdio/selenium-standalone-service": {
"version": "6.12.1",
"resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-6.12.1.tgz",
"integrity": "sha512-9R5iTAb5p7XEWfn9WkiH8K3tgArmUJ0U3CcOQCeaHQBZks5DhNQv6ZQIodnIDyWHjoEfwnF9n+/UKsfPOk4rCQ==",
"dev": true,
"requires": {
"@types/fs-extra": "^9.0.1",
"@types/selenium-standalone": "^6.15.2",
"@wdio/config": "6.12.1",
"@wdio/logger": "6.10.10",
"fs-extra": "^9.0.1",
"selenium-standalone": "^6.22.1"
},
"dependencies": {
"@sindresorhus/is": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz",
"integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==",
"dev": true
},
"@szmarczak/http-timer": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
"integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==",
"dev": true,
"requires": {
"defer-to-connect": "^2.0.0"
}
},
"@wdio/config": {
"version": "6.12.1",
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.12.1.tgz",
"integrity": "sha512-V5hTIW5FNlZ1W33smHF4Rd5BKjGW2KeYhyXDQfXHjqLCeRiirZ9fABCo9plaVQDnwWSUMWYaAaIAifV82/oJCQ==",
"dev": true,
"requires": {
"@wdio/logger": "6.10.10",
"deepmerge": "^4.0.0",
"glob": "^7.1.2"
}
},
"@wdio/logger": {
"version": "6.10.10",
"resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-6.10.10.tgz",
"integrity": "sha512-2nh0hJz9HeZE0VIEMI+oPgjr/Q37ohrR9iqsl7f7GW5ik+PnKYCT9Eab5mR1GNMG60askwbskgGC1S9ygtvrSw==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"loglevel": "^1.6.0",
"loglevel-plugin-prefix": "^0.8.4",
"strip-ansi": "^6.0.0"
}
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"cacheable-request": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
"integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
"dev": true,
"requires": {
"clone-response": "^1.0.2",
"get-stream": "^5.1.0",
"http-cache-semantics": "^4.0.0",
"keyv": "^4.0.0",
"lowercase-keys": "^2.0.0",
"normalize-url": "^6.0.1",
"responselike": "^2.0.0"
}
},
"chalk": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dev": true,
"requires": {
"mimic-response": "^3.1.0"
}
},
"defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
"dev": true
},
"fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pump": "^3.0.0"
}
},
"got": {
"version": "11.8.2",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz",
"integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==",
"dev": true,
"requires": {
"@sindresorhus/is": "^4.0.0",
"@szmarczak/http-timer": "^4.0.5",
"@types/cacheable-request": "^6.0.1",
"@types/responselike": "^1.0.0",
"cacheable-lookup": "^5.0.3",
"cacheable-request": "^7.0.1",
"decompress-response": "^6.0.0",
"http2-wrapper": "^1.0.0-beta.5.2",
"lowercase-keys": "^2.0.0",
"p-cancelable": "^2.0.0",
"responselike": "^2.0.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true
},
"keyv": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz",
"integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==",
"dev": true,
"requires": {
"json-buffer": "3.0.1"
}
},
"lowercase-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
"dev": true
},
"mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"dev": true
},
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true
},
"normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
"dev": true
},
"p-cancelable": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
"dev": true
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"responselike": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
"integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
"dev": true,
"requires": {
"lowercase-keys": "^2.0.0"
}
},
"selenium-standalone": {
"version": "6.24.0",
"resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-6.24.0.tgz",
"integrity": "sha512-Dun2XgNAgCfJNrrSzuv7Z7Wj7QTvBKpqx0VXFz7bW9T9FUe5ytzgzoCEEshwDVMh0Dv6sCgdZg7VDhM/q2yPPQ==",
"dev": true,
"requires": {
"commander": "^2.20.3",
"cross-spawn": "^7.0.3",
"debug": "^4.3.1",
"got": "^11.8.2",
"lodash.mapvalues": "^4.6.0",
"lodash.merge": "^4.6.2",
"minimist": "^1.2.5",
"mkdirp": "^1.0.4",
"progress": "2.0.3",
"tar-stream": "2.2.0",
"which": "^2.0.2",
"yauzl": "^2.10.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true,
"requires": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
}
}
},
"@wdio/types": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.6.0.tgz",
@@ -1146,6 +1496,12 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
"dev": true
},
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -1746,9 +2102,9 @@
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
},
"component-emitter": {
@@ -2517,13 +2873,13 @@
}
},
"eslint": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.27.0.tgz",
"integrity": "sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz",
"integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==",
"dev": true,
"requires": {
"@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.4.1",
"@eslint/eslintrc": "^0.4.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -2540,7 +2896,7 @@
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
"glob-parent": "^5.1.2",
"globals": "^13.6.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
@@ -2573,18 +2929,18 @@
}
},
"@babel/helper-validator-identifier": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz",
"integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==",
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
"dev": true
},
"@babel/highlight": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz",
"integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==",
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.14.0",
"@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
},
@@ -2766,12 +3122,6 @@
"requires": {
"prelude-ls": "^1.2.1"
}
},
"type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
}
}
},
@@ -4066,9 +4416,9 @@
"optional": true
},
"google-closure-deps": {
"version": "20210406.0.0",
"resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20210406.0.0.tgz",
"integrity": "sha512-4mn6qZ8u4c/9fhebKccxyN882l5/0O4nuJ+ibuxDy0y7XMgolSLNF/Gmg1HEhEgX00CF/JBKrc/rw0WVjnlSfw==",
"version": "20210601.0.0",
"resolved": "https://registry.npmjs.org/google-closure-deps/-/google-closure-deps-20210601.0.0.tgz",
"integrity": "sha512-ko3PUEDkFosckQPGqBx3f1jjHcyPbzDGvLCMB9rmYOGkvyvRsmABgJovFg1CpKLVlw10nuRXPWoyupEqH0hssQ==",
"dev": true,
"requires": {
"minimatch": "^3.0.4",
@@ -4887,6 +5237,12 @@
"isobject": "^3.0.1"
}
},
"is-port-reachable": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.0.0.tgz",
"integrity": "sha512-056IzLiWHdgVd6Eq1F9HtJl+cIkvi5X2MJ/A1fjQtByHkzQE1wGardnPhqrarOGDF88BOW+297X7PDvZ2vcyVg==",
"dev": true
},
"is-promise": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
@@ -7086,9 +7442,9 @@
}
},
"regexpp": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
"dev": true
},
"registry-auth-token": {
@@ -7404,29 +7760,31 @@
}
},
"selenium-standalone": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-6.23.0.tgz",
"integrity": "sha512-6dVLSEvbixd/MRSEmrcRQD8dmABrzNsxRqroKFQY+RVzm1JVPgGHIlo6qJzG6akfjc2V8SadHslE6lN4BFVM3w==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-7.1.0.tgz",
"integrity": "sha512-Pc7U48qwB4LVy/XczBrPPXwUhEPl3XQSik8SjLfj2qzBEtZqrjyzOlnnXq4aVCdr5wH9FiFJm8LwheJbK2+/oQ==",
"dev": true,
"requires": {
"commander": "^2.20.3",
"commander": "^7.2.0",
"cross-spawn": "^7.0.3",
"debug": "^4.3.1",
"got": "^11.8.0",
"fs-extra": "^10.0.0",
"got": "^11.8.2",
"is-port-reachable": "^3.0.0",
"lodash.mapvalues": "^4.6.0",
"lodash.merge": "^4.6.2",
"minimist": "^1.2.5",
"mkdirp": "^1.0.4",
"progress": "2.0.3",
"tar-stream": "2.1.4",
"tar-stream": "2.2.0",
"which": "^2.0.2",
"yauzl": "^2.10.0"
},
"dependencies": {
"@sindresorhus/is": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz",
"integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz",
"integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==",
"dev": true
},
"@szmarczak/http-timer": {
@@ -7439,9 +7797,9 @@
}
},
"cacheable-request": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
"integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
"integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
"dev": true,
"requires": {
"clone-response": "^1.0.2",
@@ -7449,21 +7807,10 @@
"http-cache-semantics": "^4.0.0",
"keyv": "^4.0.0",
"lowercase-keys": "^2.0.0",
"normalize-url": "^4.1.0",
"normalize-url": "^6.0.1",
"responselike": "^2.0.0"
}
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@@ -7483,9 +7830,9 @@
}
},
"defer-to-connect": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz",
"integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
"dev": true
},
"get-stream": {
@@ -7498,9 +7845,9 @@
}
},
"got": {
"version": "11.8.0",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz",
"integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==",
"version": "11.8.2",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz",
"integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==",
"dev": true,
"requires": {
"@sindresorhus/is": "^4.0.0",
@@ -7549,18 +7896,29 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true
},
"p-cancelable": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz",
"integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==",
"normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
"dev": true
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"p-cancelable": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
"dev": true
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"responselike": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
@@ -7570,21 +7928,19 @@
"lowercase-keys": "^2.0.0"
}
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -8194,9 +8550,9 @@
},
"dependencies": {
"ajv": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz",
"integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==",
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz",
"integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@@ -8528,9 +8884,9 @@
"dev": true
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
},
"typedarray": {
@@ -8539,6 +8895,12 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typescript": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
"dev": true
},
"typescript-closure-tools": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/typescript-closure-tools/-/typescript-closure-tools-0.0.7.tgz",

View File

@@ -45,12 +45,8 @@
"publish:beta": "gulp publishBeta",
"recompile": "gulp recompile",
"release": "gulp gitCreateRC",
"test": "concurrently 'npm run test:prepare' 'sleep 5 && npm run test:run'",
"test:generators": "concurrently 'npm run test:prepare' 'sleep 5 && tests/scripts/run_generators.sh'",
"test:prepare": "npm run test:setupselenium && npm run test:startselenium",
"test:run": "tests/run_all_tests.sh",
"test:setupselenium": "selenium-standalone install --config=./tests/scripts/selenium-config.js",
"test:startselenium": "selenium-standalone start --config=./tests/scripts/selenium-config.js",
"test": "tests/run_all_tests.sh",
"test:generators": "tests/scripts/run_generators.sh",
"test:compile:advanced": "gulp buildAdvancedCompilationTest",
"typings": "gulp typings",
"updateGithubPages": "gulp gitUpdateGithubPages"
@@ -68,15 +64,15 @@
"devDependencies": {
"@blockly/block-test": "^1.0.0",
"@blockly/dev-tools": "^2.0.1",
"@blockly/theme-dark": "^1.0.0",
"@blockly/theme-modern": "^2.1.1",
"@wdio/selenium-standalone-service": "^6.11.0",
"babel-eslint": "^10.1.0",
"chai": "^4.2.0",
"clang-format": "^1.5.0",
"concurrently": "^6.0.0",
"eslint": "^7.6.0",
"eslint": "^7.28.0",
"google-closure-compiler": "^20210505.0.0",
"google-closure-deps": "^20210406.0.0",
"google-closure-deps": "^20210601.0.0",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-insert": "^0.5.0",
@@ -90,8 +86,9 @@
"mocha": "^8.1.1",
"readline-sync": "^1.4.10",
"rimraf": "^3.0.2",
"selenium-standalone": "^6.17.0",
"selenium-standalone": "^7.1.0",
"through2": "^4.0.2",
"typescript": "^4.3.2",
"typescript-closure-tools": "^0.0.7",
"webdriverio": "^7.0.3",
"yargs": "^16.0.3"

View File

@@ -59,7 +59,6 @@ function copyAppengineSrc() {
function copyPlaygroundDeps() {
const playgroundDeps = [
'./node_modules/@blockly/dev-tools/dist/index.js',
'./node_modules/@blockly/theme-dark/dist/index.js',
'./node_modules/@blockly/theme-modern/dist/index.js',
'./node_modules/@blockly/block-test/dist/index.js',
];

View File

@@ -32,22 +32,26 @@ async function runLangGeneratorInBrowser(browser, filename, codegenFn) {
}
/**
* Runs the generator tests in Firefox. It uses webdriverio to
* launch Firefox and load index.html. Outputs a summary of the test results
* Runs the generator tests in Chrome. It uses webdriverio to
* launch Chrome and load index.html. Outputs a summary of the test results
* to the console and outputs files for later validation.
* @return the Thenable managing the processing of the browser tests.
*/
async function runGeneratorsInBrowser() {
var options = {
capabilities: {
browserName: 'firefox'
browserName: 'chrome',
},
path: '/wd/hub'
services: ['selenium-standalone']
};
// Run in headless mode on Github Actions.
if (process.env.CI) {
options.capabilities['moz:firefoxOptions'] = {
args: ['-headless']
options.capabilities['goog:chromeOptions'] = {
args: ['--headless', '--no-sandbox', '--disable-dev-shm-usage', '--allow-file-access-from-files']
};
} else {
options.capabilities['goog:chromeOptions'] = {
args: ['--allow-file-access-from-files']
};
}

View File

@@ -21,7 +21,7 @@
"assertVariableValues": true,
"assertNoWarnings": true,
"assertWarnings": true,
"captureWarnings": true,
"captureWarnings": false,
"createDeprecationWarningStub": true,
"createKeyDownEvent": true,
"createRenderedBlock": true,

View File

@@ -1104,6 +1104,61 @@ suite('Blocks', function() {
});
});
});
suite('Getting/Setting Field (Values)', function() {
setup(function() {
this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="text"><field name = "TEXT">test</field></block>'
), this.workspace);
});
test('Getting Field', function() {
chai.assert.instanceOf(this.block.getField('TEXT'), Blockly.Field);
});
test('Getting Field without Name', function() {
chai.assert.throws(this.block.getField.bind(this.block), TypeError);
});
test('Getting Value of Field without Name', function() {
chai.assert.throws(this.block.getFieldValue.bind(this.block), TypeError);
});
test('Getting Field with Wrong Type', function() {
var testFunction = function() {
return 'TEXT';
};
var inputs = [1, null, testFunction, {toString: testFunction}, ['TEXT']];
for (var i = 0; i < inputs.length; i++) {
chai.assert.throws(this.block.getField.bind(this.block, inputs[i]),
TypeError);
}
});
test('Getting Value of Field with Wrong Type', function() {
var testFunction = function() {
return 'TEXT';
};
var inputs = [1, null, testFunction, {toString: testFunction}, ['TEXT']];
for (var i = 0; i < inputs.length; i++) {
chai.assert.throws(
this.block.getFieldValue.bind(this.block, inputs[i]), TypeError);
}
});
test('Getting/Setting Field Value', function() {
chai.assert.equal(this.block.getFieldValue('TEXT'), 'test');
this.block.setFieldValue('abc', 'TEXT');
chai.assert.equal(this.block.getFieldValue('TEXT'), 'abc');
});
test('Setting Field without Name', function() {
chai.assert.throws(this.block.setFieldValue.bind(this.block, 'test'));
});
test('Setting Field with Wrong Type', function() {
var testFunction = function() {
return 'TEXT';
};
var inputs = [1, null, testFunction, {toString: testFunction}, ['TEXT']];
for (var i = 0; i < inputs.length; i++) {
chai.assert.throws(this.block.setFieldValue.bind(this.block, 'test',
inputs[i]), TypeError);
}
});
});
suite('Icon Management', function() {
suite('Bubbles and Collapsing', function() {
setup(function() {

View File

@@ -782,329 +782,6 @@ suite('Connection', function() {
});
});
suite('getConnectionForOrphanedOutput', function() {
setup(function() {
this.workspace = new Blockly.Workspace();
Blockly.defineBlocksWithJsonArray([
{
'type': 'input',
'message0': '%1',
'args0': [
{
'type': 'input_value',
'name': 'INPUT',
'check': 'check'
}
],
},
{
'type': 'output',
'message0': '',
'output': 'check',
},
]);
});
teardown(function() {
workspaceTeardown.call(this, this.workspace);
});
suite('No available spots', function() {
setup(function() {
Blockly.defineBlocksWithJsonArray([
{
'type': 'output_and_statements',
'message0': '%1 %2',
'args0': [
{
'type': 'input_statement',
'name': 'INPUT',
'check': 'check'
},
{
'type': 'input_statement',
'name': 'INPUT2',
'check': 'check'
}
],
'output': 'check',
},
{
'type': 'output_and_inputs',
'message0': '%1 %2',
'args0': [
{
'type': 'input_value',
'name': 'INPUT',
'check': 'check2'
},
{
'type': 'input_value',
'name': 'INPUT2',
'check': 'check2'
}
],
'output': 'check',
},
{
'type': 'check_to_check2',
'message0': '%1',
'args0': [
{
'type': 'input_value',
'name': 'INPUT',
'check': 'check2'
},
],
'output': 'check',
},
{
'type': 'check2_to_check',
'message0': '%1',
'args0': [
{
'type': 'input_value',
'name': 'CHECK2TOCHECKINPUT',
'check': 'check'
},
],
'output': 'check2',
},
]);
});
test('No connection', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('output');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('All statements', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('output_and_statements');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('Bad checks', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('output_and_inputs');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('Through different types', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('check_to_check2');
const otherChild = this.workspace.newBlock('check2_to_check');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection
.connect(otherChild.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
});
suite('Multiple available spots', function() {
setup(function() {
Blockly.defineBlocksWithJsonArray([
{
'type': 'multiple_inputs',
'message0': '%1 %2',
'args0': [
{
'type': 'input_value',
'name': 'INPUT',
'check': 'check'
},
{
'type': 'input_value',
'name': 'INPUT2',
'check': 'check'
},
],
'output': 'check',
},
{
'type': 'single_input',
'message0': '%1',
'args0': [
{
'type': 'input_value',
'name': 'INPUT',
'check': 'check'
},
],
'output': 'check',
},
]);
});
suite('No shadows', function() {
test('Top block', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('multiple_inputs');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('Child blocks', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('multiple_inputs');
const childX = this.workspace.newBlock('single_input');
const childY = this.workspace.newBlock('single_input');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection.connect(childX.outputConnection);
oldChild.getInput('INPUT2').connection.connect(childY.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('Spots filled', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('multiple_inputs');
const otherChild = this.workspace.newBlock('output');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection
.connect(otherChild.outputConnection);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
});
suite('Shadows', function() {
test('Top block', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('multiple_inputs');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="output"/></xml>')
.firstChild);
oldChild.getInput('INPUT2').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="output"/></xml>')
.firstChild);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('Child blocks', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('multiple_inputs');
const childX = this.workspace.newBlock('single_input');
const childY = this.workspace.newBlock('single_input');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection.connect(childX.outputConnection);
oldChild.getInput('INPUT2').connection.connect(childY.outputConnection);
childX.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="output"/></xml>')
.firstChild);
childY.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="output"/></xml>')
.firstChild);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
test('Spots filled', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('multiple_inputs');
const otherChild = this.workspace.newBlock('output');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection
.connect(otherChild.outputConnection);
oldChild.getInput('INPUT2').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="output"/></xml>')
.firstChild);
chai.assert.notExists(
Blockly.Connection.getConnectionForOrphanedOutput(oldChild, newChild));
});
});
});
suite('Single available spot', function() {
setup(function() {
Blockly.defineBlocksWithJsonArray([
{
'type': 'single_input',
'message0': '%1',
'args0': [
{
'type': 'input_value',
'name': 'INPUT',
'check': 'check'
},
],
'output': 'check',
},
]);
});
test('No shadows', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('single_input');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
const result = Blockly.Connection
.getConnectionForOrphanedOutput(oldChild, newChild);
chai.assert.exists(result);
chai.assert.equal(result.getParentInput().name, 'INPUT');
});
test('Shadows', function() {
const parent = this.workspace.newBlock('input');
const oldChild = this.workspace.newBlock('single_input');
const newChild = this.workspace.newBlock('output');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
oldChild.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="output"/></xml>')
.firstChild);
const result = Blockly.Connection
.getConnectionForOrphanedOutput(oldChild, newChild);
chai.assert.exists(result);
chai.assert.equal(result.getParentInput().name, 'INPUT');
});
});
});
suite('Connect', function() {
setup(function() {
this.workspace = new Blockly.Workspace();
@@ -1185,6 +862,40 @@ suite('Connection', function() {
"message0": "",
"output": 'check1'
},
{
"type": "row_block_multiple_inputs",
"message0": "%1 %2",
"args0": [
{
"type": "input_value",
"name": "INPUT",
"check": 'check1'
},
{
"type": "input_value",
"name": "INPUT2",
"check": 'check1'
}
],
"output": 'check1'
},
{
'type': 'output_to_statements',
'message0': '%1 %2',
'args0': [
{
'type': 'input_statement',
'name': 'INPUT',
'check': 'check1'
},
{
'type': 'input_statement',
'name': 'INPUT2',
'check': 'check1'
}
],
'output': 'check1',
},
{
"type": "statement_block",
"message0": "%1 %2",
@@ -1401,42 +1112,288 @@ suite('Connection', function() {
suite('Reattach or bump orphan', function() {
suite('Value', function() {
// Only one test for this b/c tested by getConnectionForOrphanedOutput.
test('Simple', function() {
var parent = this.workspace.newBlock('row_block');
var oldChild = this.workspace.newBlock('row_block');
var newChild = this.workspace.newBlock('row_block');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
var spy = sinon.spy(
Blockly.Connection, 'getConnectionForOrphanedOutput');
suite('No available spots', function() {
test('No connection', function() {
var parent = this.workspace.newBlock('row_block');
var oldChild = this.workspace.newBlock('row_block');
var newChild = this.workspace.newBlock('row_block_noend');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
parent.getInput('INPUT').connection.connect(newChild.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isTrue(newChild.getInput('INPUT').connection.isConnected());
chai.assert.equal(newChild.getInputTargetBlock('INPUT'), oldChild);
// Make sure it is actually getting called, so all functionality has
// been tested.
// Future people: if you ever stop calling this function you need to
// add more tests for reattaching orphans.
chai.assert.isTrue(spy.calledOnce);
this.assertBlockCount(3);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('All statements', function() {
var parent = this.workspace.newBlock('row_block');
var oldChild = this.workspace.newBlock('row_block');
var newChild = this.workspace.newBlock('output_to_statements');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('Bad checks', function() {
var parent = this.workspace.newBlock('row_block');
var oldChild = this.workspace.newBlock('row_block');
var newChild = this.workspace.newBlock('row_block_2to1');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('Through different types', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock('row_block_2to1');
const otherChild = this.workspace.newBlock('row_block_1to2');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection
.connect(otherChild.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
});
test('Bump', function() {
var parent = this.workspace.newBlock('row_block');
var oldChild = this.workspace.newBlock('row_block');
var newChild = this.workspace.newBlock('row_block_noend');
parent.getInput('INPUT').connection.connect(oldChild.outputConnection);
var spy = sinon.spy(oldChild.outputConnection, 'onFailedConnect');
suite('Multiple available spots', function() {
suite('No shadows', function() {
test('Top block', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock(
'row_block_multiple_inputs');
parent.getInput('INPUT').connection.connect(newChild.outputConnection);
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
chai.assert.isTrue(parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isTrue(spy.calledOnce);
this.assertBlockCount(3);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('Child blocks', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock(
'row_block_multiple_inputs');
const childX = this.workspace.newBlock('row_block');
const childY = this.workspace.newBlock('row_block');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection
.connect(childX.outputConnection);
newChild.getInput('INPUT2').connection
.connect(childY.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('Spots filled', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock(
'row_block_multiple_inputs');
const otherChild = this.workspace.newBlock('row_block_noend');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection
.connect(otherChild.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
});
suite('Shadows', function() {
test('Top block', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock(
'row_block_multiple_inputs');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="row_block"/></xml>')
.firstChild);
newChild.getInput('INPUT2').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="row_block"/></xml>')
.firstChild);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('Child blocks', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock(
'row_block_multiple_inputs');
const childX = this.workspace.newBlock('row_block');
const childY = this.workspace.newBlock('row_block');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection
.connect(childX.outputConnection);
newChild.getInput('INPUT2').connection
.connect(childY.outputConnection);
childX.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="row_block"/></xml>')
.firstChild);
childY.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="row_block"/></xml>')
.firstChild);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
test('Spots filled', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock(
'row_block_multiple_inputs');
const otherChild = this.workspace.newBlock('row_block_noend');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection
.connect(otherChild.outputConnection);
newChild.getInput('INPUT2').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="row_block"/></xml>')
.firstChild);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isFalse(
oldChild.outputConnection.isConnected());
});
});
});
suite('Single available spot', function() {
test('No shadows', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock('row_block');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isTrue(
newChild.getInput('INPUT').connection.isConnected());
chai.assert.equal(
newChild.getInputTargetBlock('INPUT'), oldChild);
});
test('Shadows', function() {
const parent = this.workspace.newBlock('row_block');
const oldChild = this.workspace.newBlock('row_block');
const newChild = this.workspace.newBlock('row_block');
parent.getInput('INPUT').connection
.connect(oldChild.outputConnection);
newChild.getInput('INPUT').connection.setShadowDom(
Blockly.Xml.textToDom('<xml><shadow type="row_block"/></xml>')
.firstChild);
parent.getInput('INPUT').connection
.connect(newChild.outputConnection);
chai.assert.isTrue(
parent.getInput('INPUT').connection.isConnected());
chai.assert.equal(
parent.getInputTargetBlock('INPUT'), newChild);
chai.assert.isTrue(
newChild.getInput('INPUT').connection.isConnected());
chai.assert.equal(
newChild.getInputTargetBlock('INPUT'), oldChild);
});
});
});

View File

@@ -101,7 +101,7 @@ suite('Colour Fields', function() {
testHelpers.runFromJsonSuiteTests(
Blockly.FieldColour, validValueTestCases,invalidValueTestCases,
validTestCaseAssertField, assertFieldDefault);
suite('setValue', function() {
suite('Empty -> New Value', function() {
setup(function() {
@@ -165,9 +165,9 @@ suite('Colour Fields', function() {
suite('Customizations', function() {
suite('Colours and Titles', function() {
function assertColoursAndTitles(field, colours, titles) {
var editor = field.dropdownCreate_();
field.dropdownCreate_();
var index = 0;
var node = editor.firstChild.firstChild;
var node = field.picker_.firstChild.firstChild;
while (node) {
chai.assert.equal(node.getAttribute('title'), titles[index]);
chai.assert.equal(
@@ -243,8 +243,8 @@ suite('Colour Fields', function() {
});
suite('Columns', function() {
function assertColumns(field, columns) {
var editor = field.dropdownCreate_();
chai.assert.equal(editor.firstChild.children.length, columns);
field.dropdownCreate_();
chai.assert.equal(field.picker_.firstChild.children.length, columns);
}
test('Constants', function() {
var columns = Blockly.FieldColour.COLUMNS;

View File

@@ -85,7 +85,7 @@ suite('Registry', function() {
test('Incorrect Plugin Name', function() {
this.options['plugins']['test'] = 'random';
var testClass;
var warnings = captureWarnings(() => {
var warnings = testHelpers.captureWarnings(() => {
testClass = Blockly.registry.getClassFromOptions('test', this.options);
});
chai.assert.isNull(testClass);

View File

@@ -22,7 +22,9 @@ async function runMochaTestsInBrowser() {
capabilities: {
browserName: 'chrome'
},
path: '/wd/hub'
services: [
['selenium-standalone']
]
};
// Run in headless mode on Github Actions.
if (process.env.CI) {

View File

@@ -20,25 +20,6 @@ function assertVariableValues(container, name, type, id) {
chai.assert.equal(variable.getId(), id);
}
/**
* Captures the strings sent to console.warn() when calling a function.
* @param {function} innerFunc The function where warnings may called.
* @return {string[]} The warning messages (only the first arguments).
*/
function captureWarnings(innerFunc) {
var msgs = [];
var nativeConsoleWarn = console.warn;
try {
console.warn = function(msg) {
msgs.push(msg);
};
innerFunc();
} finally {
console.warn = nativeConsoleWarn;
}
return msgs;
}
/**
* Asserts that the given function logs the provided warning messages.
* @param {function} innerFunc The function to call.
@@ -49,7 +30,7 @@ function assertWarnings(innerFunc, messages) {
if (!Array.isArray(messages)) {
messages = [messages];
}
var warnings = captureWarnings(innerFunc);
var warnings = testHelpers.captureWarnings(innerFunc);
chai.assert.lengthOf(warnings, messages.length);
messages.forEach((message, i) => {
chai.assert.match(warnings[i], message);

View File

@@ -1303,7 +1303,7 @@ function testAWorkspace() {
this.workspace.createVariable('name1', 'type1', 'id1');
this.workspace.deleteVariableById('id1');
var workspace = this.workspace;
var warnings = captureWarnings(function() {
var warnings = testHelpers.captureWarnings(function() {
workspace.deleteVariableById('id1');
});
chai.assert.equal(warnings.length, 1,
@@ -1332,7 +1332,7 @@ function testAWorkspace() {
createVarBlocksNoEvents(this.workspace, ['id1']);
this.workspace.deleteVariableById('id1');
var workspace = this.workspace;
var warnings = captureWarnings(function() {
var warnings = testHelpers.captureWarnings(function() {
workspace.deleteVariableById('id1');
});
chai.assert.equal(warnings.length, 1,

View File

@@ -67,7 +67,6 @@
<script src="../themes/test_themes.js"></script>
<script src="./screenshot.js"></script>
<script src="../../node_modules/@blockly/dev-tools/dist/index.js"></script>
<script src="../../node_modules/@blockly/theme-dark/dist/index.js"></script>
<script src="../../node_modules/@blockly/theme-modern/dist/index.js"></script>
<script>