From 4fca16730cd8e9fed77138afb47b74a9555fa5bb Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Fri, 5 Apr 2019 11:59:05 -0700 Subject: [PATCH 001/233] core/generator.js --- core/generator.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/generator.js b/core/generator.js index b5a79495901..dfe385f7c52 100644 --- a/core/generator.js +++ b/core/generator.js @@ -275,6 +275,8 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { /** * Generate code representing the statement. Indent the code. + * This is mainly used in generators. When trying to generate code to run look + * at using workspaceToCode and blockToCode. * @param {!Blockly.Block} block The block containing the input. * @param {string} name The name of the input. * @return {string} Generated code or '' if no blocks are connected. From 97d670c0ea1a1c3af742ad9faf187cf64d2e1c02 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Fri, 5 Apr 2019 12:00:04 -0700 Subject: [PATCH 002/233] Updates documentation --- core/generator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/generator.js b/core/generator.js index dfe385f7c52..6244c06a615 100644 --- a/core/generator.js +++ b/core/generator.js @@ -275,8 +275,8 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { /** * Generate code representing the statement. Indent the code. - * This is mainly used in generators. When trying to generate code to run look - * at using workspaceToCode and blockToCode. + * This is mainly used in generators. When trying to generate code to evaluate + * look at using workspaceToCode and blockToCode. * @param {!Blockly.Block} block The block containing the input. * @param {string} name The name of the input. * @return {string} Generated code or '' if no blocks are connected. From 98a1c06e7a681cfc0b8dd591daa7a0750cdc7522 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 8 Apr 2019 10:48:22 -0700 Subject: [PATCH 003/233] Changed jsdoc --- core/generator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/generator.js b/core/generator.js index 6244c06a615..ae669964ee1 100644 --- a/core/generator.js +++ b/core/generator.js @@ -276,7 +276,7 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { /** * Generate code representing the statement. Indent the code. * This is mainly used in generators. When trying to generate code to evaluate - * look at using workspaceToCode and blockToCode. + * look at using workspaceToCode or blockToCode. * @param {!Blockly.Block} block The block containing the input. * @param {string} name The name of the input. * @return {string} Generated code or '' if no blocks are connected. From daf59f6659bcbf0036204092b19e19cac3d3db53 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 11 Apr 2019 17:41:49 +0200 Subject: [PATCH 004/233] Localisation updates from https://translatewiki.net. --- msg/json/de.json | 4 ++-- msg/json/qqq.json | 9 +++++++++ msg/json/th.json | 6 ++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/msg/json/de.json b/msg/json/de.json index 3a115722caa..14e38dbff27 100644 --- a/msg/json/de.json +++ b/msg/json/de.json @@ -51,13 +51,13 @@ "COLOUR_PICKER_TOOLTIP": "Wählt eine Farbe aus der Palette aus.", "COLOUR_RANDOM_TITLE": "zufällige Farbe", "COLOUR_RANDOM_TOOLTIP": "Erzeugt eine Farbe nach dem Zufallsprinzip.", - "COLOUR_RGB_HELPURL": "https://de.wikipedia.org/wiki/RGB-Farbraum", + "COLOUR_RGB_HELPURL": "https://www.december.com/html/spec/colorpercompact.html", "COLOUR_RGB_TITLE": "Farbe aus", "COLOUR_RGB_RED": "rot", "COLOUR_RGB_GREEN": "grün", "COLOUR_RGB_BLUE": "blau", "COLOUR_RGB_TOOLTIP": "Erzeugt eine Farbe mit selbst definierten Rot-, Grün- und Blauwerten. Alle Werte müssen zwischen 0 und 100 liegen.", - "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", + "COLOUR_BLEND_HELPURL": "https://meyerweb.com/eric/tools/color-blend/#:::rgbp", "COLOUR_BLEND_TITLE": "mische", "COLOUR_BLEND_COLOUR1": "Farbe 1", "COLOUR_BLEND_COLOUR2": "und Farbe 2", diff --git a/msg/json/qqq.json b/msg/json/qqq.json index 0465e4ffd1b..b758cea7a13 100644 --- a/msg/json/qqq.json +++ b/msg/json/qqq.json @@ -1,4 +1,13 @@ { + "@metadata": { + "authors": [ + "Espertus", + "Liuxinyu970226", + "Metalhead64", + "Robby", + "Shirayuki" + ] + }, "VARIABLES_DEFAULT_NAME": "default name - A simple, general default name for a variable, preferably short. For more context, see [[Translating:Blockly#infrequent_message_types]].\n{{Identical|Item}}", "TODAY": "button text - Button that sets a calendar to today's date.\n{{Identical|Today}}", "DUPLICATE_BLOCK": "context menu - Make a copy of the selected block (and any blocks it contains).\n{{Identical|Duplicate}}", diff --git a/msg/json/th.json b/msg/json/th.json index dabaeb80899..6e6e8681e2e 100644 --- a/msg/json/th.json +++ b/msg/json/th.json @@ -6,7 +6,8 @@ "Horus", "Roysheng", "Aefgh39622", - "Nantapat" + "Nantapat", + "Trisorn Triboon" ] }, "VARIABLES_DEFAULT_NAME": "รายการ", @@ -14,6 +15,7 @@ "DUPLICATE_BLOCK": "ทำสำเนา", "ADD_COMMENT": "ใส่คำอธิบาย", "REMOVE_COMMENT": "เอาคำอธิบายออก", + "DUPLICATE_COMMENT": "ทำสำเนาความเห็น", "EXTERNAL_INPUTS": "อินพุตภายนอก", "INLINE_INPUTS": "อินพุตในบรรทัด", "DELETE_BLOCK": "ลบบล็อก", @@ -59,7 +61,7 @@ "COLOUR_BLEND_TOOLTIP": "ผสมสองสีเข้าด้วยกันด้วยอัตราส่วน (0.0 - 1.0)", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "ทำซ้ำ %1 ครั้ง", - "CONTROLS_REPEAT_INPUT_DO": "ทำ:", + "CONTROLS_REPEAT_INPUT_DO": "ทำ", "CONTROLS_REPEAT_TOOLTIP": "ทำซ้ำบางคำสั่งหลายครั้ง", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ทำซ้ำขณะที่", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ทำซ้ำจนกระทั่ง", From be4da5feeb0b04668dae86b3f76606418543f36d Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Thu, 11 Apr 2019 11:43:37 -0700 Subject: [PATCH 005/233] Reverts hideChaff fix --- core/inject.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/inject.js b/core/inject.js index 65a54332e42..57d2a13b402 100644 --- a/core/inject.js +++ b/core/inject.js @@ -420,11 +420,6 @@ Blockly.init_ = function(mainWorkspace) { */ Blockly.inject.bindDocumentEvents_ = function() { if (!Blockly.documentEventsBound_) { - document.addEventListener('mouseup', function() { - Blockly.hideChaff(); - Blockly.Touch.clearTouchIdentifier(); // Don't block future drags. - }, false); - Blockly.bindEventWithChecks_(document, 'scroll', null, function() { var workspaces = Blockly.Workspace.getAll(); for (var i = 0, workspace; workspace = workspaces[i]; i++) { From 8c99cccbc337fd31e35cf69b46a67630787a0048 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Sat, 13 Apr 2019 20:30:56 -0700 Subject: [PATCH 006/233] Degree symbol left of number in both LTR and RTL. Resolves issue #2380. --- core/field_angle.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index bf9d6b81f45..f776d0a951a 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -127,11 +127,8 @@ Blockly.FieldAngle.prototype.render_ = function() { this.textElement_.textContent = this.getDisplayText_(); // Insert degree symbol. - if (this.sourceBlock_.RTL) { - this.textElement_.insertBefore(this.symbol_, this.textElement_.firstChild); - } else { - this.textElement_.appendChild(this.symbol_); - } + // Degree symbol should be left of number, even in RTL (issue #2380). + this.textElement_.appendChild(this.symbol_); this.updateWidth(); }; From fd4bbe035cc61c89762f01385becf21dad202d1a Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 15 Apr 2019 17:31:58 +0200 Subject: [PATCH 007/233] Localisation updates from https://translatewiki.net. --- msg/json/br.json | 3 +- msg/json/ee.json | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 msg/json/ee.json diff --git a/msg/json/br.json b/msg/json/br.json index e12d972232d..2d8c0738890 100644 --- a/msg/json/br.json +++ b/msg/json/br.json @@ -348,5 +348,6 @@ "PROCEDURES_CREATE_DO": "Krouiñ '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Ma'z eo gwir un dalvoudenn, distreiñ un eil talvoudenn neuze.", "PROCEDURES_IFRETURN_WARNING": "Diwallit : Gallout a rafe ar bloc'h bezañ implijet e termenadur un arc'hwel hepken.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Lavaret un dra bennak..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Lavaret un dra bennak...", + "COLLAPSED_WARNINGS_WARNING": "Kemennoù-diwall zo er bloc'hadoù pleget." } diff --git a/msg/json/ee.json b/msg/json/ee.json new file mode 100644 index 00000000000..b5e45f101ea --- /dev/null +++ b/msg/json/ee.json @@ -0,0 +1,141 @@ +{ + "@metadata": { + "authors": [ + "Aguve", + "Apequm" + ] + }, + "VARIABLES_DEFAULT_NAME": "nu", + "TODAY": "Egbe", + "DUPLICATE_BLOCK": "Gbugbɔe Wɔ", + "ADD_COMMENT": "Ŋlɔ Numeɖeɖe", + "REMOVE_COMMENT": "Ɖe Numeɖeɖea Ɖa", + "DUPLICATE_COMMENT": "Kɔpi Numeɖeɖea", + "EXTERNAL_INPUTS": "Gotakpeɖeŋunuwo", + "INLINE_INPUTS": "Interdzikpeɖeŋuwo", + "DELETE_BLOCK": "Tutu Hatsotsoa", + "DELETE_X_BLOCKS": "Tutu Hatsotso %1", + "DELETE_ALL_BLOCKS": "Èdi be netutu nu %1 katã?", + "CLEAN_UP": "Tutu Nuawo", + "COLLAPSE_BLOCK": "Hatsotso Me Nuwo Nebu", + "COLLAPSE_ALL": "Hatsotsoawo Me Nuwo Nebu", + "EXPAND_BLOCK": "Hatsotsoa Me Nuwo Nedze", + "EXPAND_ALL": "Hatsotsoawo Me Nuwo Nedze", + "DISABLE_BLOCK": "Tsi Hatsotsoa", + "ENABLE_BLOCK": "Si Hatsotsoa", + "HELP": "Kpekpeɖeŋu", + "UNDO": "Gbugbɔe", + "REDO": "Trɔ Wɔe", + "CHANGE_VALUE_TITLE": "Trɔ nuŋlɔdzesiawo:", + "RENAME_VARIABLE": "Na ŋkɔ bubu nuŋlɔdzesi tɔtrɔa...", + "RENAME_VARIABLE_TITLE": "Na ŋkɔ bubu nuŋlɔdzesi tɔtrɔa '%1' yi:", + "NEW_VARIABLE": "Wɔ teaŋutrɔna...", + "NEW_STRING_VARIABLE": "Wɔ nya teaŋutrɔna...", + "NEW_NUMBER_VARIABLE": "Wɔ xexlẽdzesi teaŋutrɔna...", + "NEW_COLOUR_VARIABLE": "Wɔ amadede teaŋutrɔna...", + "NEW_VARIABLE_TYPE_TITLE": "Teaŋutrɔna ƒomevi yeye:", + "NEW_VARIABLE_TITLE": "Nuŋlɔdzesi tɔtrɔa yeye ƒe ŋkɔ:", + "VARIABLE_ALREADY_EXISTS": "Teaŋutrɔna si ŋkɔe nye '%1' li xoxo.", + "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Teaŋutrɔna '%1' li xoxo eye wotsɔ ŋkɔ sia xoxo na bubu si nye: '%2'.", + "DELETE_VARIABLE_CONFIRMATION": "Netutu %1 ŋkɔ si nètsɔ na teaŋutrɔna '%2'?", + "CANNOT_DELETE_VARIABLE_PROCEDURE": "Mate ŋu atutu teaŋutrɔna '%1' o elabe ewɔ akpa aɖe le teaŋutrɔna '%2' me.", + "DELETE_VARIABLE": "Tutu teaŋutrɔna '%1'", + "COLOUR_PICKER_HELPURL": "https://ee.wikipedia.org/wiki/Amadede", + "COLOUR_PICKER_TOOLTIP": "Tia amadede ɖeka le amadedetiaƒea.", + "COLOUR_RANDOM_TITLE": "amadede aɖe ko", + "COLOUR_RANDOM_TOOLTIP": "Tia amadede aɖe ko.", + "COLOUR_RGB_TITLE": "de amae kple", + "COLOUR_RGB_RED": "dzĩ", + "COLOUR_RGB_GREEN": "gbemumu", + "COLOUR_RGB_BLUE": "blɔ", + "COLOUR_RGB_TOOLTIP": "tsaka", + "COLOUR_BLEND_TITLE": "tsaka", + "COLOUR_BLEND_COLOUR1": "amedede 1", + "COLOUR_BLEND_COLOUR2": "amadede 2", + "COLOUR_BLEND_RATIO": "agbɔsɔsɔ", + "COLOUR_BLEND_TOOLTIP": "Tsaka amadede eve kple agbɔsɔsɔ si nye (0.0 - 1.0).", + "CONTROLS_REPEAT_HELPURL": "https://ee.wikipedia.org/wiki/Na_nogo", + "CONTROLS_REPEAT_TITLE": "Wɔe zi %1", + "CONTROLS_REPEAT_INPUT_DO": "wɔ", + "CONTROLS_REPEAT_TOOLTIP": "Gbugbɔ biabia aɖewo zi geɖe.", + "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "gbugbɔ wɔe ne", + "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "gbugbɔ wɔe va se ɖe", + "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Ne nyatakaka dea, ke wɔ biabia aɖewo.", + "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Ne nyatakaka dea, ke wɔ biabia aɖewo.", + "CONTROLS_FOR_TOOLTIP": "Xexlẽdzesi tɔtrɔ '%1' nenye xexlẽdzesi si dze egɔme kple esiwo kplɔe ɖo va se ɖe mamlɛtɔ dzi, nebu dometsotso si wofia kple nyatakaka suetɔ siwo wofia asii.", + "CONTROLS_FOR_TITLE": "Xlẽ %1 tso %2 yi %3 to %4 dzi", + "CONTROLS_FOREACH_TITLE": "nu sia nu natso %2 me ayi %1 me", + "CONTROLS_FOREACH_TOOLTIP": "Tia teaŋutrɔna '%1' na nuawo dometɔ ɖe sia ɖe si li, eye nàŋlɔ gbedeasi aɖe.", + "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "Nedo le wɔtiaɖenua me", + "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "neyi edzi kple wɔtiaɖenua si kplɔe ɖo", + "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Nedo le wɔtiaɖenua si me wòlea me.", + "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Neto wɔtiaɖenu sia susɔea ta wòayi bubu dzi.", + "CONTROLS_FLOW_STATEMENTS_WARNING": "Nuxlɔ̃ame: Wɔtiaɖenu me ko woate ŋu azã ƒuƒoƒo sia le.", + "CONTROLS_IF_TOOLTIP_1": "Ne asime aɖe le eme la, ke taɖodzinya aɖewo neva eme.", + "CONTROLS_IF_TOOLTIP_2": "Ne asime aɖe le eme la, ke taɖodzinyawo ƒe ƒuƒoƒo gbãtɔ neva eme. Ne menye nenem o la, ke taɖodzinyawo ƒe ƒuƒoƒo evelia neva eme.", + "CONTROLS_IF_TOOLTIP_3": "Ne asime gbãtɔe le eme la, ke taɖodzinyawo ƒe ƒuƒoƒo gbãtɔ neva eme. Gake ne asime eveliae le eme la, taɖodzinyawo ƒe ƒuƒoƒo evelia boŋ neva eme.", + "CONTROLS_IF_TOOLTIP_4": "Ne asime gbãtɔ le eme la, ke taɖodzinyawo ƒe ƒuƒoƒo gbãtɔ neva eme. Ke ne taɖodzinyawo ƒe ƒuƒoƒo evelia boŋue le eme la, taɖodzinyawo ƒe ƒuƒoƒo evelia neva eme. Ne taɖodzinya aɖeke mele eme o la,taɖodzinyawo ƒe ƒuƒoƒo mamlɛtɔ neva eme.", + "CONTROLS_IF_MSG_IF": "Ne", + "CONTROLS_IF_MSG_ELSEIF": "Ke boŋ ne", + "CONTROLS_IF_MSG_ELSE": "ke boŋ", + "CONTROLS_IF_IF_TOOLTIP": "Tsɔ kpee, ɖee le eme alo gbugbɔ akpawo ɖo nàtsɔ asi le ne ƒe ƒuƒoƒoa ŋu.", + "CONTROLS_IF_ELSEIF_TOOLTIP": "Tsɔ biabia aɖe kpe ne ƒuƒoƒo la.", + "CONTROLS_IF_ELSE_TOOLTIP": "Tsɔ lé wo katã ƒe ne ƒe ƒuƒoƒo kpe biabia mamlɛa.", + "IOS_OK": "YOO", + "IOS_CANCEL": "Natasii", + "IOS_ERROR": "Vodada", + "IOS_PROCEDURES_INPUTS": "NUDEMEWO", + "IOS_PROCEDURES_ADD_INPUT": "+ Tsɔ nu kpe Nudemea", + "IOS_PROCEDURES_ALLOW_STATEMENTS": "Ɖe mɔ ɖe taɖodzinyawo ŋu", + "IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR": "Nudeme evee le wɔƒe sia si.", + "IOS_VARIABLES_ADD_VARIABLE": "+ Tsɔ nugba kpee", + "IOS_VARIABLES_ADD_BUTTON": "Tsɔ kpee", + "IOS_VARIABLES_RENAME_BUTTON": "Gbugbɔ na ŋkɔe", + "IOS_VARIABLES_DELETE_BUTTON": "Tutui", + "IOS_VARIABLES_VARIABLE_NAME": "Nugba ŋkɔ", + "IOS_VARIABLES_EMPTY_NAME_ERROR": "Màte ŋu azã nugba si mena ŋkɔe o.", + "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Masɔmasɔ_(akɔntabubu)", + "LOGIC_COMPARE_TOOLTIP_EQ": "Ŋuɖoɖoa nenye nyateƒe ne nudeme eveawo sɔ kple wo nɔewo.", + "LOGIC_COMPARE_TOOLTIP_NEQ": "Ŋuɖoɖoa nenye nyateƒe ne nudeme eveawo mesɔ kple wo nɔewo o.", + "LOGIC_COMPARE_TOOLTIP_LT": "Ŋuɖoɖoa nenye nyateƒe ne nudeme gbãtɔ mede evelia nu o.", + "LOGIC_COMPARE_TOOLTIP_LTE": "Ŋuɖoɖoa nenye nyateƒe ne nudeme gbãtɔ mede evelia nu o alo sɔ kplii.", + "LOGIC_COMPARE_TOOLTIP_GT": "Ŋuɖoɖoa nenye nyateƒe ne nudeme gbãtɔ lolo wu evelia.", + "LOGIC_COMPARE_TOOLTIP_GTE": "Ŋuɖoɖoa nenye nyateƒe ne nudeme gbãtɔ lolo wu evelia alo sɔ kplii.", + "LOGIC_OPERATION_TOOLTIP_AND": "Ŋuɖoɖoa nenye nyateƒe ne nudeme eveawo nye nyateƒe.", + "LOGIC_OPERATION_AND": "eye", + "LOGIC_OPERATION_TOOLTIP_OR": "Ŋuɖoɖoa nenye nyateƒe ne nudeme ɖeka teti nye nyateƒe.", + "LOGIC_OPERATION_OR": "alo", + "LOGIC_NEGATE_TITLE": "menye %1", + "LOGIC_NEGATE_TOOLTIP": "Ŋuɖoɖoa nenye nyateƒe ne nudemea menye nyateƒe o. Ŋuɖoɖoa nenye aʋatso ne nudemea nye nyateƒe.", + "LOGIC_BOOLEAN_TRUE": "dedia", + "LOGIC_BOOLEAN_FALSE": "mademadea", + "LOGIC_BOOLEAN_TOOLTIP": "Nefia dedia alo mademadea.", + "LOGIC_NULL": "ɖeke o", + "LOGIC_NULL_TOOLTIP": "Mekpɔ ɖeke o.", + "LOGIC_TERNARY_CONDITION": "dodokpɔ", + "LOGIC_TERNARY_IF_TRUE": "nenye nyuitɔ", + "LOGIC_TERNARY_IF_FALSE": "nenye dedietɔ", + "LOGIC_TERNARY_TOOLTIP": "Kpɔ nu si dze le \"dodokpɔ\" me. Ne dediae dze la, tia \"ne dedia\"; ke ne manyomanyotɔe la, tia \"ne mademadea.\"", + "MATH_NUMBER_HELPURL": "https://ee.wikipedia.org/wiki/Xexlẽdzesi", + "MATH_NUMBER_TOOLTIP": "Xexlẽdzesi aɖe", + "MATH_ARITHMETIC_HELPURL": "https://ee.wikipedia.org/wiki/Xexlẽdzesibubu", + "MATH_ARITHMETIC_TOOLTIP_ADD": "Bu xexlẽdzesi evea ƒoƒo ƒu ƒe akɔnta.", + "MATH_ARITHMETIC_TOOLTIP_MINUS": "Bu xexlẽdzesi ɖeka ɖeɖe le evelia me ƒe akɔnta.", + "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Bu xexlẽdzesi gbãtɔ teƒe evelia ƒe akɔnta.", + "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Bu xexlẽdzesi ɖeka mama ɖe xexlẽdzesi evelia me ƒe akɔnta.", + "MATH_ARITHMETIC_TOOLTIP_POWER": "Na be xexlẽdzesi gbãtɔ nadzi eɖokui ɖe edzi zigbɔzi xexlẽdzesi evelia.", + "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/dzidziɖedzi_eɖokui zigbɔzi eve", + "MATH_SINGLE_OP_ROOT": "eƒe teƒe eve", + "MATH_SINGLE_TOOLTIP_ROOT": "Xexlẽdzesia nedzi ɖe edzi teƒe eɖokui", + "MATH_SINGLE_OP_ABSOLUTE": "xexlẽ blibo", + "MATH_SINGLE_TOOLTIP_ABS": "Nena xexlẽdzesi aɖe nanye xexlẽ blibo.", + "MATH_SINGLE_TOOLTIP_NEG": "Nena xexlẽdzesi aɖe nanye xexlẽdzesi madenanekeo.", + "MATH_SINGLE_TOOLTIP_LN": "Xexlẽdzesia nedzi ɖe edzi eɖokui zigbzi e.", + "MATH_IS_EVEN": "enye eve ƒomevi", + "MATH_IS_ODD": "enye etɔ̃ ƒomevi", + "MATH_IS_PRIME": " enye xexlẽme blibo", + "MATH_IS_WHOLE": "enye blibo", + "MATH_IS_POSITIVE": "enye xexlẽme ŋgɔgbeyitɔ", + "MATH_IS_NEGATIVE": "enye xexlẽme megbeyitɔ", + "MATH_IS_DIVISIBLE_BY": "woate ŋu amae ɖe" +} From b93253c69c25641a21b7f10bfff04ccc27a9f854 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 15 Apr 2019 10:02:07 -0700 Subject: [PATCH 008/233] Fixed Mutator Flyout Being Positioned Incorrectly RTL (#2378) * Fixed mutator flyout being positioned incorrectly. * Changed flyout_horizonal and flyout_vertical to check this.targetWorkspace_.toolboxPosition instead of targetWorkspaceMetrics.toolboxPosition. --- core/flyout_horizontal.js | 2 +- core/flyout_vertical.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index b8d931f5905..33f9eaa1942 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -155,7 +155,7 @@ Blockly.HorizontalFlyout.prototype.position = function() { // X is always 0 since this is a horizontal flyout. var x = 0; // If this flyout is the toolbox flyout. - if (targetWorkspaceMetrics.toolboxPosition == this.toolboxPosition_) { + if (this.targetWorkspace_.toolboxPosition == this.toolboxPosition_) { // If there is a toolbox. if (targetWorkspaceMetrics.toolboxHeight) { if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) { diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index ad825649e0c..d88c669f447 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -152,7 +152,7 @@ Blockly.VerticalFlyout.prototype.position = function() { // Y is always 0 since this is a vertical flyout. var y = 0; // If this flyout is the toolbox flyout. - if (targetWorkspaceMetrics.toolboxPosition == this.toolboxPosition_) { + if (this.targetWorkspace_.toolboxPosition == this.toolboxPosition_) { // If there is a category toolbox. if (targetWorkspaceMetrics.toolboxWidth) { if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) { From f88c704d69928c2a33473e6abae30e5973cc11b5 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 15 Apr 2019 13:26:20 -0700 Subject: [PATCH 009/233] Fixed visible floating point errors in number fields. (#2384) --- core/field_number.js | 11 +++++++--- tests/blocks/test_blocks.js | 40 ++++++++++++++++++++++++++++++++----- tests/playground.html | 10 ++++++++-- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/core/field_number.js b/core/field_number.js index 7d4cf275901..c9f75215a3a 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -79,6 +79,10 @@ Blockly.FieldNumber.fromJson = function(options) { Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) { precision = parseFloat(precision); this.precision_ = isNaN(precision) ? 0 : precision; + var precisionString = this.precision_.toString(); + var decimalIndex = precisionString.indexOf('.'); + this.fractionalDigits_ = (decimalIndex == -1) ? -1 : + precisionString.length - (decimalIndex + 1); min = parseFloat(min); this.min_ = isNaN(min) ? -Infinity : min; max = parseFloat(max); @@ -106,13 +110,14 @@ Blockly.FieldNumber.prototype.classValidator = function(text) { // Invalid number. return null; } + // Get the value in range. + n = Math.min(Math.max(n, this.min_), this.max_); // Round to nearest multiple of precision. if (this.precision_ && isFinite(n)) { n = Math.round(n / this.precision_) * this.precision_; } - // Get the value in range. - n = Math.min(Math.max(n, this.min_), this.max_); - return String(n); + return (this.fractionalDigits_ == -1) ? String(n) : + n.toFixed(this.fractionalDigits_); }; Blockly.Field.register('field_number', Blockly.FieldNumber); diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index 5b3da54fe2a..e3e473415be 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -207,8 +207,8 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "tooltip": "A number." }, { - "type": "test_fields_integer", - "message0": "integer %1", + "type": "test_fields_number_whole", + "message0": "precision 1 %1", "args0": [ { "type": "field_number", @@ -219,11 +219,11 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT ], "style": "math_blocks", "output": "Number", - "tooltip": "An integer." + "tooltip": "The number should be rounded to multiples of 1" }, { "type": "test_fields_number_hundredths", - "message0": "$ %1", + "message0": "precision 0.01 %1", "args0": [ { "type": "field_number", @@ -234,7 +234,37 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT ], "style": "math_blocks", "output": "Number", - "tooltip": "A dollar amount." + "tooltip": "The number should be rounded to multiples of 0.01" + }, + { + "type": "test_fields_number_halves", + "message0": "precision 0.5 %1", + "args0": [ + { + "type": "field_number", + "name": "NUM", + "precision": 0.5, + "text": "0" + } + ], + "style": "math_blocks", + "output": "Number", + "tooltip": "The number should be rounded to multiples of 0.5" + }, + { + "type": "test_fields_number_three_halves", + "message0": "precision 1.5 %1", + "args0": [ + { + "type": "field_number", + "name": "NUM", + "precision": 1.5, + "text": "0" + } + ], + "style": "math_blocks", + "output": "Number", + "tooltip": "The number should be rounded to multiples of 1.5" }, { "type": "test_fields_integer_bounded", diff --git a/tests/playground.html b/tests/playground.html index e961c49e5df..680b9fb2dab 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -1197,10 +1197,16 @@

Blockly Playground

123.456 - + 123.456 - + + 123.456 + + + 123.456 + + 123.456 From ec78eeb39b2e82882a98747617f912fe66f79df6 Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Mon, 15 Apr 2019 16:23:19 -0700 Subject: [PATCH 010/233] Propagate the visible state when blocks connect (#2003) * Propagate the visible state when blocks connect This fixes #1967. In rendered connections when connecting: - If the superior connection is hidden this hides the newly connected block. - If the superior connection isn't hidden it makes sure the block is visible. In rendered connections when disconnecting: - If the superior connection is hidden, make the disconnected block stack visible. TODO before review: - write tests. - update collapsed message * Add missing overrides * Add tests for hidden connections and fix a bug while disposing --- core/block_render_svg.js | 4 + core/connection.js | 15 ++ core/rendered_connection.js | 48 ++++- tests/mocha/connection_test.js | 322 +++++++++++++++++++++++++++++++++ tests/mocha/index.html | 7 + 5 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 tests/mocha/connection_test.js diff --git a/core/block_render_svg.js b/core/block_render_svg.js index 53719b8e36b..0b8998104c0 100644 --- a/core/block_render_svg.js +++ b/core/block_render_svg.js @@ -316,6 +316,10 @@ Blockly.BlockSvg.prototype.getHeightWidth = function() { * If true, also render block's parent, grandparent, etc. Defaults to true. */ Blockly.BlockSvg.prototype.render = function(opt_bubble) { + if (!this.workspace) { + // This block is being deleted so don't try to render it. + return; + } Blockly.Field.startCache(); this.rendered = true; diff --git a/core/connection.js b/core/connection.js index f61d0e7927e..f75ae9bf363 100644 --- a/core/connection.js +++ b/core/connection.js @@ -445,6 +445,10 @@ Blockly.Connection.prototype.connect = function(otherConnection) { return; } this.checkConnection_(otherConnection); + var eventGroup = Blockly.Events.getGroup(); + if (!eventGroup) { + Blockly.Events.setGroup(true); + } // Determine which block is superior (higher in the source stack). if (this.isSuperior()) { // Superior block. @@ -453,6 +457,9 @@ Blockly.Connection.prototype.connect = function(otherConnection) { // Inferior block. otherConnection.connect_(this); } + if (!eventGroup) { + Blockly.Events.setGroup(false); + } }; /** @@ -542,8 +549,16 @@ Blockly.Connection.prototype.disconnect = function() { childBlock = this.sourceBlock_; parentConnection = otherConnection; } + + var eventGroup = Blockly.Events.getGroup(); + if (!eventGroup) { + Blockly.Events.setGroup(true); + } this.disconnectInternal_(parentBlock, childBlock); parentConnection.respawnShadow_(); + if (!eventGroup) { + Blockly.Events.setGroup(false); + } }; /** diff --git a/core/rendered_connection.js b/core/rendered_connection.js index b4bebbbbb26..73005308819 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -225,6 +225,7 @@ Blockly.RenderedConnection.prototype.highlight = function() { * attached to this connection. This happens when a block is expanded. * Also unhides down-stream comments. * @return {!Array.} List of blocks to render. + * @protected */ Blockly.RenderedConnection.prototype.unhideAll = function() { this.setHidden(false); @@ -272,6 +273,7 @@ Blockly.RenderedConnection.prototype.unhighlight = function() { /** * Set whether this connections is hidden (not tracked in a database) or not. * @param {boolean} hidden True if connection is hidden. + * @protected */ Blockly.RenderedConnection.prototype.setHidden = function(hidden) { this.hidden_ = hidden; @@ -286,6 +288,7 @@ Blockly.RenderedConnection.prototype.setHidden = function(hidden) { * Hide this connection, as well as all down-stream connections on any block * attached to this connection. This happens when a block is collapsed. * Also hides down-stream comments. + * @protected */ Blockly.RenderedConnection.prototype.hideAll = function() { this.setHidden(true); @@ -324,6 +327,49 @@ Blockly.RenderedConnection.prototype.isConnectionAllowed = function(candidate, candidate); }; +/** + * Connect this connection to another connection. + * @param {!Blockly.Connection} otherConnection Connection to connect to. + * @override + */ +Blockly.RenderedConnection.prototype.connect = function(otherConnection) { + Blockly.RenderedConnection.superClass_.connect.call(this, otherConnection); + + // This is a quick check to make sure we aren't doing unecessary work. + if (this.hidden_ || otherConnection.hidden_) { + var superiorConnection = this.isSuperior() ? this : otherConnection; + if (superiorConnection.hidden_) { + superiorConnection.hideAll(); + } else { + superiorConnection.unhideAll(); + } + + var renderedBlock = superiorConnection.targetBlock(); + var display = superiorConnection.hidden_ ? 'none' : 'block'; + renderedBlock.getSvgRoot().style.display = display; + renderedBlock.rendered = !superiorConnection.hidden_; + } +}; + +/** + * Disconnect this connection. + * @override + */ +Blockly.RenderedConnection.prototype.disconnect = function() { + var superiorConnection = this.isSuperior() ? this : this.targetConnection; + if (this.targetConnection && superiorConnection.hidden_) { + superiorConnection.unhideAll(); + var renderedBlock = superiorConnection.targetBlock(); + renderedBlock.getSvgRoot().style.display = 'block'; + renderedBlock.rendered = true; + + // Set the hidden state for the connection back to true so shadow blocks + // will be hidden. + superiorConnection.setHidden(true); + } + Blockly.RenderedConnection.superClass_.disconnect.call(this); +}; + /** * Disconnect two blocks that are connected by this connection. * @param {!Blockly.Block} parentBlock The superior block. @@ -361,7 +407,7 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() { } blockShadow.initSvg(); blockShadow.render(false); - if (parentBlock.rendered) { + if (parentBlock.rendered && !this.hidden_) { parentBlock.render(); } } diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js new file mode 100644 index 00000000000..b3cb1ddd9c7 --- /dev/null +++ b/tests/mocha/connection_test.js @@ -0,0 +1,322 @@ + + +suite('Connections', function() { + + suite('Rendered', function() { + function assertAllConnectionsHidden(block) { + assertAllConnectionsHiddenState(block, true); + } + function assertAllConnectionsVisible(block) { + assertAllConnectionsHiddenState(block, false); + } + function assertAllConnectionsHiddenState(block, hidden) { + var connections = block.getConnections_(true); + for (var i = 0; i < connections.length; i++) { + var connection = connections[i]; + if (connection.type == Blockly.PREVIOUS_STATEMENT + || connection.type == Blockly.OUTPUT_VALUE) { + // Only superior connections on inputs get hidden + continue; + } + if (block.nextConnection && connection === block.nextConnection) { + // The next connection is not hidden when collapsed + continue; + } + assertEquals('Connection ' + i + ' failed', hidden, connections[i].hidden_) + } + } + + setup(function() { + Blockly.defineBlocksWithJsonArray([{ + "type": "stack_block", + "message0": "", + "previousStatement": null, + "nextStatement": null + }, + { + "type": "row_block", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "INPUT" + } + ], + "output": null + }, + { + "type": "inputs_block", + "message0": "%1 %2", + "args0": [ + { + "type": "input_value", + "name": "INPUT" + }, + { + "type": "input_statement", + "name": "STATEMENT" + } + ], + "previousStatement": null, + "nextStatement": null + },]); + + var toolbox = document.getElementById('toolbox-connections'); + this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox}); + }); + + teardown(function() { + delete Blockly.Blocks['stack_block']; + delete Blockly.Blocks['row_block']; + delete Blockly.Blocks['inputs_block']; + + this.workspace.dispose(); + }); + + suite('Row collapsing', function() { + setup(function() { + var blockA = this.workspace.newBlock('row_block'); + var blockB = this.workspace.newBlock('row_block'); + var blockC = this.workspace.newBlock('row_block'); + + blockA.inputList[0].connection.connect(blockB.outputConnection); + blockA.setCollapsed(true); + + assertEquals(blockA, blockB.getParent()); + assertNull(blockC.getParent()) + assertTrue(blockA.isCollapsed()); + assertAllConnectionsHidden(blockA); + assertAllConnectionsHidden(blockB); + assertAllConnectionsVisible(blockC); + + this.blocks = { + A: blockA, + B: blockB, + C: blockC + }; + }); + + test('Add to end', function() { + var blocks = this.blocks; + blocks.B.inputList[0].connection.connect(blocks.C.outputConnection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Add to end w/inferior', function() { + var blocks = this.blocks; + blocks.C.outputConnection.connect(blocks.B.inputList[0].connection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Add to middle', function() { + var blocks = this.blocks; + blocks.A.inputList[0].connection.connect(blocks.C.outputConnection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Add to middle w/inferior', function() { + var blocks = this.blocks; + blocks.C.outputConnection.connect(blocks.A.inputList[0].connection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Remove simple', function() { + var blocks = this.blocks; + blocks.B.unplug(); + assertAllConnectionsVisible(blocks.B); + }); + + test('Remove middle', function() { + var blocks = this.blocks; + blocks.B.inputList[0].connection.connect(blocks.C.outputConnection); + blocks.B.unplug(false); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + + test('Remove middle healing', function() { + var blocks = this.blocks; + blocks.B.inputList[0].connection.connect(blocks.C.outputConnection); + blocks.B.unplug(true); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsHidden(blocks.C); + }); + + test('Add before', function() { + var blocks = this.blocks; + blocks.C.inputList[0].connection.connect(blocks.A.outputConnection); + // Connecting a collapsed block to another block doesn't change any hidden state + assertAllConnectionsHidden(blocks.A); + assertAllConnectionsVisible(blocks.C); + }); + + test('Remove front', function() { + var blocks = this.blocks; + blocks.B.inputList[0].connection.connect(blocks.C.outputConnection); + blocks.A.inputList[0].connection.disconnect(); + assertTrue(blocks.A.isCollapsed()); + assertAllConnectionsHidden(blocks.A); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + + test('Uncollapse', function() { + var blocks = this.blocks; + blocks.B.inputList[0].connection.connect(blocks.C.outputConnection); + blocks.A.setCollapsed(false); + assertFalse(blocks.A.isCollapsed()); + assertAllConnectionsVisible(blocks.A); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + }); + suite('Statement collapsing', function() { + setup(function() { + var blockA = this.workspace.newBlock('inputs_block'); + var blockB = this.workspace.newBlock('inputs_block'); + var blockC = this.workspace.newBlock('inputs_block'); + + blockA.getInput('STATEMENT').connection.connect(blockB.previousConnection); + blockA.setCollapsed(true); + + assertEquals(blockA, blockB.getParent()); + assertNull(blockC.getParent()) + assertTrue(blockA.isCollapsed()); + assertAllConnectionsHidden(blockA); + assertAllConnectionsHidden(blockB); + assertAllConnectionsVisible(blockC); + + this.blocks = { + A: blockA, + B: blockB, + C: blockC + }; + }); + + test('Add to statement', function() { + var blocks = this.blocks; + blocks.B.getInput('STATEMENT').connection.connect(blocks.C.previousConnection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Insert in statement', function() { + var blocks = this.blocks; + blocks.A.getInput('STATEMENT').connection.connect(blocks.C.previousConnection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Add to hidden next', function() { + var blocks = this.blocks; + blocks.B.nextConnection.connect(blocks.C.previousConnection); + assertAllConnectionsHidden(blocks.C); + }); + + test('Remove simple', function() { + var blocks = this.blocks; + blocks.B.unplug(); + assertAllConnectionsVisible(blocks.B); + }); + + test('Remove middle', function() { + var blocks = this.blocks; + blocks.B.nextConnection.connect(blocks.C.previousConnection); + blocks.B.unplug(false); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + + test('Remove middle healing', function() { + var blocks = this.blocks; + blocks.B.nextConnection.connect(blocks.C.previousConnection); + blocks.B.unplug(true); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsHidden(blocks.C); + }); + + test('Add before', function() { + var blocks = this.blocks; + blocks.C.getInput('STATEMENT').connection.connect(blocks.A.previousConnection); + assertAllConnectionsHidden(blocks.A); + assertAllConnectionsHidden(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + + test('Remove front', function() { + var blocks = this.blocks; + blocks.B.nextConnection.connect(blocks.C.previousConnection); + blocks.A.getInput('STATEMENT').connection.disconnect(); + assertTrue(blocks.A.isCollapsed()); + assertAllConnectionsHidden(blocks.A); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + + test('Uncollapse', function() { + var blocks = this.blocks; + blocks.B.nextConnection.connect(blocks.C.previousConnection); + blocks.A.setCollapsed(false); + assertFalse(blocks.A.isCollapsed()); + assertAllConnectionsVisible(blocks.A); + assertAllConnectionsVisible(blocks.B); + assertAllConnectionsVisible(blocks.C); + }); + }); + + suite('Collapsing with shadows', function() { + setup(function() { + var blockA = this.workspace.newBlock('inputs_block'); + var blockB = this.workspace.newBlock('inputs_block'); + var blockC = this.workspace.newBlock('inputs_block'); + var blockD = this.workspace.newBlock('row_block'); + + blockB.setShadow(true); + var shadowStatement = Blockly.Xml.blockToDom(blockB, true /*noid*/); + blockB.setShadow(false); + + blockD.setShadow(true); + var shadowValue = Blockly.Xml.blockToDom(blockD, true /*noid*/); + blockD.setShadow(false); + + var connection = blockA.getInput('STATEMENT').connection; + connection.setShadowDom(shadowStatement); + connection.connect(blockB.previousConnection); + connection = blockA.getInput('INPUT').connection; + connection.setShadowDom(shadowValue); + connection.connect(blockD.outputConnection); + blockA.setCollapsed(true); + + assertEquals(blockA, blockB.getParent()); + assertNull(blockC.getParent()) + assertTrue(blockA.isCollapsed()); + assertAllConnectionsHidden(blockA); + assertAllConnectionsHidden(blockB); + assertAllConnectionsVisible(blockC); + + this.blocks = { + A: blockA, + B: blockB, + C: blockC, + D: blockD + }; + }); + + test('Reveal shadow statement', function() { + var blocks = this.blocks; + var connection = blocks.A.getInput('STATEMENT').connection; + connection.disconnect(); + var shadowBlock = connection.targetBlock(); + assertTrue(shadowBlock.isShadow()); + assertAllConnectionsHidden(shadowBlock); + }) + + test('Reveal shadow value', function() { + var blocks = this.blocks; + var connection = blocks.A.getInput('INPUT').connection; + connection.disconnect(); + var shadowBlock = connection.targetBlock(); + assertTrue(shadowBlock.isShadow()); + assertAllConnectionsHidden(shadowBlock); + }) + }); + }); +}); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 6dcef5ce6dd..1a1f601a883 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -21,9 +21,16 @@ + +
+ + From 0617cc7fea604a431991ae4020036986ce6cd5f2 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 12 Apr 2019 15:55:47 -0700 Subject: [PATCH 011/233] Added isDirty_ property to fields. --- core/field.js | 22 +++++++++++--- core/field_angle.js | 2 -- core/field_colour.js | 36 +++++++--------------- core/field_label.js | 2 -- tests/blocks/test_blocks.js | 59 ++++++++++++++++++++++++++++++++++++- tests/playground.html | 4 +++ 6 files changed, 90 insertions(+), 35 deletions(-) diff --git a/core/field.js b/core/field.js index 45083993a04..9f584f53ff5 100644 --- a/core/field.js +++ b/core/field.js @@ -137,6 +137,13 @@ Blockly.Field.prototype.text_ = ''; */ Blockly.Field.prototype.sourceBlock_ = null; +/** + * Does this block need to be re-rendered? + * @type {boolean} + * @private + */ +Blockly.Field.prototype.isDirty_ = true; + /** * Is the field visible, or hidden due to the block being collapsed? * @type {boolean} @@ -379,6 +386,7 @@ Blockly.Field.prototype.render_ = function() { // Replace the text. this.textElement_.textContent = this.getDisplayText_(); this.updateWidth(); + this.isDirty_ = false; }; /** @@ -458,10 +466,18 @@ Blockly.Field.stopCache = function() { /** * Returns the height and width of the field. + * + * This should *in general* be the only place render_ gets called from. * @return {!goog.math.Size} Height and width. */ Blockly.Field.prototype.getSize = function() { - if (!this.size_.width) { + if (this.isDirty_) { + this.render_(); + } else if (this.visible_ && this.size_.width == 0) { + // If the field is not visible the width will be 0 as well, one of the + // problems with the old system. + console.warn('Deprecated use of setting size_.width to 0 to rerender a' + + ' field. Set field.isDirty_ to true instead.'); this.render_(); } return this.size_; @@ -546,9 +562,7 @@ Blockly.Field.prototype.setText = function(newText) { * @package */ Blockly.Field.prototype.forceRerender = function() { - // Set width to 0 to force a rerender of this field. - this.size_.width = 0; - + this.isDirty_ = true; if (this.sourceBlock_ && this.sourceBlock_.rendered) { this.sourceBlock_.render(); this.sourceBlock_.bumpNeighbours_(); diff --git a/core/field_angle.js b/core/field_angle.js index f776d0a951a..535e6371139 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -280,8 +280,6 @@ Blockly.FieldAngle.prototype.setText = function(text) { return; } this.updateGraph_(); - // Cached width is obsolete. Clear it. - this.size_.width = 0; }; /** diff --git a/core/field_colour.js b/core/field_colour.js index 9838669fcd5..57dffb9f7fb 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -120,9 +120,11 @@ Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR = 'white'; */ Blockly.FieldColour.prototype.init = function() { Blockly.FieldColour.superClass_.init.call(this); - this.borderRect_.style['fillOpacity'] = 1; this.size_ = new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH, Blockly.FieldColour.DEFAULT_HEIGHT); + this.borderRect_.style['fillOpacity'] = 1; + this.borderRect_.setAttribute('width', + this.size_.width + Blockly.BlockSvg.SEP_SPACE_X); this.setValue(this.getValue()); }; @@ -140,36 +142,18 @@ Blockly.FieldColour.prototype.dispose = function() { }; /** - * Return the current colour. - * @return {string} Current colour in '#rrggbb' format. - */ -Blockly.FieldColour.prototype.getValue = function() { - return this.colour_; -}; - -/** - * Get the size, and rerender if necessary. - * @return {!goog.math.Size} Height and width. + * Colour fields are fixed with, no need to update. */ -Blockly.FieldColour.prototype.getSize = function() { - if (!this.size_.width) { - this.render_(); - } - - return this.size_; +Blockly.FieldColour.prototype.updateWidth = function() { + // NOP }; /** - * Updates the width of the field. Colour fields have a constant width, but - * the width is sometimes reset to force a rerender. + * Return the current colour. + * @return {string} Current colour in '#rrggbb' format. */ -Blockly.FieldColour.prototype.updateWidth = function() { - var width = Blockly.FieldColour.DEFAULT_WIDTH; - if (this.borderRect_) { - this.borderRect_.setAttribute('width', - width + Blockly.BlockSvg.SEP_SPACE_X); - } - this.size_.width = width; +Blockly.FieldColour.prototype.getValue = function() { + return this.colour_; }; /** diff --git a/core/field_label.js b/core/field_label.js index 7050c6b7ad8..c7a899df48e 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -92,8 +92,6 @@ Blockly.FieldLabel.prototype.init = function() { this.textElement_.tooltip = this.sourceBlock_; } Blockly.Tooltip.bindMouseEvents(this.textElement_); - // Force a render. - this.render_(); }; /** diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index e3e473415be..5849ed698d0 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -190,7 +190,64 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "text": "NO DATE FIELD" } } - ] + ], + "colour": 230 + }, + { + "type": "test_fields_text_input", + "message0": "text input %1", + "args0": [ + { + "type": "field_input", + "name": "TEXT_INPUT", + "text": "default" + } + ], + "colour": 230, + "tooltip": "", + "helpUrl": "" + }, + { + "type": "test_fields_checkbox", + "message0": "checkbox %1", + "args0": [ + { + "type": "field_checkbox", + "name": "CHECKBOX", + "checked": true + } + ], + "colour": 230, + "tooltip": "", + "helpUrl": "" + }, + { + "type": "test_fields_colour", + "message0": "colour %1", + "args0": [ + { + "type": "field_colour", + "name": "COLOUR", + "colour": "#ff0000" + } + ], + "colour": 230, + "tooltip": "", + "helpUrl": "" + }, + { + "type": "test_fields_variable", + "message0": "variable %1", + "args0": [ + { + "type": "field_variable", + "name": "VARIABLE", + "variable": "item" + } + ], + "colour": 230, + "tooltip": "", + "helpUrl": "" }, { "type": "test_fields_number", diff --git a/tests/playground.html b/tests/playground.html index 680b9fb2dab..5f5a58444e3 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -1223,6 +1223,10 @@

Blockly Playground

+ + + + From ae112354fb7f6cf1c8025325cdd49b76327e40fc Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 18 Apr 2019 16:55:44 +0200 Subject: [PATCH 012/233] Localisation updates from https://translatewiki.net. --- msg/json/nl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msg/json/nl.json b/msg/json/nl.json index 107a94b8ddb..0cb9843ccd6 100644 --- a/msg/json/nl.json +++ b/msg/json/nl.json @@ -397,5 +397,6 @@ "PROCEDURES_IFRETURN_TOOLTIP": "Als de eerste waarde \"waar\" is, geef dan de tweede waarde terug.", "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "Waarschuwing: dit blok mag alleen gebruikt worden binnen de definitie van een functie.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Zeg iets..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Zeg iets...", + "COLLAPSED_WARNINGS_WARNING": "Samengevouwen blokken bevatten waarschuwingen." } From bc7702467091aba73ce08f45b06a71f58dc9c5bf Mon Sep 17 00:00:00 2001 From: ahigerd Date: Thu, 18 Apr 2019 10:49:07 -0500 Subject: [PATCH 013/233] Reorganize conditionals for block context menu (#2390) * Reorganize conditionals for block context menu * Disable comments and disabling in block factory --- core/block_svg.js | 85 +++++++++++++++------------- demos/blockfactory/app_controller.js | 2 + 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 0fff3eda2f5..d93c2bfba45 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -647,53 +647,58 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) { var block = this; var menuOptions = []; - if (this.isDeletable() && this.isMovable() && !block.isInFlyout) { - menuOptions.push(Blockly.ContextMenu.blockDuplicateOption(block)); - if (this.isEditable() && !this.collapsed_ && - this.workspace.options.comments) { + if (!this.isInFlyout) { + if (this.isDeletable() && this.isMovable()) { + menuOptions.push(Blockly.ContextMenu.blockDuplicateOption(block)); + } + + if (this.workspace.options.comments && !this.collapsed_ && + this.isEditable()) { menuOptions.push(Blockly.ContextMenu.blockCommentOption(block)); } - // Option to make block inline. - if (!this.collapsed_) { - for (var i = 1; i < this.inputList.length; i++) { - if (this.inputList[i - 1].type != Blockly.NEXT_STATEMENT && - this.inputList[i].type != Blockly.NEXT_STATEMENT) { - // Only display this option if there are two value or dummy inputs - // next to each other. - var inlineOption = {enabled: true}; - var isInline = this.getInputsInline(); - inlineOption.text = isInline ? - Blockly.Msg['EXTERNAL_INPUTS'] : Blockly.Msg['INLINE_INPUTS']; - inlineOption.callback = function() { - block.setInputsInline(!isInline); + if (this.isMovable()) { + if (!this.collapsed_) { + // Option to make block inline. + for (var i = 1; i < this.inputList.length; i++) { + if (this.inputList[i - 1].type != Blockly.NEXT_STATEMENT && + this.inputList[i].type != Blockly.NEXT_STATEMENT) { + // Only display this option if there are two value or dummy inputs + // next to each other. + var inlineOption = {enabled: true}; + var isInline = this.getInputsInline(); + inlineOption.text = isInline ? + Blockly.Msg['EXTERNAL_INPUTS'] : Blockly.Msg['INLINE_INPUTS']; + inlineOption.callback = function() { + block.setInputsInline(!isInline); + }; + menuOptions.push(inlineOption); + break; + } + } + // Option to collapse block + if (this.workspace.options.collapse) { + var collapseOption = {enabled: true}; + collapseOption.text = Blockly.Msg['COLLAPSE_BLOCK']; + collapseOption.callback = function() { + block.setCollapsed(true); }; - menuOptions.push(inlineOption); - break; + menuOptions.push(collapseOption); } - } - } - - if (this.workspace.options.collapse) { - // Option to collapse/expand block. - if (this.collapsed_) { - var expandOption = {enabled: true}; - expandOption.text = Blockly.Msg['EXPAND_BLOCK']; - expandOption.callback = function() { - block.setCollapsed(false); - }; - menuOptions.push(expandOption); } else { - var collapseOption = {enabled: true}; - collapseOption.text = Blockly.Msg['COLLAPSE_BLOCK']; - collapseOption.callback = function() { - block.setCollapsed(true); - }; - menuOptions.push(collapseOption); + // Option to expand block. + if (this.workspace.options.collapse) { + var expandOption = {enabled: true}; + expandOption.text = Blockly.Msg['EXPAND_BLOCK']; + expandOption.callback = function() { + block.setCollapsed(false); + }; + menuOptions.push(expandOption); + } } } - if (this.workspace.options.disable) { + if (this.workspace.options.disable && this.isEditable()) { // Option to disable/enable block. var disableOption = { text: this.disabled ? @@ -713,7 +718,9 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) { menuOptions.push(disableOption); } - menuOptions.push(Blockly.ContextMenu.blockDeleteOption(block)); + if (this.isDeletable()) { + menuOptions.push(Blockly.ContextMenu.blockDeleteOption(block)); + } } menuOptions.push(Blockly.ContextMenu.blockHelpOption(block)); diff --git a/demos/blockfactory/app_controller.js b/demos/blockfactory/app_controller.js index 4902f760e28..eff016547f2 100644 --- a/demos/blockfactory/app_controller.js +++ b/demos/blockfactory/app_controller.js @@ -718,6 +718,8 @@ AppController.prototype.init = function() { BlockFactory.mainWorkspace = Blockly.inject('blockly', {collapse: false, toolbox: toolbox, + comments: false, + disable: false, media: '../../media/'}); // Add tab handlers for switching between Block Factory and Block Exporter. From 0c0eeab50202e8b20cd4b30c522e0a72bcb9e55c Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 18 Apr 2019 12:18:05 -0700 Subject: [PATCH 014/233] Add sauce labs to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 457fb810f72..4ed0a2b5170 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,6 @@ Help us focus our development efforts by telling us [what you are doing with Blockly](https://developers.google.com/blockly/registration). The questionnaire only takes a few minutes and will help us better support the Blockly community. +Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs](https://saucelabs.com) + Want to contribute? Great! First, read [our guidelines for contributors](https://developers.google.com/blockly/guides/modify/contributing). From a82604d75c04628dae27797a47001e5dc59e94e0 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 19 Apr 2019 11:38:11 -0700 Subject: [PATCH 015/233] Update version number to 1.20190419.0-develop --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b41291a3fa..3f5d710c0e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockly", - "version": "1.20190215.0-develop", + "version": "1.20190419.0-develop", "description": "Blockly is a library for building visual programming editors.", "main": "blockly_node_javascript_en.js", "keywords": [ From 5df7a39dae9116fdf003671e51402ddd4e2a5329 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 20 Apr 2019 08:32:56 -0700 Subject: [PATCH 016/233] Moved RTL demo blocks so they aren't behind the toolbox. --- demos/rtl/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/rtl/index.html b/demos/rtl/index.html index 240cf8d20d6..b96abd6020b 100644 --- a/demos/rtl/index.html +++ b/demos/rtl/index.html @@ -169,7 +169,7 @@

Blockly > From 91b0e3d79a85eb391c19ad2c95b1271cea6bc64a Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 22 Apr 2019 10:45:35 -0700 Subject: [PATCH 018/233] Changed mocha eslint config to extend root eslint config. --- tests/mocha/.eslintrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mocha/.eslintrc.json b/tests/mocha/.eslintrc.json index c887877f64b..3eae4ad0fb8 100644 --- a/tests/mocha/.eslintrc.json +++ b/tests/mocha/.eslintrc.json @@ -16,5 +16,5 @@ "assertNotUndefined": true }, - "extends": "eslint:recommended" + "extends": "../../.eslintrc.json" } From 148823146dbb82bd0e377c1ff564a1ab6208d9a4 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 22 Apr 2019 10:55:36 -0700 Subject: [PATCH 019/233] Fixed lint errors --- tests/mocha/connection_test.js | 26 +++++++++++++------------- tests/mocha/event_test.js | 2 +- tests/mocha/xml_test.js | 22 +++++++++++----------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js index b3cb1ddd9c7..8dd57ac95c4 100644 --- a/tests/mocha/connection_test.js +++ b/tests/mocha/connection_test.js @@ -3,18 +3,12 @@ suite('Connections', function() { suite('Rendered', function() { - function assertAllConnectionsHidden(block) { - assertAllConnectionsHiddenState(block, true); - } - function assertAllConnectionsVisible(block) { - assertAllConnectionsHiddenState(block, false); - } function assertAllConnectionsHiddenState(block, hidden) { var connections = block.getConnections_(true); for (var i = 0; i < connections.length; i++) { var connection = connections[i]; if (connection.type == Blockly.PREVIOUS_STATEMENT - || connection.type == Blockly.OUTPUT_VALUE) { + || connection.type == Blockly.OUTPUT_VALUE) { // Only superior connections on inputs get hidden continue; } @@ -22,9 +16,15 @@ suite('Connections', function() { // The next connection is not hidden when collapsed continue; } - assertEquals('Connection ' + i + ' failed', hidden, connections[i].hidden_) + assertEquals('Connection ' + i + ' failed', hidden, connections[i].hidden_); } } + function assertAllConnectionsHidden(block) { + assertAllConnectionsHiddenState(block, true); + } + function assertAllConnectionsVisible(block) { + assertAllConnectionsHiddenState(block, false); + } setup(function() { Blockly.defineBlocksWithJsonArray([{ @@ -83,7 +83,7 @@ suite('Connections', function() { blockA.setCollapsed(true); assertEquals(blockA, blockB.getParent()); - assertNull(blockC.getParent()) + assertNull(blockC.getParent()); assertTrue(blockA.isCollapsed()); assertAllConnectionsHidden(blockA); assertAllConnectionsHidden(blockB); @@ -180,7 +180,7 @@ suite('Connections', function() { blockA.setCollapsed(true); assertEquals(blockA, blockB.getParent()); - assertNull(blockC.getParent()) + assertNull(blockC.getParent()); assertTrue(blockA.isCollapsed()); assertAllConnectionsHidden(blockA); assertAllConnectionsHidden(blockB); @@ -286,7 +286,7 @@ suite('Connections', function() { blockA.setCollapsed(true); assertEquals(blockA, blockB.getParent()); - assertNull(blockC.getParent()) + assertNull(blockC.getParent()); assertTrue(blockA.isCollapsed()); assertAllConnectionsHidden(blockA); assertAllConnectionsHidden(blockB); @@ -307,7 +307,7 @@ suite('Connections', function() { var shadowBlock = connection.targetBlock(); assertTrue(shadowBlock.isShadow()); assertAllConnectionsHidden(shadowBlock); - }) + }); test('Reveal shadow value', function() { var blocks = this.blocks; @@ -316,7 +316,7 @@ suite('Connections', function() { var shadowBlock = connection.targetBlock(); assertTrue(shadowBlock.isShadow()); assertAllConnectionsHidden(shadowBlock); - }) + }); }); }); }); diff --git a/tests/mocha/event_test.js b/tests/mocha/event_test.js index e88d379a8b6..e68ecd03850 100644 --- a/tests/mocha/event_test.js +++ b/tests/mocha/event_test.js @@ -32,7 +32,7 @@ suite('Events', function() { function checkExactEventValues(event, values) { var keys = Object.keys(values); for (var i = 0; i < keys.length; i++) { - var field = keys[i] + var field = keys[i]; assertEquals(values[field], event[field]); } } diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index 33bfc99de0c..6f6ecf9dbe5 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -89,7 +89,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_colour_test_block'); + 'field_colour_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; assertSimpleField(resultFieldDom, 'COLOUR', '#000099'); delete Blockly.Blocks['field_colour_test_block']; @@ -107,7 +107,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_date_test_block'); + 'field_date_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; assertSimpleField(resultFieldDom, 'DATE', '2020-02-20'); delete Blockly.Blocks['field_date_test_block']; @@ -138,7 +138,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_dropdown_test_block'); + 'field_dropdown_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; assertSimpleField(resultFieldDom, 'DROPDOWN', 'A'); delete Blockly.Blocks['field_dropdown_test_block']; @@ -159,7 +159,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_image_test_block'); + 'field_image_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block); assertNonSerializingField(resultFieldDom); delete Blockly.Blocks['field_image_test_block']; @@ -177,7 +177,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_label_test_block'); + 'field_label_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block); assertNonSerializingField(resultFieldDom); delete Blockly.Blocks['field_label_test_block']; @@ -195,7 +195,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_number_test_block'); + 'field_number_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; assertSimpleField(resultFieldDom, 'NUMBER', '97'); delete Blockly.Blocks['field_number_test_block']; @@ -213,7 +213,7 @@ suite('XML', function() { ], }]); var block = new Blockly.Block(this.workspace, - 'field_text_input_test_block'); + 'field_text_input_test_block'); var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; assertSimpleField(resultFieldDom, 'TEXT', 'default'); }); @@ -237,7 +237,7 @@ suite('XML', function() { test('Variable Trivial', function() { this.workspace.createVariable('name1', '', 'id1'); var block = new Blockly.Block(this.workspace, - 'field_variable_test_block'); + 'field_variable_test_block'); block.inputList[0].fieldRow[0].setValue('id1'); var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; assertVariableField(resultFieldDom, 'VAR', '', 'id1', 'name1'); @@ -253,7 +253,7 @@ suite('XML', function() { Blockly.Events.disable(); var block = new Blockly.Block(this.workspace, - 'field_variable_test_block'); + 'field_variable_test_block'); block.inputList[0].fieldRow[0].setValue('1'); Blockly.Events.enable(); @@ -263,8 +263,8 @@ suite('XML', function() { } finally { Blockly.utils.genUid = cacheGenUid; } - }) - }) + }); + }); }); }); suite('Deserialization', function() { From 9a9c6612f8ddab794cdde86fb026a2f322181686 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 22 Apr 2019 12:23:04 -0700 Subject: [PATCH 020/233] Changed buttons and labels to respect elements in toolbox. (#2395) --- core/flyout_base.js | 30 ++++++++++++++++++------------ core/toolbox.js | 25 +++++++------------------ 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/core/flyout_base.js b/core/flyout_base.js index f1ad80f978a..82f8bbe206a 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -447,11 +447,13 @@ Blockly.Flyout.prototype.show = function(xmlList) { var contents = []; var gaps = []; this.permanentlyDisabled_.length = 0; + var default_gap = this.horizontalLayout_ ? this.GAP_X : this.GAP_Y; for (var i = 0, xml; xml = xmlList[i]; i++) { - if (xml.tagName) { - var tagName = xml.tagName.toUpperCase(); - var default_gap = this.horizontalLayout_ ? this.GAP_X : this.GAP_Y; - if (tagName == 'BLOCK') { + if (!xml.tagName) { + continue; + } + switch (xml.tagName.toUpperCase()) { + case 'BLOCK': var curBlock = Blockly.Xml.domToBlock(xml, this.workspace_); if (curBlock.disabled) { // Record blocks that were initially disabled. @@ -459,15 +461,16 @@ Blockly.Flyout.prototype.show = function(xmlList) { this.permanentlyDisabled_.push(curBlock); } contents.push({type: 'block', block: curBlock}); + // This is a deprecated method for adding gap to a block. + // var gap = parseInt(xml.getAttribute('gap'), 10); gaps.push(isNaN(gap) ? default_gap : gap); - } else if (xml.tagName.toUpperCase() == 'SEP') { - // Change the gap between two blocks. + break; + case 'SEP': + // Change the gap between two toolbox elements. // // The default gap is 24, can be set larger or smaller. - // This overwrites the gap attribute on the previous block. - // Note that a deprecated method is to add a gap to a block. - // + // This overwrites the gap attribute on the previous element. var newGap = parseInt(xml.getAttribute('gap'), 10); // Ignore gaps before the first block. if (!isNaN(newGap) && gaps.length > 0) { @@ -475,14 +478,17 @@ Blockly.Flyout.prototype.show = function(xmlList) { } else { gaps.push(default_gap); } - } else if (tagName == 'BUTTON' || tagName == 'LABEL') { + break; + case 'LABEL': // Labels behave the same as buttons, but are styled differently. - var isLabel = tagName == 'LABEL'; + var isLabel = true; + // Falls through. + case 'BUTTON': var curButton = new Blockly.FlyoutButton(this.workspace_, this.targetWorkspace_, xml, isLabel); contents.push({type: 'button', button: curButton}); gaps.push(default_gap); - } + break; } } diff --git a/core/toolbox.js b/core/toolbox.js index 82d852e3947..c920d1f5477 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -359,25 +359,14 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) { lastElement = childIn; break; case 'SEP': - if (lastElement) { - if (lastElement.tagName.toUpperCase() == 'CATEGORY') { - // Separator between two categories. - // - treeOut.add(new Blockly.Toolbox.TreeSeparator( - this.treeSeparatorConfig_)); - } else { - // Change the gap between two blocks. - // - // The default gap is 24, can be set larger or smaller. - // Note that a deprecated method is to add a gap to a block. - // - var newGap = parseFloat(childIn.getAttribute('gap')); - if (!isNaN(newGap) && lastElement) { - lastElement.setAttribute('gap', newGap); - } - } + if (lastElement && lastElement.tagName.toUpperCase() == 'CATEGORY') { + // Separator between two categories. + // + treeOut.add(new Blockly.Toolbox.TreeSeparator( + this.treeSeparatorConfig_)); + break; } - break; + // Otherwise falls through. case 'BLOCK': case 'SHADOW': case 'LABEL': From fc80d71f39863e3ee0225899314ba0a5d67ca0de Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 22 Apr 2019 22:04:07 +0200 Subject: [PATCH 021/233] Localisation updates from https://translatewiki.net. --- msg/json/ee.json | 5 +++++ msg/json/zh-hans.json | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/msg/json/ee.json b/msg/json/ee.json index b5e45f101ea..80e6a0c8bd7 100644 --- a/msg/json/ee.json +++ b/msg/json/ee.json @@ -131,6 +131,11 @@ "MATH_SINGLE_TOOLTIP_ABS": "Nena xexlẽdzesi aɖe nanye xexlẽ blibo.", "MATH_SINGLE_TOOLTIP_NEG": "Nena xexlẽdzesi aɖe nanye xexlẽdzesi madenanekeo.", "MATH_SINGLE_TOOLTIP_LN": "Xexlẽdzesia nedzi ɖe edzi eɖokui zigbzi e.", + "MATH_SINGLE_TOOLTIP_LOG10": "Nebu zigbɔzi neni 10-teƒe-10 awɔ xexlẽdzesia.", + "MATH_SINGLE_TOOLTIP_EXP": "Nebu e-teƒe-e zigbɔzi xexlẽdzesia.", + "MATH_SINGLE_TOOLTIP_POW10": " Nebu ewo-teƒe-ewo zigbɔzi xexlẽdzesia.", + "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", + "MATH_TRIG_TOOLTIP_SIN": "Nebu dzogɔe le digri me (menye radiã o).", "MATH_IS_EVEN": "enye eve ƒomevi", "MATH_IS_ODD": "enye etɔ̃ ƒomevi", "MATH_IS_PRIME": " enye xexlẽme blibo", diff --git a/msg/json/zh-hans.json b/msg/json/zh-hans.json index f961fd580bf..59ed2af504c 100644 --- a/msg/json/zh-hans.json +++ b/msg/json/zh-hans.json @@ -14,7 +14,8 @@ "Tonylianlong", "WindWood", "Deathkon", - "Muhaoying" + "Muhaoying", + "佛壁灯" ] }, "VARIABLES_DEFAULT_NAME": "项目", @@ -370,5 +371,6 @@ "PROCEDURES_IFRETURN_TOOLTIP": "如果值为真,则返回第二个值。", "PROCEDURES_IFRETURN_HELPURL": "http://c2.com/cgi/wiki?GuardClause", "PROCEDURES_IFRETURN_WARNING": "警告:这个块只能在函数内部使用。", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "说点什么..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "说点什么...", + "COLLAPSED_WARNINGS_WARNING": "已收起的信息块内包含警告。" } From 1ca7d6a28bffd5f9be732c3389d6871677c799f4 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Mon, 22 Apr 2019 14:20:05 -0700 Subject: [PATCH 022/233] Clarifies what statementToCode does --- core/generator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/generator.js b/core/generator.js index ae669964ee1..fc7471b7d6e 100644 --- a/core/generator.js +++ b/core/generator.js @@ -274,7 +274,8 @@ Blockly.Generator.prototype.valueToCode = function(block, name, outerOrder) { }; /** - * Generate code representing the statement. Indent the code. + * Generate a code string representing the blocks attached to the named + * statement input. Indent the code. * This is mainly used in generators. When trying to generate code to evaluate * look at using workspaceToCode or blockToCode. * @param {!Blockly.Block} block The block containing the input. From aa4d885cbab1daa8b707757a254a780613f7d488 Mon Sep 17 00:00:00 2001 From: asunwoo98 <45576715+asunwoo98@users.noreply.github.com> Date: Mon, 22 Apr 2019 19:00:37 -0400 Subject: [PATCH 023/233] Validate newValue parameter in setValue (#2392) * Validate newValue parameter in setValue * bugfix * alternate fix * test * cleanup --- core/field.js | 6 ++++++ core/field_number.js | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/field.js b/core/field.js index 9b1beb8bb56..6b0968e94dd 100644 --- a/core/field.js +++ b/core/field.js @@ -621,6 +621,12 @@ Blockly.Field.prototype.setValue = function(newValue) { // No change if null. return; } + // Validate input. + var validated = this.callValidator(newValue); + if (validated !== null) { + newValue = validated; + } + // Check for change. var oldValue = this.getValue(); if (oldValue == newValue) { return; diff --git a/core/field_number.js b/core/field_number.js index fd144f04d43..10e0efdf03c 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -45,10 +45,10 @@ goog.require('Blockly.FieldTextInput'); */ Blockly.FieldNumber = function(opt_value, opt_min, opt_max, opt_precision, opt_validator) { + this.setConstraints(opt_min, opt_max, opt_precision); opt_value = (opt_value && !isNaN(opt_value)) ? String(opt_value) : '0'; Blockly.FieldNumber.superClass_.constructor.call( this, opt_value, opt_validator); - this.setConstraints(opt_min, opt_max, opt_precision); }; goog.inherits(Blockly.FieldNumber, Blockly.FieldTextInput); @@ -95,7 +95,6 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) { this.min_ = isNaN(min) ? -Infinity : min; max = parseFloat(max); this.max_ = isNaN(max) ? Infinity : max; - this.setValue(this.callValidator(this.getValue())); }; /** From 1b10d134a50335902bec1d961b2fe992f4640523 Mon Sep 17 00:00:00 2001 From: Jim Jiang Date: Tue, 23 Apr 2019 11:49:07 -0400 Subject: [PATCH 024/233] Add Block.setEnabled (#2386) * Implement Block.setEnabled() From issue #1593. This commit: - add setEnabled - deprecate setDisabled * Update setDisabled calls to setEnabled Add setEnabled and deprecate setDisabled in - core/block_svg Update calls in - blocks/loops - blocks/procedures - core/block_events - core/events - core/flyout_base - core/xml - tests/workplace_svg/procedure_svg_test * Implement changes from comments from RoboErikG - Implement isEnabled() - Make this.disabled @private - Make setDisabled(disabled) call setEnabled(!disabled) - Update setEnabled to use isEnabled() * Utilize isEnabled() and fix typos Fix missing parentheses Implement isEnabled() more widely Fix lint and parentheses errors * Change prevDisabledState to prevEnabledState --- blocks/loops.js | 4 +-- blocks/procedures.js | 14 +++++----- core/block.js | 30 ++++++++++++++++++--- core/block_events.js | 2 +- core/block_svg.js | 17 +++++++++--- core/events.js | 4 +-- core/flyout_base.js | 4 +-- core/xml.js | 2 +- tests/workspace_svg/procedure_svg_test.js | 32 +++++++++++------------ 9 files changed, 71 insertions(+), 38 deletions(-) diff --git a/blocks/loops.js b/blocks/loops.js index 8017808392a..fa8f9e5fed9 100644 --- a/blocks/loops.js +++ b/blocks/loops.js @@ -328,12 +328,12 @@ Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { if (legal) { this.setWarningText(null); if (!this.isInFlyout) { - this.setDisabled(false); + this.setEnabled(true); } } else { this.setWarningText(Blockly.Msg['CONTROLS_FLOW_STATEMENTS_WARNING']); if (!this.isInFlyout && !this.getInheritedDisabled()) { - this.setDisabled(true); + this.setEnabled(false); } } } diff --git a/blocks/procedures.js b/blocks/procedures.js index c53ddee3358..aee377b04a4 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -639,7 +639,7 @@ Blockly.Blocks['procedures_callnoreturn'] = { this.argumentVarModels_ = []; this.quarkConnections_ = {}; this.quarkIds_ = null; - this.previousDisabledState_ = false; + this.previousEnabledState_ = true; }, /** @@ -933,10 +933,10 @@ Blockly.Blocks['procedures_callnoreturn'] = { } Blockly.Events.setGroup(event.group); if (event.newValue) { - this.previousDisabledState_ = this.disabled; - this.setDisabled(true); + this.previousEnabledState_ = this.isEnabled(); + this.setEnabled(false); } else { - this.setDisabled(this.previousDisabledState_); + this.setEnabled(this.previousEnabledState_); } Blockly.Events.setGroup(oldGroup); } @@ -985,7 +985,7 @@ Blockly.Blocks['procedures_callreturn'] = { this.arguments_ = []; this.quarkConnections_ = {}; this.quarkIds_ = null; - this.previousDisabledState_ = false; + this.previousEnabledState_ = true; }, getProcedureCall: Blockly.Blocks['procedures_callnoreturn'].getProcedureCall, @@ -1081,12 +1081,12 @@ Blockly.Blocks['procedures_ifreturn'] = { } this.setWarningText(null); if (!this.isInFlyout) { - this.setDisabled(false); + this.setEnabled(true); } } else { this.setWarningText(Blockly.Msg['PROCEDURES_IFRETURN_WARNING']); if (!this.isInFlyout && !this.getInheritedDisabled()) { - this.setDisabled(true); + this.setEnabled(false); } } }, diff --git a/core/block.js b/core/block.js index 53587615cc0..ffa17c75379 100644 --- a/core/block.js +++ b/core/block.js @@ -75,7 +75,10 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { this.inputList = []; /** @type {boolean|undefined} */ this.inputsInline = undefined; - /** @type {boolean} */ + /** + * @type {boolean} + * @private + */ this.disabled = false; /** @type {string|!Function} */ this.tooltip = ''; @@ -1217,12 +1220,31 @@ Blockly.Block.prototype.getInputsInline = function() { /** * Set whether the block is disabled or not. * @param {boolean} disabled True if disabled. + * @deprecated May 2019 */ Blockly.Block.prototype.setDisabled = function(disabled) { - if (this.disabled != disabled) { + console.warn('Deprecated call to Blockly.Block.prototype.setDisabled, ' + + 'use Blockly.Block.prototype.setEnabled instead.'); + this.setEnabled(!disabled); +}; + +/** + * Get whether this block is enabled or not. + * @return {boolean} True if enabled. + */ +Blockly.Block.prototype.isEnabled = function() { + return !this.disabled; +}; + +/** + * Set whether the block is enabled or not. + * @param {boolean} enabled True if enabled. + */ +Blockly.Block.prototype.setEnabled = function(enabled) { + if (this.isEnabled() != enabled) { Blockly.Events.fire(new Blockly.Events.BlockChange( - this, 'disabled', null, this.disabled, disabled)); - this.disabled = disabled; + this, 'disabled', null, this.disabled, !enabled)); + this.disabled = !enabled; } }; diff --git a/core/block_events.js b/core/block_events.js index 0c3ad6cbc0e..137798eccb7 100644 --- a/core/block_events.js +++ b/core/block_events.js @@ -186,7 +186,7 @@ Blockly.Events.Change.prototype.run = function(forward) { block.setCollapsed(value); break; case 'disabled': - block.setDisabled(value); + block.setEnabled(!value); break; case 'inline': block.setInputsInline(value); diff --git a/core/block_svg.js b/core/block_svg.js index d93c2bfba45..a997d18846d 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -709,7 +709,7 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) { if (!group) { Blockly.Events.setGroup(true); } - block.setDisabled(!block.disabled); + block.setEnabled(!block.isEnabled()); if (!group) { Blockly.Events.setGroup(false); } @@ -1174,10 +1174,21 @@ Blockly.BlockSvg.prototype.setMutator = function(mutator) { /** * Set whether the block is disabled or not. * @param {boolean} disabled True if disabled. + * @deprecated May 2019 */ Blockly.BlockSvg.prototype.setDisabled = function(disabled) { - if (this.disabled != disabled) { - Blockly.BlockSvg.superClass_.setDisabled.call(this, disabled); + console.warn('Deprecated call to Blockly.BlockSvg.prototype.setDisabled, ' + + 'use Blockly.BlockSvg.prototype.setEnabled instead.'); + this.setEnabled(!disabled); +}; + +/** + * Set whether the block is enabled or not. + * @param {boolean} enabled True if enabled. + */ +Blockly.BlockSvg.prototype.setEnabled = function(enabled) { + if (this.isEnabled() != enabled) { + Blockly.BlockSvg.superClass_.setEnabled.call(this, enabled); if (this.rendered) { this.updateDisabled(); } diff --git a/core/events.js b/core/events.js index be0612c66cc..41f247f2f80 100644 --- a/core/events.js +++ b/core/events.js @@ -414,12 +414,12 @@ Blockly.Events.disableOrphans = function(event) { if (block.getParent() && !block.getParent().disabled) { var children = block.getDescendants(false); for (var i = 0, child; child = children[i]; i++) { - child.setDisabled(false); + child.setEnabled(true); } } else if ((block.outputConnection || block.previousConnection) && !workspace.isDragging()) { do { - block.setDisabled(true); + block.setEnabled(false); block = block.getNextBlock(); } while (block); } diff --git a/core/flyout_base.js b/core/flyout_base.js index 82f8bbe206a..41e0501ae33 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -750,10 +750,10 @@ Blockly.Flyout.prototype.filterForCapacity_ = function() { var blocks = this.workspace_.getTopBlocks(false); for (var i = 0, block; block = blocks[i]; i++) { if (this.permanentlyDisabled_.indexOf(block) == -1) { - var disable = !this.targetWorkspace_ + var enable = this.targetWorkspace_ .isCapacityAvailable(Blockly.utils.getBlockTypeCounts(block)); while (block) { - block.setDisabled(disable); + block.setEnabled(enable); block = block.getNextBlock(); } } diff --git a/core/xml.js b/core/xml.js index 165e3b7a7f8..91e47d83cc8 100644 --- a/core/xml.js +++ b/core/xml.js @@ -754,7 +754,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { } var disabled = xmlBlock.getAttribute('disabled'); if (disabled) { - block.setDisabled(disabled == 'true' || disabled == 'disabled'); + block.setEnabled(disabled != 'true' && disabled != 'disabled'); } var deletable = xmlBlock.getAttribute('deletable'); if (deletable) { diff --git a/tests/workspace_svg/procedure_svg_test.js b/tests/workspace_svg/procedure_svg_test.js index 42ee75dec81..fb2a88f6720 100644 --- a/tests/workspace_svg/procedure_svg_test.js +++ b/tests/workspace_svg/procedure_svg_test.js @@ -66,7 +66,7 @@ function test_procedureReturnSetDisabledUpdatesCallers() { workspace.clearUndo(); Blockly.Events.setGroup('g1'); - barDef.setDisabled(true); + barDef.setEnabled(false); Blockly.Events.setGroup(false); assertTrue('Callers are disabled when their definition is disabled.', @@ -82,7 +82,7 @@ function test_procedureReturnSetDisabledUpdatesCallers() { workspace.clearUndo(); Blockly.Events.setGroup('g2'); - barDef.setDisabled(false); + barDef.setEnabled(true); Blockly.Events.setGroup(false); assertTrue('Callers are enabled when their definition is enabled.', @@ -125,10 +125,10 @@ function test_procedureReturnEnablingRemembersOldCallerState() { var barDef = workspace.getBlockById('bar-def'); var barCalls = [workspace.getBlockById('bar-c1'), workspace.getBlockById('bar-c2')]; - barCalls[0].setDisabled(true); + barCalls[0].setEnabled(false); workspace.clearUndo(); Blockly.Events.setGroup('g1'); - barDef.setDisabled(true); + barDef.setEnabled(false); Blockly.Events.setGroup(false); assertTrue('Callers are disabled when their definition is disabled.', @@ -143,7 +143,7 @@ function test_procedureReturnEnablingRemembersOldCallerState() { workspace.clearUndo(); Blockly.Events.setGroup('g2'); - barDef.setDisabled(false); + barDef.setEnabled(true); Blockly.Events.setGroup(false); @@ -184,7 +184,7 @@ function test_procedureNoReturnSetDisabledUpdatesCallers() { workspace.clearUndo(); Blockly.Events.setGroup('g1'); - barDef.setDisabled(true); + barDef.setEnabled(false); Blockly.Events.setGroup(false); assertTrue('Callers are disabled when their definition is disabled.', @@ -200,7 +200,7 @@ function test_procedureNoReturnSetDisabledUpdatesCallers() { workspace.clearUndo(); Blockly.Events.setGroup('g2'); - barDef.setDisabled(false); + barDef.setEnabled(true); Blockly.Events.setGroup(false); assertTrue('Callers are enabled when their definition is enabled.', @@ -241,10 +241,10 @@ function test_procedureNoReturnEnablingRemembersOldCallerState() { var barDef = workspace.getBlockById('bar-def'); var barCalls = [workspace.getBlockById('bar-c1'), workspace.getBlockById('bar-c2')]; - barCalls[0].setDisabled(true); + barCalls[0].setEnabled(false); workspace.clearUndo(); Blockly.Events.setGroup('g1'); - barDef.setDisabled(true); + barDef.setEnabled(false); Blockly.Events.setGroup(false); assertTrue('Callers are disabled when their definition is disabled.', @@ -259,7 +259,7 @@ function test_procedureNoReturnEnablingRemembersOldCallerState() { workspace.clearUndo(); Blockly.Events.setGroup('g2'); - barDef.setDisabled(false); + barDef.setEnabled(true); Blockly.Events.setGroup(false); @@ -329,19 +329,19 @@ function test_procedureEnableDisableInteractions() { var fooCalls = [workspace.getBlockById('foo-c1'), workspace.getBlockById('foo-c2')]; var bazCall = workspace.getBlockById('baz-c1'); - barDef.setDisabled(true); + barDef.setEnabled(false); assertTrue('Callers are disabled when their definition is disabled.', barCalls[0].disabled && barCalls[1].disabled); assertTrue('Callers in definitions are disabled by inheritence.', !fooCalls[0].disabled && fooCalls[0].getInheritedDisabled()); - fooDef.setDisabled(true); + fooDef.setEnabled(false); assertTrue('Callers are disabled when their definition is disabled', fooCalls[0].disabled && fooCalls[1].disabled); - barDef.setDisabled(false); + barDef.setEnabled(true); assertTrue('Callers are reenabled with their definition', !barCalls[0].disabled && !barCalls[0].disabled); @@ -349,7 +349,7 @@ function test_procedureEnableDisableInteractions() { assertTrue('Nested disabled callers remain disabled, not by inheritence.', fooCalls[0].disabled && !fooCalls[0].getInheritedDisabled()); - bazDef.setDisabled(true); + bazDef.setEnabled(false); assertTrue('Caller is disabled with its definition', bazCall.disabled); @@ -357,11 +357,11 @@ function test_procedureEnableDisableInteractions() { assertTrue('Caller in the return is disabled by inheritence.', !barCalls[1].disabled && barCalls[1].getInheritedDisabled()); - barDef.setDisabled(true); + barDef.setEnabled(false); assertTrue('Callers are disabled when their definition is disabled.', barCalls[0].disabled && barCalls[1].disabled); - bazDef.setDisabled(false); + bazDef.setEnabled(true); assertTrue('Caller in the return remains disabled, not by inheritence.', barCalls[1].disabled && !barCalls[1].getInheritedDisabled()); From d625d60c4970fd8a025eaba2c3a5a953cb1d5b3c Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Tue, 23 Apr 2019 14:36:37 -0700 Subject: [PATCH 025/233] Add release and milestone information to Readme (#2401) * Add release and milestone information to Readme * Readme updates in response to comments --- README.md | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ed0a2b5170..a7d11b41cc1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ blocks together to build programs. All code is free and open source. ![](https://developers.google.com/blockly/images/sample.png) -Blockly has an active [developer forum](https://groups.google.com/forum/#!forum/blockly). Please drop by and say hello. Show us your prototypes early; collectively we have a lot of experience and can offer hints which will save you time. +Blockly has an active [developer forum](https://groups.google.com/forum/#!forum/blockly). Please drop by and say hello. Show us your prototypes early; collectively we have a lot of experience and can offer hints which will save you time. We actively monitor the forums and typically respond to questions within 2 working days. Help us focus our development efforts by telling us [what you are doing with Blockly](https://developers.google.com/blockly/registration). The questionnaire only takes @@ -17,3 +17,37 @@ a few minutes and will help us better support the Blockly community. Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs](https://saucelabs.com) Want to contribute? Great! First, read [our guidelines for contributors](https://developers.google.com/blockly/guides/modify/contributing). + +## Releases + +We release by pushing the latest code to the master branch, followed by updating our [docs](developers.google.com/blockly) and [demo pages](https://blockly-demo.appspot.com). We typically release a new version of Blockly once a quarter (every 3 months). If there are breaking bugs, such as a crash when performing a standard action or a rendering issue that makes Blockly unusable, we will cherry-pick fixes to master between releases to fix them. The [releases page](https://github.com/google/blockly/releases) has a list of all releases. + +Releases are tagged by the release date (YYYYMMDD) with a leading '1.' and a trailing '.0' in case we ever need a major or minor version (such as [1.20190419.0](https://github.com/google/blockly/tree/1.20190419.0)). If you're using npm, a specific release can be installed by using its tag: `npm install git://github.com/google/blockly.git#1.20181219.0` + +### New APIs + +Once a new API is merged into master it is considered beta until the following release. We generally try to avoid changing an API after it has been merged to master, but sometimes we need to make changes after seeing how an API is used. If an API has been around for at least two releases we'll do our best to avoid breaking it. + +Unreleased APIs may change radically. Anything that is in `develop` but not `master` is subject to change without warning. + +### Branches + +There are two main branches for Blockly. + +**[master](https://github.com/google/blockly)** - This is the (mostly) stable current release of Blockly. + +**[develop](https://github.com/google/blockly/tree/develop)** - This is where most of our work happens. Pull requests should always be made against develop. This branch will generally be usable, but may be less stable than the master branch. Once something is in develop we expect it to merge to master in the next release. + +**other branches:** - Larger changes may have their own branches until they are good enough for people to try out. These will be developed separately until we think they are almost ready for release. These branches typically get merged into develop immediately after a release to allow extra time for testing. + +## Issues and Milestones + +We typically triage all bugs within 2 working days, which includes adding any appropriate labels and assigning it to a milestone. Please keep in mind, we are a small team so even feature reqeusts that everyone agrees on may not be prioritized. + +### Milestones + +**Upcoming release** - The upcoming release milestone is for all bugs we plan on fixing before the next release. This typically has the form of `year_quarter_release` (such as `2019_q2_release`). Some bugs will be added to this release when they are triaged, others may be added closer to a release. + +**Bug Bash Backlog** - These are bugs that we're still prioritizing. They haven't been added to a specific release yet, but we'll consider them for each release depending on relative priority and available time. + +**Icebox** - These are bugs that we do not intend to spend time on. They are either too much work or minor enough that we don't expect them to ever take priority. We are still happy to accept pull requests for these bugs. From 71d7809c8d3f3ccd724cd49adf450ef8480620dc Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 23 Apr 2019 16:33:39 -0700 Subject: [PATCH 026/233] Set node version explicitly for travis; rebuild (#2403) * Set node version explicitly for travis * rebuild * Tweak travis config --- .travis.yml | 20 ++++----- blockly_uncompressed.js | 89 ++++++++++++++++++++++------------------- 2 files changed, 58 insertions(+), 51 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82b96f3d152..53320fd0c00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,14 @@ language: node_js -matrix: - include: - - os: linux - dist: trusty - node_js: stable - sudo: required - addons: - apt: - packages: - - google-chrome-stable +os: linux +dist: trusty +node_js: + - 8 + - 10 +sudo: required +addons: + apt: + packages: + - google-chrome-stable # TODO (#2114): reenable osx build. # - os: osx # node_js: stable diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 8024da7be1a..4752507f726 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -136,8 +136,6 @@ goog.addDependency("../../doc/js/article.js", [], []); goog.addDependency("../../protractor.conf.js", [], []); goog.addDependency("../../protractor_spec.js", [], []); goog.addDependency("../../third_party/closure/goog/base.js", [], []); -goog.addDependency("../../third_party/closure/goog/caja/string/html/htmlparser.js", ['goog.string.html', 'goog.string.html.HtmlParser', 'goog.string.html.HtmlParser.EFlags', 'goog.string.html.HtmlParser.Elements', 'goog.string.html.HtmlParser.Entities', 'goog.string.html.HtmlSaxHandler'], []); -goog.addDependency("../../third_party/closure/goog/caja/string/html/htmlparser_test.js", [], ['goog.string.html.HtmlParser', 'goog.string.html.HtmlSaxHandler', 'goog.testing.LooseMock', 'goog.testing.jsunit']); goog.addDependency("../../third_party/closure/goog/deps.js", [], []); goog.addDependency("../../third_party/closure/goog/dojo/dom/query.js", ['goog.dom.query'], ['goog.array', 'goog.dom', 'goog.functions', 'goog.string', 'goog.userAgent']); goog.addDependency("../../third_party/closure/goog/dojo/dom/query_test.js", ['goog.dom.query_test'], ['goog.dom', 'goog.dom.query', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.userAgent']); @@ -186,6 +184,8 @@ goog.addDependency("base_module_test.js", [], []); goog.addDependency("base_test.js", ['goog.baseTest'], ['goog.Promise', 'goog.Timer', 'goog.Uri', 'goog.dom', 'goog.dom.TagName', 'goog.object', 'goog.test_module', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit', 'goog.testing.recordFunction', 'goog.userAgent']); goog.addDependency("bootstrap/nodejs.js", [], []); goog.addDependency("bootstrap/webworkers.js", [], []); +goog.addDependency("collections/sets.js", [], []); +goog.addDependency("collections/sets_test.js", [], ['goog.testing.jsunit']); goog.addDependency("color/alpha.js", ['goog.color.alpha'], ['goog.color']); goog.addDependency("color/alpha_test.js", ['goog.color.alphaTest'], ['goog.array', 'goog.color', 'goog.color.alpha', 'goog.testing.jsunit']); goog.addDependency("color/color.js", ['goog.color', 'goog.color.Hsl', 'goog.color.Hsv', 'goog.color.Rgb'], ['goog.color.names', 'goog.math']); @@ -254,26 +254,24 @@ goog.addDependency("date/daterange.js", ['goog.date.DateRange', 'goog.date.DateR goog.addDependency("date/daterange_test.js", ['goog.date.DateRangeTest'], ['goog.date.Date', 'goog.date.DateRange', 'goog.date.Interval', 'goog.i18n.DateTimeSymbols', 'goog.testing.jsunit']); goog.addDependency("date/duration.js", ['goog.date.duration'], ['goog.i18n.DateTimeFormat', 'goog.i18n.MessageFormat']); goog.addDependency("date/duration_test.js", ['goog.date.durationTest'], ['goog.date.duration', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_bn', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_fa', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); -goog.addDependency("date/relative.js", ['goog.date.relative', 'goog.date.relative.TimeDeltaFormatter', 'goog.date.relative.Unit'], ['goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns']); +goog.addDependency("date/relative.js", ['goog.date.relative', 'goog.date.relative.TimeDeltaFormatter', 'goog.date.relative.Unit'], ['goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns', 'goog.i18n.RelativeDateTimeFormat']); goog.addDependency("date/relative_test.js", ['goog.date.relativeTest'], ['goog.date.relativeCommonTests']); -goog.addDependency("date/relativecommontests.js", ['goog.date.relativeCommonTests'], ['goog.date.DateTime', 'goog.date.relative', 'goog.i18n.DateTimeFormat', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); -goog.addDependency("date/relativewithplurals.js", ['goog.date.relativeWithPlurals'], ['goog.date.relative', 'goog.date.relative.Unit', 'goog.i18n.MessageFormat']); -goog.addDependency("date/relativewithplurals_test.js", ['goog.date.relativeWithPluralsTest'], ['goog.date.relative', 'goog.date.relativeCommonTests', 'goog.date.relativeWithPlurals', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_bn', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.NumberFormatSymbols', 'goog.i18n.NumberFormatSymbols_bn', 'goog.i18n.NumberFormatSymbols_en', 'goog.i18n.NumberFormatSymbols_fa']); +goog.addDependency("date/relativecommontests.js", ['goog.date.relativeCommonTests'], ['goog.date.DateTime', 'goog.date.relative', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns_ar', 'goog.i18n.DateTimePatterns_bn', 'goog.i18n.DateTimePatterns_es', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimeSymbols_ar', 'goog.i18n.DateTimeSymbols_bn', 'goog.i18n.DateTimeSymbols_es', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.NumberFormatSymbols_bn', 'goog.i18n.NumberFormatSymbols_fa', 'goog.i18n.relativeDateTimeSymbols', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("date/utcdatetime.js", ['goog.date.UtcDateTime'], ['goog.date', 'goog.date.Date', 'goog.date.DateTime', 'goog.date.Interval']); goog.addDependency("date/utcdatetime_test.js", ['goog.date.UtcDateTimeTest'], ['goog.date.Interval', 'goog.date.UtcDateTime', 'goog.date.month', 'goog.date.weekDay', 'goog.testing.jsunit']); goog.addDependency("db/cursor.js", ['goog.db.Cursor'], ['goog.async.Deferred', 'goog.db.Error', 'goog.db.KeyRange', 'goog.debug', 'goog.events.EventTarget']); goog.addDependency("db/db.js", ['goog.db', 'goog.db.BlockedCallback', 'goog.db.UpgradeNeededCallback'], ['goog.asserts', 'goog.async.Deferred', 'goog.db.Error', 'goog.db.IndexedDb', 'goog.db.Transaction']); -goog.addDependency("db/db_test.js", ['goog.dbTest'], ['goog.Disposable', 'goog.Promise', 'goog.array', 'goog.db', 'goog.db.Cursor', 'goog.db.Error', 'goog.db.IndexedDb', 'goog.db.KeyRange', 'goog.db.Transaction', 'goog.events', 'goog.object', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.userAgent.product']); +goog.addDependency("db/db_test.js", ['goog.dbTest'], ['goog.Promise', 'goog.array', 'goog.db', 'goog.db.Cursor', 'goog.db.Error', 'goog.db.IndexedDb', 'goog.db.KeyRange', 'goog.db.Transaction', 'goog.events', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.userAgent.product']); goog.addDependency("db/error.js", ['goog.db.DomErrorLike', 'goog.db.Error', 'goog.db.Error.ErrorCode', 'goog.db.Error.ErrorName', 'goog.db.Error.VersionChangeBlockedError'], ['goog.asserts', 'goog.debug.Error']); goog.addDependency("db/index.js", ['goog.db.Index'], ['goog.async.Deferred', 'goog.db.Cursor', 'goog.db.Error', 'goog.db.KeyRange', 'goog.debug']); goog.addDependency("db/indexeddb.js", ['goog.db.IndexedDb'], ['goog.db.Error', 'goog.db.ObjectStore', 'goog.db.Transaction', 'goog.events.Event', 'goog.events.EventHandler', 'goog.events.EventTarget']); goog.addDependency("db/keyrange.js", ['goog.db.KeyRange'], []); -goog.addDependency("db/objectstore.js", ['goog.db.ObjectStore'], ['goog.async.Deferred', 'goog.db.Cursor', 'goog.db.Error', 'goog.db.Index', 'goog.db.KeyRange', 'goog.debug', 'goog.events']); +goog.addDependency("db/objectstore.js", ['goog.db.ObjectStore'], ['goog.async.Deferred', 'goog.db.Cursor', 'goog.db.Error', 'goog.db.Index', 'goog.db.KeyRange', 'goog.debug']); goog.addDependency("db/transaction.js", ['goog.db.Transaction', 'goog.db.Transaction.TransactionMode'], ['goog.async.Deferred', 'goog.db.Error', 'goog.db.ObjectStore', 'goog.events', 'goog.events.EventHandler', 'goog.events.EventTarget']); goog.addDependency("debug/console.js", ['goog.debug.Console'], ['goog.debug.LogManager', 'goog.debug.Logger', 'goog.debug.TextFormatter']); goog.addDependency("debug/console_test.js", ['goog.debug.ConsoleTest'], ['goog.debug.Console', 'goog.debug.LogRecord', 'goog.debug.Logger', 'goog.testing.jsunit', 'goog.testing.recordFunction']); goog.addDependency("debug/debug.js", ['goog.debug'], ['goog.array', 'goog.debug.errorcontext', 'goog.userAgent']); -goog.addDependency("debug/debug_test.js", ['goog.debugTest'], ['goog.debug', 'goog.debug.errorcontext', 'goog.structs.Set', 'goog.testing.jsunit']); +goog.addDependency("debug/debug_test.js", ['goog.debugTest'], ['goog.debug', 'goog.debug.errorcontext', 'goog.testing.jsunit']); goog.addDependency("debug/debugwindow.js", ['goog.debug.DebugWindow'], ['goog.debug.HtmlFormatter', 'goog.debug.LogManager', 'goog.debug.Logger', 'goog.dom.safe', 'goog.html.SafeHtml', 'goog.html.SafeStyleSheet', 'goog.string.Const', 'goog.structs.CircularBuffer', 'goog.userAgent']); goog.addDependency("debug/debugwindow_test.js", ['goog.debug.DebugWindowTest'], ['goog.debug.DebugWindow', 'goog.testing.jsunit']); goog.addDependency("debug/devcss/devcss.js", ['goog.debug.DevCss', 'goog.debug.DevCss.UserAgent'], ['goog.asserts', 'goog.cssom', 'goog.dom.classlist', 'goog.events', 'goog.events.EventType', 'goog.string', 'goog.userAgent']); @@ -362,12 +360,12 @@ goog.addDependency("dom/dataset.js", ['goog.dom.dataset'], ['goog.labs.userAgent goog.addDependency("dom/dataset_test.js", ['goog.dom.datasetTest'], ['goog.dom', 'goog.dom.dataset', 'goog.testing.jsunit']); goog.addDependency("dom/dom.js", ['goog.dom', 'goog.dom.Appendable', 'goog.dom.DomHelper'], ['goog.array', 'goog.asserts', 'goog.dom.BrowserFeature', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.dom.safe', 'goog.html.SafeHtml', 'goog.html.uncheckedconversions', 'goog.math.Coordinate', 'goog.math.Size', 'goog.object', 'goog.string', 'goog.string.Unicode', 'goog.userAgent']); goog.addDependency("dom/dom_compile_test.js", ['goog.dom.DomCompileTest'], ['goog.dom', 'goog.dom.TagName', 'goog.testing.jsunit']); -goog.addDependency("dom/dom_test.js", ['goog.dom.dom_test'], ['goog.array', 'goog.dom', 'goog.dom.BrowserFeature', 'goog.dom.DomHelper', 'goog.dom.InputType', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.functions', 'goog.html.SafeUrl', 'goog.html.testing', 'goog.object', 'goog.string.Const', 'goog.string.Unicode', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.userAgent', 'goog.userAgent.product', 'goog.userAgent.product.isVersion']); +goog.addDependency("dom/dom_test.js", ['goog.dom.dom_test'], ['goog.array', 'goog.asserts', 'goog.dom', 'goog.dom.BrowserFeature', 'goog.dom.DomHelper', 'goog.dom.InputType', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.functions', 'goog.html.SafeUrl', 'goog.html.testing', 'goog.object', 'goog.string.Const', 'goog.string.Unicode', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.userAgent', 'goog.userAgent.product', 'goog.userAgent.product.isVersion']); goog.addDependency("dom/fontsizemonitor.js", ['goog.dom.FontSizeMonitor', 'goog.dom.FontSizeMonitor.EventType'], ['goog.dom', 'goog.dom.TagName', 'goog.events', 'goog.events.EventTarget', 'goog.events.EventType', 'goog.userAgent']); goog.addDependency("dom/fontsizemonitor_test.js", ['goog.dom.FontSizeMonitorTest'], ['goog.dom', 'goog.dom.FontSizeMonitor', 'goog.dom.TagName', 'goog.events', 'goog.events.Event', 'goog.testing.PropertyReplacer', 'goog.testing.events', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("dom/forms.js", ['goog.dom.forms'], ['goog.dom.InputType', 'goog.dom.TagName', 'goog.structs.Map', 'goog.window']); goog.addDependency("dom/forms_test.js", ['goog.dom.formsTest'], ['goog.dom', 'goog.dom.forms', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); -goog.addDependency("dom/fullscreen.js", ['goog.dom.fullscreen', 'goog.dom.fullscreen.EventType'], ['goog.dom', 'goog.userAgent']); +goog.addDependency("dom/fullscreen.js", ['goog.dom.fullscreen', 'goog.dom.fullscreen.EventType'], ['goog.dom']); goog.addDependency("dom/fullscreen_test.js", ['goog.dom.fullscreen_test'], ['goog.dom.DomHelper', 'goog.dom.fullscreen', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit']); goog.addDependency("dom/htmlelement.js", ['goog.dom.HtmlElement'], []); goog.addDependency("dom/iframe.js", ['goog.dom.iframe'], ['goog.dom', 'goog.dom.TagName', 'goog.dom.safe', 'goog.html.SafeHtml', 'goog.html.SafeStyle', 'goog.html.TrustedResourceUrl', 'goog.string.Const', 'goog.userAgent']); @@ -404,7 +402,7 @@ goog.addDependency("dom/pattern/text.js", ['goog.dom.pattern.Text'], ['goog.dom. goog.addDependency("dom/range.js", ['goog.dom.Range'], ['goog.dom', 'goog.dom.AbstractRange', 'goog.dom.BrowserFeature', 'goog.dom.ControlRange', 'goog.dom.MultiRange', 'goog.dom.NodeType', 'goog.dom.TextRange']); goog.addDependency("dom/range_test.js", ['goog.dom.RangeTest'], ['goog.dom', 'goog.dom.NodeType', 'goog.dom.Range', 'goog.dom.RangeType', 'goog.dom.TagName', 'goog.dom.TextRange', 'goog.dom.browserrange', 'goog.testing.dom', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("dom/rangeendpoint.js", ['goog.dom.RangeEndpoint'], []); -goog.addDependency("dom/safe.js", ['goog.dom.safe', 'goog.dom.safe.InsertAdjacentHtmlPosition'], ['goog.asserts', 'goog.dom.asserts', 'goog.functions', 'goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.string', 'goog.string.Const']); +goog.addDependency("dom/safe.js", ['goog.dom.safe', 'goog.dom.safe.InsertAdjacentHtmlPosition'], ['goog.asserts', 'goog.dom.asserts', 'goog.functions', 'goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.uncheckedconversions', 'goog.string.Const', 'goog.string.internal']); goog.addDependency("dom/safe_test.js", ['goog.dom.safeTest'], ['goog.asserts', 'goog.dom', 'goog.dom.TagName', 'goog.dom.safe', 'goog.dom.safe.InsertAdjacentHtmlPosition', 'goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.testing', 'goog.string', 'goog.string.Const', 'goog.testing', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("dom/savedcaretrange.js", ['goog.dom.SavedCaretRange'], ['goog.array', 'goog.dom', 'goog.dom.SavedRange', 'goog.dom.TagName', 'goog.string']); goog.addDependency("dom/savedcaretrange_test.js", ['goog.dom.SavedCaretRangeTest'], ['goog.dom', 'goog.dom.Range', 'goog.dom.SavedCaretRange', 'goog.testing.dom', 'goog.testing.jsunit', 'goog.userAgent']); @@ -522,7 +520,7 @@ goog.addDependency("events/eventtarget_test.js", ['goog.events.EventTargetTest'] goog.addDependency("events/eventtarget_via_googevents_test.js", ['goog.events.EventTargetGoogEventsTest'], ['goog.events', 'goog.events.EventTarget', 'goog.events.eventTargetTester', 'goog.events.eventTargetTester.KeyType', 'goog.events.eventTargetTester.UnlistenReturnType', 'goog.testing', 'goog.testing.jsunit']); goog.addDependency("events/eventtarget_via_w3cinterface_test.js", ['goog.events.EventTargetW3CTest'], ['goog.events.EventTarget', 'goog.events.eventTargetTester', 'goog.events.eventTargetTester.KeyType', 'goog.events.eventTargetTester.UnlistenReturnType', 'goog.testing.jsunit']); goog.addDependency("events/eventtargettester.js", ['goog.events.eventTargetTester', 'goog.events.eventTargetTester.KeyType', 'goog.events.eventTargetTester.UnlistenReturnType'], ['goog.array', 'goog.events', 'goog.events.Event', 'goog.events.EventTarget', 'goog.testing.asserts', 'goog.testing.recordFunction']); -goog.addDependency("events/eventtype.js", ['goog.events.EventType', 'goog.events.PointerAsMouseEventType', 'goog.events.PointerAsTouchEventType', 'goog.events.PointerFallbackEventType', 'goog.events.PointerTouchFallbackEventType'], ['goog.events.BrowserFeature', 'goog.userAgent']); +goog.addDependency("events/eventtype.js", ['goog.events.EventType', 'goog.events.MouseAsMouseEventType', 'goog.events.MouseEvents', 'goog.events.PointerAsMouseEventType', 'goog.events.PointerAsTouchEventType', 'goog.events.PointerFallbackEventType', 'goog.events.PointerTouchFallbackEventType'], ['goog.events.BrowserFeature', 'goog.userAgent']); goog.addDependency("events/eventtype_test.js", ['goog.events.EventTypeTest'], ['goog.events.BrowserFeature', 'goog.events.EventType', 'goog.events.PointerFallbackEventType', 'goog.events.PointerTouchFallbackEventType', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("events/eventwrapper.js", ['goog.events.EventWrapper'], []); goog.addDependency("events/filedrophandler.js", ['goog.events.FileDropHandler', 'goog.events.FileDropHandler.EventType'], ['goog.array', 'goog.dom', 'goog.events.BrowserEvent', 'goog.events.EventHandler', 'goog.events.EventTarget', 'goog.events.EventType', 'goog.log', 'goog.log.Level']); @@ -663,18 +661,18 @@ goog.addDependency("html/flash.js", ['goog.html.flash'], ['goog.asserts', 'goog. goog.addDependency("html/flash_test.js", ['goog.html.flashTest'], ['goog.html.SafeHtml', 'goog.html.TrustedResourceUrl', 'goog.html.flash', 'goog.string.Const', 'goog.testing.jsunit']); goog.addDependency("html/legacyconversions.js", ['goog.html.legacyconversions'], ['goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl']); goog.addDependency("html/legacyconversions_test.js", ['goog.html.legacyconversionsTest'], ['goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.legacyconversions', 'goog.testing.jsunit']); -goog.addDependency("html/safehtml.js", ['goog.html.SafeHtml'], ['goog.array', 'goog.asserts', 'goog.dom.TagName', 'goog.dom.tags', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.i18n.bidi.Dir', 'goog.i18n.bidi.DirectionalString', 'goog.labs.userAgent.browser', 'goog.object', 'goog.string', 'goog.string.Const', 'goog.string.TypedString']); -goog.addDependency("html/safehtml_test.js", ['goog.html.safeHtmlTest'], ['goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.testing', 'goog.i18n.bidi.Dir', 'goog.labs.userAgent.browser', 'goog.object', 'goog.string.Const', 'goog.testing.jsunit']); +goog.addDependency("html/safehtml.js", ['goog.html.SafeHtml'], ['goog.array', 'goog.asserts', 'goog.dom.TagName', 'goog.dom.tags', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.trustedtypes', 'goog.i18n.bidi.Dir', 'goog.i18n.bidi.DirectionalString', 'goog.labs.userAgent.browser', 'goog.object', 'goog.string.Const', 'goog.string.TypedString', 'goog.string.internal']); +goog.addDependency("html/safehtml_test.js", ['goog.html.safeHtmlTest'], ['goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.testing', 'goog.html.trustedtypes', 'goog.i18n.bidi.Dir', 'goog.labs.userAgent.browser', 'goog.object', 'goog.string.Const', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("html/safehtmlformatter.js", ['goog.html.SafeHtmlFormatter'], ['goog.asserts', 'goog.dom.tags', 'goog.html.SafeHtml', 'goog.string']); goog.addDependency("html/safehtmlformatter_test.js", ['goog.html.safeHtmlFormatterTest'], ['goog.html.SafeHtml', 'goog.html.SafeHtmlFormatter', 'goog.html.SafeUrl', 'goog.string', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); -goog.addDependency("html/safescript.js", ['goog.html.SafeScript'], ['goog.asserts', 'goog.string.Const', 'goog.string.TypedString']); -goog.addDependency("html/safescript_test.js", ['goog.html.safeScriptTest'], ['goog.html.SafeScript', 'goog.object', 'goog.string.Const', 'goog.testing.jsunit']); -goog.addDependency("html/safestyle.js", ['goog.html.SafeStyle'], ['goog.array', 'goog.asserts', 'goog.html.SafeUrl', 'goog.string', 'goog.string.Const', 'goog.string.TypedString']); +goog.addDependency("html/safescript.js", ['goog.html.SafeScript'], ['goog.asserts', 'goog.html.trustedtypes', 'goog.string.Const', 'goog.string.TypedString']); +goog.addDependency("html/safescript_test.js", ['goog.html.safeScriptTest'], ['goog.html.SafeScript', 'goog.html.trustedtypes', 'goog.object', 'goog.string.Const', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); +goog.addDependency("html/safestyle.js", ['goog.html.SafeStyle'], ['goog.array', 'goog.asserts', 'goog.html.SafeUrl', 'goog.string.Const', 'goog.string.TypedString', 'goog.string.internal']); goog.addDependency("html/safestyle_test.js", ['goog.html.safeStyleTest'], ['goog.html.SafeStyle', 'goog.html.SafeUrl', 'goog.object', 'goog.string.Const', 'goog.testing.jsunit']); -goog.addDependency("html/safestylesheet.js", ['goog.html.SafeStyleSheet'], ['goog.array', 'goog.asserts', 'goog.html.SafeStyle', 'goog.object', 'goog.string', 'goog.string.Const', 'goog.string.TypedString']); +goog.addDependency("html/safestylesheet.js", ['goog.html.SafeStyleSheet'], ['goog.array', 'goog.asserts', 'goog.html.SafeStyle', 'goog.object', 'goog.string.Const', 'goog.string.TypedString', 'goog.string.internal']); goog.addDependency("html/safestylesheet_test.js", ['goog.html.safeStyleSheetTest'], ['goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.object', 'goog.string.Const', 'goog.testing.jsunit']); -goog.addDependency("html/safeurl.js", ['goog.html.SafeUrl'], ['goog.asserts', 'goog.fs.url', 'goog.html.TrustedResourceUrl', 'goog.i18n.bidi.Dir', 'goog.i18n.bidi.DirectionalString', 'goog.string', 'goog.string.Const', 'goog.string.TypedString']); -goog.addDependency("html/safeurl_test.js", ['goog.html.safeUrlTest'], ['goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.safeUrlTestVectors', 'goog.i18n.bidi.Dir', 'goog.object', 'goog.string.Const', 'goog.testing.jsunit', 'goog.userAgent']); +goog.addDependency("html/safeurl.js", ['goog.html.SafeUrl'], ['goog.asserts', 'goog.fs.url', 'goog.html.TrustedResourceUrl', 'goog.html.trustedtypes', 'goog.i18n.bidi.Dir', 'goog.i18n.bidi.DirectionalString', 'goog.string.Const', 'goog.string.TypedString', 'goog.string.internal']); +goog.addDependency("html/safeurl_test.js", ['goog.html.safeUrlTest'], ['goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.safeUrlTestVectors', 'goog.html.trustedtypes', 'goog.i18n.bidi.Dir', 'goog.object', 'goog.string.Const', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("html/safeurl_test_vectors.js", ['goog.html.safeUrlTestVectors'], []); goog.addDependency("html/sanitizer/attributewhitelist.js", ['goog.html.sanitizer.AttributeSanitizedWhitelist', 'goog.html.sanitizer.AttributeWhitelist'], []); goog.addDependency("html/sanitizer/csspropertysanitizer.js", [], []); @@ -698,9 +696,10 @@ goog.addDependency("html/silverlight_test.js", ['goog.html.silverlightTest'], [' goog.addDependency("html/testing.js", ['goog.html.testing'], ['goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.testing.mockmatchers.ArgumentMatcher']); goog.addDependency("html/textextractor.js", ['goog.html.textExtractor'], ['goog.array', 'goog.dom.TagName', 'goog.html.sanitizer.HtmlSanitizer', 'goog.object', 'goog.userAgent']); goog.addDependency("html/textextractor_test.js", [], []); -goog.addDependency("html/trustedresourceurl.js", ['goog.html.TrustedResourceUrl'], ['goog.asserts', 'goog.i18n.bidi.Dir', 'goog.i18n.bidi.DirectionalString', 'goog.string.Const', 'goog.string.TypedString']); -goog.addDependency("html/trustedresourceurl_test.js", ['goog.html.trustedResourceUrlTest'], ['goog.html.TrustedResourceUrl', 'goog.i18n.bidi.Dir', 'goog.object', 'goog.string.Const', 'goog.testing.jsunit']); -goog.addDependency("html/uncheckedconversions.js", ['goog.html.uncheckedconversions'], ['goog.asserts', 'goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.string', 'goog.string.Const']); +goog.addDependency("html/trustedresourceurl.js", ['goog.html.TrustedResourceUrl'], ['goog.asserts', 'goog.html.trustedtypes', 'goog.i18n.bidi.Dir', 'goog.i18n.bidi.DirectionalString', 'goog.string.Const', 'goog.string.TypedString']); +goog.addDependency("html/trustedresourceurl_test.js", ['goog.html.trustedResourceUrlTest'], ['goog.html.TrustedResourceUrl', 'goog.html.trustedtypes', 'goog.i18n.bidi.Dir', 'goog.object', 'goog.string.Const', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); +goog.addDependency("html/trustedtypes.js", ['goog.html.trustedtypes'], []); +goog.addDependency("html/uncheckedconversions.js", ['goog.html.uncheckedconversions'], ['goog.asserts', 'goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.string.Const', 'goog.string.internal']); goog.addDependency("html/uncheckedconversions_test.js", ['goog.html.uncheckedconversionsTest'], ['goog.html.SafeHtml', 'goog.html.SafeScript', 'goog.html.SafeStyle', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.html.uncheckedconversions', 'goog.i18n.bidi.Dir', 'goog.string.Const', 'goog.testing.jsunit']); goog.addDependency("html/utils.js", ['goog.html.utils'], ['goog.string']); goog.addDependency("html/utils_test.js", ['goog.html.UtilsTest'], ['goog.array', 'goog.dom.TagName', 'goog.html.utils', 'goog.object', 'goog.testing.jsunit']); @@ -725,7 +724,7 @@ goog.addDependency("i18n/dateintervalpatternsext.js", [], []); goog.addDependency("i18n/dateintervalsymbols.js", [], []); goog.addDependency("i18n/dateintervalsymbolsext.js", [], []); goog.addDependency("i18n/datetimeformat.js", ['goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeFormat.Format'], ['goog.asserts', 'goog.date', 'goog.i18n.DateTimeSymbols', 'goog.i18n.TimeZone', 'goog.string']); -goog.addDependency("i18n/datetimeformat_test.js", ['goog.i18n.DateTimeFormatTest'], ['goog.date.Date', 'goog.date.DateTime', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns', 'goog.i18n.DateTimePatterns_ar_EG', 'goog.i18n.DateTimePatterns_de', 'goog.i18n.DateTimePatterns_en', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimePatterns_ja', 'goog.i18n.DateTimePatterns_sv', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_ar_AE', 'goog.i18n.DateTimeSymbols_ar_EG', 'goog.i18n.DateTimeSymbols_ar_SA', 'goog.i18n.DateTimeSymbols_bn_BD', 'goog.i18n.DateTimeSymbols_de', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_en_GB', 'goog.i18n.DateTimeSymbols_en_IE', 'goog.i18n.DateTimeSymbols_en_IN', 'goog.i18n.DateTimeSymbols_en_US', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.DateTimeSymbols_fr_DJ', 'goog.i18n.DateTimeSymbols_he_IL', 'goog.i18n.DateTimeSymbols_ja', 'goog.i18n.DateTimeSymbols_ro_RO', 'goog.i18n.DateTimeSymbols_sv', 'goog.i18n.TimeZone', 'goog.testing.jsunit']); +goog.addDependency("i18n/datetimeformat_test.js", ['goog.i18n.DateTimeFormatTest'], ['goog.date.Date', 'goog.date.DateTime', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns', 'goog.i18n.DateTimePatterns_ar_EG', 'goog.i18n.DateTimePatterns_bg', 'goog.i18n.DateTimePatterns_de', 'goog.i18n.DateTimePatterns_en', 'goog.i18n.DateTimePatterns_en_XA', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimePatterns_ja', 'goog.i18n.DateTimePatterns_sv', 'goog.i18n.DateTimePatterns_zh_HK', 'goog.i18n.DateTimePatterns_zh_Hant_TW', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_ar_AE', 'goog.i18n.DateTimeSymbols_ar_EG', 'goog.i18n.DateTimeSymbols_ar_SA', 'goog.i18n.DateTimeSymbols_bn_BD', 'goog.i18n.DateTimeSymbols_de', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_en_GB', 'goog.i18n.DateTimeSymbols_en_IE', 'goog.i18n.DateTimeSymbols_en_IN', 'goog.i18n.DateTimeSymbols_en_US', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.DateTimeSymbols_fr_DJ', 'goog.i18n.DateTimeSymbols_he_IL', 'goog.i18n.DateTimeSymbols_ja', 'goog.i18n.DateTimeSymbols_ro_RO', 'goog.i18n.DateTimeSymbols_sv', 'goog.i18n.TimeZone', 'goog.testing.jsunit']); goog.addDependency("i18n/datetimeparse.js", ['goog.i18n.DateTimeParse'], ['goog.asserts', 'goog.date', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeSymbols']); goog.addDependency("i18n/datetimeparse_test.js", ['goog.i18n.DateTimeParseTest'], ['goog.date.Date', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeParse', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.DateTimeSymbols_pl', 'goog.i18n.DateTimeSymbols_zh', 'goog.testing.ExpectedFailures', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("i18n/datetimepatterns.js", ['goog.i18n.DateTimePatterns', 'goog.i18n.DateTimePatterns_af', 'goog.i18n.DateTimePatterns_am', 'goog.i18n.DateTimePatterns_ar', 'goog.i18n.DateTimePatterns_ar_DZ', 'goog.i18n.DateTimePatterns_ar_EG', 'goog.i18n.DateTimePatterns_az', 'goog.i18n.DateTimePatterns_be', 'goog.i18n.DateTimePatterns_bg', 'goog.i18n.DateTimePatterns_bn', 'goog.i18n.DateTimePatterns_br', 'goog.i18n.DateTimePatterns_bs', 'goog.i18n.DateTimePatterns_ca', 'goog.i18n.DateTimePatterns_chr', 'goog.i18n.DateTimePatterns_cs', 'goog.i18n.DateTimePatterns_cy', 'goog.i18n.DateTimePatterns_da', 'goog.i18n.DateTimePatterns_de', 'goog.i18n.DateTimePatterns_de_AT', 'goog.i18n.DateTimePatterns_de_CH', 'goog.i18n.DateTimePatterns_el', 'goog.i18n.DateTimePatterns_en', 'goog.i18n.DateTimePatterns_en_AU', 'goog.i18n.DateTimePatterns_en_CA', 'goog.i18n.DateTimePatterns_en_GB', 'goog.i18n.DateTimePatterns_en_IE', 'goog.i18n.DateTimePatterns_en_IN', 'goog.i18n.DateTimePatterns_en_SG', 'goog.i18n.DateTimePatterns_en_US', 'goog.i18n.DateTimePatterns_en_ZA', 'goog.i18n.DateTimePatterns_es', 'goog.i18n.DateTimePatterns_es_419', 'goog.i18n.DateTimePatterns_es_ES', 'goog.i18n.DateTimePatterns_es_MX', 'goog.i18n.DateTimePatterns_es_US', 'goog.i18n.DateTimePatterns_et', 'goog.i18n.DateTimePatterns_eu', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fi', 'goog.i18n.DateTimePatterns_fil', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimePatterns_fr_CA', 'goog.i18n.DateTimePatterns_ga', 'goog.i18n.DateTimePatterns_gl', 'goog.i18n.DateTimePatterns_gsw', 'goog.i18n.DateTimePatterns_gu', 'goog.i18n.DateTimePatterns_haw', 'goog.i18n.DateTimePatterns_he', 'goog.i18n.DateTimePatterns_hi', 'goog.i18n.DateTimePatterns_hr', 'goog.i18n.DateTimePatterns_hu', 'goog.i18n.DateTimePatterns_hy', 'goog.i18n.DateTimePatterns_id', 'goog.i18n.DateTimePatterns_in', 'goog.i18n.DateTimePatterns_is', 'goog.i18n.DateTimePatterns_it', 'goog.i18n.DateTimePatterns_iw', 'goog.i18n.DateTimePatterns_ja', 'goog.i18n.DateTimePatterns_ka', 'goog.i18n.DateTimePatterns_kk', 'goog.i18n.DateTimePatterns_km', 'goog.i18n.DateTimePatterns_kn', 'goog.i18n.DateTimePatterns_ko', 'goog.i18n.DateTimePatterns_ky', 'goog.i18n.DateTimePatterns_ln', 'goog.i18n.DateTimePatterns_lo', 'goog.i18n.DateTimePatterns_lt', 'goog.i18n.DateTimePatterns_lv', 'goog.i18n.DateTimePatterns_mk', 'goog.i18n.DateTimePatterns_ml', 'goog.i18n.DateTimePatterns_mn', 'goog.i18n.DateTimePatterns_mo', 'goog.i18n.DateTimePatterns_mr', 'goog.i18n.DateTimePatterns_ms', 'goog.i18n.DateTimePatterns_mt', 'goog.i18n.DateTimePatterns_my', 'goog.i18n.DateTimePatterns_nb', 'goog.i18n.DateTimePatterns_ne', 'goog.i18n.DateTimePatterns_nl', 'goog.i18n.DateTimePatterns_no', 'goog.i18n.DateTimePatterns_no_NO', 'goog.i18n.DateTimePatterns_or', 'goog.i18n.DateTimePatterns_pa', 'goog.i18n.DateTimePatterns_pl', 'goog.i18n.DateTimePatterns_pt', 'goog.i18n.DateTimePatterns_pt_BR', 'goog.i18n.DateTimePatterns_pt_PT', 'goog.i18n.DateTimePatterns_ro', 'goog.i18n.DateTimePatterns_ru', 'goog.i18n.DateTimePatterns_sh', 'goog.i18n.DateTimePatterns_si', 'goog.i18n.DateTimePatterns_sk', 'goog.i18n.DateTimePatterns_sl', 'goog.i18n.DateTimePatterns_sq', 'goog.i18n.DateTimePatterns_sr', 'goog.i18n.DateTimePatterns_sr_Latn', 'goog.i18n.DateTimePatterns_sv', 'goog.i18n.DateTimePatterns_sw', 'goog.i18n.DateTimePatterns_ta', 'goog.i18n.DateTimePatterns_te', 'goog.i18n.DateTimePatterns_th', 'goog.i18n.DateTimePatterns_tl', 'goog.i18n.DateTimePatterns_tr', 'goog.i18n.DateTimePatterns_uk', 'goog.i18n.DateTimePatterns_ur', 'goog.i18n.DateTimePatterns_uz', 'goog.i18n.DateTimePatterns_vi', 'goog.i18n.DateTimePatterns_zh', 'goog.i18n.DateTimePatterns_zh_CN', 'goog.i18n.DateTimePatterns_zh_HK', 'goog.i18n.DateTimePatterns_zh_TW', 'goog.i18n.DateTimePatterns_zu'], []); @@ -745,6 +744,10 @@ goog.addDependency("i18n/numberformatsymbolsext.js", ['goog.i18n.NumberFormatSym goog.addDependency("i18n/ordinalrules.js", ['goog.i18n.ordinalRules'], []); goog.addDependency("i18n/pluralrules.js", ['goog.i18n.pluralRules'], []); goog.addDependency("i18n/pluralrules_test.js", ['goog.i18n.pluralRulesTest'], ['goog.i18n.pluralRules', 'goog.testing.jsunit']); +goog.addDependency("i18n/relativedatetimeformat.js", [], []); +goog.addDependency("i18n/relativedatetimeformat_test.js", [], []); +goog.addDependency("i18n/relativedatetimesymbols.js", [], []); +goog.addDependency("i18n/relativedatetimesymbolsext.js", [], []); goog.addDependency("i18n/timezone.js", ['goog.i18n.TimeZone'], ['goog.array', 'goog.date.DateLike', 'goog.object', 'goog.string']); goog.addDependency("i18n/timezone_test.js", ['goog.i18n.TimeZoneTest'], ['goog.i18n.TimeZone', 'goog.testing.jsunit']); goog.addDependency("i18n/uchar.js", ['goog.i18n.uChar'], []); @@ -765,9 +768,12 @@ goog.addDependency("json/hybrid_test.js", ['goog.json.hybridTest'], ['goog.json' goog.addDependency("json/json.js", ['goog.json', 'goog.json.Replacer', 'goog.json.Reviver', 'goog.json.Serializer'], []); goog.addDependency("json/json_perf.js", ['goog.jsonPerf'], ['goog.dom', 'goog.json', 'goog.math', 'goog.string', 'goog.testing.PerformanceTable', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("json/json_test.js", ['goog.jsonTest'], ['goog.functions', 'goog.json', 'goog.testing.jsunit', 'goog.userAgent']); +goog.addDependency("json/jsonable.js", [], []); goog.addDependency("json/nativejsonprocessor.js", ['goog.json.NativeJsonProcessor'], ['goog.asserts', 'goog.json.Processor']); goog.addDependency("json/processor.js", ['goog.json.Processor'], ['goog.string.Parser', 'goog.string.Stringifier']); goog.addDependency("json/processor_test.js", ['goog.json.processorTest'], ['goog.json.NativeJsonProcessor', 'goog.testing.jsunit', 'goog.userAgent']); +goog.addDependency("labs/collections/iterables.js", [], []); +goog.addDependency("labs/collections/iterables_test.js", [], []); goog.addDependency("labs/dom/pagevisibilitymonitor.js", ['goog.labs.dom.PageVisibilityEvent', 'goog.labs.dom.PageVisibilityMonitor', 'goog.labs.dom.PageVisibilityState'], ['goog.dom', 'goog.dom.vendor', 'goog.events', 'goog.events.Event', 'goog.events.EventTarget', 'goog.events.EventType', 'goog.memoize']); goog.addDependency("labs/dom/pagevisibilitymonitor_test.js", ['goog.labs.dom.PageVisibilityMonitorTest'], ['goog.events', 'goog.functions', 'goog.labs.dom.PageVisibilityMonitor', 'goog.testing.PropertyReplacer', 'goog.testing.events', 'goog.testing.events.Event', 'goog.testing.jsunit', 'goog.testing.recordFunction']); goog.addDependency("labs/events/nondisposableeventtarget.js", ['goog.labs.events.NonDisposableEventTarget'], ['goog.array', 'goog.asserts', 'goog.events.Event', 'goog.events.Listenable', 'goog.events.ListenerMap', 'goog.object']); @@ -781,13 +787,11 @@ goog.addDependency("labs/i18n/listformat.js", ['goog.labs.i18n.GenderInfo', 'goo goog.addDependency("labs/i18n/listformat_test.js", ['goog.labs.i18n.ListFormatTest'], ['goog.labs.i18n.GenderInfo', 'goog.labs.i18n.ListFormat', 'goog.labs.i18n.ListFormatSymbols', 'goog.labs.i18n.ListFormatSymbols_el', 'goog.labs.i18n.ListFormatSymbols_en', 'goog.labs.i18n.ListFormatSymbols_fr', 'goog.labs.i18n.ListFormatSymbols_ml', 'goog.labs.i18n.ListFormatSymbols_zu', 'goog.testing.jsunit']); goog.addDependency("labs/i18n/listsymbols.js", ['goog.labs.i18n.ListFormatSymbols', 'goog.labs.i18n.ListFormatSymbols_af', 'goog.labs.i18n.ListFormatSymbols_am', 'goog.labs.i18n.ListFormatSymbols_ar', 'goog.labs.i18n.ListFormatSymbols_ar_DZ', 'goog.labs.i18n.ListFormatSymbols_ar_EG', 'goog.labs.i18n.ListFormatSymbols_az', 'goog.labs.i18n.ListFormatSymbols_be', 'goog.labs.i18n.ListFormatSymbols_bg', 'goog.labs.i18n.ListFormatSymbols_bn', 'goog.labs.i18n.ListFormatSymbols_br', 'goog.labs.i18n.ListFormatSymbols_bs', 'goog.labs.i18n.ListFormatSymbols_ca', 'goog.labs.i18n.ListFormatSymbols_chr', 'goog.labs.i18n.ListFormatSymbols_cs', 'goog.labs.i18n.ListFormatSymbols_cy', 'goog.labs.i18n.ListFormatSymbols_da', 'goog.labs.i18n.ListFormatSymbols_de', 'goog.labs.i18n.ListFormatSymbols_de_AT', 'goog.labs.i18n.ListFormatSymbols_de_CH', 'goog.labs.i18n.ListFormatSymbols_el', 'goog.labs.i18n.ListFormatSymbols_en', 'goog.labs.i18n.ListFormatSymbols_en_AU', 'goog.labs.i18n.ListFormatSymbols_en_CA', 'goog.labs.i18n.ListFormatSymbols_en_GB', 'goog.labs.i18n.ListFormatSymbols_en_IE', 'goog.labs.i18n.ListFormatSymbols_en_IN', 'goog.labs.i18n.ListFormatSymbols_en_SG', 'goog.labs.i18n.ListFormatSymbols_en_US', 'goog.labs.i18n.ListFormatSymbols_en_ZA', 'goog.labs.i18n.ListFormatSymbols_es', 'goog.labs.i18n.ListFormatSymbols_es_419', 'goog.labs.i18n.ListFormatSymbols_es_ES', 'goog.labs.i18n.ListFormatSymbols_es_MX', 'goog.labs.i18n.ListFormatSymbols_es_US', 'goog.labs.i18n.ListFormatSymbols_et', 'goog.labs.i18n.ListFormatSymbols_eu', 'goog.labs.i18n.ListFormatSymbols_fa', 'goog.labs.i18n.ListFormatSymbols_fi', 'goog.labs.i18n.ListFormatSymbols_fil', 'goog.labs.i18n.ListFormatSymbols_fr', 'goog.labs.i18n.ListFormatSymbols_fr_CA', 'goog.labs.i18n.ListFormatSymbols_ga', 'goog.labs.i18n.ListFormatSymbols_gl', 'goog.labs.i18n.ListFormatSymbols_gsw', 'goog.labs.i18n.ListFormatSymbols_gu', 'goog.labs.i18n.ListFormatSymbols_haw', 'goog.labs.i18n.ListFormatSymbols_he', 'goog.labs.i18n.ListFormatSymbols_hi', 'goog.labs.i18n.ListFormatSymbols_hr', 'goog.labs.i18n.ListFormatSymbols_hu', 'goog.labs.i18n.ListFormatSymbols_hy', 'goog.labs.i18n.ListFormatSymbols_id', 'goog.labs.i18n.ListFormatSymbols_in', 'goog.labs.i18n.ListFormatSymbols_is', 'goog.labs.i18n.ListFormatSymbols_it', 'goog.labs.i18n.ListFormatSymbols_iw', 'goog.labs.i18n.ListFormatSymbols_ja', 'goog.labs.i18n.ListFormatSymbols_ka', 'goog.labs.i18n.ListFormatSymbols_kk', 'goog.labs.i18n.ListFormatSymbols_km', 'goog.labs.i18n.ListFormatSymbols_kn', 'goog.labs.i18n.ListFormatSymbols_ko', 'goog.labs.i18n.ListFormatSymbols_ky', 'goog.labs.i18n.ListFormatSymbols_ln', 'goog.labs.i18n.ListFormatSymbols_lo', 'goog.labs.i18n.ListFormatSymbols_lt', 'goog.labs.i18n.ListFormatSymbols_lv', 'goog.labs.i18n.ListFormatSymbols_mk', 'goog.labs.i18n.ListFormatSymbols_ml', 'goog.labs.i18n.ListFormatSymbols_mn', 'goog.labs.i18n.ListFormatSymbols_mo', 'goog.labs.i18n.ListFormatSymbols_mr', 'goog.labs.i18n.ListFormatSymbols_ms', 'goog.labs.i18n.ListFormatSymbols_mt', 'goog.labs.i18n.ListFormatSymbols_my', 'goog.labs.i18n.ListFormatSymbols_nb', 'goog.labs.i18n.ListFormatSymbols_ne', 'goog.labs.i18n.ListFormatSymbols_nl', 'goog.labs.i18n.ListFormatSymbols_no', 'goog.labs.i18n.ListFormatSymbols_no_NO', 'goog.labs.i18n.ListFormatSymbols_or', 'goog.labs.i18n.ListFormatSymbols_pa', 'goog.labs.i18n.ListFormatSymbols_pl', 'goog.labs.i18n.ListFormatSymbols_pt', 'goog.labs.i18n.ListFormatSymbols_pt_BR', 'goog.labs.i18n.ListFormatSymbols_pt_PT', 'goog.labs.i18n.ListFormatSymbols_ro', 'goog.labs.i18n.ListFormatSymbols_ru', 'goog.labs.i18n.ListFormatSymbols_sh', 'goog.labs.i18n.ListFormatSymbols_si', 'goog.labs.i18n.ListFormatSymbols_sk', 'goog.labs.i18n.ListFormatSymbols_sl', 'goog.labs.i18n.ListFormatSymbols_sq', 'goog.labs.i18n.ListFormatSymbols_sr', 'goog.labs.i18n.ListFormatSymbols_sr_Latn', 'goog.labs.i18n.ListFormatSymbols_sv', 'goog.labs.i18n.ListFormatSymbols_sw', 'goog.labs.i18n.ListFormatSymbols_ta', 'goog.labs.i18n.ListFormatSymbols_te', 'goog.labs.i18n.ListFormatSymbols_th', 'goog.labs.i18n.ListFormatSymbols_tl', 'goog.labs.i18n.ListFormatSymbols_tr', 'goog.labs.i18n.ListFormatSymbols_uk', 'goog.labs.i18n.ListFormatSymbols_ur', 'goog.labs.i18n.ListFormatSymbols_uz', 'goog.labs.i18n.ListFormatSymbols_vi', 'goog.labs.i18n.ListFormatSymbols_zh', 'goog.labs.i18n.ListFormatSymbols_zh_CN', 'goog.labs.i18n.ListFormatSymbols_zh_HK', 'goog.labs.i18n.ListFormatSymbols_zh_TW', 'goog.labs.i18n.ListFormatSymbols_zu'], []); goog.addDependency("labs/i18n/listsymbolsext.js", ['goog.labs.i18n.ListFormatSymbolsExt', 'goog.labs.i18n.ListFormatSymbols_af_NA', 'goog.labs.i18n.ListFormatSymbols_af_ZA', 'goog.labs.i18n.ListFormatSymbols_agq', 'goog.labs.i18n.ListFormatSymbols_agq_CM', 'goog.labs.i18n.ListFormatSymbols_ak', 'goog.labs.i18n.ListFormatSymbols_ak_GH', 'goog.labs.i18n.ListFormatSymbols_am_ET', 'goog.labs.i18n.ListFormatSymbols_ar_001', 'goog.labs.i18n.ListFormatSymbols_ar_AE', 'goog.labs.i18n.ListFormatSymbols_ar_BH', 'goog.labs.i18n.ListFormatSymbols_ar_DJ', 'goog.labs.i18n.ListFormatSymbols_ar_EH', 'goog.labs.i18n.ListFormatSymbols_ar_ER', 'goog.labs.i18n.ListFormatSymbols_ar_IL', 'goog.labs.i18n.ListFormatSymbols_ar_IQ', 'goog.labs.i18n.ListFormatSymbols_ar_JO', 'goog.labs.i18n.ListFormatSymbols_ar_KM', 'goog.labs.i18n.ListFormatSymbols_ar_KW', 'goog.labs.i18n.ListFormatSymbols_ar_LB', 'goog.labs.i18n.ListFormatSymbols_ar_LY', 'goog.labs.i18n.ListFormatSymbols_ar_MA', 'goog.labs.i18n.ListFormatSymbols_ar_MR', 'goog.labs.i18n.ListFormatSymbols_ar_OM', 'goog.labs.i18n.ListFormatSymbols_ar_PS', 'goog.labs.i18n.ListFormatSymbols_ar_QA', 'goog.labs.i18n.ListFormatSymbols_ar_SA', 'goog.labs.i18n.ListFormatSymbols_ar_SD', 'goog.labs.i18n.ListFormatSymbols_ar_SO', 'goog.labs.i18n.ListFormatSymbols_ar_SS', 'goog.labs.i18n.ListFormatSymbols_ar_SY', 'goog.labs.i18n.ListFormatSymbols_ar_TD', 'goog.labs.i18n.ListFormatSymbols_ar_TN', 'goog.labs.i18n.ListFormatSymbols_ar_XB', 'goog.labs.i18n.ListFormatSymbols_ar_YE', 'goog.labs.i18n.ListFormatSymbols_as', 'goog.labs.i18n.ListFormatSymbols_as_IN', 'goog.labs.i18n.ListFormatSymbols_asa', 'goog.labs.i18n.ListFormatSymbols_asa_TZ', 'goog.labs.i18n.ListFormatSymbols_ast', 'goog.labs.i18n.ListFormatSymbols_ast_ES', 'goog.labs.i18n.ListFormatSymbols_az_Cyrl', 'goog.labs.i18n.ListFormatSymbols_az_Cyrl_AZ', 'goog.labs.i18n.ListFormatSymbols_az_Latn', 'goog.labs.i18n.ListFormatSymbols_az_Latn_AZ', 'goog.labs.i18n.ListFormatSymbols_bas', 'goog.labs.i18n.ListFormatSymbols_bas_CM', 'goog.labs.i18n.ListFormatSymbols_be_BY', 'goog.labs.i18n.ListFormatSymbols_bem', 'goog.labs.i18n.ListFormatSymbols_bem_ZM', 'goog.labs.i18n.ListFormatSymbols_bez', 'goog.labs.i18n.ListFormatSymbols_bez_TZ', 'goog.labs.i18n.ListFormatSymbols_bg_BG', 'goog.labs.i18n.ListFormatSymbols_bm', 'goog.labs.i18n.ListFormatSymbols_bm_ML', 'goog.labs.i18n.ListFormatSymbols_bn_BD', 'goog.labs.i18n.ListFormatSymbols_bn_IN', 'goog.labs.i18n.ListFormatSymbols_bo', 'goog.labs.i18n.ListFormatSymbols_bo_CN', 'goog.labs.i18n.ListFormatSymbols_bo_IN', 'goog.labs.i18n.ListFormatSymbols_br_FR', 'goog.labs.i18n.ListFormatSymbols_brx', 'goog.labs.i18n.ListFormatSymbols_brx_IN', 'goog.labs.i18n.ListFormatSymbols_bs_Cyrl', 'goog.labs.i18n.ListFormatSymbols_bs_Cyrl_BA', 'goog.labs.i18n.ListFormatSymbols_bs_Latn', 'goog.labs.i18n.ListFormatSymbols_bs_Latn_BA', 'goog.labs.i18n.ListFormatSymbols_ca_AD', 'goog.labs.i18n.ListFormatSymbols_ca_ES', 'goog.labs.i18n.ListFormatSymbols_ca_FR', 'goog.labs.i18n.ListFormatSymbols_ca_IT', 'goog.labs.i18n.ListFormatSymbols_ccp', 'goog.labs.i18n.ListFormatSymbols_ccp_BD', 'goog.labs.i18n.ListFormatSymbols_ccp_IN', 'goog.labs.i18n.ListFormatSymbols_ce', 'goog.labs.i18n.ListFormatSymbols_ce_RU', 'goog.labs.i18n.ListFormatSymbols_cgg', 'goog.labs.i18n.ListFormatSymbols_cgg_UG', 'goog.labs.i18n.ListFormatSymbols_chr_US', 'goog.labs.i18n.ListFormatSymbols_ckb', 'goog.labs.i18n.ListFormatSymbols_ckb_IQ', 'goog.labs.i18n.ListFormatSymbols_ckb_IR', 'goog.labs.i18n.ListFormatSymbols_cs_CZ', 'goog.labs.i18n.ListFormatSymbols_cy_GB', 'goog.labs.i18n.ListFormatSymbols_da_DK', 'goog.labs.i18n.ListFormatSymbols_da_GL', 'goog.labs.i18n.ListFormatSymbols_dav', 'goog.labs.i18n.ListFormatSymbols_dav_KE', 'goog.labs.i18n.ListFormatSymbols_de_BE', 'goog.labs.i18n.ListFormatSymbols_de_DE', 'goog.labs.i18n.ListFormatSymbols_de_IT', 'goog.labs.i18n.ListFormatSymbols_de_LI', 'goog.labs.i18n.ListFormatSymbols_de_LU', 'goog.labs.i18n.ListFormatSymbols_dje', 'goog.labs.i18n.ListFormatSymbols_dje_NE', 'goog.labs.i18n.ListFormatSymbols_dsb', 'goog.labs.i18n.ListFormatSymbols_dsb_DE', 'goog.labs.i18n.ListFormatSymbols_dua', 'goog.labs.i18n.ListFormatSymbols_dua_CM', 'goog.labs.i18n.ListFormatSymbols_dyo', 'goog.labs.i18n.ListFormatSymbols_dyo_SN', 'goog.labs.i18n.ListFormatSymbols_dz', 'goog.labs.i18n.ListFormatSymbols_dz_BT', 'goog.labs.i18n.ListFormatSymbols_ebu', 'goog.labs.i18n.ListFormatSymbols_ebu_KE', 'goog.labs.i18n.ListFormatSymbols_ee', 'goog.labs.i18n.ListFormatSymbols_ee_GH', 'goog.labs.i18n.ListFormatSymbols_ee_TG', 'goog.labs.i18n.ListFormatSymbols_el_CY', 'goog.labs.i18n.ListFormatSymbols_el_GR', 'goog.labs.i18n.ListFormatSymbols_en_001', 'goog.labs.i18n.ListFormatSymbols_en_150', 'goog.labs.i18n.ListFormatSymbols_en_AG', 'goog.labs.i18n.ListFormatSymbols_en_AI', 'goog.labs.i18n.ListFormatSymbols_en_AS', 'goog.labs.i18n.ListFormatSymbols_en_AT', 'goog.labs.i18n.ListFormatSymbols_en_BB', 'goog.labs.i18n.ListFormatSymbols_en_BE', 'goog.labs.i18n.ListFormatSymbols_en_BI', 'goog.labs.i18n.ListFormatSymbols_en_BM', 'goog.labs.i18n.ListFormatSymbols_en_BS', 'goog.labs.i18n.ListFormatSymbols_en_BW', 'goog.labs.i18n.ListFormatSymbols_en_BZ', 'goog.labs.i18n.ListFormatSymbols_en_CC', 'goog.labs.i18n.ListFormatSymbols_en_CH', 'goog.labs.i18n.ListFormatSymbols_en_CK', 'goog.labs.i18n.ListFormatSymbols_en_CM', 'goog.labs.i18n.ListFormatSymbols_en_CX', 'goog.labs.i18n.ListFormatSymbols_en_CY', 'goog.labs.i18n.ListFormatSymbols_en_DE', 'goog.labs.i18n.ListFormatSymbols_en_DG', 'goog.labs.i18n.ListFormatSymbols_en_DK', 'goog.labs.i18n.ListFormatSymbols_en_DM', 'goog.labs.i18n.ListFormatSymbols_en_ER', 'goog.labs.i18n.ListFormatSymbols_en_FI', 'goog.labs.i18n.ListFormatSymbols_en_FJ', 'goog.labs.i18n.ListFormatSymbols_en_FK', 'goog.labs.i18n.ListFormatSymbols_en_FM', 'goog.labs.i18n.ListFormatSymbols_en_GD', 'goog.labs.i18n.ListFormatSymbols_en_GG', 'goog.labs.i18n.ListFormatSymbols_en_GH', 'goog.labs.i18n.ListFormatSymbols_en_GI', 'goog.labs.i18n.ListFormatSymbols_en_GM', 'goog.labs.i18n.ListFormatSymbols_en_GU', 'goog.labs.i18n.ListFormatSymbols_en_GY', 'goog.labs.i18n.ListFormatSymbols_en_HK', 'goog.labs.i18n.ListFormatSymbols_en_IL', 'goog.labs.i18n.ListFormatSymbols_en_IM', 'goog.labs.i18n.ListFormatSymbols_en_IO', 'goog.labs.i18n.ListFormatSymbols_en_JE', 'goog.labs.i18n.ListFormatSymbols_en_JM', 'goog.labs.i18n.ListFormatSymbols_en_KE', 'goog.labs.i18n.ListFormatSymbols_en_KI', 'goog.labs.i18n.ListFormatSymbols_en_KN', 'goog.labs.i18n.ListFormatSymbols_en_KY', 'goog.labs.i18n.ListFormatSymbols_en_LC', 'goog.labs.i18n.ListFormatSymbols_en_LR', 'goog.labs.i18n.ListFormatSymbols_en_LS', 'goog.labs.i18n.ListFormatSymbols_en_MG', 'goog.labs.i18n.ListFormatSymbols_en_MH', 'goog.labs.i18n.ListFormatSymbols_en_MO', 'goog.labs.i18n.ListFormatSymbols_en_MP', 'goog.labs.i18n.ListFormatSymbols_en_MS', 'goog.labs.i18n.ListFormatSymbols_en_MT', 'goog.labs.i18n.ListFormatSymbols_en_MU', 'goog.labs.i18n.ListFormatSymbols_en_MW', 'goog.labs.i18n.ListFormatSymbols_en_MY', 'goog.labs.i18n.ListFormatSymbols_en_NA', 'goog.labs.i18n.ListFormatSymbols_en_NF', 'goog.labs.i18n.ListFormatSymbols_en_NG', 'goog.labs.i18n.ListFormatSymbols_en_NL', 'goog.labs.i18n.ListFormatSymbols_en_NR', 'goog.labs.i18n.ListFormatSymbols_en_NU', 'goog.labs.i18n.ListFormatSymbols_en_NZ', 'goog.labs.i18n.ListFormatSymbols_en_PG', 'goog.labs.i18n.ListFormatSymbols_en_PH', 'goog.labs.i18n.ListFormatSymbols_en_PK', 'goog.labs.i18n.ListFormatSymbols_en_PN', 'goog.labs.i18n.ListFormatSymbols_en_PR', 'goog.labs.i18n.ListFormatSymbols_en_PW', 'goog.labs.i18n.ListFormatSymbols_en_RW', 'goog.labs.i18n.ListFormatSymbols_en_SB', 'goog.labs.i18n.ListFormatSymbols_en_SC', 'goog.labs.i18n.ListFormatSymbols_en_SD', 'goog.labs.i18n.ListFormatSymbols_en_SE', 'goog.labs.i18n.ListFormatSymbols_en_SH', 'goog.labs.i18n.ListFormatSymbols_en_SI', 'goog.labs.i18n.ListFormatSymbols_en_SL', 'goog.labs.i18n.ListFormatSymbols_en_SS', 'goog.labs.i18n.ListFormatSymbols_en_SX', 'goog.labs.i18n.ListFormatSymbols_en_SZ', 'goog.labs.i18n.ListFormatSymbols_en_TC', 'goog.labs.i18n.ListFormatSymbols_en_TK', 'goog.labs.i18n.ListFormatSymbols_en_TO', 'goog.labs.i18n.ListFormatSymbols_en_TT', 'goog.labs.i18n.ListFormatSymbols_en_TV', 'goog.labs.i18n.ListFormatSymbols_en_TZ', 'goog.labs.i18n.ListFormatSymbols_en_UG', 'goog.labs.i18n.ListFormatSymbols_en_UM', 'goog.labs.i18n.ListFormatSymbols_en_US_POSIX', 'goog.labs.i18n.ListFormatSymbols_en_VC', 'goog.labs.i18n.ListFormatSymbols_en_VG', 'goog.labs.i18n.ListFormatSymbols_en_VI', 'goog.labs.i18n.ListFormatSymbols_en_VU', 'goog.labs.i18n.ListFormatSymbols_en_WS', 'goog.labs.i18n.ListFormatSymbols_en_XA', 'goog.labs.i18n.ListFormatSymbols_en_ZM', 'goog.labs.i18n.ListFormatSymbols_en_ZW', 'goog.labs.i18n.ListFormatSymbols_eo', 'goog.labs.i18n.ListFormatSymbols_es_AR', 'goog.labs.i18n.ListFormatSymbols_es_BO', 'goog.labs.i18n.ListFormatSymbols_es_BR', 'goog.labs.i18n.ListFormatSymbols_es_BZ', 'goog.labs.i18n.ListFormatSymbols_es_CL', 'goog.labs.i18n.ListFormatSymbols_es_CO', 'goog.labs.i18n.ListFormatSymbols_es_CR', 'goog.labs.i18n.ListFormatSymbols_es_CU', 'goog.labs.i18n.ListFormatSymbols_es_DO', 'goog.labs.i18n.ListFormatSymbols_es_EA', 'goog.labs.i18n.ListFormatSymbols_es_EC', 'goog.labs.i18n.ListFormatSymbols_es_GQ', 'goog.labs.i18n.ListFormatSymbols_es_GT', 'goog.labs.i18n.ListFormatSymbols_es_HN', 'goog.labs.i18n.ListFormatSymbols_es_IC', 'goog.labs.i18n.ListFormatSymbols_es_NI', 'goog.labs.i18n.ListFormatSymbols_es_PA', 'goog.labs.i18n.ListFormatSymbols_es_PE', 'goog.labs.i18n.ListFormatSymbols_es_PH', 'goog.labs.i18n.ListFormatSymbols_es_PR', 'goog.labs.i18n.ListFormatSymbols_es_PY', 'goog.labs.i18n.ListFormatSymbols_es_SV', 'goog.labs.i18n.ListFormatSymbols_es_UY', 'goog.labs.i18n.ListFormatSymbols_es_VE', 'goog.labs.i18n.ListFormatSymbols_et_EE', 'goog.labs.i18n.ListFormatSymbols_eu_ES', 'goog.labs.i18n.ListFormatSymbols_ewo', 'goog.labs.i18n.ListFormatSymbols_ewo_CM', 'goog.labs.i18n.ListFormatSymbols_fa_AF', 'goog.labs.i18n.ListFormatSymbols_fa_IR', 'goog.labs.i18n.ListFormatSymbols_ff', 'goog.labs.i18n.ListFormatSymbols_fi_FI', 'goog.labs.i18n.ListFormatSymbols_fil_PH', 'goog.labs.i18n.ListFormatSymbols_fo', 'goog.labs.i18n.ListFormatSymbols_fo_DK', 'goog.labs.i18n.ListFormatSymbols_fo_FO', 'goog.labs.i18n.ListFormatSymbols_fr_BE', 'goog.labs.i18n.ListFormatSymbols_fr_BF', 'goog.labs.i18n.ListFormatSymbols_fr_BI', 'goog.labs.i18n.ListFormatSymbols_fr_BJ', 'goog.labs.i18n.ListFormatSymbols_fr_BL', 'goog.labs.i18n.ListFormatSymbols_fr_CD', 'goog.labs.i18n.ListFormatSymbols_fr_CF', 'goog.labs.i18n.ListFormatSymbols_fr_CG', 'goog.labs.i18n.ListFormatSymbols_fr_CH', 'goog.labs.i18n.ListFormatSymbols_fr_CI', 'goog.labs.i18n.ListFormatSymbols_fr_CM', 'goog.labs.i18n.ListFormatSymbols_fr_DJ', 'goog.labs.i18n.ListFormatSymbols_fr_DZ', 'goog.labs.i18n.ListFormatSymbols_fr_FR', 'goog.labs.i18n.ListFormatSymbols_fr_GA', 'goog.labs.i18n.ListFormatSymbols_fr_GF', 'goog.labs.i18n.ListFormatSymbols_fr_GN', 'goog.labs.i18n.ListFormatSymbols_fr_GP', 'goog.labs.i18n.ListFormatSymbols_fr_GQ', 'goog.labs.i18n.ListFormatSymbols_fr_HT', 'goog.labs.i18n.ListFormatSymbols_fr_KM', 'goog.labs.i18n.ListFormatSymbols_fr_LU', 'goog.labs.i18n.ListFormatSymbols_fr_MA', 'goog.labs.i18n.ListFormatSymbols_fr_MC', 'goog.labs.i18n.ListFormatSymbols_fr_MF', 'goog.labs.i18n.ListFormatSymbols_fr_MG', 'goog.labs.i18n.ListFormatSymbols_fr_ML', 'goog.labs.i18n.ListFormatSymbols_fr_MQ', 'goog.labs.i18n.ListFormatSymbols_fr_MR', 'goog.labs.i18n.ListFormatSymbols_fr_MU', 'goog.labs.i18n.ListFormatSymbols_fr_NC', 'goog.labs.i18n.ListFormatSymbols_fr_NE', 'goog.labs.i18n.ListFormatSymbols_fr_PF', 'goog.labs.i18n.ListFormatSymbols_fr_PM', 'goog.labs.i18n.ListFormatSymbols_fr_RE', 'goog.labs.i18n.ListFormatSymbols_fr_RW', 'goog.labs.i18n.ListFormatSymbols_fr_SC', 'goog.labs.i18n.ListFormatSymbols_fr_SN', 'goog.labs.i18n.ListFormatSymbols_fr_SY', 'goog.labs.i18n.ListFormatSymbols_fr_TD', 'goog.labs.i18n.ListFormatSymbols_fr_TG', 'goog.labs.i18n.ListFormatSymbols_fr_TN', 'goog.labs.i18n.ListFormatSymbols_fr_VU', 'goog.labs.i18n.ListFormatSymbols_fr_WF', 'goog.labs.i18n.ListFormatSymbols_fr_YT', 'goog.labs.i18n.ListFormatSymbols_fur', 'goog.labs.i18n.ListFormatSymbols_fur_IT', 'goog.labs.i18n.ListFormatSymbols_fy', 'goog.labs.i18n.ListFormatSymbols_fy_NL', 'goog.labs.i18n.ListFormatSymbols_ga_IE', 'goog.labs.i18n.ListFormatSymbols_gd', 'goog.labs.i18n.ListFormatSymbols_gd_GB', 'goog.labs.i18n.ListFormatSymbols_gl_ES', 'goog.labs.i18n.ListFormatSymbols_gsw_CH', 'goog.labs.i18n.ListFormatSymbols_gsw_FR', 'goog.labs.i18n.ListFormatSymbols_gsw_LI', 'goog.labs.i18n.ListFormatSymbols_gu_IN', 'goog.labs.i18n.ListFormatSymbols_guz', 'goog.labs.i18n.ListFormatSymbols_guz_KE', 'goog.labs.i18n.ListFormatSymbols_gv', 'goog.labs.i18n.ListFormatSymbols_gv_IM', 'goog.labs.i18n.ListFormatSymbols_ha', 'goog.labs.i18n.ListFormatSymbols_ha_GH', 'goog.labs.i18n.ListFormatSymbols_ha_NE', 'goog.labs.i18n.ListFormatSymbols_ha_NG', 'goog.labs.i18n.ListFormatSymbols_haw_US', 'goog.labs.i18n.ListFormatSymbols_he_IL', 'goog.labs.i18n.ListFormatSymbols_hi_IN', 'goog.labs.i18n.ListFormatSymbols_hr_BA', 'goog.labs.i18n.ListFormatSymbols_hr_HR', 'goog.labs.i18n.ListFormatSymbols_hsb', 'goog.labs.i18n.ListFormatSymbols_hsb_DE', 'goog.labs.i18n.ListFormatSymbols_hu_HU', 'goog.labs.i18n.ListFormatSymbols_hy_AM', 'goog.labs.i18n.ListFormatSymbols_ia', 'goog.labs.i18n.ListFormatSymbols_ia_001', 'goog.labs.i18n.ListFormatSymbols_id_ID', 'goog.labs.i18n.ListFormatSymbols_ig', 'goog.labs.i18n.ListFormatSymbols_ig_NG', 'goog.labs.i18n.ListFormatSymbols_ii', 'goog.labs.i18n.ListFormatSymbols_ii_CN', 'goog.labs.i18n.ListFormatSymbols_is_IS', 'goog.labs.i18n.ListFormatSymbols_it_CH', 'goog.labs.i18n.ListFormatSymbols_it_IT', 'goog.labs.i18n.ListFormatSymbols_it_SM', 'goog.labs.i18n.ListFormatSymbols_it_VA', 'goog.labs.i18n.ListFormatSymbols_ja_JP', 'goog.labs.i18n.ListFormatSymbols_jgo', 'goog.labs.i18n.ListFormatSymbols_jgo_CM', 'goog.labs.i18n.ListFormatSymbols_jmc', 'goog.labs.i18n.ListFormatSymbols_jmc_TZ', 'goog.labs.i18n.ListFormatSymbols_jv', 'goog.labs.i18n.ListFormatSymbols_jv_ID', 'goog.labs.i18n.ListFormatSymbols_ka_GE', 'goog.labs.i18n.ListFormatSymbols_kab', 'goog.labs.i18n.ListFormatSymbols_kab_DZ', 'goog.labs.i18n.ListFormatSymbols_kam', 'goog.labs.i18n.ListFormatSymbols_kam_KE', 'goog.labs.i18n.ListFormatSymbols_kde', 'goog.labs.i18n.ListFormatSymbols_kde_TZ', 'goog.labs.i18n.ListFormatSymbols_kea', 'goog.labs.i18n.ListFormatSymbols_kea_CV', 'goog.labs.i18n.ListFormatSymbols_khq', 'goog.labs.i18n.ListFormatSymbols_khq_ML', 'goog.labs.i18n.ListFormatSymbols_ki', 'goog.labs.i18n.ListFormatSymbols_ki_KE', 'goog.labs.i18n.ListFormatSymbols_kk_KZ', 'goog.labs.i18n.ListFormatSymbols_kkj', 'goog.labs.i18n.ListFormatSymbols_kkj_CM', 'goog.labs.i18n.ListFormatSymbols_kl', 'goog.labs.i18n.ListFormatSymbols_kl_GL', 'goog.labs.i18n.ListFormatSymbols_kln', 'goog.labs.i18n.ListFormatSymbols_kln_KE', 'goog.labs.i18n.ListFormatSymbols_km_KH', 'goog.labs.i18n.ListFormatSymbols_kn_IN', 'goog.labs.i18n.ListFormatSymbols_ko_KP', 'goog.labs.i18n.ListFormatSymbols_ko_KR', 'goog.labs.i18n.ListFormatSymbols_kok', 'goog.labs.i18n.ListFormatSymbols_kok_IN', 'goog.labs.i18n.ListFormatSymbols_ks', 'goog.labs.i18n.ListFormatSymbols_ks_IN', 'goog.labs.i18n.ListFormatSymbols_ksb', 'goog.labs.i18n.ListFormatSymbols_ksb_TZ', 'goog.labs.i18n.ListFormatSymbols_ksf', 'goog.labs.i18n.ListFormatSymbols_ksf_CM', 'goog.labs.i18n.ListFormatSymbols_ksh', 'goog.labs.i18n.ListFormatSymbols_ksh_DE', 'goog.labs.i18n.ListFormatSymbols_ku', 'goog.labs.i18n.ListFormatSymbols_ku_TR', 'goog.labs.i18n.ListFormatSymbols_kw', 'goog.labs.i18n.ListFormatSymbols_kw_GB', 'goog.labs.i18n.ListFormatSymbols_ky_KG', 'goog.labs.i18n.ListFormatSymbols_lag', 'goog.labs.i18n.ListFormatSymbols_lag_TZ', 'goog.labs.i18n.ListFormatSymbols_lb', 'goog.labs.i18n.ListFormatSymbols_lb_LU', 'goog.labs.i18n.ListFormatSymbols_lg', 'goog.labs.i18n.ListFormatSymbols_lg_UG', 'goog.labs.i18n.ListFormatSymbols_lkt', 'goog.labs.i18n.ListFormatSymbols_lkt_US', 'goog.labs.i18n.ListFormatSymbols_ln_AO', 'goog.labs.i18n.ListFormatSymbols_ln_CD', 'goog.labs.i18n.ListFormatSymbols_ln_CF', 'goog.labs.i18n.ListFormatSymbols_ln_CG', 'goog.labs.i18n.ListFormatSymbols_lo_LA', 'goog.labs.i18n.ListFormatSymbols_lrc', 'goog.labs.i18n.ListFormatSymbols_lrc_IQ', 'goog.labs.i18n.ListFormatSymbols_lrc_IR', 'goog.labs.i18n.ListFormatSymbols_lt_LT', 'goog.labs.i18n.ListFormatSymbols_lu', 'goog.labs.i18n.ListFormatSymbols_lu_CD', 'goog.labs.i18n.ListFormatSymbols_luo', 'goog.labs.i18n.ListFormatSymbols_luo_KE', 'goog.labs.i18n.ListFormatSymbols_luy', 'goog.labs.i18n.ListFormatSymbols_luy_KE', 'goog.labs.i18n.ListFormatSymbols_lv_LV', 'goog.labs.i18n.ListFormatSymbols_mas', 'goog.labs.i18n.ListFormatSymbols_mas_KE', 'goog.labs.i18n.ListFormatSymbols_mas_TZ', 'goog.labs.i18n.ListFormatSymbols_mer', 'goog.labs.i18n.ListFormatSymbols_mer_KE', 'goog.labs.i18n.ListFormatSymbols_mfe', 'goog.labs.i18n.ListFormatSymbols_mfe_MU', 'goog.labs.i18n.ListFormatSymbols_mg', 'goog.labs.i18n.ListFormatSymbols_mg_MG', 'goog.labs.i18n.ListFormatSymbols_mgh', 'goog.labs.i18n.ListFormatSymbols_mgh_MZ', 'goog.labs.i18n.ListFormatSymbols_mgo', 'goog.labs.i18n.ListFormatSymbols_mgo_CM', 'goog.labs.i18n.ListFormatSymbols_mi', 'goog.labs.i18n.ListFormatSymbols_mi_NZ', 'goog.labs.i18n.ListFormatSymbols_mk_MK', 'goog.labs.i18n.ListFormatSymbols_ml_IN', 'goog.labs.i18n.ListFormatSymbols_mn_MN', 'goog.labs.i18n.ListFormatSymbols_mr_IN', 'goog.labs.i18n.ListFormatSymbols_ms_BN', 'goog.labs.i18n.ListFormatSymbols_ms_MY', 'goog.labs.i18n.ListFormatSymbols_ms_SG', 'goog.labs.i18n.ListFormatSymbols_mt_MT', 'goog.labs.i18n.ListFormatSymbols_mua', 'goog.labs.i18n.ListFormatSymbols_mua_CM', 'goog.labs.i18n.ListFormatSymbols_my_MM', 'goog.labs.i18n.ListFormatSymbols_mzn', 'goog.labs.i18n.ListFormatSymbols_mzn_IR', 'goog.labs.i18n.ListFormatSymbols_naq', 'goog.labs.i18n.ListFormatSymbols_naq_NA', 'goog.labs.i18n.ListFormatSymbols_nb_NO', 'goog.labs.i18n.ListFormatSymbols_nb_SJ', 'goog.labs.i18n.ListFormatSymbols_nd', 'goog.labs.i18n.ListFormatSymbols_nd_ZW', 'goog.labs.i18n.ListFormatSymbols_nds', 'goog.labs.i18n.ListFormatSymbols_nds_DE', 'goog.labs.i18n.ListFormatSymbols_nds_NL', 'goog.labs.i18n.ListFormatSymbols_ne_IN', 'goog.labs.i18n.ListFormatSymbols_ne_NP', 'goog.labs.i18n.ListFormatSymbols_nl_AW', 'goog.labs.i18n.ListFormatSymbols_nl_BE', 'goog.labs.i18n.ListFormatSymbols_nl_BQ', 'goog.labs.i18n.ListFormatSymbols_nl_CW', 'goog.labs.i18n.ListFormatSymbols_nl_NL', 'goog.labs.i18n.ListFormatSymbols_nl_SR', 'goog.labs.i18n.ListFormatSymbols_nl_SX', 'goog.labs.i18n.ListFormatSymbols_nmg', 'goog.labs.i18n.ListFormatSymbols_nmg_CM', 'goog.labs.i18n.ListFormatSymbols_nn', 'goog.labs.i18n.ListFormatSymbols_nn_NO', 'goog.labs.i18n.ListFormatSymbols_nnh', 'goog.labs.i18n.ListFormatSymbols_nnh_CM', 'goog.labs.i18n.ListFormatSymbols_nus', 'goog.labs.i18n.ListFormatSymbols_nus_SS', 'goog.labs.i18n.ListFormatSymbols_nyn', 'goog.labs.i18n.ListFormatSymbols_nyn_UG', 'goog.labs.i18n.ListFormatSymbols_om', 'goog.labs.i18n.ListFormatSymbols_om_ET', 'goog.labs.i18n.ListFormatSymbols_om_KE', 'goog.labs.i18n.ListFormatSymbols_or_IN', 'goog.labs.i18n.ListFormatSymbols_os', 'goog.labs.i18n.ListFormatSymbols_os_GE', 'goog.labs.i18n.ListFormatSymbols_os_RU', 'goog.labs.i18n.ListFormatSymbols_pa_Arab', 'goog.labs.i18n.ListFormatSymbols_pa_Arab_PK', 'goog.labs.i18n.ListFormatSymbols_pa_Guru', 'goog.labs.i18n.ListFormatSymbols_pa_Guru_IN', 'goog.labs.i18n.ListFormatSymbols_pl_PL', 'goog.labs.i18n.ListFormatSymbols_ps', 'goog.labs.i18n.ListFormatSymbols_ps_AF', 'goog.labs.i18n.ListFormatSymbols_pt_AO', 'goog.labs.i18n.ListFormatSymbols_pt_CH', 'goog.labs.i18n.ListFormatSymbols_pt_CV', 'goog.labs.i18n.ListFormatSymbols_pt_GQ', 'goog.labs.i18n.ListFormatSymbols_pt_GW', 'goog.labs.i18n.ListFormatSymbols_pt_LU', 'goog.labs.i18n.ListFormatSymbols_pt_MO', 'goog.labs.i18n.ListFormatSymbols_pt_MZ', 'goog.labs.i18n.ListFormatSymbols_pt_ST', 'goog.labs.i18n.ListFormatSymbols_pt_TL', 'goog.labs.i18n.ListFormatSymbols_qu', 'goog.labs.i18n.ListFormatSymbols_qu_BO', 'goog.labs.i18n.ListFormatSymbols_qu_EC', 'goog.labs.i18n.ListFormatSymbols_qu_PE', 'goog.labs.i18n.ListFormatSymbols_rm', 'goog.labs.i18n.ListFormatSymbols_rm_CH', 'goog.labs.i18n.ListFormatSymbols_rn', 'goog.labs.i18n.ListFormatSymbols_rn_BI', 'goog.labs.i18n.ListFormatSymbols_ro_MD', 'goog.labs.i18n.ListFormatSymbols_ro_RO', 'goog.labs.i18n.ListFormatSymbols_rof', 'goog.labs.i18n.ListFormatSymbols_rof_TZ', 'goog.labs.i18n.ListFormatSymbols_ru_BY', 'goog.labs.i18n.ListFormatSymbols_ru_KG', 'goog.labs.i18n.ListFormatSymbols_ru_KZ', 'goog.labs.i18n.ListFormatSymbols_ru_MD', 'goog.labs.i18n.ListFormatSymbols_ru_RU', 'goog.labs.i18n.ListFormatSymbols_ru_UA', 'goog.labs.i18n.ListFormatSymbols_rw', 'goog.labs.i18n.ListFormatSymbols_rw_RW', 'goog.labs.i18n.ListFormatSymbols_rwk', 'goog.labs.i18n.ListFormatSymbols_rwk_TZ', 'goog.labs.i18n.ListFormatSymbols_sah', 'goog.labs.i18n.ListFormatSymbols_sah_RU', 'goog.labs.i18n.ListFormatSymbols_saq', 'goog.labs.i18n.ListFormatSymbols_saq_KE', 'goog.labs.i18n.ListFormatSymbols_sbp', 'goog.labs.i18n.ListFormatSymbols_sbp_TZ', 'goog.labs.i18n.ListFormatSymbols_sd', 'goog.labs.i18n.ListFormatSymbols_sd_PK', 'goog.labs.i18n.ListFormatSymbols_se', 'goog.labs.i18n.ListFormatSymbols_se_FI', 'goog.labs.i18n.ListFormatSymbols_se_NO', 'goog.labs.i18n.ListFormatSymbols_se_SE', 'goog.labs.i18n.ListFormatSymbols_seh', 'goog.labs.i18n.ListFormatSymbols_seh_MZ', 'goog.labs.i18n.ListFormatSymbols_ses', 'goog.labs.i18n.ListFormatSymbols_ses_ML', 'goog.labs.i18n.ListFormatSymbols_sg', 'goog.labs.i18n.ListFormatSymbols_sg_CF', 'goog.labs.i18n.ListFormatSymbols_shi', 'goog.labs.i18n.ListFormatSymbols_shi_Latn', 'goog.labs.i18n.ListFormatSymbols_shi_Latn_MA', 'goog.labs.i18n.ListFormatSymbols_shi_Tfng', 'goog.labs.i18n.ListFormatSymbols_shi_Tfng_MA', 'goog.labs.i18n.ListFormatSymbols_si_LK', 'goog.labs.i18n.ListFormatSymbols_sk_SK', 'goog.labs.i18n.ListFormatSymbols_sl_SI', 'goog.labs.i18n.ListFormatSymbols_smn', 'goog.labs.i18n.ListFormatSymbols_smn_FI', 'goog.labs.i18n.ListFormatSymbols_sn', 'goog.labs.i18n.ListFormatSymbols_sn_ZW', 'goog.labs.i18n.ListFormatSymbols_so', 'goog.labs.i18n.ListFormatSymbols_so_DJ', 'goog.labs.i18n.ListFormatSymbols_so_ET', 'goog.labs.i18n.ListFormatSymbols_so_KE', 'goog.labs.i18n.ListFormatSymbols_so_SO', 'goog.labs.i18n.ListFormatSymbols_sq_AL', 'goog.labs.i18n.ListFormatSymbols_sq_MK', 'goog.labs.i18n.ListFormatSymbols_sq_XK', 'goog.labs.i18n.ListFormatSymbols_sr_Cyrl', 'goog.labs.i18n.ListFormatSymbols_sr_Cyrl_BA', 'goog.labs.i18n.ListFormatSymbols_sr_Cyrl_ME', 'goog.labs.i18n.ListFormatSymbols_sr_Cyrl_RS', 'goog.labs.i18n.ListFormatSymbols_sr_Cyrl_XK', 'goog.labs.i18n.ListFormatSymbols_sr_Latn_BA', 'goog.labs.i18n.ListFormatSymbols_sr_Latn_ME', 'goog.labs.i18n.ListFormatSymbols_sr_Latn_RS', 'goog.labs.i18n.ListFormatSymbols_sr_Latn_XK', 'goog.labs.i18n.ListFormatSymbols_sv_AX', 'goog.labs.i18n.ListFormatSymbols_sv_FI', 'goog.labs.i18n.ListFormatSymbols_sv_SE', 'goog.labs.i18n.ListFormatSymbols_sw_CD', 'goog.labs.i18n.ListFormatSymbols_sw_KE', 'goog.labs.i18n.ListFormatSymbols_sw_TZ', 'goog.labs.i18n.ListFormatSymbols_sw_UG', 'goog.labs.i18n.ListFormatSymbols_ta_IN', 'goog.labs.i18n.ListFormatSymbols_ta_LK', 'goog.labs.i18n.ListFormatSymbols_ta_MY', 'goog.labs.i18n.ListFormatSymbols_ta_SG', 'goog.labs.i18n.ListFormatSymbols_te_IN', 'goog.labs.i18n.ListFormatSymbols_teo', 'goog.labs.i18n.ListFormatSymbols_teo_KE', 'goog.labs.i18n.ListFormatSymbols_teo_UG', 'goog.labs.i18n.ListFormatSymbols_tg', 'goog.labs.i18n.ListFormatSymbols_tg_TJ', 'goog.labs.i18n.ListFormatSymbols_th_TH', 'goog.labs.i18n.ListFormatSymbols_ti', 'goog.labs.i18n.ListFormatSymbols_ti_ER', 'goog.labs.i18n.ListFormatSymbols_ti_ET', 'goog.labs.i18n.ListFormatSymbols_tk', 'goog.labs.i18n.ListFormatSymbols_tk_TM', 'goog.labs.i18n.ListFormatSymbols_to', 'goog.labs.i18n.ListFormatSymbols_to_TO', 'goog.labs.i18n.ListFormatSymbols_tr_CY', 'goog.labs.i18n.ListFormatSymbols_tr_TR', 'goog.labs.i18n.ListFormatSymbols_tt', 'goog.labs.i18n.ListFormatSymbols_tt_RU', 'goog.labs.i18n.ListFormatSymbols_twq', 'goog.labs.i18n.ListFormatSymbols_twq_NE', 'goog.labs.i18n.ListFormatSymbols_tzm', 'goog.labs.i18n.ListFormatSymbols_tzm_MA', 'goog.labs.i18n.ListFormatSymbols_ug', 'goog.labs.i18n.ListFormatSymbols_ug_CN', 'goog.labs.i18n.ListFormatSymbols_uk_UA', 'goog.labs.i18n.ListFormatSymbols_ur_IN', 'goog.labs.i18n.ListFormatSymbols_ur_PK', 'goog.labs.i18n.ListFormatSymbols_uz_Arab', 'goog.labs.i18n.ListFormatSymbols_uz_Arab_AF', 'goog.labs.i18n.ListFormatSymbols_uz_Cyrl', 'goog.labs.i18n.ListFormatSymbols_uz_Cyrl_UZ', 'goog.labs.i18n.ListFormatSymbols_uz_Latn', 'goog.labs.i18n.ListFormatSymbols_uz_Latn_UZ', 'goog.labs.i18n.ListFormatSymbols_vai', 'goog.labs.i18n.ListFormatSymbols_vai_Latn', 'goog.labs.i18n.ListFormatSymbols_vai_Latn_LR', 'goog.labs.i18n.ListFormatSymbols_vai_Vaii', 'goog.labs.i18n.ListFormatSymbols_vai_Vaii_LR', 'goog.labs.i18n.ListFormatSymbols_vi_VN', 'goog.labs.i18n.ListFormatSymbols_vun', 'goog.labs.i18n.ListFormatSymbols_vun_TZ', 'goog.labs.i18n.ListFormatSymbols_wae', 'goog.labs.i18n.ListFormatSymbols_wae_CH', 'goog.labs.i18n.ListFormatSymbols_wo', 'goog.labs.i18n.ListFormatSymbols_wo_SN', 'goog.labs.i18n.ListFormatSymbols_xh', 'goog.labs.i18n.ListFormatSymbols_xh_ZA', 'goog.labs.i18n.ListFormatSymbols_xog', 'goog.labs.i18n.ListFormatSymbols_xog_UG', 'goog.labs.i18n.ListFormatSymbols_yav', 'goog.labs.i18n.ListFormatSymbols_yav_CM', 'goog.labs.i18n.ListFormatSymbols_yi', 'goog.labs.i18n.ListFormatSymbols_yi_001', 'goog.labs.i18n.ListFormatSymbols_yo', 'goog.labs.i18n.ListFormatSymbols_yo_BJ', 'goog.labs.i18n.ListFormatSymbols_yo_NG', 'goog.labs.i18n.ListFormatSymbols_yue', 'goog.labs.i18n.ListFormatSymbols_yue_Hans', 'goog.labs.i18n.ListFormatSymbols_yue_Hans_CN', 'goog.labs.i18n.ListFormatSymbols_yue_Hant', 'goog.labs.i18n.ListFormatSymbols_yue_Hant_HK', 'goog.labs.i18n.ListFormatSymbols_zgh', 'goog.labs.i18n.ListFormatSymbols_zgh_MA', 'goog.labs.i18n.ListFormatSymbols_zh_Hans', 'goog.labs.i18n.ListFormatSymbols_zh_Hans_CN', 'goog.labs.i18n.ListFormatSymbols_zh_Hans_HK', 'goog.labs.i18n.ListFormatSymbols_zh_Hans_MO', 'goog.labs.i18n.ListFormatSymbols_zh_Hans_SG', 'goog.labs.i18n.ListFormatSymbols_zh_Hant', 'goog.labs.i18n.ListFormatSymbols_zh_Hant_HK', 'goog.labs.i18n.ListFormatSymbols_zh_Hant_MO', 'goog.labs.i18n.ListFormatSymbols_zh_Hant_TW', 'goog.labs.i18n.ListFormatSymbols_zu_ZA'], ['goog.labs.i18n.ListFormatSymbols']); -goog.addDependency("labs/iterable/iterable.js", [], []); -goog.addDependency("labs/iterable/iterable_test.js", [], ['goog.testing.jsunit']); goog.addDependency("labs/mock/mock.js", ['goog.labs.mock', 'goog.labs.mock.VerificationError'], ['goog.array', 'goog.asserts', 'goog.debug', 'goog.debug.Error', 'goog.functions', 'goog.labs.mock.verification', 'goog.labs.mock.verification.VerificationMode', 'goog.object']); goog.addDependency("labs/mock/mock_test.js", ['goog.labs.mockTest'], ['goog.array', 'goog.labs.mock', 'goog.labs.mock.VerificationError', 'goog.labs.testing.AnythingMatcher', 'goog.labs.testing.GreaterThanMatcher', 'goog.string', 'goog.testing.jsunit']); goog.addDependency("labs/mock/verificationmode.js", ['goog.labs.mock.verification', 'goog.labs.mock.verification.VerificationMode'], []); goog.addDependency("labs/mock/verificationmode_test.js", [], []); -goog.addDependency("labs/net/image.js", ['goog.labs.net.image'], ['goog.Promise', 'goog.events.EventHandler', 'goog.events.EventType', 'goog.net.EventType', 'goog.userAgent']); +goog.addDependency("labs/net/image.js", ['goog.labs.net.image'], ['goog.Promise', 'goog.events.EventHandler', 'goog.events.EventType', 'goog.html.SafeUrl', 'goog.net.EventType', 'goog.userAgent']); goog.addDependency("labs/net/image_test.js", ['goog.labs.net.imageTest'], ['goog.labs.net.image', 'goog.string', 'goog.testing.TestCase', 'goog.testing.jsunit', 'goog.testing.recordFunction']); goog.addDependency("labs/net/webchannel.js", ['goog.net.WebChannel'], ['goog.events', 'goog.events.Event', 'goog.events.Listenable', 'goog.net.XmlHttpFactory']); goog.addDependency("labs/net/webchannel/basetestchannel.js", ['goog.labs.net.webChannel.BaseTestChannel'], ['goog.labs.net.webChannel.Channel', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.WebChannelDebug', 'goog.labs.net.webChannel.requestStats', 'goog.net.WebChannel']); @@ -803,8 +807,8 @@ goog.addDependency("labs/net/webchannel/netutils.js", ['goog.labs.net.webChannel goog.addDependency("labs/net/webchannel/requeststats.js", ['goog.labs.net.webChannel.requestStats', 'goog.labs.net.webChannel.requestStats.Event', 'goog.labs.net.webChannel.requestStats.ServerReachability', 'goog.labs.net.webChannel.requestStats.ServerReachabilityEvent', 'goog.labs.net.webChannel.requestStats.Stat', 'goog.labs.net.webChannel.requestStats.StatEvent', 'goog.labs.net.webChannel.requestStats.TimingEvent'], ['goog.events.Event', 'goog.events.EventTarget']); goog.addDependency("labs/net/webchannel/webchannelbase.js", ['goog.labs.net.webChannel.WebChannelBase'], ['goog.Uri', 'goog.array', 'goog.asserts', 'goog.async.run', 'goog.debug.TextFormatter', 'goog.json', 'goog.labs.net.webChannel.BaseTestChannel', 'goog.labs.net.webChannel.Channel', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.ConnectionState', 'goog.labs.net.webChannel.ForwardChannelRequestPool', 'goog.labs.net.webChannel.WebChannelDebug', 'goog.labs.net.webChannel.Wire', 'goog.labs.net.webChannel.WireV8', 'goog.labs.net.webChannel.netUtils', 'goog.labs.net.webChannel.requestStats', 'goog.log', 'goog.net.WebChannel', 'goog.net.XhrIo', 'goog.net.XmlHttpFactory', 'goog.net.rpc.HttpCors', 'goog.object', 'goog.string', 'goog.structs', 'goog.structs.CircularBuffer']); goog.addDependency("labs/net/webchannel/webchannelbase_test.js", ['goog.labs.net.webChannel.webChannelBaseTest'], ['goog.Timer', 'goog.array', 'goog.dom', 'goog.functions', 'goog.json', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.ForwardChannelRequestPool', 'goog.labs.net.webChannel.WebChannelBase', 'goog.labs.net.webChannel.WebChannelBaseTransport', 'goog.labs.net.webChannel.WebChannelDebug', 'goog.labs.net.webChannel.Wire', 'goog.labs.net.webChannel.netUtils', 'goog.labs.net.webChannel.requestStats', 'goog.labs.net.webChannel.requestStats.Stat', 'goog.structs.Map', 'goog.testing.MockClock', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit']); -goog.addDependency("labs/net/webchannel/webchannelbasetransport.js", ['goog.labs.net.webChannel.WebChannelBaseTransport'], ['goog.asserts', 'goog.events.EventTarget', 'goog.json', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.WebChannelBase', 'goog.log', 'goog.net.WebChannel', 'goog.net.WebChannelTransport', 'goog.object', 'goog.string', 'goog.string.path']); -goog.addDependency("labs/net/webchannel/webchannelbasetransport_test.js", ['goog.labs.net.webChannel.webChannelBaseTransportTest'], ['goog.events', 'goog.functions', 'goog.json', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.WebChannelBase', 'goog.labs.net.webChannel.WebChannelBaseTransport', 'goog.net.WebChannel', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); +goog.addDependency("labs/net/webchannel/webchannelbasetransport.js", ['goog.labs.net.webChannel.WebChannelBaseTransport'], ['goog.asserts', 'goog.events.EventTarget', 'goog.json', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.WebChannelBase', 'goog.labs.net.webChannel.Wire', 'goog.log', 'goog.net.WebChannel', 'goog.net.WebChannelTransport', 'goog.object', 'goog.string', 'goog.string.path']); +goog.addDependency("labs/net/webchannel/webchannelbasetransport_test.js", ['goog.labs.net.webChannel.webChannelBaseTransportTest'], ['goog.events', 'goog.functions', 'goog.json', 'goog.labs.net.webChannel.ChannelRequest', 'goog.labs.net.webChannel.WebChannelBase', 'goog.labs.net.webChannel.WebChannelBaseTransport', 'goog.labs.net.webChannel.Wire', 'goog.net.WebChannel', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("labs/net/webchannel/webchanneldebug.js", ['goog.labs.net.webChannel.WebChannelDebug'], ['goog.json', 'goog.log']); goog.addDependency("labs/net/webchannel/wire.js", ['goog.labs.net.webChannel.Wire'], []); goog.addDependency("labs/net/webchannel/wirev8.js", ['goog.labs.net.webChannel.WireV8'], ['goog.asserts', 'goog.json', 'goog.json.NativeJsonProcessor', 'goog.labs.net.webChannel.Wire', 'goog.structs']); @@ -841,7 +845,7 @@ goog.addDependency("labs/testing/objectmatcher.js", ['goog.labs.testing.AnyObjec goog.addDependency("labs/testing/objectmatcher_test.js", ['goog.labs.testing.objectMatcherTest'], ['goog.labs.testing.MatcherError', 'goog.labs.testing.ObjectEqualsMatcher', 'goog.labs.testing.assertThat', 'goog.testing.jsunit']); goog.addDependency("labs/testing/stringmatcher.js", ['goog.labs.testing.AnyStringMatcher', 'goog.labs.testing.ContainsStringMatcher', 'goog.labs.testing.EndsWithMatcher', 'goog.labs.testing.EqualToIgnoringWhitespaceMatcher', 'goog.labs.testing.EqualsMatcher', 'goog.labs.testing.RegexMatcher', 'goog.labs.testing.StartsWithMatcher', 'goog.labs.testing.StringContainsInOrderMatcher'], ['goog.asserts', 'goog.labs.testing.Matcher', 'goog.string']); goog.addDependency("labs/testing/stringmatcher_test.js", ['goog.labs.testing.stringMatcherTest'], ['goog.labs.testing.MatcherError', 'goog.labs.testing.StringContainsInOrderMatcher', 'goog.labs.testing.assertThat', 'goog.testing.jsunit']); -goog.addDependency("labs/useragent/browser.js", ['goog.labs.userAgent.browser'], ['goog.array', 'goog.labs.userAgent.util', 'goog.object', 'goog.string']); +goog.addDependency("labs/useragent/browser.js", ['goog.labs.userAgent.browser'], ['goog.array', 'goog.labs.userAgent.util', 'goog.object', 'goog.string.internal']); goog.addDependency("labs/useragent/browser_test.js", ['goog.labs.userAgent.browserTest'], ['goog.labs.userAgent.browser', 'goog.labs.userAgent.testAgents', 'goog.labs.userAgent.util', 'goog.object', 'goog.testing.jsunit']); goog.addDependency("labs/useragent/device.js", ['goog.labs.userAgent.device'], ['goog.labs.userAgent.util']); goog.addDependency("labs/useragent/device_test.js", ['goog.labs.userAgent.deviceTest'], ['goog.labs.userAgent.device', 'goog.labs.userAgent.testAgents', 'goog.labs.userAgent.util', 'goog.testing.jsunit']); @@ -850,7 +854,7 @@ goog.addDependency("labs/useragent/engine_test.js", ['goog.labs.userAgent.engine goog.addDependency("labs/useragent/platform.js", ['goog.labs.userAgent.platform'], ['goog.labs.userAgent.util', 'goog.string']); goog.addDependency("labs/useragent/platform_test.js", ['goog.labs.userAgent.platformTest'], ['goog.labs.userAgent.platform', 'goog.labs.userAgent.testAgents', 'goog.labs.userAgent.util', 'goog.testing.jsunit']); goog.addDependency("labs/useragent/test_agents.js", ['goog.labs.userAgent.testAgents'], []); -goog.addDependency("labs/useragent/util.js", ['goog.labs.userAgent.util'], ['goog.string']); +goog.addDependency("labs/useragent/util.js", ['goog.labs.userAgent.util'], ['goog.string.internal']); goog.addDependency("labs/useragent/util_test.js", ['goog.labs.userAgent.utilTest'], ['goog.functions', 'goog.labs.userAgent.testAgents', 'goog.labs.userAgent.util', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("labs/useragent/verifier.js", ['goog.labs.useragent.verifier'], []); goog.addDependency("labs/useragent/verifier_test.js", [], []); @@ -1034,7 +1038,7 @@ goog.addDependency("net/tmpnetwork.js", ['goog.net.tmpnetwork'], ['goog.Uri', 'g goog.addDependency("net/websocket.js", ['goog.net.WebSocket', 'goog.net.WebSocket.ErrorEvent', 'goog.net.WebSocket.EventType', 'goog.net.WebSocket.MessageEvent'], ['goog.Timer', 'goog.asserts', 'goog.debug.entryPointRegistry', 'goog.events', 'goog.events.Event', 'goog.events.EventTarget', 'goog.log']); goog.addDependency("net/websocket_test.js", ['goog.net.WebSocketTest'], ['goog.debug.EntryPointMonitor', 'goog.debug.ErrorHandler', 'goog.debug.entryPointRegistry', 'goog.events', 'goog.functions', 'goog.net.WebSocket', 'goog.testing.MockClock', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit', 'goog.testing.recordFunction']); goog.addDependency("net/wrapperxmlhttpfactory.js", ['goog.net.WrapperXmlHttpFactory'], ['goog.net.XhrLike', 'goog.net.XmlHttpFactory']); -goog.addDependency("net/xhrio.js", ['goog.net.XhrIo', 'goog.net.XhrIo.ResponseType'], ['goog.Timer', 'goog.array', 'goog.asserts', 'goog.debug.entryPointRegistry', 'goog.events.EventTarget', 'goog.json.hybrid', 'goog.log', 'goog.net.ErrorCode', 'goog.net.EventType', 'goog.net.HttpStatus', 'goog.net.XmlHttp', 'goog.string', 'goog.structs', 'goog.structs.Map', 'goog.uri.utils', 'goog.userAgent']); +goog.addDependency("net/xhrio.js", ['goog.net.XhrIo', 'goog.net.XhrIo.ResponseType'], ['goog.Timer', 'goog.array', 'goog.asserts', 'goog.debug.entryPointRegistry', 'goog.events.EventTarget', 'goog.json.hybrid', 'goog.log', 'goog.net.ErrorCode', 'goog.net.EventType', 'goog.net.HttpStatus', 'goog.net.XmlHttp', 'goog.object', 'goog.string', 'goog.structs', 'goog.structs.Map', 'goog.uri.utils', 'goog.userAgent']); goog.addDependency("net/xhrio_test.js", ['goog.net.XhrIoTest'], ['goog.Uri', 'goog.debug.EntryPointMonitor', 'goog.debug.ErrorHandler', 'goog.debug.entryPointRegistry', 'goog.events', 'goog.functions', 'goog.net.EventType', 'goog.net.WrapperXmlHttpFactory', 'goog.net.XhrIo', 'goog.net.XmlHttp', 'goog.object', 'goog.string', 'goog.testing.MockClock', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit', 'goog.testing.net.XhrIo', 'goog.testing.recordFunction', 'goog.userAgent.product']); goog.addDependency("net/xhriopool.js", ['goog.net.XhrIoPool'], ['goog.net.XhrIo', 'goog.structs.PriorityPool']); goog.addDependency("net/xhriopool_test.js", ['goog.net.XhrIoPoolTest'], ['goog.net.XhrIoPool', 'goog.structs.Map', 'goog.testing.jsunit']); @@ -1126,7 +1130,7 @@ goog.addDependency("soy/data.js", ['goog.soy.data.SanitizedContent', 'goog.soy.d goog.addDependency("soy/data_test.js", ['goog.soy.dataTest'], ['goog.html.SafeHtml', 'goog.html.SafeStyleSheet', 'goog.html.SafeUrl', 'goog.html.TrustedResourceUrl', 'goog.soy.testHelper', 'goog.testing.jsunit']); goog.addDependency("soy/renderer.js", ['goog.soy.InjectedDataSupplier', 'goog.soy.Renderer'], ['goog.asserts', 'goog.dom', 'goog.soy', 'goog.soy.data.SanitizedContent', 'goog.soy.data.SanitizedContentKind']); goog.addDependency("soy/renderer_test.js", ['goog.soy.RendererTest'], ['goog.dom', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.html.SafeHtml', 'goog.i18n.bidi.Dir', 'goog.soy.Renderer', 'goog.soy.data.SanitizedContentKind', 'goog.soy.testHelper', 'goog.testing.jsunit', 'goog.testing.recordFunction']); -goog.addDependency("soy/soy.js", ['goog.soy'], ['goog.asserts', 'goog.dom', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.dom.safe', 'goog.soy.data.SanitizedContent', 'goog.soy.data.SanitizedContentKind', 'goog.string']); +goog.addDependency("soy/soy.js", ['goog.soy'], ['goog.asserts', 'goog.dom', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.dom.safe', 'goog.html.uncheckedconversions', 'goog.soy.data.SanitizedContent', 'goog.soy.data.SanitizedContentKind', 'goog.string']); goog.addDependency("soy/soy_test.js", ['goog.soyTest'], ['goog.dom', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.functions', 'goog.soy', 'goog.soy.testHelper', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("soy/soy_testhelper.js", ['goog.soy.testHelper'], ['goog.dom', 'goog.dom.TagName', 'goog.i18n.bidi.Dir', 'goog.soy.data.SanitizedContent', 'goog.soy.data.SanitizedContentKind', 'goog.soy.data.SanitizedCss', 'goog.soy.data.SanitizedTrustedResourceUri', 'goog.string', 'goog.userAgent']); goog.addDependency("spell/spellcheck.js", ['goog.spell.SpellCheck', 'goog.spell.SpellCheck.WordChangedEvent'], ['goog.Timer', 'goog.events.Event', 'goog.events.EventTarget', 'goog.structs.Set']); @@ -1170,6 +1174,7 @@ goog.addDependency("storage/storage_test.js", ['goog.storage.storage_test'], ['g goog.addDependency("storage/storagetester.js", ['goog.storage.storageTester'], ['goog.storage.Storage', 'goog.structs.Map', 'goog.testing.asserts']); goog.addDependency("string/const.js", ['goog.string.Const'], ['goog.asserts', 'goog.string.TypedString']); goog.addDependency("string/const_test.js", ['goog.string.constTest'], ['goog.string.Const', 'goog.testing.jsunit']); +goog.addDependency("string/internal.js", ['goog.string.internal'], []); goog.addDependency("string/linkify.js", ['goog.string.linkify'], ['goog.html.SafeHtml', 'goog.string']); goog.addDependency("string/linkify_test.js", ['goog.string.linkifyTest'], ['goog.dom', 'goog.dom.TagName', 'goog.dom.safe', 'goog.html.SafeHtml', 'goog.string', 'goog.string.linkify', 'goog.testing.dom', 'goog.testing.jsunit']); goog.addDependency("string/newlines.js", ['goog.string.newlines', 'goog.string.newlines.Line'], ['goog.array']); @@ -1177,7 +1182,7 @@ goog.addDependency("string/newlines_test.js", ['goog.string.newlinesTest'], ['go goog.addDependency("string/parser.js", ['goog.string.Parser'], []); goog.addDependency("string/path.js", ['goog.string.path'], ['goog.array', 'goog.string']); goog.addDependency("string/path_test.js", ['goog.string.pathTest'], ['goog.string.path', 'goog.testing.jsunit']); -goog.addDependency("string/string.js", ['goog.string', 'goog.string.Unicode'], []); +goog.addDependency("string/string.js", ['goog.string', 'goog.string.Unicode'], ['goog.string.internal']); goog.addDependency("string/string_test.js", ['goog.stringTest'], ['goog.dom', 'goog.dom.TagName', 'goog.functions', 'goog.object', 'goog.string', 'goog.string.Unicode', 'goog.testing.MockControl', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit']); goog.addDependency("string/stringbuffer.js", ['goog.string.StringBuffer'], []); goog.addDependency("string/stringbuffer_test.js", ['goog.string.StringBufferTest'], ['goog.string.StringBuffer', 'goog.testing.jsunit']); @@ -1284,7 +1289,7 @@ goog.addDependency("testing/fs/fs_test.js", ['goog.testing.fsTest'], ['goog.test goog.addDependency("testing/fs/integration_test.js", ['goog.testing.fs.integrationTest'], ['goog.Promise', 'goog.events', 'goog.fs', 'goog.fs.DirectoryEntry', 'goog.fs.Error', 'goog.fs.FileSaver', 'goog.testing.PropertyReplacer', 'goog.testing.fs', 'goog.testing.jsunit']); goog.addDependency("testing/fs/progressevent.js", ['goog.testing.fs.ProgressEvent'], ['goog.events.Event']); goog.addDependency("testing/functionmock.js", ['goog.testing', 'goog.testing.FunctionMock', 'goog.testing.GlobalFunctionMock', 'goog.testing.MethodMock'], ['goog.object', 'goog.testing.LooseMock', 'goog.testing.Mock', 'goog.testing.PropertyReplacer', 'goog.testing.StrictMock']); -goog.addDependency("testing/functionmock_test.js", ['goog.testing.FunctionMockTest'], ['goog.array', 'goog.string', 'goog.testing', 'goog.testing.FunctionMock', 'goog.testing.Mock', 'goog.testing.ObjectPropertyString', 'goog.testing.StrictMock', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.testing.mockmatchers']); +goog.addDependency("testing/functionmock_test.js", ['goog.testing.FunctionMockTest'], ['goog.array', 'goog.string', 'goog.testing', 'goog.testing.FunctionMock', 'goog.testing.Mock', 'goog.testing.StrictMock', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.testing.mockmatchers']); goog.addDependency("testing/graphics.js", ['goog.testing.graphics'], ['goog.graphics.Path', 'goog.testing.asserts']); goog.addDependency("testing/i18n/asserts.js", ['goog.testing.i18n.asserts'], ['goog.testing.jsunit']); goog.addDependency("testing/i18n/asserts_test.js", ['goog.testing.i18n.assertsTest'], ['goog.testing.ExpectedFailures', 'goog.testing.i18n.asserts']); @@ -1329,7 +1334,7 @@ goog.addDependency("testing/parallel_closure_test_suite_test.js", [], []); goog.addDependency("testing/performancetable.js", ['goog.testing.PerformanceTable'], ['goog.asserts', 'goog.dom', 'goog.dom.TagName', 'goog.testing.PerformanceTimer']); goog.addDependency("testing/performancetimer.js", ['goog.testing.PerformanceTimer', 'goog.testing.PerformanceTimer.Task'], ['goog.array', 'goog.async.Deferred', 'goog.math']); goog.addDependency("testing/performancetimer_test.js", ['goog.testing.PerformanceTimerTest'], ['goog.async.Deferred', 'goog.dom', 'goog.math', 'goog.testing.MockClock', 'goog.testing.PerformanceTimer', 'goog.testing.jsunit']); -goog.addDependency("testing/propertyreplacer.js", ['goog.testing.PropertyReplacer'], ['goog.asserts', 'goog.testing.ObjectPropertyString', 'goog.userAgent']); +goog.addDependency("testing/propertyreplacer.js", ['goog.testing.PropertyReplacer'], ['goog.asserts', 'goog.userAgent']); goog.addDependency("testing/propertyreplacer_test.js", ['goog.testing.PropertyReplacerTest'], ['goog.dom', 'goog.dom.TagName', 'goog.testing.PropertyReplacer', 'goog.testing.asserts', 'goog.testing.jsunit', 'goog.userAgent.product', 'goog.userAgent.product.isVersion']); goog.addDependency("testing/proto2/proto2.js", ['goog.testing.proto2'], ['goog.proto2.Message', 'goog.proto2.ObjectSerializer', 'goog.testing.asserts']); goog.addDependency("testing/proto2/proto2_test.js", ['goog.testing.proto2Test'], ['goog.testing.TestCase', 'goog.testing.jsunit', 'goog.testing.proto2', 'proto2.TestAllTypes']); @@ -1428,8 +1433,8 @@ goog.addDependency("ui/combobox.js", ['goog.ui.ComboBox', 'goog.ui.ComboBoxItem' goog.addDependency("ui/combobox_test.js", ['goog.ui.ComboBoxTest'], ['goog.dom', 'goog.dom.TagName', 'goog.dom.classlist', 'goog.events.KeyCodes', 'goog.testing.MockClock', 'goog.testing.events', 'goog.testing.jsunit', 'goog.ui.ComboBox', 'goog.ui.ComboBoxItem', 'goog.ui.Component', 'goog.ui.ControlRenderer', 'goog.ui.LabelInput', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("ui/component.js", ['goog.ui.Component', 'goog.ui.Component.Error', 'goog.ui.Component.EventType', 'goog.ui.Component.State'], ['goog.array', 'goog.asserts', 'goog.dom', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.events.EventHandler', 'goog.events.EventTarget', 'goog.object', 'goog.style', 'goog.ui.IdGenerator']); goog.addDependency("ui/component_test.js", ['goog.ui.ComponentTest'], ['goog.dom', 'goog.dom.DomHelper', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.events.EventTarget', 'goog.testing.PropertyReplacer', 'goog.testing.jsunit', 'goog.ui.Component']); -goog.addDependency("ui/componentutil.js", ['goog.ui.ComponentUtil'], ['goog.events.EventType', 'goog.events.PointerAsMouseEventType']); -goog.addDependency("ui/componentutil_test.js", ['goog.ui.ComponentUtilTest'], ['goog.events.EventType', 'goog.events.PointerAsMouseEventType', 'goog.testing.jsunit', 'goog.ui.Component', 'goog.ui.ComponentUtil']); +goog.addDependency("ui/componentutil.js", ['goog.ui.ComponentUtil'], ['goog.events.MouseAsMouseEventType', 'goog.events.MouseEvents', 'goog.events.PointerAsMouseEventType']); +goog.addDependency("ui/componentutil_test.js", ['goog.ui.ComponentUtilTest'], ['goog.events.MouseAsMouseEventType', 'goog.events.PointerAsMouseEventType', 'goog.testing.jsunit', 'goog.ui.Component', 'goog.ui.ComponentUtil']); goog.addDependency("ui/container.js", ['goog.ui.Container', 'goog.ui.Container.EventType', 'goog.ui.Container.Orientation'], ['goog.a11y.aria', 'goog.a11y.aria.State', 'goog.asserts', 'goog.dom', 'goog.events.EventType', 'goog.events.KeyCodes', 'goog.events.KeyHandler', 'goog.object', 'goog.style', 'goog.ui.Component', 'goog.ui.ComponentUtil', 'goog.ui.ContainerRenderer', 'goog.ui.Control']); goog.addDependency("ui/container_test.js", ['goog.ui.ContainerTest'], ['goog.a11y.aria', 'goog.dom', 'goog.dom.TagName', 'goog.dom.classlist', 'goog.events', 'goog.events.BrowserEvent', 'goog.events.Event', 'goog.events.KeyCodes', 'goog.events.KeyEvent', 'goog.events.PointerFallbackEventType', 'goog.testing.events', 'goog.testing.events.Event', 'goog.testing.jsunit', 'goog.ui.Component', 'goog.ui.Container', 'goog.ui.Control']); goog.addDependency("ui/containerrenderer.js", ['goog.ui.ContainerRenderer'], ['goog.a11y.aria', 'goog.array', 'goog.asserts', 'goog.dom.NodeType', 'goog.dom.TagName', 'goog.dom.classlist', 'goog.string', 'goog.style', 'goog.ui.registry', 'goog.userAgent']); @@ -1515,7 +1520,8 @@ goog.addDependency("ui/imagelessmenubuttonrenderer.js", ['goog.ui.ImagelessMenuB goog.addDependency("ui/inputdatepicker.js", ['goog.ui.InputDatePicker'], ['goog.date.DateTime', 'goog.dom', 'goog.dom.InputType', 'goog.dom.TagName', 'goog.i18n.DateTimeParse', 'goog.string', 'goog.ui.Component', 'goog.ui.DatePicker', 'goog.ui.LabelInput', 'goog.ui.PopupBase', 'goog.ui.PopupDatePicker']); goog.addDependency("ui/inputdatepicker_test.js", ['goog.ui.InputDatePickerTest'], ['goog.dom', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeParse', 'goog.testing.jsunit', 'goog.ui.InputDatePicker']); goog.addDependency("ui/itemevent.js", ['goog.ui.ItemEvent'], ['goog.events.Event']); -goog.addDependency("ui/keyboardshortcuthandler.js", ['goog.ui.KeyboardShortcutEvent', 'goog.ui.KeyboardShortcutHandler', 'goog.ui.KeyboardShortcutHandler.EventType', 'goog.ui.KeyboardShortcutHandler.Modifiers'], ['goog.array', 'goog.asserts', 'goog.dom.TagName', 'goog.events', 'goog.events.Event', 'goog.events.EventTarget', 'goog.events.EventType', 'goog.events.KeyCodes', 'goog.events.KeyNames', 'goog.events.Keys', 'goog.object', 'goog.userAgent']); +goog.addDependency("ui/keyboardeventdata.js", ['goog.ui.KeyboardEventData'], ['goog.asserts', 'goog.events.BrowserEvent']); +goog.addDependency("ui/keyboardshortcuthandler.js", ['goog.ui.KeyboardShortcutEvent', 'goog.ui.KeyboardShortcutHandler', 'goog.ui.KeyboardShortcutHandler.EventType', 'goog.ui.KeyboardShortcutHandler.Modifiers'], ['goog.array', 'goog.asserts', 'goog.dom.TagName', 'goog.events', 'goog.events.Event', 'goog.events.EventTarget', 'goog.events.EventType', 'goog.events.KeyCodes', 'goog.events.KeyNames', 'goog.events.Keys', 'goog.object', 'goog.ui.KeyboardEventData', 'goog.ui.SyntheticKeyboardEvent', 'goog.userAgent']); goog.addDependency("ui/keyboardshortcuthandler_test.js", ['goog.ui.KeyboardShortcutHandlerTest'], ['goog.dom', 'goog.events', 'goog.events.BrowserEvent', 'goog.events.KeyCodes', 'goog.testing.MockClock', 'goog.testing.PropertyReplacer', 'goog.testing.StrictMock', 'goog.testing.events', 'goog.testing.jsunit', 'goog.ui.KeyboardShortcutHandler', 'goog.userAgent']); goog.addDependency("ui/labelinput.js", ['goog.ui.LabelInput'], ['goog.Timer', 'goog.a11y.aria', 'goog.a11y.aria.State', 'goog.asserts', 'goog.dom', 'goog.dom.InputType', 'goog.dom.TagName', 'goog.dom.classlist', 'goog.events.EventHandler', 'goog.events.EventType', 'goog.ui.Component', 'goog.userAgent']); goog.addDependency("ui/labelinput_test.js", ['goog.ui.LabelInputTest'], ['goog.a11y.aria', 'goog.a11y.aria.State', 'goog.dom', 'goog.dom.classlist', 'goog.events.EventType', 'goog.testing.MockClock', 'goog.testing.events', 'goog.testing.events.Event', 'goog.testing.jsunit', 'goog.ui.LabelInput', 'goog.userAgent']); @@ -1582,7 +1588,7 @@ goog.addDependency("ui/popupbase_test.js", ['goog.ui.PopupBaseTest'], ['goog.dom goog.addDependency("ui/popupcolorpicker.js", ['goog.ui.PopupColorPicker'], ['goog.asserts', 'goog.dom.classlist', 'goog.events.EventType', 'goog.positioning.AnchoredPosition', 'goog.positioning.Corner', 'goog.ui.ColorPicker', 'goog.ui.Component', 'goog.ui.Popup']); goog.addDependency("ui/popupcolorpicker_test.js", ['goog.ui.PopupColorPickerTest'], ['goog.dom', 'goog.events', 'goog.testing.events', 'goog.testing.jsunit', 'goog.ui.ColorPicker', 'goog.ui.PopupColorPicker']); goog.addDependency("ui/popupdatepicker.js", ['goog.ui.PopupDatePicker'], ['goog.events.EventType', 'goog.positioning.AnchoredPosition', 'goog.positioning.Corner', 'goog.positioning.Overflow', 'goog.style', 'goog.ui.Component', 'goog.ui.DatePicker', 'goog.ui.Popup', 'goog.ui.PopupBase']); -goog.addDependency("ui/popupdatepicker_test.js", ['goog.ui.PopupDatePickerTest'], ['goog.date.Date', 'goog.events', 'goog.testing.jsunit', 'goog.testing.recordFunction', 'goog.ui.PopupBase', 'goog.ui.PopupDatePicker']); +goog.addDependency("ui/popupdatepicker_test.js", ['goog.ui.PopupDatePickerTest'], ['goog.date.Date', 'goog.events', 'goog.testing.MockControl', 'goog.testing.jsunit', 'goog.testing.recordFunction', 'goog.ui.DatePicker', 'goog.ui.PopupBase', 'goog.ui.PopupDatePicker']); goog.addDependency("ui/popupmenu.js", ['goog.ui.PopupMenu'], ['goog.events', 'goog.events.BrowserEvent', 'goog.events.EventType', 'goog.events.KeyCodes', 'goog.positioning.AnchoredViewportPosition', 'goog.positioning.Corner', 'goog.positioning.MenuAnchoredPosition', 'goog.positioning.Overflow', 'goog.positioning.ViewportClientPosition', 'goog.structs.Map', 'goog.style', 'goog.ui.Component', 'goog.ui.Menu', 'goog.ui.PopupBase']); goog.addDependency("ui/popupmenu_test.js", ['goog.ui.PopupMenuTest'], ['goog.dom', 'goog.events.EventHandler', 'goog.events.EventType', 'goog.events.KeyCodes', 'goog.math.Box', 'goog.math.Coordinate', 'goog.positioning.Corner', 'goog.style', 'goog.testing.events', 'goog.testing.jsunit', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.ui.PopupMenu']); goog.addDependency("ui/progressbar.js", ['goog.ui.ProgressBar', 'goog.ui.ProgressBar.Orientation'], ['goog.a11y.aria', 'goog.asserts', 'goog.dom', 'goog.dom.TagName', 'goog.dom.classlist', 'goog.events', 'goog.events.EventType', 'goog.ui.Component', 'goog.ui.RangeModel', 'goog.userAgent']); @@ -1623,6 +1629,7 @@ goog.addDependency("ui/style/app/primaryactionbuttonrenderer_test.js", ['goog.ui goog.addDependency("ui/submenu.js", ['goog.ui.SubMenu'], ['goog.Timer', 'goog.asserts', 'goog.dom', 'goog.dom.classlist', 'goog.events.KeyCodes', 'goog.positioning.AnchoredViewportPosition', 'goog.positioning.Corner', 'goog.style', 'goog.ui.Component', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.ui.SubMenuRenderer', 'goog.ui.registry']); goog.addDependency("ui/submenu_test.js", ['goog.ui.SubMenuTest'], ['goog.a11y.aria', 'goog.a11y.aria.State', 'goog.dom', 'goog.dom.classlist', 'goog.events', 'goog.events.Event', 'goog.events.KeyCodes', 'goog.events.KeyHandler', 'goog.functions', 'goog.positioning', 'goog.positioning.Overflow', 'goog.style', 'goog.testing.MockClock', 'goog.testing.events', 'goog.testing.jsunit', 'goog.ui.Component', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.ui.SubMenu', 'goog.ui.SubMenuRenderer']); goog.addDependency("ui/submenurenderer.js", ['goog.ui.SubMenuRenderer'], ['goog.a11y.aria', 'goog.a11y.aria.State', 'goog.asserts', 'goog.dom', 'goog.dom.TagName', 'goog.dom.classlist', 'goog.style', 'goog.ui.Menu', 'goog.ui.MenuItemRenderer']); +goog.addDependency("ui/synthetickeyboardevent.js", ['goog.ui.SyntheticKeyboardEvent'], ['goog.events.Event', 'goog.ui.KeyboardEventData']); goog.addDependency("ui/tab.js", ['goog.ui.Tab'], ['goog.ui.Component', 'goog.ui.Control', 'goog.ui.TabRenderer', 'goog.ui.registry']); goog.addDependency("ui/tab_test.js", ['goog.ui.TabTest'], ['goog.dom', 'goog.testing.jsunit', 'goog.ui.Component', 'goog.ui.Tab', 'goog.ui.TabRenderer']); goog.addDependency("ui/tabbar.js", ['goog.ui.TabBar', 'goog.ui.TabBar.Location'], ['goog.ui.Component.EventType', 'goog.ui.Container', 'goog.ui.Container.Orientation', 'goog.ui.Tab', 'goog.ui.TabBarRenderer', 'goog.ui.registry']); From ce816b93bf0ff702b84a19d2964c8c6dce5b4313 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 24 Apr 2019 10:43:09 -0700 Subject: [PATCH 027/233] Added field_label_serializable. (#2399) --- blockly_compressed.js | 132 +++++++++++++++------------- blockly_uncompressed.js | 4 +- core/blockly.js | 1 + core/field_label_serializable.js | 77 ++++++++++++++++ demos/blockfactory/blocks.js | 22 ++++- demos/blockfactory/factory_utils.js | 13 +++ demos/blockfactory/index.html | 1 + tests/blocks/test_blocks.js | 14 +++ tests/mocha/xml_test.js | 19 ++++ tests/playground.html | 17 ++++ 10 files changed, 235 insertions(+), 65 deletions(-) create mode 100644 core/field_label_serializable.js diff --git a/blockly_compressed.js b/blockly_compressed.js index 00679a332ad..490ad1d25b4 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -3,8 +3,8 @@ var $jscomp=$jscomp||{};$jscomp.scope={};var COMPILED=!0,goog=goog||{};goog.global=this;goog.isDef=function(a){return void 0!==a};goog.isString=function(a){return"string"==typeof a};goog.isBoolean=function(a){return"boolean"==typeof a};goog.isNumber=function(a){return"number"==typeof a}; goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||"undefined"==typeof c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&goog.isDef(b)?c[d]=b:c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}}; -goog.define=function(a,b){var c=b;if(!COMPILED){var d=goog.global.CLOSURE_UNCOMPILED_DEFINES,e=goog.global.CLOSURE_DEFINES;d&&void 0===d.nodeType&&Object.prototype.hasOwnProperty.call(d,a)?c=d[a]:e&&void 0===e.nodeType&&Object.prototype.hasOwnProperty.call(e,a)&&(c=e[a])}goog.exportPath_(a,c);return c};goog.DEBUG=!1;goog.LOCALE="en";goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG;goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1; -goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide cannot be used within a module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)};goog.constructNamespace_=function(a,b){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var c=a;(c=c.substring(0,c.lastIndexOf(".")))&&!goog.getObjectByName(c);)goog.implicitNamespaces_[c]=!0}goog.exportPath_(a,b)}; +goog.define=function(a,b){var c=b;if(!COMPILED){var d=goog.global.CLOSURE_UNCOMPILED_DEFINES,e=goog.global.CLOSURE_DEFINES;d&&void 0===d.nodeType&&Object.prototype.hasOwnProperty.call(d,a)?c=d[a]:e&&void 0===e.nodeType&&Object.prototype.hasOwnProperty.call(e,a)&&(c=e[a])}goog.exportPath_(a,c);return c};goog.FEATURESET_YEAR=2012;goog.DEBUG=!1;goog.LOCALE="en";goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG; +goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1;goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide cannot be used within a module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)};goog.constructNamespace_=function(a,b){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var c=a;(c=c.substring(0,c.lastIndexOf(".")))&&!goog.getObjectByName(c);)goog.implicitNamespaces_[c]=!0}goog.exportPath_(a,b)}; goog.getScriptNonce=function(a){if(a&&a!=goog.global)return goog.getScriptNonce_(a.document);null===goog.cspNonce_&&(goog.cspNonce_=goog.getScriptNonce_(goog.global.document));return goog.cspNonce_};goog.NONCE_PATTERN_=/^[\w+/_-]+[=]{0,2}$/;goog.cspNonce_=null;goog.getScriptNonce_=function(a){return(a=a.querySelector&&a.querySelector("script[nonce]"))&&(a=a.nonce||a.getAttribute("nonce"))&&goog.NONCE_PATTERN_.test(a)?a:""};goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/; goog.module=function(a){if(!goog.isString(a)||!a||-1==a.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInGoogModuleLoader_())throw Error("Module "+a+" has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide."); if(goog.moduleLoaderState_.moduleName)throw Error("goog.module may only be called once per module.");goog.moduleLoaderState_.moduleName=a;if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a]}};goog.module.get=function(a){return goog.module.getInternal_(a)}; @@ -12,7 +12,7 @@ goog.module.getInternal_=function(a){if(!COMPILED){if(a in goog.loadedModules_)r goog.isInEs6ModuleLoader_=function(){if(goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.ES6)return!0;var a=goog.global.$jscomp;return a?"function"!=typeof a.getCurrentModulePath?!1:!!a.getCurrentModulePath():!1}; goog.module.declareLegacyNamespace=function(){if(!COMPILED&&!goog.isInGoogModuleLoader_())throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module");if(!COMPILED&&!goog.moduleLoaderState_.moduleName)throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace.");goog.moduleLoaderState_.declareLegacyNamespace=!0}; goog.declareModuleId=function(a){if(!COMPILED){if(!goog.isInEs6ModuleLoader_())throw Error("goog.declareModuleId may only be called from within an ES6 module");if(goog.moduleLoaderState_&&goog.moduleLoaderState_.moduleName)throw Error("goog.declareModuleId may only be called once per module.");if(a in goog.loadedModules_)throw Error('Module with namespace "'+a+'" already exists.');}if(goog.moduleLoaderState_)goog.moduleLoaderState_.moduleName=a;else{var b=goog.global.$jscomp;if(!b||"function"!=typeof b.getCurrentModulePath)throw Error('Module with namespace "'+ -a+'" has been loaded incorrectly.');b=b.require(b.getCurrentModulePath());goog.loadedModules_[a]={exports:b,type:goog.ModuleType.ES6,moduleId:a}}};goog.module.declareNamespace=goog.declareModuleId;goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){}; +a+'" has been loaded incorrectly.');b=b.require(b.getCurrentModulePath());goog.loadedModules_[a]={exports:b,type:goog.ModuleType.ES6,moduleId:a}}};goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){}; COMPILED||(goog.isProvided_=function(a){return a in goog.loadedModules_||!goog.implicitNamespaces_[a]&&goog.isDefAndNotNull(goog.getObjectByName(a))},goog.implicitNamespaces_={"goog.module":!0});goog.getObjectByName=function(a,b){for(var c=a.split("."),d=b||goog.global,e=0;ea.length?"&":"")+encodeURIComponent(d)+"="+encodeURIComponent(String(g)))}}return b};goog.html.SafeUrl=function(){this.privateDoNotAccessOrElseSafeUrlWrappedValue_="";this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeUrl.INNOCUOUS_STRING="about:invalid#zClosurez";goog.html.SafeUrl.prototype.implementsGoogStringTypedString=!0;goog.html.SafeUrl.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeUrlWrappedValue_.toString()}; goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString=!0;goog.html.SafeUrl.prototype.getDirection=function(){return goog.i18n.bidi.Dir.LTR};goog.DEBUG&&(goog.html.SafeUrl.prototype.toString=function(){return"SafeUrl{"+this.privateDoNotAccessOrElseSafeUrlWrappedValue_+"}"});goog.html.SafeUrl.unwrap=function(a){return goog.html.SafeUrl.unwrapTrustedURL(a).toString()}; goog.html.SafeUrl.unwrapTrustedURL=function(a){if(a instanceof goog.html.SafeUrl&&a.constructor===goog.html.SafeUrl&&a.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseSafeUrlWrappedValue_;goog.asserts.fail("expected object of type SafeUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:SafeUrl"};goog.html.SafeUrl.fromConstant=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))}; -goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))$/i;goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.DATA_URL_PATTERN_=/^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; -goog.html.SafeUrl.fromDataUrl=function(a){a=a.replace(/(%0A|%0D)/g,"");var b=a.match(goog.html.DATA_URL_PATTERN_);b=b&&goog.html.SAFE_MIME_TYPE_PATTERN_.test(b[1]);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b?a:goog.html.SafeUrl.INNOCUOUS_STRING)};goog.html.SafeUrl.fromTelUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"tel:")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; +goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))$/i;goog.html.SafeUrl.isSafeMimeType=function(a){return goog.html.SAFE_MIME_TYPE_PATTERN_.test(a)};goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; +goog.html.DATA_URL_PATTERN_=/^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i;goog.html.SafeUrl.fromDataUrl=function(a){a=a.replace(/(%0A|%0D)/g,"");var b=a.match(goog.html.DATA_URL_PATTERN_);b=b&&goog.html.SAFE_MIME_TYPE_PATTERN_.test(b[1]);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b?a:goog.html.SafeUrl.INNOCUOUS_STRING)};goog.html.SafeUrl.fromTelUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"tel:")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SIP_URL_PATTERN_=/^sip[s]?:[+a-z0-9_.!$%&'*\/=^`{|}~-]+@([a-z0-9-]+\.)+[a-z0-9]{2,63}$/i;goog.html.SafeUrl.fromSipUrl=function(a){goog.html.SIP_URL_PATTERN_.test(decodeURIComponent(a))||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.fromFacebookMessengerUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"fb-messenger://share")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SafeUrl.fromSmsUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"sms:")&&goog.html.SafeUrl.isSmsUrlBodyValid_(a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.isSmsUrlBodyValid_=function(a){var b=a.indexOf("#");0=goog.events.KeyCodes.F1&&a.keyCode<=goog.events.KeyCodes.F12)return!1;switch(a.keyCode){case goog.events.KeyCodes.ALT:case goog.events.KeyCodes.CAPS_LOCK:case goog.events.KeyCodes.CONTEXT_MENU:case goog.events.KeyCodes.CTRL:case goog.events.KeyCodes.DOWN:case goog.events.KeyCodes.END:case goog.events.KeyCodes.ESC:case goog.events.KeyCodes.HOME:case goog.events.KeyCodes.INSERT:case goog.events.KeyCodes.LEFT:case goog.events.KeyCodes.MAC_FF_META:case goog.events.KeyCodes.META:case goog.events.KeyCodes.NUMLOCK:case goog.events.KeyCodes.NUM_CENTER:case goog.events.KeyCodes.PAGE_DOWN:case goog.events.KeyCodes.PAGE_UP:case goog.events.KeyCodes.PAUSE:case goog.events.KeyCodes.PHANTOM:case goog.events.KeyCodes.PRINT_SCREEN:case goog.events.KeyCodes.RIGHT:case goog.events.KeyCodes.SCROLL_LOCK:case goog.events.KeyCodes.SHIFT:case goog.events.KeyCodes.UP:case goog.events.KeyCodes.VK_NONAME:case goog.events.KeyCodes.WIN_KEY:case goog.events.KeyCodes.WIN_KEY_RIGHT:return!1;case goog.events.KeyCodes.WIN_KEY_FF_LINUX:return!goog.userAgent.GECKO; +goog.events.KeyCodes.isTextModifyingKeyEvent=function(a){if(a.altKey&&!a.ctrlKey||a.metaKey||a.keyCode>=goog.events.KeyCodes.F1&&a.keyCode<=goog.events.KeyCodes.F12)return!1;if(goog.events.KeyCodes.isCharacterKey(a.keyCode))return!0;switch(a.keyCode){case goog.events.KeyCodes.ALT:case goog.events.KeyCodes.CAPS_LOCK:case goog.events.KeyCodes.CONTEXT_MENU:case goog.events.KeyCodes.CTRL:case goog.events.KeyCodes.DOWN:case goog.events.KeyCodes.END:case goog.events.KeyCodes.ESC:case goog.events.KeyCodes.HOME:case goog.events.KeyCodes.INSERT:case goog.events.KeyCodes.LEFT:case goog.events.KeyCodes.MAC_FF_META:case goog.events.KeyCodes.META:case goog.events.KeyCodes.NUMLOCK:case goog.events.KeyCodes.NUM_CENTER:case goog.events.KeyCodes.PAGE_DOWN:case goog.events.KeyCodes.PAGE_UP:case goog.events.KeyCodes.PAUSE:case goog.events.KeyCodes.PHANTOM:case goog.events.KeyCodes.PRINT_SCREEN:case goog.events.KeyCodes.RIGHT:case goog.events.KeyCodes.SCROLL_LOCK:case goog.events.KeyCodes.SHIFT:case goog.events.KeyCodes.UP:case goog.events.KeyCodes.VK_NONAME:case goog.events.KeyCodes.WIN_KEY:case goog.events.KeyCodes.WIN_KEY_RIGHT:return!1;case goog.events.KeyCodes.WIN_KEY_FF_LINUX:return!goog.userAgent.GECKO; default:return a.keyCodegoog.events.KeyCodes.LAST_MEDIA_KEY}}; goog.events.KeyCodes.firesKeyPressEvent=function(a,b,c,d,e,f){if(goog.userAgent.WEBKIT&&!goog.userAgent.isVersionOrHigher("525"))return!0;if(goog.userAgent.MAC&&e)return goog.events.KeyCodes.isCharacterKey(a);if(e&&!d)return!1;if(!goog.userAgent.GECKO){goog.isNumber(b)&&(b=goog.events.KeyCodes.normalizeKeyCode(b));var g=b==goog.events.KeyCodes.CTRL||b==goog.events.KeyCodes.ALT||goog.userAgent.MAC&&b==goog.events.KeyCodes.META,h=b==goog.events.KeyCodes.SHIFT&&(d||f);if((!c||goog.userAgent.MAC)&&g|| goog.userAgent.MAC&&h)return!1}if((goog.userAgent.WEBKIT||goog.userAgent.EDGE)&&d&&c)switch(a){case goog.events.KeyCodes.BACKSLASH:case goog.events.KeyCodes.OPEN_SQUARE_BRACKET:case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET:case goog.events.KeyCodes.TILDE:case goog.events.KeyCodes.SEMICOLON:case goog.events.KeyCodes.DASH:case goog.events.KeyCodes.EQUALS:case goog.events.KeyCodes.COMMA:case goog.events.KeyCodes.PERIOD:case goog.events.KeyCodes.SLASH:case goog.events.KeyCodes.APOSTROPHE:case goog.events.KeyCodes.SINGLE_QUOTE:return!1}if(goog.userAgent.IE&& d&&b==a)return!1;switch(a){case goog.events.KeyCodes.ENTER:return goog.userAgent.GECKO?f||e?!1:!(c&&d):!0;case goog.events.KeyCodes.ESC:return!(goog.userAgent.WEBKIT||goog.userAgent.EDGE||goog.userAgent.GECKO)}return goog.userAgent.GECKO&&(d||e||f)?!1:goog.events.KeyCodes.isCharacterKey(a)}; goog.events.KeyCodes.isCharacterKey=function(a){if(a>=goog.events.KeyCodes.ZERO&&a<=goog.events.KeyCodes.NINE||a>=goog.events.KeyCodes.NUM_ZERO&&a<=goog.events.KeyCodes.NUM_MULTIPLY||a>=goog.events.KeyCodes.A&&a<=goog.events.KeyCodes.Z||(goog.userAgent.WEBKIT||goog.userAgent.EDGE)&&0==a)return!0;switch(a){case goog.events.KeyCodes.SPACE:case goog.events.KeyCodes.PLUS_SIGN:case goog.events.KeyCodes.QUESTION_MARK:case goog.events.KeyCodes.AT_SIGN:case goog.events.KeyCodes.NUM_PLUS:case goog.events.KeyCodes.NUM_MINUS:case goog.events.KeyCodes.NUM_PERIOD:case goog.events.KeyCodes.NUM_DIVISION:case goog.events.KeyCodes.SEMICOLON:case goog.events.KeyCodes.FF_SEMICOLON:case goog.events.KeyCodes.DASH:case goog.events.KeyCodes.EQUALS:case goog.events.KeyCodes.FF_EQUALS:case goog.events.KeyCodes.COMMA:case goog.events.KeyCodes.PERIOD:case goog.events.KeyCodes.SLASH:case goog.events.KeyCodes.APOSTROPHE:case goog.events.KeyCodes.SINGLE_QUOTE:case goog.events.KeyCodes.OPEN_SQUARE_BRACKET:case goog.events.KeyCodes.BACKSLASH:case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET:case goog.events.KeyCodes.FF_HASH:return!0; -default:return!1}};goog.events.KeyCodes.normalizeKeyCode=function(a){return goog.userAgent.GECKO?goog.events.KeyCodes.normalizeGeckoKeyCode(a):goog.userAgent.MAC&&goog.userAgent.WEBKIT?goog.events.KeyCodes.normalizeMacWebKitKeyCode(a):a}; +case goog.events.KeyCodes.FF_DASH:return goog.userAgent.GECKO;default:return!1}};goog.events.KeyCodes.normalizeKeyCode=function(a){return goog.userAgent.GECKO?goog.events.KeyCodes.normalizeGeckoKeyCode(a):goog.userAgent.MAC&&goog.userAgent.WEBKIT?goog.events.KeyCodes.normalizeMacWebKitKeyCode(a):a}; goog.events.KeyCodes.normalizeGeckoKeyCode=function(a){switch(a){case goog.events.KeyCodes.FF_EQUALS:return goog.events.KeyCodes.EQUALS;case goog.events.KeyCodes.FF_SEMICOLON:return goog.events.KeyCodes.SEMICOLON;case goog.events.KeyCodes.FF_DASH:return goog.events.KeyCodes.DASH;case goog.events.KeyCodes.MAC_FF_META:return goog.events.KeyCodes.META;case goog.events.KeyCodes.WIN_KEY_FF_LINUX:return goog.events.KeyCodes.WIN_KEY;default:return a}}; goog.events.KeyCodes.normalizeMacWebKitKeyCode=function(a){switch(a){case goog.events.KeyCodes.MAC_WK_CMD_RIGHT:return goog.events.KeyCodes.META;default:return a}};goog.events.KeyHandler=function(a,b){goog.events.EventTarget.call(this);a&&this.attach(a,b)};goog.inherits(goog.events.KeyHandler,goog.events.EventTarget);goog.events.KeyHandler.prototype.element_=null;goog.events.KeyHandler.prototype.keyPressKey_=null;goog.events.KeyHandler.prototype.keyDownKey_=null;goog.events.KeyHandler.prototype.keyUpKey_=null;goog.events.KeyHandler.prototype.lastKey_=-1;goog.events.KeyHandler.prototype.keyCode_=-1;goog.events.KeyHandler.prototype.altKey_=!1; goog.events.KeyHandler.EventType={KEY:"key"}; @@ -931,7 +931,7 @@ Blockly.Events.UI||"click"!=g.element||"commentOpen"!=l.element&&"mutatorOpen"!= Blockly.Events.enable=function(){Blockly.Events.disabled_--};Blockly.Events.isEnabled=function(){return 0==Blockly.Events.disabled_};Blockly.Events.getGroup=function(){return Blockly.Events.group_};Blockly.Events.setGroup=function(a){Blockly.Events.group_="boolean"==typeof a?a?Blockly.utils.genUid():"":a};Blockly.Events.getDescendantIds_=function(a){var b=[];a=a.getDescendants(!1);for(var c=0,d;d=a[c];c++)b[c]=d.id;return b}; Blockly.Events.fromJson=function(a,b){switch(a.type){case Blockly.Events.CREATE:var c=new Blockly.Events.Create(null);break;case Blockly.Events.DELETE:c=new Blockly.Events.Delete(null);break;case Blockly.Events.CHANGE:c=new Blockly.Events.Change(null,"","","","");break;case Blockly.Events.MOVE:c=new Blockly.Events.Move(null);break;case Blockly.Events.VAR_CREATE:c=new Blockly.Events.VarCreate(null);break;case Blockly.Events.VAR_DELETE:c=new Blockly.Events.VarDelete(null);break;case Blockly.Events.VAR_RENAME:c= new Blockly.Events.VarRename(null,"");break;case Blockly.Events.UI:c=new Blockly.Events.Ui(null);break;case Blockly.Events.COMMENT_CREATE:c=new Blockly.Events.CommentCreate(null);break;case Blockly.Events.COMMENT_CHANGE:c=new Blockly.Events.CommentChange(null);break;case Blockly.Events.COMMENT_MOVE:c=new Blockly.Events.CommentMove(null);break;case Blockly.Events.COMMENT_DELETE:c=new Blockly.Events.CommentDelete(null);break;default:throw Error("Unknown event type.");}c.fromJson(a);c.workspaceId=b.id; -return c};Blockly.Events.disableOrphans=function(a){if(a.type==Blockly.Events.MOVE||a.type==Blockly.Events.CREATE){var b=Blockly.Workspace.getById(a.workspaceId);if(a=b.getBlockById(a.blockId))if(a.getParent()&&!a.getParent().disabled){b=a.getDescendants(!1);a=0;for(var c;c=b[a];a++)c.setDisabled(!1)}else if((a.outputConnection||a.previousConnection)&&!b.isDragging()){do a.setDisabled(!0),a=a.getNextBlock();while(a)}}}; +return c};Blockly.Events.disableOrphans=function(a){if(a.type==Blockly.Events.MOVE||a.type==Blockly.Events.CREATE){var b=Blockly.Workspace.getById(a.workspaceId);if(a=b.getBlockById(a.blockId))if(a.getParent()&&!a.getParent().disabled){b=a.getDescendants(!1);a=0;for(var c;c=b[a];a++)c.setEnabled(!0)}else if((a.outputConnection||a.previousConnection)&&!b.isDragging()){do a.setEnabled(!1),a=a.getNextBlock();while(a)}}}; Blockly.Events.Abstract=function(){this.workspaceId=void 0;this.group=Blockly.Events.group_;this.recordUndo=Blockly.Events.recordUndo};Blockly.Events.Abstract.prototype.toJson=function(){var a={type:this.type};this.group&&(a.group=this.group);return a};Blockly.Events.Abstract.prototype.fromJson=function(a){this.group=a.group};Blockly.Events.Abstract.prototype.isNull=function(){return!1};Blockly.Events.Abstract.prototype.run=function(a){}; Blockly.Events.Abstract.prototype.getEventWorkspace_=function(){var a=Blockly.Workspace.getById(this.workspaceId);if(!a)throw Error("Workspace is null. Event must have been generated from real Blockly events.");return a};Blockly.Events.VarBase=function(a){Blockly.Events.VarBase.superClass_.constructor.call(this);this.varId=a.getId();this.workspaceId=a.workspace.id};goog.inherits(Blockly.Events.VarBase,Blockly.Events.Abstract);Blockly.Events.VarBase.prototype.toJson=function(){var a=Blockly.Events.VarBase.superClass_.toJson.call(this);a.varId=this.varId;return a};Blockly.Events.VarBase.prototype.fromJson=function(a){Blockly.Events.VarBase.superClass_.toJson.call(this);this.varId=a.varId}; Blockly.Events.VarCreate=function(a){a&&(Blockly.Events.VarCreate.superClass_.constructor.call(this,a),this.varType=a.type,this.varName=a.name)};goog.inherits(Blockly.Events.VarCreate,Blockly.Events.VarBase);Blockly.Events.VarCreate.prototype.type=Blockly.Events.VAR_CREATE;Blockly.Events.VarCreate.prototype.toJson=function(){var a=Blockly.Events.VarCreate.superClass_.toJson.call(this);a.varType=this.varType;a.varName=this.varName;return a}; @@ -951,7 +951,7 @@ Blockly.VariableMap.prototype.getVariableTypes=function(){for(var a=Object.keys( Blockly.VariableMap.prototype.getVariableUsesById=function(a){for(var b=[],c=this.workspace.getAllBlocks(!1),d=0;d";var d=Blockly.Xml.textToDom(""+a+"");b.domToMutation(d.firstChild)}Blockly.Events.fire(new Blockly.Events.Change(b,"mutation",null,c,a));break;default:console.warn("Unknown change type: "+this.element)}else console.warn("Can't change non-existent block: "+this.blockId)}; Blockly.Events.Create=function(a){a&&(Blockly.Events.Create.superClass_.constructor.call(this,a),this.xml=a.workspace.rendered?Blockly.Xml.blockToDomWithXY(a):Blockly.Xml.blockToDom(a),this.ids=Blockly.Events.getDescendantIds_(a))};goog.inherits(Blockly.Events.Create,Blockly.Events.BlockBase);Blockly.Events.BlockCreate=Blockly.Events.Create;Blockly.Events.Create.prototype.type=Blockly.Events.CREATE; Blockly.Events.Create.prototype.toJson=function(){var a=Blockly.Events.Create.superClass_.toJson.call(this);a.xml=Blockly.Xml.domToText(this.xml);a.ids=this.ids;return a};Blockly.Events.Create.prototype.fromJson=function(a){Blockly.Events.Create.superClass_.fromJson.call(this,a);this.xml=Blockly.Xml.textToDom(""+a.xml+"").firstChild;this.ids=a.ids}; @@ -970,7 +970,7 @@ Blockly.Events.FinishedLoading.prototype.fromJson=function(a){this.workspaceId=a Blockly.Xml.variablesToDom=function(a){for(var b=Blockly.Xml.utils.createElement("variables"),c=0,d;d=a[c];c++){var e=Blockly.Xml.utils.createElement("variable");e.appendChild(Blockly.Xml.utils.createTextNode(d.name));e.setAttribute("type",d.type);e.setAttribute("id",d.getId());b.appendChild(e)}return b}; Blockly.Xml.blockToDomWithXY=function(a,b){var c;a.workspace.RTL&&(c=a.workspace.getWidth());var d=Blockly.Xml.blockToDom(a,b),e=a.getRelativeToSurfaceXY();d.setAttribute("x",Math.round(a.workspace.RTL?c-e.x:e.x));d.setAttribute("y",Math.round(e.y));return d}; Blockly.Xml.fieldToDomVariable_=function(a){null==a.getValue()&&(a.initModel(),a.getValue());var b=a.getVariable();if(!b)throw Error("Tried to serialize a variable field with no variable.");var c=Blockly.Xml.utils.createElement("field");c.appendChild(Blockly.Xml.utils.createTextNode(b.name));c.setAttribute("name",a.name);c.setAttribute("id",b.getId());c.setAttribute("variabletype",b.type);return c}; -Blockly.Xml.fieldToDom_=function(a){if(a.name&&a.EDITABLE){if(a.referencesVariables())return Blockly.Xml.fieldToDomVariable_(a);var b=Blockly.Xml.utils.createElement("field");b.appendChild(Blockly.Xml.utils.createTextNode(a.getValue()));b.setAttribute("name",a.name);return b}return null};Blockly.Xml.allFieldsToDom_=function(a,b){for(var c=0,d;d=a.inputList[c];c++)for(var e=0,f;f=d.fieldRow[e];e++)(f=Blockly.Xml.fieldToDom_(f))&&b.appendChild(f)}; +Blockly.Xml.fieldToDom_=function(a){if(a.isSerializable()){if(a.referencesVariables())return Blockly.Xml.fieldToDomVariable_(a);var b=Blockly.Xml.utils.createElement("field");b.appendChild(Blockly.Xml.utils.createTextNode(a.getValue()));b.setAttribute("name",a.name);return b}return null};Blockly.Xml.allFieldsToDom_=function(a,b){for(var c=0,d;d=a.inputList[c];c++)for(var e=0,f;f=d.fieldRow[e];e++)(f=Blockly.Xml.fieldToDom_(f))&&b.appendChild(f)}; Blockly.Xml.blockToDom=function(a,b){var c=Blockly.Xml.utils.createElement(a.isShadow()?"shadow":"block");c.setAttribute("type",a.type);b||c.setAttribute("id",a.id);if(a.mutationToDom){var d=a.mutationToDom();d&&(d.hasChildNodes()||d.hasAttributes())&&c.appendChild(d)}Blockly.Xml.allFieldsToDom_(a,c);var e=a.getCommentText();e&&(d=Blockly.Xml.utils.createElement("comment"),d.appendChild(Blockly.Xml.utils.createTextNode(e)),"object"==typeof a.comment&&(d.setAttribute("pinned",a.comment.isVisible()), e=a.comment.getBubbleSize(),d.setAttribute("h",e.height),d.setAttribute("w",e.width)),c.appendChild(d));a.data&&(d=Blockly.Xml.utils.createElement("data"),d.appendChild(Blockly.Xml.utils.createTextNode(a.data)),c.appendChild(d));e=0;for(var f;f=a.inputList[e];e++){var g,h=!0;if(f.type!=Blockly.DUMMY_INPUT){var k=f.connection.targetBlock();f.type==Blockly.INPUT_VALUE?g=Blockly.Xml.utils.createElement("value"):f.type==Blockly.NEXT_STATEMENT&&(g=Blockly.Xml.utils.createElement("statement"));d=f.connection.getShadowDom(); !d||k&&k.isShadow()||g.appendChild(Blockly.Xml.cloneShadow_(d));k&&(g.appendChild(Blockly.Xml.blockToDom(k,b)),h=!1);g.setAttribute("name",f.name);h||c.appendChild(g)}}a.inputsInlineDefault!=a.inputsInline&&c.setAttribute("inline",a.inputsInline);a.isCollapsed()&&c.setAttribute("collapsed",!0);a.disabled&&c.setAttribute("disabled",!0);a.isDeletable()||a.isShadow()||c.setAttribute("deletable",!1);a.isMovable()||a.isShadow()||c.setAttribute("movable",!1);a.isEditable()||c.setAttribute("editable",!1); @@ -989,7 +989,7 @@ Blockly.Xml.domToVariables=function(a,b){for(var c=0,d;d=a.childNodes[c];c++)if( Blockly.Xml.domToBlockHeadless_=function(a,b){var c=null,d=a.getAttribute("type");if(!d)throw TypeError("Block type unspecified: "+a.outerHTML);var e=a.getAttribute("id");c=b.newBlock(d,e);var f=null;e=0;for(var g;g=a.childNodes[e];e++)if(3!=g.nodeType){for(var h=f=null,k=0,l;l=g.childNodes[k];k++)1==l.nodeType&&("block"==l.nodeName.toLowerCase()?f=l:"shadow"==l.nodeName.toLowerCase()&&(h=l));!f&&h&&(f=h);k=g.getAttribute("name");switch(g.nodeName.toLowerCase()){case "mutation":c.domToMutation&&(c.domToMutation(g), c.initSvg&&c.initSvg());break;case "comment":c.setCommentText(g.textContent);var n=g.getAttribute("pinned");n&&!c.isInFlyout&&setTimeout(function(){c.comment&&c.comment.setVisible&&c.comment.setVisible("true"==n)},1);f=parseInt(g.getAttribute("w"),10);g=parseInt(g.getAttribute("h"),10);!isNaN(f)&&!isNaN(g)&&c.comment&&c.comment.setVisible&&c.comment.setBubbleSize(f,g);break;case "data":c.data=g.textContent;break;case "title":case "field":Blockly.Xml.domToField_(c,k,g);break;case "value":case "statement":g= c.getInput(k);if(!g){console.warn("Ignoring non-existent input "+k+" in block "+d);break}h&&g.connection.setShadowDom(h);if(f)if(f=Blockly.Xml.domToBlockHeadless_(f,b),f.outputConnection)g.connection.connect(f.outputConnection);else if(f.previousConnection)g.connection.connect(f.previousConnection);else throw TypeError("Child block does not have output or previous statement.");break;case "next":h&&c.nextConnection&&c.nextConnection.setShadowDom(h);if(f){if(!c.nextConnection)throw TypeError("Next statement does not exist."); -if(c.nextConnection.isConnected())throw TypeError("Next statement is already connected.");f=Blockly.Xml.domToBlockHeadless_(f,b);if(!f.previousConnection)throw TypeError("Next block does not have previous statement.");c.nextConnection.connect(f.previousConnection)}break;default:console.warn("Ignoring unknown tag: "+g.nodeName)}}(e=a.getAttribute("inline"))&&c.setInputsInline("true"==e);(e=a.getAttribute("disabled"))&&c.setDisabled("true"==e||"disabled"==e);(e=a.getAttribute("deletable"))&&c.setDeletable("true"== +if(c.nextConnection.isConnected())throw TypeError("Next statement is already connected.");f=Blockly.Xml.domToBlockHeadless_(f,b);if(!f.previousConnection)throw TypeError("Next block does not have previous statement.");c.nextConnection.connect(f.previousConnection)}break;default:console.warn("Ignoring unknown tag: "+g.nodeName)}}(e=a.getAttribute("inline"))&&c.setInputsInline("true"==e);(e=a.getAttribute("disabled"))&&c.setEnabled("true"!=e&&"disabled"!=e);(e=a.getAttribute("deletable"))&&c.setDeletable("true"== e);(e=a.getAttribute("movable"))&&c.setMovable("true"==e);(e=a.getAttribute("editable"))&&c.setEditable("true"==e);(e=a.getAttribute("collapsed"))&&c.setCollapsed("true"==e);if("shadow"==a.nodeName.toLowerCase()){d=c.getChildren(!1);for(e=0;g=d[e];e++)if(!g.isShadow())throw TypeError("Shadow block not allowed non-shadow child.");if(c.getVarModels().length)throw TypeError("Shadow blocks cannot have variable references.");c.setShadow(!0)}return c}; Blockly.Xml.domToFieldVariable_=function(a,b,c,d){var e=b.getAttribute("variabletype")||"";"''"==e&&(e="");a=Blockly.Variables.getOrCreateVariablePackage(a,b.id,c,e);if(null!=e&&e!==a.type)throw Error("Serialized variable type with id '"+a.getId()+"' had type "+a.type+", and does not match variable field that references it: "+Blockly.Xml.domToText(b)+".");d.setValue(a.getId())}; Blockly.Xml.domToField_=function(a,b,c){var d=a.getField(b);d?(a=a.workspace,b=c.textContent,d.referencesVariables()?Blockly.Xml.domToFieldVariable_(a,c,b,d):d.setValue(b)):console.warn("Ignoring non-existent field "+b+" in block "+a.type)};Blockly.Xml.deleteNext=function(a){for(var b=0,c;c=a.childNodes[b];b++)if("next"==c.nodeName.toLowerCase()){a.removeChild(c);break}};goog.global.Blockly||(goog.global.Blockly={});goog.global.Blockly.Xml||(goog.global.Blockly.Xml={}); @@ -1077,10 +1077,10 @@ Blockly.Connection.prototype.checkConnection_=function(a){switch(this.canConnect case Blockly.Connection.REASON_CHECKS_FAILED:throw Error("Connection checks failed. "+(this+" expected "+this.check_+", found "+a.check_));case Blockly.Connection.REASON_SHADOW_PARENT:throw Error("Connecting non-shadow to shadow block.");default:throw Error("Unknown connection failure: this should never happen!");}}; Blockly.Connection.prototype.canConnectToPrevious_=function(a){if(this.targetConnection||-1!=Blockly.draggingConnections_.indexOf(a))return!1;if(!a.targetConnection)return!0;a=a.targetBlock();return a.isInsertionMarker()?!a.getPreviousBlock():!1}; Blockly.Connection.prototype.isConnectionAllowed=function(a){if(a.sourceBlock_.isInsertionMarker()||this.canConnectWithReason_(a)!=Blockly.Connection.CAN_CONNECT)return!1;switch(a.type){case Blockly.PREVIOUS_STATEMENT:return this.canConnectToPrevious_(a);case Blockly.OUTPUT_VALUE:if(a.isConnected()&&!a.targetBlock().isInsertionMarker()||this.isConnected())return!1;break;case Blockly.INPUT_VALUE:if(a.isConnected()&&!a.targetBlock().isMovable()&&!a.targetBlock().isShadow())return!1;break;case Blockly.NEXT_STATEMENT:if(a.isConnected()&& -!this.sourceBlock_.nextConnection&&!a.targetBlock().isShadow()&&a.targetBlock().nextConnection)return!1;break;default:throw Error("Unknown connection type in isConnectionAllowed");}return-1!=Blockly.draggingConnections_.indexOf(a)?!1:!0};Blockly.Connection.prototype.connect=function(a){this.targetConnection!=a&&(this.checkConnection_(a),this.isSuperior()?this.connect_(a):a.connect_(this))}; +!this.sourceBlock_.nextConnection&&!a.targetBlock().isShadow()&&a.targetBlock().nextConnection)return!1;break;default:throw Error("Unknown connection type in isConnectionAllowed");}return-1!=Blockly.draggingConnections_.indexOf(a)?!1:!0};Blockly.Connection.prototype.connect=function(a){if(this.targetConnection!=a){this.checkConnection_(a);var b=Blockly.Events.getGroup();b||Blockly.Events.setGroup(!0);this.isSuperior()?this.connect_(a):a.connect_(this);b||Blockly.Events.setGroup(!1)}}; Blockly.Connection.connectReciprocally_=function(a,b){if(!a||!b)throw Error("Cannot connect null connections.");a.targetConnection=b;b.targetConnection=a};Blockly.Connection.singleConnection_=function(a,b){for(var c=!1,d=0;db?!1:Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,a)}; +Blockly.RenderedConnection.prototype.connect=function(a){Blockly.RenderedConnection.superClass_.connect.call(this,a);if(this.hidden_||a.hidden_){a=this.isSuperior()?this:a;a.hidden_?a.hideAll():a.unhideAll();var b=a.targetBlock(),c=a.hidden_?"none":"block";b.getSvgRoot().style.display=c;b.rendered=!a.hidden_}}; +Blockly.RenderedConnection.prototype.disconnect=function(){var a=this.isSuperior()?this:this.targetConnection;if(this.targetConnection&&a.hidden_){a.unhideAll();var b=a.targetBlock();b.getSvgRoot().style.display="block";b.rendered=!0;a.setHidden(!0)}Blockly.RenderedConnection.superClass_.disconnect.call(this)}; Blockly.RenderedConnection.prototype.disconnectInternal_=function(a,b){Blockly.RenderedConnection.superClass_.disconnectInternal_.call(this,a,b);a.rendered&&a.render();b.rendered&&(b.updateDisabled(),b.render())}; -Blockly.RenderedConnection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo){Blockly.RenderedConnection.superClass_.respawnShadow_.call(this);b=this.targetBlock();if(!b)throw Error("Couldn't respawn the shadow block that should exist here.");b.initSvg();b.render(!1);a.rendered&&a.render()}};Blockly.RenderedConnection.prototype.neighbours_=function(a){return this.dbOpposite_.getNeighbours(this,a)}; +Blockly.RenderedConnection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo){Blockly.RenderedConnection.superClass_.respawnShadow_.call(this);b=this.targetBlock();if(!b)throw Error("Couldn't respawn the shadow block that should exist here.");b.initSvg();b.render(!1);a.rendered&&!this.hidden_&&a.render()}};Blockly.RenderedConnection.prototype.neighbours_=function(a){return this.dbOpposite_.getNeighbours(this,a)}; Blockly.RenderedConnection.prototype.connect_=function(a){Blockly.RenderedConnection.superClass_.connect_.call(this,a);var b=this.getSourceBlock();a=a.getSourceBlock();b.rendered&&b.updateDisabled();a.rendered&&a.updateDisabled();b.rendered&&a.rendered&&(this.type==Blockly.NEXT_STATEMENT||this.type==Blockly.PREVIOUS_STATEMENT?a.render():b.render())}; Blockly.RenderedConnection.prototype.onCheckChanged_=function(){this.isConnected()&&!this.checkType_(this.targetConnection)&&((this.isSuperior()?this.targetBlock():this.sourceBlock_).unplug(),this.sourceBlock_.bumpNeighbours_())};Blockly.InsertionMarkerManager=function(a){this.topBlock_=Blockly.selected=a;this.workspace_=a.workspace;this.lastMarker_=this.lastOnStack_=null;this.firstMarker_=this.createMarkerBlock_(this.topBlock_);this.localConnection_=this.closestConnection_=null;this.wouldDeleteBlock_=!1;this.markerConnection_=null;this.highlightingBlock_=!1;this.highlightedBlock_=null;this.availableConnections_=this.initAvailableConnections_()}; Blockly.InsertionMarkerManager.prototype.dispose=function(){this.workspace_=this.topBlock_=null;this.availableConnections_.length=0;this.localConnection_=this.closestConnection_=null;Blockly.Events.disable();try{this.firstMarker_&&(this.firstMarker_.dispose(),this.firstMarker_=null),this.lastMarker_&&(this.lastMarker_.dispose(),this.lastMarker_=null)}finally{Blockly.Events.enable()}this.highlightedBlock_=null};Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock=function(){return this.wouldDeleteBlock_}; @@ -1409,20 +1411,23 @@ Blockly.Extensions.buildTooltipForDropdown=function(a,b){var c=[];"object"==type this.type),console.warn(d+".")):e=Blockly.utils.replaceMessageReferences(e);return e}.bind(this))}};Blockly.Extensions.checkDropdownOptionsInTable_=function(a,b,c){var d=a.getField(b);if(!d.isOptionListDynamic()){d=d.getOptions();for(var e=0;ethis.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; -Blockly.Field.prototype.forceRerender=function(){this.size_.width=0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()};Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}}; -Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){};Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.init=function(){this.textElement_||(this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},null),this.class_&&Blockly.utils.addClass(this.textElement_,this.class_),this.visible_||(this.textElement_.style.display="none"),this.sourceBlock_.getSvgRoot().appendChild(this.textElement_),this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_,Blockly.Tooltip.bindMouseEvents(this.textElement_),this.render_())}; +Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()}; +Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.callValidator(a);null!==b&&(a=b);b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){}; +Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; +Blockly.FieldLabel.prototype.init=function(){this.textElement_||(this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},null),this.class_&&Blockly.utils.addClass(this.textElement_,this.class_),this.visible_||(this.textElement_.style.display="none"),this.sourceBlock_.getSvgRoot().appendChild(this.textElement_),this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_,Blockly.Tooltip.bindMouseEvents(this.textElement_))}; Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.getSvgRoot=function(){return this.textElement_};Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; @@ -1463,8 +1468,8 @@ this.previousConnection=null}};Blockly.Block.prototype.setNextStatement=function Blockly.Block.prototype.setOutput=function(a,b){if(a){void 0===b&&(b=null);if(!this.outputConnection){if(this.previousConnection)throw Error("Remove previous connection prior to adding output connection.");this.outputConnection=this.makeConnection_(Blockly.OUTPUT_VALUE)}this.outputConnection.setCheck(b)}else if(this.outputConnection){if(this.outputConnection.isConnected())throw Error("Must disconnect output value before removing connection.");this.outputConnection.dispose();this.outputConnection= null}};Blockly.Block.prototype.setInputsInline=function(a){this.inputsInline!=a&&(Blockly.Events.fire(new Blockly.Events.BlockChange(this,"inline",null,this.inputsInline,a)),this.inputsInline=a)}; Blockly.Block.prototype.getInputsInline=function(){if(void 0!=this.inputsInline)return this.inputsInline;for(var a=1;aa&&(c=c.substring(0,a-3)+"...");return c}; Blockly.Block.prototype.appendValueInput=function(a){return this.appendInput_(Blockly.INPUT_VALUE,a)};Blockly.Block.prototype.appendStatementInput=function(a){return this.appendInput_(Blockly.NEXT_STATEMENT,a)};Blockly.Block.prototype.appendDummyInput=function(a){return this.appendInput_(Blockly.DUMMY_INPUT,a||"")}; Blockly.Block.prototype.jsonInit=function(a){var b=a.type?'Block "'+a.type+'": ':"";if(a.output&&a.previousStatement)throw Error(b+"Must not have both an output and a previousStatement.");a.style&&a.style.hat&&(this.hat=a.style.hat,a.style=null);if(a.style&&a.colour)throw Error(b+"Must not have both a colour and a style.");a.style?this.jsonInitStyle_(a,b):this.jsonInitColour_(a,b);for(var c=0;void 0!==a["message"+c];)this.interpolate_(a["message"+c],a["args"+c]||[],a["lastDummyAlign"+c]),c++;void 0!== @@ -1512,10 +1517,10 @@ Blockly.BlockSvg.prototype.setCollapsed=function(a){if(this.collapsed_!=a){for(v Blockly.BlockSvg.COLLAPSED_WARNING_ID);break}}else this.removeInput("_TEMP_COLLAPSED_INPUT"),this.warning&&(this.warning.setText("",Blockly.BlockSvg.COLLAPSED_WARNING_ID),Object.keys(this.warning.text_).length||this.setWarningText(null));Blockly.BlockSvg.superClass_.setCollapsed.call(this,a);b.length||(b[0]=this);if(this.rendered)for(c=0;e=b[c];c++)e.render()}}; Blockly.BlockSvg.prototype.tab=function(a,b){var c=this.createTabList_(),d=c.indexOf(a);-1==d&&(d=b?-1:c.length);(c=c[b?d+1:d-1])?c instanceof Blockly.Field?c.showEditor_():c.tab(null,b):(c=this.getParent())&&c.tab(this,b)};Blockly.BlockSvg.prototype.createTabList_=function(){for(var a=[],b=0,c;c=this.inputList[b];b++){for(var d=0,e;e=c.fieldRow[d];d++)e instanceof Blockly.FieldTextInput&&a.push(e);c.connection&&(c=c.connection.targetBlock())&&a.push(c)}return a}; Blockly.BlockSvg.prototype.onMouseDown_=function(a){var b=this.workspace&&this.workspace.getGesture(a);b&&b.handleBlockStart(a,this)};Blockly.BlockSvg.prototype.showHelp_=function(){var a="function"==typeof this.helpUrl?this.helpUrl():this.helpUrl;a&&window.open(a)}; -Blockly.BlockSvg.prototype.showContextMenu_=function(a){if(!this.workspace.options.readOnly&&this.contextMenu){var b=this,c=[];if(this.isDeletable()&&this.isMovable()&&!b.isInFlyout){c.push(Blockly.ContextMenu.blockDuplicateOption(b));this.isEditable()&&!this.collapsed_&&this.workspace.options.comments&&c.push(Blockly.ContextMenu.blockCommentOption(b));if(!this.collapsed_)for(var d=1;dc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+ Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),this.sourceBlock_.getColour());Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b, "mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;a=a.clientY-b.top-Blockly.FieldAngle.HALF;b=Math.atan(-a/c);isNaN(b)||(b=Blockly.utils.toDegrees(b),0>c?b+=180:0a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; +Blockly.FieldAngle.prototype.classValidator=function(a){if(null===a)return null;a=parseFloat(a||0);if(isNaN(a))return null;a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; Blockly.FieldCheckbox.prototype.init=function(){if(!this.fieldGroup_){Blockly.FieldCheckbox.superClass_.init.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"}};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; Blockly.FieldCheckbox.prototype.setValue=function(a){a="string"==typeof a?"TRUE"==a.toUpperCase():!!a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(String(a).toUpperCase())}; -Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null;Blockly.FieldColour.prototype.columns_=0; -Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.init=function(){Blockly.FieldColour.superClass_.init.call(this);this.borderRect_.style.fillOpacity=1;this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.setValue(this.getValue())};Blockly.FieldColour.prototype.CURSOR="default"; -Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.getValue=function(){return this.colour_};Blockly.FieldColour.prototype.getSize=function(){this.size_.width||this.render_();return this.size_}; -Blockly.FieldColour.prototype.updateWidth=function(){var a=Blockly.FieldColour.DEFAULT_WIDTH;this.borderRect_&&this.borderRect_.setAttribute("width",a+Blockly.BlockSvg.SEP_SPACE_X);this.size_.width=a};Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)}; -Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); +Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null; +Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.init=function(){Blockly.FieldColour.superClass_.init.call(this);this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.borderRect_.style.fillOpacity=1;this.borderRect_.setAttribute("width",this.size_.width+Blockly.BlockSvg.SEP_SPACE_X);this.setValue(this.getValue())}; +Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.updateWidth=function(){};Blockly.FieldColour.prototype.getValue=function(){return this.colour_}; +Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); Blockly.FieldColour.TITLES=[];Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a,b){this.colours_=a;void 0!==b&&(this.titles_=b);return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this}; Blockly.FieldColour.prototype.showEditor_=function(){Blockly.DropDownDiv.hideWithoutAnimation();Blockly.DropDownDiv.clearContent();var a=this.createWidget_();Blockly.DropDownDiv.getContentDiv().appendChild(a);Blockly.DropDownDiv.setColour(this.DROPDOWN_BACKGROUND_COLOUR,this.DROPDOWN_BORDER_COLOUR);Blockly.DropDownDiv.showPositionedByField(this);Blockly.FieldColour.onUpWrapper_=Blockly.bindEvent_(a,"mouseup",this,this.onClick_)}; Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;gb.viewBottom||b.c n=b.viewBottom-d.bottomRight.y;0>n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; -Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(document.addEventListener("mouseup",function(){Blockly.hideChaff();Blockly.Touch.clearTouchIdentifier()},!1),Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document, -"touchcancel",null,Blockly.longStop_),goog.userAgent.IPAD&&Blockly.bindEventWithChecks_(window,"orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; +Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),goog.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, +"orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[],e=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,e,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,e,!0))}; Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 4752507f726..c498aa19413 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -41,7 +41,7 @@ goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.Block goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml.utils', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg']); goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.color', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml', 'goog.color']); +goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml', 'goog.color']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []); goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.Workspace', 'goog.math.Coordinate', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); @@ -64,6 +64,7 @@ goog.addDependency("../../../" + dir + "/core/field_date.js", ['Blockly.FieldDat goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Field', 'Blockly.utils', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.utils', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'goog.math.Size']); +goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel']); goog.addDependency("../../../" + dir + "/core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.FieldTextInput']); goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Field', 'Blockly.Msg', 'Blockly.utils', 'goog.math.Coordinate', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.utils', 'Blockly.VariableModel', 'Blockly.Variables', 'goog.math.Size']); @@ -1790,6 +1791,7 @@ goog.require('Blockly.FieldDate'); goog.require('Blockly.FieldDropdown'); goog.require('Blockly.FieldImage'); goog.require('Blockly.FieldLabel'); +goog.require('Blockly.FieldLabelSerializable'); goog.require('Blockly.FieldNumber'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.FieldVariable'); diff --git a/core/blockly.js b/core/blockly.js index 0b948ff678c..ca1dcb83f69 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -39,6 +39,7 @@ goog.require('Blockly.FieldColour'); // Add it only if you need it. //goog.require('Blockly.FieldDate'); goog.require('Blockly.FieldDropdown'); +goog.require('Blockly.FieldLabelSerializable'); goog.require('Blockly.FieldImage'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.FieldNumber'); diff --git a/core/field_label_serializable.js b/core/field_label_serializable.js new file mode 100644 index 00000000000..26bf1818562 --- /dev/null +++ b/core/field_label_serializable.js @@ -0,0 +1,77 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Non-editable, serializable text field. Behaves like a + * normal label but is serialized to XML. It may only be + * edited programmatically. + */ +'use strict'; + +goog.provide('Blockly.FieldLabelSerializable'); + +goog.require('Blockly.FieldLabel'); + + +/** + * Class for a non-editable, serializable text field. + * @param {string} text The initial content of the field. + * @param {string} opt_class Optional CSS class for the field's text. + * @extends {Blockly.FieldLabel} + * @constructor + * + */ +Blockly.FieldLabelSerializable = function(text, opt_class) { + Blockly.FieldLabelSerializable.superClass_.constructor.call(this, text, + opt_class); +}; +goog.inherits(Blockly.FieldLabelSerializable, Blockly.FieldLabel); + +/** + * Construct a FieldLabelSerializable from a JSON arg object, + * dereferencing any string table references. + * @param {!Object} options A JSON object with options (text, and class). + * @returns {!Blockly.FieldLabelSerializable} The new field instance. + * @package + * @nocollapse + */ +Blockly.FieldLabelSerializable.fromJson = function(options) { + var text = Blockly.utils.replaceMessageReferences(options['text']); + return new Blockly.FieldLabelSerializable(text, options['class']); +}; + +/** + * Editable fields usually show some sort of UI indicating they are + * editable. This field should not. + * @type {boolean} + * @public + */ +Blockly.FieldLabelSerializable.prototype.EDITABLE = false; + +/** + * Serializable fields are saved by the XML renderer, non-serializable fields + * are not. This field should be serialized, but only edited programmatically. + * @type {boolean} + * @public + */ +Blockly.FieldLabelSerializable.prototype.SERIALIZABLE = true; + +Blockly.Field.register( + 'field_label_serializable', Blockly.FieldLabelSerializable); diff --git a/demos/blockfactory/blocks.js b/demos/blockfactory/blocks.js index 15a7f2a41a2..4ff1af61d06 100644 --- a/demos/blockfactory/blocks.js +++ b/demos/blockfactory/blocks.js @@ -244,13 +244,33 @@ Blockly.Blocks['field_static'] = { // Text value. init: function() { this.setColour(160); - this.appendDummyInput() + this.appendDummyInput('FIRST') .appendField('text') .appendField(new Blockly.FieldTextInput(''), 'TEXT'); this.setPreviousStatement(true, 'Field'); this.setNextStatement(true, 'Field'); this.setTooltip('Static text that serves as a label.'); this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88'); + }, +}; + +Blockly.Blocks['field_label_serializable'] = { + // Text value that is saved to XML. + init: function() { + this.setColour(160); + this.appendDummyInput('FIRST') + .appendField('text') + .appendField(new Blockly.FieldTextInput(''), 'TEXT') + .appendField(',') + .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); + this.setPreviousStatement(true, 'Field'); + this.setNextStatement(true, 'Field'); + this.setTooltip('Static text that serves as a label, and is saved to' + + ' XML. Use only if you want to modify this label at runtime.'); + this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88'); + }, + onchange: function() { + fieldNameCheck(this); } }; diff --git a/demos/blockfactory/factory_utils.js b/demos/blockfactory/factory_utils.js index 4006d43087d..1aac2b331da 100644 --- a/demos/blockfactory/factory_utils.js +++ b/demos/blockfactory/factory_utils.js @@ -406,6 +406,12 @@ FactoryUtils.getFieldsJs_ = function(block) { // Result: 'hello' fields.push(JSON.stringify(block.getFieldValue('TEXT'))); break; + case 'field_label_serializable': + // Result: new Blockly.FieldLabelSerializable('Hello'), 'GREET' + fields.push('new Blockly.FieldLabelSerializable(' + + JSON.stringify(block.getFieldValue('TEXT')) + '), ' + + JSON.stringify(block.getFieldValue('FIELDNAME'))); + break; case 'field_input': // Result: new Blockly.FieldTextInput('Hello'), 'GREET' fields.push('new Blockly.FieldTextInput(' + @@ -511,6 +517,13 @@ FactoryUtils.getFieldsJson_ = function(block) { // Result: 'hello' fields.push(block.getFieldValue('TEXT')); break; + case 'field_label_serializable': + fields.push({ + type: block.type, + name: block.getFieldValue('FIELDNAME'), + text: block.getFieldValue('TEXT') + }); + break; case 'field_input': fields.push({ type: block.type, diff --git a/demos/blockfactory/index.html b/demos/blockfactory/index.html index c3b3bb80b0e..afdfe01a8f3 100644 --- a/demos/blockfactory/index.html +++ b/demos/blockfactory/index.html @@ -421,6 +421,7 @@

Generator stub: + diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index d4cb90284cf..fb9da04df21 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -249,6 +249,20 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "tooltip": "", "helpUrl": "" }, + { + "type": "test_fields_label_serializable", + "message0": "label serializable %1", + "args0": [ + { + "type": "field_label_serializable", + "name": "LABEL", + "text": "default" + } + ], + "colour": 230, + "tooltip": "", + "helpUrl": "" + }, { "type": "test_numbers_float", "message0": "float %1", diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index 6f6ecf9dbe5..f0801c625c5 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -182,6 +182,25 @@ suite('XML', function() { assertNonSerializingField(resultFieldDom); delete Blockly.Blocks['field_label_test_block']; }); + test('Label Serializable', function() { + Blockly.defineBlocksWithJsonArray([{ + "type": "field_label_serializable_test_block", + "message0": "%1", + "args0": [ + { + "type": "field_label_serializable", + "name": "LABEL", + "text": "default" + } + ], + }]); + var block = new Blockly.Block(this.workspace, + 'field_label_serializable_test_block'); + var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; + console.log(resultFieldDom); + assertSimpleField(resultFieldDom, 'LABEL', 'default'); + delete Blockly.Blocks['field_label_serializable_test_block']; + }); test('Number', function() { Blockly.defineBlocksWithJsonArray([{ "type": "field_number_test_block", diff --git a/tests/playground.html b/tests/playground.html index 5da23ea8adf..2c7deeb1163 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -144,6 +144,21 @@ } function addToolboxButtonCallbacks() { + var randomizeLabelText = function(button) { + var blocks = button.targetWorkspace_ + .getBlocksByType('test_fields_label_serializable'); + var possible = 'AB'; + for (var i = 0, block; block = blocks[i]; i++) { + var text = ''; + for (var j = 0; j < 4; j++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + block.setFieldValue(text, 'LABEL'); + } + }; + + workspace.registerButtonCallback( + 'randomizeLabelText', randomizeLabelText); workspace.registerButtonCallback( 'addDynamicOption', Blockly.TestBlocks.addDynamicDropdownOption_); workspace.registerButtonCallback( @@ -1200,6 +1215,8 @@

Blockly Playground

+ +
From 5c4c816a9b186ae9fb4b7c068ba798b7c1f556e2 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 24 Apr 2019 16:07:47 -0700 Subject: [PATCH 028/233] Removed setVisible from the public API (#2406) --- blocks/procedures.js | 2 +- core/field.js | 11 ++++------- core/field_angle.js | 5 ----- core/field_dropdown.js | 4 ---- core/input.js | 3 ++- 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/blocks/procedures.js b/blocks/procedures.js index aee377b04a4..934b8ee5643 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -172,7 +172,7 @@ Blockly.Blocks['procedures_defnoreturn'] = { containerBlock.setFieldValue( this.hasStatements_ ? 'TRUE' : 'FALSE', 'STATEMENTS'); } else { - containerBlock.getInput('STATEMENT_INPUT').setVisible(false); + containerBlock.removeInput('STATEMENT_INPUT'); } // Parameter list. diff --git a/core/field.js b/core/field.js index 6b0968e94dd..ab1309d66c9 100644 --- a/core/field.js +++ b/core/field.js @@ -319,8 +319,10 @@ Blockly.Field.prototype.isVisible = function() { }; /** - * Sets whether this editable field is visible or not. + * Sets whether this editable field is visible or not. Should only be called + * by input.setVisible. * @param {boolean} visible True if visible. + * @package */ Blockly.Field.prototype.setVisible = function(visible) { if (this.visible_ == visible) { @@ -330,7 +332,7 @@ Blockly.Field.prototype.setVisible = function(visible) { var root = this.getSvgRoot(); if (root) { root.style.display = visible ? 'block' : 'none'; - this.render_(); + this.size_.width = 0; } }; @@ -411,11 +413,6 @@ Blockly.Field.prototype.getSvgRoot = function() { * @protected */ Blockly.Field.prototype.render_ = function() { - if (!this.visible_) { - this.size_.width = 0; - return; - } - // Replace the text. this.textElement_.textContent = this.getDisplayText_(); this.updateWidth(); diff --git a/core/field_angle.js b/core/field_angle.js index 0cc308d3f4e..a9a177462d8 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -126,11 +126,6 @@ Blockly.FieldAngle.RADIUS = Blockly.FieldAngle.HALF - 1; * @private */ Blockly.FieldAngle.prototype.render_ = function() { - if (!this.visible_) { - this.size_.width = 0; - return; - } - // Update textElement. this.textElement_.textContent = this.getDisplayText_(); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index abd4fd7ea46..0aadc0306ea 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -437,10 +437,6 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) { * @private */ Blockly.FieldDropdown.prototype.render_ = function() { - if (!this.visible_) { - this.size_.width = 0; - return; - } if (this.sourceBlock_ && this.arrow_) { // Update arrow's colour. this.arrow_.style.fill = this.sourceBlock_.getColour(); diff --git a/core/input.js b/core/input.js index 74aaf4c959f..5b9c8b17074 100644 --- a/core/input.js +++ b/core/input.js @@ -163,9 +163,10 @@ Blockly.Input.prototype.isVisible = function() { /** * Sets whether this input is visible or not. - * Used to collapse/uncollapse a block. + * Should only be used to collapse/uncollapse a block. * @param {boolean} visible True if visible. * @return {!Array.} List of blocks to render. + * @package */ Blockly.Input.prototype.setVisible = function(visible) { var renderList = []; From 123b5dc91ea975816ad1abe6c0f9d0ab5f882e67 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 24 Apr 2019 10:43:09 -0700 Subject: [PATCH 029/233] Added fromXml and toXml to fields. --- core/field.js | 24 ++++++++++++ core/field_variable.js | 31 +++++++++++++++ core/xml.js | 87 ++---------------------------------------- 3 files changed, 59 insertions(+), 83 deletions(-) diff --git a/core/field.js b/core/field.js index ab1309d66c9..8df264e6ac3 100644 --- a/core/field.js +++ b/core/field.js @@ -243,6 +243,30 @@ Blockly.Field.prototype.init = function() { Blockly.Field.prototype.initModel = function() { }; +/** + * Sets the field's value based on the given XML element. Should only be + * called by Blockly.Xml. + * @param {!Element} fieldElement The element containing info about the + * field's state. + * @package + */ +Blockly.Field.prototype.fromXml = function(fieldElement) { + this.setValue(fieldElement.textContent); +}; + +/** + * Serializes this field's value to XML. Should only be called by Blockly.Xml. + * @param {!Element} fieldElement The element to populate with info about the + * field's state. + * @return {!Element} The element containing info about the field's state. + * @package + */ +Blockly.Field.prototype.toXml = function(fieldElement) { + fieldElement.setAttribute('name', this.name); + fieldElement.textContent = this.getValue(); + return fieldElement; +}; + /** * Dispose of all DOM objects belonging to this editable field. */ diff --git a/core/field_variable.js b/core/field_variable.js index dd4315e5996..29c6af878c8 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -126,6 +126,37 @@ Blockly.FieldVariable.prototype.initModel = function() { } }; +Blockly.FieldVariable.prototype.fromXml = function(fieldElement) { + var id = fieldElement.getAttribute('id'); + var variableName = fieldElement.textContent; + var variableType = fieldElement.getAttribute('variabletype') || ''; + + var variable = Blockly.Variables.getOrCreateVariablePackage( + this.workspace_ || this.sourceBlock_.workspace, id, + variableName, variableType); + + // This should never happen :) + if (variableType != null && variableType !== variable.type) { + throw Error('Serialized variable type with id \'' + + variable.getId() + '\' had type ' + variable.type + ', and ' + + 'does not match variable field that references it: ' + + Blockly.Xml.domToText(fieldElement) + '.'); + } + + this.setValue(variable.getId()); +}; + +Blockly.FieldVariable.prototype.toXml = function(fieldElement) { + // Make sure the variable is initialized. + this.initModel(); + + fieldElement.setAttribute('name', this.name); + fieldElement.setAttribute('id', this.variable_.getId()); + fieldElement.textContent = this.variable_.name; + fieldElement.setAttribute('variableType', this.variable_.type); + return fieldElement; +}; + /** * Dispose of this field. * @public diff --git a/core/xml.js b/core/xml.js index 91e47d83cc8..158bd8e0ca0 100644 --- a/core/xml.js +++ b/core/xml.js @@ -97,41 +97,6 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) { return element; }; -/** - * Encode a variable field as XML. - * @param {!Blockly.FieldVariable} field The field to encode. - * @return {Element} XML element, or null if the field did not need to be - * serialized. - * @private - */ -Blockly.Xml.fieldToDomVariable_ = function(field) { - var id = field.getValue(); - // The field had not been initialized fully before being serialized. - // This can happen if a block is created directly through a call to - // workspace.newBlock instead of from XML. - // The new block will be serialized for the first time when firing a block - // creation event. - if (id == null) { - field.initModel(); - id = field.getValue(); - } - // Get the variable directly from the field, instead of doing a lookup. This - // will work even if the variable has already been deleted. This can happen - // because the flyout defers deleting blocks until the next time the flyout - // is opened. - var variable = field.getVariable(); - - if (!variable) { - throw Error('Tried to serialize a variable field with no variable.'); - } - var container = Blockly.Xml.utils.createElement('field'); - container.appendChild(Blockly.Xml.utils.createTextNode(variable.name)); - container.setAttribute('name', field.name); - container.setAttribute('id', variable.getId()); - container.setAttribute('variabletype', variable.type); - return container; -}; - /** * Encode a field as XML. * @param {!Blockly.Field} field The field to encode. @@ -141,14 +106,8 @@ Blockly.Xml.fieldToDomVariable_ = function(field) { */ Blockly.Xml.fieldToDom_ = function(field) { if (field.isSerializable()) { - if (field.referencesVariables()) { - return Blockly.Xml.fieldToDomVariable_(field); - } else { - var container = Blockly.Xml.utils.createElement('field'); - container.appendChild(Blockly.Xml.utils.createTextNode(field.getValue())); - container.setAttribute('name', field.name); - return container; - } + var container = Blockly.Xml.utils.createElement('field'); + return field.toXml(container); } return null; }; @@ -789,37 +748,6 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { return block; }; -/** - * Decode an XML variable field tag and set the value of that field. - * @param {!Blockly.Workspace} workspace The workspace that is currently being - * deserialized. - * @param {!Element} xml The field tag to decode. - * @param {string} text The text content of the XML tag. - * @param {!Blockly.FieldVariable} field The field on which the value will be - * set. - * @private - */ -Blockly.Xml.domToFieldVariable_ = function(workspace, xml, text, field) { - var type = xml.getAttribute('variabletype') || ''; - // TODO (fenichel): Does this need to be explicit or not? - if (type == '\'\'') { - type = ''; - } - - var variable = Blockly.Variables.getOrCreateVariablePackage(workspace, xml.id, - text, type); - - // This should never happen :) - if (type != null && type !== variable.type) { - throw Error('Serialized variable type with id \'' + - variable.getId() + '\' had type ' + variable.type + ', and ' + - 'does not match variable field that references it: ' + - Blockly.Xml.domToText(xml) + '.'); - } - - field.setValue(variable.getId()); -}; - /** * Decode an XML field tag and set the value of that field on the given block. * @param {!Blockly.Block} block The block that is currently being deserialized. @@ -831,17 +759,10 @@ Blockly.Xml.domToField_ = function(block, fieldName, xml) { var field = block.getField(fieldName); if (!field) { console.warn('Ignoring non-existent field ' + fieldName + ' in block ' + - block.type); + block.type); return; } - - var workspace = block.workspace; - var text = xml.textContent; - if (field.referencesVariables()) { - Blockly.Xml.domToFieldVariable_(workspace, xml, text, field); - } else { - field.setValue(text); - } + field.fromXml(xml); }; /** From c438188ab11610bc77ddd6ecd5f7f25c87817b34 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 25 Apr 2019 16:42:53 -0700 Subject: [PATCH 030/233] Delete two unused i18n scripts These date back to before Blockly Games was separated from Blockly. --- i18n/create_messages.py | 2 +- i18n/js_to_json.py | 2 +- i18n/json_to_js.py | 185 -------------------------------- i18n/xliff_to_json.py | 232 ---------------------------------------- 4 files changed, 2 insertions(+), 419 deletions(-) delete mode 100755 i18n/json_to_js.py delete mode 100755 i18n/xliff_to_json.py diff --git a/i18n/create_messages.py b/i18n/create_messages.py index 8a93fbbc713..733d0d71aa8 100755 --- a/i18n/create_messages.py +++ b/i18n/create_messages.py @@ -37,7 +37,7 @@ def string_is_ascii(s): def load_constants(filename): """Read in constants file, which must be output in every language.""" - constant_defs = read_json_file(filename); + constant_defs = read_json_file(filename) constants_text = '\n' for key in constant_defs: value = constant_defs[key] diff --git a/i18n/js_to_json.py b/i18n/js_to_json.py index e48b1cee19d..8f83222ff04 100755 --- a/i18n/js_to_json.py +++ b/i18n/js_to_json.py @@ -17,7 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Extracts messages from .js files into .json files for translation. +"""Extracts messages from messages.js file into .json files for translation. Specifically, lines with the following formats are extracted: diff --git a/i18n/json_to_js.py b/i18n/json_to_js.py deleted file mode 100755 index bf3fb38df58..00000000000 --- a/i18n/json_to_js.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/python - -# Converts .json files into .js files for use within Blockly apps. -# -# Copyright 2013 Google Inc. -# https://developers.google.com/blockly/ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import codecs # for codecs.open(..., 'utf-8') -import glob -import json # for json.load() -import os # for os.path() -import subprocess # for subprocess.check_call() -from common import InputError -from common import read_json_file - - -# Store parsed command-line arguments in global variable. -args = None - - -def _create_xlf(target_lang): - """Creates a .xlf file for Soy. - - Args: - target_lang: The ISO 639 language code for the target language. - This is used in the name of the file and in the metadata. - - Returns: - A pointer to a file to which the metadata has been written. - - Raises: - IOError: An error occurred while opening or writing the file. - """ - filename = os.path.join(os.curdir, args.output_dir, target_lang + '.xlf') - out_file = codecs.open(filename, 'w', 'utf-8') - out_file.write(""" - - - """.format(args.source_lang, target_lang)) - return out_file - - -def _close_xlf(xlf_file): - """Closes a .xlf file created with create_xlf(). - - This includes writing the terminating XML. - - Args: - xlf_file: A pointer to a file created by _create_xlf(). - - Raises: - IOError: An error occurred while writing to or closing the file. - """ - xlf_file.write(""" - - - -""") - xlf_file.close() - - -def _process_file(path_to_json, target_lang, key_dict): - """Creates an .xlf file corresponding to the specified .json input file. - - The name of the input file must be target_lang followed by '.json'. - The name of the output file will be target_lang followed by '.js'. - - Args: - path_to_json: Path to the directory of xx.json files. - target_lang: A IETF language code (RFC 4646), such as 'es' or 'pt-br'. - key_dict: Dictionary mapping Blockly keys (e.g., Maze.turnLeft) to - Closure keys (hash numbers). - - Raises: - IOError: An I/O error occurred with an input or output file. - InputError: Input JSON could not be parsed. - KeyError: Key found in input file but not in key file. - """ - keyfile = os.path.join(path_to_json, target_lang + '.json') - j = read_json_file(keyfile) - out_file = _create_xlf(target_lang) - for key in j: - if key != '@metadata': - try: - identifier = key_dict[key] - except KeyError as e: - print('Key "%s" is in %s but not in %s' % - (key, keyfile, args.key_file)) - raise e - target = j.get(key) - out_file.write(u""" - - {1} - """.format(identifier, target)) - _close_xlf(out_file) - - -def main(): - """Parses arguments and iterates over files.""" - - # Set up argument parser. - parser = argparse.ArgumentParser(description='Convert JSON files to JS.') - parser.add_argument('--source_lang', default='en', - help='ISO 639-1 source language code') - parser.add_argument('--output_dir', default='generated', - help='relative directory for output files') - parser.add_argument('--key_file', default='json' + os.path.sep + 'keys.json', - help='relative path to input keys file') - parser.add_argument('--template', default='template.soy') - parser.add_argument('--path_to_jar', - default='..' + os.path.sep + 'apps' + os.path.sep - + '_soy', - help='relative path from working directory to ' - 'SoyToJsSrcCompiler.jar') - parser.add_argument('files', nargs='+', help='input files') - - # Initialize global variables. - global args - args = parser.parse_args() - - # Make sure output_dir ends with slash. - if (not args.output_dir.endswith(os.path.sep)): - args.output_dir += os.path.sep - - # Read in keys.json, mapping descriptions (e.g., Maze.turnLeft) to - # Closure keys (long hash numbers). - key_file = open(args.key_file) - key_dict = json.load(key_file) - key_file.close() - - # Process each input file. - print('Creating .xlf files...') - processed_langs = [] - if len(args.files) == 1: - # Windows does not expand globs automatically. - args.files = glob.glob(args.files[0]) - for arg_file in args.files: - (path_to_json, filename) = os.path.split(arg_file) - if not filename.endswith('.json'): - raise InputError(filename, 'filenames must end with ".json"') - target_lang = filename[:filename.index('.')] - if not target_lang in ('qqq', 'keys'): - processed_langs.append(target_lang) - _process_file(path_to_json, target_lang, key_dict) - - # Output command line for Closure compiler. - if processed_langs: - print('Creating .js files...') - processed_lang_list = ','.join(processed_langs) - subprocess.check_call([ - 'java', - '-jar', os.path.join(args.path_to_jar, 'SoyToJsSrcCompiler.jar'), - '--locales', processed_lang_list, - '--messageFilePathFormat', args.output_dir + '{LOCALE}.xlf', - '--outputPathFormat', args.output_dir + '{LOCALE}.js', - '--srcs', args.template]) - if len(processed_langs) == 1: - print('Created ' + processed_lang_list + '.js in ' + args.output_dir) - else: - print('Created {' + processed_lang_list + '}.js in ' + args.output_dir) - - for lang in processed_langs: - os.remove(args.output_dir + lang + '.xlf') - print('Removed .xlf files.') - - -if __name__ == '__main__': - main() diff --git a/i18n/xliff_to_json.py b/i18n/xliff_to_json.py deleted file mode 100755 index c95d83366f8..00000000000 --- a/i18n/xliff_to_json.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/python - -# Converts .xlf files into .json files for use at http://translatewiki.net. -# -# Copyright 2013 Google Inc. -# https://developers.google.com/blockly/ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import os -import re -import subprocess -import sys -from xml.dom import minidom -from common import InputError -from common import write_files - -# Global variables -args = None # Parsed command-line arguments. - - -def _parse_trans_unit(trans_unit): - """Converts a trans-unit XML node into a more convenient dictionary format. - - Args: - trans_unit: An XML representation of a .xlf translation unit. - - Returns: - A dictionary with useful information about the translation unit. - The returned dictionary is guaranteed to have an entry for 'key' and - may have entries for 'source', 'target', 'description', and 'meaning' - if present in the argument. - - Raises: - InputError: A required field was not present. - """ - - def get_value(tag_name): - elts = trans_unit.getElementsByTagName(tag_name) - if not elts: - return None - elif len(elts) == 1: - return ''.join([child.toxml() for child in elts[0].childNodes]) - else: - raise InputError('', 'Unable to extract ' + tag_name) - - result = {} - key = trans_unit.getAttribute('id') - if not key: - raise InputError('', 'id attribute not found') - result['key'] = key - - # Get source and target, if present. - try: - result['source'] = get_value('source') - result['target'] = get_value('target') - except InputError as e: - raise InputError(key, e.msg) - - # Get notes, using the from value as key and the data as value. - notes = trans_unit.getElementsByTagName('note') - for note in notes: - from_value = note.getAttribute('from') - if from_value and len(note.childNodes) == 1: - result[from_value] = note.childNodes[0].data - else: - raise InputError(key, 'Unable to extract ' + from_value) - - return result - - -def _process_file(filename): - """Builds list of translation units from input file. - - Each translation unit in the input file includes: - - an id (opaquely generated by Soy) - - the Blockly name for the message - - the text in the source language (generally English) - - a description for the translator - - The Soy and Blockly ids are joined with a hyphen and serve as the - keys in both output files. The value is the corresponding text (in the - .json file) or the description (in the qqq.json file). - - Args: - filename: The name of an .xlf file produced by Closure. - - Raises: - IOError: An I/O error occurred with an input or output file. - InputError: The input file could not be parsed or lacked required - fields. - - Returns: - A list of dictionaries produced by parse_trans_unit(). - """ - try: - results = [] # list of dictionaries (return value) - names = [] # list of names of encountered keys (local variable) - try: - parsed_xml = minidom.parse(filename) - except IOError: - # Don't get caught by below handler - raise - except Exception as e: - print() - raise InputError(filename, str(e)) - - # Make sure needed fields are present and non-empty. - for trans_unit in parsed_xml.getElementsByTagName('trans-unit'): - unit = _parse_trans_unit(trans_unit) - for key in ['description', 'meaning', 'source']: - if not key in unit or not unit[key]: - raise InputError(filename + ':' + unit['key'], - key + ' not found') - if unit['description'].lower() == 'ibid': - if unit['meaning'] not in names: - # If the term has not already been described, the use of 'ibid' - # is an error. - raise InputError( - filename, - 'First encountered definition of: ' + unit['meaning'] - + ' has definition: ' + unit['description'] - + '. This error can occur if the definition was not' - + ' provided on the first appearance of the message' - + ' or if the source (English-language) messages differ.') - else: - # If term has already been described, 'ibid' was used correctly, - # and we output nothing. - pass - else: - if unit['meaning'] in names: - raise InputError(filename, - 'Second definition of: ' + unit['meaning']) - names.append(unit['meaning']) - results.append(unit) - - return results - except IOError as e: - print('Error with file {0}: {1}'.format(filename, e.strerror)) - sys.exit(1) - - -def sort_units(units, templates): - """Sorts the translation units by their definition order in the template. - - Args: - units: A list of dictionaries produced by parse_trans_unit() - that have a non-empty value for the key 'meaning'. - templates: A string containing the Soy templates in which each of - the units' meanings is defined. - - Returns: - A new list of translation units, sorted by the order in which - their meaning is defined in the templates. - - Raises: - InputError: If a meaning definition cannot be found in the - templates. - """ - def key_function(unit): - match = re.search( - '\\smeaning\\s*=\\s*"{0}"\\s'.format(unit['meaning']), - templates) - if match: - return match.start() - else: - raise InputError(args.templates, - 'msg definition for meaning not found: ' + - unit['meaning']) - return sorted(units, key=key_function) - - -def main(): - """Parses arguments and processes the specified file. - - Raises: - IOError: An I/O error occurred with an input or output file. - InputError: Input files lacked required fields. - """ - # Set up argument parser. - parser = argparse.ArgumentParser(description='Create translation files.') - parser.add_argument( - '--author', - default='Ellen Spertus ', - help='name and email address of contact for translators') - parser.add_argument('--lang', default='en', - help='ISO 639-1 source language code') - parser.add_argument('--output_dir', default='json', - help='relative directory for output files') - parser.add_argument('--xlf', help='file containing xlf definitions') - parser.add_argument('--templates', default=['template.soy'], nargs='+', - help='relative path to Soy templates, comma or space ' - 'separated (used for ordering messages)') - global args - args = parser.parse_args() - - # Make sure output_dir ends with slash. - if (not args.output_dir.endswith(os.path.sep)): - args.output_dir += os.path.sep - - # Process the input file, and sort the entries. - units = _process_file(args.xlf) - files = [] - for arg in args.templates: - for filename in arg.split(','): - filename = filename.strip(); - if filename: - with open(filename) as myfile: - files.append(' '.join(line.strip() for line in myfile)) - sorted_units = sort_units(units, ' '.join(files)) - - # Write the output files. - write_files(args.author, args.lang, args.output_dir, sorted_units, True) - - # Delete the input .xlf file. - os.remove(args.xlf) - print('Removed ' + args.xlf) - - -if __name__ == '__main__': - main() From 79d75b9f3d9f624a64e49da8de8fab1b9da8e706 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 25 Apr 2019 18:21:42 -0700 Subject: [PATCH 031/233] Fixed buttons being rendered as labels if they come after a label. (#2410) --- core/flyout_base.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/flyout_base.js b/core/flyout_base.js index 41e0501ae33..ab77802f99a 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -480,10 +480,8 @@ Blockly.Flyout.prototype.show = function(xmlList) { } break; case 'LABEL': - // Labels behave the same as buttons, but are styled differently. - var isLabel = true; - // Falls through. case 'BUTTON': + var isLabel = xml.tagName.toUpperCase() == 'LABEL'; var curButton = new Blockly.FlyoutButton(this.workspace_, this.targetWorkspace_, xml, isLabel); contents.push({type: 'button', button: curButton}); From 247aafae7e07e9061d07f29388a5703c8c18d866 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 26 Apr 2019 07:39:16 -0700 Subject: [PATCH 032/233] Added updateColour to field. --- core/block.js | 41 +++++++++++++++++++++++ core/block_svg.js | 65 ++++++++++++++----------------------- core/field.js | 9 +++++ core/field_dropdown.js | 19 ++++++++--- tests/blocks/test_blocks.js | 14 ++++---- tests/playground.html | 34 ++++++++++++++++++- 6 files changed, 130 insertions(+), 52 deletions(-) diff --git a/core/block.js b/core/block.js index ffa17c75379..3df892d4792 100644 --- a/core/block.js +++ b/core/block.js @@ -41,6 +41,7 @@ goog.require('Blockly.Warning'); goog.require('Blockly.Workspace'); goog.require('goog.math.Coordinate'); +goog.require('goog.color'); /** @@ -881,6 +882,46 @@ Blockly.Block.prototype.getColourTertiary = function() { return this.colourTertiary_; }; +/** + * Get the shadow colour of a block. + * @return {?string} #RRGGBB string. + */ +Blockly.Block.prototype.getColourShadow = function() { + var colourSecondary = this.getColourSecondary(); + if (colourSecondary) { + return colourSecondary; + } + var rgb = goog.color.hexToRgb(this.getColour()); + rgb = goog.color.lighten(rgb, 0.6); + return goog.color.rgbArrayToHex(rgb); +}; + +/** + * Get the border colour(s) of a block. + * @return {{colourDark, colourLight, colourBorder}} An object containing + * colour values for the border(s) of the block. If the block is using a + * style the colourBorder will be defined and equal to the tertiary colour + * of the style (#RRGGBB string). Otherwise the colourDark and colourLight + * attributes will be defined (#RRGGBB strings). + * @package + */ +Blockly.Block.prototype.getColourBorder = function() { + var colourTertiary = this.getColourTertiary(); + if (colourTertiary) { + return { + colourBorder: colourTertiary, + colourLight: null, + colourDark: null + }; + } + var rgb = goog.color.hexToRgb(this.getColour()); + return { + colourBorder: null, + colourLight: goog.color.rgbArrayToHex(goog.color.lighten(rgb, 0.3)), + colourDark: goog.color.rgbArrayToHex(goog.color.darken(rgb, 0.2)) + }; +}; + /** * Get the name of the block style. * @return {?string} Name of the block style. diff --git a/core/block_svg.js b/core/block_svg.js index a997d18846d..ea5b51aa7b1 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -941,74 +941,59 @@ Blockly.BlockSvg.prototype.updateColour = function() { // Disabled blocks don't have colour. return; } - var hexColour = this.getColour(); - var colourSecondary = this.getColourSecondary(); - var colourTertiary = this.getColourTertiary(); - var rgb = goog.color.hexToRgb(hexColour); if (this.isShadow()) { - hexColour = this.setShadowColour_(rgb, colourSecondary); + this.setShadowColour_(); } else { - this.setBorderColour_(rgb, colourTertiary); + this.setBorderColour_(); + this.svgPath_.setAttribute('fill', this.getColour()); } - this.svgPath_.setAttribute('fill', hexColour); var icons = this.getIcons(); for (var i = 0; i < icons.length; i++) { icons[i].updateColour(); } - // Bump every dropdown to change its colour. - // TODO (#1456) for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { - field.forceRerender(); + field.updateColour(); } } }; /** * Sets the colour of the border. - * Removes the light and dark paths if a tertiary colour is defined. - * @param {!string} rgb Colour of the block. - * @param {?string} colourTertiary Colour of the border. - */ -Blockly.BlockSvg.prototype.setBorderColour_ = function(rgb, colourTertiary) { - if (colourTertiary) { - this.svgPathLight_.setAttribute('stroke', 'none'); - this.svgPathDark_.setAttribute('fill', 'none'); - this.svgPath_.setAttribute('stroke', colourTertiary); + * Removes the light and dark paths if a border colour is defined. + */ +Blockly.BlockSvg.prototype.setBorderColour_ = function() { + var borderColours = this.getColourBorder(); + if (borderColours.colourBorder) { + this.svgPathLight_.style.display = 'none'; + this.svgPathDark_.style.display = 'none'; + + this.svgPath_.setAttribute('stroke', borderColours.colourBorder); } else { this.svgPathLight_.style.display = ''; - var hexLight = goog.color.rgbArrayToHex(goog.color.lighten(rgb, 0.3)); - var hexDark = goog.color.rgbArrayToHex(goog.color.darken(rgb, 0.2)); - this.svgPathLight_.setAttribute('stroke', hexLight); - this.svgPathDark_.setAttribute('fill', hexDark); + this.svgPathDark_.style.display = ''; this.svgPath_.setAttribute('stroke', 'none'); + this.svgPathLight_.setAttribute('stroke', borderColours.colourLight); + this.svgPathDark_.setAttribute('fill', borderColours.colourDark); } }; /** * Sets the colour of shadow blocks. - * @param {!string} rgb Primary colour of the block. - * @param {?string} colourSecondary Colour for shadow block. - * @return {!string} The background colour of the block. + * @return {?string} The background colour of the block. */ -Blockly.BlockSvg.prototype.setShadowColour_ = function(rgb, colourSecondary) { - var hexColour; - if (colourSecondary) { - this.svgPathLight_.style.display = 'none'; - this.svgPathDark_.style.display = 'none'; - this.svgPath_.setAttribute('fill', colourSecondary); - hexColour = colourSecondary; - } else { - rgb = goog.color.lighten(rgb, 0.6); - hexColour = goog.color.rgbArrayToHex(rgb); - this.svgPathLight_.style.display = 'none'; - this.svgPathDark_.setAttribute('fill', hexColour); - } - return hexColour; +Blockly.BlockSvg.prototype.setShadowColour_ = function() { + this.svgPathLight_.style.display = 'none'; + this.svgPathDark_.style.display = 'none'; + this.svgPath_.setAttribute('stroke', 'none'); + + var shadowColour = this.getColourShadow(); + this.svgPath_.setAttribute('fill', shadowColour); + return shadowColour; }; /** diff --git a/core/field.js b/core/field.js index 8df264e6ac3..63bed078700 100644 --- a/core/field.js +++ b/core/field.js @@ -431,6 +431,15 @@ Blockly.Field.prototype.getSvgRoot = function() { return /** @type {!Element} */ (this.fieldGroup_); }; +/** + * Updates the field to match the colour/style of the block. Should only be + * called by BlockSvg.updateColour(). + * @package + */ +Blockly.Field.prototype.updateColour = function() { + // Non-abstract sub-classes may wish to implement this. See FieldDropdown. +}; + /** * Draws the border with the correct width. * Saves the computed width in a property. diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 0aadc0306ea..e6c6f267e81 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -432,15 +432,26 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) { this.forceRerender(); }; +/** + * Updates the dropdown arrow to match the colour/style of the block. + * @package + */ +Blockly.FieldDropdown.prototype.updateColour = function() { + // Update arrow's colour. + if (this.sourceBlock_ && this.arrow_) { + if (this.sourceBlock_.isShadow()) { + this.arrow_.style.fill = this.sourceBlock_.getColourShadow(); + } else { + this.arrow_.style.fill = this.sourceBlock_.getColour(); + } + } +}; + /** * Draws the border with the correct width. * @private */ Blockly.FieldDropdown.prototype.render_ = function() { - if (this.sourceBlock_ && this.arrow_) { - // Update arrow's colour. - this.arrow_.style.fill = this.sourceBlock_.getColour(); - } var child; while ((child = this.textElement_.firstChild)) { this.textElement_.removeChild(child); diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index fb9da04df21..1d5b47b0f54 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -174,7 +174,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT } } ], - "colour": "230" + "style": "math_blocks", }, { "type": "test_fields_date", @@ -191,7 +191,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT } } ], - "colour": 230 + "style": "math_blocks", }, { "type": "test_fields_text_input", @@ -203,7 +203,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "text": "default" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -217,7 +217,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "checked": true } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -231,7 +231,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "colour": "#ff0000" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -245,7 +245,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "variable": "item" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, @@ -259,7 +259,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "text": "default" } ], - "colour": 230, + "style": "math_blocks", "tooltip": "", "helpUrl": "" }, diff --git a/tests/playground.html b/tests/playground.html index 2c7deeb1163..a46d88164eb 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -156,9 +156,36 @@ block.setFieldValue(text, 'LABEL'); } }; + var setRandomStyle = function(button) { + var blocks = button.workspace_.getAllBlocks(); + var styles = Object.keys(Blockly.getTheme().getAllBlockStyles()); + styles.splice(styles.indexOf(blocks[0].getStyleName()), 1); + var style = styles[Math.floor(Math.random() * styles.length)]; + for(var i = 0, block; block = blocks[i]; i++) { + block.setStyle(style); + } + }; + var toggleEnabled = function(button) { + var blocks = button.workspace_.getAllBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + block.setEnabled(!block.isEnabled()); + } + }; + var toggleShadow = function(button) { + var blocks = button.workspace_.getAllBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + block.setShadow(!block.isShadow()); + } + }; workspace.registerButtonCallback( - 'randomizeLabelText', randomizeLabelText); + 'setRandomStyle', setRandomStyle); + workspace.registerButtonCallback( + 'toggleEnabled', toggleEnabled); + workspace.registerButtonCallback( + 'toggleShadow', toggleShadow); + workspace.registerButtonCallback( + 'randomizeLabelText', randomizeLabelText); workspace.registerButtonCallback( 'addDynamicOption', Blockly.TestBlocks.addDynamicDropdownOption_); workspace.registerButtonCallback( @@ -1209,6 +1236,11 @@

Blockly Playground

+ + + + + From 8d4a73e33dd2b9bba3a77a84f1cdb9ad43160e03 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 29 Apr 2019 15:00:30 -0700 Subject: [PATCH 033/233] =?UTF-8?q?Strip=20MIT=E2=80=99s=20licence=20out?= =?UTF-8?q?=20of=20compiled=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Matches existing stripping of Google’s licence. Done with MIT’s permission. Resolves issue 2412. --- blockly_compressed.js | 20 +------------------- build.py | 9 +++++---- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/blockly_compressed.js b/blockly_compressed.js index 490ad1d25b4..dc8f48c0b3f 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -1581,25 +1581,7 @@ Blockly.BlockSvg.prototype.renderDummyInput_=function(a,b,c,d,e){var f=a.steps;a Blockly.BlockSvg.prototype.renderStatementInput_=function(a,b,c,d,e,f){var g=a.steps;a=a.highlightSteps;var h=b[0];0==f&&(g.push("v",Blockly.BlockSvg.SEP_SPACE_Y),this.RTL&&a.push("v",Blockly.BlockSvg.SEP_SPACE_Y-1),c.y+=Blockly.BlockSvg.SEP_SPACE_Y);var k=c.x,l=c.y;if(h.align!=Blockly.ALIGN_LEFT){var n=e.statementEdge-h.fieldWidth-2*Blockly.BlockSvg.SEP_SPACE_X;h.align==Blockly.ALIGN_RIGHT?k+=n:h.align==Blockly.ALIGN_CENTRE&&(k+=n/2)}this.renderFields_(h.fieldRow,k,l);c.x=e.statementEdge+Blockly.BlockSvg.NOTCH_WIDTH; g.push("H",c.x);g.push(Blockly.BlockSvg.INNER_TOP_LEFT_CORNER);g.push("v",b.height-2*Blockly.BlockSvg.CORNER_RADIUS);g.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER);g.push("H",e.rightEdge);this.RTL?(a.push("M",c.x-Blockly.BlockSvg.NOTCH_WIDTH+Blockly.BlockSvg.DISTANCE_45_OUTSIDE+","+(c.y+Blockly.BlockSvg.DISTANCE_45_OUTSIDE)),a.push(Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL),a.push("v",b.height-2*Blockly.BlockSvg.CORNER_RADIUS),a.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL)): (a.push("M",c.x-Blockly.BlockSvg.NOTCH_WIDTH+Blockly.BlockSvg.DISTANCE_45_OUTSIDE+","+(c.y+b.height-Blockly.BlockSvg.DISTANCE_45_OUTSIDE)),a.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_LTR));a.push("H",e.rightEdge-.5);d.x=this.RTL?-c.x:c.x+1;h.connection.setOffsetInBlock(d.x,c.y+1);h.connection.isConnected()&&(this.width=Math.max(this.width,e.statementEdge+h.connection.targetBlock().getHeightWidth().width));if(f==e.length-1||e[f+1].type==Blockly.NEXT_STATEMENT)g.push("v",Blockly.BlockSvg.SEP_SPACE_Y), -this.RTL&&a.push("v",Blockly.BlockSvg.SEP_SPACE_Y-1),c.y+=Blockly.BlockSvg.SEP_SPACE_Y};Blockly.BlockSvg.prototype.positionNewBlock=function(a,b,c){b.type!=Blockly.NEXT_STATEMENT&&b.type!=Blockly.INPUT_VALUE||a.moveBy(c.x_-b.x_,c.y_-b.y_)};Blockly.BlockSvg.prototype.highlightForReplacement=function(a){a?Blockly.utils.addClass(this.svgGroup_,"blocklyReplaceable"):Blockly.utils.removeClass(this.svgGroup_,"blocklyReplaceable")};/* - - Visual Blocks Editor - - Copyright 2016 Massachusetts Institute of Technology - All rights reserved. - - 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. -*/ +this.RTL&&a.push("v",Blockly.BlockSvg.SEP_SPACE_Y-1),c.y+=Blockly.BlockSvg.SEP_SPACE_Y};Blockly.BlockSvg.prototype.positionNewBlock=function(a,b,c){b.type!=Blockly.NEXT_STATEMENT&&b.type!=Blockly.INPUT_VALUE||a.moveBy(c.x_-b.x_,c.y_-b.y_)};Blockly.BlockSvg.prototype.highlightForReplacement=function(a){a?Blockly.utils.addClass(this.svgGroup_,"blocklyReplaceable"):Blockly.utils.removeClass(this.svgGroup_,"blocklyReplaceable")}; Blockly.DropDownDiv=function(){};Blockly.DropDownDiv.DIV_=null;Blockly.DropDownDiv.boundsElement_=null;Blockly.DropDownDiv.owner_=null;Blockly.DropDownDiv.positionToField_=null;Blockly.DropDownDiv.ARROW_SIZE=16;Blockly.DropDownDiv.BORDER_SIZE=1;Blockly.DropDownDiv.ARROW_HORIZONTAL_PADDING=12;Blockly.DropDownDiv.PADDING_Y=16;Blockly.DropDownDiv.ANIMATION_TIME=.25;Blockly.DropDownDiv.animateOutTimer_=null;Blockly.DropDownDiv.onHide_=0; Blockly.DropDownDiv.createDom=function(){if(!Blockly.DropDownDiv.DIV_){var a=document.createElement("div");a.className="blocklyDropDownDiv";document.body.appendChild(a);Blockly.DropDownDiv.DIV_=a;var b=document.createElement("div");b.className="blocklyDropDownContent";a.appendChild(b);Blockly.DropDownDiv.content_=b;b=document.createElement("div");b.className="blocklyDropDownArrow";a.appendChild(b);Blockly.DropDownDiv.arrow_=b;Blockly.DropDownDiv.DIV_.style.transition="transform "+Blockly.DropDownDiv.ANIMATION_TIME+ "s, opacity "+Blockly.DropDownDiv.ANIMATION_TIME+"s"}};Blockly.DropDownDiv.setBoundsElement=function(a){Blockly.DropDownDiv.boundsElement_=a};Blockly.DropDownDiv.getContentDiv=function(){return Blockly.DropDownDiv.content_};Blockly.DropDownDiv.clearContent=function(){Blockly.DropDownDiv.content_.innerHTML="";Blockly.DropDownDiv.content_.style.width=""};Blockly.DropDownDiv.setColour=function(a,b){Blockly.DropDownDiv.DIV_.style.backgroundColor=a;Blockly.DropDownDiv.DIV_.style.borderColor=b}; diff --git a/build.py b/build.py index 1566ae3f0df..2455bb74e9d 100755 --- a/build.py +++ b/build.py @@ -391,14 +391,15 @@ def file_lookup(name): code = HEADER + "\n" + json_data["compiledCode"] code = code.replace(remove, "") - # Trim down Google's (and only Google's) Apache licences. - # The Closure Compiler preserves these. + # The Closure Compiler preserves licences. + # Trim out Google's and MIT's (and nobody else's) Apache licences. + # MIT's permission to do this is logged in Blockly issue 2412. LICENSE = re.compile("""/\\* [\w ]+ - Copyright \\d+ Google Inc. - https://developers.google.com/blockly/ + Copyright \\d+ (Google Inc.|Massachusetts Institute of Technology) + (https://developers.google.com/blockly/|All rights reserved.) Licensed under the Apache License, Version 2.0 \(the "License"\); you may not use this file except in compliance with the License. From da2a89e177c549263bdf06e9f29aea6789062a81 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 30 Apr 2019 14:38:33 -0700 Subject: [PATCH 034/233] Update to webdriverio v5; fix resulting test breakages --- package.json | 2 +- tests/generators/run_generators_in_browser.js | 140 +++++++----------- tests/jsunit/run_jsunit_tests_in_browser.js | 100 +++++-------- tests/scripts/get_geckdriver.sh | 4 +- 4 files changed, 93 insertions(+), 153 deletions(-) diff --git a/package.json b/package.json index 3f5d710c0e4..dc62e77d19f 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "gulp-series": "^1.0.2", "gulp-shell": "^0.6.5", "jshint": "^2.10.1", - "webdriverio": "^4.14.1" + "webdriverio": "^5.8.0" }, "jshintConfig": { "globalstrict": true, diff --git a/tests/generators/run_generators_in_browser.js b/tests/generators/run_generators_in_browser.js index 4983b3e6210..1a39c6d1227 100644 --- a/tests/generators/run_generators_in_browser.js +++ b/tests/generators/run_generators_in_browser.js @@ -24,6 +24,8 @@ var webdriverio = require('webdriverio'); var fs = require('fs'); +module.exports = runGeneratorsInBrowser; + /** * Run the generator for a given language and save the results to a file. * @param {Thenable} browser A Thenable managing the processing of the browser @@ -31,23 +33,16 @@ var fs = require('fs'); * @param {string} filename Where to write the output file. * @param {Function} codegenFn The function to run for code generation for this * language. - * @return the Thenable managing the processing of the browser tests. */ -function runLangGeneratorInBrowser(browser, filename, codegenFn) { - return browser - .pause(5000) - .then(function() { - this.execute(codegenFn) - }) - .pause(10000) - .getValue("#importExport") - .then(function(result) { - fs.writeFile(filename, result, function(err) { - if (err) { - return console.log(err); - } - }); - }); +async function runLangGeneratorInBrowser(browser, filename, codegenFn) { + await browser.execute(codegenFn); + var elem = await browser.$("#importExport"); + var result = await elem.getValue(); + fs.writeFile(filename, result, function(err) { + if (err) { + return console.log(err); + } + }); } /** @@ -56,90 +51,61 @@ function runLangGeneratorInBrowser(browser, filename, codegenFn) { * to the console and outputs files for later validation. * @return the Thenable managing the processing of the browser tests. */ -function runGeneratorsInBrowser() { +async function runGeneratorsInBrowser() { var options = { - desiredCapabilities: { + capabilities: { browserName: 'firefox' } }; var url = 'file://' + __dirname + '/index.html'; - var prefix = 'tests/generators/tmp/generated' + var prefix = 'tests/generators/tmp/generated'; + console.log('Starting webdriverio...'); - return webdriverio - .remote(options) - .init() - .then(function() { - console.log('Initialized.\nLoading url: ' + url); - }) - .url(url) - .then(function() { - console.log('about to load'); - this.execute(function() { - checkAll(); - loadSelected(); - }) - }) - .pause(10000) - .then(function() { - return runLangGeneratorInBrowser(this, prefix + '.js', function() { - toJavaScript(); - }); - }) - .then(function() { - return runLangGeneratorInBrowser(this, prefix + '.py', function() { - toPython(); - }); - }) - .then(function() { - return runLangGeneratorInBrowser(this, prefix + '.dart', function() { - toDart(); - }); - }) - .then(function() { - return runLangGeneratorInBrowser(this, prefix + '.lua', function() { - toLua(); - }); - }) - .then(function() { - return runLangGeneratorInBrowser(this, prefix + '.php', function() { - toPhp(); - }); - }) - .pause(10000) - .catch(function(e) { - console.error('Error: ', e); + const browser = await webdriverio.remote(options); + console.log('Initialized.\nLoading url: ' + url); + await browser.url(url); - if (require.main === module) { - // .catch() doesn't seem to work in the calling code, - // even if the error is rethrown. To ensure the script - // exit code is non-zero, shutdown the process here. - process.exit(1); - } + await browser.execute(function() { + checkAll(); + loadSelected(); + }); - // WARNING: Catching this outside of runJsUnitTestsInBrowser() is not - // working. However, killing the process doesn't seem good, either. - throw e; + await runLangGeneratorInBrowser(browser, prefix + '.js', + function() { + toJavaScript(); + }); + await runLangGeneratorInBrowser(browser, prefix + '.py', + function() { + toPython(); + }); + await runLangGeneratorInBrowser(browser, prefix + '.dart', + function() { + toDart(); + }); + await runLangGeneratorInBrowser(browser, prefix + '.lua', + function() { + toLua(); + }); + await runLangGeneratorInBrowser(browser, prefix + '.php', + function() { + toPhp(); }); -} -module.exports = runGeneratorsInBrowser; + await browser.deleteSession(); +} if (require.main === module) { - try { - runGeneratorsInBrowser() - .catch(function(e) { - // TODO: Never called during errors. Fix. - console.error('Error: ' + e); + runGeneratorsInBrowser().catch(e => { + console.error(e); + process.exit(1); + }).then(function(result) { + if (result) { + console.log('Generator tests failed'); process.exit(1); - }) - .endAll() - .then(function() { - console.log('JSUnit tests completed'); + } else { + console.log('Generator tests passed'); process.exit(0); - }); - } catch(e) { - console.error('Uncaught error: ', e); - process.exit(1); - } + } + }); } diff --git a/tests/jsunit/run_jsunit_tests_in_browser.js b/tests/jsunit/run_jsunit_tests_in_browser.js index 2764dc237d0..e75a357dd0c 100644 --- a/tests/jsunit/run_jsunit_tests_in_browser.js +++ b/tests/jsunit/run_jsunit_tests_in_browser.js @@ -23,86 +23,60 @@ */ var webdriverio = require('webdriverio'); +module.exports = runJsUnitTestsInBrowser; + /** * Runs the JsUnit tests in this directory in Chrome. It uses webdriverio to * launch Chrome and load index.html. Outputs a summary of the test results * to the console. - * @return the Thenable managing the processing of the browser tests. + * @return 0 on success, 1 on failure. */ -function runJsUnitTestsInBrowser() { +async function runJsUnitTestsInBrowser() { var options = { - desiredCapabilities: { + capabilities: { browserName: 'chrome' } }; var url = 'file://' + __dirname + '/index.html'; console.log('Starting webdriverio...'); - return webdriverio - .remote(options) - .init() - .then(function() { - console.log('Initialized.\nLoading url: ' + url); - }) - .url(url) - .then(function() { - console.log('Loaded.\nPausing to allow processing.'); - }) - .pause(5000) //TODO: change pause to waitunitl - .then(function() { - console.log('Retrieving results...'); - }) - .getHTML('#closureTestRunnerLog') - .then(function(result) { - // call js to parse html - var regex = /[\d]+\spassed,\s([\d]+)\sfailed./i; - var numOfFailure = regex.exec(result)[1]; - var regex2 = /Unit Tests for Blockly .*]/; - var testStatus = regex2.exec(result)[0]; - console.log('============Blockly Unit Test Summary================='); - console.log(testStatus); - var regex3 = /\d+ passed,\s\d+ failed/; - var detail = regex3.exec(result)[0]; - console.log(detail); - console.log('============Blockly Unit Test Summary================='); - if (parseInt(numOfFailure) !== 0) { - console.log(result); - process.exit(1); - } - }) - .catch(function(e) { - console.error('Error: ', e); + const browser = await webdriverio.remote(options); + console.log('Initialized.\nLoading url: ' + url); + await browser.url(url); - if (require.main === module) { - // .catch() doesn't seem to work in the calling code, - // even if the error is rethrown. To ensure the script - // exit code is non-zero, shutdown the process here. - process.exit(1); - } + const elem = await browser.$('#closureTestRunnerLog') + const result = await elem.getHTML(); - // WARNING: Catching this outside of runJsUnitTestsInBrowser() is not - // working. However, killing the process doesn't seem good, either. - throw e; - }); + // call js to parse html + var regex = /[\d]+\spassed,\s([\d]+)\sfailed./i; + var numOfFailure = regex.exec(result)[1]; + var regex2 = /Unit Tests for Blockly .*]/; + var testStatus = regex2.exec(result)[0]; + console.log('============Blockly Unit Test Summary================='); + console.log(testStatus); + var regex3 = /\d+ passed,\s\d+ failed/; + var detail = regex3.exec(result)[0]; + console.log(detail); + console.log('============Blockly Unit Test Summary================='); + if (parseInt(numOfFailure) !== 0) { + await browser.deleteSession(); + return 1; + } + await browser.deleteSession(); + return 0; } -module.exports = runJsUnitTestsInBrowser; - if (require.main === module) { - try { - runJsUnitTestsInBrowser() - .catch(function(e) { - // TODO: Never called during errors. Fix. - console.error('Error: ' + e); + runJsUnitTestsInBrowser().catch(e => { + console.error(e); + process.exit(1); + }).then(function(result) { + if (result) { + console.log('JSUnit tests failed'); process.exit(1); - }) - .endAll() - .then(function() { - console.log('JSUnit tests completed'); + } else { + console.log('JSUnit tests passed'); process.exit(0); - }); - } catch(e) { - console.error('Uncaught error: ', e); - process.exit(1); - } + } + }); } diff --git a/tests/scripts/get_geckdriver.sh b/tests/scripts/get_geckdriver.sh index 77fecd4ec82..60743841bf7 100755 --- a/tests/scripts/get_geckdriver.sh +++ b/tests/scripts/get_geckdriver.sh @@ -7,9 +7,9 @@ fi echo "downloading gechdriver" if [[ $os_name == 'Linux' ]]; then - cd ../ && curl -L https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-linux64.tar.gz | tar xz + cd ../ && curl -L https://github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-linux64.tar.gz | tar xz sleep 5 elif [[ $os_name == 'Darwin' ]]; then - cd ../ && curl -L https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-macos.tar.gz | tar xz + cd ../ && curl -L https://github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-macos.tar.gz | tar xz sleep 5 fi From 00f84bb5952dbaba1a18a4bd1d8446e09e0204fb Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 1 May 2019 10:50:14 -0700 Subject: [PATCH 035/233] Add firefox addon explicitly --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 53320fd0c00..a0707ec2003 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ node_js: - 10 sudo: required addons: + firefox: latest apt: packages: - google-chrome-stable From e77efa6c13276ac7c8dc9f303d58711eb7054d4a Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 1 May 2019 13:43:19 -0700 Subject: [PATCH 036/233] Add mocha tests + parsing to npm test --- .eslintignore | 1 + tests/mocha/index.html | 6 +- tests/mocha/run_mocha_tests_in_browser.js | 81 +++++++++++++++++++++++ tests/run_all_tests.sh | 4 +- 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/mocha/run_mocha_tests_in_browser.js diff --git a/.eslintignore b/.eslintignore index 0d60b8df106..0022114ea33 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,6 +8,7 @@ gulpfile.js /tests/compile/* /tests/jsunit/* /tests/generators/* +/tests/mocha/run_mocha_tests_in_browser.js /tests/test_runner.js /tests/workspace_svg/* /generators/* diff --git a/tests/mocha/index.html b/tests/mocha/index.html index b177d8cfa6e..f6564786548 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -10,6 +10,7 @@
+ @@ -34,7 +35,10 @@ diff --git a/tests/mocha/run_mocha_tests_in_browser.js b/tests/mocha/run_mocha_tests_in_browser.js new file mode 100644 index 00000000000..72b521505c7 --- /dev/null +++ b/tests/mocha/run_mocha_tests_in_browser.js @@ -0,0 +1,81 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2018 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Node.js script to run JsUnit tests in Chrome, via webdriver. + */ +var webdriverio = require('webdriverio'); + +module.exports = runMochaTestsInBrowser; + +/** + * Runs the Mocha tests in this directory in Chrome. It uses webdriverio to + * launch Chrome and load index.html. Outputs a summary of the test results + * to the console. + * @return 0 on success, 1 on failure. + */ +async function runMochaTestsInBrowser() { + var options = { + capabilities: { + browserName: 'chrome' + } + }; + + var url = 'file://' + __dirname + '/index.html'; + console.log('Starting webdriverio...'); + const browser = await webdriverio.remote(options); + console.log('Initialized.\nLoading url: ' + url); + await browser.url(url); + + await browser.waitUntil(async () => { + var elem = await browser.$('#failureCount'); + var text = await elem.getAttribute('tests_failed'); + return text != 'unset'; + }) + + const elem = await browser.$('#failureCount') + const numOfFailure = await elem.getAttribute('tests_failed'); + + console.log('============Blockly Mocha Test Summary================='); + console.log(numOfFailure); + console.log(numOfFailure + ' tests failed'); + console.log('============Blockly Mocha Test Summary================='); + if (parseInt(numOfFailure) !== 0) { + await browser.deleteSession(); + return 1; + } + await browser.deleteSession(); + return 0; +} + +if (require.main === module) { + runMochaTestsInBrowser().catch(e => { + console.error(e); + process.exit(1); + }).then(function(result) { + if (result) { + console.log('Mocha tests failed'); + process.exit(1); + } else { + console.log('Mocha tests passed'); + process.exit(0); + } + }); +} diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index f63646fb69d..f0d4695d749 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -57,7 +57,9 @@ run_test_command "eslint" "eslint ." # Run JSUnit tests inside a browser. run_test_command "jsunit" "node tests/jsunit/run_jsunit_tests_in_browser.js" -# TODO: Make sure jsunit output is captured. Child process? + +# Run Mocha tests inside a browser. +run_test_command "mocha" "node tests/mocha/run_mocha_tests_in_browser.js" # Run generator tests inside a browser and check the results. run_test_command "generators" "tests/scripts/run_generators.sh" From 99dc9bb38f3f6e3f01735555a98d519315bac257 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 1 May 2019 14:19:55 -0700 Subject: [PATCH 037/233] Fix test (matching fix in jsunit tests) --- tests/mocha/block_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index 5613d40ec82..82ea9049007 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -105,7 +105,7 @@ suite('Blocks', function() { // Add extra input to middle block blocks.B.appendValueInput("INPUT").setCheck(null); blocks.B.unplug(true); - assertUnpluggedNoheal(blocks); + assertUnpluggedHealed(blocks); }); test('Child block has multiple inputs', function() { From 3afcd2353556f480c977e0996d0897ec36757d84 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Apr 2019 16:10:25 -0700 Subject: [PATCH 038/233] Removed explicitly setting variable type to two single quotes. --- core/variables.js | 3 - tests/mocha/xml_test.js | 132 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/core/variables.js b/core/variables.js index cec5132fe39..4b7e0669e76 100644 --- a/core/variables.js +++ b/core/variables.js @@ -466,9 +466,6 @@ Blockly.Variables.generateVariableFieldXmlString = function(variableModel) { // The variable name may be user input, so it may contain characters that // need to be escaped to create valid XML. var typeString = variableModel.type; - if (typeString == '') { - typeString = '\'\''; - } var text = '' + goog.string.htmlEscape(variableModel.name) + ''; diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index f0801c625c5..82bd0c73c1a 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -287,6 +287,138 @@ suite('XML', function() { }); }); suite('Deserialization', function() { + suite('Dynamic Category Blocks', function() { + test('Untyped Variables', function() { + Blockly.defineBlocksWithJsonArray([{ + "type": "variables_get", + "message0": "%1", + "args0": [ + { + "type": "field_variable", + "name": "VAR", + } + ] + }, + { + "type": "variables_set", + "message0": "%1 %2", + "args0": [ + { + "type": "field_variable", + "name": "VAR" + }, + { + "type": "input_value", + "name": "VALUE" + } + ] + }, + { + "type": "math_change", + "message0": "%1 %2", + "args0": [ + { + "type": "field_variable", + "name": "VAR", + }, + { + "type": "input_value", + "name": "DELTA", + "check": "Number" + } + ] + }, + { + "type": "math_number", + "message0": "%1", + "args0": [{ + "type": "field_number", + "name": "NUM", + "value": 0 + }], + "output": "Number" + }]); + + this.workspace.createVariable('name1', '', 'id1'); + var blocksArray = Blockly.Variables.flyoutCategoryBlocks(this.workspace); + try { + for (var i = 0, xml; xml = blocksArray[i]; i++) { + Blockly.Xml.domToBlock(xml, this.workspace); + } + } finally { + delete Blockly.Blocks['variables_get']; + delete Blockly.Blocks['variables_set']; + delete Blockly.Blocks['math_change']; + delete Blockly.Blocks['math_number']; + } + }); + test('Typed Variables', function() { + Blockly.defineBlocksWithJsonArray([{ + "type": "variables_get", + "message0": "%1", + "args0": [ + { + "type": "field_variable", + "name": "VAR", + } + ] + }, + { + "type": "variables_set", + "message0": "%1 %2", + "args0": [ + { + "type": "field_variable", + "name": "VAR" + }, + { + "type": "input_value", + "name": "VALUE" + } + ] + }, + { + "type": "math_change", + "message0": "%1 %2", + "args0": [ + { + "type": "field_variable", + "name": "VAR", + }, + { + "type": "input_value", + "name": "DELTA", + "check": "Number" + } + ] + }, + { + "type": "math_number", + "message0": "%1", + "args0": [{ + "type": "field_number", + "name": "NUM", + "value": 0 + }], + "output": "Number" + }]); + this.workspace.createVariable('name1', 'String', 'id1'); + this.workspace.createVariable('name2', 'Number', 'id2'); + this.workspace.createVariable('name3', 'Colour', 'id3'); + var blocksArray = Blockly.VariablesDynamic + .flyoutCategoryBlocks(this.workspace); + try { + for (var i = 0, xml; xml = blocksArray[i]; i++) { + Blockly.Xml.domToBlock(xml, this.workspace); + } + } finally { + delete Blockly.Blocks['variables_get']; + delete Blockly.Blocks['variables_set']; + delete Blockly.Blocks['math_change']; + delete Blockly.Blocks['math_number']; + } + }); + }); }); }); From e06916e5e3b02845219a166db6dd246cda350d3b Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 1 May 2019 21:07:25 -0700 Subject: [PATCH 039/233] Factor out licence stripping Matches code in Blockly Games. No functional change. --- build.py | 59 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/build.py b/build.py index 2455bb74e9d..c62c2cb5cb8 100755 --- a/build.py +++ b/build.py @@ -390,30 +390,7 @@ def file_lookup(name): code = HEADER + "\n" + json_data["compiledCode"] code = code.replace(remove, "") - - # The Closure Compiler preserves licences. - # Trim out Google's and MIT's (and nobody else's) Apache licences. - # MIT's permission to do this is logged in Blockly issue 2412. - LICENSE = re.compile("""/\\* - - [\w ]+ - - Copyright \\d+ (Google Inc.|Massachusetts Institute of Technology) - (https://developers.google.com/blockly/|All rights reserved.) - - 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. -\\*/""") - code = re.sub(LICENSE, "", code) + code = self.trim_licence(code) stats = json_data["statistics"] original_b = stats["originalSize"] @@ -432,6 +409,40 @@ def file_lookup(name): 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("""/\\* + + [\\w: ]+ + + (Copyright \\d+ (Google Inc.|Massachusetts Institute of Technology)) + (https://developers.google.com/blockly/|All rights reserved.) + + 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. +\\*/""") + return re.sub(apache2, "", code) + class Gen_langfiles(threading.Thread): """Generate JavaScript file for each natural language supported. From 6f433d75219b8c3e9ddb1cee81bfec26e6d16595 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 1 May 2019 21:12:38 -0700 Subject: [PATCH 040/233] =?UTF-8?q?Don=E2=80=99t=20preserve=20IDs=20during?= =?UTF-8?q?=20cut/copy/paste=20or=20flyout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, if the XML of a toolbox contained a block ID, the first creation of this block would inherit this ID. Thus two realtime collaborators could realistically end up with conflict. Likewise, cut and paste could generate similar conflict. --- core/blockly.js | 2 +- core/flyout_base.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/blockly.js b/core/blockly.js index ca1dcb83f69..562af5f2988 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -281,7 +281,7 @@ Blockly.copy_ = function(toCopy) { if (toCopy.isComment) { var xml = toCopy.toXmlWithXY(); } else { - var xml = Blockly.Xml.blockToDom(toCopy); + var xml = Blockly.Xml.blockToDom(toCopy, true); // Copy only the selected block and internal blocks. Blockly.Xml.deleteNext(xml); // Encode start position in XML. diff --git a/core/flyout_base.js b/core/flyout_base.js index ab77802f99a..61ffed7cb17 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -794,7 +794,7 @@ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) { } // Create the new block by cloning the block in the flyout (via XML). - var xml = Blockly.Xml.blockToDom(oldBlock); + var xml = Blockly.Xml.blockToDom(oldBlock, true); // The target workspace would normally resize during domToBlock, which will // lead to weird jumps. Save it for terminateDrag. targetWorkspace.setResizesEnabled(false); From 834fa6467478ee96a9bfe2ab93c39d57ab5dfd60 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 1 May 2019 21:18:19 -0700 Subject: [PATCH 041/233] =?UTF-8?q?Use=20Element=20constants=20and=20?= =?UTF-8?q?=E2=80=98i=E2=80=99=20variable.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don’t care about whether we use the Element constants or the ubiquitously known 1 & 3 integers. But we had a mix. Also, ’x’ is usually used for horizontal location, ‘i’ is an iterator. No functional change. --- core/block_render_svg.js | 2 +- core/flyout_base.js | 2 +- core/generator.js | 2 +- core/xml.js | 11 ++++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/block_render_svg.js b/core/block_render_svg.js index 0b8998104c0..d8753a18fb0 100644 --- a/core/block_render_svg.js +++ b/core/block_render_svg.js @@ -907,7 +907,7 @@ Blockly.BlockSvg.prototype.renderInlineRow_ = function(pathObject, row, cursor, var steps = pathObject.steps; var highlightSteps = pathObject.highlightSteps; - for (var x = 0, input; input = row[x]; x++) { + for (var i = 0, input; input = row[i]; i++) { var fieldX = cursor.x; var fieldY = cursor.y; if (row.thicker) { diff --git a/core/flyout_base.js b/core/flyout_base.js index 61ffed7cb17..b7897e7b1a1 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -404,7 +404,7 @@ Blockly.Flyout.prototype.hide = function() { } this.setVisible(false); // Delete all the event listeners. - for (var x = 0, listen; listen = this.listeners_[x]; x++) { + for (var i = 0, listen; listen = this.listeners_[i]; i++) { Blockly.unbindEvent_(listen); } this.listeners_.length = 0; diff --git a/core/generator.js b/core/generator.js index fc7471b7d6e..13cfc33581f 100644 --- a/core/generator.js +++ b/core/generator.js @@ -96,7 +96,7 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) { var code = []; this.init(workspace); var blocks = workspace.getTopBlocks(true); - for (var x = 0, block; block = blocks[x]; x++) { + for (var i = 0, block; block = blocks[i]; i++) { var line = this.blockToCode(block); if (Array.isArray(line)) { // Value blocks return tuples of code and operator order. diff --git a/core/xml.js b/core/xml.js index 158bd8e0ca0..d953c87e396 100644 --- a/core/xml.js +++ b/core/xml.js @@ -250,8 +250,8 @@ Blockly.Xml.cloneShadow_ = function(shadow) { while (node && !node.nextSibling) { textNode = node; node = node.parentNode; - if (textNode.nodeType == 3 && textNode.data.trim() == '' && - node.firstChild != textNode) { + if (textNode.nodeType == Element.TEXT_NODE && + textNode.data.trim() == '' && node.firstChild != textNode) { // Prune whitespace after a tag. Blockly.utils.removeNode(textNode); } @@ -259,7 +259,8 @@ Blockly.Xml.cloneShadow_ = function(shadow) { if (node) { textNode = node; node = node.nextSibling; - if (textNode.nodeType == 3 && textNode.data.trim() == '') { + if (textNode.nodeType == Element.TEXT_NODE && + textNode.data.trim() == '') { // Prune whitespace before a tag. Blockly.utils.removeNode(textNode); } @@ -594,7 +595,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { var blockChild = null; for (var i = 0, xmlChild; xmlChild = xmlBlock.childNodes[i]; i++) { - if (xmlChild.nodeType == 3) { + if (xmlChild.nodeType == Element.TEXT_NODE) { // Ignore any text at the level. It's all whitespace anyway. continue; } @@ -604,7 +605,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { var childBlockElement = null; var childShadowElement = null; for (var j = 0, grandchild; grandchild = xmlChild.childNodes[j]; j++) { - if (grandchild.nodeType == 1) { + if (grandchild.nodeType == Element.ELEMENT_NODE) { if (grandchild.nodeName.toLowerCase() == 'block') { childBlockElement = /** @type {!Element} */ (grandchild); } else if (grandchild.nodeName.toLowerCase() == 'shadow') { From 44501f17cc44aa2eab9b605490e3bcf404851a14 Mon Sep 17 00:00:00 2001 From: Navid Zandi Date: Fri, 3 May 2019 01:08:48 +0430 Subject: [PATCH 042/233] Resolve field angle overlap render problem (#2418) * Rebuild and update version numbers * rebuild * Update version number to 1.20190419.0 * Resolve field angle overlap render problem * use block.getColourBorder() function --- core/field_angle.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index a9a177462d8..edea08ae46b 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -207,9 +207,11 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { }, svg); } - - Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), - this.sourceBlock_.getColour()); + + var border = this.sourceBlock_.getColourBorder(); + border = border.colourBorder == null ? border.colourLight : border.colourBorder; + + Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); Blockly.DropDownDiv.showPositionedByField(this); // The angle picker is different from other fields in that it updates on // mousemove even if it's not in the middle of a drag. In future we may From 9e7becc26209bf2876865db18a164c6f981e71f3 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 2 May 2019 15:31:54 -0700 Subject: [PATCH 043/233] Update comments --- tests/mocha/run_mocha_tests_in_browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mocha/run_mocha_tests_in_browser.js b/tests/mocha/run_mocha_tests_in_browser.js index 72b521505c7..3eaae0c1d65 100644 --- a/tests/mocha/run_mocha_tests_in_browser.js +++ b/tests/mocha/run_mocha_tests_in_browser.js @@ -2,7 +2,7 @@ * @license * Visual Blocks Editor * - * Copyright 2018 Google Inc. + * Copyright 2019 Google Inc. * https://developers.google.com/blockly/ * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ */ /** - * @fileoverview Node.js script to run JsUnit tests in Chrome, via webdriver. + * @fileoverview Node.js script to run Mocha tests in Chrome, via webdriver. */ var webdriverio = require('webdriverio'); From 354d402c49c39fddf1345fbda27f183c24c92cb9 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 30 Apr 2019 13:37:45 -0700 Subject: [PATCH 044/233] Refactored field.init into field.initView and field.initModel --- core/field.js | 17 ++++++++++++++--- core/field_checkbox.js | 12 +++++------- core/field_colour.js | 8 +++++--- core/field_dropdown.js | 13 +++++-------- core/field_image.js | 16 +++------------- core/field_label.js | 28 +++++++--------------------- core/field_variable.js | 16 ---------------- tests/playground.html | 2 +- 8 files changed, 40 insertions(+), 72 deletions(-) diff --git a/core/field.js b/core/field.js index 63bed078700..854bfad85bf 100644 --- a/core/field.js +++ b/core/field.js @@ -202,15 +202,26 @@ Blockly.Field.prototype.setSourceBlock = function(block) { }; /** - * Install this field on a block. + * Initialize everything to render this field. Override + * methods initModel and initView rather than this method. + * @package */ Blockly.Field.prototype.init = function() { if (this.fieldGroup_) { // Field has already been initialized once. return; } - // Build the DOM. this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); + this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); + this.initView(); + this.initModel(); +}; + +/** + * Create the block UI for this field. + * @package + */ +Blockly.Field.prototype.initView = function() { if (!this.visible_) { this.fieldGroup_.style.display = 'none'; } @@ -230,7 +241,6 @@ Blockly.Field.prototype.init = function() { this.updateEditable(); this.clickTarget_ = this.getSvgRoot(); - this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); this.mouseDownWrapper_ = Blockly.bindEventWithChecks_( this.clickTarget_, 'mousedown', this, this.onMouseDown_); @@ -239,6 +249,7 @@ Blockly.Field.prototype.init = function() { /** * Initializes the model of the field after it has been installed on a block. * No-op by default. + * @package */ Blockly.Field.prototype.initModel = function() { }; diff --git a/core/field_checkbox.js b/core/field_checkbox.js index 005476f69d9..b37217068d3 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -77,14 +77,12 @@ Blockly.FieldCheckbox.CHECK_CHAR = '\u2713'; Blockly.FieldCheckbox.prototype.CURSOR = 'default'; /** - * Install this checkbox on a block. + * Create the block UI for this checkbox. + * @package */ -Blockly.FieldCheckbox.prototype.init = function() { - if (this.fieldGroup_) { - // Checkbox has already been initialized once. - return; - } - Blockly.FieldCheckbox.superClass_.init.call(this); +Blockly.FieldCheckbox.prototype.initView = function() { + Blockly.FieldCheckbox.superClass_.initView.call(this); + // The checkbox doesn't use the inherited text element. // Instead it uses a custom checkmark element that is either visible or not. this.checkElement_ = Blockly.utils.createSvgElement('text', diff --git a/core/field_colour.js b/core/field_colour.js index 1ac5382bc03..8ec1bc22370 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -124,10 +124,12 @@ Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR = 'silver'; Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR = 'white'; /** - * Install this field on a block. + * Create the block UI for this colour field. + * @package */ -Blockly.FieldColour.prototype.init = function() { - Blockly.FieldColour.superClass_.init.call(this); +Blockly.FieldColour.prototype.initView = function() { + Blockly.FieldColour.superClass_.initView.call(this); + this.size_ = new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH, Blockly.FieldColour.DEFAULT_HEIGHT); this.borderRect_.style['fillOpacity'] = 1; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index e6c6f267e81..ac2475f3a2e 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -127,20 +127,17 @@ Blockly.FieldDropdown.prototype.imageElement_ = null; Blockly.FieldDropdown.prototype.imageJson_ = null; /** - * Install this dropdown on a block. + * Create the block UI for this dropdown. + * @package */ -Blockly.FieldDropdown.prototype.init = function() { - if (this.fieldGroup_) { - // Dropdown has already been initialized once. - return; - } +Blockly.FieldDropdown.prototype.initView = function() { + Blockly.FieldDropdown.superClass_.initView.call(this); + // Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL) this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, null); this.arrow_.appendChild(document.createTextNode(this.sourceBlock_.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : ' ' + Blockly.FieldDropdown.ARROW_CHAR)); - - Blockly.FieldDropdown.superClass_.init.call(this); }; /** diff --git a/core/field_image.js b/core/field_image.js index 5feaa956253..dfebb2d2ce0 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -92,20 +92,10 @@ Blockly.FieldImage.fromJson = function(options) { Blockly.FieldImage.prototype.EDITABLE = false; /** - * Install this image on a block. + * Create the block UI for this image. + * @package */ -Blockly.FieldImage.prototype.init = function() { - if (this.fieldGroup_) { - // Image has already been initialized once. - return; - } - // Build the DOM. - /** @type {SVGElement} */ - this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); - if (!this.visible_) { - this.fieldGroup_.style.display = 'none'; - } - /** @type {SVGElement} */ +Blockly.FieldImage.prototype.initView = function() { this.imageElement_ = Blockly.utils.createSvgElement( 'image', { diff --git a/core/field_label.js b/core/field_label.js index d2f951863a2..cecf2b8c0f7 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -71,23 +71,18 @@ Blockly.FieldLabel.fromJson = function(options) { Blockly.FieldLabel.prototype.EDITABLE = false; /** - * Install this text on a block. + * Create block UI for this label. + * @package */ -Blockly.FieldLabel.prototype.init = function() { - if (this.textElement_) { - // Text has already been initialized once. - return; - } - // Build the DOM. +Blockly.FieldLabel.prototype.initView = function() { this.textElement_ = Blockly.utils.createSvgElement('text', - {'class': 'blocklyText', 'y': this.size_.height - 5}, null); + { + 'class': 'blocklyText', + 'y': this.size_.height - 5 + }, this.fieldGroup_); if (this.class_) { Blockly.utils.addClass(this.textElement_, this.class_); } - if (!this.visible_) { - this.textElement_.style.display = 'none'; - } - this.sourceBlock_.getSvgRoot().appendChild(this.textElement_); if (this.tooltip_) { this.textElement_.tooltip = this.tooltip_; @@ -108,15 +103,6 @@ Blockly.FieldLabel.prototype.dispose = function() { } }; -/** - * Gets the group element for this field. - * Used for measuring the size and for positioning. - * @return {!Element} The group element. - */ -Blockly.FieldLabel.prototype.getSvgRoot = function() { - return /** @type {!Element} */ (this.textElement_); -}; - /** * Change the tooltip text for this field. * @param {string|!Element} newTip Text for tooltip or a parent element to diff --git a/core/field_variable.js b/core/field_variable.js index 29c6af878c8..6c5561a7f86 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -86,22 +86,6 @@ Blockly.FieldVariable.fromJson = function(options) { */ Blockly.FieldVariable.prototype.SERIALIZABLE = true; -/** - * Initialize everything needed to render this field. This includes making sure - * that the field's value is valid. - * @public - */ -Blockly.FieldVariable.prototype.init = function() { - if (this.fieldGroup_) { - // Dropdown has already been initialized once. - return; - } - Blockly.FieldVariable.superClass_.init.call(this); - - // TODO (#1010): Change from init/initModel to initView/initModel - this.initModel(); -}; - /** * Initialize the model for this field if it has not already been initialized. * If the value has not been set to a variable by the first render, we make up a diff --git a/tests/playground.html b/tests/playground.html index a46d88164eb..72d5dbd5d2c 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -1288,7 +1288,7 @@

Blockly Playground

- + From f065c78dee3120fa0ca80435acf5ff1c2f4a7066 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 6 May 2019 16:35:40 +0200 Subject: [PATCH 045/233] Localisation updates from https://translatewiki.net. --- msg/json/ee.json | 28 +++++++++++++++++++++++++++- msg/json/kab.json | 6 +++++- msg/json/sd.json | 11 +++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/msg/json/ee.json b/msg/json/ee.json index 80e6a0c8bd7..c16f908f9ed 100644 --- a/msg/json/ee.json +++ b/msg/json/ee.json @@ -142,5 +142,31 @@ "MATH_IS_WHOLE": "enye blibo", "MATH_IS_POSITIVE": "enye xexlẽme ŋgɔgbeyitɔ", "MATH_IS_NEGATIVE": "enye xexlẽme megbeyitɔ", - "MATH_IS_DIVISIBLE_BY": "woate ŋu amae ɖe" + "MATH_IS_DIVISIBLE_BY": "woate ŋu amae ɖe", + "MATH_ONLIST_OPERATOR_MIN": "suetɔ le wo dome", + "MATH_ONLIST_TOOLTIP_MIN": "Neʋu suetɔ le nuwo dome.", + "MATH_ONLIST_OPERATOR_MAX": "gãtɔ le nuwo dome", + "MATH_ONLIST_TOOLTIP_MAX": "Neʋu xexlẽdzesi gãtɔ.", + "LISTS_ISEMPTY_TITLE": "%1 le ƒuƒlu", + "LISTS_GET_INDEX_REMOVE": "ɖee ɖa", + "LISTS_GET_INDEX_FROM_END": "# tso nuwuwu", + "LISTS_GET_INDEX_FIRST": "gbãtɔ", + "LISTS_GET_INDEX_LAST": "mamlɛtɔ", + "LISTS_GET_INDEX_RANDOM": "ɖe sia ɖe ko", + "LISTS_INDEX_FROM_START_TOOLTIP": "%1 nye nu gbãtɔ.", + "LISTS_INDEX_FROM_END_TOOLTIP": "%1 nye nu mamlɛtɔ.", + "LISTS_GET_INDEX_TOOLTIP_GET_FROM": "Aʋu nua le afi si wòle le nuwo dome.", + "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Aʋu nu gbãtɔ.", + "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Aʋu nu mamlɛtɔ.", + "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Aʋu nu ɖe sia ɖe aɖe ko.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM": "Aɖe nua ɖa eye wòaʋu nua le afi si wòle le nuawo dome.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Eɖea nu gbãtɔ ɖa eye eya kee gaʋua nu gbãtɔ.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Eɖea nu mamlɛtɔ ɖa eye eya kee gaʋua nu mamlɛtɔ.", + "LISTS_GET_SUBLIST_END_FROM_START": "yi #", + "LISTS_GET_SUBLIST_END_FROM_END": "yi # tso nuwuwu", + "LISTS_GET_SUBLIST_END_LAST": "yi mamlɛtɔ", + "LISTS_SORT_ORDER_ASCENDING": "dzi yim", + "LISTS_SORT_ORDER_DESCENDING": "ɖiɖim", + "PROCEDURES_BEFORE_PARAMS": "kple:", + "PROCEDURES_CALL_BEFORE_PARAMS": "kple:" } diff --git a/msg/json/kab.json b/msg/json/kab.json index e003866d283..7088288eab4 100644 --- a/msg/json/kab.json +++ b/msg/json/kab.json @@ -187,6 +187,9 @@ "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "tirẓi tagacurant", "MATH_RANDOM_FLOAT_TOOLTIP": "Ad d-yerr tirẓi tagacurant gar 0.0 (yedda) akked 1.0 (ur yeddi ara).", + "MATH_ATAN2_HELPURL": "https://kab.wikipedia.org/wiki/Atan2", + "MATH_ATAN2_TITLE": "atan2 seg X:%1 Y:%2", + "MATH_ATAN2_TOOLTIP": "Ad d-yerr arctangent n waggaz (X, Y) s tfesniwin deg -180 ɣer 180.", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Asekkil, awal neɣ izirig n uḍris.", "TEXT_JOIN_TITLE_CREATEWITH": "rnu aḍṛis s", @@ -337,5 +340,6 @@ "PROCEDURES_CREATE_DO": "rnu '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "ma yella azal d idetti, ad d-yerr azal-nniḍen wis sin.", "PROCEDURES_IFRETURN_WARNING": "Ɣur-k: Iḥder-agi yezmer ur yettwaseqdac ara ala di tebadut n twuri-agi.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Ini kra..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Ini kra...", + "COLLAPSED_WARNINGS_WARNING": "Iḥedran yettin gebren ilɣa." } diff --git a/msg/json/sd.json b/msg/json/sd.json index 09ebe1d64dd..1ea423588d4 100644 --- a/msg/json/sd.json +++ b/msg/json/sd.json @@ -3,18 +3,21 @@ "authors": [ "Aursani", "Mehtab ahmed", - "Indus Asia" + "Indus Asia", + "Tweety" ] }, "VARIABLES_DEFAULT_NAME": "اسم", "TODAY": "اڄ", "DUPLICATE_BLOCK": "نقل", - "ADD_COMMENT": "راءِ ڏيو", - "REMOVE_COMMENT": "راءِ ڊاهيو", - "EXTERNAL_INPUTS": "ٻاهرين ڄاڻ", + "ADD_COMMENT": "رايو ڏيو", + "REMOVE_COMMENT": "رايو ڊاهيو", + "DUPLICATE_COMMENT": "نقل رايو", + "EXTERNAL_INPUTS": "ٻاهرين داخلائون", "INLINE_INPUTS": "اِنلائين اِن پٽس", "DELETE_BLOCK": "بلاڪ ڊاهيو", "DELETE_X_BLOCKS": "1٪ بلاڪ ڊاهيو", + "DELETE_ALL_BLOCKS": "سڀ %1 بلاڪ ڊاھيون؟", "CLEAN_UP": "بندشون هٽايو", "COLLAPSE_BLOCK": "بلاڪ ڍڪيو", "COLLAPSE_ALL": "بلاڪَ ڍڪيو", From e25734ff2512691f1bf12008415a14df05ae3179 Mon Sep 17 00:00:00 2001 From: asunwoo98 <45576715+asunwoo98@users.noreply.github.com> Date: Mon, 6 May 2019 16:09:50 -0400 Subject: [PATCH 046/233] typo fix in createVariable documentation in variable.js (#2443) --- core/variables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/variables.js b/core/variables.js index 4b7e0669e76..9255cd432ee 100644 --- a/core/variables.js +++ b/core/variables.js @@ -267,7 +267,7 @@ Blockly.Variables.generateUniqueName = function(workspace) { /** * Handles "Create Variable" button in the default variables toolbox category. - * It will prompt the user for a varibale name, including re-prompts if a name + * It will prompt the user for a variable name, including re-prompts if a name * is already in use among the workspace's variables. * * Custom button handlers can delegate to this function, allowing variables From e2281e5a982da7e9145fbe718c3e0ff4ed8695b8 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 9 May 2019 16:52:24 +0200 Subject: [PATCH 047/233] Localisation updates from https://translatewiki.net. --- msg/json/az.json | 5 ++++- msg/json/et.json | 26 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/msg/json/az.json b/msg/json/az.json index 87e0e25bd13..6bfec572227 100644 --- a/msg/json/az.json +++ b/msg/json/az.json @@ -3,7 +3,8 @@ "authors": [ "Cekli829", "AZISS", - "Masalli qasimli" + "Masalli qasimli", + "Adil" ] }, "VARIABLES_DEFAULT_NAME": "element", @@ -200,6 +201,8 @@ "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "təsadüfi kəsr", "MATH_RANDOM_FLOAT_TOOLTIP": "0.0 (daxil olmaqla) və 1.0 (daxil olmamaqla) ədədlərinin arasından təsadüfi bir kəsr ədəd qaytarır.", + "MATH_ATAN2_HELPURL": "https://en.wikipedia.org/wiki/Atan2", + "MATH_ATAN2_TOOLTIP": "(X,Y) nöqtələrinin -180 - 180 dərəcədə arktangensini hesabla.", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Mətndəki hərf, söz və ya sətir.", "TEXT_JOIN_TITLE_CREATEWITH": "Verilmişlərlə mətn yarat", diff --git a/msg/json/et.json b/msg/json/et.json index 09d07a29c38..a2f11bce814 100644 --- a/msg/json/et.json +++ b/msg/json/et.json @@ -4,7 +4,8 @@ "Aivarannamaa", "Hasso", "Puik", - "Ilmarine" + "Ilmarine", + "Masavi" ] }, "VARIABLES_DEFAULT_NAME": "objekt", @@ -12,6 +13,7 @@ "DUPLICATE_BLOCK": "Tekita duplikaat", "ADD_COMMENT": "Lisa kommentaar", "REMOVE_COMMENT": "Eemalda kommentaar", + "DUPLICATE_COMMENT": "Dubleeri kommentaar", "EXTERNAL_INPUTS": "Sisendid ploki taga", "INLINE_INPUTS": "Sisendid ploki sees", "DELETE_BLOCK": "Kustuta plokk", @@ -31,9 +33,15 @@ "RENAME_VARIABLE": "Nimeta muutuja ümber ...", "RENAME_VARIABLE_TITLE": "Muutuja „%1“ uus nimi:", "NEW_VARIABLE": "Uus muutuja ...", + "NEW_STRING_VARIABLE": "Loo muutuja sõnena...", + "NEW_NUMBER_VARIABLE": "Loo muutuja arvuna...", + "NEW_COLOUR_VARIABLE": "Loo muutuja värvina...", + "NEW_VARIABLE_TYPE_TITLE": "Uue muutuja tüüp:", "NEW_VARIABLE_TITLE": "Uue muutuja nimi:", "VARIABLE_ALREADY_EXISTS": "'%1'-nimeline muutuja on juba olemas.", + "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Muutuja nimega '%1' juba eksisteerib teise tüübina: '%2'.", "DELETE_VARIABLE_CONFIRMATION": "Kas kustutada %1 kohas kasutatav muutuja '%2'?", + "CANNOT_DELETE_VARIABLE_PROCEDURE": "Muutujat '%1' ei saa kustutada, sest see on osa funktsiooni '%2' määratlusest", "DELETE_VARIABLE": "Kustuta muutuja '%1'", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Valitud värv paletist.", @@ -76,6 +84,14 @@ "CONTROLS_IF_IF_TOOLTIP": "Selle „kui“ ploki muutmine sektsioonide lisamise, eemaldamise ja järjestamisega.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Lisab „kui“ plokile tingimuse.", "CONTROLS_IF_ELSE_TOOLTIP": "Lisab „kui“ plokile lõpliku tingimuseta koodiploki.", + "IOS_OK": "OK", + "IOS_CANCEL": "Tühista", + "IOS_ERROR": "Viga", + "IOS_PROCEDURES_INPUTS": "SISEND", + "IOS_PROCEDURES_ADD_INPUT": "+ Lisa sisend", + "IOS_VARIABLES_ADD_VARIABLE": "+ Lisa muutuja", + "IOS_VARIABLES_ADD_BUTTON": "Lisa", + "IOS_VARIABLES_RENAME_BUTTON": "Nimeta ümber", "IOS_VARIABLES_DELETE_BUTTON": "Kustuta", "IOS_VARIABLES_VARIABLE_NAME": "Muutuja nimi", "IOS_VARIABLES_EMPTY_NAME_ERROR": "Tühja muutuja nime ei saa kasutada.", @@ -171,6 +187,9 @@ "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "juhuslik murdosa", "MATH_RANDOM_FLOAT_TOOLTIP": "Tagastab juhusliku murdosa 0.0 (kaasa arvatud) and 1.0 (välja arvatud) vahel.", + "MATH_ATAN2_HELPURL": "https://en.wikipedia.org/wiki/Atan2", + "MATH_ATAN2_TITLE": "atan2(X:%1, Y:%2)", + "MATH_ATAN2_TOOLTIP": "Tagastab punkti (X, Y) arkustangentsit kraadides vahemikus -180 kuni 180.", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Täht, sõna või rida teksti.", "TEXT_JOIN_TITLE_CREATEWITH": "tekita tekst", @@ -188,6 +207,7 @@ "TEXT_INDEXOF_TITLE": "tekstist %1 %2 %3 asukoht", "TEXT_INDEXOF_OPERATOR_FIRST": "esimese leitud tekstitüki", "TEXT_INDEXOF_OPERATOR_LAST": "viimase leitud tekstitüki", + "TEXT_CHARAT_TITLE": "tekstis %1 %2", "TEXT_CHARAT_FROM_START": "sümbol #", "TEXT_CHARAT_FROM_END": "lõpust sümbol #", "TEXT_CHARAT_FIRST": "esimene sümbol", @@ -216,7 +236,11 @@ "TEXT_PROMPT_TYPE_NUMBER": "kasutajalt küsitud arv teatega", "TEXT_PROMPT_TOOLTIP_NUMBER": "Küsib kasutajalt teadet näidates mingit arvu.", "TEXT_PROMPT_TOOLTIP_TEXT": "Küsib kasutajalt teadet näidates mingit teksti.", + "TEXT_COUNT_MESSAGE0": "loenda %1 %2-ses", "TEXT_COUNT_TOOLTIP": "Loenda, mitu korda mingi tekst esineb teise teksti sees.", + "TEXT_REPLACE_MESSAGE0": "asenda %1 %2-ga %3-s", + "TEXT_REPLACE_TOOLTIP": "Asenda mõne teksti esinemine mõnes muus tekstis.", + "TEXT_REVERSE_MESSAGE0": "ümberpöördud %1", "LISTS_CREATE_EMPTY_TITLE": "tühi loend", "LISTS_CREATE_EMPTY_TOOLTIP": "Tagastab loendi, mille pikkus on 0 ja milles pole ühtegi elementi.", "LISTS_CREATE_WITH_TOOLTIP": "Tekitab mistahes arvust elementidest loendi.", From 4062030731a3af81bfa0f7c0b373320fcd4b5dd1 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 10 May 2019 14:03:21 -0700 Subject: [PATCH 048/233] Remove goog.userAgent dependency. --- core/bubble.js | 9 +++---- core/comment.js | 5 ++-- core/contextmenu.js | 5 ++-- core/field.js | 3 +-- core/field_angle.js | 10 ++++---- core/field_dropdown.js | 7 +++--- core/field_textinput.js | 12 ++++----- core/flyout_horizontal.js | 1 - core/flyout_vertical.js | 4 +-- core/grid.js | 4 +-- core/inject.js | 3 +-- core/utils.js | 51 +++++++++++++++++++++++++++++++++++---- core/workspace_audio.js | 12 ++++----- 13 files changed, 79 insertions(+), 47 deletions(-) diff --git a/core/bubble.js b/core/bubble.js index 7befb33ccaf..ef2ff9c7146 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -27,9 +27,10 @@ goog.provide('Blockly.Bubble'); goog.require('Blockly.Touch'); +goog.require('Blockly.utils'); goog.require('Blockly.Workspace'); + goog.require('goog.math.Coordinate'); -goog.require('goog.userAgent'); /** @@ -224,10 +225,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { this.bubbleGroup_ = Blockly.utils.createSvgElement('g', {}, null); var filter = {'filter': 'url(#' + this.workspace_.options.embossFilterId + ')'}; - if (goog.userAgent.getUserAgentString().indexOf('JavaFX') != -1) { - // Multiple reports that JavaFX can't handle filters. UserAgent: - // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 - // (KHTML, like Gecko) JavaFX/8.0 Safari/537.44 + if (Blockly.utils.userAgent.JAVA_FX) { + // Multiple reports that JavaFX can't handle filters. // https://github.com/google/blockly/issues/99 filter = {}; } diff --git a/core/comment.js b/core/comment.js index a1d7fbc0248..f269e5ec636 100644 --- a/core/comment.js +++ b/core/comment.js @@ -32,8 +32,6 @@ goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); goog.require('Blockly.utils'); -goog.require('goog.userAgent'); - /** * Class for a comment. @@ -184,7 +182,8 @@ Blockly.Comment.prototype.setVisible = function(visible) { } Blockly.Events.fire( new Blockly.Events.Ui(this.block_, 'commentOpen', !visible, visible)); - if ((!this.block_.isEditable() && !this.textarea_) || goog.userAgent.IE) { + if ((!this.block_.isEditable() && !this.textarea_) || + Blockly.utils.userAgent.IE) { // Steal the code from warnings to make an uneditable text bubble. // MSIE does not support foreignobject; textareas are impossible. // https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-svg/56e6e04c-7c8c-44dd-8100-bd745ee42034 diff --git a/core/contextmenu.js b/core/contextmenu.js index bd8b38f8e06..e8e75f18d56 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -39,7 +39,6 @@ goog.require('goog.events'); goog.require('goog.math.Coordinate'); goog.require('goog.ui.Menu'); goog.require('goog.ui.MenuItem'); -goog.require('goog.userAgent'); /** @@ -280,7 +279,7 @@ Blockly.ContextMenu.blockDuplicateOption = function(block) { */ Blockly.ContextMenu.blockCommentOption = function(block) { var commentOption = { - enabled: !goog.userAgent.IE + enabled: !Blockly.utils.userAgent.IE }; // If there's already a comment, add an option to delete it. if (block.comment) { @@ -388,7 +387,7 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { var wsCommentOption = { // Foreign objects don't work in IE. Don't let the user create comments // that they won't be able to edit. - enabled: !goog.userAgent.IE + enabled: !Blockly.utils.userAgent.IE }; wsCommentOption.text = Blockly.Msg.ADD_COMMENT; wsCommentOption.callback = function() { diff --git a/core/field.js b/core/field.js index 854bfad85bf..54d4cf657b3 100644 --- a/core/field.js +++ b/core/field.js @@ -34,7 +34,6 @@ goog.require('Blockly.utils'); goog.require('goog.math.Size'); goog.require('goog.style'); -goog.require('goog.userAgent'); /** @@ -496,7 +495,7 @@ Blockly.Field.getCachedWidth = function(textElement) { // Attempt to compute fetch the width of the SVG text element. try { - if (goog.userAgent.IE || goog.userAgent.EDGE) { + if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { width = textElement.getBBox().width; } else { width = textElement.getComputedTextLength(); diff --git a/core/field_angle.js b/core/field_angle.js index edea08ae46b..3fb335bd144 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -30,8 +30,6 @@ goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.utils'); -goog.require('goog.userAgent'); - /** * Class for an editable angle field. @@ -163,7 +161,9 @@ Blockly.FieldAngle.prototype.dispose_ = function() { */ Blockly.FieldAngle.prototype.showEditor_ = function() { var noFocus = - goog.userAgent.MOBILE || goog.userAgent.ANDROID || goog.userAgent.IPAD; + Blockly.utils.userAgent.MOBILE || + Blockly.utils.userAgent.ANDROID || + Blockly.utils.userAgent.IPAD; // Mobile browsers have issues with in-line textareas (focus & keyboards). Blockly.FieldAngle.superClass_.showEditor_.call(this, noFocus); @@ -207,10 +207,10 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { }, svg); } - + var border = this.sourceBlock_.getColourBorder(); border = border.colourBorder == null ? border.colourLight : border.colourBorder; - + Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); Blockly.DropDownDiv.showPositionedByField(this); // The angle picker is different from other fields in that it updates on diff --git a/core/field_dropdown.js b/core/field_dropdown.js index ac2475f3a2e..a0c18f3d01f 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -35,7 +35,6 @@ goog.require('Blockly.utils.uiMenu'); goog.require('goog.events'); goog.require('goog.ui.Menu'); goog.require('goog.ui.MenuItem'); -goog.require('goog.userAgent'); /** @@ -97,7 +96,8 @@ Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45; /** * Android can't (in 2014) display "▾", so use "▼" instead. */ -Blockly.FieldDropdown.ARROW_CHAR = goog.userAgent.ANDROID ? '\u25BC' : '\u25BE'; +Blockly.FieldDropdown.ARROW_CHAR = + Blockly.utils.userAgent.ANDROID ? '\u25BC' : '\u25BE'; /** * Mouse cursor style when over the hotspot that initiates the editor. @@ -525,7 +525,8 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { * implementation. */ Blockly.FieldDropdown.prototype.updateWidth = function() { - if (this.imageJson_ && (goog.userAgent.IE || goog.userAgent.EDGE)) { + if (this.imageJson_ && + (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE)) { // Recalculate the full width. var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_); var width = Number(this.imageJson_.width) + arrowWidth + diff --git a/core/field_textinput.js b/core/field_textinput.js index 997552f1d68..251d0689877 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -32,7 +32,6 @@ goog.require('Blockly.Msg'); goog.require('Blockly.utils'); goog.require('goog.math.Coordinate'); -goog.require('goog.userAgent'); /** @@ -166,8 +165,9 @@ Blockly.FieldTextInput.prototype.setSpellcheck = function(check) { Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) { this.workspace_ = this.sourceBlock_.workspace; var quietInput = opt_quietInput || false; - if (!quietInput && (goog.userAgent.MOBILE || goog.userAgent.ANDROID || - goog.userAgent.IPAD)) { + if (!quietInput && (Blockly.utils.userAgent.MOBILE || + Blockly.utils.userAgent.ANDROID || + Blockly.utils.userAgent.IPAD)) { this.showPromptEditor_(); } else { this.showInlineEditor_(quietInput); @@ -301,7 +301,7 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { this.setValue(text); Blockly.Events.setGroup(false); this.validate_(); - } else if (goog.userAgent.WEBKIT) { + } else if (Blockly.utils.userAgent.WEBKIT) { // Cursor key. Render the source block to show the caret moving. // Chrome only (version 26, OS X). this.sourceBlock_.render(); @@ -348,13 +348,13 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { // Shift by a few pixels to line up exactly. xy.y += 1; - if (goog.userAgent.GECKO && Blockly.WidgetDiv.DIV.style.top) { + if (Blockly.utils.userAgent.GECKO && Blockly.WidgetDiv.DIV.style.top) { // Firefox mis-reports the location of the border by a pixel // once the WidgetDiv is moved into position. xy.x -= 1; xy.y -= 1; } - if (goog.userAgent.WEBKIT) { + if (Blockly.utils.userAgent.WEBKIT) { xy.y -= 3; } div.style.left = xy.x + 'px'; diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index 33f9eaa1942..4000aa81d33 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -33,7 +33,6 @@ goog.require('Blockly.Flyout'); goog.require('Blockly.WorkspaceSvg'); goog.require('goog.math.Rect'); -goog.require('goog.userAgent'); /** diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index d88c669f447..417a3e4f6cd 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -30,10 +30,10 @@ goog.require('Blockly.Block'); goog.require('Blockly.Events'); goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); +goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); goog.require('goog.math.Rect'); -goog.require('goog.userAgent'); /** @@ -337,7 +337,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { // Firefox sometimes reports the wrong value for the client rect. // See https://github.com/google/blockly/issues/1425 and // https://bugzilla.mozilla.org/show_bug.cgi?id=1066435 - if (goog.userAgent.GECKO && + if (Blockly.utils.userAgent.GECKO && this.targetWorkspace_ && this.targetWorkspace_.isMutator) { // The position of the left side of the mutator workspace in pixels // relative to the window origin. diff --git a/core/grid.js b/core/grid.js index ae6a8f9caf7..52669ca519b 100644 --- a/core/grid.js +++ b/core/grid.js @@ -29,8 +29,6 @@ goog.provide('Blockly.Grid'); goog.require('Blockly.utils'); -goog.require('goog.userAgent'); - /** * Class for a workspace's grid. @@ -187,7 +185,7 @@ Blockly.Grid.prototype.moveTo = function(x, y) { this.gridPattern_.setAttribute('x', x); this.gridPattern_.setAttribute('y', y); - if (goog.userAgent.IE || goog.userAgent.EDGE) { + if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { // IE/Edge doesn't notice that the x/y offsets have changed. // Force an update. this.update(this.scale_); diff --git a/core/inject.js b/core/inject.js index 57d2a13b402..deeb6c63a81 100644 --- a/core/inject.js +++ b/core/inject.js @@ -36,7 +36,6 @@ goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.WorkspaceDragSurfaceSvg'); goog.require('goog.ui.Component'); -goog.require('goog.userAgent'); /** @@ -434,7 +433,7 @@ Blockly.inject.bindDocumentEvents_ = function() { Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); Blockly.bindEvent_(document, 'touchcancel', null, Blockly.longStop_); // Some iPad versions don't fire resize after portrait to landscape change. - if (goog.userAgent.IPAD) { + if (Blockly.utils.userAgent.IPAD) { Blockly.bindEventWithChecks_(window, 'orientationchange', document, function() { // TODO (#397): Fix for multiple Blockly workspaces. diff --git a/core/utils.js b/core/utils.js index 2a30ae6bf54..617d5bfdc01 100644 --- a/core/utils.js +++ b/core/utils.js @@ -34,7 +34,6 @@ goog.provide('Blockly.utils'); goog.require('goog.dom'); goog.require('goog.math.Coordinate'); -goog.require('goog.userAgent'); /** @@ -46,9 +45,7 @@ goog.require('goog.userAgent'); * @param {string} attributeName Name of attribute to remove. */ Blockly.utils.removeAttribute = function(element, attributeName) { - // goog.userAgent.isVersion is deprecated, but the replacement is - // goog.userAgent.isVersionOrHigher. - if (goog.userAgent.IE && goog.userAgent.isVersion('10.0')) { + if (Blockly.utils.userAgent.IE10) { element.setAttribute(attributeName, null); } else { element.removeAttribute(attributeName); @@ -277,7 +274,7 @@ Blockly.utils.createSvgElement = function(name, attrs, parent) { * @return {boolean} True if right-click. */ Blockly.utils.isRightButton = function(e) { - if (e.ctrlKey && goog.userAgent.MAC) { + if (e.ctrlKey && Blockly.utils.userAgent.MAC) { // Control-clicking on Mac OS X is treated as a right-click. // WebKit on Mac OS X fails to change button to 2 (but Gecko does). return true; @@ -1046,3 +1043,47 @@ Blockly.utils.clampNumber = function(lowerBound, number, upperBound) { } return Math.max(lowerBound, Math.min(number, upperBound)); }; + +Blockly.utils.userAgent = {}; +(function(raw) { + Blockly.utils.userAgent.raw = raw; + var rawUpper = Blockly.utils.userAgent.raw.toUpperCase(); + /** + * Case-insensitive test of whether name is in the useragent string. + * @param {string} name Name to test. + */ + function has(name) { + return rawUpper.indexOf(name.toUpperCase()) != -1; + } + // Browsers. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/browser.js + Blockly.utils.userAgent.IE = has('Trident') || has('MSIE'); + Blockly.utils.userAgent.IE10 = has('MSIE 10.0'); // 10.1 does not exist. + Blockly.utils.userAgent.EDGE = has('Edge'); + // Useragent for JavaFX: + // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 + // (KHTML, like Gecko) JavaFX/8.0 Safari/537.44 + Blockly.utils.userAgent.JAVA_FX = has('JavaFX'); + // Engines. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js + Blockly.utils.userAgent.WEBKIT = has('WebKit') && + !Blockly.utils.userAgent.EDGE; + Blockly.utils.userAgent.GECKO = has('Gecko') && + !Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE; + // Platform. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js + Blockly.utils.userAgent.ANDROID = has('Android'); + Blockly.utils.userAgent.IPAD = has('iPad'); + Blockly.utils.userAgent.IPOD = has('iPod'); + Blockly.utils.userAgent.IPHONE = has('iPhone') && + !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; + Blockly.utils.userAgent.MAC = has('Macintosh'); + // Device. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/device.js + Blockly.utils.userAgent.TABLET = Blockly.utils.userAgent.IPAD || + (Blockly.utils.userAgent.ANDROID && !has('Mobile')) || has('Silk'); + Blockly.utils.userAgent.MOBILE = !Blockly.utils.userAgent.TABLET && + (Blockly.utils.userAgent.IPOD || Blockly.utils.userAgent.IPHONE || + Blockly.utils.userAgent.ANDROID || has('IEMobile')); +})((this.navigator && this.navigator.userAgent) || ''); + diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 8b7089f9166..8d58c415661 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -27,7 +27,7 @@ goog.provide('Blockly.WorkspaceAudio'); -goog.require('goog.userAgent'); +goog.require('Blockly.utils'); /** @@ -115,7 +115,7 @@ Blockly.WorkspaceAudio.prototype.preload = function() { sound.pause(); // iOS can only process one sound at a time. Trying to load more than one // corrupts the earlier ones. Just load one and leave the others uncached. - if (goog.userAgent.IPAD || goog.userAgent.IPHONE) { + if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.IPHONE) { break; } } @@ -138,11 +138,9 @@ Blockly.WorkspaceAudio.prototype.play = function(name, opt_volume) { } this.lastSound_ = now; var mySound; - var ie9 = goog.userAgent.DOCUMENT_MODE && - goog.userAgent.DOCUMENT_MODE === 9; - if (ie9 || goog.userAgent.IPAD || goog.userAgent.ANDROID) { - // Creating a new audio node causes lag in IE9, Android and iPad. Android - // and IE9 refetch the file from the server, iPad uses a singleton audio + if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.ANDROID) { + // Creating a new audio node causes lag in Android and iPad. Android + // refetches the file from the server, iPad uses a singleton audio // node which must be deleted and recreated for each new audio tag. mySound = sound; } else { From fa8c7f3884e531ac27fdaa83325f33865adc2afe Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 10 May 2019 14:30:31 -0700 Subject: [PATCH 049/233] Lint fix. --- core/utils.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/utils.js b/core/utils.js index 617d5bfdc01..a97e56a8cfa 100644 --- a/core/utils.js +++ b/core/utils.js @@ -1051,10 +1051,12 @@ Blockly.utils.userAgent = {}; /** * Case-insensitive test of whether name is in the useragent string. * @param {string} name Name to test. + * @return {boolean} True if name is present. */ function has(name) { return rawUpper.indexOf(name.toUpperCase()) != -1; } + // Browsers. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/browser.js Blockly.utils.userAgent.IE = has('Trident') || has('MSIE'); @@ -1064,13 +1066,15 @@ Blockly.utils.userAgent = {}; // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 // (KHTML, like Gecko) JavaFX/8.0 Safari/537.44 Blockly.utils.userAgent.JAVA_FX = has('JavaFX'); + // Engines. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js Blockly.utils.userAgent.WEBKIT = has('WebKit') && !Blockly.utils.userAgent.EDGE; Blockly.utils.userAgent.GECKO = has('Gecko') && !Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE; - // Platform. Logic from: + + // Platforms. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js Blockly.utils.userAgent.ANDROID = has('Android'); Blockly.utils.userAgent.IPAD = has('iPad'); @@ -1078,7 +1082,8 @@ Blockly.utils.userAgent = {}; Blockly.utils.userAgent.IPHONE = has('iPhone') && !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; Blockly.utils.userAgent.MAC = has('Macintosh'); - // Device. Logic from: + + // Devices. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/device.js Blockly.utils.userAgent.TABLET = Blockly.utils.userAgent.IPAD || (Blockly.utils.userAgent.ANDROID && !has('Mobile')) || has('Silk'); From 25ddecab504d2a51fb8d0362df4c8610c86c6c2f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 10 May 2019 16:39:32 -0700 Subject: [PATCH 050/233] Undo workaround for IE10. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to no longer supporting IE10, we don’t need the code added here: https://github.com/google/blockly/commit/92f388000801e5a67aad093ef578b6e930b5840b --- core/block_svg.js | 4 ++-- core/utils.js | 19 +------------------ core/workspace_comment_svg.js | 2 +- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index ea5b51aa7b1..3b08c919f44 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -429,7 +429,7 @@ Blockly.BlockSvg.prototype.moveDuringDrag = function(newLoc) { * @private */ Blockly.BlockSvg.prototype.clearTransformAttributes_ = function() { - Blockly.utils.removeAttribute(this.getSvgRoot(), 'transform'); + this.getSvgRoot().removeAttribute('transform'); }; /** @@ -1194,7 +1194,7 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { 'url(#' + this.workspace.options.embossFilterId + ')'); this.svgPathLight_.style.display = 'none'; } else { - Blockly.utils.removeAttribute(this.svgPath_, 'filter'); + this.svgPath_.removeAttribute('filter'); delete this.svgPathLight_.style.display; } }; diff --git a/core/utils.js b/core/utils.js index a97e56a8cfa..52187c16059 100644 --- a/core/utils.js +++ b/core/utils.js @@ -36,22 +36,6 @@ goog.require('goog.dom'); goog.require('goog.math.Coordinate'); -/** - * Remove an attribute from a element even if it's in IE 10. - * Similar to Element.removeAttribute() but it works on SVG elements in IE 10. - * Sets the attribute to null in IE 10, which treats removeAttribute as a no-op - * if it's called on an SVG element. - * @param {!Element} element DOM element to remove attribute from. - * @param {string} attributeName Name of attribute to remove. - */ -Blockly.utils.removeAttribute = function(element, attributeName) { - if (Blockly.utils.userAgent.IE10) { - element.setAttribute(attributeName, null); - } else { - element.removeAttribute(attributeName); - } -}; - /** * Add a CSS class to a element. * Similar to Closure's goog.dom.classes.add, except it handles SVG elements. @@ -93,7 +77,7 @@ Blockly.utils.removeClass = function(element, className) { if (classList.length) { element.setAttribute('class', classList.join(' ')); } else { - Blockly.utils.removeAttribute(element, 'class'); + element.removeAttribute('class'); } return true; }; @@ -1060,7 +1044,6 @@ Blockly.utils.userAgent = {}; // Browsers. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/browser.js Blockly.utils.userAgent.IE = has('Trident') || has('MSIE'); - Blockly.utils.userAgent.IE10 = has('MSIE 10.0'); // 10.1 does not exist. Blockly.utils.userAgent.EDGE = has('Edge'); // Useragent for JavaFX: // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 61a1655bf89..b76614f1aa5 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -410,7 +410,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveTo = function(x, y) { * @private */ Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { - Blockly.utils.removeAttribute(this.getSvgRoot(), 'transform'); + this.getSvgRoot().removeAttribute('transform'); }; /** From 28ad3a9bd3a3642daeba46348fb770b2047854d2 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 10 May 2019 16:56:26 -0700 Subject: [PATCH 051/233] Blockly.utils.userAgent moved to Blockly.userAgent --- blockly_uncompressed.js | 40 ++++++++-------- core/block_render_svg.js | 1 + core/bubble.js | 3 +- core/comment.js | 3 +- core/contextmenu.js | 5 +- core/field.js | 3 +- core/field_angle.js | 7 +-- core/field_colour.js | 1 - core/field_dropdown.js | 5 +- core/field_label_serializable.js | 1 + core/field_textinput.js | 13 +++--- core/flyout_horizontal.js | 1 + core/flyout_vertical.js | 3 +- core/grid.js | 3 +- core/inject.js | 3 +- core/useragent.js | 78 ++++++++++++++++++++++++++++++++ core/utils.js | 52 ++------------------- core/workspace_audio.js | 6 +-- core/xml.js | 1 + 19 files changed, 138 insertions(+), 91 deletions(-) create mode 100644 core/useragent.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index c498aa19413..955381da650 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -34,50 +34,50 @@ this.BLOCKLY_BOOT = function(root) { dir = this.BLOCKLY_DIR.match(/[^\/]+$/)[0]; } // Execute after Closure has loaded. -goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.utils', 'Blockly.Warning', 'Blockly.Workspace', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.utils', 'Blockly.Warning', 'Blockly.Workspace', 'goog.math.Coordinate', 'goog.color']); goog.addDependency("../../../" + dir + "/core/block_animations.js", ['Blockly.BlockAnimations'], ['Blockly.utils']); goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.InsertionMarkerManager', 'Blockly.Events.BlockMove', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg']); +goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.color', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml', 'goog.color']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []); -goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.Workspace', 'goog.math.Coordinate', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.Workspace', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events.BlockMove', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']); goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []); -goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events.BlockCreate', 'Blockly.utils', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.math.Coordinate', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events.BlockCreate', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.math.Coordinate', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []); goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/dropdowndiv.js", ['Blockly.DropDownDiv'], ['Blockly.utils', 'goog.dom', 'goog.style']); goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], ['Blockly.utils']); goog.addDependency("../../../" + dir + "/core/events_abstract.js", ['Blockly.Events.Abstract'], ['Blockly.Events']); goog.addDependency("../../../" + dir + "/core/extensions.js", ['Blockly.Extensions'], ['Blockly.Mutator', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.utils', 'goog.math.Size', 'goog.style', 'goog.userAgent']); -goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.utils', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.userAgent', 'Blockly.utils', 'goog.math.Size', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_checkbox.js", ['Blockly.FieldCheckbox'], ['Blockly.Field', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/field_colour.js", ['Blockly.FieldColour'], ['Blockly.DropDownDiv', 'Blockly.Field', 'Blockly.utils', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/field_colour.js", ['Blockly.FieldColour'], ['Blockly.DropDownDiv', 'Blockly.Field', 'goog.style']); goog.addDependency("../../../" + dir + "/core/field_date.js", ['Blockly.FieldDate'], ['Blockly.Field', 'Blockly.utils', 'goog.date', 'goog.date.DateTime', 'goog.events', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_he', 'goog.style', 'goog.ui.DatePicker']); -goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Field', 'Blockly.utils', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Field', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.utils', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'goog.math.Size']); -goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel']); +goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.FieldTextInput']); -goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Field', 'Blockly.Msg', 'Blockly.utils', 'goog.math.Coordinate', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.utils', 'Blockly.VariableModel', 'Blockly.Variables', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'goog.math.Rect']); goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.FlyoutDragger'], ['Blockly.WorkspaceDragger']); -goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.FlyoutButton', 'Blockly.Flyout', 'Blockly.WorkspaceSvg', 'goog.math.Rect', 'goog.userAgent']); -goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.WorkspaceSvg', 'goog.math.Rect', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.FlyoutButton', 'Blockly.Flyout', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'goog.math.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'goog.math.Rect']); goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block']); goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.utils', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Grid', 'Blockly.Options', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Grid', 'Blockly.Options', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../../" + dir + "/core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.BlockAnimations', 'Blockly.Events.BlockMove', 'Blockly.RenderedConnection', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []); @@ -98,7 +98,8 @@ goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.Touch goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'goog.math.Rect']); goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], []); -goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['goog.dom', 'goog.math.Coordinate', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/useragent.js", ['Blockly.userAgent'], []); +goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.userAgent', 'goog.dom', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/variable_events.js", ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/variable_map.js", ['Blockly.VariableMap'], ['Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/variable_model.js", ['Blockly.VariableModel'], ['Blockly.Events.VarCreate', 'Blockly.utils']); @@ -107,7 +108,7 @@ goog.addDependency("../../../" + dir + "/core/variables_dynamic.js", ['Blockly.V goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.style']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.utils', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']); -goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.userAgent']); goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceComment', 'goog.math.Coordinate']); @@ -116,7 +117,7 @@ goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.W goog.addDependency("../../../" + dir + "/core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.utils', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.dom', 'goog.math.Coordinate']); goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.Xml.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.Xml.utils']); +goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.utils', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/xml_utils.js", ['Blockly.Xml.utils'], []); goog.addDependency("../../../" + dir + "/core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Touch', 'Blockly.utils']); goog.addDependency("../../alltests.js", [], []); @@ -725,7 +726,7 @@ goog.addDependency("i18n/dateintervalpatternsext.js", [], []); goog.addDependency("i18n/dateintervalsymbols.js", [], []); goog.addDependency("i18n/dateintervalsymbolsext.js", [], []); goog.addDependency("i18n/datetimeformat.js", ['goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeFormat.Format'], ['goog.asserts', 'goog.date', 'goog.i18n.DateTimeSymbols', 'goog.i18n.TimeZone', 'goog.string']); -goog.addDependency("i18n/datetimeformat_test.js", ['goog.i18n.DateTimeFormatTest'], ['goog.date.Date', 'goog.date.DateTime', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns', 'goog.i18n.DateTimePatterns_ar_EG', 'goog.i18n.DateTimePatterns_bg', 'goog.i18n.DateTimePatterns_de', 'goog.i18n.DateTimePatterns_en', 'goog.i18n.DateTimePatterns_en_XA', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimePatterns_ja', 'goog.i18n.DateTimePatterns_sv', 'goog.i18n.DateTimePatterns_zh_HK', 'goog.i18n.DateTimePatterns_zh_Hant_TW', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_ar_AE', 'goog.i18n.DateTimeSymbols_ar_EG', 'goog.i18n.DateTimeSymbols_ar_SA', 'goog.i18n.DateTimeSymbols_bn_BD', 'goog.i18n.DateTimeSymbols_de', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_en_GB', 'goog.i18n.DateTimeSymbols_en_IE', 'goog.i18n.DateTimeSymbols_en_IN', 'goog.i18n.DateTimeSymbols_en_US', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.DateTimeSymbols_fr_DJ', 'goog.i18n.DateTimeSymbols_he_IL', 'goog.i18n.DateTimeSymbols_ja', 'goog.i18n.DateTimeSymbols_ro_RO', 'goog.i18n.DateTimeSymbols_sv', 'goog.i18n.TimeZone', 'goog.testing.jsunit']); +goog.addDependency("i18n/datetimeformat_test.js", ['goog.i18n.DateTimeFormatTest'], ['goog.date.Date', 'goog.date.DateTime', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimePatterns', 'goog.i18n.DateTimePatterns_ar_EG', 'goog.i18n.DateTimePatterns_de', 'goog.i18n.DateTimePatterns_en', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimePatterns_ja', 'goog.i18n.DateTimePatterns_sv', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_ar_AE', 'goog.i18n.DateTimeSymbols_ar_EG', 'goog.i18n.DateTimeSymbols_ar_SA', 'goog.i18n.DateTimeSymbols_bn_BD', 'goog.i18n.DateTimeSymbols_de', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_en_GB', 'goog.i18n.DateTimeSymbols_en_IE', 'goog.i18n.DateTimeSymbols_en_IN', 'goog.i18n.DateTimeSymbols_en_US', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.DateTimeSymbols_fr_DJ', 'goog.i18n.DateTimeSymbols_he_IL', 'goog.i18n.DateTimeSymbols_ja', 'goog.i18n.DateTimeSymbols_ro_RO', 'goog.i18n.DateTimeSymbols_sv', 'goog.i18n.TimeZone', 'goog.testing.jsunit']); goog.addDependency("i18n/datetimeparse.js", ['goog.i18n.DateTimeParse'], ['goog.asserts', 'goog.date', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeSymbols']); goog.addDependency("i18n/datetimeparse_test.js", ['goog.i18n.DateTimeParseTest'], ['goog.date.Date', 'goog.i18n.DateTimeFormat', 'goog.i18n.DateTimeParse', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_en', 'goog.i18n.DateTimeSymbols_fa', 'goog.i18n.DateTimeSymbols_fr', 'goog.i18n.DateTimeSymbols_pl', 'goog.i18n.DateTimeSymbols_zh', 'goog.testing.ExpectedFailures', 'goog.testing.jsunit', 'goog.userAgent']); goog.addDependency("i18n/datetimepatterns.js", ['goog.i18n.DateTimePatterns', 'goog.i18n.DateTimePatterns_af', 'goog.i18n.DateTimePatterns_am', 'goog.i18n.DateTimePatterns_ar', 'goog.i18n.DateTimePatterns_ar_DZ', 'goog.i18n.DateTimePatterns_ar_EG', 'goog.i18n.DateTimePatterns_az', 'goog.i18n.DateTimePatterns_be', 'goog.i18n.DateTimePatterns_bg', 'goog.i18n.DateTimePatterns_bn', 'goog.i18n.DateTimePatterns_br', 'goog.i18n.DateTimePatterns_bs', 'goog.i18n.DateTimePatterns_ca', 'goog.i18n.DateTimePatterns_chr', 'goog.i18n.DateTimePatterns_cs', 'goog.i18n.DateTimePatterns_cy', 'goog.i18n.DateTimePatterns_da', 'goog.i18n.DateTimePatterns_de', 'goog.i18n.DateTimePatterns_de_AT', 'goog.i18n.DateTimePatterns_de_CH', 'goog.i18n.DateTimePatterns_el', 'goog.i18n.DateTimePatterns_en', 'goog.i18n.DateTimePatterns_en_AU', 'goog.i18n.DateTimePatterns_en_CA', 'goog.i18n.DateTimePatterns_en_GB', 'goog.i18n.DateTimePatterns_en_IE', 'goog.i18n.DateTimePatterns_en_IN', 'goog.i18n.DateTimePatterns_en_SG', 'goog.i18n.DateTimePatterns_en_US', 'goog.i18n.DateTimePatterns_en_ZA', 'goog.i18n.DateTimePatterns_es', 'goog.i18n.DateTimePatterns_es_419', 'goog.i18n.DateTimePatterns_es_ES', 'goog.i18n.DateTimePatterns_es_MX', 'goog.i18n.DateTimePatterns_es_US', 'goog.i18n.DateTimePatterns_et', 'goog.i18n.DateTimePatterns_eu', 'goog.i18n.DateTimePatterns_fa', 'goog.i18n.DateTimePatterns_fi', 'goog.i18n.DateTimePatterns_fil', 'goog.i18n.DateTimePatterns_fr', 'goog.i18n.DateTimePatterns_fr_CA', 'goog.i18n.DateTimePatterns_ga', 'goog.i18n.DateTimePatterns_gl', 'goog.i18n.DateTimePatterns_gsw', 'goog.i18n.DateTimePatterns_gu', 'goog.i18n.DateTimePatterns_haw', 'goog.i18n.DateTimePatterns_he', 'goog.i18n.DateTimePatterns_hi', 'goog.i18n.DateTimePatterns_hr', 'goog.i18n.DateTimePatterns_hu', 'goog.i18n.DateTimePatterns_hy', 'goog.i18n.DateTimePatterns_id', 'goog.i18n.DateTimePatterns_in', 'goog.i18n.DateTimePatterns_is', 'goog.i18n.DateTimePatterns_it', 'goog.i18n.DateTimePatterns_iw', 'goog.i18n.DateTimePatterns_ja', 'goog.i18n.DateTimePatterns_ka', 'goog.i18n.DateTimePatterns_kk', 'goog.i18n.DateTimePatterns_km', 'goog.i18n.DateTimePatterns_kn', 'goog.i18n.DateTimePatterns_ko', 'goog.i18n.DateTimePatterns_ky', 'goog.i18n.DateTimePatterns_ln', 'goog.i18n.DateTimePatterns_lo', 'goog.i18n.DateTimePatterns_lt', 'goog.i18n.DateTimePatterns_lv', 'goog.i18n.DateTimePatterns_mk', 'goog.i18n.DateTimePatterns_ml', 'goog.i18n.DateTimePatterns_mn', 'goog.i18n.DateTimePatterns_mo', 'goog.i18n.DateTimePatterns_mr', 'goog.i18n.DateTimePatterns_ms', 'goog.i18n.DateTimePatterns_mt', 'goog.i18n.DateTimePatterns_my', 'goog.i18n.DateTimePatterns_nb', 'goog.i18n.DateTimePatterns_ne', 'goog.i18n.DateTimePatterns_nl', 'goog.i18n.DateTimePatterns_no', 'goog.i18n.DateTimePatterns_no_NO', 'goog.i18n.DateTimePatterns_or', 'goog.i18n.DateTimePatterns_pa', 'goog.i18n.DateTimePatterns_pl', 'goog.i18n.DateTimePatterns_pt', 'goog.i18n.DateTimePatterns_pt_BR', 'goog.i18n.DateTimePatterns_pt_PT', 'goog.i18n.DateTimePatterns_ro', 'goog.i18n.DateTimePatterns_ru', 'goog.i18n.DateTimePatterns_sh', 'goog.i18n.DateTimePatterns_si', 'goog.i18n.DateTimePatterns_sk', 'goog.i18n.DateTimePatterns_sl', 'goog.i18n.DateTimePatterns_sq', 'goog.i18n.DateTimePatterns_sr', 'goog.i18n.DateTimePatterns_sr_Latn', 'goog.i18n.DateTimePatterns_sv', 'goog.i18n.DateTimePatterns_sw', 'goog.i18n.DateTimePatterns_ta', 'goog.i18n.DateTimePatterns_te', 'goog.i18n.DateTimePatterns_th', 'goog.i18n.DateTimePatterns_tl', 'goog.i18n.DateTimePatterns_tr', 'goog.i18n.DateTimePatterns_uk', 'goog.i18n.DateTimePatterns_ur', 'goog.i18n.DateTimePatterns_uz', 'goog.i18n.DateTimePatterns_vi', 'goog.i18n.DateTimePatterns_zh', 'goog.i18n.DateTimePatterns_zh_CN', 'goog.i18n.DateTimePatterns_zh_HK', 'goog.i18n.DateTimePatterns_zh_TW', 'goog.i18n.DateTimePatterns_zu'], []); @@ -1842,6 +1843,7 @@ goog.require('Blockly.Xml.utils'); goog.require('Blockly.ZoomControls'); goog.require('Blockly.constants'); goog.require('Blockly.inject'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.uiMenu'); diff --git a/core/block_render_svg.js b/core/block_render_svg.js index d8753a18fb0..6c905293471 100644 --- a/core/block_render_svg.js +++ b/core/block_render_svg.js @@ -28,6 +28,7 @@ goog.provide('Blockly.BlockSvg.render'); goog.require('Blockly.BlockSvg'); +goog.require('Blockly.utils'); /** diff --git a/core/bubble.js b/core/bubble.js index ef2ff9c7146..3d3ace56c53 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Bubble'); goog.require('Blockly.Touch'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.Workspace'); @@ -225,7 +226,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { this.bubbleGroup_ = Blockly.utils.createSvgElement('g', {}, null); var filter = {'filter': 'url(#' + this.workspace_.options.embossFilterId + ')'}; - if (Blockly.utils.userAgent.JAVA_FX) { + if (Blockly.userAgent.JAVA_FX) { // Multiple reports that JavaFX can't handle filters. // https://github.com/google/blockly/issues/99 filter = {}; diff --git a/core/comment.js b/core/comment.js index f269e5ec636..73a9c669528 100644 --- a/core/comment.js +++ b/core/comment.js @@ -30,6 +30,7 @@ goog.require('Blockly.Bubble'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); @@ -183,7 +184,7 @@ Blockly.Comment.prototype.setVisible = function(visible) { Blockly.Events.fire( new Blockly.Events.Ui(this.block_, 'commentOpen', !visible, visible)); if ((!this.block_.isEditable() && !this.textarea_) || - Blockly.utils.userAgent.IE) { + Blockly.userAgent.IE) { // Steal the code from warnings to make an uneditable text bubble. // MSIE does not support foreignobject; textareas are impossible. // https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-svg/56e6e04c-7c8c-44dd-8100-bd745ee42034 diff --git a/core/contextmenu.js b/core/contextmenu.js index e8e75f18d56..f9e7a39bd3c 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -31,6 +31,7 @@ goog.provide('Blockly.ContextMenu'); goog.require('Blockly.Events.BlockCreate'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.uiMenu'); goog.require('Blockly.Xml'); @@ -279,7 +280,7 @@ Blockly.ContextMenu.blockDuplicateOption = function(block) { */ Blockly.ContextMenu.blockCommentOption = function(block) { var commentOption = { - enabled: !Blockly.utils.userAgent.IE + enabled: !Blockly.userAgent.IE }; // If there's already a comment, add an option to delete it. if (block.comment) { @@ -387,7 +388,7 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { var wsCommentOption = { // Foreign objects don't work in IE. Don't let the user create comments // that they won't be able to edit. - enabled: !Blockly.utils.userAgent.IE + enabled: !Blockly.userAgent.IE }; wsCommentOption.text = Blockly.Msg.ADD_COMMENT; wsCommentOption.callback = function() { diff --git a/core/field.js b/core/field.js index 54d4cf657b3..6ce1aa79eb5 100644 --- a/core/field.js +++ b/core/field.js @@ -30,6 +30,7 @@ goog.provide('Blockly.Field'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('goog.math.Size'); @@ -495,7 +496,7 @@ Blockly.Field.getCachedWidth = function(textElement) { // Attempt to compute fetch the width of the SVG text element. try { - if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { + if (Blockly.userAgent.IE || Blockly.userAgent.EDGE) { width = textElement.getBBox().width; } else { width = textElement.getComputedTextLength(); diff --git a/core/field_angle.js b/core/field_angle.js index 3fb335bd144..2c29395e4e5 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -28,6 +28,7 @@ goog.provide('Blockly.FieldAngle'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); @@ -161,9 +162,9 @@ Blockly.FieldAngle.prototype.dispose_ = function() { */ Blockly.FieldAngle.prototype.showEditor_ = function() { var noFocus = - Blockly.utils.userAgent.MOBILE || - Blockly.utils.userAgent.ANDROID || - Blockly.utils.userAgent.IPAD; + Blockly.userAgent.MOBILE || + Blockly.userAgent.ANDROID || + Blockly.userAgent.IPAD; // Mobile browsers have issues with in-line textareas (focus & keyboards). Blockly.FieldAngle.superClass_.showEditor_.call(this, noFocus); diff --git a/core/field_colour.js b/core/field_colour.js index 8ec1bc22370..f3d17df1f38 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -28,7 +28,6 @@ goog.provide('Blockly.FieldColour'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Field'); -goog.require('Blockly.utils'); goog.require('goog.style'); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index a0c18f3d01f..cbfded728c9 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -29,6 +29,7 @@ goog.provide('Blockly.FieldDropdown'); goog.require('Blockly.Field'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.uiMenu'); @@ -97,7 +98,7 @@ Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45; * Android can't (in 2014) display "▾", so use "▼" instead. */ Blockly.FieldDropdown.ARROW_CHAR = - Blockly.utils.userAgent.ANDROID ? '\u25BC' : '\u25BE'; + Blockly.userAgent.ANDROID ? '\u25BC' : '\u25BE'; /** * Mouse cursor style when over the hotspot that initiates the editor. @@ -526,7 +527,7 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { */ Blockly.FieldDropdown.prototype.updateWidth = function() { if (this.imageJson_ && - (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE)) { + (Blockly.userAgent.IE || Blockly.userAgent.EDGE)) { // Recalculate the full width. var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_); var width = Number(this.imageJson_.width) + arrowWidth + diff --git a/core/field_label_serializable.js b/core/field_label_serializable.js index 26bf1818562..182ecbbd4dd 100644 --- a/core/field_label_serializable.js +++ b/core/field_label_serializable.js @@ -28,6 +28,7 @@ goog.provide('Blockly.FieldLabelSerializable'); goog.require('Blockly.FieldLabel'); +goog.require('Blockly.utils'); /** diff --git a/core/field_textinput.js b/core/field_textinput.js index 251d0689877..3fd38c0284b 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -29,6 +29,7 @@ goog.provide('Blockly.FieldTextInput'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('goog.math.Coordinate'); @@ -165,9 +166,9 @@ Blockly.FieldTextInput.prototype.setSpellcheck = function(check) { Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) { this.workspace_ = this.sourceBlock_.workspace; var quietInput = opt_quietInput || false; - if (!quietInput && (Blockly.utils.userAgent.MOBILE || - Blockly.utils.userAgent.ANDROID || - Blockly.utils.userAgent.IPAD)) { + if (!quietInput && (Blockly.userAgent.MOBILE || + Blockly.userAgent.ANDROID || + Blockly.userAgent.IPAD)) { this.showPromptEditor_(); } else { this.showInlineEditor_(quietInput); @@ -301,7 +302,7 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { this.setValue(text); Blockly.Events.setGroup(false); this.validate_(); - } else if (Blockly.utils.userAgent.WEBKIT) { + } else if (Blockly.userAgent.WEBKIT) { // Cursor key. Render the source block to show the caret moving. // Chrome only (version 26, OS X). this.sourceBlock_.render(); @@ -348,13 +349,13 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { // Shift by a few pixels to line up exactly. xy.y += 1; - if (Blockly.utils.userAgent.GECKO && Blockly.WidgetDiv.DIV.style.top) { + if (Blockly.userAgent.GECKO && Blockly.WidgetDiv.DIV.style.top) { // Firefox mis-reports the location of the border by a pixel // once the WidgetDiv is moved into position. xy.x -= 1; xy.y -= 1; } - if (Blockly.utils.userAgent.WEBKIT) { + if (Blockly.userAgent.WEBKIT) { xy.y -= 3; } div.style.left = xy.x + 'px'; diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index 4000aa81d33..be8426bb190 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -30,6 +30,7 @@ goog.require('Blockly.Block'); goog.require('Blockly.Events'); goog.require('Blockly.FlyoutButton'); goog.require('Blockly.Flyout'); +goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); goog.require('goog.math.Rect'); diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 417a3e4f6cd..a2fe351a436 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -30,6 +30,7 @@ goog.require('Blockly.Block'); goog.require('Blockly.Events'); goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); @@ -337,7 +338,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { // Firefox sometimes reports the wrong value for the client rect. // See https://github.com/google/blockly/issues/1425 and // https://bugzilla.mozilla.org/show_bug.cgi?id=1066435 - if (Blockly.utils.userAgent.GECKO && + if (Blockly.userAgent.GECKO && this.targetWorkspace_ && this.targetWorkspace_.isMutator) { // The position of the left side of the mutator workspace in pixels // relative to the window origin. diff --git a/core/grid.js b/core/grid.js index 52669ca519b..9322dea37ad 100644 --- a/core/grid.js +++ b/core/grid.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Grid'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); @@ -185,7 +186,7 @@ Blockly.Grid.prototype.moveTo = function(x, y) { this.gridPattern_.setAttribute('x', x); this.gridPattern_.setAttribute('y', y); - if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { + if (Blockly.userAgent.IE || Blockly.userAgent.EDGE) { // IE/Edge doesn't notice that the x/y offsets have changed. // Force an update. this.update(this.scale_); diff --git a/core/inject.js b/core/inject.js index deeb6c63a81..8ecd1e1f7d3 100644 --- a/core/inject.js +++ b/core/inject.js @@ -31,6 +31,7 @@ goog.require('Blockly.Css'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Grid'); goog.require('Blockly.Options'); +goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.WorkspaceDragSurfaceSvg'); @@ -433,7 +434,7 @@ Blockly.inject.bindDocumentEvents_ = function() { Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); Blockly.bindEvent_(document, 'touchcancel', null, Blockly.longStop_); // Some iPad versions don't fire resize after portrait to landscape change. - if (Blockly.utils.userAgent.IPAD) { + if (Blockly.userAgent.IPAD) { Blockly.bindEventWithChecks_(window, 'orientationchange', document, function() { // TODO (#397): Fix for multiple Blockly workspaces. diff --git a/core/useragent.js b/core/useragent.js new file mode 100644 index 00000000000..1abc62855cb --- /dev/null +++ b/core/useragent.js @@ -0,0 +1,78 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Useragent detection. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.userAgent + * @namespace + */ +goog.provide('Blockly.userAgent'); + + +(function(raw) { + Blockly.userAgent.raw = raw; + var rawUpper = Blockly.userAgent.raw.toUpperCase(); + /** + * Case-insensitive test of whether name is in the useragent string. + * @param {string} name Name to test. + * @return {boolean} True if name is present. + */ + function has(name) { + return rawUpper.indexOf(name.toUpperCase()) != -1; + } + + // Browsers. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/browser.js + Blockly.userAgent.IE = has('Trident') || has('MSIE'); + Blockly.userAgent.EDGE = has('Edge'); + // Useragent for JavaFX: + // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 + // (KHTML, like Gecko) JavaFX/8.0 Safari/537.44 + Blockly.userAgent.JAVA_FX = has('JavaFX'); + + // Engines. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js + Blockly.userAgent.WEBKIT = has('WebKit') && + !Blockly.userAgent.EDGE; + Blockly.userAgent.GECKO = has('Gecko') && !Blockly.userAgent.WEBKIT && + !Blockly.userAgent.IE && !Blockly.userAgent.EDGE; + + // Platforms. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js + Blockly.userAgent.ANDROID = has('Android'); + Blockly.userAgent.IPAD = has('iPad'); + Blockly.userAgent.IPOD = has('iPod'); + Blockly.userAgent.IPHONE = has('iPhone') && + !Blockly.userAgent.IPAD && !Blockly.userAgent.IPOD; + Blockly.userAgent.MAC = has('Macintosh'); + + // Devices. Logic from: + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/device.js + Blockly.userAgent.TABLET = Blockly.userAgent.IPAD || + (Blockly.userAgent.ANDROID && !has('Mobile')) || has('Silk'); + Blockly.userAgent.MOBILE = !Blockly.userAgent.TABLET && + (Blockly.userAgent.IPOD || Blockly.userAgent.IPHONE || + Blockly.userAgent.ANDROID || has('IEMobile')); +})((this.navigator && this.navigator.userAgent) || ''); diff --git a/core/utils.js b/core/utils.js index 52187c16059..9c08ee8cc2d 100644 --- a/core/utils.js +++ b/core/utils.js @@ -32,6 +32,8 @@ */ goog.provide('Blockly.utils'); +goog.require('Blockly.userAgent'); + goog.require('goog.dom'); goog.require('goog.math.Coordinate'); @@ -258,7 +260,7 @@ Blockly.utils.createSvgElement = function(name, attrs, parent) { * @return {boolean} True if right-click. */ Blockly.utils.isRightButton = function(e) { - if (e.ctrlKey && Blockly.utils.userAgent.MAC) { + if (e.ctrlKey && Blockly.userAgent.MAC) { // Control-clicking on Mac OS X is treated as a right-click. // WebKit on Mac OS X fails to change button to 2 (but Gecko does). return true; @@ -1027,51 +1029,3 @@ Blockly.utils.clampNumber = function(lowerBound, number, upperBound) { } return Math.max(lowerBound, Math.min(number, upperBound)); }; - -Blockly.utils.userAgent = {}; -(function(raw) { - Blockly.utils.userAgent.raw = raw; - var rawUpper = Blockly.utils.userAgent.raw.toUpperCase(); - /** - * Case-insensitive test of whether name is in the useragent string. - * @param {string} name Name to test. - * @return {boolean} True if name is present. - */ - function has(name) { - return rawUpper.indexOf(name.toUpperCase()) != -1; - } - - // Browsers. Logic from: - // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/browser.js - Blockly.utils.userAgent.IE = has('Trident') || has('MSIE'); - Blockly.utils.userAgent.EDGE = has('Edge'); - // Useragent for JavaFX: - // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 - // (KHTML, like Gecko) JavaFX/8.0 Safari/537.44 - Blockly.utils.userAgent.JAVA_FX = has('JavaFX'); - - // Engines. Logic from: - // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js - Blockly.utils.userAgent.WEBKIT = has('WebKit') && - !Blockly.utils.userAgent.EDGE; - Blockly.utils.userAgent.GECKO = has('Gecko') && - !Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE; - - // Platforms. Logic from: - // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js - Blockly.utils.userAgent.ANDROID = has('Android'); - Blockly.utils.userAgent.IPAD = has('iPad'); - Blockly.utils.userAgent.IPOD = has('iPod'); - Blockly.utils.userAgent.IPHONE = has('iPhone') && - !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; - Blockly.utils.userAgent.MAC = has('Macintosh'); - - // Devices. Logic from: - // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/device.js - Blockly.utils.userAgent.TABLET = Blockly.utils.userAgent.IPAD || - (Blockly.utils.userAgent.ANDROID && !has('Mobile')) || has('Silk'); - Blockly.utils.userAgent.MOBILE = !Blockly.utils.userAgent.TABLET && - (Blockly.utils.userAgent.IPOD || Blockly.utils.userAgent.IPHONE || - Blockly.utils.userAgent.ANDROID || has('IEMobile')); -})((this.navigator && this.navigator.userAgent) || ''); - diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 8d58c415661..9e0402551b8 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -27,7 +27,7 @@ goog.provide('Blockly.WorkspaceAudio'); -goog.require('Blockly.utils'); +goog.require('Blockly.userAgent'); /** @@ -115,7 +115,7 @@ Blockly.WorkspaceAudio.prototype.preload = function() { sound.pause(); // iOS can only process one sound at a time. Trying to load more than one // corrupts the earlier ones. Just load one and leave the others uncached. - if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.IPHONE) { + if (Blockly.userAgent.IPAD || Blockly.userAgent.IPHONE) { break; } } @@ -138,7 +138,7 @@ Blockly.WorkspaceAudio.prototype.play = function(name, opt_volume) { } this.lastSound_ = now; var mySound; - if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.ANDROID) { + if (Blockly.userAgent.IPAD || Blockly.userAgent.ANDROID) { // Creating a new audio node causes lag in Android and iPad. Android // refetches the file from the server, iPad uses a singleton audio // node which must be deleted and recreated for each new audio tag. diff --git a/core/xml.js b/core/xml.js index d953c87e396..75978deeeb7 100644 --- a/core/xml.js +++ b/core/xml.js @@ -33,6 +33,7 @@ goog.provide('Blockly.Xml'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.FinishedLoading'); goog.require('Blockly.Events.VarCreate'); +goog.require('Blockly.utils'); goog.require('Blockly.Xml.utils'); From 6d962e5f87c1faa552cb82a09a8d314b49a19088 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 13 May 2019 14:27:56 +0200 Subject: [PATCH 052/233] Localisation updates from https://translatewiki.net. --- msg/json/eo.json | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/msg/json/eo.json b/msg/json/eo.json index 621c91094ef..795c0d120f7 100644 --- a/msg/json/eo.json +++ b/msg/json/eo.json @@ -5,7 +5,8 @@ "Ochilov", "Orikrin1998", "Robin van der Vliet", - "Cérilew" + "Cérilew", + "Mirin" ] }, "VARIABLES_DEFAULT_NAME": "elemento", @@ -32,6 +33,10 @@ "RENAME_VARIABLE": "Renomi varianton...", "RENAME_VARIABLE_TITLE": "Renomi ĉiujn '%1' variantojn kiel:", "NEW_VARIABLE": "Nova varianto...", + "NEW_STRING_VARIABLE": "Krei signoĉenan variablon...", + "NEW_NUMBER_VARIABLE": "Krei nombran variablon...", + "NEW_COLOUR_VARIABLE": "Krei koloran variablon...", + "NEW_VARIABLE_TYPE_TITLE": "Tipo de nova variablo:", "NEW_VARIABLE_TITLE": "Nova nomo de varianto:", "VARIABLE_ALREADY_EXISTS": "Jam ekzistas varianto kun la nomo '%1'.", "DELETE_VARIABLE_CONFIRMATION": "Ĉu forigi %1 uzojn de la varianto '%2'?", @@ -67,6 +72,15 @@ "CONTROLS_IF_MSG_ELSE": "alie", "CONTROLS_IF_ELSEIF_TOOLTIP": "Aldoni kondiĉon al la bloko 'se'", "CONTROLS_IF_ELSE_TOOLTIP": "Aldoni 'aliokaze' kondiĉon al la 'se' bloko.", + "IOS_OK": "Bone", + "IOS_CANCEL": "Nuligi", + "IOS_ERROR": "Eraro", + "IOS_PROCEDURES_INPUTS": "ENIGOJ", + "IOS_VARIABLES_ADD_VARIABLE": "+ Aldoni Variablon", + "IOS_VARIABLES_ADD_BUTTON": "Aldoni", + "IOS_VARIABLES_RENAME_BUTTON": "Alinomigi", + "IOS_VARIABLES_DELETE_BUTTON": "Forigi", + "IOS_VARIABLES_VARIABLE_NAME": "Nomo de variablo", "LOGIC_COMPARE_HELPURL": "https://eo.wikipedia.org/wiki/Neegala%C4%B5o_(pli_granda,_malpli_granda)", "LOGIC_COMPARE_TOOLTIP_EQ": "Vero estos liverita, se la du eniroj egalas.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Vero estos liverita, se la du eniroj ne egalas.", @@ -83,6 +97,8 @@ "LOGIC_BOOLEAN_TRUE": "vera", "LOGIC_BOOLEAN_FALSE": "falsa", "LOGIC_BOOLEAN_TOOLTIP": "La rezulto egalas ĉu vero, ĉu malvero.", + "LOGIC_NULL": "senvalora", + "LOGIC_NULL_TOOLTIP": "Liveras senvaloron.", "LOGIC_TERNARY_CONDITION": "testi", "LOGIC_TERNARY_IF_TRUE": "se estas vero", "LOGIC_TERNARY_IF_FALSE": "se estas malvero", @@ -104,7 +120,11 @@ "MATH_SINGLE_TOOLTIP_LOG10": "La dekbaza logaritmo de numero estos liverita.", "MATH_SINGLE_TOOLTIP_EXP": "La rezulto de la potenco de e je la nombro.", "MATH_TRIG_HELPURL": "https://eo.wikipedia.org/wiki/Trigonometria_funkcio", + "MATH_TRIG_TOOLTIP_SIN": "Liveras la sinuson de angulo en gradoj (ne radianoj).", + "MATH_TRIG_TOOLTIP_COS": "Liveras la kosinuson de angulo en gradoj (ne radianoj).", + "MATH_TRIG_TOOLTIP_TAN": "Liveras la tangenton de angulo en gradoj (ne radianoj).", "MATH_TRIG_TOOLTIP_ASIN": "La sinusarko de nombro estos liverita.", + "MATH_TRIG_TOOLTIP_ACOS": "Liveras la arkokosinuson de nombro.", "MATH_TRIG_TOOLTIP_ATAN": "La targentarko de nombro estos liverita.", "MATH_CONSTANT_HELPURL": "https://eo.wikipedia.org/wiki/Matematika_konstanto", "MATH_IS_EVEN": "estas para", @@ -115,6 +135,7 @@ "MATH_IS_NEGATIVE": "estas negativa", "MATH_IS_DIVISIBLE_BY": "estas dividebla de", "MATH_IS_TOOLTIP": "Vero aŭ malvero estos liverita, depende de la rezulto de kontrolo, ĉu nombro estas para, nepara, pozitiva, negativa, aŭ dividebla de iu nombro.", + "MATH_CHANGE_TITLE": "krementi %1 per %2", "MATH_CHANGE_TOOLTIP": "Aldoni nombro al varianto '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Rondigi nombroj, supren aŭ malsupren.", @@ -142,10 +163,19 @@ "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "hazarda entjero inter %1 kaj %2", "MATH_RANDOM_INT_TOOLTIP": "Nombro estos hazarde liverita, tiel ke ĝi egalas la limojn aŭ troviĝas inter ili.", + "MATH_RANDOM_FLOAT_TITLE_RANDOM": "hazarda frakcio", + "MATH_ATAN2_TITLE": "atan2 de X:%1 Y:%2", + "MATH_ATAN2_TOOLTIP": "Liveri la arkotangenton de punkto (X, Y) en gradoj inter -180 kaj 180.", + "TEXT_TEXT_HELPURL": "https://eo.wikipedia.org/wiki/Signo%C4%89eno", + "TEXT_JOIN_TITLE_CREATEWITH": "krei tekston kun", + "TEXT_CREATE_JOIN_TITLE_JOIN": "kunigi", "TEXT_LENGTH_TITLE": "longo de %1", "TEXT_ISEMPTY_TITLE": "%1 malplenas", "TEXT_INDEXOF_TITLE": "en la teksto %1 %2 %3", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "en la teksto", + "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "MAJUSKLIGI", + "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "minuskligi", + "TEXT_CHANGECASE_OPERATOR_TITLECASE": "Nomuskligi", "TEXT_TRIM_OPERATOR_RIGHT": "forigi spacojn el la dekstra flanko de", "TEXT_PRINT_TITLE": "presi %1", "TEXT_PRINT_TOOLTIP": "Presi la specifitan tekston, nombron aŭ alian valoron.", @@ -192,6 +222,19 @@ "LISTS_SET_INDEX_SET": "difini", "LISTS_SET_INDEX_INSERT": "enmeti je", "LISTS_SET_INDEX_INPUT_TO": "kiel", + "LISTS_SORT_TYPE_NUMERIC": "nombre", + "LISTS_SORT_TYPE_TEXT": "alfabete", + "LISTS_SORT_TYPE_IGNORECASE": "alfabete, ignorante usklon", + "LISTS_SPLIT_LIST_FROM_TEXT": "fari liston el teksto", + "LISTS_SPLIT_TEXT_FROM_LIST": "fari tekston el listo", + "LISTS_SPLIT_WITH_DELIMITER": "kun apartigilo", + "PROCEDURES_DEFNORETURN_PROCEDURE": "fari ion", + "PROCEDURES_BEFORE_PARAMS": "kun:", + "PROCEDURES_CALL_BEFORE_PARAMS": "kun:", + "PROCEDURES_DEFRETURN_RETURN": "liveri", + "PROCEDURES_MUTATORCONTAINER_TITLE": "enigoj", + "PROCEDURES_MUTATORARG_TITLE": "nomo de enigo:", + "PROCEDURES_MUTATORARG_TOOLTIP": "Aldoni enigon al la funkcio.", "PROCEDURES_CREATE_DO": "Krei '%1'", "WORKSPACE_COMMENT_DEFAULT_TEXT": "Diru ion…" } From ba18ae2159186f6b3aa8adb2bcbc655c1586bbe2 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 10 May 2019 23:19:35 -0700 Subject: [PATCH 053/233] Add STATEMENT_SUFFIX Also remove need to manually indent INFINITE_LOOP_TRAP. This is a breaking change for Python users of this property. However, very few users of this property exist, given that the existing code breaks if the block ID has a $ in it (also fixed in this PR). --- core/generator.js | 25 ++++++++++++++++++++++--- demos/code/code.js | 2 +- generators/dart/procedures.js | 18 ++++++++++++------ generators/javascript/procedures.js | 18 ++++++++++++------ generators/lua/procedures.js | 18 ++++++++++++------ generators/php/procedures.js | 18 ++++++++++++------ generators/python/procedures.js | 18 ++++++++++++------ 7 files changed, 83 insertions(+), 34 deletions(-) diff --git a/core/generator.js b/core/generator.js index 13cfc33581f..adacfbd086a 100644 --- a/core/generator.js +++ b/core/generator.js @@ -62,6 +62,14 @@ Blockly.Generator.prototype.INFINITE_LOOP_TRAP = null; */ Blockly.Generator.prototype.STATEMENT_PREFIX = null; +/** + * Arbitrary code to inject after every statement. + * Any instances of '%1' will be replaced by the block ID of the statement. + * E.g. 'highlight(%1);\n' + * @type {?string} + */ +Blockly.Generator.prototype.STATEMENT_SUFFIX = null; + /** * The method of indenting. Defaults to two spaces, but language generators * may override this to increase indent or change to tabs. @@ -126,6 +134,7 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) { /** * Prepend a common prefix onto each line of code. + * Intended for indenting code or adding comment markers. * @param {string} text The lines of code. * @param {string} prefix The common prefix. * @return {string} The prefixed lines of code. @@ -193,6 +202,9 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { if (this.STATEMENT_PREFIX) { code = this.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\'') + code; } + if (this.STATEMENT_SUFFIX) { + code = code + this.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''); + } return this.scrub_(block, code, opt_thisOnly); } else if (code === null) { // Block has handled code generation itself. @@ -299,7 +311,9 @@ Blockly.Generator.prototype.statementToCode = function(block, name) { /** * Add an infinite loop trap to the contents of a loop. - * If loop is empty, add a statment prefix for the loop block. + * Add statement suffix at the start of the loop block (right after the loop + * statement executes), and a statement prefix to the end of the loop block + * (right before the loop statement executes). * @param {string} branch Code for loop contents. * @param {string} id ID of enclosing block. * @return {string} Loop contents, with infinite loop trap added. @@ -307,10 +321,15 @@ Blockly.Generator.prototype.statementToCode = function(block, name) { Blockly.Generator.prototype.addLoopTrap = function(branch, id) { id = id.replace(/\$/g, '$$$$'); // Issue 251. if (this.INFINITE_LOOP_TRAP) { - branch = this.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\'') + branch; + branch = this.prefixLines(this.INFINITE_LOOP_TRAP.replace(/%1/g, + '\'' + id + '\''), this.INDENT) + branch; + } + if (this.STATEMENT_SUFFIX) { + branch = this.prefixLines(this.STATEMENT_SUFFIX.replace(/%1/g, + '\'' + id + '\''), this.INDENT) + branch; } if (this.STATEMENT_PREFIX) { - branch += this.prefixLines(this.STATEMENT_PREFIX.replace(/%1/g, + branch = branch + this.prefixLines(this.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), this.INDENT); } return branch; diff --git a/demos/code/code.js b/demos/code/code.js index 7ffed86bdbb..7128adfc76c 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -516,7 +516,7 @@ Code.initLanguage = function() { * Just a quick and dirty eval. Catch infinite loops. */ Code.runJS = function() { - Blockly.JavaScript.INFINITE_LOOP_TRAP = ' checkTimeout();\n'; + Blockly.JavaScript.INFINITE_LOOP_TRAP = 'checkTimeout();\n'; var timeouts = 0; var checkTimeout = function() { if (timeouts++ > 1000000) { diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index 7e61ab56cb7..b9daf055ae3 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -34,15 +34,21 @@ Blockly.Dart['procedures_defreturn'] = function(block) { var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Dart.statementToCode(block, 'STACK'); - if (Blockly.Dart.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.Dart.STATEMENT_SUFFIX) { branch = Blockly.Dart.prefixLines( - Blockly.Dart.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), Blockly.Dart.INDENT) + branch; + Blockly.Dart.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.INDENT) + branch; } if (Blockly.Dart.INFINITE_LOOP_TRAP) { - branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.Dart.prefixLines( + Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.INDENT) + branch; + } + if (Blockly.Dart.STATEMENT_PREFIX) { + branch = Blockly.Dart.prefixLines( + Blockly.Dart.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.INDENT) + branch; } var returnValue = Blockly.Dart.valueToCode(block, 'RETURN', Blockly.Dart.ORDER_NONE) || ''; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index 7ed4da794df..a3f9c88d65d 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -34,15 +34,21 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.JavaScript.statementToCode(block, 'STACK'); - if (Blockly.JavaScript.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.JavaScript.STATEMENT_SUFFIX) { branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), Blockly.JavaScript.INDENT) + branch; + Blockly.JavaScript.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.INDENT) + branch; } if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { - branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.JavaScript.prefixLines( + Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.INDENT) + branch; + } + if (Blockly.JavaScript.STATEMENT_PREFIX) { + branch = Blockly.JavaScript.prefixLines( + Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.INDENT) + branch; } var returnValue = Blockly.JavaScript.valueToCode(block, 'RETURN', Blockly.JavaScript.ORDER_NONE) || ''; diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 07626b65a9d..58c32baba6a 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -34,15 +34,21 @@ Blockly.Lua['procedures_defreturn'] = function(block) { var funcName = Blockly.Lua.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Lua.statementToCode(block, 'STACK'); - if (Blockly.Lua.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.Lua.STATEMENT_SUFFIX) { branch = Blockly.Lua.prefixLines( - Blockly.Lua.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), Blockly.Lua.INDENT) + branch; + Blockly.Lua.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.INDENT) + branch; } if (Blockly.Lua.INFINITE_LOOP_TRAP) { - branch = Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.Lua.prefixLines( + Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.INDENT) + branch; + } + if (Blockly.Lua.STATEMENT_PREFIX) { + branch = Blockly.Lua.prefixLines( + Blockly.Lua.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.INDENT) + branch; } var returnValue = Blockly.Lua.valueToCode(block, 'RETURN', Blockly.Lua.ORDER_NONE) || ''; diff --git a/generators/php/procedures.js b/generators/php/procedures.js index c81eab3441c..d93d7cb6386 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -55,15 +55,21 @@ Blockly.PHP['procedures_defreturn'] = function(block) { var funcName = Blockly.PHP.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.PHP.statementToCode(block, 'STACK'); - if (Blockly.PHP.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.PHP.STATEMENT_SUFFIX) { branch = Blockly.PHP.prefixLines( - Blockly.PHP.STATEMENT_PREFIX.replace( - /%1/g, '\'' + id + '\''), Blockly.PHP.INDENT) + branch; + Blockly.PHP.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.INDENT) + branch; } if (Blockly.PHP.INFINITE_LOOP_TRAP) { - branch = Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + block.id + '\'') + branch; + branch = Blockly.PHP.prefixLines( + Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.INDENT) + branch; + } + if (Blockly.PHP.STATEMENT_PREFIX) { + branch = Blockly.PHP.prefixLines( + Blockly.PHP.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.INDENT) + branch; } var returnValue = Blockly.PHP.valueToCode(block, 'RETURN', Blockly.PHP.ORDER_NONE) || ''; diff --git a/generators/python/procedures.js b/generators/python/procedures.js index 520b3f5892d..c95c279f1fb 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -56,15 +56,21 @@ Blockly.Python['procedures_defreturn'] = function(block) { var funcName = Blockly.Python.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Python.statementToCode(block, 'STACK'); - if (Blockly.Python.STATEMENT_PREFIX) { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + if (Blockly.Python.STATEMENT_SUFFIX) { branch = Blockly.Python.prefixLines( - Blockly.Python.STATEMENT_PREFIX.replace( - /%1/g, '\'' + id + '\''), Blockly.Python.INDENT) + branch; + Blockly.Python.STATEMENT_SUFFIX.replace( /%1/g, '\'' + id + '\''), + Blockly.Python.INDENT) + branch; } if (Blockly.Python.INFINITE_LOOP_TRAP) { - branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, - '"' + block.id + '"') + branch; + branch = Blockly.Python.prefixLines( + Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Python.INDENT) + branch; + } + if (Blockly.Python.STATEMENT_PREFIX) { + branch = Blockly.Python.prefixLines( + Blockly.Python.STATEMENT_PREFIX.replace( /%1/g, '\'' + id + '\''), + Blockly.Python.INDENT) + branch; } var returnValue = Blockly.Python.valueToCode(block, 'RETURN', Blockly.Python.ORDER_NONE) || ''; From 0259f8bb486fd76f0e3d4fdb262d57ed33c60214 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 13 May 2019 14:26:38 -0700 Subject: [PATCH 054/233] Add extra suffix when generating if/return block. Also fix loops in Lua. --- core/generator.js | 34 ++++++++++++------- generators/dart/loops.js | 8 ++--- generators/dart/procedures.js | 14 +++++--- generators/javascript/loops.js | 8 ++--- generators/javascript/procedures.js | 17 +++++++--- generators/lua/loops.js | 52 ++++++++++++++--------------- generators/lua/procedures.js | 14 +++++--- generators/php/loops.js | 8 ++--- generators/php/procedures.js | 15 ++++++--- generators/python/loops.js | 12 +++---- generators/python/procedures.js | 14 +++++--- 11 files changed, 117 insertions(+), 79 deletions(-) diff --git a/core/generator.js b/core/generator.js index adacfbd086a..81fdf199443 100644 --- a/core/generator.js +++ b/core/generator.js @@ -198,12 +198,11 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { } return [this.scrub_(block, code[0], opt_thisOnly), code[1]]; } else if (typeof code == 'string') { - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (this.STATEMENT_PREFIX) { - code = this.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\'') + code; + code = this.injectId(this.STATEMENT_PREFIX, block) + code; } if (this.STATEMENT_SUFFIX) { - code = code + this.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''); + code = code + this.injectId(this.STATEMENT_SUFFIX, block); } return this.scrub_(block, code, opt_thisOnly); } else if (code === null) { @@ -315,26 +314,37 @@ Blockly.Generator.prototype.statementToCode = function(block, name) { * statement executes), and a statement prefix to the end of the loop block * (right before the loop statement executes). * @param {string} branch Code for loop contents. - * @param {string} id ID of enclosing block. + * @param {!Blockly.Block} block Enclosing block. * @return {string} Loop contents, with infinite loop trap added. */ -Blockly.Generator.prototype.addLoopTrap = function(branch, id) { - id = id.replace(/\$/g, '$$$$'); // Issue 251. +Blockly.Generator.prototype.addLoopTrap = function(branch, block) { if (this.INFINITE_LOOP_TRAP) { - branch = this.prefixLines(this.INFINITE_LOOP_TRAP.replace(/%1/g, - '\'' + id + '\''), this.INDENT) + branch; + branch = this.prefixLines(this.injectId(this.INFINITE_LOOP_TRAP, block), + this.INDENT) + branch; } if (this.STATEMENT_SUFFIX) { - branch = this.prefixLines(this.STATEMENT_SUFFIX.replace(/%1/g, - '\'' + id + '\''), this.INDENT) + branch; + branch = this.prefixLines(this.injectId(this.STATEMENT_SUFFIX, block), + this.INDENT) + branch; } if (this.STATEMENT_PREFIX) { - branch = branch + this.prefixLines(this.STATEMENT_PREFIX.replace(/%1/g, - '\'' + id + '\''), this.INDENT); + branch = branch + this.prefixLines(this.injectId(this.STATEMENT_PREFIX, + block), this.INDENT); } return branch; }; +/** + * Inject a block ID into a message to replace '%1'. + * Used for STATEMENT_PREFIX, STATEMENT_SUFFIX, and INFINITE_LOOP_TRAP. + * @param {string} msg Code snippet with '%1'. + * @param {!Blockly.Block} block Block which has an ID. + * @return {string} Code snippet with ID. + */ +Blockly.Generator.prototype.injectId = function(msg, block) { + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + return msg.replace(/%1/g, '\'' + id + '\''); +} + /** * Comma-separated list of reserved words. * @type {string} diff --git a/generators/dart/loops.js b/generators/dart/loops.js index 6c83a2fd5c0..c0d3bf9aa61 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -40,7 +40,7 @@ Blockly.Dart['controls_repeat_ext'] = function(block) { Blockly.Dart.ORDER_ASSIGNMENT) || '0'; } var branch = Blockly.Dart.statementToCode(block, 'DO'); - branch = Blockly.Dart.addLoopTrap(branch, block.id); + branch = Blockly.Dart.addLoopTrap(branch, block); var code = ''; var loopVar = Blockly.Dart.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); @@ -66,7 +66,7 @@ Blockly.Dart['controls_whileUntil'] = function(block) { until ? Blockly.Dart.ORDER_UNARY_PREFIX : Blockly.Dart.ORDER_NONE) || 'false'; var branch = Blockly.Dart.statementToCode(block, 'DO'); - branch = Blockly.Dart.addLoopTrap(branch, block.id); + branch = Blockly.Dart.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } @@ -84,7 +84,7 @@ Blockly.Dart['controls_for'] = function(block) { var increment = Blockly.Dart.valueToCode(block, 'BY', Blockly.Dart.ORDER_ASSIGNMENT) || '1'; var branch = Blockly.Dart.statementToCode(block, 'DO'); - branch = Blockly.Dart.addLoopTrap(branch, block.id); + branch = Blockly.Dart.addLoopTrap(branch, block); var code; if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) && Blockly.isNumber(increment)) { @@ -145,7 +145,7 @@ Blockly.Dart['controls_forEach'] = function(block) { var argument0 = Blockly.Dart.valueToCode(block, 'LIST', Blockly.Dart.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.Dart.statementToCode(block, 'DO'); - branch = Blockly.Dart.addLoopTrap(branch, block.id); + branch = Blockly.Dart.addLoopTrap(branch, block); var code = 'for (var ' + variable0 + ' in ' + argument0 + ') {\n' + branch + '}\n'; return code; diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index b9daf055ae3..5af422147a9 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -34,20 +34,19 @@ Blockly.Dart['procedures_defreturn'] = function(block) { var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Dart.statementToCode(block, 'STACK'); - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (Blockly.Dart.STATEMENT_SUFFIX) { branch = Blockly.Dart.prefixLines( - Blockly.Dart.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block), Blockly.Dart.INDENT) + branch; } if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.prefixLines( - Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.injectId(Blockly.Dart.INFINITE_LOOP_TRAP, block), Blockly.Dart.INDENT) + branch; } if (Blockly.Dart.STATEMENT_PREFIX) { branch = Blockly.Dart.prefixLines( - Blockly.Dart.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block), Blockly.Dart.INDENT) + branch; } var returnValue = Blockly.Dart.valueToCode(block, 'RETURN', @@ -104,6 +103,13 @@ Blockly.Dart['procedures_ifreturn'] = function(block) { var condition = Blockly.Dart.valueToCode(block, 'CONDITION', Blockly.Dart.ORDER_NONE) || 'false'; var code = 'if (' + condition + ') {\n'; + if (Blockly.Dart.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the return is triggered. + code += Blockly.Dart.prefixLines( + Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block), + Blockly.Dart.INDENT); + } if (block.hasReturnValue_) { var value = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_NONE) || 'null'; diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index 416bbc8be96..c1ad595eb99 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -40,7 +40,7 @@ Blockly.JavaScript['controls_repeat_ext'] = function(block) { Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; } var branch = Blockly.JavaScript.statementToCode(block, 'DO'); - branch = Blockly.JavaScript.addLoopTrap(branch, block.id); + branch = Blockly.JavaScript.addLoopTrap(branch, block); var code = ''; var loopVar = Blockly.JavaScript.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); @@ -67,7 +67,7 @@ Blockly.JavaScript['controls_whileUntil'] = function(block) { until ? Blockly.JavaScript.ORDER_LOGICAL_NOT : Blockly.JavaScript.ORDER_NONE) || 'false'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); - branch = Blockly.JavaScript.addLoopTrap(branch, block.id); + branch = Blockly.JavaScript.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } @@ -85,7 +85,7 @@ Blockly.JavaScript['controls_for'] = function(block) { var increment = Blockly.JavaScript.valueToCode(block, 'BY', Blockly.JavaScript.ORDER_ASSIGNMENT) || '1'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); - branch = Blockly.JavaScript.addLoopTrap(branch, block.id); + branch = Blockly.JavaScript.addLoopTrap(branch, block); var code; if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) && Blockly.isNumber(increment)) { @@ -146,7 +146,7 @@ Blockly.JavaScript['controls_forEach'] = function(block) { var argument0 = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); - branch = Blockly.JavaScript.addLoopTrap(branch, block.id); + branch = Blockly.JavaScript.addLoopTrap(branch, block); var code = ''; // Cache non-trivial values to variables to prevent repeated look-ups. var listVar = argument0; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index a3f9c88d65d..2096ddef01b 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -34,20 +34,19 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.JavaScript.statementToCode(block, 'STACK'); - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (Blockly.JavaScript.STATEMENT_SUFFIX) { branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, block), Blockly.JavaScript.INDENT) + branch; } if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), - Blockly.JavaScript.INDENT) + branch; + Blockly.JavaScript.injectId(Blockly.JavaScript.INFINITE_LOOP_TRAP, + block), Blockly.JavaScript.INDENT) + branch; } if (Blockly.JavaScript.STATEMENT_PREFIX) { branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, block), Blockly.JavaScript.INDENT) + branch; } var returnValue = Blockly.JavaScript.valueToCode(block, 'RETURN', @@ -104,6 +103,14 @@ Blockly.JavaScript['procedures_ifreturn'] = function(block) { var condition = Blockly.JavaScript.valueToCode(block, 'CONDITION', Blockly.JavaScript.ORDER_NONE) || 'false'; var code = 'if (' + condition + ') {\n'; + if (Blockly.JavaScript.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the return is triggered. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + code += Blockly.JavaScript.prefixLines( + Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, block), + Blockly.JavaScript.INDENT); + } if (block.hasReturnValue_) { var value = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_NONE) || 'null'; diff --git a/generators/lua/loops.js b/generators/lua/loops.js index d671534a608..612f4ae7814 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.js @@ -45,37 +45,34 @@ Blockly.Lua.CONTINUE_STATEMENT = 'goto continue\n'; * * @param {string} branch Generated code of the loop body * @return {string} Generated label or '' if unnecessary + * @private */ -Blockly.Lua.addContinueLabel = function(branch) { - if (branch.indexOf(Blockly.Lua.CONTINUE_STATEMENT) > -1) { +Blockly.Lua.addContinueLabel_ = function(branch) { + if (branch.indexOf(Blockly.Lua.CONTINUE_STATEMENT) != -1) { return branch + Blockly.Lua.INDENT + '::continue::\n'; } else { return branch; } }; -Blockly.Lua['controls_repeat'] = function(block) { - // Repeat n times (internal number). - var repeats = parseInt(block.getFieldValue('TIMES'), 10); - var branch = Blockly.Lua.statementToCode(block, 'DO') || ''; - branch = Blockly.Lua.addContinueLabel(branch); - var loopVar = Blockly.Lua.variableDB_.getDistinctName( - 'count', Blockly.Variables.NAME_TYPE); - var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + branch + 'end\n'; - return code; -}; - Blockly.Lua['controls_repeat_ext'] = function(block) { - // Repeat n times (external number). - var repeats = Blockly.Lua.valueToCode(block, 'TIMES', - Blockly.Lua.ORDER_NONE) || '0'; + // Repeat n times. + if (block.getField('TIMES')) { + // Internal number. + var repeats = String(Number(block.getFieldValue('TIMES'))); + } else { + // External number. + var repeats = Blockly.Lua.valueToCode(block, 'TIMES', + Blockly.Lua.ORDER_NONE) || '0'; + } if (Blockly.isNumber(repeats)) { repeats = parseInt(repeats, 10); } else { repeats = 'math.floor(' + repeats + ')'; } - var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; - branch = Blockly.Lua.addContinueLabel(branch); + var branch = Blockly.Lua.statementToCode(block, 'DO'); + branch = Blockly.Lua.addLoopTrap(branch, block); + branch = Blockly.Lua.addContinueLabel_(branch); var loopVar = Blockly.Lua.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + @@ -83,15 +80,17 @@ Blockly.Lua['controls_repeat_ext'] = function(block) { return code; }; +Blockly.Lua['controls_repeat'] = Blockly.Lua['controls_repeat_ext']; + Blockly.Lua['controls_whileUntil'] = function(block) { // Do while/until loop. var until = block.getFieldValue('MODE') == 'UNTIL'; var argument0 = Blockly.Lua.valueToCode(block, 'BOOL', until ? Blockly.Lua.ORDER_UNARY : Blockly.Lua.ORDER_NONE) || 'false'; - var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; - branch = Blockly.Lua.addLoopTrap(branch, block.id); - branch = Blockly.Lua.addContinueLabel(branch); + var branch = Blockly.Lua.statementToCode(block, 'DO'); + branch = Blockly.Lua.addLoopTrap(branch, block); + branch = Blockly.Lua.addContinueLabel_(branch); if (until) { argument0 = 'not ' + argument0; } @@ -108,9 +107,9 @@ Blockly.Lua['controls_for'] = function(block) { Blockly.Lua.ORDER_NONE) || '0'; var increment = Blockly.Lua.valueToCode(block, 'BY', Blockly.Lua.ORDER_NONE) || '1'; - var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; - branch = Blockly.Lua.addLoopTrap(branch, block.id); - branch = Blockly.Lua.addContinueLabel(branch); + var branch = Blockly.Lua.statementToCode(block, 'DO'); + branch = Blockly.Lua.addLoopTrap(branch, block); + branch = Blockly.Lua.addContinueLabel_(branch); var code = ''; var incValue; if (Blockly.isNumber(startVar) && Blockly.isNumber(endVar) && @@ -147,8 +146,9 @@ Blockly.Lua['controls_forEach'] = function(block) { block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Lua.valueToCode(block, 'LIST', Blockly.Lua.ORDER_NONE) || '{}'; - var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; - branch = Blockly.Lua.addContinueLabel(branch); + var branch = Blockly.Lua.statementToCode(block, 'DO'); + branch = Blockly.Lua.addLoopTrap(branch, block); + branch = Blockly.Lua.addContinueLabel_(branch); var code = 'for _, ' + variable0 + ' in ipairs(' + argument0 + ') do \n' + branch + 'end\n'; return code; diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 58c32baba6a..7995c9d780c 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -34,20 +34,19 @@ Blockly.Lua['procedures_defreturn'] = function(block) { var funcName = Blockly.Lua.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Lua.statementToCode(block, 'STACK'); - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (Blockly.Lua.STATEMENT_SUFFIX) { branch = Blockly.Lua.prefixLines( - Blockly.Lua.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block), Blockly.Lua.INDENT) + branch; } if (Blockly.Lua.INFINITE_LOOP_TRAP) { branch = Blockly.Lua.prefixLines( - Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.injectId(Blockly.Lua.INFINITE_LOOP_TRAP, block), Blockly.Lua.INDENT) + branch; } if (Blockly.Lua.STATEMENT_PREFIX) { branch = Blockly.Lua.prefixLines( - Blockly.Lua.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block), Blockly.Lua.INDENT) + branch; } var returnValue = Blockly.Lua.valueToCode(block, 'RETURN', @@ -106,6 +105,13 @@ Blockly.Lua['procedures_ifreturn'] = function(block) { var condition = Blockly.Lua.valueToCode(block, 'CONDITION', Blockly.Lua.ORDER_NONE) || 'false'; var code = 'if ' + condition + ' then\n'; + if (Blockly.Lua.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the return is triggered. + code += Blockly.Lua.prefixLines( + Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block), + Blockly.Lua.INDENT); + } if (block.hasReturnValue_) { var value = Blockly.Lua.valueToCode(block, 'VALUE', Blockly.Lua.ORDER_NONE) || 'nil'; diff --git a/generators/php/loops.js b/generators/php/loops.js index b504740ba3b..f85ce0116df 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -40,7 +40,7 @@ Blockly.PHP['controls_repeat_ext'] = function(block) { Blockly.PHP.ORDER_ASSIGNMENT) || '0'; } var branch = Blockly.PHP.statementToCode(block, 'DO'); - branch = Blockly.PHP.addLoopTrap(branch, block.id); + branch = Blockly.PHP.addLoopTrap(branch, block); var code = ''; var loopVar = Blockly.PHP.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); @@ -66,7 +66,7 @@ Blockly.PHP['controls_whileUntil'] = function(block) { until ? Blockly.PHP.ORDER_LOGICAL_NOT : Blockly.PHP.ORDER_NONE) || 'false'; var branch = Blockly.PHP.statementToCode(block, 'DO'); - branch = Blockly.PHP.addLoopTrap(branch, block.id); + branch = Blockly.PHP.addLoopTrap(branch, block); if (until) { argument0 = '!' + argument0; } @@ -84,7 +84,7 @@ Blockly.PHP['controls_for'] = function(block) { var increment = Blockly.PHP.valueToCode(block, 'BY', Blockly.PHP.ORDER_ASSIGNMENT) || '1'; var branch = Blockly.PHP.statementToCode(block, 'DO'); - branch = Blockly.PHP.addLoopTrap(branch, block.id); + branch = Blockly.PHP.addLoopTrap(branch, block); var code; if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) && Blockly.isNumber(increment)) { @@ -145,7 +145,7 @@ Blockly.PHP['controls_forEach'] = function(block) { var argument0 = Blockly.PHP.valueToCode(block, 'LIST', Blockly.PHP.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.PHP.statementToCode(block, 'DO'); - branch = Blockly.PHP.addLoopTrap(branch, block.id); + branch = Blockly.PHP.addLoopTrap(branch, block); var code = ''; code += 'foreach (' + argument0 + ' as ' + variable0 + ') {\n' + branch + '}\n'; diff --git a/generators/php/procedures.js b/generators/php/procedures.js index d93d7cb6386..d24a1d6c591 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -55,20 +55,19 @@ Blockly.PHP['procedures_defreturn'] = function(block) { var funcName = Blockly.PHP.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.PHP.statementToCode(block, 'STACK'); - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (Blockly.PHP.STATEMENT_SUFFIX) { branch = Blockly.PHP.prefixLines( - Blockly.PHP.STATEMENT_SUFFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block), Blockly.PHP.INDENT) + branch; } if (Blockly.PHP.INFINITE_LOOP_TRAP) { branch = Blockly.PHP.prefixLines( - Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.injectId(Blockly.PHP.INFINITE_LOOP_TRAP, block), Blockly.PHP.INDENT) + branch; } if (Blockly.PHP.STATEMENT_PREFIX) { branch = Blockly.PHP.prefixLines( - Blockly.PHP.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\''), + Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block), Blockly.PHP.INDENT) + branch; } var returnValue = Blockly.PHP.valueToCode(block, 'RETURN', @@ -125,6 +124,14 @@ Blockly.PHP['procedures_ifreturn'] = function(block) { var condition = Blockly.PHP.valueToCode(block, 'CONDITION', Blockly.PHP.ORDER_NONE) || 'false'; var code = 'if (' + condition + ') {\n'; + if (Blockly.PHP.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the return is triggered. + var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. + code += Blockly.PHP.prefixLines( + Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block), + Blockly.PHP.INDENT); + } if (block.hasReturnValue_) { var value = Blockly.PHP.valueToCode(block, 'VALUE', Blockly.PHP.ORDER_NONE) || 'null'; diff --git a/generators/python/loops.js b/generators/python/loops.js index 918bcdfb5a6..e7047dee1d9 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -45,8 +45,7 @@ Blockly.Python['controls_repeat_ext'] = function(block) { repeats = 'int(' + repeats + ')'; } var branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block.id) || - Blockly.Python.PASS; + branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; var loopVar = Blockly.Python.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; @@ -62,8 +61,7 @@ Blockly.Python['controls_whileUntil'] = function(block) { until ? Blockly.Python.ORDER_LOGICAL_NOT : Blockly.Python.ORDER_NONE) || 'False'; var branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block.id) || - Blockly.Python.PASS; + branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; if (until) { argument0 = 'not ' + argument0; } @@ -81,8 +79,7 @@ Blockly.Python['controls_for'] = function(block) { var increment = Blockly.Python.valueToCode(block, 'BY', Blockly.Python.ORDER_NONE) || '1'; var branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block.id) || - Blockly.Python.PASS; + branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; var code = ''; var range; @@ -193,8 +190,7 @@ Blockly.Python['controls_forEach'] = function(block) { var argument0 = Blockly.Python.valueToCode(block, 'LIST', Blockly.Python.ORDER_RELATIONAL) || '[]'; var branch = Blockly.Python.statementToCode(block, 'DO'); - branch = Blockly.Python.addLoopTrap(branch, block.id) || - Blockly.Python.PASS; + branch = Blockly.Python.addLoopTrap(branch, block) || Blockly.Python.PASS; var code = 'for ' + variable0 + ' in ' + argument0 + ':\n' + branch; return code; }; diff --git a/generators/python/procedures.js b/generators/python/procedures.js index c95c279f1fb..efdd738500f 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -56,20 +56,19 @@ Blockly.Python['procedures_defreturn'] = function(block) { var funcName = Blockly.Python.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Python.statementToCode(block, 'STACK'); - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (Blockly.Python.STATEMENT_SUFFIX) { branch = Blockly.Python.prefixLines( - Blockly.Python.STATEMENT_SUFFIX.replace( /%1/g, '\'' + id + '\''), + Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), Blockly.Python.INDENT) + branch; } if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.prefixLines( - Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + id + '\''), + Blockly.Python.injectId(Blockly.Python.INFINITE_LOOP_TRAP, block), Blockly.Python.INDENT) + branch; } if (Blockly.Python.STATEMENT_PREFIX) { branch = Blockly.Python.prefixLines( - Blockly.Python.STATEMENT_PREFIX.replace( /%1/g, '\'' + id + '\''), + Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block), Blockly.Python.INDENT) + branch; } var returnValue = Blockly.Python.valueToCode(block, 'RETURN', @@ -128,6 +127,13 @@ Blockly.Python['procedures_ifreturn'] = function(block) { var condition = Blockly.Python.valueToCode(block, 'CONDITION', Blockly.Python.ORDER_NONE) || 'False'; var code = 'if ' + condition + ':\n'; + if (Blockly.Python.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the return is triggered. + code += Blockly.Python.prefixLines( + Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), + Blockly.Python.INDENT); + } if (block.hasReturnValue_) { var value = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || 'None'; From 25adb40e6697e0b8e493474b796e53e23f0979be Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 13 May 2019 15:25:52 -0700 Subject: [PATCH 055/233] Prefix and suffix edge cases for flow statements. Call suffix code on break/continue before executing the break/continue. Call prefix code for enclosing loop before executing continue. --- blocks/loops.js | 34 ++++++++++++++++++----------- blocks/procedures.js | 4 ++-- blocks/variables.js | 4 ++-- core/blockly.js | 2 +- core/extensions.js | 2 +- core/generator.js | 2 +- core/mutator.js | 2 +- core/toolbox.js | 4 ++-- core/touch.js | 4 ++-- generators/dart/loops.js | 22 ++++++++++++++++--- generators/javascript/loops.js | 24 +++++++++++++++++--- generators/javascript/procedures.js | 1 - generators/lua/loops.js | 23 ++++++++++++++++--- generators/php/loops.js | 22 ++++++++++++++++--- generators/php/procedures.js | 1 - generators/python/loops.js | 22 ++++++++++++++++--- 16 files changed, 131 insertions(+), 42 deletions(-) diff --git a/blocks/loops.js b/blocks/loops.js index fa8f9e5fed9..eb245a808b4 100644 --- a/blocks/loops.js +++ b/blocks/loops.js @@ -258,7 +258,7 @@ Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = { * @this Blockly.Block */ customContextMenu: function(options) { - if (this.isInFlyout){ + if (this.isInFlyout) { return; } var variable = this.getField('VAR').getVariable(); @@ -303,7 +303,24 @@ Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { * Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.push('custom_loop'); */ LOOP_TYPES: ['controls_repeat', 'controls_repeat_ext', 'controls_forEach', - 'controls_for', 'controls_whileUntil'], + 'controls_for', 'controls_whileUntil'], + + /** + * Is the given block enclosed (at any level) by a loop? + * @param {!Blockly.Block} block Current block. + * @return {Blockly.Block} The nearest surrounding loop, or null if none. + */ + getSurroundLoop: function(block) { + // Is the block nested in a loop? + do { + if (Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES + .indexOf(block.type) != -1) { + return block; + } + block = block.getSurroundParent(); + } while (block); + return null; + }, /** * Called whenever anything on the workspace changes. @@ -315,17 +332,8 @@ Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { if (!this.workspace.isDragging || this.workspace.isDragging()) { return; // Don't change state at the start of a drag. } - var legal = false; - // Is the block nested in a loop? - var block = this; - do { - if (this.LOOP_TYPES.indexOf(block.type) != -1) { - legal = true; - break; - } - block = block.getSurroundParent(); - } while (block); - if (legal) { + if (Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN + .getSurroundLoop(this)) { this.setWarningText(null); if (!this.isInFlyout) { this.setEnabled(true); diff --git a/blocks/procedures.js b/blocks/procedures.js index 934b8ee5643..5188ac8b96e 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -349,7 +349,7 @@ Blockly.Blocks['procedures_defnoreturn'] = { * @this Blockly.Block */ customContextMenu: function(options) { - if (this.isInFlyout){ + if (this.isInFlyout) { return; } // Add option to create caller. @@ -489,7 +489,7 @@ Blockly.Blocks['procedures_mutatorcontainer'] = { } return; } - + if (event.type != Blockly.Events.BLOCK_CREATE) { return; } diff --git a/blocks/variables.js b/blocks/variables.js index 4ea1d1b07e2..1cd2f36f89b 100644 --- a/blocks/variables.js +++ b/blocks/variables.js @@ -100,7 +100,7 @@ Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = { * @this Blockly.Block */ customContextMenu: function(options) { - if (!this.isInFlyout){ + if (!this.isInFlyout) { // Getter blocks have the option to create a setter block, and vice versa. if (this.type == 'variables_get') { var opposite_type = 'variables_set'; @@ -123,7 +123,7 @@ Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = { options.push(option); // Getter blocks have the option to rename or delete that variable. } else { - if (this.type == 'variables_get' || this.type == 'variables_get_reporter'){ + if (this.type == 'variables_get' || this.type == 'variables_get_reporter') { var renameOption = { text: Blockly.Msg.RENAME_VARIABLE, enabled: true, diff --git a/core/blockly.js b/core/blockly.js index 562af5f2988..500d4139525 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -705,7 +705,7 @@ Blockly.setTheme = function(theme) { Blockly.refreshTheme_ = function(ws) { // Update all blocks in workspace that have a style name. this.updateBlockStyles_(ws.getAllBlocks().filter( - function(block){ + function(block) { return block.getStyleName() !== undefined; } )); diff --git a/core/extensions.js b/core/extensions.js index 7b0b3672d96..583cdc91030 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -73,7 +73,7 @@ Blockly.Extensions.register = function(name, initFn) { * registered. */ Blockly.Extensions.registerMixin = function(name, mixinObj) { - if (!mixinObj || typeof mixinObj != 'object'){ + if (!mixinObj || typeof mixinObj != 'object') { throw Error('Error: Mixin "' + name + '" must be a object'); } Blockly.Extensions.register(name, function() { diff --git a/core/generator.js b/core/generator.js index 81fdf199443..e9baf59a7d2 100644 --- a/core/generator.js +++ b/core/generator.js @@ -343,7 +343,7 @@ Blockly.Generator.prototype.addLoopTrap = function(branch, block) { Blockly.Generator.prototype.injectId = function(msg, block) { var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. return msg.replace(/%1/g, '\'' + id + '\''); -} +}; /** * Comma-separated list of reserved words. diff --git a/core/mutator.js b/core/mutator.js index b7968e85090..307c0bf8a35 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -416,7 +416,7 @@ Blockly.Mutator.prototype.dispose = function() { Blockly.Mutator.prototype.updateBlockStyle = function() { var ws = this.workspace_; - if (ws && ws.getAllBlocks()){ + if (ws && ws.getAllBlocks()) { var workspaceBlocks = ws.getAllBlocks(); for (var i = 0; i < workspaceBlocks.length; i++) { var block = workspaceBlocks[i]; diff --git a/core/toolbox.js b/core/toolbox.js index c920d1f5477..890b9d2e3e4 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -387,7 +387,7 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) { * @param {string} categoryName Name of the toolbox category. * @private */ -Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryName){ +Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryName) { // Decode the colour for any potential message references // (eg. `%{BKY_MATH_HUE}`). var colour = Blockly.utils.replaceMessageReferences(colourValue); @@ -416,7 +416,7 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryN * @param {string} categoryName Name of the toolbox category. */ Blockly.Toolbox.prototype.setColourFromStyle_ = function( - styleName, childOut, categoryName){ + styleName, childOut, categoryName) { childOut.styleName = styleName; if (styleName && Blockly.getTheme()) { var style = Blockly.getTheme().getCategoryStyle(styleName); diff --git a/core/touch.js b/core/touch.js index 6b54bb8a7f3..041a4c487fc 100644 --- a/core/touch.js +++ b/core/touch.js @@ -244,8 +244,8 @@ Blockly.Touch.splitEventByTouches = function(e) { type: e.type, changedTouches: [e.changedTouches[i]], target: e.target, - stopPropagation: function(){ e.stopPropagation(); }, - preventDefault: function(){ e.preventDefault(); } + stopPropagation: function() { e.stopPropagation(); }, + preventDefault: function() { e.preventDefault(); } }; events[i] = newEvent; } diff --git a/generators/dart/loops.js b/generators/dart/loops.js index c0d3bf9aa61..adab0f5934d 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -153,11 +153,27 @@ Blockly.Dart['controls_forEach'] = function(block) { Blockly.Dart['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - switch (block.getFieldValue('FLOW')) { + var flowType = block.getFieldValue('FLOW'); + var xfix = ''; + if (Blockly.Dart.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the break/continue is triggered. + xfix += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block); + } + if (Blockly.Dart.STATEMENT_PREFIX && flowType == 'CONTINUE') { + var loop = Blockly.Constants.Loops + .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); + if (loop) { + // Inject loop's statement prefix here since the regular one at the end + // of the loop will not get executed if the continue is triggered. + xfix += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, loop); + } + } + switch (flowType) { case 'BREAK': - return 'break;\n'; + return xfix + 'break;\n'; case 'CONTINUE': - return 'continue;\n'; + return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); }; diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index c1ad595eb99..9f6c6001b08 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -165,11 +165,29 @@ Blockly.JavaScript['controls_forEach'] = function(block) { Blockly.JavaScript['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - switch (block.getFieldValue('FLOW')) { + var flowType = block.getFieldValue('FLOW'); + var xfix = ''; + if (Blockly.JavaScript.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the break/continue is triggered. + xfix += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, + block); + } + if (Blockly.JavaScript.STATEMENT_PREFIX && flowType == 'CONTINUE') { + var loop = Blockly.Constants.Loops + .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); + if (loop) { + // Inject loop's statement prefix here since the regular one at the end + // of the loop will not get executed if the continue is triggered. + xfix += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, + loop); + } + } + switch (flowType) { case 'BREAK': - return 'break;\n'; + return xfix + 'break;\n'; case 'CONTINUE': - return 'continue;\n'; + return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); }; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index 2096ddef01b..ad6083f30cb 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -106,7 +106,6 @@ Blockly.JavaScript['procedures_ifreturn'] = function(block) { if (Blockly.JavaScript.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. code += Blockly.JavaScript.prefixLines( Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, block), Blockly.JavaScript.INDENT); diff --git a/generators/lua/loops.js b/generators/lua/loops.js index 612f4ae7814..4205af07d93 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.js @@ -49,6 +49,7 @@ Blockly.Lua.CONTINUE_STATEMENT = 'goto continue\n'; */ Blockly.Lua.addContinueLabel_ = function(branch) { if (branch.indexOf(Blockly.Lua.CONTINUE_STATEMENT) != -1) { + // False positives are possible (e.g. a string literal), but are harmless. return branch + Blockly.Lua.INDENT + '::continue::\n'; } else { return branch; @@ -156,11 +157,27 @@ Blockly.Lua['controls_forEach'] = function(block) { Blockly.Lua['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - switch (block.getFieldValue('FLOW')) { + var flowType = block.getFieldValue('FLOW'); + var xfix = ''; + if (Blockly.Lua.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the break/continue is triggered. + xfix += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block); + } + if (Blockly.Lua.STATEMENT_PREFIX && flowType == 'CONTINUE') { + var loop = Blockly.Constants.Loops + .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); + if (loop) { + // Inject loop's statement prefix here since the regular one at the end + // of the loop will not get executed if the continue is triggered. + xfix += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, loop); + } + } + switch (flowType) { case 'BREAK': - return 'break\n'; + return xfix + 'break\n'; case 'CONTINUE': - return Blockly.Lua.CONTINUE_STATEMENT; + return xfix + Blockly.Lua.CONTINUE_STATEMENT; } throw Error('Unknown flow statement.'); }; diff --git a/generators/php/loops.js b/generators/php/loops.js index f85ce0116df..490f7e1523d 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -154,11 +154,27 @@ Blockly.PHP['controls_forEach'] = function(block) { Blockly.PHP['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - switch (block.getFieldValue('FLOW')) { + var flowType = block.getFieldValue('FLOW'); + var xfix = ''; + if (Blockly.PHP.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the break/continue is triggered. + xfix += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block); + } + if (Blockly.PHP.STATEMENT_PREFIX && flowType == 'CONTINUE') { + var loop = Blockly.Constants.Loops + .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); + if (loop) { + // Inject loop's statement prefix here since the regular one at the end + // of the loop will not get executed if the continue is triggered. + xfix += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, loop); + } + } + switch (flowType) { case 'BREAK': - return 'break;\n'; + return xfix + 'break;\n'; case 'CONTINUE': - return 'continue;\n'; + return xfix + 'continue;\n'; } throw Error('Unknown flow statement.'); }; diff --git a/generators/php/procedures.js b/generators/php/procedures.js index d24a1d6c591..56e042dcd5c 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -127,7 +127,6 @@ Blockly.PHP['procedures_ifreturn'] = function(block) { if (Blockly.PHP.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the return is triggered. - var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. code += Blockly.PHP.prefixLines( Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block), Blockly.PHP.INDENT); diff --git a/generators/python/loops.js b/generators/python/loops.js index e7047dee1d9..a29b8d78784 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -197,11 +197,27 @@ Blockly.Python['controls_forEach'] = function(block) { Blockly.Python['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - switch (block.getFieldValue('FLOW')) { + var flowType = block.getFieldValue('FLOW'); + var xfix = ''; + if (Blockly.Python.STATEMENT_SUFFIX) { + // Inject any statement suffix here since the regular one at the end + // will not get executed if the break/continue is triggered. + xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); + } + if (Blockly.Python.STATEMENT_PREFIX && flowType == 'CONTINUE') { + var loop = Blockly.Constants.Loops + .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); + if (loop) { + // Inject loop's statement prefix here since the regular one at the end + // of the loop will not get executed if the continue is triggered. + xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, loop); + } + } + switch (flowType) { case 'BREAK': - return 'break\n'; + return xfix + 'break\n'; case 'CONTINUE': - return 'continue\n'; + return xfix + 'continue\n'; } throw Error('Unknown flow statement.'); }; From c0e14c3a7c621803dbce73758b4bc3b57689aed9 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 14 May 2019 13:59:19 -0700 Subject: [PATCH 056/233] Add method to suppress prefix/suffix from blocks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows generators to have more control over the placement of suffix. Needed for ‘if’ blocks and function calls which require their suffix code to be somewhere other than the end. Also, add loop’s prefix to ‘break’ blocks, since the loop’s suffix will be the next statement hit. Also, reuse procedures_callreturn generator for procedures_callnoreturn. --- blocks/logic.js | 6 ++++++ blocks/loops.js | 15 +++++++++++++-- blocks/procedures.js | 6 ++++++ core/generator.js | 4 ++-- generators/dart/logic.js | 19 ++++++++++++++++--- generators/dart/loops.js | 12 ++++++++---- generators/dart/procedures.js | 19 ++++++++++++------- generators/javascript/logic.js | 20 +++++++++++++++++--- generators/javascript/loops.js | 13 +++++++++---- generators/javascript/procedures.js | 21 ++++++++++++++------- generators/lua/logic.js | 19 ++++++++++++++++--- generators/lua/loops.js | 12 ++++++++---- generators/lua/procedures.js | 19 ++++++++++++------- generators/php/logic.js | 19 ++++++++++++++++--- generators/php/loops.js | 12 ++++++++---- generators/php/procedures.js | 19 ++++++++++++------- generators/python/logic.js | 17 +++++++++++++++-- generators/python/loops.js | 12 ++++++++---- generators/python/procedures.js | 19 ++++++++++++------- 19 files changed, 210 insertions(+), 73 deletions(-) diff --git a/blocks/logic.js b/blocks/logic.js index 9fcecbfce34..8de2ae6d47b 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -305,6 +305,12 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = { elseifCount_: 0, elseCount_: 0, + /** + * Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated + * code. These will be handled manually in this block's generators. + */ + suppressPrefixSuffix: true, + /** * Create XML to represent the number of else-if and else inputs. * @return {Element} XML storage element. diff --git a/blocks/loops.js b/blocks/loops.js index eb245a808b4..d8dae09bac4 100644 --- a/blocks/loops.js +++ b/blocks/loops.js @@ -302,8 +302,19 @@ Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { * To add a new loop type add this to your code: * Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.push('custom_loop'); */ - LOOP_TYPES: ['controls_repeat', 'controls_repeat_ext', 'controls_forEach', - 'controls_for', 'controls_whileUntil'], + LOOP_TYPES: [ + 'controls_repeat', + 'controls_repeat_ext', + 'controls_forEach', + 'controls_for', + 'controls_whileUntil' + ], + + /** + * Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated + * code. These will be handled manually in this block's generators. + */ + suppressPrefixSuffix: true, /** * Is the given block enclosed (at any level) by a loop? diff --git a/blocks/procedures.js b/blocks/procedures.js index 5188ac8b96e..a95babe47c5 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -642,6 +642,12 @@ Blockly.Blocks['procedures_callnoreturn'] = { this.previousEnabledState_ = true; }, + /** + * Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated + * code. These will be handled manually in this block's generators. + */ + suppressPrefixSuffix: true, + /** * Returns the name of the procedure this block calls. * @return {string} Procedure name. diff --git a/core/generator.js b/core/generator.js index e9baf59a7d2..bc2bf8e6043 100644 --- a/core/generator.js +++ b/core/generator.js @@ -198,10 +198,10 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { } return [this.scrub_(block, code[0], opt_thisOnly), code[1]]; } else if (typeof code == 'string') { - if (this.STATEMENT_PREFIX) { + if (this.STATEMENT_PREFIX && !block.suppressPrefixSuffix) { code = this.injectId(this.STATEMENT_PREFIX, block) + code; } - if (this.STATEMENT_SUFFIX) { + if (this.STATEMENT_SUFFIX && !block.suppressPrefixSuffix) { code = code + this.injectId(this.STATEMENT_SUFFIX, block); } return this.scrub_(block, code, opt_thisOnly); diff --git a/generators/dart/logic.js b/generators/dart/logic.js index 620b55da810..bd99aa2b3ca 100644 --- a/generators/dart/logic.js +++ b/generators/dart/logic.js @@ -33,18 +33,31 @@ Blockly.Dart['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var code = '', branchCode, conditionCode; + if (Blockly.Dart.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block); + } do { conditionCode = Blockly.Dart.valueToCode(block, 'IF' + n, - Blockly.Dart.ORDER_NONE) || 'false'; + Blockly.Dart.ORDER_NONE) || 'false'; branchCode = Blockly.Dart.statementToCode(block, 'DO' + n); + if (Blockly.Dart.STATEMENT_SUFFIX) { + branchCode = Blockly.Dart.prefixLines( + Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block), + Blockly.Dart.INDENT) + branchCode; + } code += (n > 0 ? 'else ' : '') + 'if (' + conditionCode + ') {\n' + branchCode + '}'; - ++n; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE')) { + if (block.getInput('ELSE') || Blockly.Dart.STATEMENT_SUFFIX) { branchCode = Blockly.Dart.statementToCode(block, 'ELSE'); + if (Blockly.Dart.STATEMENT_SUFFIX) { + branchCode = Blockly.Dart.prefixLines( + Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block), + Blockly.Dart.INDENT) + branchCode; + } code += ' else {\n' + branchCode + '}'; } return code + '\n'; diff --git a/generators/dart/loops.js b/generators/dart/loops.js index adab0f5934d..b24895e9700 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -153,23 +153,27 @@ Blockly.Dart['controls_forEach'] = function(block) { Blockly.Dart['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - var flowType = block.getFieldValue('FLOW'); var xfix = ''; + if (Blockly.Dart.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + xfix += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block); + } if (Blockly.Dart.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. xfix += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block); } - if (Blockly.Dart.STATEMENT_PREFIX && flowType == 'CONTINUE') { + if (Blockly.Dart.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); if (loop) { // Inject loop's statement prefix here since the regular one at the end - // of the loop will not get executed if the continue is triggered. + // of the loop will not get executed if 'continue' is triggered. + // In the case of 'break', a prefix is needed due to the loop's suffix. xfix += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, loop); } } - switch (flowType) { + switch (block.getFieldValue('FLOW')) { case 'BREAK': return xfix + 'break;\n'; case 'CONTINUE': diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index 5af422147a9..fa751c1ef68 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -87,14 +87,19 @@ Blockly.Dart['procedures_callreturn'] = function(block) { Blockly.Dart['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), - Blockly.Procedures.NAME_TYPE); - var args = []; - for (var i = 0; i < block.arguments_.length; i++) { - args[i] = Blockly.Dart.valueToCode(block, 'ARG' + i, - Blockly.Dart.ORDER_NONE) || 'null'; + var code = ''; + if (Blockly.Dart.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block); + } + if (Blockly.Dart.STATEMENT_SUFFIX) { + // Suffix needs to be added before the function call. + code += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block); } - var code = funcName + '(' + args.join(', ') + ');\n'; + // Generated code is for a function call as a statement is the same as a + // function call as a value, with the addition of line ending. + var tuple = Blockly.Dart['procedures_callreturn'](block); + code += tuple[0] + ';\n'; return code; }; diff --git a/generators/javascript/logic.js b/generators/javascript/logic.js index 1c4d4b6205c..27c439f2b5d 100644 --- a/generators/javascript/logic.js +++ b/generators/javascript/logic.js @@ -33,18 +33,32 @@ Blockly.JavaScript['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var code = '', branchCode, conditionCode; + if (Blockly.JavaScript.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, + block); + } do { conditionCode = Blockly.JavaScript.valueToCode(block, 'IF' + n, - Blockly.JavaScript.ORDER_NONE) || 'false'; + Blockly.JavaScript.ORDER_NONE) || 'false'; branchCode = Blockly.JavaScript.statementToCode(block, 'DO' + n); + if (Blockly.JavaScript.STATEMENT_SUFFIX) { + branchCode = Blockly.JavaScript.prefixLines( + Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, + block), Blockly.JavaScript.INDENT) + branchCode; + } code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + branchCode + '}'; - ++n; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE')) { + if (block.getInput('ELSE') || Blockly.JavaScript.STATEMENT_SUFFIX) { branchCode = Blockly.JavaScript.statementToCode(block, 'ELSE'); + if (Blockly.JavaScript.STATEMENT_SUFFIX) { + branchCode = Blockly.JavaScript.prefixLines( + Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, + block), Blockly.JavaScript.INDENT) + branchCode; + } code += ' else {\n' + branchCode + '}'; } return code + '\n'; diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index 9f6c6001b08..3ce74f6b01b 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -165,25 +165,30 @@ Blockly.JavaScript['controls_forEach'] = function(block) { Blockly.JavaScript['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - var flowType = block.getFieldValue('FLOW'); var xfix = ''; + if (Blockly.JavaScript.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + xfix += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, + block); + } if (Blockly.JavaScript.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. xfix += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, block); } - if (Blockly.JavaScript.STATEMENT_PREFIX && flowType == 'CONTINUE') { + if (Blockly.JavaScript.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); if (loop) { // Inject loop's statement prefix here since the regular one at the end - // of the loop will not get executed if the continue is triggered. + // of the loop will not get executed if 'continue' is triggered. + // In the case of 'break', a prefix is needed due to the loop's suffix. xfix += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, loop); } } - switch (flowType) { + switch (block.getFieldValue('FLOW')) { case 'BREAK': return xfix + 'break;\n'; case 'CONTINUE': diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index ad6083f30cb..d2fba2d8e82 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -87,14 +87,21 @@ Blockly.JavaScript['procedures_callreturn'] = function(block) { Blockly.JavaScript['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var funcName = Blockly.JavaScript.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var args = []; - for (var i = 0; i < block.arguments_.length; i++) { - args[i] = Blockly.JavaScript.valueToCode(block, 'ARG' + i, - Blockly.JavaScript.ORDER_COMMA) || 'null'; + var code = ''; + if (Blockly.JavaScript.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, + block); + } + if (Blockly.JavaScript.STATEMENT_SUFFIX) { + // Suffix needs to be added before the function call. + code += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, + block); } - var code = funcName + '(' + args.join(', ') + ');\n'; + // Generated code is for a function call as a statement is the same as a + // function call as a value, with the addition of line ending. + var tuple = Blockly.JavaScript['procedures_callreturn'](block); + code += tuple[0] + ';\n'; return code; }; diff --git a/generators/lua/logic.js b/generators/lua/logic.js index 033c52e3324..ac08521f75e 100644 --- a/generators/lua/logic.js +++ b/generators/lua/logic.js @@ -33,18 +33,31 @@ Blockly.Lua['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var code = '', branchCode, conditionCode; + if (Blockly.Lua.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block); + } do { conditionCode = Blockly.Lua.valueToCode(block, 'IF' + n, - Blockly.Lua.ORDER_NONE) || 'false'; + Blockly.Lua.ORDER_NONE) || 'false'; branchCode = Blockly.Lua.statementToCode(block, 'DO' + n); + if (Blockly.Lua.STATEMENT_SUFFIX) { + branchCode = Blockly.Lua.prefixLines( + Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block), + Blockly.Lua.INDENT) + branchCode; + } code += (n > 0 ? 'else' : '') + 'if ' + conditionCode + ' then\n' + branchCode; - ++n; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE')) { + if (block.getInput('ELSE') || Blockly.Lua.STATEMENT_SUFFIX) { branchCode = Blockly.Lua.statementToCode(block, 'ELSE'); + if (Blockly.Lua.STATEMENT_SUFFIX) { + branchCode = Blockly.Lua.prefixLines( + Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block), + Blockly.Lua.INDENT) + branchCode; + } code += 'else\n' + branchCode; } return code + 'end\n'; diff --git a/generators/lua/loops.js b/generators/lua/loops.js index 4205af07d93..7a41d58b9a8 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.js @@ -157,23 +157,27 @@ Blockly.Lua['controls_forEach'] = function(block) { Blockly.Lua['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - var flowType = block.getFieldValue('FLOW'); var xfix = ''; + if (Blockly.Lua.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + xfix += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block); + } if (Blockly.Lua.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. xfix += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block); } - if (Blockly.Lua.STATEMENT_PREFIX && flowType == 'CONTINUE') { + if (Blockly.Lua.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); if (loop) { // Inject loop's statement prefix here since the regular one at the end - // of the loop will not get executed if the continue is triggered. + // of the loop will not get executed if 'continue' is triggered. + // In the case of 'break', a prefix is needed due to the loop's suffix. xfix += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, loop); } } - switch (flowType) { + switch (block.getFieldValue('FLOW')) { case 'BREAK': return xfix + 'break\n'; case 'CONTINUE': diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 7995c9d780c..b1739cdd9ad 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -89,14 +89,19 @@ Blockly.Lua['procedures_callreturn'] = function(block) { Blockly.Lua['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var funcName = Blockly.Lua.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var args = []; - for (var i = 0; i < block.arguments_.length; i++) { - args[i] = Blockly.Lua.valueToCode(block, 'ARG' + i, - Blockly.Lua.ORDER_NONE) || 'nil'; + var code = ''; + if (Blockly.Lua.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block); + } + if (Blockly.Lua.STATEMENT_SUFFIX) { + // Suffix needs to be added before the function call. + code += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block); } - var code = funcName + '(' + args.join(', ') + ')\n'; + // Generated code is for a function call as a statement is the same as a + // function call as a value, with the addition of line ending. + var tuple = Blockly.Lua['procedures_callreturn'](block); + code += tuple[0] + '\n'; return code; }; diff --git a/generators/php/logic.js b/generators/php/logic.js index 475d2f70345..fe618210b98 100644 --- a/generators/php/logic.js +++ b/generators/php/logic.js @@ -33,18 +33,31 @@ Blockly.PHP['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var code = '', branchCode, conditionCode; + if (Blockly.PHP.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block); + } do { conditionCode = Blockly.PHP.valueToCode(block, 'IF' + n, - Blockly.PHP.ORDER_NONE) || 'false'; + Blockly.PHP.ORDER_NONE) || 'false'; branchCode = Blockly.PHP.statementToCode(block, 'DO' + n); + if (Blockly.PHP.STATEMENT_SUFFIX) { + branchCode = Blockly.PHP.prefixLines( + Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block), + Blockly.PHP.INDENT) + branchCode; + } code += (n > 0 ? ' else ' : '') + 'if (' + conditionCode + ') {\n' + branchCode + '}'; - ++n; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE')) { + if (block.getInput('ELSE') || Blockly.PHP.STATEMENT_SUFFIX) { branchCode = Blockly.PHP.statementToCode(block, 'ELSE'); + if (Blockly.PHP.STATEMENT_SUFFIX) { + branchCode = Blockly.PHP.prefixLines( + Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block), + Blockly.PHP.INDENT) + branchCode; + } code += ' else {\n' + branchCode + '}'; } return code + '\n'; diff --git a/generators/php/loops.js b/generators/php/loops.js index 490f7e1523d..7b277156ee7 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -154,23 +154,27 @@ Blockly.PHP['controls_forEach'] = function(block) { Blockly.PHP['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - var flowType = block.getFieldValue('FLOW'); var xfix = ''; + if (Blockly.PHP.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + xfix += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block); + } if (Blockly.PHP.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. xfix += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block); } - if (Blockly.PHP.STATEMENT_PREFIX && flowType == 'CONTINUE') { + if (Blockly.PHP.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); if (loop) { // Inject loop's statement prefix here since the regular one at the end - // of the loop will not get executed if the continue is triggered. + // of the loop will not get executed if 'continue' is triggered. + // In the case of 'break', a prefix is needed due to the loop's suffix. xfix += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, loop); } } - switch (flowType) { + switch (block.getFieldValue('FLOW')) { case 'BREAK': return xfix + 'break;\n'; case 'CONTINUE': diff --git a/generators/php/procedures.js b/generators/php/procedures.js index 56e042dcd5c..fe51de40886 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -108,14 +108,19 @@ Blockly.PHP['procedures_callreturn'] = function(block) { Blockly.PHP['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var funcName = Blockly.PHP.variableDB_.getName( - block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var args = []; - for (var i = 0; i < block.arguments_.length; i++) { - args[i] = Blockly.PHP.valueToCode(block, 'ARG' + i, - Blockly.PHP.ORDER_COMMA) || 'null'; + var code = ''; + if (Blockly.PHP.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block); + } + if (Blockly.PHP.STATEMENT_SUFFIX) { + // Suffix needs to be added before the function call. + code += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block); } - var code = funcName + '(' + args.join(', ') + ');\n'; + // Generated code is for a function call as a statement is the same as a + // function call as a value, with the addition of line ending. + var tuple = Blockly.PHP['procedures_callreturn'](block); + code += tuple[0] + ';\n'; return code; }; diff --git a/generators/python/logic.js b/generators/python/logic.js index fe0364868c6..1642ef5b0b7 100644 --- a/generators/python/logic.js +++ b/generators/python/logic.js @@ -33,19 +33,32 @@ Blockly.Python['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var code = '', branchCode, conditionCode; + if (Blockly.Python.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + } do { conditionCode = Blockly.Python.valueToCode(block, 'IF' + n, Blockly.Python.ORDER_NONE) || 'False'; branchCode = Blockly.Python.statementToCode(block, 'DO' + n) || Blockly.Python.PASS; + if (Blockly.Python.STATEMENT_SUFFIX) { + branchCode = Blockly.Python.prefixLines( + Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), + Blockly.Python.INDENT) + branchCode; + } code += (n == 0 ? 'if ' : 'elif ' ) + conditionCode + ':\n' + branchCode; - ++n; } while (block.getInput('IF' + n)); - if (block.getInput('ELSE')) { + if (block.getInput('ELSE') || Blockly.Python.STATEMENT_SUFFIX) { branchCode = Blockly.Python.statementToCode(block, 'ELSE') || Blockly.Python.PASS; + if (Blockly.Python.STATEMENT_SUFFIX) { + branchCode = Blockly.Python.prefixLines( + Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), + Blockly.Python.INDENT) + branchCode; + } code += 'else:\n' + branchCode; } return code; diff --git a/generators/python/loops.js b/generators/python/loops.js index a29b8d78784..f0e31a2cd0a 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -197,23 +197,27 @@ Blockly.Python['controls_forEach'] = function(block) { Blockly.Python['controls_flow_statements'] = function(block) { // Flow statements: continue, break. - var flowType = block.getFieldValue('FLOW'); var xfix = ''; + if (Blockly.Python.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + } if (Blockly.Python.STATEMENT_SUFFIX) { // Inject any statement suffix here since the regular one at the end // will not get executed if the break/continue is triggered. xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); } - if (Blockly.Python.STATEMENT_PREFIX && flowType == 'CONTINUE') { + if (Blockly.Python.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); if (loop) { // Inject loop's statement prefix here since the regular one at the end - // of the loop will not get executed if the continue is triggered. + // of the loop will not get executed if 'continue' is triggered. + // In the case of 'break', a prefix is needed due to the loop's suffix. xfix += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, loop); } } - switch (flowType) { + switch (block.getFieldValue('FLOW')) { case 'BREAK': return xfix + 'break\n'; case 'CONTINUE': diff --git a/generators/python/procedures.js b/generators/python/procedures.js index efdd738500f..76bd1168754 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -111,14 +111,19 @@ Blockly.Python['procedures_callreturn'] = function(block) { Blockly.Python['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'), - Blockly.Procedures.NAME_TYPE); - var args = []; - for (var i = 0; i < block.arguments_.length; i++) { - args[i] = Blockly.Python.valueToCode(block, 'ARG' + i, - Blockly.Python.ORDER_NONE) || 'None'; + var code = ''; + if (Blockly.Python.STATEMENT_PREFIX) { + // Automatic prefix insertion is switched off for this block. Add manually. + code += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + } + if (Blockly.Python.STATEMENT_SUFFIX) { + // Suffix needs to be added before the function call. + code += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); } - var code = funcName + '(' + args.join(', ') + ')\n'; + // Generated code is for a function call as a statement is the same as a + // function call as a value, with the addition of line ending. + var tuple = Blockly.Python['procedures_callreturn'](block); + code += tuple[0] + '\n'; return code; }; From 585866a1b6dde1a2739e5daab01b602e47c555e3 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 14 May 2019 16:10:42 -0700 Subject: [PATCH 057/233] Revisit function block for return. Visit (with prefix and suffix) function block when executed. This commit adds a revisit at the end of the function body when evaluating the return value. --- generators/dart/procedures.js | 28 +++++++++++++++------------ generators/javascript/procedures.js | 30 +++++++++++++++++------------ generators/lua/procedures.js | 28 +++++++++++++++------------ generators/php/procedures.js | 28 +++++++++++++++------------ generators/python/procedures.js | 28 +++++++++++++++------------ 5 files changed, 82 insertions(+), 60 deletions(-) diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index fa751c1ef68..efb432986d8 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -33,24 +33,28 @@ Blockly.Dart['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var branch = Blockly.Dart.statementToCode(block, 'STACK'); + var xfix1 = ''; + if (Blockly.Dart.STATEMENT_PREFIX) { + xfix1 += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block); + } if (Blockly.Dart.STATEMENT_SUFFIX) { - branch = Blockly.Dart.prefixLines( - Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block), - Blockly.Dart.INDENT) + branch; + xfix1 += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block); } + xfix1 = Blockly.Dart.prefixLines(xfix1, Blockly.Dart.INDENT); + var loopTrap = ''; if (Blockly.Dart.INFINITE_LOOP_TRAP) { - branch = Blockly.Dart.prefixLines( + loopTrap = Blockly.Dart.prefixLines( Blockly.Dart.injectId(Blockly.Dart.INFINITE_LOOP_TRAP, block), - Blockly.Dart.INDENT) + branch; - } - if (Blockly.Dart.STATEMENT_PREFIX) { - branch = Blockly.Dart.prefixLines( - Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block), - Blockly.Dart.INDENT) + branch; + Blockly.Dart.INDENT); } + var branch = Blockly.Dart.statementToCode(block, 'STACK'); var returnValue = Blockly.Dart.valueToCode(block, 'RETURN', Blockly.Dart.ORDER_NONE) || ''; + var xfix2 = ''; + if (branch && returnValue) { + // After executing the function body, revisit this block for the return. + xfix2 = xfix1; + } if (returnValue) { returnValue = Blockly.Dart.INDENT + 'return ' + returnValue + ';\n'; } @@ -61,7 +65,7 @@ Blockly.Dart['procedures_defreturn'] = function(block) { Blockly.Variables.NAME_TYPE); } var code = returnType + ' ' + funcName + '(' + args.join(', ') + ') {\n' + - branch + returnValue + '}'; + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; code = Blockly.Dart.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. Blockly.Dart.definitions_['%' + funcName] = code; diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index d2fba2d8e82..cd6767daafa 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -33,24 +33,30 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var branch = Blockly.JavaScript.statementToCode(block, 'STACK'); + var xfix1 = ''; + if (Blockly.JavaScript.STATEMENT_PREFIX) { + xfix1 += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, + block); + } if (Blockly.JavaScript.STATEMENT_SUFFIX) { - branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, block), - Blockly.JavaScript.INDENT) + branch; + xfix1 += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, + block); } + xfix1 = Blockly.JavaScript.prefixLines(xfix1, Blockly.JavaScript.INDENT); + var loopTrap = ''; if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { - branch = Blockly.JavaScript.prefixLines( + loopTrap = Blockly.JavaScript.prefixLines( Blockly.JavaScript.injectId(Blockly.JavaScript.INFINITE_LOOP_TRAP, - block), Blockly.JavaScript.INDENT) + branch; - } - if (Blockly.JavaScript.STATEMENT_PREFIX) { - branch = Blockly.JavaScript.prefixLines( - Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, block), - Blockly.JavaScript.INDENT) + branch; + block), Blockly.JavaScript.INDENT); } + var branch = Blockly.JavaScript.statementToCode(block, 'STACK'); var returnValue = Blockly.JavaScript.valueToCode(block, 'RETURN', Blockly.JavaScript.ORDER_NONE) || ''; + var xfix2 = ''; + if (branch && returnValue) { + // After executing the function body, revisit this block for the return. + xfix2 = xfix1; + } if (returnValue) { returnValue = Blockly.JavaScript.INDENT + 'return ' + returnValue + ';\n'; } @@ -60,7 +66,7 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { Blockly.Variables.NAME_TYPE); } var code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + - branch + returnValue + '}'; + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; code = Blockly.JavaScript.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. Blockly.JavaScript.definitions_['%' + funcName] = code; diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index b1739cdd9ad..32462b3af78 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -33,24 +33,28 @@ Blockly.Lua['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.Lua.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var branch = Blockly.Lua.statementToCode(block, 'STACK'); + var xfix1 = ''; + if (Blockly.Lua.STATEMENT_PREFIX) { + xfix1 += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block); + } if (Blockly.Lua.STATEMENT_SUFFIX) { - branch = Blockly.Lua.prefixLines( - Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block), - Blockly.Lua.INDENT) + branch; + xfix1 += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block); } + xfix1 = Blockly.Lua.prefixLines(xfix1, Blockly.Lua.INDENT); + var loopTrap = ''; if (Blockly.Lua.INFINITE_LOOP_TRAP) { - branch = Blockly.Lua.prefixLines( + loopTrap = Blockly.Lua.prefixLines( Blockly.Lua.injectId(Blockly.Lua.INFINITE_LOOP_TRAP, block), - Blockly.Lua.INDENT) + branch; - } - if (Blockly.Lua.STATEMENT_PREFIX) { - branch = Blockly.Lua.prefixLines( - Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block), - Blockly.Lua.INDENT) + branch; + Blockly.Lua.INDENT); } + var branch = Blockly.Lua.statementToCode(block, 'STACK'); var returnValue = Blockly.Lua.valueToCode(block, 'RETURN', Blockly.Lua.ORDER_NONE) || ''; + var xfix2 = ''; + if (branch && returnValue) { + // After executing the function body, revisit this block for the return. + xfix2 = xfix1; + } if (returnValue) { returnValue = Blockly.Lua.INDENT + 'return ' + returnValue + '\n'; } else if (!branch) { @@ -62,7 +66,7 @@ Blockly.Lua['procedures_defreturn'] = function(block) { Blockly.Variables.NAME_TYPE); } var code = 'function ' + funcName + '(' + args.join(', ') + ')\n' + - branch + returnValue + 'end\n'; + xfix1 + loopTrap + branch + xfix2 + returnValue + 'end\n'; code = Blockly.Lua.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. Blockly.Lua.definitions_['%' + funcName] = code; diff --git a/generators/php/procedures.js b/generators/php/procedures.js index fe51de40886..e567068b16a 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -54,24 +54,28 @@ Blockly.PHP['procedures_defreturn'] = function(block) { var funcName = Blockly.PHP.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var branch = Blockly.PHP.statementToCode(block, 'STACK'); + var xfix1 = ''; + if (Blockly.PHP.STATEMENT_PREFIX) { + xfix1 += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block); + } if (Blockly.PHP.STATEMENT_SUFFIX) { - branch = Blockly.PHP.prefixLines( - Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block), - Blockly.PHP.INDENT) + branch; + xfix1 += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block); } + xfix1 = Blockly.PHP.prefixLines(xfix1, Blockly.PHP.INDENT); + var loopTrap = ''; if (Blockly.PHP.INFINITE_LOOP_TRAP) { - branch = Blockly.PHP.prefixLines( + loopTrap = Blockly.PHP.prefixLines( Blockly.PHP.injectId(Blockly.PHP.INFINITE_LOOP_TRAP, block), - Blockly.PHP.INDENT) + branch; - } - if (Blockly.PHP.STATEMENT_PREFIX) { - branch = Blockly.PHP.prefixLines( - Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block), - Blockly.PHP.INDENT) + branch; + Blockly.PHP.INDENT); } + var branch = Blockly.PHP.statementToCode(block, 'STACK'); var returnValue = Blockly.PHP.valueToCode(block, 'RETURN', Blockly.PHP.ORDER_NONE) || ''; + var xfix2 = ''; + if (branch && returnValue) { + // After executing the function body, revisit this block for the return. + xfix2 = xfix1; + } if (returnValue) { returnValue = Blockly.PHP.INDENT + 'return ' + returnValue + ';\n'; } @@ -81,7 +85,7 @@ Blockly.PHP['procedures_defreturn'] = function(block) { Blockly.Variables.NAME_TYPE); } var code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + - globals + branch + returnValue + '}'; + globals + xfix1 + loopTrap + branch + xfix2 + returnValue + '}'; code = Blockly.PHP.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. Blockly.PHP.definitions_['%' + funcName] = code; diff --git a/generators/python/procedures.js b/generators/python/procedures.js index 76bd1168754..2455c2903b7 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -55,24 +55,28 @@ Blockly.Python['procedures_defreturn'] = function(block) { Blockly.Python.INDENT + 'global ' + globals.join(', ') + '\n' : ''; var funcName = Blockly.Python.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); - var branch = Blockly.Python.statementToCode(block, 'STACK'); + var xfix1 = ''; + if (Blockly.Python.STATEMENT_PREFIX) { + xfix1 += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); + } if (Blockly.Python.STATEMENT_SUFFIX) { - branch = Blockly.Python.prefixLines( - Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block), - Blockly.Python.INDENT) + branch; + xfix1 += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); } + xfix1 = Blockly.Python.prefixLines(xfix1, Blockly.Python.INDENT); + var loopTrap = ''; if (Blockly.Python.INFINITE_LOOP_TRAP) { - branch = Blockly.Python.prefixLines( + loopTrap = Blockly.Python.prefixLines( Blockly.Python.injectId(Blockly.Python.INFINITE_LOOP_TRAP, block), - Blockly.Python.INDENT) + branch; - } - if (Blockly.Python.STATEMENT_PREFIX) { - branch = Blockly.Python.prefixLines( - Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block), - Blockly.Python.INDENT) + branch; + Blockly.Python.INDENT); } + var branch = Blockly.Python.statementToCode(block, 'STACK'); var returnValue = Blockly.Python.valueToCode(block, 'RETURN', Blockly.Python.ORDER_NONE) || ''; + var xfix2 = ''; + if (branch && returnValue) { + // After executing the function body, revisit this block for the return. + xfix2 = xfix1; + } if (returnValue) { returnValue = Blockly.Python.INDENT + 'return ' + returnValue + '\n'; } else if (!branch) { @@ -84,7 +88,7 @@ Blockly.Python['procedures_defreturn'] = function(block) { Blockly.Variables.NAME_TYPE); } var code = 'def ' + funcName + '(' + args.join(', ') + '):\n' + - globals + branch + returnValue; + globals + xfix1 + loopTrap + branch + xfix2 + returnValue; code = Blockly.Python.scrub_(block, code); // Add % so as not to collide with helper functions in definitions list. Blockly.Python.definitions_['%' + funcName] = code; From 04e39c20f8d7a7572acfeb2cc33ebd86d751a4b3 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 14 May 2019 16:55:52 -0700 Subject: [PATCH 058/233] Fix indentation bug if no xfix exists in function --- core/useragent.js | 3 +-- generators/dart/procedures.js | 4 +++- generators/javascript/procedures.js | 4 +++- generators/lua/procedures.js | 4 +++- generators/php/procedures.js | 4 +++- generators/python/procedures.js | 4 +++- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/core/useragent.js b/core/useragent.js index 1abc62855cb..1e2e8739067 100644 --- a/core/useragent.js +++ b/core/useragent.js @@ -54,8 +54,7 @@ goog.provide('Blockly.userAgent'); // Engines. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js - Blockly.userAgent.WEBKIT = has('WebKit') && - !Blockly.userAgent.EDGE; + Blockly.userAgent.WEBKIT = has('WebKit') && !Blockly.userAgent.EDGE; Blockly.userAgent.GECKO = has('Gecko') && !Blockly.userAgent.WEBKIT && !Blockly.userAgent.IE && !Blockly.userAgent.EDGE; diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index efb432986d8..e6402a77bea 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -40,7 +40,9 @@ Blockly.Dart['procedures_defreturn'] = function(block) { if (Blockly.Dart.STATEMENT_SUFFIX) { xfix1 += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block); } - xfix1 = Blockly.Dart.prefixLines(xfix1, Blockly.Dart.INDENT); + if (xfix1) { + xfix1 = Blockly.Dart.prefixLines(xfix1, Blockly.Dart.INDENT); + } var loopTrap = ''; if (Blockly.Dart.INFINITE_LOOP_TRAP) { loopTrap = Blockly.Dart.prefixLines( diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index cd6767daafa..86ee28b214f 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -42,7 +42,9 @@ Blockly.JavaScript['procedures_defreturn'] = function(block) { xfix1 += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, block); } - xfix1 = Blockly.JavaScript.prefixLines(xfix1, Blockly.JavaScript.INDENT); + if (xfix1) { + xfix1 = Blockly.JavaScript.prefixLines(xfix1, Blockly.JavaScript.INDENT); + } var loopTrap = ''; if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { loopTrap = Blockly.JavaScript.prefixLines( diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 32462b3af78..1a5b605dc4b 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -40,7 +40,9 @@ Blockly.Lua['procedures_defreturn'] = function(block) { if (Blockly.Lua.STATEMENT_SUFFIX) { xfix1 += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block); } - xfix1 = Blockly.Lua.prefixLines(xfix1, Blockly.Lua.INDENT); + if (xfix1) { + xfix1 = Blockly.Lua.prefixLines(xfix1, Blockly.Lua.INDENT); + } var loopTrap = ''; if (Blockly.Lua.INFINITE_LOOP_TRAP) { loopTrap = Blockly.Lua.prefixLines( diff --git a/generators/php/procedures.js b/generators/php/procedures.js index e567068b16a..f66703d100c 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -61,7 +61,9 @@ Blockly.PHP['procedures_defreturn'] = function(block) { if (Blockly.PHP.STATEMENT_SUFFIX) { xfix1 += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block); } - xfix1 = Blockly.PHP.prefixLines(xfix1, Blockly.PHP.INDENT); + if (xfix1) { + xfix1 = Blockly.PHP.prefixLines(xfix1, Blockly.PHP.INDENT); + } var loopTrap = ''; if (Blockly.PHP.INFINITE_LOOP_TRAP) { loopTrap = Blockly.PHP.prefixLines( diff --git a/generators/python/procedures.js b/generators/python/procedures.js index 2455c2903b7..daec89855be 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -62,7 +62,9 @@ Blockly.Python['procedures_defreturn'] = function(block) { if (Blockly.Python.STATEMENT_SUFFIX) { xfix1 += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); } - xfix1 = Blockly.Python.prefixLines(xfix1, Blockly.Python.INDENT); + if (xfix1) { + xfix1 = Blockly.Python.prefixLines(xfix1, Blockly.Python.INDENT); + } var loopTrap = ''; if (Blockly.Python.INFINITE_LOOP_TRAP) { loopTrap = Blockly.Python.prefixLines( From 475d8eb71fe4f154013d671c05d2b9c9451e822b Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Fri, 17 May 2019 12:11:24 +0200 Subject: [PATCH 059/233] Localisation updates from https://translatewiki.net. --- msg/json/eo.json | 200 ++++++++++++++++++++++++++++++++++++----------- msg/json/fi.json | 1 + msg/json/ia.json | 5 +- msg/json/te.json | 5 +- 4 files changed, 162 insertions(+), 49 deletions(-) diff --git a/msg/json/eo.json b/msg/json/eo.json index 795c0d120f7..d5d4c7d4291 100644 --- a/msg/json/eo.json +++ b/msg/json/eo.json @@ -14,6 +14,7 @@ "DUPLICATE_BLOCK": "Duobligi", "ADD_COMMENT": "Aldoni komenton", "REMOVE_COMMENT": "Forigi komenton", + "DUPLICATE_COMMENT": "Duobligi Komenton", "EXTERNAL_INPUTS": "Eksteraj eniroj", "INLINE_INPUTS": "Entekstaj eniroj", "DELETE_BLOCK": "Forigi blokon", @@ -30,17 +31,19 @@ "UNDO": "Malfari", "REDO": "Refari", "CHANGE_VALUE_TITLE": "Ŝangi valoron:", - "RENAME_VARIABLE": "Renomi varianton...", - "RENAME_VARIABLE_TITLE": "Renomi ĉiujn '%1' variantojn kiel:", - "NEW_VARIABLE": "Nova varianto...", + "RENAME_VARIABLE": "Renomi variablon...", + "RENAME_VARIABLE_TITLE": "Renomi ĉiujn '%1' variablojn kiel:", + "NEW_VARIABLE": "Nova variablo...", "NEW_STRING_VARIABLE": "Krei signoĉenan variablon...", "NEW_NUMBER_VARIABLE": "Krei nombran variablon...", "NEW_COLOUR_VARIABLE": "Krei koloran variablon...", "NEW_VARIABLE_TYPE_TITLE": "Tipo de nova variablo:", - "NEW_VARIABLE_TITLE": "Nova nomo de varianto:", - "VARIABLE_ALREADY_EXISTS": "Jam ekzistas varianto kun la nomo '%1'.", - "DELETE_VARIABLE_CONFIRMATION": "Ĉu forigi %1 uzojn de la varianto '%2'?", - "DELETE_VARIABLE": "Forigi la varianton '%1'", + "NEW_VARIABLE_TITLE": "Nova nomo de variablo:", + "VARIABLE_ALREADY_EXISTS": "Jam ekzistas variablo kun la nomo '%1'.", + "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Jam ekzistas variablo kun la nomo '%1' por alia tipo: '%2'.", + "DELETE_VARIABLE_CONFIRMATION": "Ĉu forigi %1 uzojn de la variablo '%2'?", + "CANNOT_DELETE_VARIABLE_PROCEDURE": "Ne povas forigi la variablon '%1' ĉar ĝi estas parto de la difino de la funkcio '%2'", + "DELETE_VARIABLE": "Forigi la variablon '%1'", "COLOUR_PICKER_HELPURL": "https://eo.wikipedia.org/wiki/Koloro", "COLOUR_PICKER_TOOLTIP": "Elekti koloron el la paletro.", "COLOUR_RANDOM_TITLE": "hazarda koloro", @@ -49,54 +52,68 @@ "COLOUR_RGB_RED": "ruĝa", "COLOUR_RGB_GREEN": "verda", "COLOUR_RGB_BLUE": "blua", + "COLOUR_RGB_TOOLTIP": "Kreas koloron kun specifita kvanto de ruĝo, verdo, kaj bluo. Ĉiuj valoroj devas esti inter 0 kaj 100.", + "COLOUR_BLEND_TITLE": "miksi", "COLOUR_BLEND_COLOUR1": "koloro 1", "COLOUR_BLEND_COLOUR2": "koloro 2", "COLOUR_BLEND_RATIO": "proporcio", + "COLOUR_BLEND_TOOLTIP": "Kunmiksas du kolorojn laŭ specifita proporcio (0,0 - 1,0).", + "CONTROLS_REPEAT_HELPURL": "https://eo.wikipedia.org/wiki/Iteracio", "CONTROLS_REPEAT_TITLE": "ripeti %1 fojojn", "CONTROLS_REPEAT_INPUT_DO": "fari", - "CONTROLS_REPEAT_TOOLTIP": "Plenumi kelkajn ordonojn plurfoje.", + "CONTROLS_REPEAT_TOOLTIP": "Plenumas kelkajn ordonojn plurfoje.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ripeti dum", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ripeti ĝis", - "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Plenumi ordonojn dum la valoro egalas vero.", + "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Plenumas ordonojn dum la valoro egalas vero.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Plenumi ordonojn dum valoro egalas malvero.", + "CONTROLS_FOR_TOOLTIP": "Varias la variablon '%1', ekde la komenca nombro ĝis la fina nombro, laŭ la specifita diferenco; dume rulas la specifitajn blokojn.", + "CONTROLS_FOR_TITLE": "kalkuli kun variablo %1 ekde %2 ĝis %3 per diferenco %4", "CONTROLS_FOREACH_TITLE": "por ĉiu elemento %1 en la listo %2", + "CONTROLS_FOREACH_TOOLTIP": "Pri ĉiu elemento en listo, difinas la variablon '%1' al la elemento, kaj faras kelkajn ordonojn.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "eliri el la ciklo", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "daŭrigi je la venonta ripeto de la ciklo", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Eliri el la enhava ciklo.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Pretersalti la ceteron de tiu ĉi ciklo kaj daŭrigi je la venonta ripeto.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Averto: tiu ĉi bloko uzeblas nur ene de ciklo.", - "CONTROLS_IF_TOOLTIP_1": "Plenumi ordonojn se la valoro estas vero.", + "CONTROLS_IF_TOOLTIP_1": "Plenumas ordonojn se la valoro estas vero.", "CONTROLS_IF_TOOLTIP_2": "Plenumi la unuan blokon de ordonoj se la valoro estas vero, se ne, la duan.", + "CONTROLS_IF_TOOLTIP_3": "Se la unua valoro estas vero, do faras la unuan blokon de ordonoj. Alie, se la dua valoro estas vero, do faras la duan blokon de ordonoj.", + "CONTROLS_IF_TOOLTIP_4": "Se la unua valoro estas vero, do faras la unuan blokon de ordonoj. Alie, se la dua valoro estas vero, do faras la duan blokon de ordonoj. Se neniu el la du valoroj estas vero, do faras la lastan blokon de ordonoj.", "CONTROLS_IF_MSG_IF": "se", "CONTROLS_IF_MSG_ELSEIF": "alie se", "CONTROLS_IF_MSG_ELSE": "alie", + "CONTROLS_IF_IF_TOOLTIP": "Aldoni, forigi aŭ reorganizi partojn por reagordi la 'se'-blokon.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Aldoni kondiĉon al la bloko 'se'", "CONTROLS_IF_ELSE_TOOLTIP": "Aldoni 'aliokaze' kondiĉon al la 'se' bloko.", "IOS_OK": "Bone", "IOS_CANCEL": "Nuligi", "IOS_ERROR": "Eraro", - "IOS_PROCEDURES_INPUTS": "ENIGOJ", + "IOS_PROCEDURES_INPUTS": "ENIROJ", + "IOS_PROCEDURES_ADD_INPUT": "+ Aldoni eniron", + "IOS_PROCEDURES_ALLOW_STATEMENTS": "Permesi ordonojn", + "IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR": "Ĉi tiu funkcio havas du samnomajn enirojn.", "IOS_VARIABLES_ADD_VARIABLE": "+ Aldoni Variablon", "IOS_VARIABLES_ADD_BUTTON": "Aldoni", "IOS_VARIABLES_RENAME_BUTTON": "Alinomigi", "IOS_VARIABLES_DELETE_BUTTON": "Forigi", "IOS_VARIABLES_VARIABLE_NAME": "Nomo de variablo", + "IOS_VARIABLES_EMPTY_NAME_ERROR": "La nomo de la variablo devas esti ne malplena.", "LOGIC_COMPARE_HELPURL": "https://eo.wikipedia.org/wiki/Neegala%C4%B5o_(pli_granda,_malpli_granda)", - "LOGIC_COMPARE_TOOLTIP_EQ": "Vero estos liverita, se la du eniroj egalas.", + "LOGIC_COMPARE_TOOLTIP_EQ": "Liveras veron, se la du eniroj egalas.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Vero estos liverita, se la du eniroj ne egalas.", - "LOGIC_COMPARE_TOOLTIP_LT": "Vero estos liverita, se la unua eniro estas pli eta ol la dua.", + "LOGIC_COMPARE_TOOLTIP_LT": "Liveras veron, se la unua eniro estas pli malgranda ol la dua.", "LOGIC_COMPARE_TOOLTIP_LTE": "Vero estos liverita, se la unua eniro estas pli eta aŭ egala al la dua.", - "LOGIC_COMPARE_TOOLTIP_GT": "Vero estos liverita, se la unua eniro estas pli granda ol la dua.", + "LOGIC_COMPARE_TOOLTIP_GT": "Liveras veron, se la unua eniro estas pli granda ol la dua.", "LOGIC_COMPARE_TOOLTIP_GTE": "Vero estos liverita, se la unua eniro estas pli granda aŭ egala al la dua.", - "LOGIC_OPERATION_TOOLTIP_AND": "Vero estos liverita, se la du eniroj egalas veron.", + "LOGIC_OPERATION_TOOLTIP_AND": "Liveras veron, se la du eniroj egalas veron.", "LOGIC_OPERATION_AND": "kaj", - "LOGIC_OPERATION_TOOLTIP_OR": "Vero estos liverita, se almenaŭ unu el la eniroj egalas veron.", + "LOGIC_OPERATION_TOOLTIP_OR": "Liveras veron, se almenaŭ unu el la eniroj egalas veron.", "LOGIC_OPERATION_OR": "aŭ", "LOGIC_NEGATE_TITLE": "maligi %1", - "LOGIC_NEGATE_TOOLTIP": "Se la eniro egalas vero, la rezulto egalas malvero. Se la eniro egalas malvero, la rezulto egalas vero.", + "LOGIC_NEGATE_TOOLTIP": "Liveras veron, se la eniro egalas veron. Liveras malveron, se la eniro egalas malveron.", "LOGIC_BOOLEAN_TRUE": "vera", "LOGIC_BOOLEAN_FALSE": "falsa", - "LOGIC_BOOLEAN_TOOLTIP": "La rezulto egalas ĉu vero, ĉu malvero.", + "LOGIC_BOOLEAN_TOOLTIP": "Liveras aŭ veron aŭ malveron.", "LOGIC_NULL": "senvalora", "LOGIC_NULL_TOOLTIP": "Liveras senvaloron.", "LOGIC_TERNARY_CONDITION": "testi", @@ -106,19 +123,21 @@ "MATH_NUMBER_HELPURL": "https://eo.wikipedia.org/wiki/Nombro", "MATH_NUMBER_TOOLTIP": "Nombro.", "MATH_ARITHMETIC_HELPURL": "https://eo.wikipedia.org/wiki/Aritmetiko", - "MATH_ARITHMETIC_TOOLTIP_ADD": "La sumo de la du nombroj estos liverita.", + "MATH_ARITHMETIC_TOOLTIP_ADD": "Liveras la sumon de la du nombroj.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "La diferenco inter la du nombroj estos liverita.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "La produto de la du numeroj estos liverita.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "La kvociento de la du nombroj estos liverita.", + "MATH_ARITHMETIC_TOOLTIP_POWER": "Livero la tian potencon de la unua nombro, kia la dua nombro estas", "MATH_SINGLE_HELPURL": "https://eo.wikipedia.org/wiki/Kvadrata_radiko", "MATH_SINGLE_OP_ROOT": "kvadrata radiko", - "MATH_SINGLE_TOOLTIP_ROOT": "La kvadrata radiko de nombro estos liverita.", + "MATH_SINGLE_TOOLTIP_ROOT": "Liveras la kvadratan radikon de nombro.", "MATH_SINGLE_OP_ABSOLUTE": "absoluta", - "MATH_SINGLE_TOOLTIP_ABS": "La absoluta valoro de nombro estos liverita.", + "MATH_SINGLE_TOOLTIP_ABS": "Liveras la absolutan valoron de nombro.", "MATH_SINGLE_TOOLTIP_NEG": "La negativigo de numero estos liverita.", - "MATH_SINGLE_TOOLTIP_LN": "La natura logaritmo de nombro estos liverita.", + "MATH_SINGLE_TOOLTIP_LN": "Liveras la naturan logaritmon de nombro.", "MATH_SINGLE_TOOLTIP_LOG10": "La dekbaza logaritmo de numero estos liverita.", - "MATH_SINGLE_TOOLTIP_EXP": "La rezulto de la potenco de e je la nombro.", + "MATH_SINGLE_TOOLTIP_EXP": "Liveras ian potencon de e.", + "MATH_SINGLE_TOOLTIP_POW10": "Liveri tian potencon de 10, kia la eniro estas.", "MATH_TRIG_HELPURL": "https://eo.wikipedia.org/wiki/Trigonometria_funkcio", "MATH_TRIG_TOOLTIP_SIN": "Liveras la sinuson de angulo en gradoj (ne radianoj).", "MATH_TRIG_TOOLTIP_COS": "Liveras la kosinuson de angulo en gradoj (ne radianoj).", @@ -127,6 +146,7 @@ "MATH_TRIG_TOOLTIP_ACOS": "Liveras la arkokosinuson de nombro.", "MATH_TRIG_TOOLTIP_ATAN": "La targentarko de nombro estos liverita.", "MATH_CONSTANT_HELPURL": "https://eo.wikipedia.org/wiki/Matematika_konstanto", + "MATH_CONSTANT_TOOLTIP": "Liveras unu el la ofte uzataj konstantoj: π (3,141…), e (2,718…), φ (1,618…), √2 (1,414…), √½ (0,707…), aŭ ∞ (malfinio).", "MATH_IS_EVEN": "estas para", "MATH_IS_ODD": "estas nepara", "MATH_IS_PRIME": "estas primo", @@ -135,65 +155,109 @@ "MATH_IS_NEGATIVE": "estas negativa", "MATH_IS_DIVISIBLE_BY": "estas dividebla de", "MATH_IS_TOOLTIP": "Vero aŭ malvero estos liverita, depende de la rezulto de kontrolo, ĉu nombro estas para, nepara, pozitiva, negativa, aŭ dividebla de iu nombro.", + "MATH_CHANGE_HELPURL": "https://eo.wikipedia.org/wiki/Kremento", "MATH_CHANGE_TITLE": "krementi %1 per %2", - "MATH_CHANGE_TOOLTIP": "Aldoni nombro al varianto '%1'.", + "MATH_CHANGE_TOOLTIP": "Aldoni nombro al variablo '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Rondigi nombroj, supren aŭ malsupren.", "MATH_ROUND_OPERATOR_ROUND": "rondigi", "MATH_ROUND_OPERATOR_ROUNDUP": "Rondigi supren", "MATH_ROUND_OPERATOR_ROUNDDOWN": "rondigi malsupren", "MATH_ONLIST_OPERATOR_SUM": "sumo de listo", - "MATH_ONLIST_TOOLTIP_SUM": "La sumo de ĉiuj nombro en la listo estos liverita.", + "MATH_ONLIST_TOOLTIP_SUM": "Liveras la sumon de ĉiuj nombroj en la listo.", "MATH_ONLIST_OPERATOR_MIN": "listminimumo", - "MATH_ONLIST_TOOLTIP_MIN": "La plej eta nombro en la listo estos redonita.", + "MATH_ONLIST_TOOLTIP_MIN": "Liveras la plej malgrandan nombron en la listo.", "MATH_ONLIST_OPERATOR_MAX": "listmaksimumo", - "MATH_ONLIST_TOOLTIP_MAX": "La plej granda numero en la listo estos redonita.", + "MATH_ONLIST_TOOLTIP_MAX": "Liveras la plej grandan nombron en la listo.", "MATH_ONLIST_OPERATOR_AVERAGE": "listmezumo", - "MATH_ONLIST_TOOLTIP_AVERAGE": "La aritmetika meznombro de la numeroj en la listo estos liverita.", - "MATH_ONLIST_OPERATOR_MODE": "reĝimoj de listo", + "MATH_ONLIST_TOOLTIP_AVERAGE": "Liveras la aritmetikan meznombron de la nombroj en la listo.", + "MATH_ONLIST_OPERATOR_MEDIAN": "mediano de listo", + "MATH_ONLIST_TOOLTIP_MEDIAN": "Liveras la medianan nombron en la listo.", + "MATH_ONLIST_OPERATOR_MODE": "modoj de listo", + "MATH_ONLIST_TOOLTIP_MODE": "Liveras liston de la plej ofta(j) elemento(j) en la listo.", "MATH_ONLIST_OPERATOR_STD_DEV": "Norma devio de la listo", - "MATH_ONLIST_TOOLTIP_STD_DEV": "La norma devio de la listo estos liverita.", + "MATH_ONLIST_TOOLTIP_STD_DEV": "Liveras la norman devion de la listo.", "MATH_ONLIST_OPERATOR_RANDOM": "hazarda elemento el la listo", - "MATH_ONLIST_TOOLTIP_RANDOM": "Elemento el la listo estos hazarde liverita.", + "MATH_ONLIST_TOOLTIP_RANDOM": "Liveras hazardan elementon el la listo.", "MATH_MODULO_HELPURL": "https://eo.wikipedia.org/wiki/Resto", "MATH_MODULO_TITLE": "resto de %1 ÷ %2", - "MATH_MODULO_TOOLTIP": "La resto de la divido de du nombroj estos liverita.", + "MATH_MODULO_TOOLTIP": "Liveras la reston de la divido de la du nombroj.", "MATH_CONSTRAIN_TITLE": "limigi %1 inter %2 kaj %3", "MATH_CONSTRAIN_TOOLTIP": "La nombro estos limigita tiel ke ĝi egalas la limojn aŭ troviĝas inter ili.", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "hazarda entjero inter %1 kaj %2", "MATH_RANDOM_INT_TOOLTIP": "Nombro estos hazarde liverita, tiel ke ĝi egalas la limojn aŭ troviĝas inter ili.", + "MATH_RANDOM_FLOAT_HELPURL": "https://eo.wikipedia.org/wiki/Hazardo", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "hazarda frakcio", + "MATH_RANDOM_FLOAT_TOOLTIP": "Liveras hazardan frakcion inter 0,0 (inkluzive) kaj 1,0 (ekskluzive).", + "MATH_ATAN2_HELPURL": "https://eo.wikipedia.org/wiki/Inversa_trigonometria_funkcio#Duargumenta_varianto_de_tangentarko", "MATH_ATAN2_TITLE": "atan2 de X:%1 Y:%2", - "MATH_ATAN2_TOOLTIP": "Liveri la arkotangenton de punkto (X, Y) en gradoj inter -180 kaj 180.", - "TEXT_TEXT_HELPURL": "https://eo.wikipedia.org/wiki/Signo%C4%89eno", + "MATH_ATAN2_TOOLTIP": "Liveras la arkotangenton de punkto (X, Y) en gradoj inter -180 kaj 180.", + "TEXT_TEXT_HELPURL": "https://eo.wikipedia.org/wiki/Signoĉeno", + "TEXT_TEXT_TOOLTIP": "Litero, vorto, aŭ linio da teksto.", "TEXT_JOIN_TITLE_CREATEWITH": "krei tekston kun", + "TEXT_JOIN_TOOLTIP": "Krei pecon de teksto per kunigi ajnan nombron de eroj.", "TEXT_CREATE_JOIN_TITLE_JOIN": "kunigi", + "TEXT_CREATE_JOIN_TOOLTIP": "Aldonu, forigu, aŭ reorganizu partojn por reagordi la tekstan blokon.", + "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Aldoni eron al la teksto.", + "TEXT_APPEND_TITLE": "al %1 postaldoni tekston %2", + "TEXT_APPEND_TOOLTIP": "Postapendi iom da teksto al variablo '%1'.", "TEXT_LENGTH_TITLE": "longo de %1", + "TEXT_LENGTH_TOOLTIP": "Liveras la nombron de literoj (inkluzive de spacetoj) en la provizita teksto.", "TEXT_ISEMPTY_TITLE": "%1 malplenas", + "TEXT_ISEMPTY_TOOLTIP": "Liveras veron, se la provizita teksto estas malplena.", + "TEXT_INDEXOF_TOOLTIP": "Liveras indekson de la unua/lasta okazo de la unua teksto en la dua teksto. Liveras %1 se la unua teksto ne okazas en la dua teksto.", "TEXT_INDEXOF_TITLE": "en la teksto %1 %2 %3", + "TEXT_INDEXOF_OPERATOR_FIRST": "trovi la unuan okazon de teksto", + "TEXT_INDEXOF_OPERATOR_LAST": "trovi la lastan okazon de teksto", + "TEXT_CHARAT_TITLE": "en la teksto %1, %2", + "TEXT_CHARAT_FROM_START": "akiri literon de numero", + "TEXT_CHARAT_FROM_END": "akiri literon de inversa numero", + "TEXT_CHARAT_FIRST": "akiri unuan literon", + "TEXT_CHARAT_LAST": "akiri lastan literon", + "TEXT_CHARAT_RANDOM": "akiri hazardan literon", + "TEXT_CHARAT_TOOLTIP": "Liveras literon ĉe specifita loko.", + "TEXT_GET_SUBSTRING_TOOLTIP": "Liveri specifitan parto de la teksto.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "en la teksto", + "TEXT_GET_SUBSTRING_START_FROM_START": "akiri subsignoĉenon ekde litero de numero", + "TEXT_GET_SUBSTRING_START_FROM_END": "akiri subsignoĉenon ekde litero de inversa numero", + "TEXT_GET_SUBSTRING_START_FIRST": "akiri subsignoĉenon ekde la unua litero", + "TEXT_GET_SUBSTRING_END_FROM_START": "ĝis litero de numero", + "TEXT_GET_SUBSTRING_END_FROM_END": "ĝis litero de inversa numero", + "TEXT_GET_SUBSTRING_END_LAST": "ĝis lasta litero", + "TEXT_CHANGECASE_TOOLTIP": "Liveras kopion de la teksto je alia usklo.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "MAJUSKLIGI", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "minuskligi", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "Nomuskligi", - "TEXT_TRIM_OPERATOR_RIGHT": "forigi spacojn el la dekstra flanko de", + "TEXT_TRIM_TOOLTIP": "Liveras kopion de teksto, de kies fino(j) spacetoj foriĝis.", + "TEXT_TRIM_OPERATOR_BOTH": "forigi spacetojn for de ambaŭ finoj de", + "TEXT_TRIM_OPERATOR_LEFT": "forigi spacetojn for de maldekstra fino de", + "TEXT_TRIM_OPERATOR_RIGHT": "forigi spacetojn for de dekstra fino de", "TEXT_PRINT_TITLE": "presi %1", "TEXT_PRINT_TOOLTIP": "Presi la specifitan tekston, nombron aŭ alian valoron.", + "TEXT_PROMPT_TYPE_TEXT": "ricevi tekston per mesaĝo", + "TEXT_PROMPT_TYPE_NUMBER": "ricevi nombron per mesaĝo", "TEXT_PROMPT_TOOLTIP_NUMBER": "Peti nombron al uzanto.", "TEXT_PROMPT_TOOLTIP_TEXT": "Peti tekston al uzanto.", + "TEXT_COUNT_MESSAGE0": "kalkuli la okazojn de %1 en %2", + "TEXT_COUNT_TOOLTIP": "Kalkuli kiomfoje iu teksto okazas en iu alia teksto.", + "TEXT_REPLACE_MESSAGE0": "anstataŭigi tekston %1 per %2 en %3", + "TEXT_REPLACE_TOOLTIP": "Anstataŭigi ĉiujn okazojn de iu teksto en alia teksto.", + "TEXT_REVERSE_MESSAGE0": "inversigi tekston %1", + "TEXT_REVERSE_TOOLTIP": "Inversigi la ordon de la skribsignoj en la teksto.", "LISTS_CREATE_EMPTY_TITLE": "krei malplenan liston", - "LISTS_CREATE_EMPTY_TOOLTIP": "Listo, de longo 0, sen datumaj registroj, estos liverita.", + "LISTS_CREATE_EMPTY_TOOLTIP": "Liveras liston, de longo 0, sen datenaj rikordoj", "LISTS_CREATE_WITH_TOOLTIP": "Krei liston kun ajna nombro de elementoj.", "LISTS_CREATE_WITH_INPUT_WITH": "krei liston kun", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "listo", - "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Aldoni, forigi aŭ oridigi sekciojn por reagordi tiun ĉi blokon de listo.", + "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Aldonu, forigu aŭ oridigu partojn por reagordi la listan blokon.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Aldoni elementon al la listo.", "LISTS_REPEAT_TOOLTIP": "Listo kun la specifita nombro de elementoj, kiuj havos la donitan valoron, estos kreita.", "LISTS_REPEAT_TITLE": "krei liston kun elemento %1 ripetita %2 fojojn", "LISTS_LENGTH_TITLE": "longo de %1", - "LISTS_LENGTH_TOOLTIP": "La longo de listo estos liverita.", + "LISTS_LENGTH_TOOLTIP": "Liveras la longon de listo.", "LISTS_ISEMPTY_TITLE": "%1 malplenas", - "LISTS_ISEMPTY_TOOLTIP": "Vero estos liverita, se la listo malplenas.", + "LISTS_ISEMPTY_TOOLTIP": "Liveras veron, se la listo malplenas.", "LISTS_INLIST": "en la listo", "LISTS_INDEX_OF_FIRST": "trovi la unuan aperon de elemento", "LISTS_INDEX_OF_LAST": "trovi la lastan aperon de elemento", @@ -207,13 +271,13 @@ "LISTS_GET_INDEX_RANDOM": "hazardan", "LISTS_INDEX_FROM_START_TOOLTIP": "%1 estas la unua elemento.", "LISTS_INDEX_FROM_END_TOOLTIP": "%1 estas la lasta elemento.", - "LISTS_GET_INDEX_TOOLTIP_GET_FROM": "La elemento en la specifita pozicio en la listo estos liverita.", + "LISTS_GET_INDEX_TOOLTIP_GET_FROM": "Liveras la elementon ĉe la specifita pozicio en listo.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "La unua elemento en la listo esto liverita.", - "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "La lasta elemento en la listo estos liverita.", + "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Liveras la lastan elementon en la listo.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Hazarda elemento en la listo estos liverita.", - "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM": "La elemento en la specifita pozicio de la listo estos liverita kaj forigita.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM": "Liveras kaj forigas la elementon en la specifita pozicio de la listo.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "La unua elemento en la listo estos liverita kaj forigita.", - "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "La lasta elemento en la listo estos liverita kaj forigita.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Forigas kaj liveras la lastan elementon en listo.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Hazarda elemento en la listo estos liverita kaj forigita.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM": "La elemento en la specifita pozicio en la listo estos forigita.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "La unua elemento en la listo estos forigita.", @@ -222,19 +286,63 @@ "LISTS_SET_INDEX_SET": "difini", "LISTS_SET_INDEX_INSERT": "enmeti je", "LISTS_SET_INDEX_INPUT_TO": "kiel", + "LISTS_SET_INDEX_TOOLTIP_SET_FROM": "Difinas la elementon ĉe la specifita pozicio en listo", + "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Difinas la unua elementon en listo.", + "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Difinas la lastan elementon en listo.", + "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Difinas hazardan elementon en listo.", + "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM": "Enigas la elementon ĉe specifita pozicio en listo.", + "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Antaŭaldonas la elementon ĉe la komenco de listo.", + "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Postaldonas la elementon ĉe la fino de listo.", + "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Enigas la elementon hazarde en listo.", + "LISTS_GET_SUBLIST_START_FROM_START": "akiri subliston ekde elemento de numero", + "LISTS_GET_SUBLIST_START_FROM_END": "akiri subliston ekde elemento de inversa numero", + "LISTS_GET_SUBLIST_START_FIRST": "akiri subliston ekde la unua elemento", + "LISTS_GET_SUBLIST_END_FROM_START": "ĝis elemento de numero", + "LISTS_GET_SUBLIST_END_FROM_END": "ĝis elemento de inversa numero", + "LISTS_GET_SUBLIST_END_LAST": "ĝis la lasta elemento", + "LISTS_GET_SUBLIST_TOOLTIP": "Kreas kopion de la specifita parto de listo.", + "LISTS_SORT_HELPURL": "https://github.com/google/blockly/wiki/Lists#sorting-a-list", + "LISTS_SORT_TITLE": "ordigi %1 %2 liston %3", + "LISTS_SORT_TOOLTIP": "Ordigas kopion de listo.", + "LISTS_SORT_ORDER_ASCENDING": "kreskante", + "LISTS_SORT_ORDER_DESCENDING": "malkreskante", "LISTS_SORT_TYPE_NUMERIC": "nombre", "LISTS_SORT_TYPE_TEXT": "alfabete", "LISTS_SORT_TYPE_IGNORECASE": "alfabete, ignorante usklon", "LISTS_SPLIT_LIST_FROM_TEXT": "fari liston el teksto", "LISTS_SPLIT_TEXT_FROM_LIST": "fari tekston el listo", "LISTS_SPLIT_WITH_DELIMITER": "kun apartigilo", + "LISTS_SPLIT_TOOLTIP_SPLIT": "Disdividas tekston en liston da tekstoj, laŭ apartigilo.", + "LISTS_SPLIT_TOOLTIP_JOIN": "Kunigas liston de tekstoj en unu tekston, kun apartigilo inter la elementoj.", + "LISTS_REVERSE_MESSAGE0": "inversigi liston %1", + "LISTS_REVERSE_TOOLTIP": "Inversigi kopion de listo.", + "VARIABLES_GET_TOOLTIP": "Liveras la valoron de ĉi tiu variablo.", + "VARIABLES_GET_CREATE_SET": "Krei blokon 'difini variablon %1'", + "VARIABLES_SET": "difini %1 kiel %2", + "VARIABLES_SET_TOOLTIP": "Difinas ĉi tiun variablon kiel la eniron.", + "VARIABLES_SET_CREATE_GET": "Krei blokon 'akiri variablon %1'", + "PROCEDURES_DEFNORETURN_TITLE": "por", "PROCEDURES_DEFNORETURN_PROCEDURE": "fari ion", "PROCEDURES_BEFORE_PARAMS": "kun:", "PROCEDURES_CALL_BEFORE_PARAMS": "kun:", + "PROCEDURES_DEFNORETURN_TOOLTIP": "Krei funkcion sen eliro.", + "PROCEDURES_DEFNORETURN_COMMENT": "Priskribi ĉi tiun funkcion...", "PROCEDURES_DEFRETURN_RETURN": "liveri", - "PROCEDURES_MUTATORCONTAINER_TITLE": "enigoj", + "PROCEDURES_DEFRETURN_TOOLTIP": "Krei funkcion kun unu eliro.", + "PROCEDURES_ALLOW_STATEMENTS": "permesi ordonojn", + "PROCEDURES_DEF_DUPLICATE_WARNING": "Averto: la funkcio havas du parametrojn kun la sama nomo.", + "PROCEDURES_CALLNORETURN_HELPURL": "https://eo.wikipedia.org/wiki/Subprogramo", + "PROCEDURES_CALLNORETURN_TOOLTIP": "Ruli la uzanto-difinitan funkcion '%1'.", + "PROCEDURES_CALLRETURN_HELPURL": "https://eo.wikipedia.org/wiki/Subprogramo", + "PROCEDURES_CALLRETURN_TOOLTIP": "Ruli la uzanto-difinitan funkcion '%1' kaj uzi ĝian eliron.", + "PROCEDURES_MUTATORCONTAINER_TITLE": "eniroj", + "PROCEDURES_MUTATORCONTAINER_TOOLTIP": "Aldoni, forigi, aŭ reorganizi enirojn je ĉi tiu funkcio.", "PROCEDURES_MUTATORARG_TITLE": "nomo de enigo:", - "PROCEDURES_MUTATORARG_TOOLTIP": "Aldoni enigon al la funkcio.", + "PROCEDURES_MUTATORARG_TOOLTIP": "Aldoni eniron al la funkcio.", + "PROCEDURES_HIGHLIGHT_DEF": "Emfazi difinon de funkcio", "PROCEDURES_CREATE_DO": "Krei '%1'", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Diru ion…" + "PROCEDURES_IFRETURN_TOOLTIP": "Se valoro estas vero, do liveras duan valoron.", + "PROCEDURES_IFRETURN_WARNING": "Averto: Ĉi tiu bloko estas uzebla nur en difino de funkcio.", + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Diru ion…", + "COLLAPSED_WARNINGS_WARNING": "Falditaj blokoj enhavas avertojn." } diff --git a/msg/json/fi.json b/msg/json/fi.json index 8d11fbba952..29b7befa17a 100644 --- a/msg/json/fi.json +++ b/msg/json/fi.json @@ -257,6 +257,7 @@ "TEXT_PROMPT_TOOLTIP_TEXT": "Kehottaa käyttäjää syöttämään tekstiä.", "TEXT_COUNT_MESSAGE0": "laske määrä '%1' '%2' sisällä", "TEXT_COUNT_TOOLTIP": "Laske kuiunka monta kertaa jokin teksti esiintyy jossakin toisessa tekstissä.", + "TEXT_REPLACE_MESSAGE0": "Korvaa teksti %1 tekstillä %2 tekstissä %3", "TEXT_REVERSE_MESSAGE0": "%1 takaperin", "TEXT_REVERSE_TOOLTIP": "Muuttaa tekstin kirjainten järjestyksen toisin päin.", "LISTS_CREATE_EMPTY_TITLE": "Luo tyhjä lista", diff --git a/msg/json/ia.json b/msg/json/ia.json index 0b9cdf8961b..ae3b5341d67 100644 --- a/msg/json/ia.json +++ b/msg/json/ia.json @@ -182,6 +182,8 @@ "MATH_RANDOM_INT_TOOLTIP": "Retornar un numero integre aleatori inter le duo limites specificate, incluse.", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fraction aleatori", "MATH_RANDOM_FLOAT_TOOLTIP": "Retornar un fraction aleatori inter 0.0 (incluse) e 1.0 (excluse).", + "MATH_ATAN2_TITLE": "atan2 de X:%1 Y:%2", + "MATH_ATAN2_TOOLTIP": "Retornar le arco tangente del puncto (X, Y) in grados de -180 a 180.", "TEXT_TEXT_TOOLTIP": "Un littera, parola o linea de texto.", "TEXT_JOIN_TITLE_CREATEWITH": "crear texto con", "TEXT_JOIN_TOOLTIP": "Crear un pecia de texto uniente un certe numero de elementos.", @@ -328,5 +330,6 @@ "PROCEDURES_CREATE_DO": "Crear '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Si un valor es ver, alora retornar un secunde valor.", "PROCEDURES_IFRETURN_WARNING": "Attention: Iste bloco pote solmente esser usate in le definition de un function.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Dice qualcosa..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Dice qualcosa...", + "COLLAPSED_WARNINGS_WARNING": "Blocos plicate contine advertimentos." } diff --git a/msg/json/te.json b/msg/json/te.json index 22f77faedb1..cfd50cc3c4a 100644 --- a/msg/json/te.json +++ b/msg/json/te.json @@ -2,7 +2,8 @@ "@metadata": { "authors": [ "Naidugari Jayanna", - "WP MANIKHANTA" + "WP MANIKHANTA", + "Veeven" ] }, "VARIABLES_DEFAULT_NAME": "అంశం", @@ -69,7 +70,7 @@ "MATH_IS_NEGATIVE": "ప్రతికూలంగా ఉంది", "MATH_IS_DIVISIBLE_BY": "దీనితో భాగించబడును", "MATH_ONLIST_OPERATOR_SUM": "జాబితా మొత్తం", - "MATH_ONLIST_OPERATOR_AVERAGE": "జాబితా యొక్క సగటు", + "MATH_ONLIST_OPERATOR_AVERAGE": "జాబితా సగటు", "TEXT_CREATE_JOIN_TITLE_JOIN": "చేరు", "TEXT_LENGTH_TITLE": "%1 పొడువు", "TEXT_ISEMPTY_TITLE": "% 1 ఖాళీ", From e642a77f5d877bdf6ab562be5833ebb6c5769e60 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 13:43:57 -0700 Subject: [PATCH 060/233] Use conventional prefix/suffix for function calls. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously a function call with no return value generated: prefix(); suffix(); function(); The intent was so the prefix and suffix calls in the function body wouldn’t overlap with the prefix and suffix calls of the function call. However, this is doomed to be inconsistent with a function call with a return value: prefix(); print(function()); suffix(); Thus since overlaping must exist, both types of function calls should have consistent suffix locations. --- blocks/procedures.js | 6 ------ generators/dart/procedures.js | 12 +----------- generators/javascript/procedures.js | 14 +------------- generators/lua/procedures.js | 12 +----------- generators/php/procedures.js | 12 +----------- generators/python/procedures.js | 12 +----------- 6 files changed, 5 insertions(+), 63 deletions(-) diff --git a/blocks/procedures.js b/blocks/procedures.js index a95babe47c5..5188ac8b96e 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -642,12 +642,6 @@ Blockly.Blocks['procedures_callnoreturn'] = { this.previousEnabledState_ = true; }, - /** - * Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated - * code. These will be handled manually in this block's generators. - */ - suppressPrefixSuffix: true, - /** * Returns the name of the procedure this block calls. * @return {string} Procedure name. diff --git a/generators/dart/procedures.js b/generators/dart/procedures.js index e6402a77bea..451be16d813 100644 --- a/generators/dart/procedures.js +++ b/generators/dart/procedures.js @@ -93,20 +93,10 @@ Blockly.Dart['procedures_callreturn'] = function(block) { Blockly.Dart['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var code = ''; - if (Blockly.Dart.STATEMENT_PREFIX) { - // Automatic prefix insertion is switched off for this block. Add manually. - code += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX, block); - } - if (Blockly.Dart.STATEMENT_SUFFIX) { - // Suffix needs to be added before the function call. - code += Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX, block); - } // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. var tuple = Blockly.Dart['procedures_callreturn'](block); - code += tuple[0] + ';\n'; - return code; + return tuple[0] + ';\n'; }; Blockly.Dart['procedures_ifreturn'] = function(block) { diff --git a/generators/javascript/procedures.js b/generators/javascript/procedures.js index 86ee28b214f..9c2ac09acef 100644 --- a/generators/javascript/procedures.js +++ b/generators/javascript/procedures.js @@ -95,22 +95,10 @@ Blockly.JavaScript['procedures_callreturn'] = function(block) { Blockly.JavaScript['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var code = ''; - if (Blockly.JavaScript.STATEMENT_PREFIX) { - // Automatic prefix insertion is switched off for this block. Add manually. - code += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, - block); - } - if (Blockly.JavaScript.STATEMENT_SUFFIX) { - // Suffix needs to be added before the function call. - code += Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX, - block); - } // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. var tuple = Blockly.JavaScript['procedures_callreturn'](block); - code += tuple[0] + ';\n'; - return code; + return tuple[0] + ';\n'; }; Blockly.JavaScript['procedures_ifreturn'] = function(block) { diff --git a/generators/lua/procedures.js b/generators/lua/procedures.js index 1a5b605dc4b..917ee2493f6 100644 --- a/generators/lua/procedures.js +++ b/generators/lua/procedures.js @@ -95,20 +95,10 @@ Blockly.Lua['procedures_callreturn'] = function(block) { Blockly.Lua['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var code = ''; - if (Blockly.Lua.STATEMENT_PREFIX) { - // Automatic prefix insertion is switched off for this block. Add manually. - code += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX, block); - } - if (Blockly.Lua.STATEMENT_SUFFIX) { - // Suffix needs to be added before the function call. - code += Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX, block); - } // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. var tuple = Blockly.Lua['procedures_callreturn'](block); - code += tuple[0] + '\n'; - return code; + return tuple[0] + '\n'; }; Blockly.Lua['procedures_ifreturn'] = function(block) { diff --git a/generators/php/procedures.js b/generators/php/procedures.js index f66703d100c..0f9dd91ac55 100644 --- a/generators/php/procedures.js +++ b/generators/php/procedures.js @@ -114,20 +114,10 @@ Blockly.PHP['procedures_callreturn'] = function(block) { Blockly.PHP['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var code = ''; - if (Blockly.PHP.STATEMENT_PREFIX) { - // Automatic prefix insertion is switched off for this block. Add manually. - code += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX, block); - } - if (Blockly.PHP.STATEMENT_SUFFIX) { - // Suffix needs to be added before the function call. - code += Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX, block); - } // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. var tuple = Blockly.PHP['procedures_callreturn'](block); - code += tuple[0] + ';\n'; - return code; + return tuple[0] + ';\n'; }; Blockly.PHP['procedures_ifreturn'] = function(block) { diff --git a/generators/python/procedures.js b/generators/python/procedures.js index daec89855be..3b81edca49b 100644 --- a/generators/python/procedures.js +++ b/generators/python/procedures.js @@ -117,20 +117,10 @@ Blockly.Python['procedures_callreturn'] = function(block) { Blockly.Python['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. - var code = ''; - if (Blockly.Python.STATEMENT_PREFIX) { - // Automatic prefix insertion is switched off for this block. Add manually. - code += Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX, block); - } - if (Blockly.Python.STATEMENT_SUFFIX) { - // Suffix needs to be added before the function call. - code += Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX, block); - } // Generated code is for a function call as a statement is the same as a // function call as a value, with the addition of line ending. var tuple = Blockly.Python['procedures_callreturn'](block); - code += tuple[0] + '\n'; - return code; + return tuple[0] + '\n'; }; Blockly.Python['procedures_ifreturn'] = function(block) { From ed0b5adcd16efd6be9475cc41ba248294ef62b61 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 14:01:38 -0700 Subject: [PATCH 061/233] Wrong language. --- core/generator.js | 4 ++-- generators/php/math.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/generator.js b/core/generator.js index bc2bf8e6043..d07333722c6 100644 --- a/core/generator.js +++ b/core/generator.js @@ -427,8 +427,8 @@ Blockly.Generator.prototype.init = function(_workspace) { * the block, or to handle comments for the specified block and any connected * value blocks. * @param {!Blockly.Block} _block The current block. - * @param {string} code The JavaScript code created for this block. - * @return {string} JavaScript code with comments and subsequent blocks added. + * @param {string} code The code created for this block. + * @return {string} Code with comments and subsequent blocks added. * @private */ Blockly.Generator.prototype.scrub_ = function(_block, code) { diff --git a/generators/php/math.js b/generators/php/math.js index cef90928119..478faa8c642 100644 --- a/generators/php/math.js +++ b/generators/php/math.js @@ -188,7 +188,7 @@ Blockly.PHP['math_number_property'] = function(block) { ' return true;', '}']); code = functionName + '(' + number_to_check + ')'; - return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; + return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; } switch (dropdown_property) { case 'EVEN': @@ -381,4 +381,4 @@ Blockly.PHP['math_atan2'] = function(block) { Blockly.PHP.ORDER_COMMA) || '0'; return ['atan2(' + argument1 + ', ' + argument0 + ') / pi() * 180', Blockly.PHP.ORDER_DIVISION]; -}; \ No newline at end of file +}; From 49954e0cec8d9cd5bd7363820d8d5c1e90ebf63e Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 15:01:44 -0700 Subject: [PATCH 062/233] Remove calls to goog.dom.getViewportSize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit document.documentElement.clientWidth/clientHeight seems to work everywhere Blockly works. Closure’s functions are mind-numbingly complex due to IE5, old WebKit, Opera 8, and others. --- core/dropdowndiv.js | 2 +- core/tooltip.js | 11 +++++------ core/utils.js | 7 ++----- core/workspace_svg.js | 3 +-- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 1836214dc02..cdcb1438856 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -30,9 +30,9 @@ goog.provide('Blockly.DropDownDiv'); goog.require('Blockly.utils'); -goog.require('goog.dom'); goog.require('goog.style'); + /** * Class for drop-down div. * @constructor diff --git a/core/tooltip.js b/core/tooltip.js index 3abf7787ff0..a423f31dc1a 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -37,8 +37,6 @@ goog.provide('Blockly.Tooltip'); goog.require('Blockly.utils'); -goog.require('goog.dom'); - /** * Is a tooltip currently showing? @@ -303,7 +301,8 @@ Blockly.Tooltip.show_ = function() { Blockly.Tooltip.DIV.appendChild(div); } var rtl = Blockly.Tooltip.element_.RTL; - var windowSize = goog.dom.getViewportSize(); + var windowWidth = document.documentElement.clientWidth; + var windowHeight = document.documentElement.clientHeight; // Display the tooltip. Blockly.Tooltip.DIV.style.direction = rtl ? 'rtl' : 'ltr'; Blockly.Tooltip.DIV.style.display = 'block'; @@ -318,7 +317,7 @@ Blockly.Tooltip.show_ = function() { var anchorY = Blockly.Tooltip.lastY_ + Blockly.Tooltip.OFFSET_Y; if (anchorY + Blockly.Tooltip.DIV.offsetHeight > - windowSize.height + window.scrollY) { + windowHeight + window.scrollY) { // Falling off the bottom of the screen; shift the tooltip up. anchorY -= Blockly.Tooltip.DIV.offsetHeight + 2 * Blockly.Tooltip.OFFSET_Y; } @@ -327,10 +326,10 @@ Blockly.Tooltip.show_ = function() { anchorX = Math.max(Blockly.Tooltip.MARGINS - window.scrollX, anchorX); } else { if (anchorX + Blockly.Tooltip.DIV.offsetWidth > - windowSize.width + window.scrollX - 2 * Blockly.Tooltip.MARGINS) { + windowWidth + window.scrollX - 2 * Blockly.Tooltip.MARGINS) { // Falling off the right edge of the screen; // clamp the tooltip on the edge. - anchorX = windowSize.width - Blockly.Tooltip.DIV.offsetWidth - + anchorX = windowWidth - Blockly.Tooltip.DIV.offsetWidth - 2 * Blockly.Tooltip.MARGINS; } } diff --git a/core/utils.js b/core/utils.js index 9c08ee8cc2d..292a76a591f 100644 --- a/core/utils.js +++ b/core/utils.js @@ -34,7 +34,6 @@ goog.provide('Blockly.utils'); goog.require('Blockly.userAgent'); -goog.require('goog.dom'); goog.require('goog.math.Coordinate'); @@ -909,13 +908,11 @@ Blockly.utils.setCssTransform = function(node, transform) { * @package */ Blockly.utils.getViewportBBox = function() { - // Pixels. - var windowSize = goog.dom.getViewportSize(); // Pixels, in window coordinates. var scrollOffset = goog.style.getViewportPageOffset(document); return { - right: windowSize.width + scrollOffset.x, - bottom: windowSize.height + scrollOffset.y, + right: document.documentElement.clientWidth + scrollOffset.x, + bottom: document.documentElement.clientHeight + scrollOffset.y, top: scrollOffset.y, left: scrollOffset.x }; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 74896cbac74..7f20dca13fd 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -767,8 +767,7 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = function() { /* eslint-disable indent */ var currScroll = goog.dom.getDocumentScroll(); - if (!goog.math.Coordinate.equals(this.lastRecordedPageScroll_, - currScroll)) { + if (!goog.math.Coordinate.equals(this.lastRecordedPageScroll_, currScroll)) { this.lastRecordedPageScroll_ = currScroll; this.updateScreenCalculations_(); } From 25bc3e02684d3b1e9ac98caab6b5819b73340475 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 15:41:48 -0700 Subject: [PATCH 063/233] Fix require statements. Also throw error instead of string. And stop using goog.asserts. --- core/dragged_connection_manager.js | 2 -- core/field_colour.js | 2 +- core/flyout_base.js | 2 +- core/insertion_marker_manager.js | 11 ++++++----- core/toolbox.js | 4 ++-- core/ui_menu_utils.js | 2 ++ core/utils.js | 1 + 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/core/dragged_connection_manager.js b/core/dragged_connection_manager.js index 7b7947a43f6..09cfdab01e4 100644 --- a/core/dragged_connection_manager.js +++ b/core/dragged_connection_manager.js @@ -29,8 +29,6 @@ goog.provide('Blockly.DraggedConnectionManager'); goog.require('Blockly.BlockAnimations'); goog.require('Blockly.RenderedConnection'); -goog.require('goog.math.Coordinate'); - /** * Class that controls updates to connections during drags. It is primarily diff --git a/core/field_colour.js b/core/field_colour.js index f3d17df1f38..a6a501efade 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -29,7 +29,7 @@ goog.provide('Blockly.FieldColour'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Field'); -goog.require('goog.style'); +goog.require('goog.math.Size'); /** diff --git a/core/flyout_base.js b/core/flyout_base.js index b7897e7b1a1..b651f725528 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -37,7 +37,7 @@ goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.Xml'); -goog.require('goog.math.Rect'); +goog.require('goog.math.Coordinate'); /** diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index e0572e4a8f9..8b3bd3079ff 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -30,8 +30,6 @@ goog.require('Blockly.BlockAnimations'); goog.require('Blockly.Events.BlockMove'); goog.require('Blockly.RenderedConnection'); -goog.require('goog.math.Coordinate'); - /** * Class that controls updates to connections during drags. It is primarily @@ -660,7 +658,8 @@ Blockly.InsertionMarkerManager.prototype.disconnectMarker_ = function() { } if (imConn.targetConnection) { - throw 'markerConnection_ still connected at the end of disconnectInsertionMarker'; + throw Error('markerConnection_ still connected at the end of ' + + 'disconnectInsertionMarker'); } this.markerConnection_ = null; @@ -679,8 +678,10 @@ Blockly.InsertionMarkerManager.prototype.connectMarker_ = function() { var imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_; var imConn = imBlock.getMatchingConnection(local.sourceBlock_, local); - goog.asserts.assert(imConn != this.markerConnection_, - 'Made it to connectMarker_ even though the marker isn\'t changing'); + if (imConn == this.markerConnection_) { + throw Error('Made it to connectMarker_ even though the marker isn\'t ' + + 'changing'); + } // Render disconnected from everything else so that we have a valid // connection location. diff --git a/core/toolbox.js b/core/toolbox.js index 890b9d2e3e4..3804cbc370a 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -35,10 +35,10 @@ goog.require('Blockly.VerticalFlyout'); goog.require('goog.events'); goog.require('goog.events.BrowserFeature'); +goog.require('goog.events.EventType'); goog.require('goog.html.SafeHtml'); -goog.require('goog.html.SafeStyle'); goog.require('goog.math.Rect'); -goog.require('goog.style'); +goog.require('goog.ui.tree.BaseNode'); goog.require('goog.ui.tree.TreeControl'); goog.require('goog.ui.tree.TreeNode'); diff --git a/core/ui_menu_utils.js b/core/ui_menu_utils.js index 695041ce74e..a621827fb47 100644 --- a/core/ui_menu_utils.js +++ b/core/ui_menu_utils.js @@ -31,6 +31,8 @@ */ goog.provide('Blockly.utils.uiMenu'); +goog.require('goog.style'); + /** * Get the size of a rendered goog.ui.Menu. diff --git a/core/utils.js b/core/utils.js index 292a76a591f..e5a1f91c15d 100644 --- a/core/utils.js +++ b/core/utils.js @@ -35,6 +35,7 @@ goog.provide('Blockly.utils'); goog.require('Blockly.userAgent'); goog.require('goog.math.Coordinate'); +goog.require('goog.style'); /** From 4161ba0fa7423c47311e0641053d21d8496fc195 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 16:05:18 -0700 Subject: [PATCH 064/233] Move goog.global to Blockly.utils.global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can’t use Blockly.global since that’s the last file to load. --- core/block_svg.js | 1 - core/blockly.js | 14 +++++++------- core/connection.js | 4 ++-- core/mutator.js | 11 ++++++----- core/touch.js | 2 +- core/utils.js | 10 ++++++++-- core/xml.js | 18 ++++++++++-------- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 3b08c919f44..47cee2673c4 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -37,7 +37,6 @@ goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); -goog.require('goog.color'); goog.require('goog.math.Coordinate'); diff --git a/core/blockly.js b/core/blockly.js index 500d4139525..2cbbe956d5c 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -498,7 +498,7 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, }; var bindData = []; - if (goog.global.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) { + if (Blockly.utils.global.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) { for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) { node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); @@ -550,7 +550,7 @@ Blockly.bindEvent_ = function(node, name, thisObject, func) { }; var bindData = []; - var window = goog.global['window']; + var window = Blockly.utils.global['window']; if (window && window.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) { for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) { node.addEventListener(type, wrapFunc, false); @@ -736,7 +736,6 @@ Blockly.refreshTheme_ = function(ws) { Blockly.updateBlockStyles_ = function(blocks) { for (var i = 0, block; block = blocks[i]; i++) { var blockStyleName = block.getStyleName(); - block.setStyle(blockStyleName); if (block.mutator) { block.mutator.updateBlockStyle(blockStyleName); @@ -753,8 +752,9 @@ Blockly.getTheme = function() { }; // Export symbols that would otherwise be renamed by Closure compiler. -if (!goog.global['Blockly']) { - goog.global['Blockly'] = {}; +if (!Blockly.utils.global['Blockly']) { + Blockly.utils.global['Blockly'] = {}; } -goog.global['Blockly']['getMainWorkspace'] = Blockly.getMainWorkspace; -goog.global['Blockly']['addChangeListener'] = Blockly.addChangeListener; +Blockly.utils.global['Blockly']['getMainWorkspace'] = Blockly.getMainWorkspace; +Blockly.utils.global['Blockly']['addChangeListener'] = + Blockly.addChangeListener; diff --git a/core/connection.js b/core/connection.js index f75ae9bf363..739ad131461 100644 --- a/core/connection.js +++ b/core/connection.js @@ -671,8 +671,8 @@ Blockly.Connection.prototype.setCheck = function(check) { /** * Get a connection's compatibility. - * @return {Array} List of compatible value types. Null if - * all types are compatible. + * @return {Array} List of compatible value types. + * Null if all types are compatible. * @public */ Blockly.Connection.prototype.getCheck = function() { diff --git a/core/mutator.js b/core/mutator.js index 307c0bf8a35..fe499e99672 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -481,10 +481,11 @@ Blockly.Mutator.findParentWs = function(workspace) { }; // Export symbols that would otherwise be renamed by Closure compiler. -if (!goog.global['Blockly']) { - goog.global['Blockly'] = {}; +if (!Blockly.utils.global['Blockly']) { + Blockly.utils.global['Blockly'] = {}; } -if (!goog.global['Blockly']['Mutator']) { - goog.global['Blockly']['Mutator'] = {}; +if (!Blockly.utils.global['Blockly']['Mutator']) { + Blockly.utils.global['Blockly']['Mutator'] = {}; } -goog.global['Blockly']['Mutator']['reconnect'] = Blockly.Mutator.reconnect; +Blockly.utils.global['Blockly']['Mutator']['reconnect'] = + Blockly.Mutator.reconnect; diff --git a/core/touch.js b/core/touch.js index 041a4c487fc..69f35a4d00d 100644 --- a/core/touch.js +++ b/core/touch.js @@ -48,7 +48,7 @@ Blockly.Touch.touchIdentifier_ = null; * @type {Object} */ Blockly.Touch.TOUCH_MAP = {}; -if (goog.global.PointerEvent) { +if (Blockly.utils.global.PointerEvent) { Blockly.Touch.TOUCH_MAP = { 'mousedown': ['pointerdown'], 'mouseenter': ['pointerenter'], diff --git a/core/utils.js b/core/utils.js index e5a1f91c15d..b41dda36e19 100644 --- a/core/utils.js +++ b/core/utils.js @@ -808,7 +808,7 @@ Blockly.utils.is3dSupported = function() { } // CC-BY-SA Lorenzo Polidori // stackoverflow.com/questions/5661671/detecting-transform-translate3d-support - if (!goog.global.getComputedStyle) { + if (!Blockly.utils.global.getComputedStyle) { return false; } @@ -828,7 +828,7 @@ Blockly.utils.is3dSupported = function() { for (var t in transforms) { if (el.style[t] !== undefined) { el.style[t] = 'translate3d(1px,1px,1px)'; - var computedStyle = goog.global.getComputedStyle(el); + var computedStyle = Blockly.utils.global.getComputedStyle(el); if (!computedStyle) { // getComputedStyle in Firefox returns null when Blockly is loaded // inside an iframe with display: none. Returning false and not @@ -1027,3 +1027,9 @@ Blockly.utils.clampNumber = function(lowerBound, number, upperBound) { } return Math.max(lowerBound, Math.min(number, upperBound)); }; + +/** + * Reference to the global object. + */ +Blockly.utils.global = this || self; + diff --git a/core/xml.js b/core/xml.js index 75978deeeb7..3c03c0c643a 100644 --- a/core/xml.js +++ b/core/xml.js @@ -781,13 +781,15 @@ Blockly.Xml.deleteNext = function(xmlBlock) { }; // Export symbols that would otherwise be renamed by Closure compiler. -if (!goog.global['Blockly']) { - goog.global['Blockly'] = {}; +if (!Blockly.utils.global['Blockly']) { + Blockly.utils.global['Blockly'] = {}; } -if (!goog.global['Blockly']['Xml']) { - goog.global['Blockly']['Xml'] = {}; +if (!Blockly.utils.global['Blockly']['Xml']) { + Blockly.utils.global['Blockly']['Xml'] = {}; } -goog.global['Blockly']['Xml']['domToText'] = Blockly.Xml.domToText; -goog.global['Blockly']['Xml']['domToWorkspace'] = Blockly.Xml.domToWorkspace; -goog.global['Blockly']['Xml']['textToDom'] = Blockly.Xml.textToDom; -goog.global['Blockly']['Xml']['workspaceToDom'] = Blockly.Xml.workspaceToDom; +Blockly.utils.global['Blockly']['Xml']['domToText'] = Blockly.Xml.domToText; +Blockly.utils.global['Blockly']['Xml']['domToWorkspace'] = + Blockly.Xml.domToWorkspace; +Blockly.utils.global['Blockly']['Xml']['textToDom'] = Blockly.Xml.textToDom; +Blockly.utils.global['Blockly']['Xml']['workspaceToDom'] = + Blockly.Xml.workspaceToDom; From 32631577a46deedc2698e627e8a7ee9572d03ba5 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 16:47:35 -0700 Subject: [PATCH 065/233] Defenestration --- core/block_svg.js | 2 +- core/blockly.js | 13 +++++++------ core/dropdowndiv.js | 4 +++- core/touch.js | 2 +- core/workspace_audio.js | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 47cee2673c4..505da905a6e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -629,7 +629,7 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { Blockly.BlockSvg.prototype.showHelp_ = function() { var url = (typeof this.helpUrl == 'function') ? this.helpUrl() : this.helpUrl; if (url) { - window.open(url); + open(url); } }; diff --git a/core/blockly.js b/core/blockly.js index 2cbbe956d5c..d9c6764d97e 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -383,7 +383,7 @@ Blockly.getMainWorkspace = function() { * @param {function()=} opt_callback The callback when the alert is dismissed. */ Blockly.alert = function(message, opt_callback) { - window.alert(message); + alert(message); if (opt_callback) { opt_callback(); } @@ -396,7 +396,7 @@ Blockly.alert = function(message, opt_callback) { * @param {!function(boolean)} callback The callback for handling user response. */ Blockly.confirm = function(message, callback) { - callback(window.confirm(message)); + callback(confirm(message)); }; /** @@ -409,7 +409,7 @@ Blockly.confirm = function(message, callback) { * @param {!function(string)} callback The callback for handling user response. */ Blockly.prompt = function(message, defaultValue, callback) { - callback(window.prompt(message, defaultValue)); + callback(prompt(message, defaultValue)); }; /** @@ -498,7 +498,8 @@ Blockly.bindEventWithChecks_ = function(node, name, thisObject, func, }; var bindData = []; - if (Blockly.utils.global.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) { + if (Blockly.utils.global['PointerEvent'] && + (name in Blockly.Touch.TOUCH_MAP)) { for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) { node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); @@ -550,8 +551,8 @@ Blockly.bindEvent_ = function(node, name, thisObject, func) { }; var bindData = []; - var window = Blockly.utils.global['window']; - if (window && window.PointerEvent && (name in Blockly.Touch.TOUCH_MAP)) { + if (Blockly.utils.global['PointerEvent'] && + (name in Blockly.Touch.TOUCH_MAP)) { for (var i = 0, type; type = Blockly.Touch.TOUCH_MAP[name][i]; i++) { node.addEventListener(type, wrapFunc, false); bindData.push([node, type, wrapFunc]); diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index cdcb1438856..5af33b8c971 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -456,7 +456,9 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { if (!Blockly.DropDownDiv.isVisible()) { return; } - Blockly.DropDownDiv.animateOutTimer_ && window.clearTimeout(Blockly.DropDownDiv.animateOutTimer_); + if (Blockly.DropDownDiv.animateOutTimer_) { + clearTimeout(Blockly.DropDownDiv.animateOutTimer_); + } Blockly.DropDownDiv.positionInternal_(); Blockly.DropDownDiv.clearContent(); Blockly.DropDownDiv.owner_ = null; diff --git a/core/touch.js b/core/touch.js index 69f35a4d00d..9ca395b306e 100644 --- a/core/touch.js +++ b/core/touch.js @@ -48,7 +48,7 @@ Blockly.Touch.touchIdentifier_ = null; * @type {Object} */ Blockly.Touch.TOUCH_MAP = {}; -if (Blockly.utils.global.PointerEvent) { +if (Blockly.utils.global['PointerEvent']) { Blockly.Touch.TOUCH_MAP = { 'mousedown': ['pointerdown'], 'mouseenter': ['pointerenter'], diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 9e0402551b8..75e02d04cc0 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -82,7 +82,7 @@ Blockly.WorkspaceAudio.prototype.load = function(filenames, name) { return; } try { - var audioTest = new window['Audio'](); + var audioTest = new Blockly.utils.global['Audio'](); } catch (e) { // No browser support for Audio. // IE can throw an error even if the Audio object exists. @@ -94,7 +94,7 @@ Blockly.WorkspaceAudio.prototype.load = function(filenames, name) { var ext = filename.match(/\.(\w+)$/); if (ext && audioTest.canPlayType('audio/' + ext[1])) { // Found an audio format we can play. - sound = new window['Audio'](filename); + sound = new Blockly.utils.global['Audio'](filename); break; } } From 05253d0766f3516a7cfd299c880e381d6500bbc5 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 15 May 2019 17:03:21 -0700 Subject: [PATCH 066/233] Add prefix/suffix to orphaned value blocks. Also respect suppressPrefixSuffix on loops when generating prefix/suffix with continue/break blocks. --- core/generator.js | 10 ++++++++-- generators/dart/loops.js | 2 +- generators/javascript/loops.js | 2 +- generators/lua/loops.js | 2 +- generators/php/loops.js | 2 +- generators/python/loops.js | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/core/generator.js b/core/generator.js index d07333722c6..fc59214c151 100644 --- a/core/generator.js +++ b/core/generator.js @@ -116,6 +116,12 @@ Blockly.Generator.prototype.workspaceToCode = function(workspace) { // This block is a naked value. Ask the language's code generator if // it wants to append a semicolon, or something. line = this.scrubNakedValue(line); + if (this.STATEMENT_PREFIX && !block.suppressPrefixSuffix) { + line = this.injectId(this.STATEMENT_PREFIX, block) + line; + } + if (this.STATEMENT_SUFFIX && !block.suppressPrefixSuffix) { + line = line + this.injectId(this.STATEMENT_SUFFIX, block); + } } code.push(line); } @@ -322,11 +328,11 @@ Blockly.Generator.prototype.addLoopTrap = function(branch, block) { branch = this.prefixLines(this.injectId(this.INFINITE_LOOP_TRAP, block), this.INDENT) + branch; } - if (this.STATEMENT_SUFFIX) { + if (this.STATEMENT_SUFFIX && !block.suppressPrefixSuffix) { branch = this.prefixLines(this.injectId(this.STATEMENT_SUFFIX, block), this.INDENT) + branch; } - if (this.STATEMENT_PREFIX) { + if (this.STATEMENT_PREFIX && !block.suppressPrefixSuffix) { branch = branch + this.prefixLines(this.injectId(this.STATEMENT_PREFIX, block), this.INDENT); } diff --git a/generators/dart/loops.js b/generators/dart/loops.js index b24895e9700..617768ce6ef 100644 --- a/generators/dart/loops.js +++ b/generators/dart/loops.js @@ -166,7 +166,7 @@ Blockly.Dart['controls_flow_statements'] = function(block) { if (Blockly.Dart.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); - if (loop) { + if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. diff --git a/generators/javascript/loops.js b/generators/javascript/loops.js index 3ce74f6b01b..79dda13c14a 100644 --- a/generators/javascript/loops.js +++ b/generators/javascript/loops.js @@ -180,7 +180,7 @@ Blockly.JavaScript['controls_flow_statements'] = function(block) { if (Blockly.JavaScript.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); - if (loop) { + if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. diff --git a/generators/lua/loops.js b/generators/lua/loops.js index 7a41d58b9a8..d229a940292 100644 --- a/generators/lua/loops.js +++ b/generators/lua/loops.js @@ -170,7 +170,7 @@ Blockly.Lua['controls_flow_statements'] = function(block) { if (Blockly.Lua.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); - if (loop) { + if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. diff --git a/generators/php/loops.js b/generators/php/loops.js index 7b277156ee7..09d54de0ae5 100644 --- a/generators/php/loops.js +++ b/generators/php/loops.js @@ -167,7 +167,7 @@ Blockly.PHP['controls_flow_statements'] = function(block) { if (Blockly.PHP.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); - if (loop) { + if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. diff --git a/generators/python/loops.js b/generators/python/loops.js index f0e31a2cd0a..4e331f0892a 100644 --- a/generators/python/loops.js +++ b/generators/python/loops.js @@ -210,7 +210,7 @@ Blockly.Python['controls_flow_statements'] = function(block) { if (Blockly.Python.STATEMENT_PREFIX) { var loop = Blockly.Constants.Loops .CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(block); - if (loop) { + if (loop && !loop.suppressPrefixSuffix) { // Inject loop's statement prefix here since the regular one at the end // of the loop will not get executed if 'continue' is triggered. // In the case of 'break', a prefix is needed due to the loop's suffix. From acd96aa2c5e19a2b9e24f2e3d8714dca0e2ee340 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 17 May 2019 15:19:14 -0700 Subject: [PATCH 067/233] Added Field Value Tests (#2459) * Added field value tests. * Fixed field image src param. * Fixed falsy values with label fields. * Fixed falsy values with text input fields. * Fixed some angle field tests. * Fixed other text input when editing tests. * Fixed colour tests. * Cleaned up some number and variable field tests. * Added angle field > 360 degrees tests. * Fixed variable validator tests. * Split setValue tests into sub-suites. * Fixed angle >360 tests * Changed var declarations to property declarations. --- core/field_checkbox.js | 7 +- core/field_colour.js | 9 +- core/field_date.js | 12 +- core/field_image.js | 21 +- core/field_label.js | 8 +- core/field_label_serializable.js | 4 +- core/field_textinput.js | 8 +- tests/mocha/field_angle_test.js | 248 ++++++++++++++ tests/mocha/field_checkbox_test.js | 173 ++++++++++ tests/mocha/field_colour_test.js | 210 ++++++++++++ tests/mocha/field_date_test.js | 179 ++++++++++ tests/mocha/field_dropdown_test.js | 193 +++++++++++ tests/mocha/field_image_test.js | 169 +++++++++ tests/mocha/field_label_serializable_test.js | 170 +++++++++ tests/mocha/field_label_test.js | 167 +++++++++ tests/mocha/field_number_test.js | 342 +++++++++++++++++++ tests/mocha/field_textinput_test.js | 213 ++++++++++++ tests/mocha/field_variable_test.js | 183 ++++++++-- tests/mocha/index.html | 12 + tests/mocha/test_helpers.js | 2 +- 20 files changed, 2274 insertions(+), 56 deletions(-) create mode 100644 tests/mocha/field_angle_test.js create mode 100644 tests/mocha/field_checkbox_test.js create mode 100644 tests/mocha/field_colour_test.js create mode 100644 tests/mocha/field_date_test.js create mode 100644 tests/mocha/field_dropdown_test.js create mode 100644 tests/mocha/field_image_test.js create mode 100644 tests/mocha/field_label_serializable_test.js create mode 100644 tests/mocha/field_label_test.js create mode 100644 tests/mocha/field_number_test.js create mode 100644 tests/mocha/field_textinput_test.js diff --git a/core/field_checkbox.js b/core/field_checkbox.js index b37217068d3..f096b1e9a27 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -32,7 +32,8 @@ goog.require('Blockly.utils'); /** * Class for a checkbox field. - * @param {string} state The initial state of the field ('TRUE' or 'FALSE'). + * @param {string=} opt_state The initial state of the field ('TRUE' or + * 'FALSE'), defaults to 'FALSE'. * @param {Function=} opt_validator A function that is executed when a new * option is selected. Its sole argument is the new checkbox state. If * it returns a value, this becomes the new checkbox state, unless the @@ -40,10 +41,10 @@ goog.require('Blockly.utils'); * @extends {Blockly.Field} * @constructor */ -Blockly.FieldCheckbox = function(state, opt_validator) { +Blockly.FieldCheckbox = function(opt_state, opt_validator) { Blockly.FieldCheckbox.superClass_.constructor.call(this, '', opt_validator); // Set the initial state. - this.setValue(state); + this.setValue(opt_state); }; goog.inherits(Blockly.FieldCheckbox, Blockly.Field); diff --git a/core/field_colour.js b/core/field_colour.js index a6a501efade..d0796acf0a6 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -34,7 +34,8 @@ goog.require('goog.math.Size'); /** * Class for a colour input field. - * @param {string} colour The initial colour in '#rrggbb' format. + * @param {string=} opt_colour The initial colour in '#rrggbb' format, defaults + * to the first value in the default colour array. * @param {Function=} opt_validator A function that is executed when a new * colour is selected. Its sole argument is the new colour value. Its * return value becomes the selected colour, unless it is undefined, in @@ -43,8 +44,10 @@ goog.require('goog.math.Size'); * @extends {Blockly.Field} * @constructor */ -Blockly.FieldColour = function(colour, opt_validator) { - Blockly.FieldColour.superClass_.constructor.call(this, colour, opt_validator); +Blockly.FieldColour = function(opt_colour, opt_validator) { + opt_colour = opt_colour || Blockly.FieldColour.COLOURS[0]; + Blockly.FieldColour.superClass_.constructor + .call(this, opt_colour, opt_validator); this.setText(Blockly.Field.NBSP + Blockly.Field.NBSP + Blockly.Field.NBSP); }; goog.inherits(Blockly.FieldColour, Blockly.Field); diff --git a/core/field_date.js b/core/field_date.js index de80d026b83..7cbe31a16f4 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -40,7 +40,7 @@ goog.require('goog.ui.DatePicker'); /** * Class for a date input field. - * @param {string} date The initial date. + * @param {string=} opt_date The initial date, defaults to the current day. * @param {Function=} opt_validator A function that is executed when a new * date is selected. Its sole argument is the new date value. Its * return value becomes the selected date, unless it is undefined, in @@ -49,12 +49,12 @@ goog.require('goog.ui.DatePicker'); * @extends {Blockly.Field} * @constructor */ -Blockly.FieldDate = function(date, opt_validator) { - if (!date) { - date = new goog.date.Date().toIsoString(true); +Blockly.FieldDate = function(opt_date, opt_validator) { + if (!opt_date) { + opt_date = new goog.date.Date().toIsoString(true); } - Blockly.FieldDate.superClass_.constructor.call(this, date, opt_validator); - this.setValue(date); + Blockly.FieldDate.superClass_.constructor.call(this, opt_date, opt_validator); + this.setValue(opt_date); }; goog.inherits(Blockly.FieldDate, Blockly.Field); diff --git a/core/field_image.js b/core/field_image.js index dfebb2d2ce0..dda92236407 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -34,9 +34,9 @@ goog.require('goog.math.Size'); /** * Class for an image on a block. - * @param {string} src The URL of the image. - * @param {number} width Width of the image. - * @param {number} height Height of the image. + * @param {string=} src The URL of the image, defaults to an empty string. + * @param {!(string|number)} width Width of the image. + * @param {!(string|number)} height Height of the image. * @param {string=} opt_alt Optional alt text for when block is collapsed. * @param {Function=} opt_onClick Optional function to be called when the image * is clicked. If opt_onClick is defined, opt_alt must also be defined. @@ -48,15 +48,26 @@ Blockly.FieldImage = function(src, width, height, opt_alt, opt_onClick, opt_flipRtl) { this.sourceBlock_ = null; + + if (isNaN(height) || isNaN(width)) { + throw Error('Height and width values of an image field must cast to' + + ' numbers.'); + } + // Ensure height and width are numbers. Strings are bad at math. this.height_ = Number(height); this.width_ = Number(width); + if (this.height_ <= 0 || this.width_ <= 0) { + throw Error('Height and width values of an image field must be greater' + + ' than 0.'); + } this.size_ = new goog.math.Size(this.width_, this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y); + this.flipRtl_ = opt_flipRtl; this.tooltip_ = ''; - this.setValue(src); - this.setText(opt_alt); + this.setValue(src || ''); + this.setText(opt_alt || ''); if (typeof opt_onClick == 'function') { this.clickHandler_ = opt_onClick; diff --git a/core/field_label.js b/core/field_label.js index cecf2b8c0f7..2db51c03a20 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -36,7 +36,8 @@ goog.require('goog.math.Size'); /** * Class for a non-editable, non-serializable text field. - * @param {string} text The initial content of the field. + * @param {string=} text The initial content of the field, defaults to an + * empty string. * @param {string=} opt_class Optional CSS class for the field's text. * @extends {Blockly.Field} * @constructor @@ -44,7 +45,10 @@ goog.require('goog.math.Size'); Blockly.FieldLabel = function(text, opt_class) { this.size_ = new goog.math.Size(0, 17.5); this.class_ = opt_class; - this.setValue(text); + if (text === null || text === undefined) { + text = ''; + } + this.setValue(String(text)); this.tooltip_ = ''; }; goog.inherits(Blockly.FieldLabel, Blockly.Field); diff --git a/core/field_label_serializable.js b/core/field_label_serializable.js index 182ecbbd4dd..b8f579f7f2a 100644 --- a/core/field_label_serializable.js +++ b/core/field_label_serializable.js @@ -33,8 +33,8 @@ goog.require('Blockly.utils'); /** * Class for a non-editable, serializable text field. - * @param {string} text The initial content of the field. - * @param {string} opt_class Optional CSS class for the field's text. + * @param {!string} text The initial content of the field. + * @param {string=} opt_class Optional CSS class for the field's text. * @extends {Blockly.FieldLabel} * @constructor * diff --git a/core/field_textinput.js b/core/field_textinput.js index 3fd38c0284b..088a28109af 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -37,7 +37,8 @@ goog.require('goog.math.Coordinate'); /** * Class for an editable text field. - * @param {string} text The initial content of the field. + * @param {string=} text The initial content of the field, defaults to an + * empty string. * @param {Function=} opt_validator An optional function that is called * to validate any constraints on what the user entered. Takes the new * text as an argument and returns either the accepted text, a replacement @@ -46,7 +47,10 @@ goog.require('goog.math.Coordinate'); * @constructor */ Blockly.FieldTextInput = function(text, opt_validator) { - Blockly.FieldTextInput.superClass_.constructor.call(this, text, + if (text === null || text === undefined) { + text = ''; + } + Blockly.FieldTextInput.superClass_.constructor.call(this, String(text), opt_validator); }; goog.inherits(Blockly.FieldTextInput, Blockly.Field); diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js new file mode 100644 index 00000000000..de468e48f6c --- /dev/null +++ b/tests/mocha/field_angle_test.js @@ -0,0 +1,248 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Angle Fields', function() { + function assertValue(angleField, expectedValue, opt_expectedText) { + var actualValue = angleField.getValue(); + var actualText = angleField.getText(); + opt_expectedText = opt_expectedText || String(expectedValue); + assertEquals(String(actualValue), String(expectedValue)); + assertEquals(parseFloat(actualValue), expectedValue); + assertEquals(actualText, opt_expectedText); + } + function assertValueDefault(angleField) { + assertValue(angleField, 0); + } + suite('Constructor', function() { + test('Empty', function() { + var angleField = new Blockly.FieldAngle(); + assertValueDefault(angleField); + }); + test('Null', function() { + var angleField = new Blockly.FieldAngle(null); + assertValueDefault(angleField); + }); + test('Undefined', function() { + var angleField = new Blockly.FieldAngle(undefined); + assertValueDefault(angleField); + }); + test('Non-Parsable String', function() { + var angleField = new Blockly.FieldAngle('bad'); + assertValueDefault(angleField); + }); + test('NaN', function() { + var angleField = new Blockly.FieldAngle(NaN); + assertValueDefault(angleField); + }); + test('Integer', function() { + var angleField = new Blockly.FieldAngle(1); + assertValue(angleField, 1); + }); + test('Float', function() { + var angleField = new Blockly.FieldAngle(1.5); + assertValue(angleField, 1.5); + }); + test('Integer String', function() { + var angleField = new Blockly.FieldAngle('1'); + assertValue(angleField, 1); + }); + test('Float String', function() { + var angleField = new Blockly.FieldAngle('1.5'); + assertValue(angleField, 1.5); + }); + test('> 360°', function() { + var angleField = new Blockly.FieldAngle(362); + assertValue(angleField, 2); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var angleField = Blockly.FieldAngle.fromJson({}); + assertValueDefault(angleField); + }); + test('Null', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:null }); + assertValueDefault(angleField); + }); + test('Undefined', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:undefined }); + assertValueDefault(angleField); + }); + test('Non-Parsable String', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:'bad' }); + assertValueDefault(angleField); + }); + test('NaN', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:NaN }); + assertValueDefault(angleField); + }); + test('Integer', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:1 }); + assertValue(angleField, 1); + }); + test('Float', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:1.5 }); + assertValue(angleField, 1.5); + }); + test('Integer String', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:'1' }); + assertValue(angleField, 1); + }); + test('Float String', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:'1.5' }); + assertValue(angleField, 1.5); + }); + test('> 360°', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:362 }); + assertValue(angleField, 2); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.angleField = new Blockly.FieldAngle(); + }); + test('Null', function() { + this.angleField.setValue(null); + assertValueDefault(this.angleField); + }); + test('Undefined', function() { + this.angleField.setValue(undefined); + assertValueDefault(this.angleField); + }); + test.skip('Non-Parsable String', function() { + this.angleField.setValue('bad'); + assertValueDefault(this.angleField); + }); + test('NaN', function() { + this.angleField.setValue(NaN); + assertValueDefault(this.angleField); + }); + test('Integer', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue(2.5); + assertValue(this.angleField, 2.5); + }); + test('Integer String', function() { + this.angleField.setValue('2'); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue('2.5'); + assertValue(this.angleField, 2.5); + }); + test('>360°', function() { + this.angleField.setValue(362); + assertValue(this.angleField, 2); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.angleField = new Blockly.FieldAngle(1); + }); + test('Null', function() { + this.angleField.setValue(null); + assertValue(this.angleField, 1); + }); + test.skip('Undefined', function() { + this.angleField.setValue(undefined); + assertValue(this.angleField, 1); + }); + test.skip('Non-Parsable String', function() { + this.angleField.setValue('bad'); + assertValue(this.angleField, 1); + }); + test.skip('NaN', function() { + this.angleField.setValue(NaN); + assertValue(this.angleField, 1); + }); + test('Integer', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue(2.5); + assertValue(this.angleField, 2.5); + }); + test('Integer String', function() { + this.angleField.setValue('2'); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue('2.5'); + assertValue(this.angleField, 2.5); + }); + test('>360°', function() { + this.angleField.setValue(362); + assertValue(this.angleField, 2); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.angleField = new Blockly.FieldAngle(1); + Blockly.FieldTextInput.htmlInput_ = Object.create(null); + Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; + Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; + }); + teardown(function() { + Blockly.FieldTextInput.htmlInput_ = null; + }); + suite('Null Validator', function() { + setup(function() { + this.angleField.setValidator(function() { + return null; + }); + }); + test('When Editing', function() { + this.angleField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '2'; + this.angleField.onHtmlInputChange_(null); + assertValue(this.angleField, 1, '2'); + this.angleField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 1); + }); + }); + suite('Force Mult of 30 Validator', function() { + setup(function() { + this.angleField.setValidator(function(newValue) { + return Math.round(newValue / 30) * 30; + }); + }); + test('When Editing', function() { + this.angleField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '25'; + this.angleField.onHtmlInputChange_(null); + assertValue(this.angleField, 30, '25'); + this.angleField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.angleField.setValue(25); + assertValue(this.angleField, 30); + }); + }); + }); +}); diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js new file mode 100644 index 00000000000..0c909df82b1 --- /dev/null +++ b/tests/mocha/field_checkbox_test.js @@ -0,0 +1,173 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite.skip('Checkbox Fields', function() { + function assertValue(checkboxField, expectedValue, expectedText) { + var actualValue = checkboxField.getValue(); + var actualText = checkboxField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + function assertValueDefault(checkboxField) { + assertValue(checkboxField, 'FALSE', 'false'); + } + suite('Constructor', function() { + test('Null', function() { + var checkboxField = new Blockly.FieldCheckbox(null); + assertValueDefault(checkboxField); + }); + test('Undefined', function() { + var checkboxField = new Blockly.FieldCheckbox(undefined); + assertValueDefault(checkboxField); + }); + test('Non-Parsable String', function() { + var checkboxField = new Blockly.FieldCheckbox('bad'); + assertValueDefault(checkboxField); + }); + test('True', function() { + var checkboxField = new Blockly.FieldCheckbox(true); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('False', function() { + var checkboxField = new Blockly.FieldCheckbox(false); + assertValue(checkboxField, 'FALSE', 'false'); + }); + test('String TRUE', function() { + var checkboxField = new Blockly.FieldCheckbox('TRUE'); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('String FALSE', function() { + var checkboxField = new Blockly.FieldCheckbox('FALSE'); + assertValue(checkboxField, 'FALSE', 'false'); + }); + }); + suite('fromJson', function() { + test('Null', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: null}); + assertValueDefault(checkboxField); + }); + test('Undefined', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: undefined}); + assertValueDefault(checkboxField); + }); + test('Non-Parsable String', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: 'bad'}); + assertValueDefault(checkboxField); + }); + test('True', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: true}); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('False', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: false}); + assertValue(checkboxField, 'FALSE', 'false'); + }); + test('String TRUE', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: 'TRUE'}); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('String FALSE', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: 'FALSE'}); + assertValue(checkboxField, 'FALSE', 'false'); + }); + }); + suite('setValue', function() { + suite('True -> New Value', function() { + setup(function() { + this.checkboxField = new Blockly.FieldCheckbox('TRUE'); + }); + test('Null', function() { + this.checkboxField.setValue(null); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + test('Undefined', function() { + this.checkboxField.setValue(undefined); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + test('Non-Parsable String', function() { + this.checkboxField.setValue('bad'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + test('False', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + }); + suite('False -> New Value', function() { + setup(function() { + this.checkboxField = new Blockly.FieldCheckbox('FALSE'); + }); + test('Null', function() { + this.checkboxField.setValue(null); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + test('Undefined', function() { + this.checkboxField.setValue(undefined); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + test('Non-Parsable String', function() { + this.checkboxField.setValue('bad'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + test('True', function() { + this.checkboxField.setValue('TRUE'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + }); + }); + suite('Validators', function() { + setup(function() { + this.checkboxField = new Blockly.FieldCheckbox(true); + }); + suite('Null Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + }); + suite('Always True Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() { + return 'TRUE'; + }); + }); + test('New Value', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + }); + suite('Always False Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() { + return 'FALSE'; + }); + }); + test('New Value', function() { + this.checkboxField.setValue('TRUE'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + }); + }); +}); diff --git a/tests/mocha/field_colour_test.js b/tests/mocha/field_colour_test.js new file mode 100644 index 00000000000..2979bf0caed --- /dev/null +++ b/tests/mocha/field_colour_test.js @@ -0,0 +1,210 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Colour Fields', function() { + function assertValue(colourField, expectedValue, expectedText) { + var actualValue = colourField.getValue(); + var actualText = colourField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + function assertValueDefault(colourField) { + var expectedValue = Blockly.FieldColour.COLOURS[0]; + var expectedText = expectedValue; + var m = expectedValue.match(/^#(.)\1(.)\2(.)\3$/); + if (m) { + expectedText = '#' + m[1] + m[2] + m[3]; + } + assertValue(colourField, expectedValue, expectedText); + } + + setup(function() { + this.previousColours = Blockly.FieldColour.COLOURS; + Blockly.FieldColour.Colours = [ + '#ffffff', '#ff0000', '#00ff00', '#0000ff', '#ffffff' + ]; + }); + teardown(function() { + Blockly.FieldColour.Colours = this.previousColours; + }); + suite('Constructor', function() { + test('Empty', function() { + var colourField = new Blockly.FieldColour(); + assertValueDefault(colourField); + }); + test('Null', function() { + var colourField = new Blockly.FieldColour(null); + assertValueDefault(colourField); + }); + test('Undefined', function() { + var colourField = new Blockly.FieldColour(undefined); + assertValueDefault(colourField); + }); + test.skip('Non-Parsable String', function() { + var colourField = new Blockly.FieldColour('bad'); + assertValueDefault(colourField); + }); + test.skip('#AAAAAA', function() { + var colourField = new Blockly.FieldColour('#AAAAAA'); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test('#aaaaaa', function() { + var colourField = new Blockly.FieldColour('#aaaaaa'); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test.skip('#AAAA00', function() { + var colourField = new Blockly.FieldColour('#AAAA00'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('#aaaa00', function() { + var colourField = new Blockly.FieldColour('#aaaa00'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test.skip('#BCBCBC', function() { + var colourField = new Blockly.FieldColour('#BCBCBC'); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + test('#bcbcbc', function() { + var colourField = new Blockly.FieldColour('#bcbcbc'); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var colourField = new Blockly.FieldColour.fromJson({}); + assertValueDefault(colourField); + }); + test('Null', function() { + var colourField = new Blockly.FieldColour.fromJson({ colour:null }); + assertValueDefault(colourField); + }); + test('Undefined', function() { + var colourField = new Blockly.FieldColour.fromJson({ colour:undefined }); + assertValueDefault(colourField); + }); + test.skip('Non-Parsable String', function() { + var colourField = new Blockly.FieldColour.fromJson({ colour:'bad' }); + assertValueDefault(colourField); + }); + test.skip('#AAAAAA', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAAAA' }); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test('#aaaaaa', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaaaa' }); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test.skip('#AAAA00', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAA00' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('#aaaa00', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaa00' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test.skip('#BCBCBC', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#BCBCBC' }); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + test('#bcbcbc', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#bcbcbc' }); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.colourField = new Blockly.FieldColour(); + }); + test.skip('Null', function() { + this.colourField.setValue(null); + assertValueDefault(this.colourField); + }); + test.skip('Undefined', function() { + this.colourField.setValue(undefined); + assertValueDefault(this.colourField); + }); + test.skip('Non-Parsable String', function() { + this.colourField.setValue('bad'); + assertValueDefault(this.colourField); + }); + test('#000000', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#000000', '#000'); + }); + test('#bcbcbc', function() { + this.colourField.setValue('#bcbcbc'); + assertValue(this.colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.colourField = new Blockly.FieldColour('#aaaaaa'); + }); + test.skip('Null', function() { + this.colourField.setValue(null); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + test.skip('Undefined', function() { + this.colourField.setValue(undefined); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + test.skip('Non-Parsable String', function() { + this.colourField.setValue('bad'); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + test('#000000', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#000000', '#000'); + }); + test('#bcbcbc', function() { + this.colourField.setValue('#bcbcbc'); + assertValue(this.colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.colourField = new Blockly.FieldColour('#aaaaaa'); + }); + suite('Null Validator', function() { + setup(function() { + this.colourField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + }); + suite('Force Full Red Validator', function() { + setup(function() { + this.colourField.setValidator(function(newValue) { + return '#ff' + newValue.substr(3, 4); + }); + }); + test('New Value', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#ff0000', '#f00'); + }); + }); + }); +}); diff --git a/tests/mocha/field_date_test.js b/tests/mocha/field_date_test.js new file mode 100644 index 00000000000..cc95b36ba61 --- /dev/null +++ b/tests/mocha/field_date_test.js @@ -0,0 +1,179 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Date Fields', function() { + function assertValue(dateField, expectedValue) { + var actualValue = dateField.getValue(); + var actualText = dateField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedValue); + } + function assertValueDefault(dateField) { + var today = new goog.date.Date().toIsoString(true); + assertValue(dateField, today); + } + suite('Constructor', function() { + test('Empty', function() { + var dateField = new Blockly.FieldDate(); + assertValueDefault(dateField); + }); + test('Null', function() { + var dateField = new Blockly.FieldDate(null); + assertValueDefault(dateField); + }); + test('Undefined', function() { + var dateField = new Blockly.FieldDate(undefined); + assertValueDefault(dateField); + }); + test.skip('Non-Parsable String', function() { + var dateField = new Blockly.FieldDate('bad'); + assertValueDefault(dateField); + }); + test('2020-02-20', function() { + var dateField = new Blockly.FieldDate('2020-02-20'); + assertValue(dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + var dateField = new Blockly.FieldDate('2020-13-20'); + assertValueDefault(dateField); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + var dateField = new Blockly.FieldDate('2020-02-32'); + assertValueDefault(dateField); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var dateField = Blockly.FieldDate.fromJson({}); + assertValueDefault(dateField); + }); + test('Null', function() { + var dateField = Blockly.FieldDate.fromJson({ date: null }); + assertValueDefault(dateField); + }); + test('Undefined', function() { + var dateField = Blockly.FieldDate.fromJson({ date: undefined }); + assertValueDefault(dateField); + }); + test.skip('Non-Parsable String', function() { + var dateField = Blockly.FieldDate.fromJson({ date: 'bad' }); + assertValueDefault(dateField); + }); + test('2020-02-20', function() { + var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-20' }); + assertValue(dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + var dateField = Blockly.FieldDate.fromJson({ date: '2020-13-20' }); + assertValueDefault(dateField); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-32' }); + assertValueDefault(dateField); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.dateField = new Blockly.FieldDate(); + }); + test.skip('Null', function() { + this.dateField.setValue(null); + assertValueDefault(this.dateField); + }); + test.skip('Undefined', function() { + this.dateField.setValue(undefined); + assertValueDefault(this.dateField); + }); + test.skip('Non-Parsable String', function() { + this.dateField.setValue('bad'); + assertValueDefault(this.dateField); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + this.dateField.setValue('2020-13-20'); + assertValueDefault(this.dateField); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + this.dateField.setValue('2020-02-32'); + assertValueDefault(this.dateField); + }); + test('3030-03-30', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-30'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.dateField = new Blockly.FieldDate('2020-02-20'); + }); + test.skip('Null', function() { + this.dateField.setValue(null); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Undefined', function() { + this.dateField.setValue(undefined); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Non-Parsable String', function() { + this.dateField.setValue('bad'); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + this.dateField.setValue('2020-13-20'); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + this.dateField.setValue('2020-02-32'); + assertValue(this.dateField, '2020-02-20'); + }); + test('3030-03-30', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-30'); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.dateField = new Blockly.FieldDate('2020-02-20'); + }); + suite('Null Validator', function() { + setup(function() { + this.dateField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '2020-02-20'); + }); + }); + suite('Force Day 20s Validator', function() { + setup(function() { + this.dateField.setValidator(function(newValue) { + return newValue.substr(0, 8) + '2' + newValue.substr(9, 1); + }); + }); + test('New Value', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-20'); + }); + }); + }); +}); diff --git a/tests/mocha/field_dropdown_test.js b/tests/mocha/field_dropdown_test.js new file mode 100644 index 00000000000..23c5f8016dd --- /dev/null +++ b/tests/mocha/field_dropdown_test.js @@ -0,0 +1,193 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Dropdown Fields', function() { + function assertValue(dropdownField, expectedValue, expectedText) { + var actualValue = dropdownField.getValue(); + var actualText = dropdownField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + suite('Constructor', function() { + test('Empty', function() { + chai.assert.throws(function() { + new Blockly.FieldDropdown(); + }); + }); + test('Null', function() { + chai.assert.throws(function() { + new Blockly.FieldDropdown(null); + }); + }); + test('Undefined', function() { + chai.assert.throws(function() { + new Blockly.FieldDropdown(undefined); + }); + }); + test('Array Items not Arrays', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + new Blockly.FieldDropdown([1, 2, 3]); + }); + }); + test('Array Items with Invalid IDs', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + new Blockly.FieldDropdown([['1', 1], ['2', 2], ['3', 3]]); + }); + }); + test('Array Items with Invalid Content', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + new Blockly.FieldDropdown([[1, '1'], [2, '2'], [3, '3']]); + }); + }); + test('Text Dropdown', function() { + var dropdownField = new Blockly.FieldDropdown( + [['a', 'A'], ['b', 'B'], ['c', 'C']]); + assertValue(dropdownField, 'A', 'a'); + }); + test('Image Dropdown', function() { + var dropdownField = new Blockly.FieldDropdown([ + [{ src:'scrA', alt:'a' }, 'A'], + [{ src:'scrB', alt:'b' }, 'B'], + [{ src:'scrC', alt:'c' }, 'C']]); + assertValue(dropdownField, 'A', 'a'); + }); + test('Dynamic Dropdown Text', function() { + var dynamicDropdownFunc = function() { + return [['a', 'A'], ['b', 'B'], ['c', 'C']]; + }; + var dropdownField = new Blockly.FieldDropdown(dynamicDropdownFunc); + assertValue(dropdownField, 'A', 'a'); + }); + test('Dynamic Dropdown Image', function() { + var dynamicDropdownFunc = function() { + return [ + [{ src:'scrA', alt:'a' }, 'A'], + [{ src:'scrB', alt:'b' }, 'B'], + [{ src:'scrC', alt:'c' }, 'C'] + ]; + }; + var dropdownField = new Blockly.FieldDropdown(dynamicDropdownFunc); + assertValue(dropdownField, 'A', 'a'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({}); + }); + }); + test('Null', function() { + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({ options: null }); + }); + }); + test('Undefined', function() { + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({ options: undefined }); + }); + }); + test('Array Items not Arrays', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({ options: [1, 2, 3] }); + }); + }); + test('Array Items with Invalid IDs', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson( + { options:[['1', 1], ['2', 2], ['3', 3]] }); + }); + }); + test('Array Items with Invalid Content', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson( + { options:[[1, '1'], [2, '2'], [3, '3']] }); + }); + }); + test('Text Dropdown', function() { + var dropdownField = Blockly.FieldDropdown.fromJson( + { options:[['a', 'A'], ['b', 'B'], ['c', 'C']] }); + assertValue(dropdownField, 'A', 'a'); + }); + test('Image Dropdown', function() { + var dropdownField = Blockly.FieldDropdown.fromJson({ options:[ + [{ src:'scrA', alt:'a' }, 'A'], + [{ src:'scrB', alt:'b' }, 'B'], + [{ src:'scrC', alt:'c' }, 'C']] }); + assertValue(dropdownField, 'A', 'a'); + }); + }); + suite('setValue', function() { + setup(function() { + this.dropdownField = new Blockly.FieldDropdown( + [['a', 'A'], ['b', 'B'], ['c', 'C']]); + }); + test('Null', function() { + this.dropdownField.setValue(null); + assertValue(this.dropdownField, 'A', 'a'); + }); + test.skip('Undefined', function() { + this.dropdownField.setValue(undefined); + assertValue(this.dropdownField, 'A', 'a'); + }); + test.skip('Invalid ID', function() { + this.dropdownField.setValue('bad'); + assertValue(this.dropdownField, 'A', 'a'); + }); + test('Valid ID', function() { + this.dropdownField.setValue('B'); + assertValue(this.dropdownField, 'B', 'b'); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.dropdownField = new Blockly.FieldDropdown([ + ["1a","1A"], ["1b","1B"], ["1c","1C"], + ["2a","2A"], ["2b","2B"], ["2c","2C"]]); + }); + suite('Null Validator', function() { + setup(function() { + this.dropdownField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.dropdownField.setValue('1B'); + assertValue(this.dropdownField, '1A', '1a'); + }); + }); + suite('Force 1s Validator', function() { + setup(function() { + this.dropdownField.setValidator(function(newValue) { + return '1' + newValue.charAt(1); + }); + }); + test('New Value', function() { + this.dropdownField.setValue('2B'); + assertValue(this.dropdownField, '1B', '1b'); + }); + }); + }); +}); diff --git a/tests/mocha/field_image_test.js b/tests/mocha/field_image_test.js new file mode 100644 index 00000000000..eb968882cda --- /dev/null +++ b/tests/mocha/field_image_test.js @@ -0,0 +1,169 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Image Fields', function() { + function assertValue(imageField, expectedValue, expectedText) { + var actualValue = imageField.getValue(); + var actualText = imageField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + function assertValueDefault(imageField) { + assertValue(imageField, '', ''); + } + suite('Constructor', function() { + test('Empty', function() { + chai.assert.throws(function() { + new Blockly.FieldImage(); + }); + }); + test('Null Src', function() { + var imageField = new Blockly.FieldImage(null, 1, 1); + assertValueDefault(imageField); + }); + test('Undefined Src', function() { + var imageField = new Blockly.FieldImage(undefined, 1, 1); + assertValueDefault(imageField); + }); + test('Null Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', null, null); + }); + }); + test('Undefined Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', undefined, undefined); + }); + }); + test('Zero Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', 0, 0); + }); + }); + test('Non-Parsable String for Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', 'bad', 'bad'); + }); + }); + // Note: passing invalid an src path doesn't need to throw errors + // because the developer can see they did it incorrectly when they view + // the block. + test('With Alt', function() { + var imageField = new Blockly.FieldImage('src', 1, 1, 'alt'); + assertValue(imageField, 'src', 'alt'); + }); + test('Without Alt', function() { + var imageField = new Blockly.FieldImage('src', 1, 1); + assertValue(imageField, 'src', ''); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({}); + }); + }); + test('Null Src', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: null, + width: 1, + height: 1 + }); + assertValueDefault(imageField); + }); + test('Undefined Src', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: undefined, + width: 1, + height: 1 + }); + assertValueDefault(imageField); + }); + test('Null Size', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({ + src: 'src', + width: null, + height: null + }); + }); + }); + test('Undefined Size', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({ + src: 'src', + width: undefined, + height: undefined + }); + }); + }); + test('Non-Parsable String for Size', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({ + src: 'src', + width: 'bad', + height: 'bad' + }); + }); + }); + test('With Alt', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: 'src', + width: 1, + height: 1, + alt: 'alt' + }); + assertValue(imageField, 'src', 'alt'); + }); + test('Without Alt', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: 'src', + width: 1, + height: 1 + }); + assertValue(imageField, 'src', ''); + }); + }); + suite('setValue', function() { + setup(function() { + this.imageField = new Blockly.FieldImage('src', 1, 1, 'alt'); + }); + test('Null', function() { + this.imageField.setValue(null); + assertValue(this.imageField, 'src', 'alt'); + }); + test.skip('Undefined', function() { + this.imageField.setValue(undefined); + assertValue(this.imageField, 'src', 'alt'); + }); + test('New Src, New Alt', function() { + this.imageField.setValue('newSrc'); + assertValue(this.imageField, 'newSrc', 'alt'); + this.imageField.setText('newAlt'); + assertValue(this.imageField, 'newSrc', 'newAlt'); + }); + test('New Alt, New Src', function() { + this.imageField.setText('newAlt'); + assertValue(this.imageField, 'src', 'newAlt'); + this.imageField.setValue('newSrc'); + assertValue(this.imageField, 'newSrc', 'newAlt'); + }); + }); +}); diff --git a/tests/mocha/field_label_serializable_test.js b/tests/mocha/field_label_serializable_test.js new file mode 100644 index 00000000000..e59fd329cea --- /dev/null +++ b/tests/mocha/field_label_serializable_test.js @@ -0,0 +1,170 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Label Serializable Fields', function() { + function assertValue(labelField, expectedValue) { + var actualValue = labelField.getValue(); + var actualText = labelField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedValue); + } + function assertValueDefault(labelField) { + assertValue(labelField, ''); + } + suite('Constructor', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabelSerializable(); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabelSerializable(null); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabelSerializable(undefined); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = new Blockly.FieldLabelSerializable('value'); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = new Blockly.FieldLabelSerializable(1); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = new Blockly.FieldLabelSerializable(0); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = new Blockly.FieldLabelSerializable(true); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = new Blockly.FieldLabelSerializable(false); + assertValue(labelField, 'false'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabelSerializable.fromJson({}); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabelSerializable + .fromJson({ text:null }); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabelSerializable + .fromJson({ text:undefined }); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = Blockly.FieldLabelSerializable + .fromJson({ text:'value' }); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:1 }); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:0 }); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:true }); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:false }); + assertValue(labelField, 'false'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabelSerializable(); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValueDefault(this.labelField); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValueDefault(this.labelField); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test.skip('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test.skip('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabelSerializable('value'); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValue(this.labelField, 'value'); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValue(this.labelField, 'value'); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + }); +}); diff --git a/tests/mocha/field_label_test.js b/tests/mocha/field_label_test.js new file mode 100644 index 00000000000..1974da55e0d --- /dev/null +++ b/tests/mocha/field_label_test.js @@ -0,0 +1,167 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Label Fields', function() { + function assertValue(labelField, expectedValue) { + var actualValue = labelField.getValue(); + var actualText = labelField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedValue); + } + function assertValueDefault(labelField) { + assertValue(labelField, ''); + } + suite('Constructor', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabel(); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabel(null); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabel(undefined); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = new Blockly.FieldLabel('value'); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = new Blockly.FieldLabel(1); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = new Blockly.FieldLabel(0); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = new Blockly.FieldLabel(true); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = new Blockly.FieldLabel(false); + assertValue(labelField, 'false'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabel.fromJson({}); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabel.fromJson({ text:null }); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabel.fromJson({ text:undefined }); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:'value' }); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:1 }); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:0 }); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:true }); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:false }); + assertValue(labelField, 'false'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabel(); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValueDefault(this.labelField); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValueDefault(this.labelField); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test.skip('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test.skip('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabel('value'); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValue(this.labelField, 'value'); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValue(this.labelField, 'value'); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + }); +}); diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js new file mode 100644 index 00000000000..f0c1d1db0f5 --- /dev/null +++ b/tests/mocha/field_number_test.js @@ -0,0 +1,342 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Number Fields', function() { + function assertValue(numberField, expectedValue, opt_expectedText) { + var actualValue = numberField.getValue(); + var actualText = numberField.getText(); + opt_expectedText = opt_expectedText || String(expectedValue); + assertEquals(String(actualValue), String(expectedValue)); + assertEquals(parseFloat(actualValue), expectedValue); + assertEquals(actualText, opt_expectedText); + } + function assertValueDefault(numberFieldField) { + assertValue(numberFieldField, 0); + } + function assertNumberField(numberField, expectedMin, expectedMax, + expectedPrecision, expectedValue) { + assertValue(numberField, expectedValue); + assertEquals(numberField.min_, expectedMin); + assertEquals(numberField.max_, expectedMax); + assertEquals(numberField.precision_, expectedPrecision); + } + function assertNumberFieldDefault(numberField) { + assertNumberField(numberField, -Infinity, Infinity, 0, 0); + } + function createNumberFieldSameValuesConstructor(value) { + return new Blockly.FieldNumber(value, value, value, value); + } + function createNumberFieldSameValuesJson(value) { + return Blockly.FieldNumber.fromJson( + { 'value': value, min: value, max: value, precision: value }); + } + function assertNumberFieldSameValues(numberField, value) { + assertNumberField(numberField, value, value, value, value); + } + suite('Constructor', function() { + test('Empty', function() { + var numberField = new Blockly.FieldNumber(); + assertNumberFieldDefault(numberField); + }); + test('Null', function() { + var numberField = createNumberFieldSameValuesConstructor(null); + assertNumberFieldDefault(numberField); + }); + test('Undefined', function() { + var numberField = createNumberFieldSameValuesConstructor(undefined); + assertNumberFieldDefault(numberField); + }); + test('Non-Parsable String', function() { + var numberField = createNumberFieldSameValuesConstructor('bad'); + assertNumberFieldDefault(numberField); + }); + test('NaN', function() { + var numberField = createNumberFieldSameValuesConstructor(NaN); + assertNumberFieldDefault(numberField); + }); + test('Integer', function() { + var numberField = createNumberFieldSameValuesConstructor(1); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float', function() { + var numberField = createNumberFieldSameValuesConstructor(1.5); + assertNumberFieldSameValues(numberField, 1.5); + }); + test('Integer String', function() { + var numberField = createNumberFieldSameValuesConstructor('1'); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float String', function() { + var numberField = createNumberFieldSameValuesConstructor('1.5'); + assertNumberFieldSameValues(numberField, 1.5); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var numberField = Blockly.FieldNumber.fromJson({}); + assertNumberFieldDefault(numberField); + }); + test('Null', function() { + var numberField = createNumberFieldSameValuesJson(null); + assertNumberFieldDefault(numberField); + }); + test('Undefined', function() { + var numberField = createNumberFieldSameValuesJson(undefined); + assertNumberFieldDefault(numberField); + }); + test('Non-Parsable String', function() { + var numberField = createNumberFieldSameValuesJson('bad'); + assertNumberFieldDefault(numberField); + }); + test('NaN', function() { + var numberField = createNumberFieldSameValuesJson(NaN); + assertNumberFieldDefault(numberField); + }); + test('Integer', function() { + var numberField = createNumberFieldSameValuesJson(1); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float', function() { + var numberField = createNumberFieldSameValuesJson(1.5); + assertNumberFieldSameValues(numberField, 1.5); + }); + test('Integer String', function() { + var numberField = createNumberFieldSameValuesJson('1'); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float String', function() { + var numberField = createNumberFieldSameValuesJson('1.5'); + assertNumberFieldSameValues(numberField, 1.5); + }); + }); + suite('setValue', function() { + suite('Value Types', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.numberField = new Blockly.FieldNumber(); + }); + test('Null', function() { + this.numberField.setValue(null); + assertValueDefault(this.numberField); + }); + test.skip('Undefined', function() { + this.numberField.setValue(undefined); + assertValueDefault(this.numberField); + }); + test.skip('Non-Parsable String', function() { + this.numberField.setValue('bad'); + assertValueDefault(this.numberField); + }); + test.skip('NaN', function() { + this.numberField.setValue(NaN); + assertValueDefault(this.numberField); + }); + test('Integer', function() { + this.numberField.setValue(2); + assertValue(this.numberField, 2); + }); + test('Float', function() { + this.numberField.setValue(2.5); + assertValue(this.numberField, 2.5); + }); + test('Integer String', function() { + this.numberField.setValue('2'); + assertValue(this.numberField, 2); + }); + test('Float String', function() { + this.numberField.setValue('2.5'); + assertValue(this.numberField, 2.5); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.numberField = new Blockly.FieldNumber(1); + }); + test('Null', function() { + this.numberField.setValue(null); + assertValue(this.numberField, 1); + }); + test.skip('Undefined', function() { + this.numberField.setValue(undefined); + assertValue(this.numberField, 1); + }); + test.skip('Non-Parsable String', function() { + this.numberField.setValue('bad'); + assertValue(this.numberField, 1); + }); + test.skip('NaN', function() { + this.numberField.setValue(NaN); + assertValue(this.numberField, 1); + }); + test('Integer', function() { + this.numberField.setValue(2); + assertValue(this.numberField, 2); + }); + test('Float', function() { + this.numberField.setValue(2.5); + assertValue(this.numberField, 2.5); + }); + test('Integer String', function() { + this.numberField.setValue('2'); + assertValue(this.numberField, 2); + }); + test('Float String', function() { + this.numberField.setValue('2.5'); + assertValue(this.numberField, 2.5); + }); + }); + }); + suite('Constraints', function() { + suite('Precision', function() { + test('Float', function() { + var numberField = new Blockly.FieldNumber(); + numberField.setValue(123.456); + assertValue(numberField, 123.456); + }); + test('0.01', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: .01 }); + numberField.setValue(123.456); + assertValue(numberField, 123.46); + }); + test('0.5', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: .5 }); + numberField.setValue(123.456); + assertValue(numberField, 123.5); + }); + test('1', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: 1 }); + numberField.setValue(123.456); + assertValue(numberField, 123); + }); + test.skip('1.5', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: 1.5 }); + numberField.setValue(123.456); + assertValue(numberField, 123); + }); + }); + suite('Min', function() { + test('-10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ min: -10 }); + numberField.setValue(-20); + assertValue(numberField, -10); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 20); + }); + test('0', function() { + var numberField = new Blockly.FieldNumber.fromJson({ min: 0 }); + numberField.setValue(-20); + assertValue(numberField, 0); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 20); + }); + test('+10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ min: 10 }); + numberField.setValue(-20); + assertValue(numberField, 10); + numberField.setValue(0); + assertValue(numberField, 10); + numberField.setValue(20); + assertValue(numberField, 20); + }); + }); + suite('Max', function() { + test('-10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ max: -10 }); + numberField.setValue(-20); + assertValue(numberField, -20); + numberField.setValue(0); + assertValue(numberField, -10); + numberField.setValue(20); + assertValue(numberField, -10); + }); + test('0', function() { + var numberField = new Blockly.FieldNumber.fromJson({ max: 0 }); + numberField.setValue(-20); + assertValue(numberField, -20); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 0); + }); + test('+10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ max: 10 }); + numberField.setValue(-20); + assertValue(numberField, -20); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 10); + }); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.numberFieldField = new Blockly.FieldNumber(1); + Blockly.FieldTextInput.htmlInput_ = Object.create(null); + Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; + Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; + }); + suite('Null Validator', function() { + setup(function() { + this.numberFieldField.setValidator(function() { + return null; + }); + }); + test('When Editing', function() { + this.numberFieldField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '2'; + this.numberFieldField.onHtmlInputChange_(null); + assertValue(this.numberFieldField, 1, '2'); + this.numberFieldField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.numberFieldField.setValue(2); + assertValue(this.numberFieldField, 1); + }); + }); + suite('Force End with 6 Validator', function() { + setup(function() { + this.numberFieldField.setValidator(function(newValue) { + return String(newValue).replace(/.$/, "6"); + }); + }); + test('When Editing', function() { + this.numberFieldField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '25'; + this.numberFieldField.onHtmlInputChange_(null); + assertValue(this.numberFieldField, 26, '25'); + this.numberFieldField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.numberFieldField.setValue(25); + assertValue(this.numberFieldField, 26); + }); + }); + }); +}); diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js new file mode 100644 index 00000000000..2a1b72b06c4 --- /dev/null +++ b/tests/mocha/field_textinput_test.js @@ -0,0 +1,213 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Text Input Fields', function() { + function assertValue(textInputField, expectedValue, opt_expectedText) { + var actualValue = textInputField.getValue(); + var actualText = textInputField.getText(); + opt_expectedText = opt_expectedText || expectedValue; + assertEquals(actualValue, expectedValue); + assertEquals(actualText, opt_expectedText); + } + function assertValueDefault(textInputField) { + assertValue(textInputField, ''); + } + suite('Constructor', function() { + test('Empty', function() { + var textInputField = new Blockly.FieldTextInput(); + assertValueDefault(textInputField); + }); + test('Null', function() { + var textInputField = new Blockly.FieldTextInput(null); + assertValueDefault(textInputField); + }); + test('Undefined', function() { + var textInputField = new Blockly.FieldTextInput(undefined); + assertValueDefault(textInputField); + }); + test('String', function() { + var textInputField = new Blockly.FieldTextInput('value'); + assertValue(textInputField, 'value'); + }); + test('Number (Truthy)', function() { + var textInputField = new Blockly.FieldTextInput(1); + assertValue(textInputField, '1'); + }); + test('Number (Falsy)', function() { + var textInputField = new Blockly.FieldTextInput(0); + assertValue(textInputField, '0'); + }); + test('Boolean True', function() { + var textInputField = new Blockly.FieldTextInput(true); + assertValue(textInputField, 'true'); + }); + test('Boolean False', function() { + var textInputField = new Blockly.FieldTextInput(false); + assertValue(textInputField, 'false'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var textInputField = new Blockly.FieldTextInput.fromJson({}); + assertValueDefault(textInputField); + }); + test('Null', function() { + var textInputField = new Blockly.FieldTextInput.fromJson({ text: null}); + assertValueDefault(textInputField); + }); + test('Undefined', function() { + var textInputField = new Blockly.FieldTextInput + .fromJson({ text: undefined}); + assertValueDefault(textInputField); + }); + test('String', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:'value' }); + assertValue(textInputField, 'value'); + }); + test('Number (Truthy)', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:1 }); + assertValue(textInputField, '1'); + }); + test('Number (Falsy)', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:0 }); + assertValue(textInputField, '0'); + }); + test('Boolean True', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:true }); + assertValue(textInputField, 'true'); + }); + test('Boolean False', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:false }); + assertValue(textInputField, 'false'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.textInputField = new Blockly.FieldTextInput(); + }); + test('Null', function() { + this.textInputField.setValue(null); + assertValueDefault(this.textInputField); + }); + test.skip('Undefined', function() { + this.textInputField.setValue(undefined); + assertValueDefault(this.textInputField); + }); + test('New String', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.textInputField.setValue(1); + assertValue(this.textInputField, '1'); + }); + test.skip('Number (Falsy)', function() { + this.textInputField.setValue(0); + assertValue(this.textInputField, '0'); + }); + test('Boolean True', function() { + this.textInputField.setValue(true); + assertValue(this.textInputField, 'true'); + }); + test.skip('Boolean False', function() { + this.textInputField.setValue(false); + assertValue(this.textInputField, 'false'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.textInputField = new Blockly.FieldTextInput('value'); + }); + test('Null', function() { + this.textInputField.setValue(null); + assertValue(this.textInputField, 'value'); + }); + test.skip('Undefined', function() { + this.textInputField.setValue(undefined); + assertValue(this.textInputField, 'value'); + }); + test('New String', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.textInputField.setValue(1); + assertValue(this.textInputField, '1'); + }); + test('Number (Falsy)', function() { + this.textInputField.setValue(0); + assertValue(this.textInputField, '0'); + }); + test('Boolean True', function() { + this.textInputField.setValue(true); + assertValue(this.textInputField, 'true'); + }); + test('Boolean False', function() { + this.textInputField.setValue(false); + assertValue(this.textInputField, 'false'); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.textInputField = new Blockly.FieldTextInput('value'); + Blockly.FieldTextInput.htmlInput_ = Object.create(null); + Blockly.FieldTextInput.htmlInput_.oldValue_ = 'value'; + Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 'value'; + }); + suite('Null Validator', function() { + setup(function() { + this.textInputField.setValidator(function() { + return null; + }); + }); + test('When Editing', function() { + this.textInputField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = 'newValue'; + this.textInputField.onHtmlInputChange_(null); + assertValue(this.textInputField, 'value', 'newValue'); + this.textInputField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'value'); + }); + }); + suite('Remove \'a\' Validator', function() { + setup(function() { + this.textInputField.setValidator(function(newValue) { + return newValue.replace(/a/g, ''); + }); + }); + test('When Editing', function() { + this.textInputField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = 'bbbaaa'; + this.textInputField.onHtmlInputChange_(null); + assertValue(this.textInputField, 'bbb', 'bbbaaa'); + this.textInputField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.textInputField.setValue('bbbaaa'); + assertValue(this.textInputField, 'bbb'); + }); + }); + }); +}); diff --git a/tests/mocha/field_variable_test.js b/tests/mocha/field_variable_test.js index da8338c388e..8e7026eb6cc 100644 --- a/tests/mocha/field_variable_test.js +++ b/tests/mocha/field_variable_test.js @@ -1,5 +1,27 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ suite('Variable Fields', function() { + var FAKE_VARIABLE_NAME = 'yertle'; + var FAKE_ID = 'turtle'; + function getMockBlock(workspace) { return { 'workspace': workspace, @@ -8,54 +30,49 @@ suite('Variable Fields', function() { } }; } - function fieldVariable_createAndInitField(workspace) { - var fieldVariable = new Blockly.FieldVariable('name1'); + function initField(fieldVariable, workspace) { var mockBlock = getMockBlock(workspace); fieldVariable.setSourceBlock(mockBlock); // No view to initialize, but still need to init the model. fieldVariable.initModel(); return fieldVariable; } + function createAndInitFieldConstructor(workspace, variableName) { + return initField(new Blockly.FieldVariable(variableName), workspace); + } + function createAndInitFieldJson(workspace, variableName) { + return initField(Blockly.FieldVariable.fromJson( + { variable:variableName }), workspace); + } + function assertValue(variableField, expectedName, opt_expectedId) { + var actualName = variableField.getText(); + var actualId = variableField.getValue(); + opt_expectedId = opt_expectedId || FAKE_ID; + assertEquals(actualName, expectedName); + assertEquals(actualId, opt_expectedId); + } + function assertValueDefault(variableField) { + assertValue(variableField, FAKE_VARIABLE_NAME, FAKE_ID); + } setup(function() { this.workspace = new Blockly.Workspace(); + + sinon.stub(Blockly.utils, 'genUid') + .returns(FAKE_ID); + sinon.stub(Blockly.Variables, 'generateUniqueName') + .returns(FAKE_VARIABLE_NAME); }); teardown(function() { this.workspace.dispose(); - }); - - test('Constructor', function() { - var fieldVariable = new Blockly.FieldVariable('name1'); - // The field does not have a variable until after init() is called. - assertEquals('', fieldVariable.getText()); - assertNull(fieldVariable.getValue()); - }); - - test('Set value by ID', function() { - this.workspace.createVariable('name2', null, 'id2'); - - var fieldVariable = fieldVariable_createAndInitField(this.workspace); - var oldId = fieldVariable.getValue(); - - fieldVariable.setValue('id2'); - // Setting value by ID gives us the right text as well. - assertEquals('name2', fieldVariable.getText()); - assertEquals('id2', fieldVariable.getValue()); - chai.assert.notEqual(oldId, fieldVariable.getValue()); - }); - - test('Set value: variable does not exist', function() { - var fieldVariable = fieldVariable_createAndInitField(this.workspace); - chai.assert.throws(function() { - fieldVariable.setValue('id1'); - }); + sinon.restore(); }); test('Dropdown contains variables', function() { // Expect that the dropdown options will contain the variables that exist this.workspace.createVariable('name1', '', 'id1'); this.workspace.createVariable('name2', '', 'id2'); - var fieldVariable = fieldVariable_createAndInitField(this.workspace); + var fieldVariable = createAndInitFieldConstructor(this.workspace, 'name1'); // Expect that variables created after field creation will show up too. this.workspace.createVariable('name3', '', 'id3'); @@ -68,9 +85,112 @@ suite('Variable Fields', function() { isEqualArrays(result_options[0], ['name1', 'id1']); isEqualArrays(result_options[1], ['name2', 'id2']); isEqualArrays(result_options[2], ['name3', 'id3']); - }); + suite('Constructor', function() { + test('Null', function() { + var variableField = createAndInitFieldConstructor(this.workspace, null); + assertValueDefault(variableField); + }); + test('Undefined', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, undefined); + assertValueDefault(variableField); + }); + test('No Value Before InitModel', function() { + var fieldVariable = new Blockly.FieldVariable('name1'); + assertEquals('', fieldVariable.getText()); + assertNull(fieldVariable.getValue()); + }); + test('Given Variable Name', function() { + var fieldVariable = createAndInitFieldConstructor( + this.workspace, 'name1'); + assertValue(fieldVariable, 'name1'); + }); + }); + suite('fromJson', function() { + test('Null', function() { + var variableField = createAndInitFieldJson(this.workspace, null); + assertValueDefault(variableField); + }); + test('Undefined', function() { + var variableField = createAndInitFieldJson(this.workspace, undefined); + assertValueDefault(variableField); + }); + test('No Value Before InitModel', function() { + var variableField = new Blockly.FieldVariable('name1'); + assertEquals('', variableField.getText()); + assertNull(variableField.getValue()); + }); + test('Given Variable Name', function() { + var variableField = createAndInitFieldJson(this.workspace, 'name1'); + assertValue(variableField, 'name1'); + }); + }); + suite('setValue', function() { + test.skip('Null', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + variableField.setValue(null); + assertValue(variableField, 'name1'); + }); + test.skip('Undefined', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + variableField.setValue(undefined); + assertValue(variableField, 'name1'); + }); + test('New Variable ID', function() { + this.workspace.createVariable('name2', null, 'id2'); + + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + var oldId = variableField.getValue(); + variableField.setValue('id2'); + // Setting value by ID gives us the right text as well. + assertEquals('name2', variableField.getText()); + assertEquals('id2', variableField.getValue()); + chai.assert.notEqual(oldId, variableField.getValue()); + }); + test.skip('Variable Does not Exist', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + variableField.setValue('id1'); + assertValue(variableField, 'name1'); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.workspace.createVariable('name1', null, 'id1'); + this.workspace.createVariable('name2', null, 'id2'); + this.workspace.createVariable('name3', null, 'id3'); + this.variableField = createAndInitFieldConstructor(this.workspace, 'name1'); + }); + suite('Null Validator', function() { + setup(function() { + this.variableField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.variableField.setValue('id2'); + assertValue(this.variableField, 'name1', 'id1'); + }); + }); + suite('Force \'id\' ID Validator', function() { + setup(function() { + this.variableField.setValidator(function(newValue) { + return 'id' + newValue.charAt(newValue.length - 1); + }); + }); + test('New Value', function() { + // Must create the var so that the field doesn't throw an error. + this.workspace.createVariable('thing2', null, 'other2'); + this.variableField.setValue('other2'); + assertValue(this.variableField, 'name2', 'id2'); + }); + }); + }); suite('Get variable types', function() { setup(function() { this.workspace.createVariable('name1', 'type1'); @@ -121,7 +241,6 @@ suite('Variable Fields', function() { }); }); }); - suite('Default types', function() { test('Default type exists', function() { var fieldVariable = new Blockly.FieldVariable(null, null, ['b'], 'b'); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index f6564786548..48c0c2e5183 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -19,11 +19,23 @@ ui: 'tdd' }); + + + + + + + + + + + + diff --git a/tests/mocha/test_helpers.js b/tests/mocha/test_helpers.js index deea338e892..fc6b1e79551 100644 --- a/tests/mocha/test_helpers.js +++ b/tests/mocha/test_helpers.js @@ -104,5 +104,5 @@ function assertNotUndefined() { _validateArguments(1, arguments); var commentArg = _commentArg(1, arguments); var val = _nonCommentArg(1, 1, arguments); - chai.assert.isNotUndefined(val, commentArg); + chai.assert.isDefined(val, commentArg); } From 5cf52c566a4ce6fe31b66fc1bbb355bc1d92e99f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 17 May 2019 16:23:18 -0700 Subject: [PATCH 068/233] Fix a dozen compiler warnings. --- core/block_svg.js | 2 +- core/events.js | 3 ++- core/flyout_base.js | 4 ++-- core/generator.js | 2 +- core/gesture.js | 2 +- core/workspace_svg.js | 26 ++++++++++++++++---------- core/xml.js | 8 ++++++-- core/xml_utils.js | 2 +- externs/browser-externs.js | 32 ++++++++++++++++++++++++++++++++ tests/compile/compile.sh | 1 + tests/compile/index.html | 2 +- 11 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 externs/browser-externs.js diff --git a/core/block_svg.js b/core/block_svg.js index 505da905a6e..47cee2673c4 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -629,7 +629,7 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { Blockly.BlockSvg.prototype.showHelp_ = function() { var url = (typeof this.helpUrl == 'function') ? this.helpUrl() : this.helpUrl; if (url) { - open(url); + window.open(url); } }; diff --git a/core/events.js b/core/events.js index 41f247f2f80..285c9d45c98 100644 --- a/core/events.js +++ b/core/events.js @@ -411,7 +411,8 @@ Blockly.Events.disableOrphans = function(event) { var workspace = Blockly.Workspace.getById(event.workspaceId); var block = workspace.getBlockById(event.blockId); if (block) { - if (block.getParent() && !block.getParent().disabled) { + var parent = block.getParent() + if (parent && parent.isEnabled()) { var children = block.getDescendants(false); for (var i = 0, child; child = children[i]; i++) { child.setEnabled(true); diff --git a/core/flyout_base.js b/core/flyout_base.js index b651f725528..c8fcc79d2a7 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -455,7 +455,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { switch (xml.tagName.toUpperCase()) { case 'BLOCK': var curBlock = Blockly.Xml.domToBlock(xml, this.workspace_); - if (curBlock.disabled) { + if (!curBlock.isEnabled()) { // Record blocks that were initially disabled. // Do not enable these blocks as a result of capacity filtering. this.permanentlyDisabled_.push(curBlock); @@ -612,7 +612,7 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) { * @package */ Blockly.Flyout.prototype.isBlockCreatable_ = function(block) { - return !block.disabled; + return block.isEnabled(); }; /** diff --git a/core/generator.js b/core/generator.js index fc59214c151..4241e2440b6 100644 --- a/core/generator.js +++ b/core/generator.js @@ -182,7 +182,7 @@ Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { if (!block) { return ''; } - if (block.disabled) { + if (!block.isEnabled()) { // Skip past this block if it is disabled. return opt_thisOnly ? '' : this.blockToCode(block.getNextBlock()); } diff --git a/core/gesture.js b/core/gesture.js index 9023b272f46..4e18a1204a3 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -734,7 +734,7 @@ Blockly.Gesture.prototype.doFieldClick_ = function() { Blockly.Gesture.prototype.doBlockClick_ = function() { // Block click in an autoclosing flyout. if (this.flyout_ && this.flyout_.autoClose) { - if (!this.targetBlock_.disabled) { + if (this.targetBlock_.isEnabled()) { if (!Blockly.Events.getGroup()) { Blockly.Events.setGroup(true); } diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 7f20dca13fd..f07cdc5f2fc 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -272,6 +272,21 @@ Blockly.WorkspaceSvg.prototype.trashcan = null; */ Blockly.WorkspaceSvg.prototype.scrollbar = null; +/** + * Fixed flyout providing blocks which may be dragged into this workspace. + * @type {Blockly.Flyout} + * @private + */ +Blockly.WorkspaceSvg.prototype.flyout_ = null; + +/** + * Category-based toolbox providing blocks which may be dragged into this + * workspace. + * @type {Blockly.Toolbox} + * @private + */ +Blockly.WorkspaceSvg.prototype.toolbox_ = null; + /** * The current gesture in progress on this workspace, if any. * @type {Blockly.TouchGesture} @@ -533,10 +548,6 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { // Determine if there needs to be a category tree, or a simple list of // blocks. This cannot be changed later, since the UI is very different. if (this.options.hasCategories) { - /** - * @type {Blockly.Toolbox} - * @private - */ this.toolbox_ = new Blockly.Toolbox(this); } if (this.grid_) { @@ -660,11 +671,6 @@ Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) { horizontalLayout: this.horizontalLayout, toolboxPosition: this.options.toolboxPosition }; - /** - * @type {!Blockly.Flyout} - * @private - */ - this.flyout_ = null; if (this.horizontalLayout) { this.flyout_ = new Blockly.HorizontalFlyout(workspaceOptions); } else { @@ -672,7 +678,7 @@ Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) { } this.flyout_.autoClose = false; - // Return the element so that callers can place it in their desired + // Return the element so that callers can place it in their desired // spot in the DOM. For example, mutator flyouts do not go in the same place // as main workspace flyouts. return this.flyout_.createDom(tagName); diff --git a/core/xml.js b/core/xml.js index 3c03c0c643a..eb736afaf70 100644 --- a/core/xml.js +++ b/core/xml.js @@ -206,7 +206,7 @@ Blockly.Xml.blockToDom = function(block, opt_noId) { if (block.isCollapsed()) { element.setAttribute('collapsed', true); } - if (block.disabled) { + if (!block.isEnabled()) { element.setAttribute('disabled', true); } if (!block.isDeletable() && !block.isShadow()) { @@ -350,11 +350,13 @@ Blockly.Xml.clearWorkspaceAndLoadFromXml = function(xml, workspace) { * Decode an XML DOM and create blocks on the workspace. * @param {!Element} xml XML DOM. * @param {!Blockly.Workspace} workspace The workspace. - * @return {Array.} An array containing new block IDs. + * @return {!Array.} An array containing new block IDs. */ Blockly.Xml.domToWorkspace = function(xml, workspace) { if (xml instanceof Blockly.Workspace) { var swap = xml; + // Closure Compiler complains here because the arguments are reversed. + /** @suppress {checkTypes} */ xml = workspace; workspace = swap; console.warn('Deprecated call to Blockly.Xml.domToWorkspace, ' + @@ -498,6 +500,8 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { Blockly.Xml.domToBlock = function(xmlBlock, workspace) { if (xmlBlock instanceof Blockly.Workspace) { var swap = xmlBlock; + // Closure Compiler complains here because the arguments are reversed. + /** @suppress {checkTypes} */ xmlBlock = workspace; workspace = swap; console.warn('Deprecated call to Blockly.Xml.domToBlock, ' + diff --git a/core/xml_utils.js b/core/xml_utils.js index 0e1a3d4a175..1395923dc15 100644 --- a/core/xml_utils.js +++ b/core/xml_utils.js @@ -58,7 +58,7 @@ Blockly.Xml.utils.createTextNode = function(text) { * Converts an XML string into a DOM tree. This method will be overridden in * the Node.js build of Blockly. See gulpfile.js, blockly_javascript_en task. * @param {string} text XML string. - * @return {!Element} The DOM document. + * @return {Document} The DOM document. * @throws if XML doesn't parse. * @package */ diff --git a/externs/browser-externs.js b/externs/browser-externs.js new file mode 100644 index 00000000000..38a84fdd9fb --- /dev/null +++ b/externs/browser-externs.js @@ -0,0 +1,32 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Property definitions in browsers that Closure Compiler is + * unaware of. + * @author fraser@google.com (Neil Fraser) + * + * @externs + */ +'use strict'; + + +Element.ELEMENT_NODE = 1; +Element.TEXT_NODE = 3; diff --git a/tests/compile/compile.sh b/tests/compile/compile.sh index f60c37cb179..6352746a3b4 100755 --- a/tests/compile/compile.sh +++ b/tests/compile/compile.sh @@ -82,6 +82,7 @@ COMPILATION_COMMAND="java -jar $COMPILER --js='$BLOCKLY_ROOT/tests/compile/main. --js='$CLOSURE_LIB_ROOT/closure/goog/**.js' \ --js='$CLOSURE_LIB_ROOT/third_party/closure/goog/**.js' \ --generate_exports \ + --externs $BLOCKLY_ROOT/externs/browser-externs.js \ --externs $BLOCKLY_ROOT/externs/svg-externs.js \ --compilation_level ADVANCED_OPTIMIZATIONS \ --dependency_mode=STRICT --entry_point=Main \ diff --git a/tests/compile/index.html b/tests/compile/index.html index 93444421d4a..95e2af9d3c1 100644 --- a/tests/compile/index.html +++ b/tests/compile/index.html @@ -20,7 +20,7 @@

Blockly: Advanced Compilation Test

To run this test manually, download closure-compiler-vxxxxxxxx.jar, - place it in this directory, then run compile.js from the command line.

+ place it in this directory, then run compile.sh from the command line.

Measure the size of main_compressed.js (295kb as of October 2017), then reload this page and see if Blockly works.

From 611b2b230003256ae148ed4a30116db51181dcdd Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 17 May 2019 16:26:34 -0700 Subject: [PATCH 069/233] Routine recompile --- blockly_accessible_compressed.js | 656 ++++++++++++++--------------- blockly_accessible_uncompressed.js | 58 +-- blockly_compressed.js | 547 ++++++++++++------------ blockly_uncompressed.js | 20 +- blocks_compressed.js | 18 +- dart_compressed.js | 26 +- javascript_compressed.js | 27 +- lua_compressed.js | 28 +- msg/js/az.js | 4 +- msg/js/br.js | 2 +- msg/js/de.js | 4 +- msg/js/ee.js | 436 +++++++++++++++++++ msg/js/eo.js | 380 ++++++++--------- msg/js/et.js | 46 +- msg/js/fi.js | 2 +- msg/js/ia.js | 6 +- msg/js/kab.js | 8 +- msg/js/nl.js | 2 +- msg/js/sd.js | 10 +- msg/js/te.js | 2 +- msg/js/th.js | 4 +- msg/js/zh-hans.js | 2 +- php_compressed.js | 25 +- python_compressed.js | 28 +- 24 files changed, 1396 insertions(+), 945 deletions(-) create mode 100644 msg/js/ee.js diff --git a/blockly_accessible_compressed.js b/blockly_accessible_compressed.js index 1b5fcc6ca1c..f336370527d 100644 --- a/blockly_accessible_compressed.js +++ b/blockly_accessible_compressed.js @@ -1,9 +1,9 @@ // Do not edit this file; automatically generated by build.py. 'use strict'; -var $jscomp=$jscomp||{};$jscomp.scope={};var COMPILED=!0,goog=goog||{};goog.global=this;goog.isDef=function(a){return void 0!==a};goog.isString=function(a){return"string"==typeof a};goog.isBoolean=function(a){return"boolean"==typeof a};goog.isNumber=function(a){return"number"==typeof a}; +var $jscomp=$jscomp||{};$jscomp.scope={};var COMPILED=!0,goog=goog||{};goog.global=this||self;goog.isDef=function(a){return void 0!==a};goog.isString=function(a){return"string"==typeof a};goog.isBoolean=function(a){return"boolean"==typeof a};goog.isNumber=function(a){return"number"==typeof a}; goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||"undefined"==typeof c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&goog.isDef(b)?c[d]=b:c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}}; -goog.define=function(a,b){if(!COMPILED){var c=goog.global.CLOSURE_UNCOMPILED_DEFINES,d=goog.global.CLOSURE_DEFINES;c&&void 0===c.nodeType&&Object.prototype.hasOwnProperty.call(c,a)?b=c[a]:d&&void 0===d.nodeType&&Object.prototype.hasOwnProperty.call(d,a)&&(b=d[a])}goog.exportPath_(a,b);return b};goog.DEBUG=!1;goog.LOCALE="en";goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG;goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1; +goog.define=function(a,b){if(!COMPILED){var c=goog.global.CLOSURE_UNCOMPILED_DEFINES,d=goog.global.CLOSURE_DEFINES;c&&void 0===c.nodeType&&Object.prototype.hasOwnProperty.call(c,a)?b=c[a]:d&&void 0===d.nodeType&&Object.prototype.hasOwnProperty.call(d,a)&&(b=d[a])}return b};goog.FEATURESET_YEAR=2012;goog.DEBUG=!1;goog.LOCALE="en";goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG;goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1; goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide cannot be used within a module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)};goog.constructNamespace_=function(a,b){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var c=a;(c=c.substring(0,c.lastIndexOf(".")))&&!goog.getObjectByName(c);)goog.implicitNamespaces_[c]=!0}goog.exportPath_(a,b)}; goog.getScriptNonce=function(a){if(a&&a!=goog.global)return goog.getScriptNonce_(a.document);null===goog.cspNonce_&&(goog.cspNonce_=goog.getScriptNonce_(goog.global.document));return goog.cspNonce_};goog.NONCE_PATTERN_=/^[\w+/_-]+[=]{0,2}$/;goog.cspNonce_=null;goog.getScriptNonce_=function(a){return(a=a.querySelector&&a.querySelector("script[nonce]"))&&(a=a.nonce||a.getAttribute("nonce"))&&goog.NONCE_PATTERN_.test(a)?a:""};goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/; goog.module=function(a){if(!goog.isString(a)||!a||-1==a.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInGoogModuleLoader_())throw Error("Module "+a+" has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide."); @@ -12,7 +12,7 @@ goog.module.getInternal_=function(a){if(!COMPILED){if(a in goog.loadedModules_)r goog.isInEs6ModuleLoader_=function(){if(goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.ES6)return!0;var a=goog.global.$jscomp;return a?"function"!=typeof a.getCurrentModulePath?!1:!!a.getCurrentModulePath():!1}; goog.module.declareLegacyNamespace=function(){if(!COMPILED&&!goog.isInGoogModuleLoader_())throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module");if(!COMPILED&&!goog.moduleLoaderState_.moduleName)throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace.");goog.moduleLoaderState_.declareLegacyNamespace=!0}; goog.declareModuleId=function(a){if(!COMPILED){if(!goog.isInEs6ModuleLoader_())throw Error("goog.declareModuleId may only be called from within an ES6 module");if(goog.moduleLoaderState_&&goog.moduleLoaderState_.moduleName)throw Error("goog.declareModuleId may only be called once per module.");if(a in goog.loadedModules_)throw Error('Module with namespace "'+a+'" already exists.');}if(goog.moduleLoaderState_)goog.moduleLoaderState_.moduleName=a;else{var b=goog.global.$jscomp;if(!b||"function"!=typeof b.getCurrentModulePath)throw Error('Module with namespace "'+ -a+'" has been loaded incorrectly.');b=b.require(b.getCurrentModulePath());goog.loadedModules_[a]={exports:b,type:goog.ModuleType.ES6,moduleId:a}}};goog.module.declareNamespace=goog.declareModuleId;goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){}; +a+'" has been loaded incorrectly.');b=b.require(b.getCurrentModulePath());goog.loadedModules_[a]={exports:b,type:goog.ModuleType.ES6,moduleId:a}}};goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){}; COMPILED||(goog.isProvided_=function(a){return a in goog.loadedModules_||!goog.implicitNamespaces_[a]&&goog.isDefAndNotNull(goog.getObjectByName(a))},goog.implicitNamespaces_={"goog.module":!0});goog.getObjectByName=function(a,b){a=a.split(".");b=b||goog.global;for(var c=0;cc?Math.max(0,a.length+c):c;if(goog.isString(a))return goog.isString(b)&&1==b.length?a.indexOf(b,c):-1;for(;c=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2]))]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)}; goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)};goog.color.highContrast=function(a,b){for(var c=[],d=0;d":"
")}; goog.string.internal.htmlEscape=function(a,b){if(b)a=a.replace(goog.string.internal.AMP_RE_,"&").replace(goog.string.internal.LT_RE_,"<").replace(goog.string.internal.GT_RE_,">").replace(goog.string.internal.QUOT_RE_,""").replace(goog.string.internal.SINGLE_QUOTE_RE_,"'").replace(goog.string.internal.NULL_RE_,"�");else{if(!goog.string.internal.ALL_RE_.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(goog.string.internal.AMP_RE_,"&"));-1!=a.indexOf("<")&&(a=a.replace(goog.string.internal.LT_RE_, @@ -160,115 +162,18 @@ goog.labs.userAgent.browser.isOpera=goog.labs.userAgent.browser.matchOpera_;goog goog.labs.userAgent.browser.isChrome=goog.labs.userAgent.browser.matchChrome_;goog.labs.userAgent.browser.isAndroidBrowser=goog.labs.userAgent.browser.matchAndroidBrowser_;goog.labs.userAgent.browser.isSilk=function(){return goog.labs.userAgent.util.matchUserAgent("Silk")}; goog.labs.userAgent.browser.getVersion=function(){function a(a){a=goog.array.find(a,d);return c[a]||""}var b=goog.labs.userAgent.util.getUserAgent();if(goog.labs.userAgent.browser.isIE())return goog.labs.userAgent.browser.getIEVersion_(b);b=goog.labs.userAgent.util.extractVersionTuples(b);var c={};goog.array.forEach(b,function(a){c[a[0]]=a[1]});var d=goog.partial(goog.object.containsKey,c);return goog.labs.userAgent.browser.isOpera()?a(["Version","Opera"]):goog.labs.userAgent.browser.isEdge()?a(["Edge"]): goog.labs.userAgent.browser.isChrome()?a(["Chrome","CriOS"]):(b=b[2])&&b[1]||""};goog.labs.userAgent.browser.isVersionOrHigher=function(a){return 0<=goog.string.internal.compareVersions(goog.labs.userAgent.browser.getVersion(),a)}; -goog.labs.userAgent.browser.getIEVersion_=function(a){var b=/rv: *([\d\.]*)/.exec(a);if(b&&b[1])return b[1];b="";var c=/MSIE +([\d\.]+)/.exec(a);if(c&&c[1])if(a=/Trident\/(\d.\d)/.exec(a),"7.0"==c[1])if(a&&a[1])switch(a[1]){case "4.0":b="8.0";break;case "5.0":b="9.0";break;case "6.0":b="10.0";break;case "7.0":b="11.0"}else b="7.0";else b=c[1];return b};goog.string.DETECT_DOUBLE_ESCAPING=!1;goog.string.FORCE_NON_DOM_HTML_UNESCAPING=!1;goog.string.Unicode={NBSP:"\u00a0"};goog.string.startsWith=goog.string.internal.startsWith;goog.string.endsWith=goog.string.internal.endsWith;goog.string.caseInsensitiveStartsWith=goog.string.internal.caseInsensitiveStartsWith;goog.string.caseInsensitiveEndsWith=goog.string.internal.caseInsensitiveEndsWith;goog.string.caseInsensitiveEquals=goog.string.internal.caseInsensitiveEquals; -goog.string.subs=function(a,b){for(var c=a.split("%s"),d="",e=Array.prototype.slice.call(arguments,1);e.length&&1=a||"\u0080"<=a&&"\ufffd">=a}; -goog.string.stripNewlines=function(a){return a.replace(/(\r\n|\r|\n)+/g," ")};goog.string.canonicalizeNewlines=function(a){return a.replace(/(\r\n|\r|\n)/g,"\n")};goog.string.normalizeWhitespace=function(a){return a.replace(/\xa0|\s/g," ")};goog.string.normalizeSpaces=function(a){return a.replace(/\xa0|[ \t]+/g," ")};goog.string.collapseBreakingSpaces=function(a){return a.replace(/[\t\r\n ]+/g," ").replace(/^[\t\r\n ]+|[\t\r\n ]+$/g,"")};goog.string.trim=goog.string.internal.trim; -goog.string.trimLeft=function(a){return a.replace(/^[\s\xa0]+/,"")};goog.string.trimRight=function(a){return a.replace(/[\s\xa0]+$/,"")};goog.string.caseInsensitiveCompare=goog.string.internal.caseInsensitiveCompare; -goog.string.numberAwareCompare_=function(a,b,c){if(a==b)return 0;if(!a)return-1;if(!b)return 1;for(var d=a.toLowerCase().match(c),e=b.toLowerCase().match(c),f=Math.min(d.length,e.length),g=0;g",""":'"'};var d=b?b.createElement("div"):goog.global.document.createElement("div");return a.replace(goog.string.HTML_ENTITY_PATTERN_,function(a,b){var e=c[a];if(e)return e;"#"==b.charAt(0)&&(b=Number("0"+b.substr(1)),isNaN(b)||(e=String.fromCharCode(b)));e||(d.innerHTML=a+" ",e=d.firstChild.nodeValue.slice(0,-1));return c[a]=e})}; -goog.string.unescapePureXmlEntities_=function(a){return a.replace(/&([^;]+);/g,function(a,c){switch(c){case "amp":return"&";case "lt":return"<";case "gt":return">";case "quot":return'"';default:return"#"!=c.charAt(0)||(c=Number("0"+c.substr(1)),isNaN(c))?a:String.fromCharCode(c)}})};goog.string.HTML_ENTITY_PATTERN_=/&([^;\s<&]+);?/g;goog.string.whitespaceEscape=function(a,b){return goog.string.newLineToBr(a.replace(/ /g,"  "),b)}; -goog.string.preserveSpaces=function(a){return a.replace(/(^|[\n ]) /g,"$1"+goog.string.Unicode.NBSP)};goog.string.stripQuotes=function(a,b){for(var c=b.length,d=0;db&&(a=a.substring(0,b-3)+"...");c&&(a=goog.string.htmlEscape(a));return a}; -goog.string.truncateMiddle=function(a,b,c,d){c&&(a=goog.string.unescapeEntities(a));if(d&&a.length>b){d>b&&(d=b);var e=a.length-d;a=a.substring(0,b-d)+"..."+a.substring(e)}else a.length>b&&(d=Math.floor(b/2),e=a.length-d,a=a.substring(0,d+b%2)+"..."+a.substring(e));c&&(a=goog.string.htmlEscape(a));return a};goog.string.specialEscapeChars_={"\x00":"\\0","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\x0B",'"':'\\"',"\\":"\\\\","<":"<"};goog.string.jsEscapeCache_={"'":"\\'"}; -goog.string.quote=function(a){a=String(a);for(var b=['"'],c=0;ce?d:goog.string.escapeChar(d))}b.push('"');return b.join("")};goog.string.escapeString=function(a){for(var b=[],c=0;cb)var c=a;else{if(256>b){if(c="\\x",16>b||256b&&(c+="0");c+=b.toString(16).toUpperCase()}return goog.string.jsEscapeCache_[a]=c};goog.string.contains=goog.string.internal.contains;goog.string.caseInsensitiveContains=goog.string.internal.caseInsensitiveContains; -goog.string.countOf=function(a,b){return a&&b?a.split(b).length-1:0};goog.string.removeAt=function(a,b,c){var d=a;0<=b&&b>>0;return b};goog.string.uniqueStringCounter_=2147483648*Math.random()|0; -goog.string.createUniqueString=function(){return"goog_"+goog.string.uniqueStringCounter_++};goog.string.toNumber=function(a){var b=Number(a);return 0==b&&goog.string.isEmptyOrWhitespace(a)?NaN:b};goog.string.isLowerCamelCase=function(a){return/^[a-z]+([A-Z][a-z]*)*$/.test(a)};goog.string.isUpperCamelCase=function(a){return/^([A-Z][a-z]*)+$/.test(a)};goog.string.toCamelCase=function(a){return String(a).replace(/\-([a-z])/g,function(a,c){return c.toUpperCase()})}; -goog.string.toSelectorCase=function(a){return String(a).replace(/([A-Z])/g,"-$1").toLowerCase()};goog.string.toTitleCase=function(a,b){b=goog.isString(b)?goog.string.regExpEscape(b):"\\s";return a.replace(new RegExp("(^"+(b?"|["+b+"]+":"")+")([a-z])","g"),function(a,b,e){return b+e.toUpperCase()})};goog.string.capitalize=function(a){return String(a.charAt(0)).toUpperCase()+String(a.substr(1)).toLowerCase()}; -goog.string.parseInt=function(a){isFinite(a)&&(a=String(a));return goog.isString(a)?/^\s*-?0x/i.test(a)?parseInt(a,16):parseInt(a,10):NaN};goog.string.splitLimit=function(a,b,c){a=a.split(b);for(var d=[];0c&&(c=e)}return-1==c?a:a.slice(c+1)}; -goog.string.editDistance=function(a,b){var c=[],d=[];if(a==b)return 0;if(!a.length||!b.length)return Math.max(a.length,b.length);for(var e=0;eparseFloat(a))?String(b):a}; -goog.userAgent.getVersionRegexResult_=function(){var a=goog.userAgent.getUserAgentString();if(goog.userAgent.GECKO)return/rv:([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.EDGE)return/Edge\/([\d\.]+)/.exec(a);if(goog.userAgent.IE)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.WEBKIT)return/WebKit\/(\S+)/.exec(a);if(goog.userAgent.OPERA)return/(?:Version)[ \/]?(\S+)/.exec(a)};goog.userAgent.getDocumentMode_=function(){var a=goog.global.document;return a?a.documentMode:void 0}; -goog.userAgent.VERSION=goog.userAgent.determineVersion_();goog.userAgent.compare=function(a,b){return goog.string.compareVersions(a,b)};goog.userAgent.isVersionOrHigherCache_={};goog.userAgent.isVersionOrHigher=function(a){return goog.userAgent.ASSUME_ANY_VERSION||goog.reflect.cache(goog.userAgent.isVersionOrHigherCache_,a,function(){return 0<=goog.string.compareVersions(goog.userAgent.VERSION,a)})};goog.userAgent.isVersion=goog.userAgent.isVersionOrHigher; -goog.userAgent.isDocumentModeOrHigher=function(a){return Number(goog.userAgent.DOCUMENT_MODE)>=a};goog.userAgent.isDocumentMode=goog.userAgent.isDocumentModeOrHigher;goog.userAgent.DOCUMENT_MODE=function(){var a=goog.global.document,b=goog.userAgent.getDocumentMode_();if(a&&goog.userAgent.IE)return b||("CSS1Compat"==a.compatMode?parseInt(goog.userAgent.VERSION,10):5)}();goog.debug.entryPointRegistry={};goog.debug.EntryPointMonitor=function(){};goog.debug.entryPointRegistry.refList_=[];goog.debug.entryPointRegistry.monitors_=[];goog.debug.entryPointRegistry.monitorsMayExist_=!1;goog.debug.entryPointRegistry.register=function(a){goog.debug.entryPointRegistry.refList_[goog.debug.entryPointRegistry.refList_.length]=a;if(goog.debug.entryPointRegistry.monitorsMayExist_)for(var b=goog.debug.entryPointRegistry.monitors_,c=0;c=goog.debug.MAX_STACK_DEPTH){b.push("[...long stack...]");break}}a&&d>=a?b.push("[...reached max depth limit...]"):b.push("[end]");return b.join("")}; -goog.debug.MAX_STACK_DEPTH=50;goog.debug.getNativeStackTrace_=function(a){var b=Error();if(Error.captureStackTrace)return Error.captureStackTrace(b,a),String(b.stack);try{throw b;}catch(c){b=c}return(a=b.stack)?String(a):null};goog.debug.getStacktrace=function(a){var b;goog.debug.FORCE_SLOPPY_STACKS||(b=goog.debug.getNativeStackTrace_(a||goog.debug.getStacktrace));b||(b=goog.debug.getStacktraceHelper_(a||arguments.callee.caller,[]));return b}; -goog.debug.getStacktraceHelper_=function(a,b){var c=[];if(goog.array.contains(b,a))c.push("[...circular reference...]");else if(a&&b.length=a.keyCode)a.keyCode=-1}catch(b){}};goog.events.BrowserEvent.prototype.getBrowserEvent=function(){return this.event_}; -goog.events.BrowserEvent.getPointerType_=function(a){return goog.isString(a.pointerType)?a.pointerType:goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[a.pointerType]||""};goog.events.Listenable=function(){};goog.events.Listenable.IMPLEMENTED_BY_PROP="closure_listenable_"+(1E6*Math.random()|0);goog.events.Listenable.addImplementation=function(a){a.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP]=!0};goog.events.Listenable.isImplementedBy=function(a){return!(!a||!a[goog.events.Listenable.IMPLEMENTED_BY_PROP])};goog.events.ListenableKey=function(){};goog.events.ListenableKey.counter_=0;goog.events.ListenableKey.reserveKey=function(){return++goog.events.ListenableKey.counter_};goog.events.Listener=function(a,b,c,d,e,f){goog.events.Listener.ENABLE_MONITORING&&(this.creationStack=Error().stack);this.listener=a;this.proxy=b;this.src=c;this.type=d;this.capture=!!e;this.handler=f;this.key=goog.events.ListenableKey.reserveKey();this.removed=this.callOnce=!1};goog.events.Listener.ENABLE_MONITORING=!1;goog.events.Listener.prototype.markAsRemoved=function(){this.removed=!0;this.handler=this.src=this.proxy=this.listener=null};goog.events.ListenerMap=function(a){this.src=a;this.listeners={};this.typeCount_=0};goog.events.ListenerMap.prototype.getTypeCount=function(){return this.typeCount_};goog.events.ListenerMap.prototype.getListenerCount=function(){var a=0,b;for(b in this.listeners)a+=this.listeners[b].length;return a}; -goog.events.ListenerMap.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.listeners[f];a||(a=this.listeners[f]=[],this.typeCount_++);var g=goog.events.ListenerMap.findListenerIndex_(a,b,d,e);-1a.keyCode||void 0!=a.returnValue}; -goog.events.uniqueIdCounter_=0;goog.events.getUniqueId=function(a){return a+"_"+goog.events.uniqueIdCounter_++};goog.events.getListenerMap_=function(a){a=a[goog.events.LISTENER_MAP_PROP_];return a instanceof goog.events.ListenerMap?a:null};goog.events.LISTENER_WRAPPER_PROP_="__closure_events_fn_"+(1E9*Math.random()>>>0); -goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.dom.HtmlElement=function(){};goog.dom.TagName=function(a){this.tagName_=a};goog.dom.TagName.prototype.toString=function(){return this.tagName_};goog.dom.TagName.A=new goog.dom.TagName("A");goog.dom.TagName.ABBR=new goog.dom.TagName("ABBR");goog.dom.TagName.ACRONYM=new goog.dom.TagName("ACRONYM");goog.dom.TagName.ADDRESS=new goog.dom.TagName("ADDRESS");goog.dom.TagName.APPLET=new goog.dom.TagName("APPLET");goog.dom.TagName.AREA=new goog.dom.TagName("AREA");goog.dom.TagName.ARTICLE=new goog.dom.TagName("ARTICLE"); +goog.labs.userAgent.browser.getIEVersion_=function(a){var b=/rv: *([\d\.]*)/.exec(a);if(b&&b[1])return b[1];b="";var c=/MSIE +([\d\.]+)/.exec(a);if(c&&c[1])if(a=/Trident\/(\d.\d)/.exec(a),"7.0"==c[1])if(a&&a[1])switch(a[1]){case "4.0":b="8.0";break;case "5.0":b="9.0";break;case "6.0":b="10.0";break;case "7.0":b="11.0"}else b="7.0";else b=c[1];return b};goog.dom.asserts={};goog.dom.asserts.assertIsLocation=function(a){if(goog.asserts.ENABLE_ASSERTS){var b=goog.dom.asserts.getWindow_(a);b&&(!a||!(a instanceof b.Location)&&a instanceof b.Element)&&goog.asserts.fail("Argument is not a Location (or a non-Element mock); got: %s",goog.dom.asserts.debugStringForType_(a))}return a}; +goog.dom.asserts.assertIsElementType_=function(a,b){if(goog.asserts.ENABLE_ASSERTS){var c=goog.dom.asserts.getWindow_(a);c&&"undefined"!=typeof c[b]&&(a&&(a instanceof c[b]||!(a instanceof c.Location||a instanceof c.Element))||goog.asserts.fail("Argument is not a %s (or a non-Element, non-Location mock); got: %s",b,goog.dom.asserts.debugStringForType_(a)))}return a};goog.dom.asserts.assertIsHTMLAnchorElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLAnchorElement")}; +goog.dom.asserts.assertIsHTMLButtonElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLButtonElement")};goog.dom.asserts.assertIsHTMLLinkElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLLinkElement")};goog.dom.asserts.assertIsHTMLImageElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLImageElement")};goog.dom.asserts.assertIsHTMLAudioElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLAudioElement")}; +goog.dom.asserts.assertIsHTMLVideoElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLVideoElement")};goog.dom.asserts.assertIsHTMLInputElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLInputElement")};goog.dom.asserts.assertIsHTMLTextAreaElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLTextAreaElement")};goog.dom.asserts.assertIsHTMLCanvasElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLCanvasElement")}; +goog.dom.asserts.assertIsHTMLEmbedElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLEmbedElement")};goog.dom.asserts.assertIsHTMLFormElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLFormElement")};goog.dom.asserts.assertIsHTMLFrameElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLFrameElement")};goog.dom.asserts.assertIsHTMLIFrameElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLIFrameElement")}; +goog.dom.asserts.assertIsHTMLObjectElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLObjectElement")};goog.dom.asserts.assertIsHTMLScriptElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLScriptElement")}; +goog.dom.asserts.debugStringForType_=function(a){if(goog.isObject(a))try{return a.constructor.displayName||a.constructor.name||Object.prototype.toString.call(a)}catch(b){return""}else return void 0===a?"undefined":null===a?"null":typeof a};goog.dom.asserts.getWindow_=function(a){try{var b=a&&a.ownerDocument,c=b&&(b.defaultView||b.parentWindow);c=c||goog.global;if(c.Element&&c.Location)return c}catch(d){}return null};goog.functions={};goog.functions.constant=function(a){return function(){return a}};goog.functions.FALSE=function(){return!1};goog.functions.TRUE=function(){return!0};goog.functions.NULL=function(){return null};goog.functions.identity=function(a,b){return a};goog.functions.error=function(a){return function(){throw Error(a);}};goog.functions.fail=function(a){return function(){throw a;}}; +goog.functions.lock=function(a,b){b=b||0;return function(){return a.apply(this,Array.prototype.slice.call(arguments,0,b))}};goog.functions.nth=function(a){return function(){return arguments[a]}};goog.functions.partialRight=function(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var b=Array.prototype.slice.call(arguments);b.push.apply(b,c);return a.apply(this,b)}};goog.functions.withReturnValue=function(a,b){return goog.functions.sequence(a,goog.functions.constant(b))}; +goog.functions.equalTo=function(a,b){return function(c){return b?a==c:a===c}};goog.functions.compose=function(a,b){var c=arguments,d=c.length;return function(){var a;d&&(a=c[d-1].apply(this,arguments));for(var b=d-2;0<=b;b--)a=c[b].call(this,a);return a}};goog.functions.sequence=function(a){var b=arguments,c=b.length;return function(){for(var a,e=0;ea.length?"&":"")+encodeURIComponent(d)+"="+encodeURIComponent(String(g)))}}return b};goog.html.SafeUrl=function(){this.privateDoNotAccessOrElseSafeUrlWrappedValue_="";this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeUrl.INNOCUOUS_STRING="about:invalid#zClosurez";goog.html.SafeUrl.prototype.implementsGoogStringTypedString=!0;goog.html.SafeUrl.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeUrlWrappedValue_.toString()}; goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString=!0;goog.html.SafeUrl.prototype.getDirection=function(){return goog.i18n.bidi.Dir.LTR};goog.DEBUG&&(goog.html.SafeUrl.prototype.toString=function(){return"SafeUrl{"+this.privateDoNotAccessOrElseSafeUrlWrappedValue_+"}"});goog.html.SafeUrl.unwrap=function(a){return goog.html.SafeUrl.unwrapTrustedURL(a).toString()}; goog.html.SafeUrl.unwrapTrustedURL=function(a){if(a instanceof goog.html.SafeUrl&&a.constructor===goog.html.SafeUrl&&a.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseSafeUrlWrappedValue_;goog.asserts.fail("expected object of type SafeUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:SafeUrl"};goog.html.SafeUrl.fromConstant=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))}; -goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))$/i;goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.DATA_URL_PATTERN_=/^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; -goog.html.SafeUrl.fromDataUrl=function(a){a=a.replace(/(%0A|%0D)/g,"");var b=a.match(goog.html.DATA_URL_PATTERN_);b=b&&goog.html.SAFE_MIME_TYPE_PATTERN_.test(b[1]);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b?a:goog.html.SafeUrl.INNOCUOUS_STRING)};goog.html.SafeUrl.fromTelUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"tel:")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; +goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))(?:;\w+=(?:\w+|"[\w;=]+"))*$/i;goog.html.SafeUrl.isSafeMimeType=function(a){return goog.html.SAFE_MIME_TYPE_PATTERN_.test(a)};goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; +goog.html.DATA_URL_PATTERN_=/^data:([^,]*);base64,[a-z0-9+\/]+=*$/i;goog.html.SafeUrl.fromDataUrl=function(a){a=a.replace(/(%0A|%0D)/g,"");var b=a.match(goog.html.DATA_URL_PATTERN_);b=b&&goog.html.SAFE_MIME_TYPE_PATTERN_.test(b[1]);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b?a:goog.html.SafeUrl.INNOCUOUS_STRING)};goog.html.SafeUrl.fromTelUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"tel:")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SIP_URL_PATTERN_=/^sip[s]?:[+a-z0-9_.!$%&'*\/=^`{|}~-]+@([a-z0-9-]+\.)+[a-z0-9]{2,63}$/i;goog.html.SafeUrl.fromSipUrl=function(a){goog.html.SIP_URL_PATTERN_.test(decodeURIComponent(a))||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.fromFacebookMessengerUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"fb-messenger://share")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SafeUrl.fromSmsUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"sms:")&&goog.html.SafeUrl.isSmsUrlBodyValid_(a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.isSmsUrlBodyValid_=function(a){var b=a.indexOf("#");0=a||"\u0080"<=a&&"\ufffd">=a}; +goog.string.stripNewlines=function(a){return a.replace(/(\r\n|\r|\n)+/g," ")};goog.string.canonicalizeNewlines=function(a){return a.replace(/(\r\n|\r|\n)/g,"\n")};goog.string.normalizeWhitespace=function(a){return a.replace(/\xa0|\s/g," ")};goog.string.normalizeSpaces=function(a){return a.replace(/\xa0|[ \t]+/g," ")};goog.string.collapseBreakingSpaces=function(a){return a.replace(/[\t\r\n ]+/g," ").replace(/^[\t\r\n ]+|[\t\r\n ]+$/g,"")};goog.string.trim=goog.string.internal.trim; +goog.string.trimLeft=function(a){return a.replace(/^[\s\xa0]+/,"")};goog.string.trimRight=function(a){return a.replace(/[\s\xa0]+$/,"")};goog.string.caseInsensitiveCompare=goog.string.internal.caseInsensitiveCompare; +goog.string.numberAwareCompare_=function(a,b,c){if(a==b)return 0;if(!a)return-1;if(!b)return 1;for(var d=a.toLowerCase().match(c),e=b.toLowerCase().match(c),f=Math.min(d.length,e.length),g=0;g",""":'"'};var d=b?b.createElement("div"):goog.global.document.createElement("div");return a.replace(goog.string.HTML_ENTITY_PATTERN_,function(a,b){var e=c[a];if(e)return e;"#"==b.charAt(0)&&(b=Number("0"+b.substr(1)),isNaN(b)||(e=String.fromCharCode(b)));e||(goog.dom.safe.setInnerHtml(d,goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract(goog.string.Const.from("Single HTML entity."), +a+" ")),e=d.firstChild.nodeValue.slice(0,-1));return c[a]=e})};goog.string.unescapePureXmlEntities_=function(a){return a.replace(/&([^;]+);/g,function(a,c){switch(c){case "amp":return"&";case "lt":return"<";case "gt":return">";case "quot":return'"';default:return"#"!=c.charAt(0)||(c=Number("0"+c.substr(1)),isNaN(c))?a:String.fromCharCode(c)}})};goog.string.HTML_ENTITY_PATTERN_=/&([^;\s<&]+);?/g;goog.string.whitespaceEscape=function(a,b){return goog.string.newLineToBr(a.replace(/ /g,"  "),b)}; +goog.string.preserveSpaces=function(a){return a.replace(/(^|[\n ]) /g,"$1"+goog.string.Unicode.NBSP)};goog.string.stripQuotes=function(a,b){for(var c=b.length,d=0;db&&(a=a.substring(0,b-3)+"...");c&&(a=goog.string.htmlEscape(a));return a}; +goog.string.truncateMiddle=function(a,b,c,d){c&&(a=goog.string.unescapeEntities(a));if(d&&a.length>b){d>b&&(d=b);var e=a.length-d;a=a.substring(0,b-d)+"..."+a.substring(e)}else a.length>b&&(d=Math.floor(b/2),e=a.length-d,a=a.substring(0,d+b%2)+"..."+a.substring(e));c&&(a=goog.string.htmlEscape(a));return a};goog.string.specialEscapeChars_={"\x00":"\\0","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\x0B",'"':'\\"',"\\":"\\\\","<":"<"};goog.string.jsEscapeCache_={"'":"\\'"}; +goog.string.quote=function(a){a=String(a);for(var b=['"'],c=0;ce?d:goog.string.escapeChar(d))}b.push('"');return b.join("")};goog.string.escapeString=function(a){for(var b=[],c=0;cb)var c=a;else{if(256>b){if(c="\\x",16>b||256b&&(c+="0");c+=b.toString(16).toUpperCase()}return goog.string.jsEscapeCache_[a]=c};goog.string.contains=goog.string.internal.contains;goog.string.caseInsensitiveContains=goog.string.internal.caseInsensitiveContains; +goog.string.countOf=function(a,b){return a&&b?a.split(b).length-1:0};goog.string.removeAt=function(a,b,c){var d=a;0<=b&&b>>0;return b};goog.string.uniqueStringCounter_=2147483648*Math.random()|0; +goog.string.createUniqueString=function(){return"goog_"+goog.string.uniqueStringCounter_++};goog.string.toNumber=function(a){var b=Number(a);return 0==b&&goog.string.isEmptyOrWhitespace(a)?NaN:b};goog.string.isLowerCamelCase=function(a){return/^[a-z]+([A-Z][a-z]*)*$/.test(a)};goog.string.isUpperCamelCase=function(a){return/^([A-Z][a-z]*)+$/.test(a)};goog.string.toCamelCase=function(a){return String(a).replace(/\-([a-z])/g,function(a,c){return c.toUpperCase()})}; +goog.string.toSelectorCase=function(a){return String(a).replace(/([A-Z])/g,"-$1").toLowerCase()};goog.string.toTitleCase=function(a,b){b=goog.isString(b)?goog.string.regExpEscape(b):"\\s";return a.replace(new RegExp("(^"+(b?"|["+b+"]+":"")+")([a-z])","g"),function(a,b,e){return b+e.toUpperCase()})};goog.string.capitalize=function(a){return String(a.charAt(0)).toUpperCase()+String(a.substr(1)).toLowerCase()}; +goog.string.parseInt=function(a){isFinite(a)&&(a=String(a));return goog.isString(a)?/^\s*-?0x/i.test(a)?parseInt(a,16):parseInt(a,10):NaN};goog.string.splitLimit=function(a,b,c){a=a.split(b);for(var d=[];0c&&(c=e)}return-1==c?a:a.slice(c+1)}; +goog.string.editDistance=function(a,b){var c=[],d=[];if(a==b)return 0;if(!a.length||!b.length)return Math.max(a.length,b.length);for(var e=0;eparseFloat(a))?String(b):a}; +goog.userAgent.getVersionRegexResult_=function(){var a=goog.userAgent.getUserAgentString();if(goog.userAgent.GECKO)return/rv:([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.EDGE)return/Edge\/([\d\.]+)/.exec(a);if(goog.userAgent.IE)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.WEBKIT)return/WebKit\/(\S+)/.exec(a);if(goog.userAgent.OPERA)return/(?:Version)[ \/]?(\S+)/.exec(a)};goog.userAgent.getDocumentMode_=function(){var a=goog.global.document;return a?a.documentMode:void 0}; +goog.userAgent.VERSION=goog.userAgent.determineVersion_();goog.userAgent.compare=function(a,b){return goog.string.compareVersions(a,b)};goog.userAgent.isVersionOrHigherCache_={};goog.userAgent.isVersionOrHigher=function(a){return goog.userAgent.ASSUME_ANY_VERSION||goog.reflect.cache(goog.userAgent.isVersionOrHigherCache_,a,function(){return 0<=goog.string.compareVersions(goog.userAgent.VERSION,a)})};goog.userAgent.isVersion=goog.userAgent.isVersionOrHigher; +goog.userAgent.isDocumentModeOrHigher=function(a){return Number(goog.userAgent.DOCUMENT_MODE)>=a};goog.userAgent.isDocumentMode=goog.userAgent.isDocumentModeOrHigher;goog.userAgent.DOCUMENT_MODE=function(){var a=goog.global.document,b=goog.userAgent.getDocumentMode_();if(a&&goog.userAgent.IE)return b||("CSS1Compat"==a.compatMode?parseInt(goog.userAgent.VERSION,10):5)}();goog.debug.LOGGING_ENABLED=goog.DEBUG;goog.debug.FORCE_SLOPPY_STACKS=!1;goog.debug.catchErrors=function(a,b,c){c=c||goog.global;var d=c.onerror,e=!!b;goog.userAgent.WEBKIT&&!goog.userAgent.isVersionOrHigher("535.3")&&(e=!e);c.onerror=function(b,c,h,k,l){d&&d(b,c,h,k,l);a({message:b,fileName:c,line:h,lineNumber:h,col:k,error:l});return e}}; +goog.debug.expose=function(a,b){if("undefined"==typeof a)return"undefined";if(null==a)return"NULL";var c=[],d;for(d in a)if(b||!goog.isFunction(a[d])){var e=d+" = ";try{e+=a[d]}catch(f){e+="*** "+f+" ***"}c.push(e)}return c.join("\n")}; +goog.debug.deepExpose=function(a,b){var c=[],d=[],e={},f=function(a,h){var g=h+" ";try{if(goog.isDef(a))if(goog.isNull(a))c.push("NULL");else if(goog.isString(a))c.push('"'+a.replace(/\n/g,"\n"+h)+'"');else if(goog.isFunction(a))c.push(String(a).replace(/\n/g,"\n"+h));else if(goog.isObject(a)){goog.hasUid(a)||d.push(a);var l=goog.getUid(a);if(e[l])c.push("*** reference loop detected (id="+l+") ***");else{e[l]=!0;c.push("{");for(var n in a)if(b||!goog.isFunction(a[n]))c.push("\n"),c.push(g),c.push(n+ +" = "),f(a[n],g);c.push("\n"+h+"}");delete e[l]}}else c.push(a);else c.push("undefined")}catch(m){c.push("*** "+m+" ***")}};f(a,"");for(a=0;a=goog.debug.MAX_STACK_DEPTH){b.push("[...long stack...]");break}}a&&d>=a?b.push("[...reached max depth limit...]"):b.push("[end]");return b.join("")}; +goog.debug.MAX_STACK_DEPTH=50;goog.debug.getNativeStackTrace_=function(a){var b=Error();if(Error.captureStackTrace)return Error.captureStackTrace(b,a),String(b.stack);try{throw b;}catch(c){b=c}return(a=b.stack)?String(a):null};goog.debug.getStacktrace=function(a){var b;goog.debug.FORCE_SLOPPY_STACKS||(b=goog.debug.getNativeStackTrace_(a||goog.debug.getStacktrace));b||(b=goog.debug.getStacktraceHelper_(a||arguments.callee.caller,[]));return b}; +goog.debug.getStacktraceHelper_=function(a,b){var c=[];if(goog.array.contains(b,a))c.push("[...circular reference...]");else if(a&&b.length=a.keyCode)a.keyCode=-1}catch(b){}};goog.events.BrowserEvent.prototype.getBrowserEvent=function(){return this.event_}; +goog.events.BrowserEvent.getPointerType_=function(a){return goog.isString(a.pointerType)?a.pointerType:goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[a.pointerType]||""};goog.events.Listenable=function(){};goog.events.Listenable.IMPLEMENTED_BY_PROP="closure_listenable_"+(1E6*Math.random()|0);goog.events.Listenable.addImplementation=function(a){a.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP]=!0};goog.events.Listenable.isImplementedBy=function(a){return!(!a||!a[goog.events.Listenable.IMPLEMENTED_BY_PROP])};goog.events.ListenableKey=function(){};goog.events.ListenableKey.counter_=0;goog.events.ListenableKey.reserveKey=function(){return++goog.events.ListenableKey.counter_};goog.events.Listener=function(a,b,c,d,e,f){goog.events.Listener.ENABLE_MONITORING&&(this.creationStack=Error().stack);this.listener=a;this.proxy=b;this.src=c;this.type=d;this.capture=!!e;this.handler=f;this.key=goog.events.ListenableKey.reserveKey();this.removed=this.callOnce=!1};goog.events.Listener.ENABLE_MONITORING=!1;goog.events.Listener.prototype.markAsRemoved=function(){this.removed=!0;this.handler=this.src=this.proxy=this.listener=null};goog.events.ListenerMap=function(a){this.src=a;this.listeners={};this.typeCount_=0};goog.events.ListenerMap.prototype.getTypeCount=function(){return this.typeCount_};goog.events.ListenerMap.prototype.getListenerCount=function(){var a=0,b;for(b in this.listeners)a+=this.listeners[b].length;return a}; +goog.events.ListenerMap.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.listeners[f];a||(a=this.listeners[f]=[],this.typeCount_++);var g=goog.events.ListenerMap.findListenerIndex_(a,b,d,e);-1a.keyCode||void 0!=a.returnValue}; +goog.events.uniqueIdCounter_=0;goog.events.getUniqueId=function(a){return a+"_"+goog.events.uniqueIdCounter_++};goog.events.getListenerMap_=function(a){a=a[goog.events.LISTENER_MAP_PROP_];return a instanceof goog.events.ListenerMap?a:null};goog.events.LISTENER_WRAPPER_PROP_="__closure_events_fn_"+(1E9*Math.random()>>>0); +goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.dom.BrowserFeature={CAN_ADD_NAME_OR_TYPE_ATTRIBUTES:!goog.userAgent.IE||goog.userAgent.isDocumentModeOrHigher(9),CAN_USE_CHILDREN_ATTRIBUTE:!goog.userAgent.GECKO&&!goog.userAgent.IE||goog.userAgent.IE&&goog.userAgent.isDocumentModeOrHigher(9)||goog.userAgent.GECKO&&goog.userAgent.isVersionOrHigher("1.9.1"),CAN_USE_INNER_TEXT:goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("9"),CAN_USE_PARENT_ELEMENT_PROPERTY:goog.userAgent.IE||goog.userAgent.OPERA||goog.userAgent.WEBKIT,INNER_HTML_NEEDS_SCOPED_ELEMENT:goog.userAgent.IE, +LEGACY_IE_RANGES:goog.userAgent.IE&&!goog.userAgent.isDocumentModeOrHigher(9)};goog.math.Size=function(a,b){this.width=a;this.height=b};goog.math.Size.equals=function(a,b){return a==b?!0:a&&b?a.width==b.width&&a.height==b.height:!1};goog.math.Size.prototype.clone=function(){return new goog.math.Size(this.width,this.height)};goog.DEBUG&&(goog.math.Size.prototype.toString=function(){return"("+this.width+" x "+this.height+")"});goog.math.Size.prototype.getLongest=function(){return Math.max(this.width,this.height)}; goog.math.Size.prototype.getShortest=function(){return Math.min(this.width,this.height)};goog.math.Size.prototype.area=function(){return this.width*this.height};goog.math.Size.prototype.perimeter=function(){return 2*(this.width+this.height)};goog.math.Size.prototype.aspectRatio=function(){return this.width/this.height};goog.math.Size.prototype.isEmpty=function(){return!this.area()};goog.math.Size.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this}; goog.math.Size.prototype.fitsInside=function(a){return this.width<=a.width&&this.height<=a.height};goog.math.Size.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};goog.math.Size.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};goog.math.Size.prototype.scale=function(a,b){b=goog.isNumber(b)?b:a;this.width*=a;this.height*=b;return this}; goog.math.Size.prototype.scaleToCover=function(a){a=this.aspectRatio()<=a.aspectRatio()?a.width/this.width:a.height/this.height;return this.scale(a)};goog.math.Size.prototype.scaleToFit=function(a){a=this.aspectRatio()>a.aspectRatio()?a.width/this.width:a.height/this.height;return this.scale(a)};goog.dom.ASSUME_QUIRKS_MODE=!1;goog.dom.ASSUME_STANDARDS_MODE=!1;goog.dom.COMPAT_MODE_KNOWN_=goog.dom.ASSUME_QUIRKS_MODE||goog.dom.ASSUME_STANDARDS_MODE;goog.dom.getDomHelper=function(a){return a?new goog.dom.DomHelper(goog.dom.getOwnerDocument(a)):goog.dom.defaultDomHelper_||(goog.dom.defaultDomHelper_=new goog.dom.DomHelper)};goog.dom.getDocument=function(){return document};goog.dom.getElement=function(a){return goog.dom.getElementHelper_(document,a)}; @@ -589,13 +589,13 @@ goog.a11y.aria.getStateString=function(a,b){a=a.getAttribute(goog.a11y.aria.getA goog.a11y.aria.isContainerRole=function(a){a=goog.a11y.aria.getRole(a);return goog.array.contains(goog.a11y.aria.CONTAINER_ROLES_,a)};goog.a11y.aria.splitStringOnWhitespace_=function(a){return a?a.split(/\s+/):[]};goog.a11y.aria.getAriaAttributeName_=function(a){goog.asserts.ENABLE_ASSERTS&&(goog.asserts.assert(a,"ARIA attribute cannot be empty."),goog.asserts.assert(goog.object.containsValue(goog.a11y.aria.State,a),"No such ARIA attribute "+a));return goog.a11y.aria.ARIA_PREFIX_+a};goog.events.KeyCodes={WIN_KEY_FF_LINUX:0,MAC_ENTER:3,BACKSPACE:8,TAB:9,NUM_CENTER:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,PLUS_SIGN:43,PRINT_SCREEN:44,INSERT:45,DELETE:46,ZERO:48,ONE:49,TWO:50,THREE:51,FOUR:52,FIVE:53,SIX:54,SEVEN:55,EIGHT:56,NINE:57,FF_SEMICOLON:59,FF_EQUALS:61,FF_DASH:173,FF_HASH:163,QUESTION_MARK:63,AT_SIGN:64,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77, N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,META:91,WIN_KEY_RIGHT:92,CONTEXT_MENU:93,NUM_ZERO:96,NUM_ONE:97,NUM_TWO:98,NUM_THREE:99,NUM_FOUR:100,NUM_FIVE:101,NUM_SIX:102,NUM_SEVEN:103,NUM_EIGHT:104,NUM_NINE:105,NUM_MULTIPLY:106,NUM_PLUS:107,NUM_MINUS:109,NUM_PERIOD:110,NUM_DIVISION:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,NUMLOCK:144,SCROLL_LOCK:145,FIRST_MEDIA_KEY:166,LAST_MEDIA_KEY:183,SEMICOLON:186,DASH:189,EQUALS:187,COMMA:188, PERIOD:190,SLASH:191,APOSTROPHE:192,TILDE:192,SINGLE_QUOTE:222,OPEN_SQUARE_BRACKET:219,BACKSLASH:220,CLOSE_SQUARE_BRACKET:221,WIN_KEY:224,MAC_FF_META:224,MAC_WK_CMD_LEFT:91,MAC_WK_CMD_RIGHT:93,WIN_IME:229,VK_NONAME:252,PHANTOM:255}; -goog.events.KeyCodes.isTextModifyingKeyEvent=function(a){if(a.altKey&&!a.ctrlKey||a.metaKey||a.keyCode>=goog.events.KeyCodes.F1&&a.keyCode<=goog.events.KeyCodes.F12)return!1;switch(a.keyCode){case goog.events.KeyCodes.ALT:case goog.events.KeyCodes.CAPS_LOCK:case goog.events.KeyCodes.CONTEXT_MENU:case goog.events.KeyCodes.CTRL:case goog.events.KeyCodes.DOWN:case goog.events.KeyCodes.END:case goog.events.KeyCodes.ESC:case goog.events.KeyCodes.HOME:case goog.events.KeyCodes.INSERT:case goog.events.KeyCodes.LEFT:case goog.events.KeyCodes.MAC_FF_META:case goog.events.KeyCodes.META:case goog.events.KeyCodes.NUMLOCK:case goog.events.KeyCodes.NUM_CENTER:case goog.events.KeyCodes.PAGE_DOWN:case goog.events.KeyCodes.PAGE_UP:case goog.events.KeyCodes.PAUSE:case goog.events.KeyCodes.PHANTOM:case goog.events.KeyCodes.PRINT_SCREEN:case goog.events.KeyCodes.RIGHT:case goog.events.KeyCodes.SCROLL_LOCK:case goog.events.KeyCodes.SHIFT:case goog.events.KeyCodes.UP:case goog.events.KeyCodes.VK_NONAME:case goog.events.KeyCodes.WIN_KEY:case goog.events.KeyCodes.WIN_KEY_RIGHT:return!1;case goog.events.KeyCodes.WIN_KEY_FF_LINUX:return!goog.userAgent.GECKO; +goog.events.KeyCodes.isTextModifyingKeyEvent=function(a){if(a.altKey&&!a.ctrlKey||a.metaKey||a.keyCode>=goog.events.KeyCodes.F1&&a.keyCode<=goog.events.KeyCodes.F12)return!1;if(goog.events.KeyCodes.isCharacterKey(a.keyCode))return!0;switch(a.keyCode){case goog.events.KeyCodes.ALT:case goog.events.KeyCodes.CAPS_LOCK:case goog.events.KeyCodes.CONTEXT_MENU:case goog.events.KeyCodes.CTRL:case goog.events.KeyCodes.DOWN:case goog.events.KeyCodes.END:case goog.events.KeyCodes.ESC:case goog.events.KeyCodes.HOME:case goog.events.KeyCodes.INSERT:case goog.events.KeyCodes.LEFT:case goog.events.KeyCodes.MAC_FF_META:case goog.events.KeyCodes.META:case goog.events.KeyCodes.NUMLOCK:case goog.events.KeyCodes.NUM_CENTER:case goog.events.KeyCodes.PAGE_DOWN:case goog.events.KeyCodes.PAGE_UP:case goog.events.KeyCodes.PAUSE:case goog.events.KeyCodes.PHANTOM:case goog.events.KeyCodes.PRINT_SCREEN:case goog.events.KeyCodes.RIGHT:case goog.events.KeyCodes.SCROLL_LOCK:case goog.events.KeyCodes.SHIFT:case goog.events.KeyCodes.UP:case goog.events.KeyCodes.VK_NONAME:case goog.events.KeyCodes.WIN_KEY:case goog.events.KeyCodes.WIN_KEY_RIGHT:return!1;case goog.events.KeyCodes.WIN_KEY_FF_LINUX:return!goog.userAgent.GECKO; default:return a.keyCodegoog.events.KeyCodes.LAST_MEDIA_KEY}}; goog.events.KeyCodes.firesKeyPressEvent=function(a,b,c,d,e,f){if(goog.userAgent.WEBKIT&&!goog.userAgent.isVersionOrHigher("525"))return!0;if(goog.userAgent.MAC&&e)return goog.events.KeyCodes.isCharacterKey(a);if(e&&!d)return!1;if(!goog.userAgent.GECKO){goog.isNumber(b)&&(b=goog.events.KeyCodes.normalizeKeyCode(b));var g=b==goog.events.KeyCodes.CTRL||b==goog.events.KeyCodes.ALT||goog.userAgent.MAC&&b==goog.events.KeyCodes.META,h=b==goog.events.KeyCodes.SHIFT&&(d||f);if((!c||goog.userAgent.MAC)&&g|| goog.userAgent.MAC&&h)return!1}if((goog.userAgent.WEBKIT||goog.userAgent.EDGE)&&d&&c)switch(a){case goog.events.KeyCodes.BACKSLASH:case goog.events.KeyCodes.OPEN_SQUARE_BRACKET:case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET:case goog.events.KeyCodes.TILDE:case goog.events.KeyCodes.SEMICOLON:case goog.events.KeyCodes.DASH:case goog.events.KeyCodes.EQUALS:case goog.events.KeyCodes.COMMA:case goog.events.KeyCodes.PERIOD:case goog.events.KeyCodes.SLASH:case goog.events.KeyCodes.APOSTROPHE:case goog.events.KeyCodes.SINGLE_QUOTE:return!1}if(goog.userAgent.IE&& d&&b==a)return!1;switch(a){case goog.events.KeyCodes.ENTER:return goog.userAgent.GECKO?f||e?!1:!(c&&d):!0;case goog.events.KeyCodes.ESC:return!(goog.userAgent.WEBKIT||goog.userAgent.EDGE||goog.userAgent.GECKO)}return goog.userAgent.GECKO&&(d||e||f)?!1:goog.events.KeyCodes.isCharacterKey(a)}; goog.events.KeyCodes.isCharacterKey=function(a){if(a>=goog.events.KeyCodes.ZERO&&a<=goog.events.KeyCodes.NINE||a>=goog.events.KeyCodes.NUM_ZERO&&a<=goog.events.KeyCodes.NUM_MULTIPLY||a>=goog.events.KeyCodes.A&&a<=goog.events.KeyCodes.Z||(goog.userAgent.WEBKIT||goog.userAgent.EDGE)&&0==a)return!0;switch(a){case goog.events.KeyCodes.SPACE:case goog.events.KeyCodes.PLUS_SIGN:case goog.events.KeyCodes.QUESTION_MARK:case goog.events.KeyCodes.AT_SIGN:case goog.events.KeyCodes.NUM_PLUS:case goog.events.KeyCodes.NUM_MINUS:case goog.events.KeyCodes.NUM_PERIOD:case goog.events.KeyCodes.NUM_DIVISION:case goog.events.KeyCodes.SEMICOLON:case goog.events.KeyCodes.FF_SEMICOLON:case goog.events.KeyCodes.DASH:case goog.events.KeyCodes.EQUALS:case goog.events.KeyCodes.FF_EQUALS:case goog.events.KeyCodes.COMMA:case goog.events.KeyCodes.PERIOD:case goog.events.KeyCodes.SLASH:case goog.events.KeyCodes.APOSTROPHE:case goog.events.KeyCodes.SINGLE_QUOTE:case goog.events.KeyCodes.OPEN_SQUARE_BRACKET:case goog.events.KeyCodes.BACKSLASH:case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET:case goog.events.KeyCodes.FF_HASH:return!0; -default:return!1}};goog.events.KeyCodes.normalizeKeyCode=function(a){return goog.userAgent.GECKO?goog.events.KeyCodes.normalizeGeckoKeyCode(a):goog.userAgent.MAC&&goog.userAgent.WEBKIT?goog.events.KeyCodes.normalizeMacWebKitKeyCode(a):a}; +case goog.events.KeyCodes.FF_DASH:return goog.userAgent.GECKO;default:return!1}};goog.events.KeyCodes.normalizeKeyCode=function(a){return goog.userAgent.GECKO?goog.events.KeyCodes.normalizeGeckoKeyCode(a):goog.userAgent.MAC&&goog.userAgent.WEBKIT?goog.events.KeyCodes.normalizeMacWebKitKeyCode(a):a}; goog.events.KeyCodes.normalizeGeckoKeyCode=function(a){switch(a){case goog.events.KeyCodes.FF_EQUALS:return goog.events.KeyCodes.EQUALS;case goog.events.KeyCodes.FF_SEMICOLON:return goog.events.KeyCodes.SEMICOLON;case goog.events.KeyCodes.FF_DASH:return goog.events.KeyCodes.DASH;case goog.events.KeyCodes.MAC_FF_META:return goog.events.KeyCodes.META;case goog.events.KeyCodes.WIN_KEY_FF_LINUX:return goog.events.KeyCodes.WIN_KEY;default:return a}}; goog.events.KeyCodes.normalizeMacWebKitKeyCode=function(a){switch(a){case goog.events.KeyCodes.MAC_WK_CMD_RIGHT:return goog.events.KeyCodes.META;default:return a}};goog.events.KeyHandler=function(a,b){goog.events.EventTarget.call(this);a&&this.attach(a,b)};goog.inherits(goog.events.KeyHandler,goog.events.EventTarget);goog.events.KeyHandler.prototype.element_=null;goog.events.KeyHandler.prototype.keyPressKey_=null;goog.events.KeyHandler.prototype.keyDownKey_=null;goog.events.KeyHandler.prototype.keyUpKey_=null;goog.events.KeyHandler.prototype.lastKey_=-1;goog.events.KeyHandler.prototype.keyCode_=-1;goog.events.KeyHandler.prototype.altKey_=!1; goog.events.KeyHandler.EventType={KEY:"key"}; @@ -746,38 +746,14 @@ goog.ui.Menu.prototype.setAllowHighlightDisabled=function(a){this.allowHighlight goog.ui.Menu.prototype.handleEnterItem=function(a){this.allowAutoFocus_&&this.getKeyEventTarget().focus();return goog.ui.Menu.superClass_.handleEnterItem.call(this,a)};goog.ui.Menu.prototype.highlightNextPrefix=function(a){var b=new RegExp("^"+goog.string.regExpEscape(a),"i");return this.highlightHelper(function(a,d){var c=0>a?0:a,f=!1;do{++a;a==d&&(a=0,f=!0);var g=this.getChildAt(a).getCaption();if(g&&g.match(b))return a}while(!f||a!=c);return this.getHighlightedIndex()},this.getHighlightedIndex())}; goog.ui.Menu.prototype.canHighlightItem=function(a){return(this.allowHighlightDisabled_||a.isEnabled())&&a.isVisible()&&a.isSupportedState(goog.ui.Component.State.HOVER)};goog.ui.Menu.prototype.decorateInternal=function(a){this.decorateContent(a);goog.ui.Menu.superClass_.decorateInternal.call(this,a)}; goog.ui.Menu.prototype.handleKeyEventInternal=function(a){var b=goog.ui.Menu.superClass_.handleKeyEventInternal.call(this,a);b||this.forEachChild(function(c){!b&&c.getMnemonic&&c.getMnemonic()==a.keyCode&&(this.isEnabled()&&this.setHighlighted(c),b=c.handleKeyEvent(a))},this);return b};goog.ui.Menu.prototype.setHighlightedIndex=function(a){goog.ui.Menu.superClass_.setHighlightedIndex.call(this,a);(a=this.getChildAt(a))&&goog.style.scrollIntoContainerView(a.getElement(),this.getElement())}; -goog.ui.Menu.prototype.decorateContent=function(a){var b=this.getRenderer();a=this.getDomHelper().getElementsByTagNameAndClass("DIV",b.getCssClass()+"-content",a);for(var c=a.length,d=0;d=this.getEffectiveLevel().value}; -goog.debug.Logger.prototype.log=function(a,b,c){goog.debug.LOGGING_ENABLED&&this.isLoggable(a)&&(goog.isFunction(b)&&(b=b()),this.doLogRecord_(this.getLogRecord(a,b,c)))};goog.debug.Logger.prototype.getLogRecord=function(a,b,c){a=goog.debug.LogBuffer.isBufferingEnabled()?goog.debug.LogBuffer.getInstance().addRecord(a,b,this.name_):new goog.debug.LogRecord(a,String(b),this.name_);c&&a.setException(c);return a}; -goog.debug.Logger.prototype.shout=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SHOUT,a,b)};goog.debug.Logger.prototype.severe=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SEVERE,a,b)};goog.debug.Logger.prototype.warning=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.WARNING,a,b)};goog.debug.Logger.prototype.info=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.INFO,a,b)}; -goog.debug.Logger.prototype.config=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.CONFIG,a,b)};goog.debug.Logger.prototype.fine=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINE,a,b)};goog.debug.Logger.prototype.finer=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINER,a,b)};goog.debug.Logger.prototype.finest=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINEST,a,b)}; -goog.debug.Logger.prototype.logRecord=function(a){goog.debug.LOGGING_ENABLED&&this.isLoggable(a.getLevel())&&this.doLogRecord_(a)};goog.debug.Logger.prototype.doLogRecord_=function(a){goog.debug.Logger.ENABLE_PROFILER_LOGGING&&goog.debug.Logger.logToProfilers("log:"+a.getMessage());if(goog.debug.Logger.ENABLE_HIERARCHY)for(var b=this;b;)b.callPublish_(a),b=b.getParent();else{b=0;for(var c;c=goog.debug.Logger.rootHandlers_[b++];)c(a)}}; -goog.debug.Logger.prototype.callPublish_=function(a){if(this.handlers_)for(var b=0,c;c=this.handlers_[b];b++)c(a)};goog.debug.Logger.prototype.setParent_=function(a){this.parent_=a};goog.debug.Logger.prototype.addChild_=function(a,b){this.getChildren()[a]=b};goog.debug.LogManager={};goog.debug.LogManager.loggers_={};goog.debug.LogManager.rootLogger_=null; -goog.debug.LogManager.initialize=function(){goog.debug.LogManager.rootLogger_||(goog.debug.LogManager.rootLogger_=new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME),goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME]=goog.debug.LogManager.rootLogger_,goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))};goog.debug.LogManager.getLoggers=function(){return goog.debug.LogManager.loggers_}; -goog.debug.LogManager.getRoot=function(){goog.debug.LogManager.initialize();return goog.debug.LogManager.rootLogger_};goog.debug.LogManager.getLogger=function(a){goog.debug.LogManager.initialize();return goog.debug.LogManager.loggers_[a]||goog.debug.LogManager.createLogger_(a)};goog.debug.LogManager.createFunctionForCatchErrors=function(a){return function(b){(a||goog.debug.LogManager.getRoot()).severe("Error: "+b.message+" ("+b.fileName+" @ Line: "+b.line+")")}}; -goog.debug.LogManager.createLogger_=function(a){var b=new goog.debug.Logger(a);if(goog.debug.Logger.ENABLE_HIERARCHY){var c=a.lastIndexOf("."),d=a.substr(0,c);c=a.substr(c+1);d=goog.debug.LogManager.getLogger(d);d.addChild_(c,b);b.setParent_(d)}return goog.debug.LogManager.loggers_[a]=b};goog.log={};goog.log.ENABLED=goog.debug.LOGGING_ENABLED;goog.log.ROOT_LOGGER_NAME=goog.debug.Logger.ROOT_LOGGER_NAME;goog.log.Logger=goog.debug.Logger;goog.log.Level=goog.debug.Logger.Level;goog.log.LogRecord=goog.debug.LogRecord;goog.log.getLogger=function(a,b){return goog.log.ENABLED?(a=goog.debug.LogManager.getLogger(a),b&&a&&a.setLevel(b),a):null};goog.log.addHandler=function(a,b){goog.log.ENABLED&&a&&a.addHandler(b)}; -goog.log.removeHandler=function(a,b){return goog.log.ENABLED&&a?a.removeHandler(b):!1};goog.log.log=function(a,b,c,d){goog.log.ENABLED&&a&&a.log(b,c,d)};goog.log.error=function(a,b,c){goog.log.ENABLED&&a&&a.severe(b,c)};goog.log.warning=function(a,b,c){goog.log.ENABLED&&a&&a.warning(b,c)};goog.log.info=function(a,b,c){goog.log.ENABLED&&a&&a.info(b,c)};goog.log.fine=function(a,b,c){goog.log.ENABLED&&a&&a.fine(b,c)};goog.Thenable=function(){};goog.Thenable.prototype.then=function(a,b,c){};goog.Thenable.IMPLEMENTED_BY_PROP="$goog_Thenable";goog.Thenable.addImplementation=function(a){COMPILED?a.prototype[goog.Thenable.IMPLEMENTED_BY_PROP]=!0:a.prototype.$goog_Thenable=!0};goog.Thenable.isImplementedBy=function(a){if(!a)return!1;try{return COMPILED?!!a[goog.Thenable.IMPLEMENTED_BY_PROP]:!!a.$goog_Thenable}catch(b){return!1}};goog.async={};goog.async.FreeList=function(a,b,c){this.limit_=c;this.create_=a;this.reset_=b;this.occupants_=0;this.head_=null};goog.async.FreeList.prototype.get=function(){if(0=this.getEffectiveLevel().value}; +goog.debug.Logger.prototype.log=function(a,b,c){goog.debug.LOGGING_ENABLED&&this.isLoggable(a)&&(goog.isFunction(b)&&(b=b()),this.doLogRecord_(this.getLogRecord(a,b,c)))};goog.debug.Logger.prototype.getLogRecord=function(a,b,c){a=goog.debug.LogBuffer.isBufferingEnabled()?goog.debug.LogBuffer.getInstance().addRecord(a,b,this.name_):new goog.debug.LogRecord(a,String(b),this.name_);c&&a.setException(c);return a}; +goog.debug.Logger.prototype.shout=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SHOUT,a,b)};goog.debug.Logger.prototype.severe=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SEVERE,a,b)};goog.debug.Logger.prototype.warning=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.WARNING,a,b)};goog.debug.Logger.prototype.info=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.INFO,a,b)}; +goog.debug.Logger.prototype.config=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.CONFIG,a,b)};goog.debug.Logger.prototype.fine=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINE,a,b)};goog.debug.Logger.prototype.finer=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINER,a,b)};goog.debug.Logger.prototype.finest=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINEST,a,b)}; +goog.debug.Logger.prototype.logRecord=function(a){goog.debug.LOGGING_ENABLED&&this.isLoggable(a.getLevel())&&this.doLogRecord_(a)};goog.debug.Logger.prototype.doLogRecord_=function(a){goog.debug.Logger.ENABLE_PROFILER_LOGGING&&goog.debug.Logger.logToProfilers("log:"+a.getMessage());if(goog.debug.Logger.ENABLE_HIERARCHY)for(var b=this;b;)b.callPublish_(a),b=b.getParent();else{b=0;for(var c;c=goog.debug.Logger.rootHandlers_[b++];)c(a)}}; +goog.debug.Logger.prototype.callPublish_=function(a){if(this.handlers_)for(var b=0,c;c=this.handlers_[b];b++)c(a)};goog.debug.Logger.prototype.setParent_=function(a){this.parent_=a};goog.debug.Logger.prototype.addChild_=function(a,b){this.getChildren()[a]=b};goog.debug.LogManager={};goog.debug.LogManager.loggers_={};goog.debug.LogManager.rootLogger_=null; +goog.debug.LogManager.initialize=function(){goog.debug.LogManager.rootLogger_||(goog.debug.LogManager.rootLogger_=new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME),goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME]=goog.debug.LogManager.rootLogger_,goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))};goog.debug.LogManager.getLoggers=function(){return goog.debug.LogManager.loggers_}; +goog.debug.LogManager.getRoot=function(){goog.debug.LogManager.initialize();return goog.debug.LogManager.rootLogger_};goog.debug.LogManager.getLogger=function(a){goog.debug.LogManager.initialize();return goog.debug.LogManager.loggers_[a]||goog.debug.LogManager.createLogger_(a)};goog.debug.LogManager.createFunctionForCatchErrors=function(a){return function(b){(a||goog.debug.LogManager.getRoot()).severe("Error: "+b.message+" ("+b.fileName+" @ Line: "+b.line+")")}}; +goog.debug.LogManager.createLogger_=function(a){var b=new goog.debug.Logger(a);if(goog.debug.Logger.ENABLE_HIERARCHY){var c=a.lastIndexOf("."),d=a.substr(0,c);c=a.substr(c+1);d=goog.debug.LogManager.getLogger(d);d.addChild_(c,b);b.setParent_(d)}return goog.debug.LogManager.loggers_[a]=b};goog.log={};goog.log.ENABLED=goog.debug.LOGGING_ENABLED;goog.log.ROOT_LOGGER_NAME=goog.debug.Logger.ROOT_LOGGER_NAME;goog.log.Logger=goog.debug.Logger;goog.log.Level=goog.debug.Logger.Level;goog.log.LogRecord=goog.debug.LogRecord;goog.log.getLogger=function(a,b){return goog.log.ENABLED?(a=goog.debug.LogManager.getLogger(a),b&&a&&a.setLevel(b),a):null};goog.log.addHandler=function(a,b){goog.log.ENABLED&&a&&a.addHandler(b)}; +goog.log.removeHandler=function(a,b){return goog.log.ENABLED&&a?a.removeHandler(b):!1};goog.log.log=function(a,b,c,d){goog.log.ENABLED&&a&&a.log(b,c,d)};goog.log.error=function(a,b,c){goog.log.ENABLED&&a&&a.severe(b,c)};goog.log.warning=function(a,b,c){goog.log.ENABLED&&a&&a.warning(b,c)};goog.log.info=function(a,b,c){goog.log.ENABLED&&a&&a.info(b,c)};goog.log.fine=function(a,b,c){goog.log.ENABLED&&a&&a.fine(b,c)};goog.ui.tree.TreeNode=function(a,b,c){goog.ui.tree.BaseNode.call(this,a,b,c)};goog.inherits(goog.ui.tree.TreeNode,goog.ui.tree.BaseNode);goog.ui.tree.TreeNode.prototype.getTree=function(){if(this.tree)return this.tree;var a=this.getParent();return a&&(a=a.getTree())?(this.setTreeInternal(a),a):null}; goog.ui.tree.TreeNode.prototype.getCalculatedIconClass=function(){var a=this.getExpanded(),b=this.getExpandedIconClass();if(a&&b)return b;b=this.getIconClass();if(!a&&b)return b;b=this.getConfig();if(this.hasChildren()){if(a&&b.cssExpandedFolderIcon)return b.cssTreeIcon+" "+b.cssExpandedFolderIcon;if(!a&&b.cssCollapsedFolderIcon)return b.cssTreeIcon+" "+b.cssCollapsedFolderIcon}else if(b.cssFileIcon)return b.cssTreeIcon+" "+b.cssFileIcon;return""};goog.structs={};goog.structs.getCount=function(a){return a.getCount&&"function"==typeof a.getCount?a.getCount():goog.isArrayLike(a)||goog.isString(a)?a.length:goog.object.getCount(a)};goog.structs.getValues=function(a){if(a.getValues&&"function"==typeof a.getValues)return a.getValues();if(goog.isString(a))return a.split("");if(goog.isArrayLike(a)){for(var b=[],c=a.length,d=0;db&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;a=[];var h=c.length/e,k=1;for(d=0;df);return g}; Blockly.utils.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.utils.wrapMutate_(a,e,c):b};Blockly.utils.wrapToText_=function(a,b){for(var c=[],d=0;d";var d=Blockly.Xml.textToDom(""+a+"");b.domToMutation(d.firstChild)}Blockly.Events.fire(new Blockly.Events.Change(b,"mutation",null,c,a));break;default:console.warn("Unknown change type: "+this.element)}else console.warn("Can't change non-existent block: "+this.blockId)}; Blockly.Events.Create=function(a){a&&(Blockly.Events.Create.superClass_.constructor.call(this,a),this.xml=a.workspace.rendered?Blockly.Xml.blockToDomWithXY(a):Blockly.Xml.blockToDom(a),this.ids=Blockly.Events.getDescendantIds_(a))};goog.inherits(Blockly.Events.Create,Blockly.Events.BlockBase);Blockly.Events.BlockCreate=Blockly.Events.Create;Blockly.Events.Create.prototype.type=Blockly.Events.CREATE; Blockly.Events.Create.prototype.toJson=function(){var a=Blockly.Events.Create.superClass_.toJson.call(this);a.xml=Blockly.Xml.domToText(this.xml);a.ids=this.ids;return a};Blockly.Events.Create.prototype.fromJson=function(a){Blockly.Events.Create.superClass_.fromJson.call(this,a);this.xml=Blockly.Xml.textToDom(""+a.xml+"").firstChild;this.ids=a.ids}; @@ -961,18 +965,16 @@ Blockly.Events.Move.prototype.toJson=function(){var a=Blockly.Events.Move.superC Blockly.Events.Move.prototype.fromJson=function(a){Blockly.Events.Move.superClass_.fromJson.call(this,a);this.newParentId=a.newParentId;this.newInputName=a.newInputName;a.newCoordinate&&(a=a.newCoordinate.split(","),this.newCoordinate=new goog.math.Coordinate(parseFloat(a[0]),parseFloat(a[1])))};Blockly.Events.Move.prototype.recordNew=function(){var a=this.currentLocation_();this.newParentId=a.parentId;this.newInputName=a.inputName;this.newCoordinate=a.coordinate}; Blockly.Events.Move.prototype.currentLocation_=function(){var a=Blockly.Workspace.getById(this.workspaceId).getBlockById(this.blockId),b={},c=a.getParent();if(c){if(b.parentId=c.id,a=c.getInputWithBlock(a))b.inputName=a.name}else b.coordinate=a.getRelativeToSurfaceXY();return b};Blockly.Events.Move.prototype.isNull=function(){return this.oldParentId==this.newParentId&&this.oldInputName==this.newInputName&&goog.math.Coordinate.equals(this.oldCoordinate,this.newCoordinate)}; Blockly.Events.Move.prototype.run=function(a){var b=this.getEventWorkspace_(),c=b.getBlockById(this.blockId);if(c){var d=a?this.newParentId:this.oldParentId,e=a?this.newInputName:this.oldInputName;a=a?this.newCoordinate:this.oldCoordinate;var f=null;if(d&&(f=b.getBlockById(d),!f)){console.warn("Can't connect to non-existent block: "+d);return}c.getParent()&&c.unplug();if(a)e=c.getRelativeToSurfaceXY(),c.moveBy(a.x-e.x,a.y-e.y);else{c=c.outputConnection||c.previousConnection;if(e){if(b=f.getInput(e))var g= -b.connection}else c.type==Blockly.PREVIOUS_STATEMENT&&(g=f.nextConnection);g?c.connect(g):console.warn("Can't connect to non-existent input: "+e)}}else console.warn("Can't move non-existent block: "+this.blockId)}; -Blockly.Events.FinishedLoading=function(a){this.workspaceId=a.id;this.group=Blockly.Events.group_;this.recordUndo=!1};goog.inherits(Blockly.Events.FinishedLoading,Blockly.Events.Abstract);Blockly.Events.FinishedLoading.prototype.type=Blockly.Events.FINISHED_LOADING;Blockly.Events.FinishedLoading.prototype.toJson=function(){var a={type:this.type};this.group&&(a.group=this.group);this.workspaceId&&(a.workspaceId=this.workspaceId);return a}; +b.connection}else c.type==Blockly.PREVIOUS_STATEMENT&&(g=f.nextConnection);g?c.connect(g):console.warn("Can't connect to non-existent input: "+e)}}else console.warn("Can't move non-existent block: "+this.blockId)};Blockly.Events.FinishedLoading=function(a){this.workspaceId=a.id;this.group=Blockly.Events.group_;this.recordUndo=!1};goog.inherits(Blockly.Events.FinishedLoading,Blockly.Events.Abstract);Blockly.Events.FinishedLoading.prototype.type=Blockly.Events.FINISHED_LOADING;Blockly.Events.FinishedLoading.prototype.toJson=function(){var a={type:this.type};this.group&&(a.group=this.group);this.workspaceId&&(a.workspaceId=this.workspaceId);return a}; Blockly.Events.FinishedLoading.prototype.fromJson=function(a){this.workspaceId=a.workspaceId;this.group=a.group};Blockly.Xml.workspaceToDom=function(a,b){var c=Blockly.Xml.utils.createElement("xml"),d=Blockly.Xml.variablesToDom(Blockly.Variables.allUsedVarModels(a));d.hasChildNodes()&&c.appendChild(d);var e=a.getTopComments(!0);d=0;for(var f;f=e[d];d++)c.appendChild(f.toXmlWithXY(b));a=a.getTopBlocks(!0);for(d=0;e=a[d];d++)c.appendChild(Blockly.Xml.blockToDomWithXY(e,b));return c}; Blockly.Xml.variablesToDom=function(a){for(var b=Blockly.Xml.utils.createElement("variables"),c=0,d;d=a[c];c++){var e=Blockly.Xml.utils.createElement("variable");e.appendChild(Blockly.Xml.utils.createTextNode(d.name));e.setAttribute("type",d.type);e.setAttribute("id",d.getId());b.appendChild(e)}return b}; -Blockly.Xml.blockToDomWithXY=function(a,b){var c;a.workspace.RTL&&(c=a.workspace.getWidth());b=Blockly.Xml.blockToDom(a,b);var d=a.getRelativeToSurfaceXY();b.setAttribute("x",Math.round(a.workspace.RTL?c-d.x:d.x));b.setAttribute("y",Math.round(d.y));return b}; -Blockly.Xml.fieldToDomVariable_=function(a){null==a.getValue()&&(a.initModel(),a.getValue());var b=a.getVariable();if(!b)throw Error("Tried to serialize a variable field with no variable.");var c=Blockly.Xml.utils.createElement("field");c.appendChild(Blockly.Xml.utils.createTextNode(b.name));c.setAttribute("name",a.name);c.setAttribute("id",b.getId());c.setAttribute("variabletype",b.type);return c}; -Blockly.Xml.fieldToDom_=function(a){if(a.name&&a.EDITABLE){if(a.referencesVariables())return Blockly.Xml.fieldToDomVariable_(a);var b=Blockly.Xml.utils.createElement("field");b.appendChild(Blockly.Xml.utils.createTextNode(a.getValue()));b.setAttribute("name",a.name);return b}return null};Blockly.Xml.allFieldsToDom_=function(a,b){for(var c=0,d;d=a.inputList[c];c++)for(var e=0,f;f=d.fieldRow[e];e++)(f=Blockly.Xml.fieldToDom_(f))&&b.appendChild(f)}; +Blockly.Xml.blockToDomWithXY=function(a,b){var c;a.workspace.RTL&&(c=a.workspace.getWidth());b=Blockly.Xml.blockToDom(a,b);var d=a.getRelativeToSurfaceXY();b.setAttribute("x",Math.round(a.workspace.RTL?c-d.x:d.x));b.setAttribute("y",Math.round(d.y));return b};Blockly.Xml.fieldToDom_=function(a){if(a.isSerializable()){var b=Blockly.Xml.utils.createElement("field");return a.toXml(b)}return null}; +Blockly.Xml.allFieldsToDom_=function(a,b){for(var c=0,d;d=a.inputList[c];c++)for(var e=0,f;f=d.fieldRow[e];e++)(f=Blockly.Xml.fieldToDom_(f))&&b.appendChild(f)}; Blockly.Xml.blockToDom=function(a,b){var c=Blockly.Xml.utils.createElement(a.isShadow()?"shadow":"block");c.setAttribute("type",a.type);b||c.setAttribute("id",a.id);if(a.mutationToDom){var d=a.mutationToDom();d&&(d.hasChildNodes()||d.hasAttributes())&&c.appendChild(d)}Blockly.Xml.allFieldsToDom_(a,c);var e=a.getCommentText();e&&(d=Blockly.Xml.utils.createElement("comment"),d.appendChild(Blockly.Xml.utils.createTextNode(e)),"object"==typeof a.comment&&(d.setAttribute("pinned",a.comment.isVisible()), e=a.comment.getBubbleSize(),d.setAttribute("h",e.height),d.setAttribute("w",e.width)),c.appendChild(d));a.data&&(d=Blockly.Xml.utils.createElement("data"),d.appendChild(Blockly.Xml.utils.createTextNode(a.data)),c.appendChild(d));e=0;for(var f;f=a.inputList[e];e++){var g,h=!0;if(f.type!=Blockly.DUMMY_INPUT){var k=f.connection.targetBlock();f.type==Blockly.INPUT_VALUE?g=Blockly.Xml.utils.createElement("value"):f.type==Blockly.NEXT_STATEMENT&&(g=Blockly.Xml.utils.createElement("statement"));d=f.connection.getShadowDom(); -!d||k&&k.isShadow()||g.appendChild(Blockly.Xml.cloneShadow_(d));k&&(g.appendChild(Blockly.Xml.blockToDom(k,b)),h=!1);g.setAttribute("name",f.name);h||c.appendChild(g)}}a.inputsInlineDefault!=a.inputsInline&&c.setAttribute("inline",a.inputsInline);a.isCollapsed()&&c.setAttribute("collapsed",!0);a.disabled&&c.setAttribute("disabled",!0);a.isDeletable()||a.isShadow()||c.setAttribute("deletable",!1);a.isMovable()||a.isShadow()||c.setAttribute("movable",!1);a.isEditable()||c.setAttribute("editable",!1); -if(e=a.getNextBlock())g=Blockly.Xml.utils.createElement("next"),g.appendChild(Blockly.Xml.blockToDom(e,b)),c.appendChild(g);d=a.nextConnection&&a.nextConnection.getShadowDom();!d||e&&e.isShadow()||g.appendChild(Blockly.Xml.cloneShadow_(d));return c}; -Blockly.Xml.cloneShadow_=function(a){for(var b=a=a.cloneNode(!0),c;b;)if(b.firstChild)b=b.firstChild;else{for(;b&&!b.nextSibling;)c=b,b=b.parentNode,3==c.nodeType&&""==c.data.trim()&&b.firstChild!=c&&Blockly.utils.removeNode(c);b&&(c=b,b=b.nextSibling,3==c.nodeType&&""==c.data.trim()&&Blockly.utils.removeNode(c))}return a};Blockly.Xml.domToText=function(a){return Blockly.Xml.utils.domToText(a)}; +!d||k&&k.isShadow()||g.appendChild(Blockly.Xml.cloneShadow_(d));k&&(g.appendChild(Blockly.Xml.blockToDom(k,b)),h=!1);g.setAttribute("name",f.name);h||c.appendChild(g)}}a.inputsInlineDefault!=a.inputsInline&&c.setAttribute("inline",a.inputsInline);a.isCollapsed()&&c.setAttribute("collapsed",!0);a.isEnabled()||c.setAttribute("disabled",!0);a.isDeletable()||a.isShadow()||c.setAttribute("deletable",!1);a.isMovable()||a.isShadow()||c.setAttribute("movable",!1);a.isEditable()||c.setAttribute("editable", +!1);if(e=a.getNextBlock())g=Blockly.Xml.utils.createElement("next"),g.appendChild(Blockly.Xml.blockToDom(e,b)),c.appendChild(g);d=a.nextConnection&&a.nextConnection.getShadowDom();!d||e&&e.isShadow()||g.appendChild(Blockly.Xml.cloneShadow_(d));return c}; +Blockly.Xml.cloneShadow_=function(a){for(var b=a=a.cloneNode(!0),c;b;)if(b.firstChild)b=b.firstChild;else{for(;b&&!b.nextSibling;)c=b,b=b.parentNode,c.nodeType==Element.TEXT_NODE&&""==c.data.trim()&&b.firstChild!=c&&Blockly.utils.removeNode(c);b&&(c=b,b=b.nextSibling,c.nodeType==Element.TEXT_NODE&&""==c.data.trim()&&Blockly.utils.removeNode(c))}return a};Blockly.Xml.domToText=function(a){return Blockly.Xml.utils.domToText(a)}; Blockly.Xml.domToPrettyText=function(a){a=Blockly.Xml.domToText(a).split("<");for(var b="",c=1;c"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=Blockly.Xml.utils.textToDomDocument(a);if(!a||!a.documentElement||"xml"!=a.documentElement.nodeName.toLowerCase())throw TypeError("Blockly.Xml.textToDom expected an document.");return a.documentElement};Blockly.Xml.clearWorkspaceAndLoadFromXml=function(a,b){b.setResizesEnabled(!1);b.clear();a=Blockly.Xml.domToWorkspace(a,b);b.setResizesEnabled(!0);return a}; Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());c=[];Blockly.Field.startCache();var e=a.childNodes.length,f=Blockly.Events.getGroup();f||Blockly.Events.setGroup(!0);b.setResizesEnabled&&b.setResizesEnabled(!1);var g=!0;try{for(var h=0;hb?!1:Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,a)}; +Blockly.RenderedConnection.prototype.connect=function(a){Blockly.RenderedConnection.superClass_.connect.call(this,a);if(this.hidden_||a.hidden_){a=this.isSuperior()?this:a;a.hidden_?a.hideAll():a.unhideAll();var b=a.targetBlock(),c=a.hidden_?"none":"block";b.getSvgRoot().style.display=c;b.rendered=!a.hidden_}}; +Blockly.RenderedConnection.prototype.disconnect=function(){var a=this.isSuperior()?this:this.targetConnection;if(this.targetConnection&&a.hidden_){a.unhideAll();var b=a.targetBlock();b.getSvgRoot().style.display="block";b.rendered=!0;a.setHidden(!0)}Blockly.RenderedConnection.superClass_.disconnect.call(this)}; Blockly.RenderedConnection.prototype.disconnectInternal_=function(a,b){Blockly.RenderedConnection.superClass_.disconnectInternal_.call(this,a,b);a.rendered&&a.render();b.rendered&&(b.updateDisabled(),b.render())}; -Blockly.RenderedConnection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo){Blockly.RenderedConnection.superClass_.respawnShadow_.call(this);b=this.targetBlock();if(!b)throw Error("Couldn't respawn the shadow block that should exist here.");b.initSvg();b.render(!1);a.rendered&&a.render()}};Blockly.RenderedConnection.prototype.neighbours_=function(a){return this.dbOpposite_.getNeighbours(this,a)}; +Blockly.RenderedConnection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo){Blockly.RenderedConnection.superClass_.respawnShadow_.call(this);b=this.targetBlock();if(!b)throw Error("Couldn't respawn the shadow block that should exist here.");b.initSvg();b.render(!1);a.rendered&&!this.hidden_&&a.render()}};Blockly.RenderedConnection.prototype.neighbours_=function(a){return this.dbOpposite_.getNeighbours(this,a)}; Blockly.RenderedConnection.prototype.connect_=function(a){Blockly.RenderedConnection.superClass_.connect_.call(this,a);var b=this.getSourceBlock();a=a.getSourceBlock();b.rendered&&b.updateDisabled();a.rendered&&a.updateDisabled();b.rendered&&a.rendered&&(this.type==Blockly.NEXT_STATEMENT||this.type==Blockly.PREVIOUS_STATEMENT?a.render():b.render())}; Blockly.RenderedConnection.prototype.onCheckChanged_=function(){this.isConnected()&&!this.checkType_(this.targetConnection)&&((this.isSuperior()?this.targetBlock():this.sourceBlock_).unplug(),this.sourceBlock_.bumpNeighbours_())};Blockly.InsertionMarkerManager=function(a){this.topBlock_=Blockly.selected=a;this.workspace_=a.workspace;this.lastMarker_=this.lastOnStack_=null;this.firstMarker_=this.createMarkerBlock_(this.topBlock_);this.localConnection_=this.closestConnection_=null;this.wouldDeleteBlock_=!1;this.markerConnection_=null;this.highlightingBlock_=!1;this.highlightedBlock_=null;this.availableConnections_=this.initAvailableConnections_()}; Blockly.InsertionMarkerManager.prototype.dispose=function(){this.workspace_=this.topBlock_=null;this.availableConnections_.length=0;this.localConnection_=this.closestConnection_=null;Blockly.Events.disable();try{this.firstMarker_&&(this.firstMarker_.dispose(),this.firstMarker_=null),this.lastMarker_&&(this.lastMarker_.dispose(),this.lastMarker_=null)}finally{Blockly.Events.enable()}this.highlightedBlock_=null};Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock=function(){return this.wouldDeleteBlock_}; @@ -1128,9 +1130,9 @@ Blockly.InsertionMarkerManager.prototype.maybeHidePreview_=function(a){if(a.clos Blockly.InsertionMarkerManager.prototype.hidePreview_=function(){this.closestConnection_&&this.closestConnection_.unhighlight();this.highlightingBlock_?this.unhighlightBlock_():this.markerConnection_&&this.disconnectMarker_()}; Blockly.InsertionMarkerManager.prototype.highlightBlock_=function(){var a=this.closestConnection_,b=this.localConnection_;a.targetBlock()?(this.highlightedBlock_=a.targetBlock(),a.targetBlock().highlightForReplacement(!0)):b.type==Blockly.OUTPUT_VALUE&&(this.highlightedBlock_=a.sourceBlock_,a.sourceBlock_.highlightShapeForInput(a,!0));this.highlightingBlock_=!0}; Blockly.InsertionMarkerManager.prototype.unhighlightBlock_=function(){var a=this.closestConnection_;a.type!=Blockly.INPUT_VALUE||a.isConnected()?this.highlightedBlock_.highlightForReplacement(!1):this.highlightedBlock_.highlightShapeForInput(a,!1);this.highlightedBlock_=null;this.highlightingBlock_=!1}; -Blockly.InsertionMarkerManager.prototype.disconnectMarker_=function(){if(this.markerConnection_){var a=this.markerConnection_,b=a.sourceBlock_,c=b.nextConnection,d=b.previousConnection,e=b.outputConnection;e=a.type==Blockly.INPUT_VALUE&&!(e&&e.targetConnection);!(a!=c||d&&d.targetConnection)||e?a.targetBlock().unplug(!1):a.type==Blockly.NEXT_STATEMENT&&a!=c?(c=a.targetConnection,c.sourceBlock_.unplug(!1),d=d?d.targetConnection:null,b.unplug(!0),d&&d.connect(c)):b.unplug(!0);if(a.targetConnection)throw"markerConnection_ still connected at the end of disconnectInsertionMarker"; +Blockly.InsertionMarkerManager.prototype.disconnectMarker_=function(){if(this.markerConnection_){var a=this.markerConnection_,b=a.sourceBlock_,c=b.nextConnection,d=b.previousConnection,e=b.outputConnection;e=a.type==Blockly.INPUT_VALUE&&!(e&&e.targetConnection);!(a!=c||d&&d.targetConnection)||e?a.targetBlock().unplug(!1):a.type==Blockly.NEXT_STATEMENT&&a!=c?(c=a.targetConnection,c.sourceBlock_.unplug(!1),d=d?d.targetConnection:null,b.unplug(!0),d&&d.connect(c)):b.unplug(!0);if(a.targetConnection)throw Error("markerConnection_ still connected at the end of disconnectInsertionMarker"); this.markerConnection_=null;b.getSvgRoot().setAttribute("visibility","hidden")}else console.log("No insertion marker connection to disconnect")}; -Blockly.InsertionMarkerManager.prototype.connectMarker_=function(){var a=this.localConnection_,b=this.closestConnection_,c=this.lastOnStack_&&a==this.lastOnStack_?this.lastMarker_:this.firstMarker_;a=c.getMatchingConnection(a.sourceBlock_,a);goog.asserts.assert(a!=this.markerConnection_,"Made it to connectMarker_ even though the marker isn't changing");c.render();c.rendered=!0;c.getSvgRoot().setAttribute("visibility","visible");c.positionNewBlock(c,a,b);a.connect(b);this.markerConnection_=a}; +Blockly.InsertionMarkerManager.prototype.connectMarker_=function(){var a=this.localConnection_,b=this.closestConnection_,c=this.lastOnStack_&&a==this.lastOnStack_?this.lastMarker_:this.firstMarker_;a=c.getMatchingConnection(a.sourceBlock_,a);if(a==this.markerConnection_)throw Error("Made it to connectMarker_ even though the marker isn't changing");c.render();c.rendered=!0;c.getSvgRoot().setAttribute("visibility","visible");c.positionNewBlock(c,a,b);a.connect(b);this.markerConnection_=a}; Blockly.InsertionMarkerManager.prototype.getInsertionMarkers=function(){var a=[];this.firstMarker_&&a.push(this.firstMarker_);this.lastMarker_&&a.push(this.lastMarker_);return a};Blockly.BlockDragger=function(a,b){this.draggingBlock_=a;this.workspace_=b;this.draggedConnectionManager_=new Blockly.InsertionMarkerManager(this.draggingBlock_);this.deleteArea_=null;this.wouldDeleteBlock_=!1;this.startXY_=this.draggingBlock_.getRelativeToSurfaceXY();this.dragIconData_=Blockly.BlockDragger.initIconData_(a)}; Blockly.BlockDragger.prototype.dispose=function(){this.startWorkspace_=this.workspace_=this.draggingBlock_=null;this.dragIconData_.length=0;this.draggedConnectionManager_&&(this.draggedConnectionManager_.dispose(),this.draggedConnectionManager_=null)};Blockly.BlockDragger.initIconData_=function(a){var b=[];a=a.getDescendants(!1);for(var c=0,d;d=a[c];c++){d=d.getIcons();for(var e=0;eBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,Blockly.Tooltip.showPid_= setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));Blockly.Tooltip.showPid_&&clearTimeout(Blockly.Tooltip.showPid_)};Blockly.Tooltip.block=function(){Blockly.Tooltip.hide();Blockly.Tooltip.blocked_=!0};Blockly.Tooltip.unblock=function(){Blockly.Tooltip.blocked_=!1}; -Blockly.Tooltip.show_=function(){if(!Blockly.Tooltip.blocked_&&(Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_,Blockly.Tooltip.DIV)){Blockly.Tooltip.DIV.innerHTML="";for(var a=Blockly.Tooltip.element_.tooltip;"function"==typeof a;)a=a();a=Blockly.utils.wrap(a,Blockly.Tooltip.LIMIT);a=a.split("\n");for(var b=0;bb.height+window.scrollY&&(d-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?c=Math.max(Blockly.Tooltip.MARGINS-window.scrollX,c):c+Blockly.Tooltip.DIV.offsetWidth> -b.width+window.scrollX-2*Blockly.Tooltip.MARGINS&&(c=b.width-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=d+"px";Blockly.Tooltip.DIV.style.left=c+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; +Blockly.Tooltip.show_=function(){if(!Blockly.Tooltip.blocked_&&(Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_,Blockly.Tooltip.DIV)){Blockly.Tooltip.DIV.innerHTML="";for(var a=Blockly.Tooltip.element_.tooltip;"function"==typeof a;)a=a();a=Blockly.utils.wrap(a,Blockly.Tooltip.LIMIT);a=a.split("\n");for(var b=0;bc+window.scrollY&&(e-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?d=Math.max(Blockly.Tooltip.MARGINS-window.scrollX, +d):d+Blockly.Tooltip.DIV.offsetWidth>b+window.scrollX-2*Blockly.Tooltip.MARGINS&&(d=b-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=e+"px";Blockly.Tooltip.DIV.style.left=d+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; this.healStack_=!Blockly.DRAG_STACK}; Blockly.Gesture.prototype.dispose=function(){Blockly.Touch.clearTouchIdentifier();Blockly.Tooltip.unblock();this.creatorWorkspace_.clearGesture();this.onMoveWrapper_&&Blockly.unbindEvent_(this.onMoveWrapper_);this.onUpWrapper_&&Blockly.unbindEvent_(this.onUpWrapper_);this.flyout_=this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=null;this.blockDragger_&&(this.blockDragger_.dispose(),this.blockDragger_=null);this.workspaceDragger_&&(this.workspaceDragger_.dispose(),this.workspaceDragger_= null);this.bubbleDragger_&&(this.bubbleDragger_.dispose(),this.bubbleDragger_=null)};Blockly.Gesture.prototype.updateFromEvent_=function(a){var b=new goog.math.Coordinate(a.clientX,a.clientY);this.updateDragDelta_(b)&&(this.updateIsDragging_(),Blockly.longStop_());this.mostRecentEvent_=a}; @@ -1196,14 +1198,14 @@ Blockly.Gesture.prototype.handleRightClick=function(a){this.targetBlock_?(this.b Blockly.Gesture.prototype.handleWsStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleWsStart, but the gesture had already been started.");this.setStartWorkspace_(b);this.mostRecentEvent_=a;this.doStart(a)};Blockly.Gesture.prototype.handleFlyoutStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleFlyoutStart, but the gesture had already been started.");this.setStartFlyout_(b);this.handleWsStart(a,b.getWorkspace())}; Blockly.Gesture.prototype.handleBlockStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleBlockStart, but the gesture had already been started.");this.setStartBlock(b);this.mostRecentEvent_=a};Blockly.Gesture.prototype.handleBubbleStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleBubbleStart, but the gesture had already been started.");this.setStartBubble(b);this.mostRecentEvent_=a}; Blockly.Gesture.prototype.doBubbleClick_=function(){this.startBubble_.setFocus&&this.startBubble_.setFocus();this.startBubble_.select&&this.startBubble_.select()};Blockly.Gesture.prototype.doFieldClick_=function(){this.startField_.showEditor_();this.bringBlockToFront_()}; -Blockly.Gesture.prototype.doBlockClick_=function(){this.flyout_&&this.flyout_.autoClose?this.targetBlock_.disabled||(Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.flyout_.createBlock(this.targetBlock_).scheduleSnapAndBump()):Blockly.Events.fire(new Blockly.Events.Ui(this.startBlock_,"click",void 0,void 0));this.bringBlockToFront_();Blockly.Events.setGroup(!1)};Blockly.Gesture.prototype.doWorkspaceClick_=function(){Blockly.selected&&Blockly.selected.unselect()}; +Blockly.Gesture.prototype.doBlockClick_=function(){this.flyout_&&this.flyout_.autoClose?this.targetBlock_.isEnabled()&&(Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.flyout_.createBlock(this.targetBlock_).scheduleSnapAndBump()):Blockly.Events.fire(new Blockly.Events.Ui(this.startBlock_,"click",void 0,void 0));this.bringBlockToFront_();Blockly.Events.setGroup(!1)};Blockly.Gesture.prototype.doWorkspaceClick_=function(){Blockly.selected&&Blockly.selected.unselect()}; Blockly.Gesture.prototype.bringBlockToFront_=function(){this.targetBlock_&&!this.flyout_&&this.targetBlock_.bringToFront()};Blockly.Gesture.prototype.setStartField=function(a){if(this.hasStarted_)throw Error("Tried to call gesture.setStartField, but the gesture had already been started.");this.startField_||(this.startField_=a)};Blockly.Gesture.prototype.setStartBubble=function(a){this.startBubble_||(this.startBubble_=a)}; Blockly.Gesture.prototype.setStartBlock=function(a){this.startBlock_||this.startBubble_||(this.startBlock_=a,a.isInFlyout&&a!=a.getRootBlock()?this.setTargetBlock_(a.getRootBlock()):this.setTargetBlock_(a))};Blockly.Gesture.prototype.setTargetBlock_=function(a){a.isShadow()?this.setTargetBlock_(a.getParent()):this.targetBlock_=a};Blockly.Gesture.prototype.setStartWorkspace_=function(a){this.startWorkspace_||(this.startWorkspace_=a)}; Blockly.Gesture.prototype.setStartFlyout_=function(a){this.flyout_||(this.flyout_=a)};Blockly.Gesture.prototype.isBubbleClick_=function(){return!!this.startBubble_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isBlockClick_=function(){return!!this.startBlock_&&!this.hasExceededDragRadius_&&!this.isFieldClick_()};Blockly.Gesture.prototype.isFieldClick_=function(){return(this.startField_?this.startField_.isCurrentlyEditable():!1)&&!this.hasExceededDragRadius_&&(!this.flyout_||!this.flyout_.autoClose)}; Blockly.Gesture.prototype.isWorkspaceClick_=function(){return!this.startBlock_&&!this.startBubble_&&!this.startField_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isDragging=function(){return this.isDraggingWorkspace_||this.isDraggingBlock_||this.isDraggingBubble_};Blockly.Gesture.prototype.hasStarted=function(){return this.hasStarted_};Blockly.Gesture.prototype.getInsertionMarkers=function(){return this.blockDragger_?this.blockDragger_.getInsertionMarkers():[]}; Blockly.Gesture.inProgress=function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)if(c.currentGesture_)return!0;return!1};Blockly.Grid=function(a,b){this.gridPattern_=a;this.spacing_=b.spacing;this.length_=b.length;this.line2_=(this.line1_=a.firstChild)&&this.line1_.nextSibling;this.snapToGrid_=b.snap};Blockly.Grid.prototype.scale_=1;Blockly.Grid.prototype.dispose=function(){this.gridPattern_=null};Blockly.Grid.prototype.shouldSnap=function(){return this.snapToGrid_};Blockly.Grid.prototype.getSpacing=function(){return this.spacing_};Blockly.Grid.prototype.getPatternId=function(){return this.gridPattern_.id}; Blockly.Grid.prototype.update=function(a){this.scale_=a;var b=this.spacing_*a||100;this.gridPattern_.setAttribute("width",b);this.gridPattern_.setAttribute("height",b);b=Math.floor(this.spacing_/2)+.5;var c=b-this.length_/2,d=b+this.length_/2;b*=a;c*=a;d*=a;this.setLineAttributes_(this.line1_,a,c,d,b,b);this.setLineAttributes_(this.line2_,a,b,b,c,d)}; -Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(goog.userAgent.IE||goog.userAgent.EDGE)&&this.update(this.scale_)}; +Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(Blockly.userAgent.IE||Blockly.userAgent.EDGE)&&this.update(this.scale_)}; Blockly.Grid.createDom=function(a,b,c){a=Blockly.utils.createSvgElement("pattern",{id:"blocklyGridPattern"+a,patternUnits:"userSpaceOnUse"},c);0'+goog.string.htmlEscape(a.name)+""}; +Blockly.Variables.nameUsedWithAnyType_=function(a,b){b=b.getVariableMap().getAllVariables();a=a.toLowerCase();for(var c=0,d;d=b[c];c++)if(d.name.toLowerCase()==a)return d;return null};Blockly.Variables.generateVariableFieldXmlString=function(a){var b=a.type;return''+goog.string.htmlEscape(a.name)+""}; Blockly.Variables.generateVariableFieldDom=function(a){a=Blockly.Variables.generateVariableFieldXmlString(a);return Blockly.Xml.textToDom(""+a+"").firstChild};Blockly.Variables.getOrCreateVariablePackage=function(a,b,c,d){var e=Blockly.Variables.getVariable(a,b,c,d);e||(e=Blockly.Variables.createVariable_(a,b,c,d));return e}; Blockly.Variables.getVariable=function(a,b,c,d){var e=a.getPotentialVariableMap();if(b){var f=a.getVariableById(b);!f&&e&&(f=e.getVariableById(b));if(f)return f}if(c){if(void 0==d)throw Error("Tried to look up a variable by name without a type");f=a.getVariable(c,d);!f&&e&&(f=e.getVariable(c,d))}return f}; Blockly.Variables.createVariable_=function(a,b,c,d){var e=a.getPotentialVariableMap();c||(c=Blockly.Variables.generateUniqueName(a.isFlyout?a.targetWorkspace:a));return e?e.createVariable(c,d,b):a.createVariable(c,d,b)};Blockly.Variables.getAddedVariables=function(a,b){a=a.getAllVariables();var c=[];if(b.length!=a.length)for(var d=0;d";c=Blockly.Xml.textToDom(c).firstChild;b.push(c)}if(Blockly.Blocks.variables_get_dynamic){a.sort(Blockly.VariableModel.compareByName);for(var d=0;c=a[d];d++)c=''+Blockly.Variables.generateVariableFieldXmlString(c)+ -"",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null};Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new window.Audio}catch(h){return}for(var d,e=0;e",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null}; +Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new Blockly.utils.global.Audio}catch(h){return}for(var d,e=0;ethis.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; -Blockly.Field.prototype.forceRerender=function(){this.size_.width=0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()};Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}}; -Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){};Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.init=function(){this.textElement_||(this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},null),this.class_&&Blockly.utils.addClass(this.textElement_,this.class_),this.visible_||(this.textElement_.style.display="none"),this.sourceBlock_.getSvgRoot().appendChild(this.textElement_),this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_,Blockly.Tooltip.bindMouseEvents(this.textElement_),this.render_())}; -Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.getSvgRoot=function(){return this.textElement_};Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; +Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()}; +Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.callValidator(a);null!==b&&(a=b);b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){}; +Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; +Blockly.FieldLabel.prototype.initView=function(){this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},this.fieldGroup_);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_);this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_;Blockly.Tooltip.bindMouseEvents(this.textElement_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)}; +Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; Blockly.Input.prototype.setVisible=function(a){var b=[];if(this.visible_==a)return b;for(var c=(this.visible_=a)?"block":"none",d=0,e;e=this.fieldRow[d];d++)e.setVisible(a);this.connection&&(a?b=this.connection.unhideAll():this.connection.hideAll(),d=this.connection.targetBlock())&&(d.getSvgRoot().style.display=c,a||(d.rendered=!1));return b};Blockly.Input.prototype.setCheck=function(a){if(!this.connection)throw Error("This input does not have a connection.");this.connection.setCheck(a);return this}; @@ -1448,7 +1454,8 @@ Blockly.Block.prototype.setMovable=function(a){this.movable_=a};Blockly.Block.pr Blockly.Block.prototype.setInsertionMarker=function(a){this.isInsertionMarker_=a};Blockly.Block.prototype.isEditable=function(){return this.editable_&&!(this.workspace&&this.workspace.options.readOnly)};Blockly.Block.prototype.setEditable=function(a){this.editable_=a;a=0;for(var b;b=this.inputList[a];a++)for(var c=0,d;d=b.fieldRow[c];c++)d.updateEditable()}; Blockly.Block.prototype.setConnectionsHidden=function(a){if(!a&&this.isCollapsed()){if(this.outputConnection&&this.outputConnection.setHidden(a),this.previousConnection&&this.previousConnection.setHidden(a),this.nextConnection){this.nextConnection.setHidden(a);var b=this.nextConnection.targetBlock();b&&b.setConnectionsHidden(a)}}else for(var c=this.getConnections_(!0),d=0;b=c[d];d++)b.setHidden(a),b.isSuperior()&&(b=b.targetBlock())&&b.setConnectionsHidden(a)}; Blockly.Block.prototype.getMatchingConnection=function(a,b){var c=this.getConnections_(!0);a=a.getConnections_(!0);if(c.length!=a.length)throw Error("Connection lists did not match in length.");for(var d=0;d=c)this.hue_=c,this.colour_=Blockly.hueToRgb(c);else if("string"==typeof b&&/^#[0-9a-fA-F]{6}$/.test(b))this.colour_=b,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; Blockly.Block.prototype.setStyle=function(a){var b=Blockly.getTheme();if(!b)throw Error("Trying to set block style to "+a+" before theme was defined via Blockly.setTheme().");b=b.getBlockStyle(a);this.styleName_=a;if(b)this.colourSecondary_=b.colourSecondary,this.colourTertiary_=b.colourTertiary,this.hat=b.hat,this.setColour(b.colourPrimary);else throw Error("Invalid style name: "+a);}; Blockly.Block.prototype.setOnChange=function(a){if(a&&"function"!=typeof a)throw Error("onchange must be a function.");this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);if(this.onchange=a)this.onchangeWrapper_=a.bind(this),this.workspace.addChangeListener(this.onchangeWrapper_)};Blockly.Block.prototype.getField=function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(e.name===a)return e;return null}; @@ -1460,8 +1467,8 @@ this.previousConnection=null}};Blockly.Block.prototype.setNextStatement=function Blockly.Block.prototype.setOutput=function(a,b){if(a){void 0===b&&(b=null);if(!this.outputConnection){if(this.previousConnection)throw Error("Remove previous connection prior to adding output connection.");this.outputConnection=this.makeConnection_(Blockly.OUTPUT_VALUE)}this.outputConnection.setCheck(b)}else if(this.outputConnection){if(this.outputConnection.isConnected())throw Error("Must disconnect output value before removing connection.");this.outputConnection.dispose();this.outputConnection= null}};Blockly.Block.prototype.setInputsInline=function(a){this.inputsInline!=a&&(Blockly.Events.fire(new Blockly.Events.BlockChange(this,"inline",null,this.inputsInline,a)),this.inputsInline=a)}; Blockly.Block.prototype.getInputsInline=function(){if(void 0!=this.inputsInline)return this.inputsInline;for(var a=1;aa&&(c=c.substring(0,a-3)+"...");return c}; Blockly.Block.prototype.appendValueInput=function(a){return this.appendInput_(Blockly.INPUT_VALUE,a)};Blockly.Block.prototype.appendStatementInput=function(a){return this.appendInput_(Blockly.NEXT_STATEMENT,a)};Blockly.Block.prototype.appendDummyInput=function(a){return this.appendInput_(Blockly.DUMMY_INPUT,a||"")}; Blockly.Block.prototype.jsonInit=function(a){var b=a.type?'Block "'+a.type+'": ':"";if(a.output&&a.previousStatement)throw Error(b+"Must not have both an output and a previousStatement.");a.style&&a.style.hat&&(this.hat=a.style.hat,a.style=null);if(a.style&&a.colour)throw Error(b+"Must not have both a colour and a style.");a.style?this.jsonInitStyle_(a,b):this.jsonInitColour_(a,b);for(var c=0;void 0!==a["message"+c];)this.interpolate_(a["message"+c],a["args"+c]||[],a["lastDummyAlign"+c]),c++;void 0!== @@ -1484,10 +1491,10 @@ Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBo Blockly.ContextMenu.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);var b=a.getElement();Blockly.utils.addClass(b,"blocklyContextMenu");Blockly.bindEventWithChecks_(b,"contextmenu",null,Blockly.utils.noEvent);a.setAllowAutoFocus(!0)};Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_&&Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_)}; Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(c));c.select()}}; Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; -Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!goog.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; +Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; -Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!goog.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/a.scale); -c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= +Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/ +a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= Blockly.utils.is3dSupported()&&!!a.blockDragSurface_;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,a,b,c);this.svgGroup_.dataset&&(this.svgGroup_.dataset.id=this.id)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.prototype.warningTextDb_=null;Blockly.BlockSvg.INLINE=-1;Blockly.BlockSvg.COLLAPSED_WARNING_ID="TEMP_COLLAPSED_WARNING_"; Blockly.BlockSvg.prototype.initSvg=function(){if(!this.workspace.rendered)throw TypeError("Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;ae.bottom)if(d-f.heightc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+ -Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),this.sourceBlock_.getColour());Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b, -"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; +Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a, +"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;a=a.clientY-b.top-Blockly.FieldAngle.HALF;b=Math.atan(-a/c);isNaN(b)||(b=Blockly.utils.toDegrees(b),0>c?b+=180:0a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; -Blockly.FieldCheckbox.prototype.init=function(){if(!this.fieldGroup_){Blockly.FieldCheckbox.superClass_.init.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"}};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; +Blockly.FieldAngle.prototype.classValidator=function(a){if(null===a)return null;a=parseFloat(a||0);if(isNaN(a))return null;a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; +Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; Blockly.FieldCheckbox.prototype.setValue=function(a){a="string"==typeof a?"TRUE"==a.toUpperCase():!!a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(String(a).toUpperCase())}; -Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null;Blockly.FieldColour.prototype.columns_=0; -Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.init=function(){Blockly.FieldColour.superClass_.init.call(this);this.borderRect_.style.fillOpacity=1;this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.setValue(this.getValue())};Blockly.FieldColour.prototype.CURSOR="default"; -Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.getValue=function(){return this.colour_};Blockly.FieldColour.prototype.getSize=function(){this.size_.width||this.render_();return this.size_}; -Blockly.FieldColour.prototype.updateWidth=function(){var a=Blockly.FieldColour.DEFAULT_WIDTH;this.borderRect_&&this.borderRect_.setAttribute("width",a+Blockly.BlockSvg.SEP_SPACE_X);this.size_.width=a};Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)}; -Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); +Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null; +Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.initView=function(){Blockly.FieldColour.superClass_.initView.call(this);this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.borderRect_.style.fillOpacity=1;this.borderRect_.setAttribute("width",this.size_.width+Blockly.BlockSvg.SEP_SPACE_X);this.setValue(this.getValue())}; +Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.updateWidth=function(){};Blockly.FieldColour.prototype.getValue=function(){return this.colour_}; +Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); Blockly.FieldColour.TITLES=[];Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a,b){this.colours_=a;void 0!==b&&(this.titles_=b);return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this}; Blockly.FieldColour.prototype.showEditor_=function(){Blockly.DropDownDiv.hideWithoutAnimation();Blockly.DropDownDiv.clearContent();var a=this.createWidget_();Blockly.DropDownDiv.getContentDiv().appendChild(a);Blockly.DropDownDiv.setColour(this.DROPDOWN_BACKGROUND_COLOUR,this.DROPDOWN_BORDER_COLOUR);Blockly.DropDownDiv.showPositionedByField(this);Blockly.FieldColour.onUpWrapper_=Blockly.bindEvent_(a,"mouseup",this,this.onClick_)}; Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;ge&&(d.height=e);this.sourceBlock_.RTL&&Blockly.utils.uiMenu.adjustBBoxesForRTL(b,c,d);Blockly.WidgetDiv.positionWithAnchor(b,c,d,this.sourceBlock_.RTL);a.getElement().focus()}; @@ -1647,37 +1636,40 @@ Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.pr c);!d&&!e||c<=d+e||(d&&(this.prefixField=b[0].substring(0,d-1)),e&&(this.suffixField=b[0].substr(1-e)),this.menuGenerator_=Blockly.FieldDropdown.applyTrim_(a,d,e))}}};Blockly.FieldDropdown.applyTrim_=function(a,b,c){for(var d=[],e=0;e-b||a<-180+b||a>180-b?!0:!1}; -Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new goog.math.Rect(b-1E9,-1E9,1E9+a,2E9);if(goog.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new goog.math.Rect(b, +Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new goog.math.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new goog.math.Rect(b, -1E9,1E9+a,2E9)}; Blockly.VerticalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);a=Math.max(a,e)}for(c=0;d=this.buttons_[c];c++)a=Math.max(a,d.width);a+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=a){for(c=0;d=b[c];c++)this.RTL&&(e=d.getRelativeToSurfaceXY().x, d.moveBy(a/this.workspace_.scale-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH-e,0)),d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);if(this.RTL)for(c=0;d=this.buttons_[c];c++)b=d.getPosition().y,d.moveTo(a/this.workspace_.scale-d.width-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH,b);this.width_=a;this.position()}};Blockly.Toolbox=function(a){this.workspace_=a;this.RTL=a.options.RTL;this.horizontalLayout_=a.options.horizontalLayout;this.toolboxPosition=a.options.toolboxPosition;this.config_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"};this.treeSeparatorConfig_={cssTreeRow:"blocklyTreeSeparator"}; @@ -1752,7 +1744,7 @@ Blockly.Toolbox.prototype.getHeight=function(){return this.height}; Blockly.Toolbox.prototype.position=function(){var a=this.HtmlDiv;if(a){var b=this.workspace_.getParentSvg();b=Blockly.svgSize(b);this.horizontalLayout_?(a.style.left="0",a.style.height="auto",a.style.width=b.width+"px",this.height=a.offsetHeight,this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?a.style.top="0":a.style.bottom="0"):(this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?a.style.right="0":a.style.left="0",a.style.height=b.height+"px",this.width=a.offsetWidth);this.flyout_.position()}}; Blockly.Toolbox.prototype.populate_=function(a){this.tree_.removeChildren();this.tree_.blocks=[];this.hasColours_=!1;a=this.syncTrees_(a,this.tree_,this.workspace_.options.pathToMedia);if(this.tree_.blocks.length)throw Error("Toolbox cannot have both blocks and categories in the root level.");this.workspace_.resizeContents();return a}; Blockly.Toolbox.prototype.syncTrees_=function(a,b,c){for(var d=null,e=null,f=0,g;g=a.childNodes[f];f++)if(g.tagName)switch(g.tagName.toUpperCase()){case "CATEGORY":e=Blockly.utils.replaceMessageReferences(g.getAttribute("name"));var h=this.tree_.createNode(e);h.blocks=[];b.add(h);var k=g.getAttribute("custom");k?h.blocks=k:(k=this.syncTrees_(g,h,c))&&(d=k);k=g.getAttribute("categorystyle");var l=g.getAttribute("colour");l&&k?(h.hexColour="",console.warn('Toolbox category "'+e+'" can not have both a style and a colour')): -k?this.setColourFromStyle_(k,h,e):this.setColour_(l,h,e);"true"==g.getAttribute("expanded")?(h.blocks.length&&(d=h),h.setExpanded(!0)):h.setExpanded(!1);e=g;break;case "SEP":e&&("CATEGORY"==e.tagName.toUpperCase()?b.add(new Blockly.Toolbox.TreeSeparator(this.treeSeparatorConfig_)):(g=parseFloat(g.getAttribute("gap")),!isNaN(g)&&e&&e.setAttribute("gap",g)));break;case "BLOCK":case "SHADOW":case "LABEL":case "BUTTON":b.blocks.push(g),e=g}return d}; +k?this.setColourFromStyle_(k,h,e):this.setColour_(l,h,e);"true"==g.getAttribute("expanded")?(h.blocks.length&&(d=h),h.setExpanded(!0)):h.setExpanded(!1);e=g;break;case "SEP":if(e&&"CATEGORY"==e.tagName.toUpperCase()){b.add(new Blockly.Toolbox.TreeSeparator(this.treeSeparatorConfig_));break}case "BLOCK":case "SHADOW":case "LABEL":case "BUTTON":b.blocks.push(g),e=g}return d}; Blockly.Toolbox.prototype.setColour_=function(a,b,c){a=Blockly.utils.replaceMessageReferences(a);null===a||""===a?b.hexColour="":/^#[0-9a-fA-F]{6}$/.test(a)?(b.hexColour=a,this.hasColours_=!0):"number"===typeof a||"string"===typeof a&&!isNaN(Number(a))?(b.hexColour=Blockly.hueToRgb(Number(a)),this.hasColours_=!0):(b.hexColour="",console.warn('Toolbox category "'+c+'" has unrecognized colour attribute: '+a))}; Blockly.Toolbox.prototype.setColourFromStyle_=function(a,b,c){if((b.styleName=a)&&Blockly.getTheme()){var d=Blockly.getTheme().getCategoryStyle(a);d&&d.colour?this.setColour_(d.colour,b,c):console.warn('Style "'+a+'" must exist and contain a colour value')}};Blockly.Toolbox.prototype.updateColourFromTheme_=function(a){if(a=a||this.tree_){a=a.getChildren(!1);for(var b=0,c;c=a[b];b++)c.styleName&&(this.setColourFromStyle_(c.styleName,c,""),this.addColour_()),this.updateColourFromTheme_(c)}}; Blockly.Toolbox.prototype.updateColourFromTheme=function(){var a=this.tree_;a&&(this.updateColourFromTheme_(a),this.updateSelectedItemColour_(a))};Blockly.Toolbox.prototype.updateSelectedItemColour_=function(a){var b=a.selectedItem_;if(b){var c=b.hexColour||"#57e";b.getRowElement().style.backgroundColor=c;a.toolbox_.addColour_(b)}}; @@ -1817,28 +1809,28 @@ c.contentHeight)/d);if(b.contentTopb.viewBottom||b.c n=b.viewBottom-d.bottomRight.y;0>n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; -Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(document.addEventListener("mouseup",function(){Blockly.hideChaff();Blockly.Touch.clearTouchIdentifier()},!1),Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document, -"touchcancel",null,Blockly.longStop_),goog.userAgent.IPAD&&Blockly.bindEventWithChecks_(window,"orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; +Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, +"orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[];a=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,a,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,a,!0))}; Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; Blockly.onKeyDown_=function(a){var b=Blockly.mainWorkspace;if(!(b.options.readOnly||Blockly.utils.isTargetInput(a)||b.rendered&&!b.isVisible())){var c=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode){a.preventDefault();if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&(c=!0)}else if(a.altKey||a.ctrlKey||a.metaKey){if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&& (67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),Blockly.clipboardTypeCounts_&&b.isCapacityAvailable(Blockly.clipboardTypeCounts_)&&(Blockly.Events.setGroup(!0),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1))):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&& -(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}};Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace;Blockly.clipboardTypeCounts_=a.isComment?null:Blockly.utils.getBlockTypeCounts(a,!0)}; +(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}};Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a,!0);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace;Blockly.clipboardTypeCounts_=a.isComment?null:Blockly.utils.getBlockTypeCounts(a,!0)}; Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c};Blockly.onContextMenu_=function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()}; Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();Blockly.DropDownDiv.hideWithoutAnimation();var b=Blockly.getMainWorkspace();b.trashcan&&b.trashcan.flyout_&&b.trashcan.flyout_.hide();a||b.toolbox_&&b.toolbox_.flyout_&&b.toolbox_.flyout_.autoClose&&b.toolbox_.clearSelection()};Blockly.addChangeListener=function(a){console.warn("Deprecated call to Blockly.addChangeListener, use workspace.addChangeListener instead.");return Blockly.getMainWorkspace().addChangeListener(a)}; -Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){window.alert(a);b&&b()};Blockly.confirm=function(a,b){b(window.confirm(a))};Blockly.prompt=function(a,b,c){c(window.prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; +Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){alert(a);b&&b()};Blockly.confirm=function(a,b){b(confirm(a))};Blockly.prompt=function(a,b,c){c(prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; Blockly.defineBlocksWithJsonArray=function(a){for(var b=0;bc?Math.max(0,a.length+c):c;if(goog.isString(a))return goog.isString(b)&&1==b.length?a.indexOf(b,c):-1;for(;c=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2]))]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)}; goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)};goog.color.highContrast=function(a,b){for(var c=[],d=0;d":"
")}; goog.string.internal.htmlEscape=function(a,b){if(b)a=a.replace(goog.string.internal.AMP_RE_,"&").replace(goog.string.internal.LT_RE_,"<").replace(goog.string.internal.GT_RE_,">").replace(goog.string.internal.QUOT_RE_,""").replace(goog.string.internal.SINGLE_QUOTE_RE_,"'").replace(goog.string.internal.NULL_RE_,"�");else{if(!goog.string.internal.ALL_RE_.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(goog.string.internal.AMP_RE_,"&"));-1!=a.indexOf("<")&&(a=a.replace(goog.string.internal.LT_RE_, @@ -160,115 +162,18 @@ goog.labs.userAgent.browser.isOpera=goog.labs.userAgent.browser.matchOpera_;goog goog.labs.userAgent.browser.isChrome=goog.labs.userAgent.browser.matchChrome_;goog.labs.userAgent.browser.isAndroidBrowser=goog.labs.userAgent.browser.matchAndroidBrowser_;goog.labs.userAgent.browser.isSilk=function(){return goog.labs.userAgent.util.matchUserAgent("Silk")}; goog.labs.userAgent.browser.getVersion=function(){function a(a){a=goog.array.find(a,d);return c[a]||""}var b=goog.labs.userAgent.util.getUserAgent();if(goog.labs.userAgent.browser.isIE())return goog.labs.userAgent.browser.getIEVersion_(b);b=goog.labs.userAgent.util.extractVersionTuples(b);var c={};goog.array.forEach(b,function(a){c[a[0]]=a[1]});var d=goog.partial(goog.object.containsKey,c);return goog.labs.userAgent.browser.isOpera()?a(["Version","Opera"]):goog.labs.userAgent.browser.isEdge()?a(["Edge"]): goog.labs.userAgent.browser.isChrome()?a(["Chrome","CriOS"]):(b=b[2])&&b[1]||""};goog.labs.userAgent.browser.isVersionOrHigher=function(a){return 0<=goog.string.internal.compareVersions(goog.labs.userAgent.browser.getVersion(),a)}; -goog.labs.userAgent.browser.getIEVersion_=function(a){var b=/rv: *([\d\.]*)/.exec(a);if(b&&b[1])return b[1];b="";var c=/MSIE +([\d\.]+)/.exec(a);if(c&&c[1])if(a=/Trident\/(\d.\d)/.exec(a),"7.0"==c[1])if(a&&a[1])switch(a[1]){case "4.0":b="8.0";break;case "5.0":b="9.0";break;case "6.0":b="10.0";break;case "7.0":b="11.0"}else b="7.0";else b=c[1];return b};goog.string.DETECT_DOUBLE_ESCAPING=!1;goog.string.FORCE_NON_DOM_HTML_UNESCAPING=!1;goog.string.Unicode={NBSP:"\u00a0"};goog.string.startsWith=goog.string.internal.startsWith;goog.string.endsWith=goog.string.internal.endsWith;goog.string.caseInsensitiveStartsWith=goog.string.internal.caseInsensitiveStartsWith;goog.string.caseInsensitiveEndsWith=goog.string.internal.caseInsensitiveEndsWith;goog.string.caseInsensitiveEquals=goog.string.internal.caseInsensitiveEquals; -goog.string.subs=function(a,b){for(var c=a.split("%s"),d="",e=Array.prototype.slice.call(arguments,1);e.length&&1=a||"\u0080"<=a&&"\ufffd">=a}; -goog.string.stripNewlines=function(a){return a.replace(/(\r\n|\r|\n)+/g," ")};goog.string.canonicalizeNewlines=function(a){return a.replace(/(\r\n|\r|\n)/g,"\n")};goog.string.normalizeWhitespace=function(a){return a.replace(/\xa0|\s/g," ")};goog.string.normalizeSpaces=function(a){return a.replace(/\xa0|[ \t]+/g," ")};goog.string.collapseBreakingSpaces=function(a){return a.replace(/[\t\r\n ]+/g," ").replace(/^[\t\r\n ]+|[\t\r\n ]+$/g,"")};goog.string.trim=goog.string.internal.trim; -goog.string.trimLeft=function(a){return a.replace(/^[\s\xa0]+/,"")};goog.string.trimRight=function(a){return a.replace(/[\s\xa0]+$/,"")};goog.string.caseInsensitiveCompare=goog.string.internal.caseInsensitiveCompare; -goog.string.numberAwareCompare_=function(a,b,c){if(a==b)return 0;if(!a)return-1;if(!b)return 1;for(var d=a.toLowerCase().match(c),e=b.toLowerCase().match(c),f=Math.min(d.length,e.length),g=0;g",""":'"'};var d=b?b.createElement("div"):goog.global.document.createElement("div");return a.replace(goog.string.HTML_ENTITY_PATTERN_,function(a,b){var e=c[a];if(e)return e;if("#"==b.charAt(0)){var f=Number("0"+b.substr(1));isNaN(f)||(e=String.fromCharCode(f))}e||(d.innerHTML=a+" ",e=d.firstChild.nodeValue.slice(0,-1));return c[a]=e})}; -goog.string.unescapePureXmlEntities_=function(a){return a.replace(/&([^;]+);/g,function(a,c){switch(c){case "amp":return"&";case "lt":return"<";case "gt":return">";case "quot":return'"';default:if("#"==c.charAt(0)){var b=Number("0"+c.substr(1));if(!isNaN(b))return String.fromCharCode(b)}return a}})};goog.string.HTML_ENTITY_PATTERN_=/&([^;\s<&]+);?/g;goog.string.whitespaceEscape=function(a,b){return goog.string.newLineToBr(a.replace(/ /g,"  "),b)}; -goog.string.preserveSpaces=function(a){return a.replace(/(^|[\n ]) /g,"$1"+goog.string.Unicode.NBSP)};goog.string.stripQuotes=function(a,b){for(var c=b.length,d=0;db&&(a=a.substring(0,b-3)+"...");c&&(a=goog.string.htmlEscape(a));return a}; -goog.string.truncateMiddle=function(a,b,c,d){c&&(a=goog.string.unescapeEntities(a));if(d&&a.length>b){d>b&&(d=b);var e=a.length-d;a=a.substring(0,b-d)+"..."+a.substring(e)}else a.length>b&&(d=Math.floor(b/2),e=a.length-d,a=a.substring(0,d+b%2)+"..."+a.substring(e));c&&(a=goog.string.htmlEscape(a));return a};goog.string.specialEscapeChars_={"\x00":"\\0","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\x0B",'"':'\\"',"\\":"\\\\","<":"<"};goog.string.jsEscapeCache_={"'":"\\'"}; -goog.string.quote=function(a){a=String(a);for(var b=['"'],c=0;ce?d:goog.string.escapeChar(d))}b.push('"');return b.join("")};goog.string.escapeString=function(a){for(var b=[],c=0;cb)var c=a;else{if(256>b){if(c="\\x",16>b||256b&&(c+="0");c+=b.toString(16).toUpperCase()}return goog.string.jsEscapeCache_[a]=c};goog.string.contains=goog.string.internal.contains;goog.string.caseInsensitiveContains=goog.string.internal.caseInsensitiveContains; -goog.string.countOf=function(a,b){return a&&b?a.split(b).length-1:0};goog.string.removeAt=function(a,b,c){var d=a;0<=b&&b>>0;return b};goog.string.uniqueStringCounter_=2147483648*Math.random()|0; -goog.string.createUniqueString=function(){return"goog_"+goog.string.uniqueStringCounter_++};goog.string.toNumber=function(a){var b=Number(a);return 0==b&&goog.string.isEmptyOrWhitespace(a)?NaN:b};goog.string.isLowerCamelCase=function(a){return/^[a-z]+([A-Z][a-z]*)*$/.test(a)};goog.string.isUpperCamelCase=function(a){return/^([A-Z][a-z]*)+$/.test(a)};goog.string.toCamelCase=function(a){return String(a).replace(/\-([a-z])/g,function(a,c){return c.toUpperCase()})}; -goog.string.toSelectorCase=function(a){return String(a).replace(/([A-Z])/g,"-$1").toLowerCase()};goog.string.toTitleCase=function(a,b){var c=goog.isString(b)?goog.string.regExpEscape(b):"\\s";return a.replace(new RegExp("(^"+(c?"|["+c+"]+":"")+")([a-z])","g"),function(a,b,c){return b+c.toUpperCase()})};goog.string.capitalize=function(a){return String(a.charAt(0)).toUpperCase()+String(a.substr(1)).toLowerCase()}; -goog.string.parseInt=function(a){isFinite(a)&&(a=String(a));return goog.isString(a)?/^\s*-?0x/i.test(a)?parseInt(a,16):parseInt(a,10):NaN};goog.string.splitLimit=function(a,b,c){a=a.split(b);for(var d=[];0c&&(c=e)}return-1==c?a:a.slice(c+1)}; -goog.string.editDistance=function(a,b){var c=[],d=[];if(a==b)return 0;if(!a.length||!b.length)return Math.max(a.length,b.length);for(var e=0;eparseFloat(a))?String(b):a}; -goog.userAgent.getVersionRegexResult_=function(){var a=goog.userAgent.getUserAgentString();if(goog.userAgent.GECKO)return/rv:([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.EDGE)return/Edge\/([\d\.]+)/.exec(a);if(goog.userAgent.IE)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.WEBKIT)return/WebKit\/(\S+)/.exec(a);if(goog.userAgent.OPERA)return/(?:Version)[ \/]?(\S+)/.exec(a)};goog.userAgent.getDocumentMode_=function(){var a=goog.global.document;return a?a.documentMode:void 0}; -goog.userAgent.VERSION=goog.userAgent.determineVersion_();goog.userAgent.compare=function(a,b){return goog.string.compareVersions(a,b)};goog.userAgent.isVersionOrHigherCache_={};goog.userAgent.isVersionOrHigher=function(a){return goog.userAgent.ASSUME_ANY_VERSION||goog.reflect.cache(goog.userAgent.isVersionOrHigherCache_,a,function(){return 0<=goog.string.compareVersions(goog.userAgent.VERSION,a)})};goog.userAgent.isVersion=goog.userAgent.isVersionOrHigher; -goog.userAgent.isDocumentModeOrHigher=function(a){return Number(goog.userAgent.DOCUMENT_MODE)>=a};goog.userAgent.isDocumentMode=goog.userAgent.isDocumentModeOrHigher;goog.userAgent.DOCUMENT_MODE=function(){var a=goog.global.document,b=goog.userAgent.getDocumentMode_();if(a&&goog.userAgent.IE)return b||("CSS1Compat"==a.compatMode?parseInt(goog.userAgent.VERSION,10):5)}();goog.debug.entryPointRegistry={};goog.debug.EntryPointMonitor=function(){};goog.debug.entryPointRegistry.refList_=[];goog.debug.entryPointRegistry.monitors_=[];goog.debug.entryPointRegistry.monitorsMayExist_=!1;goog.debug.entryPointRegistry.register=function(a){goog.debug.entryPointRegistry.refList_[goog.debug.entryPointRegistry.refList_.length]=a;if(goog.debug.entryPointRegistry.monitorsMayExist_)for(var b=goog.debug.entryPointRegistry.monitors_,c=0;c=goog.debug.MAX_STACK_DEPTH){b.push("[...long stack...]");break}}a&&d>=a?b.push("[...reached max depth limit...]"):b.push("[end]");return b.join("")}; -goog.debug.MAX_STACK_DEPTH=50;goog.debug.getNativeStackTrace_=function(a){var b=Error();if(Error.captureStackTrace)return Error.captureStackTrace(b,a),String(b.stack);try{throw b;}catch(c){b=c}return(a=b.stack)?String(a):null};goog.debug.getStacktrace=function(a){var b;goog.debug.FORCE_SLOPPY_STACKS||(b=goog.debug.getNativeStackTrace_(a||goog.debug.getStacktrace));b||(b=goog.debug.getStacktraceHelper_(a||arguments.callee.caller,[]));return b}; -goog.debug.getStacktraceHelper_=function(a,b){var c=[];if(goog.array.contains(b,a))c.push("[...circular reference...]");else if(a&&b.length=a.keyCode)a.keyCode=-1}catch(b){}};goog.events.BrowserEvent.prototype.getBrowserEvent=function(){return this.event_}; -goog.events.BrowserEvent.getPointerType_=function(a){return goog.isString(a.pointerType)?a.pointerType:goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[a.pointerType]||""};goog.events.Listenable=function(){};goog.events.Listenable.IMPLEMENTED_BY_PROP="closure_listenable_"+(1E6*Math.random()|0);goog.events.Listenable.addImplementation=function(a){a.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP]=!0};goog.events.Listenable.isImplementedBy=function(a){return!(!a||!a[goog.events.Listenable.IMPLEMENTED_BY_PROP])};goog.events.ListenableKey=function(){};goog.events.ListenableKey.counter_=0;goog.events.ListenableKey.reserveKey=function(){return++goog.events.ListenableKey.counter_};goog.events.Listener=function(a,b,c,d,e,f){goog.events.Listener.ENABLE_MONITORING&&(this.creationStack=Error().stack);this.listener=a;this.proxy=b;this.src=c;this.type=d;this.capture=!!e;this.handler=f;this.key=goog.events.ListenableKey.reserveKey();this.removed=this.callOnce=!1};goog.events.Listener.ENABLE_MONITORING=!1;goog.events.Listener.prototype.markAsRemoved=function(){this.removed=!0;this.handler=this.src=this.proxy=this.listener=null};goog.events.ListenerMap=function(a){this.src=a;this.listeners={};this.typeCount_=0};goog.events.ListenerMap.prototype.getTypeCount=function(){return this.typeCount_};goog.events.ListenerMap.prototype.getListenerCount=function(){var a=0,b;for(b in this.listeners)a+=this.listeners[b].length;return a}; -goog.events.ListenerMap.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.listeners[f];a||(a=this.listeners[f]=[],this.typeCount_++);var g=goog.events.ListenerMap.findListenerIndex_(a,b,d,e);-1a.keyCode||void 0!=a.returnValue}; -goog.events.uniqueIdCounter_=0;goog.events.getUniqueId=function(a){return a+"_"+goog.events.uniqueIdCounter_++};goog.events.getListenerMap_=function(a){a=a[goog.events.LISTENER_MAP_PROP_];return a instanceof goog.events.ListenerMap?a:null};goog.events.LISTENER_WRAPPER_PROP_="__closure_events_fn_"+(1E9*Math.random()>>>0); -goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.dom.HtmlElement=function(){};goog.dom.TagName=function(a){this.tagName_=a};goog.dom.TagName.prototype.toString=function(){return this.tagName_};goog.dom.TagName.A=new goog.dom.TagName("A");goog.dom.TagName.ABBR=new goog.dom.TagName("ABBR");goog.dom.TagName.ACRONYM=new goog.dom.TagName("ACRONYM");goog.dom.TagName.ADDRESS=new goog.dom.TagName("ADDRESS");goog.dom.TagName.APPLET=new goog.dom.TagName("APPLET");goog.dom.TagName.AREA=new goog.dom.TagName("AREA");goog.dom.TagName.ARTICLE=new goog.dom.TagName("ARTICLE"); +goog.labs.userAgent.browser.getIEVersion_=function(a){var b=/rv: *([\d\.]*)/.exec(a);if(b&&b[1])return b[1];b="";var c=/MSIE +([\d\.]+)/.exec(a);if(c&&c[1])if(a=/Trident\/(\d.\d)/.exec(a),"7.0"==c[1])if(a&&a[1])switch(a[1]){case "4.0":b="8.0";break;case "5.0":b="9.0";break;case "6.0":b="10.0";break;case "7.0":b="11.0"}else b="7.0";else b=c[1];return b};goog.dom.asserts={};goog.dom.asserts.assertIsLocation=function(a){if(goog.asserts.ENABLE_ASSERTS){var b=goog.dom.asserts.getWindow_(a);b&&(!a||!(a instanceof b.Location)&&a instanceof b.Element)&&goog.asserts.fail("Argument is not a Location (or a non-Element mock); got: %s",goog.dom.asserts.debugStringForType_(a))}return a}; +goog.dom.asserts.assertIsElementType_=function(a,b){if(goog.asserts.ENABLE_ASSERTS){var c=goog.dom.asserts.getWindow_(a);c&&"undefined"!=typeof c[b]&&(a&&(a instanceof c[b]||!(a instanceof c.Location||a instanceof c.Element))||goog.asserts.fail("Argument is not a %s (or a non-Element, non-Location mock); got: %s",b,goog.dom.asserts.debugStringForType_(a)))}return a};goog.dom.asserts.assertIsHTMLAnchorElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLAnchorElement")}; +goog.dom.asserts.assertIsHTMLButtonElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLButtonElement")};goog.dom.asserts.assertIsHTMLLinkElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLLinkElement")};goog.dom.asserts.assertIsHTMLImageElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLImageElement")};goog.dom.asserts.assertIsHTMLAudioElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLAudioElement")}; +goog.dom.asserts.assertIsHTMLVideoElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLVideoElement")};goog.dom.asserts.assertIsHTMLInputElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLInputElement")};goog.dom.asserts.assertIsHTMLTextAreaElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLTextAreaElement")};goog.dom.asserts.assertIsHTMLCanvasElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLCanvasElement")}; +goog.dom.asserts.assertIsHTMLEmbedElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLEmbedElement")};goog.dom.asserts.assertIsHTMLFormElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLFormElement")};goog.dom.asserts.assertIsHTMLFrameElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLFrameElement")};goog.dom.asserts.assertIsHTMLIFrameElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLIFrameElement")}; +goog.dom.asserts.assertIsHTMLObjectElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLObjectElement")};goog.dom.asserts.assertIsHTMLScriptElement=function(a){return goog.dom.asserts.assertIsElementType_(a,"HTMLScriptElement")}; +goog.dom.asserts.debugStringForType_=function(a){if(goog.isObject(a))try{return a.constructor.displayName||a.constructor.name||Object.prototype.toString.call(a)}catch(b){return""}else return void 0===a?"undefined":null===a?"null":typeof a};goog.dom.asserts.getWindow_=function(a){try{var b=a&&a.ownerDocument,c=b&&(b.defaultView||b.parentWindow);c=c||goog.global;if(c.Element&&c.Location)return c}catch(d){}return null};goog.functions={};goog.functions.constant=function(a){return function(){return a}};goog.functions.FALSE=function(){return!1};goog.functions.TRUE=function(){return!0};goog.functions.NULL=function(){return null};goog.functions.identity=function(a,b){return a};goog.functions.error=function(a){return function(){throw Error(a);}};goog.functions.fail=function(a){return function(){throw a;}}; +goog.functions.lock=function(a,b){b=b||0;return function(){return a.apply(this,Array.prototype.slice.call(arguments,0,b))}};goog.functions.nth=function(a){return function(){return arguments[a]}};goog.functions.partialRight=function(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var b=Array.prototype.slice.call(arguments);b.push.apply(b,c);return a.apply(this,b)}};goog.functions.withReturnValue=function(a,b){return goog.functions.sequence(a,goog.functions.constant(b))}; +goog.functions.equalTo=function(a,b){return function(c){return b?a==c:a===c}};goog.functions.compose=function(a,b){var c=arguments,d=c.length;return function(){var a;d&&(a=c[d-1].apply(this,arguments));for(var b=d-2;0<=b;b--)a=c[b].call(this,a);return a}};goog.functions.sequence=function(a){var b=arguments,c=b.length;return function(){for(var a,e=0;ea.length?"&":"")+encodeURIComponent(d)+"="+encodeURIComponent(String(g)))}}return b};goog.html.SafeUrl=function(){this.privateDoNotAccessOrElseSafeUrlWrappedValue_="";this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeUrl.INNOCUOUS_STRING="about:invalid#zClosurez";goog.html.SafeUrl.prototype.implementsGoogStringTypedString=!0;goog.html.SafeUrl.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeUrlWrappedValue_.toString()}; goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString=!0;goog.html.SafeUrl.prototype.getDirection=function(){return goog.i18n.bidi.Dir.LTR};goog.DEBUG&&(goog.html.SafeUrl.prototype.toString=function(){return"SafeUrl{"+this.privateDoNotAccessOrElseSafeUrlWrappedValue_+"}"});goog.html.SafeUrl.unwrap=function(a){return goog.html.SafeUrl.unwrapTrustedURL(a).toString()}; goog.html.SafeUrl.unwrapTrustedURL=function(a){if(a instanceof goog.html.SafeUrl&&a.constructor===goog.html.SafeUrl&&a.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseSafeUrlWrappedValue_;goog.asserts.fail("expected object of type SafeUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:SafeUrl"};goog.html.SafeUrl.fromConstant=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))}; -goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))$/i;goog.html.SafeUrl.isSafeMimeType=function(a){return goog.html.SAFE_MIME_TYPE_PATTERN_.test(a)};goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; -goog.html.DATA_URL_PATTERN_=/^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i;goog.html.SafeUrl.fromDataUrl=function(a){a=a.replace(/(%0A|%0D)/g,"");var b=a.match(goog.html.DATA_URL_PATTERN_);b=b&&goog.html.SAFE_MIME_TYPE_PATTERN_.test(b[1]);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b?a:goog.html.SafeUrl.INNOCUOUS_STRING)};goog.html.SafeUrl.fromTelUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"tel:")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; +goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))(?:;\w+=(?:\w+|"[\w;=]+"))*$/i;goog.html.SafeUrl.isSafeMimeType=function(a){return goog.html.SAFE_MIME_TYPE_PATTERN_.test(a)};goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; +goog.html.DATA_URL_PATTERN_=/^data:([^,]*);base64,[a-z0-9+\/]+=*$/i;goog.html.SafeUrl.fromDataUrl=function(a){a=a.replace(/(%0A|%0D)/g,"");var b=a.match(goog.html.DATA_URL_PATTERN_);b=b&&goog.html.SAFE_MIME_TYPE_PATTERN_.test(b[1]);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b?a:goog.html.SafeUrl.INNOCUOUS_STRING)};goog.html.SafeUrl.fromTelUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"tel:")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SIP_URL_PATTERN_=/^sip[s]?:[+a-z0-9_.!$%&'*\/=^`{|}~-]+@([a-z0-9-]+\.)+[a-z0-9]{2,63}$/i;goog.html.SafeUrl.fromSipUrl=function(a){goog.html.SIP_URL_PATTERN_.test(decodeURIComponent(a))||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.fromFacebookMessengerUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"fb-messenger://share")||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SafeUrl.fromSmsUrl=function(a){goog.string.internal.caseInsensitiveStartsWith(a,"sms:")&&goog.html.SafeUrl.isSmsUrlBodyValid_(a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.isSmsUrlBodyValid_=function(a){var b=a.indexOf("#");0=a||"\u0080"<=a&&"\ufffd">=a}; +goog.string.stripNewlines=function(a){return a.replace(/(\r\n|\r|\n)+/g," ")};goog.string.canonicalizeNewlines=function(a){return a.replace(/(\r\n|\r|\n)/g,"\n")};goog.string.normalizeWhitespace=function(a){return a.replace(/\xa0|\s/g," ")};goog.string.normalizeSpaces=function(a){return a.replace(/\xa0|[ \t]+/g," ")};goog.string.collapseBreakingSpaces=function(a){return a.replace(/[\t\r\n ]+/g," ").replace(/^[\t\r\n ]+|[\t\r\n ]+$/g,"")};goog.string.trim=goog.string.internal.trim; +goog.string.trimLeft=function(a){return a.replace(/^[\s\xa0]+/,"")};goog.string.trimRight=function(a){return a.replace(/[\s\xa0]+$/,"")};goog.string.caseInsensitiveCompare=goog.string.internal.caseInsensitiveCompare; +goog.string.numberAwareCompare_=function(a,b,c){if(a==b)return 0;if(!a)return-1;if(!b)return 1;for(var d=a.toLowerCase().match(c),e=b.toLowerCase().match(c),f=Math.min(d.length,e.length),g=0;g",""":'"'};var d=b?b.createElement("div"):goog.global.document.createElement("div");return a.replace(goog.string.HTML_ENTITY_PATTERN_,function(a,b){var e=c[a];if(e)return e;if("#"==b.charAt(0)){var f=Number("0"+b.substr(1));isNaN(f)||(e=String.fromCharCode(f))}e||(goog.dom.safe.setInnerHtml(d,goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract(goog.string.Const.from("Single HTML entity."), +a+" ")),e=d.firstChild.nodeValue.slice(0,-1));return c[a]=e})};goog.string.unescapePureXmlEntities_=function(a){return a.replace(/&([^;]+);/g,function(a,c){switch(c){case "amp":return"&";case "lt":return"<";case "gt":return">";case "quot":return'"';default:if("#"==c.charAt(0)){var b=Number("0"+c.substr(1));if(!isNaN(b))return String.fromCharCode(b)}return a}})};goog.string.HTML_ENTITY_PATTERN_=/&([^;\s<&]+);?/g; +goog.string.whitespaceEscape=function(a,b){return goog.string.newLineToBr(a.replace(/ /g,"  "),b)};goog.string.preserveSpaces=function(a){return a.replace(/(^|[\n ]) /g,"$1"+goog.string.Unicode.NBSP)};goog.string.stripQuotes=function(a,b){for(var c=b.length,d=0;db&&(a=a.substring(0,b-3)+"...");c&&(a=goog.string.htmlEscape(a));return a};goog.string.truncateMiddle=function(a,b,c,d){c&&(a=goog.string.unescapeEntities(a));if(d&&a.length>b){d>b&&(d=b);var e=a.length-d;a=a.substring(0,b-d)+"..."+a.substring(e)}else a.length>b&&(d=Math.floor(b/2),e=a.length-d,a=a.substring(0,d+b%2)+"..."+a.substring(e));c&&(a=goog.string.htmlEscape(a));return a}; +goog.string.specialEscapeChars_={"\x00":"\\0","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\x0B",'"':'\\"',"\\":"\\\\","<":"<"};goog.string.jsEscapeCache_={"'":"\\'"};goog.string.quote=function(a){a=String(a);for(var b=['"'],c=0;ce?d:goog.string.escapeChar(d))}b.push('"');return b.join("")}; +goog.string.escapeString=function(a){for(var b=[],c=0;cb)var c=a;else{if(256>b){if(c="\\x",16>b||256b&&(c+="0");c+=b.toString(16).toUpperCase()}return goog.string.jsEscapeCache_[a]=c};goog.string.contains=goog.string.internal.contains;goog.string.caseInsensitiveContains=goog.string.internal.caseInsensitiveContains; +goog.string.countOf=function(a,b){return a&&b?a.split(b).length-1:0};goog.string.removeAt=function(a,b,c){var d=a;0<=b&&b>>0;return b};goog.string.uniqueStringCounter_=2147483648*Math.random()|0; +goog.string.createUniqueString=function(){return"goog_"+goog.string.uniqueStringCounter_++};goog.string.toNumber=function(a){var b=Number(a);return 0==b&&goog.string.isEmptyOrWhitespace(a)?NaN:b};goog.string.isLowerCamelCase=function(a){return/^[a-z]+([A-Z][a-z]*)*$/.test(a)};goog.string.isUpperCamelCase=function(a){return/^([A-Z][a-z]*)+$/.test(a)};goog.string.toCamelCase=function(a){return String(a).replace(/\-([a-z])/g,function(a,c){return c.toUpperCase()})}; +goog.string.toSelectorCase=function(a){return String(a).replace(/([A-Z])/g,"-$1").toLowerCase()};goog.string.toTitleCase=function(a,b){var c=goog.isString(b)?goog.string.regExpEscape(b):"\\s";return a.replace(new RegExp("(^"+(c?"|["+c+"]+":"")+")([a-z])","g"),function(a,b,c){return b+c.toUpperCase()})};goog.string.capitalize=function(a){return String(a.charAt(0)).toUpperCase()+String(a.substr(1)).toLowerCase()}; +goog.string.parseInt=function(a){isFinite(a)&&(a=String(a));return goog.isString(a)?/^\s*-?0x/i.test(a)?parseInt(a,16):parseInt(a,10):NaN};goog.string.splitLimit=function(a,b,c){a=a.split(b);for(var d=[];0c&&(c=e)}return-1==c?a:a.slice(c+1)}; +goog.string.editDistance=function(a,b){var c=[],d=[];if(a==b)return 0;if(!a.length||!b.length)return Math.max(a.length,b.length);for(var e=0;eparseFloat(a))?String(b):a}; +goog.userAgent.getVersionRegexResult_=function(){var a=goog.userAgent.getUserAgentString();if(goog.userAgent.GECKO)return/rv:([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.EDGE)return/Edge\/([\d\.]+)/.exec(a);if(goog.userAgent.IE)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(goog.userAgent.WEBKIT)return/WebKit\/(\S+)/.exec(a);if(goog.userAgent.OPERA)return/(?:Version)[ \/]?(\S+)/.exec(a)};goog.userAgent.getDocumentMode_=function(){var a=goog.global.document;return a?a.documentMode:void 0}; +goog.userAgent.VERSION=goog.userAgent.determineVersion_();goog.userAgent.compare=function(a,b){return goog.string.compareVersions(a,b)};goog.userAgent.isVersionOrHigherCache_={};goog.userAgent.isVersionOrHigher=function(a){return goog.userAgent.ASSUME_ANY_VERSION||goog.reflect.cache(goog.userAgent.isVersionOrHigherCache_,a,function(){return 0<=goog.string.compareVersions(goog.userAgent.VERSION,a)})};goog.userAgent.isVersion=goog.userAgent.isVersionOrHigher; +goog.userAgent.isDocumentModeOrHigher=function(a){return Number(goog.userAgent.DOCUMENT_MODE)>=a};goog.userAgent.isDocumentMode=goog.userAgent.isDocumentModeOrHigher;goog.userAgent.DOCUMENT_MODE=function(){var a=goog.global.document,b=goog.userAgent.getDocumentMode_();if(a&&goog.userAgent.IE)return b||("CSS1Compat"==a.compatMode?parseInt(goog.userAgent.VERSION,10):5)}();goog.debug.LOGGING_ENABLED=goog.DEBUG;goog.debug.FORCE_SLOPPY_STACKS=!1;goog.debug.catchErrors=function(a,b,c){c=c||goog.global;var d=c.onerror,e=!!b;goog.userAgent.WEBKIT&&!goog.userAgent.isVersionOrHigher("535.3")&&(e=!e);c.onerror=function(b,c,h,k,l){d&&d(b,c,h,k,l);a({message:b,fileName:c,line:h,lineNumber:h,col:k,error:l});return e}}; +goog.debug.expose=function(a,b){if("undefined"==typeof a)return"undefined";if(null==a)return"NULL";var c=[],d;for(d in a)if(b||!goog.isFunction(a[d])){var e=d+" = ";try{e+=a[d]}catch(f){e+="*** "+f+" ***"}c.push(e)}return c.join("\n")}; +goog.debug.deepExpose=function(a,b){var c=[],d=[],e={},f=function(a,g){var h=g+" ";try{if(goog.isDef(a))if(goog.isNull(a))c.push("NULL");else if(goog.isString(a))c.push('"'+a.replace(/\n/g,"\n"+g)+'"');else if(goog.isFunction(a))c.push(String(a).replace(/\n/g,"\n"+g));else if(goog.isObject(a)){goog.hasUid(a)||d.push(a);var k=goog.getUid(a);if(e[k])c.push("*** reference loop detected (id="+k+") ***");else{e[k]=!0;c.push("{");for(var m in a)if(b||!goog.isFunction(a[m]))c.push("\n"),c.push(h),c.push(m+ +" = "),f(a[m],h);c.push("\n"+g+"}");delete e[k]}}else c.push(a);else c.push("undefined")}catch(p){c.push("*** "+p+" ***")}};f(a,"");for(var g=0;g=goog.debug.MAX_STACK_DEPTH){b.push("[...long stack...]");break}}a&&d>=a?b.push("[...reached max depth limit...]"):b.push("[end]");return b.join("")}; +goog.debug.MAX_STACK_DEPTH=50;goog.debug.getNativeStackTrace_=function(a){var b=Error();if(Error.captureStackTrace)return Error.captureStackTrace(b,a),String(b.stack);try{throw b;}catch(c){b=c}return(a=b.stack)?String(a):null};goog.debug.getStacktrace=function(a){var b;goog.debug.FORCE_SLOPPY_STACKS||(b=goog.debug.getNativeStackTrace_(a||goog.debug.getStacktrace));b||(b=goog.debug.getStacktraceHelper_(a||arguments.callee.caller,[]));return b}; +goog.debug.getStacktraceHelper_=function(a,b){var c=[];if(goog.array.contains(b,a))c.push("[...circular reference...]");else if(a&&b.length=a.keyCode)a.keyCode=-1}catch(b){}};goog.events.BrowserEvent.prototype.getBrowserEvent=function(){return this.event_}; +goog.events.BrowserEvent.getPointerType_=function(a){return goog.isString(a.pointerType)?a.pointerType:goog.events.BrowserEvent.IE_POINTER_TYPE_MAP[a.pointerType]||""};goog.events.Listenable=function(){};goog.events.Listenable.IMPLEMENTED_BY_PROP="closure_listenable_"+(1E6*Math.random()|0);goog.events.Listenable.addImplementation=function(a){a.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP]=!0};goog.events.Listenable.isImplementedBy=function(a){return!(!a||!a[goog.events.Listenable.IMPLEMENTED_BY_PROP])};goog.events.ListenableKey=function(){};goog.events.ListenableKey.counter_=0;goog.events.ListenableKey.reserveKey=function(){return++goog.events.ListenableKey.counter_};goog.events.Listener=function(a,b,c,d,e,f){goog.events.Listener.ENABLE_MONITORING&&(this.creationStack=Error().stack);this.listener=a;this.proxy=b;this.src=c;this.type=d;this.capture=!!e;this.handler=f;this.key=goog.events.ListenableKey.reserveKey();this.removed=this.callOnce=!1};goog.events.Listener.ENABLE_MONITORING=!1;goog.events.Listener.prototype.markAsRemoved=function(){this.removed=!0;this.handler=this.src=this.proxy=this.listener=null};goog.events.ListenerMap=function(a){this.src=a;this.listeners={};this.typeCount_=0};goog.events.ListenerMap.prototype.getTypeCount=function(){return this.typeCount_};goog.events.ListenerMap.prototype.getListenerCount=function(){var a=0,b;for(b in this.listeners)a+=this.listeners[b].length;return a}; +goog.events.ListenerMap.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.listeners[f];a||(a=this.listeners[f]=[],this.typeCount_++);var g=goog.events.ListenerMap.findListenerIndex_(a,b,d,e);-1a.keyCode||void 0!=a.returnValue}; +goog.events.uniqueIdCounter_=0;goog.events.getUniqueId=function(a){return a+"_"+goog.events.uniqueIdCounter_++};goog.events.getListenerMap_=function(a){a=a[goog.events.LISTENER_MAP_PROP_];return a instanceof goog.events.ListenerMap?a:null};goog.events.LISTENER_WRAPPER_PROP_="__closure_events_fn_"+(1E9*Math.random()>>>0); +goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.dom.BrowserFeature={CAN_ADD_NAME_OR_TYPE_ATTRIBUTES:!goog.userAgent.IE||goog.userAgent.isDocumentModeOrHigher(9),CAN_USE_CHILDREN_ATTRIBUTE:!goog.userAgent.GECKO&&!goog.userAgent.IE||goog.userAgent.IE&&goog.userAgent.isDocumentModeOrHigher(9)||goog.userAgent.GECKO&&goog.userAgent.isVersionOrHigher("1.9.1"),CAN_USE_INNER_TEXT:goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("9"),CAN_USE_PARENT_ELEMENT_PROPERTY:goog.userAgent.IE||goog.userAgent.OPERA||goog.userAgent.WEBKIT,INNER_HTML_NEEDS_SCOPED_ELEMENT:goog.userAgent.IE, +LEGACY_IE_RANGES:goog.userAgent.IE&&!goog.userAgent.isDocumentModeOrHigher(9)};goog.math.Size=function(a,b){this.width=a;this.height=b};goog.math.Size.equals=function(a,b){return a==b?!0:a&&b?a.width==b.width&&a.height==b.height:!1};goog.math.Size.prototype.clone=function(){return new goog.math.Size(this.width,this.height)};goog.DEBUG&&(goog.math.Size.prototype.toString=function(){return"("+this.width+" x "+this.height+")"});goog.math.Size.prototype.getLongest=function(){return Math.max(this.width,this.height)}; goog.math.Size.prototype.getShortest=function(){return Math.min(this.width,this.height)};goog.math.Size.prototype.area=function(){return this.width*this.height};goog.math.Size.prototype.perimeter=function(){return 2*(this.width+this.height)};goog.math.Size.prototype.aspectRatio=function(){return this.width/this.height};goog.math.Size.prototype.isEmpty=function(){return!this.area()};goog.math.Size.prototype.ceil=function(){this.width=Math.ceil(this.width);this.height=Math.ceil(this.height);return this}; goog.math.Size.prototype.fitsInside=function(a){return this.width<=a.width&&this.height<=a.height};goog.math.Size.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};goog.math.Size.prototype.round=function(){this.width=Math.round(this.width);this.height=Math.round(this.height);return this};goog.math.Size.prototype.scale=function(a,b){var c=goog.isNumber(b)?b:a;this.width*=a;this.height*=c;return this}; goog.math.Size.prototype.scaleToCover=function(a){a=this.aspectRatio()<=a.aspectRatio()?a.width/this.width:a.height/this.height;return this.scale(a)};goog.math.Size.prototype.scaleToFit=function(a){a=this.aspectRatio()>a.aspectRatio()?a.width/this.width:a.height/this.height;return this.scale(a)};goog.dom.ASSUME_QUIRKS_MODE=!1;goog.dom.ASSUME_STANDARDS_MODE=!1;goog.dom.COMPAT_MODE_KNOWN_=goog.dom.ASSUME_QUIRKS_MODE||goog.dom.ASSUME_STANDARDS_MODE;goog.dom.getDomHelper=function(a){return a?new goog.dom.DomHelper(goog.dom.getOwnerDocument(a)):goog.dom.defaultDomHelper_||(goog.dom.defaultDomHelper_=new goog.dom.DomHelper)};goog.dom.getDocument=function(){return document};goog.dom.getElement=function(a){return goog.dom.getElementHelper_(document,a)}; @@ -749,38 +750,14 @@ goog.ui.Menu.prototype.setAllowHighlightDisabled=function(a){this.allowHighlight goog.ui.Menu.prototype.handleEnterItem=function(a){this.allowAutoFocus_&&this.getKeyEventTarget().focus();return goog.ui.Menu.superClass_.handleEnterItem.call(this,a)};goog.ui.Menu.prototype.highlightNextPrefix=function(a){var b=new RegExp("^"+goog.string.regExpEscape(a),"i");return this.highlightHelper(function(a,d){var c=0>a?0:a,f=!1;do{++a;a==d&&(a=0,f=!0);var g=this.getChildAt(a).getCaption();if(g&&g.match(b))return a}while(!f||a!=c);return this.getHighlightedIndex()},this.getHighlightedIndex())}; goog.ui.Menu.prototype.canHighlightItem=function(a){return(this.allowHighlightDisabled_||a.isEnabled())&&a.isVisible()&&a.isSupportedState(goog.ui.Component.State.HOVER)};goog.ui.Menu.prototype.decorateInternal=function(a){this.decorateContent(a);goog.ui.Menu.superClass_.decorateInternal.call(this,a)}; goog.ui.Menu.prototype.handleKeyEventInternal=function(a){var b=goog.ui.Menu.superClass_.handleKeyEventInternal.call(this,a);b||this.forEachChild(function(c){!b&&c.getMnemonic&&c.getMnemonic()==a.keyCode&&(this.isEnabled()&&this.setHighlighted(c),b=c.handleKeyEvent(a))},this);return b};goog.ui.Menu.prototype.setHighlightedIndex=function(a){goog.ui.Menu.superClass_.setHighlightedIndex.call(this,a);(a=this.getChildAt(a))&&goog.style.scrollIntoContainerView(a.getElement(),this.getElement())}; -goog.ui.Menu.prototype.decorateContent=function(a){var b=this.getRenderer();a=this.getDomHelper().getElementsByTagNameAndClass("DIV",b.getCssClass()+"-content",a);for(var c=a.length,d=0;d=this.getEffectiveLevel().value}; -goog.debug.Logger.prototype.log=function(a,b,c){goog.debug.LOGGING_ENABLED&&this.isLoggable(a)&&(goog.isFunction(b)&&(b=b()),this.doLogRecord_(this.getLogRecord(a,b,c)))};goog.debug.Logger.prototype.getLogRecord=function(a,b,c){a=goog.debug.LogBuffer.isBufferingEnabled()?goog.debug.LogBuffer.getInstance().addRecord(a,b,this.name_):new goog.debug.LogRecord(a,String(b),this.name_);c&&a.setException(c);return a}; -goog.debug.Logger.prototype.shout=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SHOUT,a,b)};goog.debug.Logger.prototype.severe=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SEVERE,a,b)};goog.debug.Logger.prototype.warning=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.WARNING,a,b)};goog.debug.Logger.prototype.info=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.INFO,a,b)}; -goog.debug.Logger.prototype.config=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.CONFIG,a,b)};goog.debug.Logger.prototype.fine=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINE,a,b)};goog.debug.Logger.prototype.finer=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINER,a,b)};goog.debug.Logger.prototype.finest=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINEST,a,b)}; -goog.debug.Logger.prototype.logRecord=function(a){goog.debug.LOGGING_ENABLED&&this.isLoggable(a.getLevel())&&this.doLogRecord_(a)};goog.debug.Logger.prototype.doLogRecord_=function(a){goog.debug.Logger.ENABLE_PROFILER_LOGGING&&goog.debug.Logger.logToProfilers("log:"+a.getMessage());if(goog.debug.Logger.ENABLE_HIERARCHY)for(var b=this;b;)b.callPublish_(a),b=b.getParent();else{b=0;for(var c;c=goog.debug.Logger.rootHandlers_[b++];)c(a)}}; -goog.debug.Logger.prototype.callPublish_=function(a){if(this.handlers_)for(var b=0,c;c=this.handlers_[b];b++)c(a)};goog.debug.Logger.prototype.setParent_=function(a){this.parent_=a};goog.debug.Logger.prototype.addChild_=function(a,b){this.getChildren()[a]=b};goog.debug.LogManager={};goog.debug.LogManager.loggers_={};goog.debug.LogManager.rootLogger_=null; -goog.debug.LogManager.initialize=function(){goog.debug.LogManager.rootLogger_||(goog.debug.LogManager.rootLogger_=new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME),goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME]=goog.debug.LogManager.rootLogger_,goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))};goog.debug.LogManager.getLoggers=function(){return goog.debug.LogManager.loggers_}; -goog.debug.LogManager.getRoot=function(){goog.debug.LogManager.initialize();return goog.debug.LogManager.rootLogger_};goog.debug.LogManager.getLogger=function(a){goog.debug.LogManager.initialize();return goog.debug.LogManager.loggers_[a]||goog.debug.LogManager.createLogger_(a)};goog.debug.LogManager.createFunctionForCatchErrors=function(a){return function(b){(a||goog.debug.LogManager.getRoot()).severe("Error: "+b.message+" ("+b.fileName+" @ Line: "+b.line+")")}}; -goog.debug.LogManager.createLogger_=function(a){var b=new goog.debug.Logger(a);if(goog.debug.Logger.ENABLE_HIERARCHY){var c=a.lastIndexOf("."),d=a.substr(0,c);c=a.substr(c+1);d=goog.debug.LogManager.getLogger(d);d.addChild_(c,b);b.setParent_(d)}return goog.debug.LogManager.loggers_[a]=b};goog.log={};goog.log.ENABLED=goog.debug.LOGGING_ENABLED;goog.log.ROOT_LOGGER_NAME=goog.debug.Logger.ROOT_LOGGER_NAME;goog.log.Logger=goog.debug.Logger;goog.log.Level=goog.debug.Logger.Level;goog.log.LogRecord=goog.debug.LogRecord;goog.log.getLogger=function(a,b){if(goog.log.ENABLED){var c=goog.debug.LogManager.getLogger(a);b&&c&&c.setLevel(b);return c}return null};goog.log.addHandler=function(a,b){goog.log.ENABLED&&a&&a.addHandler(b)}; -goog.log.removeHandler=function(a,b){return goog.log.ENABLED&&a?a.removeHandler(b):!1};goog.log.log=function(a,b,c,d){goog.log.ENABLED&&a&&a.log(b,c,d)};goog.log.error=function(a,b,c){goog.log.ENABLED&&a&&a.severe(b,c)};goog.log.warning=function(a,b,c){goog.log.ENABLED&&a&&a.warning(b,c)};goog.log.info=function(a,b,c){goog.log.ENABLED&&a&&a.info(b,c)};goog.log.fine=function(a,b,c){goog.log.ENABLED&&a&&a.fine(b,c)};goog.Thenable=function(){};goog.Thenable.prototype.then=function(a,b,c){};goog.Thenable.IMPLEMENTED_BY_PROP="$goog_Thenable";goog.Thenable.addImplementation=function(a){COMPILED?a.prototype[goog.Thenable.IMPLEMENTED_BY_PROP]=!0:a.prototype.$goog_Thenable=!0};goog.Thenable.isImplementedBy=function(a){if(!a)return!1;try{return COMPILED?!!a[goog.Thenable.IMPLEMENTED_BY_PROP]:!!a.$goog_Thenable}catch(b){return!1}};goog.async={};goog.async.FreeList=function(a,b,c){this.limit_=c;this.create_=a;this.reset_=b;this.occupants_=0;this.head_=null};goog.async.FreeList.prototype.get=function(){if(0=this.getEffectiveLevel().value}; +goog.debug.Logger.prototype.log=function(a,b,c){goog.debug.LOGGING_ENABLED&&this.isLoggable(a)&&(goog.isFunction(b)&&(b=b()),this.doLogRecord_(this.getLogRecord(a,b,c)))};goog.debug.Logger.prototype.getLogRecord=function(a,b,c){a=goog.debug.LogBuffer.isBufferingEnabled()?goog.debug.LogBuffer.getInstance().addRecord(a,b,this.name_):new goog.debug.LogRecord(a,String(b),this.name_);c&&a.setException(c);return a}; +goog.debug.Logger.prototype.shout=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SHOUT,a,b)};goog.debug.Logger.prototype.severe=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.SEVERE,a,b)};goog.debug.Logger.prototype.warning=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.WARNING,a,b)};goog.debug.Logger.prototype.info=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.INFO,a,b)}; +goog.debug.Logger.prototype.config=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.CONFIG,a,b)};goog.debug.Logger.prototype.fine=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINE,a,b)};goog.debug.Logger.prototype.finer=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINER,a,b)};goog.debug.Logger.prototype.finest=function(a,b){goog.debug.LOGGING_ENABLED&&this.log(goog.debug.Logger.Level.FINEST,a,b)}; +goog.debug.Logger.prototype.logRecord=function(a){goog.debug.LOGGING_ENABLED&&this.isLoggable(a.getLevel())&&this.doLogRecord_(a)};goog.debug.Logger.prototype.doLogRecord_=function(a){goog.debug.Logger.ENABLE_PROFILER_LOGGING&&goog.debug.Logger.logToProfilers("log:"+a.getMessage());if(goog.debug.Logger.ENABLE_HIERARCHY)for(var b=this;b;)b.callPublish_(a),b=b.getParent();else{b=0;for(var c;c=goog.debug.Logger.rootHandlers_[b++];)c(a)}}; +goog.debug.Logger.prototype.callPublish_=function(a){if(this.handlers_)for(var b=0,c;c=this.handlers_[b];b++)c(a)};goog.debug.Logger.prototype.setParent_=function(a){this.parent_=a};goog.debug.Logger.prototype.addChild_=function(a,b){this.getChildren()[a]=b};goog.debug.LogManager={};goog.debug.LogManager.loggers_={};goog.debug.LogManager.rootLogger_=null; +goog.debug.LogManager.initialize=function(){goog.debug.LogManager.rootLogger_||(goog.debug.LogManager.rootLogger_=new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME),goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME]=goog.debug.LogManager.rootLogger_,goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))};goog.debug.LogManager.getLoggers=function(){return goog.debug.LogManager.loggers_}; +goog.debug.LogManager.getRoot=function(){goog.debug.LogManager.initialize();return goog.debug.LogManager.rootLogger_};goog.debug.LogManager.getLogger=function(a){goog.debug.LogManager.initialize();return goog.debug.LogManager.loggers_[a]||goog.debug.LogManager.createLogger_(a)};goog.debug.LogManager.createFunctionForCatchErrors=function(a){return function(b){(a||goog.debug.LogManager.getRoot()).severe("Error: "+b.message+" ("+b.fileName+" @ Line: "+b.line+")")}}; +goog.debug.LogManager.createLogger_=function(a){var b=new goog.debug.Logger(a);if(goog.debug.Logger.ENABLE_HIERARCHY){var c=a.lastIndexOf("."),d=a.substr(0,c);c=a.substr(c+1);d=goog.debug.LogManager.getLogger(d);d.addChild_(c,b);b.setParent_(d)}return goog.debug.LogManager.loggers_[a]=b};goog.log={};goog.log.ENABLED=goog.debug.LOGGING_ENABLED;goog.log.ROOT_LOGGER_NAME=goog.debug.Logger.ROOT_LOGGER_NAME;goog.log.Logger=goog.debug.Logger;goog.log.Level=goog.debug.Logger.Level;goog.log.LogRecord=goog.debug.LogRecord;goog.log.getLogger=function(a,b){if(goog.log.ENABLED){var c=goog.debug.LogManager.getLogger(a);b&&c&&c.setLevel(b);return c}return null};goog.log.addHandler=function(a,b){goog.log.ENABLED&&a&&a.addHandler(b)}; +goog.log.removeHandler=function(a,b){return goog.log.ENABLED&&a?a.removeHandler(b):!1};goog.log.log=function(a,b,c,d){goog.log.ENABLED&&a&&a.log(b,c,d)};goog.log.error=function(a,b,c){goog.log.ENABLED&&a&&a.severe(b,c)};goog.log.warning=function(a,b,c){goog.log.ENABLED&&a&&a.warning(b,c)};goog.log.info=function(a,b,c){goog.log.ENABLED&&a&&a.info(b,c)};goog.log.fine=function(a,b,c){goog.log.ENABLED&&a&&a.fine(b,c)};goog.ui.tree.TreeNode=function(a,b,c){goog.ui.tree.BaseNode.call(this,a,b,c)};goog.inherits(goog.ui.tree.TreeNode,goog.ui.tree.BaseNode);goog.ui.tree.TreeNode.prototype.getTree=function(){if(this.tree)return this.tree;var a=this.getParent();return a&&(a=a.getTree())?(this.setTreeInternal(a),a):null}; goog.ui.tree.TreeNode.prototype.getCalculatedIconClass=function(){var a=this.getExpanded(),b=this.getExpandedIconClass();if(a&&b)return b;b=this.getIconClass();if(!a&&b)return b;b=this.getConfig();if(this.hasChildren()){if(a&&b.cssExpandedFolderIcon)return b.cssTreeIcon+" "+b.cssExpandedFolderIcon;if(!a&&b.cssCollapsedFolderIcon)return b.cssTreeIcon+" "+b.cssCollapsedFolderIcon}else if(b.cssFileIcon)return b.cssTreeIcon+" "+b.cssFileIcon;return""};goog.structs={};goog.structs.getCount=function(a){return a.getCount&&"function"==typeof a.getCount?a.getCount():goog.isArrayLike(a)||goog.isString(a)?a.length:goog.object.getCount(a)};goog.structs.getValues=function(a){if(a.getValues&&"function"==typeof a.getValues)return a.getValues();if(goog.isString(a))return a.split("");if(goog.isArrayLike(a)){for(var b=[],c=a.length,d=0;db&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;var h=[],k=c.length/e,l=1;for(d=0;df);return g}; Blockly.utils.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.utils.wrapMutate_(a,e,c):b};Blockly.utils.wrapToText_=function(a,b){for(var c=[],d=0;d"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=Blockly.Xml.utils.textToDomDocument(a);if(!a||!a.documentElement||"xml"!=a.documentElement.nodeName.toLowerCase())throw TypeError("Blockly.Xml.textToDom expected an document.");return a.documentElement};Blockly.Xml.clearWorkspaceAndLoadFromXml=function(a,b){b.setResizesEnabled(!1);b.clear();var c=Blockly.Xml.domToWorkspace(a,b);b.setResizesEnabled(!0);return c}; Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());c=[];Blockly.Field.startCache();var e=a.childNodes.length,f=Blockly.Events.getGroup();f||Blockly.Events.setGroup(!0);b.setResizesEnabled&&b.setResizesEnabled(!1);var g=!0;try{for(var h=0;hBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,Blockly.Tooltip.showPid_= setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));Blockly.Tooltip.showPid_&&clearTimeout(Blockly.Tooltip.showPid_)};Blockly.Tooltip.block=function(){Blockly.Tooltip.hide();Blockly.Tooltip.blocked_=!0};Blockly.Tooltip.unblock=function(){Blockly.Tooltip.blocked_=!1}; -Blockly.Tooltip.show_=function(){if(!Blockly.Tooltip.blocked_&&(Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_,Blockly.Tooltip.DIV)){Blockly.Tooltip.DIV.innerHTML="";for(var a=Blockly.Tooltip.element_.tooltip;"function"==typeof a;)a=a();a=Blockly.utils.wrap(a,Blockly.Tooltip.LIMIT);a=a.split("\n");for(var b=0;bb.height+window.scrollY&&(d-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?c=Math.max(Blockly.Tooltip.MARGINS-window.scrollX,c):c+Blockly.Tooltip.DIV.offsetWidth> -b.width+window.scrollX-2*Blockly.Tooltip.MARGINS&&(c=b.width-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=d+"px";Blockly.Tooltip.DIV.style.left=c+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; +Blockly.Tooltip.show_=function(){if(!Blockly.Tooltip.blocked_&&(Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_,Blockly.Tooltip.DIV)){Blockly.Tooltip.DIV.innerHTML="";for(var a=Blockly.Tooltip.element_.tooltip;"function"==typeof a;)a=a();a=Blockly.utils.wrap(a,Blockly.Tooltip.LIMIT);a=a.split("\n");for(var b=0;bc+window.scrollY&&(e-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?d=Math.max(Blockly.Tooltip.MARGINS-window.scrollX, +d):d+Blockly.Tooltip.DIV.offsetWidth>b+window.scrollX-2*Blockly.Tooltip.MARGINS&&(d=b-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=e+"px";Blockly.Tooltip.DIV.style.left=d+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; this.healStack_=!Blockly.DRAG_STACK}; Blockly.Gesture.prototype.dispose=function(){Blockly.Touch.clearTouchIdentifier();Blockly.Tooltip.unblock();this.creatorWorkspace_.clearGesture();this.onMoveWrapper_&&Blockly.unbindEvent_(this.onMoveWrapper_);this.onUpWrapper_&&Blockly.unbindEvent_(this.onUpWrapper_);this.flyout_=this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=null;this.blockDragger_&&(this.blockDragger_.dispose(),this.blockDragger_=null);this.workspaceDragger_&&(this.workspaceDragger_.dispose(),this.workspaceDragger_= null);this.bubbleDragger_&&(this.bubbleDragger_.dispose(),this.bubbleDragger_=null)};Blockly.Gesture.prototype.updateFromEvent_=function(a){var b=new goog.math.Coordinate(a.clientX,a.clientY);this.updateDragDelta_(b)&&(this.updateIsDragging_(),Blockly.longStop_());this.mostRecentEvent_=a}; @@ -1201,14 +1202,14 @@ Blockly.Gesture.prototype.handleRightClick=function(a){this.targetBlock_?(this.b Blockly.Gesture.prototype.handleWsStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleWsStart, but the gesture had already been started.");this.setStartWorkspace_(b);this.mostRecentEvent_=a;this.doStart(a)};Blockly.Gesture.prototype.handleFlyoutStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleFlyoutStart, but the gesture had already been started.");this.setStartFlyout_(b);this.handleWsStart(a,b.getWorkspace())}; Blockly.Gesture.prototype.handleBlockStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleBlockStart, but the gesture had already been started.");this.setStartBlock(b);this.mostRecentEvent_=a};Blockly.Gesture.prototype.handleBubbleStart=function(a,b){if(this.hasStarted_)throw Error("Tried to call gesture.handleBubbleStart, but the gesture had already been started.");this.setStartBubble(b);this.mostRecentEvent_=a}; Blockly.Gesture.prototype.doBubbleClick_=function(){this.startBubble_.setFocus&&this.startBubble_.setFocus();this.startBubble_.select&&this.startBubble_.select()};Blockly.Gesture.prototype.doFieldClick_=function(){this.startField_.showEditor_();this.bringBlockToFront_()}; -Blockly.Gesture.prototype.doBlockClick_=function(){this.flyout_&&this.flyout_.autoClose?this.targetBlock_.disabled||(Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.flyout_.createBlock(this.targetBlock_).scheduleSnapAndBump()):Blockly.Events.fire(new Blockly.Events.Ui(this.startBlock_,"click",void 0,void 0));this.bringBlockToFront_();Blockly.Events.setGroup(!1)};Blockly.Gesture.prototype.doWorkspaceClick_=function(){Blockly.selected&&Blockly.selected.unselect()}; +Blockly.Gesture.prototype.doBlockClick_=function(){this.flyout_&&this.flyout_.autoClose?this.targetBlock_.isEnabled()&&(Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.flyout_.createBlock(this.targetBlock_).scheduleSnapAndBump()):Blockly.Events.fire(new Blockly.Events.Ui(this.startBlock_,"click",void 0,void 0));this.bringBlockToFront_();Blockly.Events.setGroup(!1)};Blockly.Gesture.prototype.doWorkspaceClick_=function(){Blockly.selected&&Blockly.selected.unselect()}; Blockly.Gesture.prototype.bringBlockToFront_=function(){this.targetBlock_&&!this.flyout_&&this.targetBlock_.bringToFront()};Blockly.Gesture.prototype.setStartField=function(a){if(this.hasStarted_)throw Error("Tried to call gesture.setStartField, but the gesture had already been started.");this.startField_||(this.startField_=a)};Blockly.Gesture.prototype.setStartBubble=function(a){this.startBubble_||(this.startBubble_=a)}; Blockly.Gesture.prototype.setStartBlock=function(a){this.startBlock_||this.startBubble_||(this.startBlock_=a,a.isInFlyout&&a!=a.getRootBlock()?this.setTargetBlock_(a.getRootBlock()):this.setTargetBlock_(a))};Blockly.Gesture.prototype.setTargetBlock_=function(a){a.isShadow()?this.setTargetBlock_(a.getParent()):this.targetBlock_=a};Blockly.Gesture.prototype.setStartWorkspace_=function(a){this.startWorkspace_||(this.startWorkspace_=a)}; Blockly.Gesture.prototype.setStartFlyout_=function(a){this.flyout_||(this.flyout_=a)};Blockly.Gesture.prototype.isBubbleClick_=function(){return!!this.startBubble_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isBlockClick_=function(){return!!this.startBlock_&&!this.hasExceededDragRadius_&&!this.isFieldClick_()};Blockly.Gesture.prototype.isFieldClick_=function(){return(this.startField_?this.startField_.isCurrentlyEditable():!1)&&!this.hasExceededDragRadius_&&(!this.flyout_||!this.flyout_.autoClose)}; Blockly.Gesture.prototype.isWorkspaceClick_=function(){return!this.startBlock_&&!this.startBubble_&&!this.startField_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isDragging=function(){return this.isDraggingWorkspace_||this.isDraggingBlock_||this.isDraggingBubble_};Blockly.Gesture.prototype.hasStarted=function(){return this.hasStarted_};Blockly.Gesture.prototype.getInsertionMarkers=function(){return this.blockDragger_?this.blockDragger_.getInsertionMarkers():[]}; Blockly.Gesture.inProgress=function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)if(c.currentGesture_)return!0;return!1};Blockly.Grid=function(a,b){this.gridPattern_=a;this.spacing_=b.spacing;this.length_=b.length;this.line2_=(this.line1_=a.firstChild)&&this.line1_.nextSibling;this.snapToGrid_=b.snap};Blockly.Grid.prototype.scale_=1;Blockly.Grid.prototype.dispose=function(){this.gridPattern_=null};Blockly.Grid.prototype.shouldSnap=function(){return this.snapToGrid_};Blockly.Grid.prototype.getSpacing=function(){return this.spacing_};Blockly.Grid.prototype.getPatternId=function(){return this.gridPattern_.id}; Blockly.Grid.prototype.update=function(a){this.scale_=a;var b=this.spacing_*a||100;this.gridPattern_.setAttribute("width",b);this.gridPattern_.setAttribute("height",b);b=Math.floor(this.spacing_/2)+.5;var c=b-this.length_/2,d=b+this.length_/2;b*=a;c*=a;d*=a;this.setLineAttributes_(this.line1_,a,c,d,b,b);this.setLineAttributes_(this.line2_,a,b,b,c,d)}; -Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(goog.userAgent.IE||goog.userAgent.EDGE)&&this.update(this.scale_)}; +Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(Blockly.userAgent.IE||Blockly.userAgent.EDGE)&&this.update(this.scale_)}; Blockly.Grid.createDom=function(a,b,c){a=Blockly.utils.createSvgElement("pattern",{id:"blocklyGridPattern"+a,patternUnits:"userSpaceOnUse"},c);0'+goog.string.htmlEscape(a.name)+""}; +Blockly.Variables.nameUsedWithAnyType_=function(a,b){var c=b.getVariableMap().getAllVariables();a=a.toLowerCase();for(var d=0,e;e=c[d];d++)if(e.name.toLowerCase()==a)return e;return null};Blockly.Variables.generateVariableFieldXmlString=function(a){var b=a.type;return''+goog.string.htmlEscape(a.name)+""}; Blockly.Variables.generateVariableFieldDom=function(a){a=Blockly.Variables.generateVariableFieldXmlString(a);return Blockly.Xml.textToDom(""+a+"").firstChild};Blockly.Variables.getOrCreateVariablePackage=function(a,b,c,d){var e=Blockly.Variables.getVariable(a,b,c,d);e||(e=Blockly.Variables.createVariable_(a,b,c,d));return e}; Blockly.Variables.getVariable=function(a,b,c,d){var e=a.getPotentialVariableMap();if(b){var f=a.getVariableById(b);!f&&e&&(f=e.getVariableById(b));if(f)return f}if(c){if(void 0==d)throw Error("Tried to look up a variable by name without a type");f=a.getVariable(c,d);!f&&e&&(f=e.getVariable(c,d))}return f}; Blockly.Variables.createVariable_=function(a,b,c,d){var e=a.getPotentialVariableMap();c||(c=Blockly.Variables.generateUniqueName(a.isFlyout?a.targetWorkspace:a));return e?e.createVariable(c,d,b):a.createVariable(c,d,b)};Blockly.Variables.getAddedVariables=function(a,b){var c=a.getAllVariables(),d=[];if(b.length!=c.length)for(var e=0;e";c=Blockly.Xml.textToDom(c).firstChild;b.push(c)}if(Blockly.Blocks.variables_get_dynamic){a.sort(Blockly.VariableModel.compareByName);for(var d=0;c=a[d];d++)c=''+Blockly.Variables.generateVariableFieldXmlString(c)+ -"",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null};Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new window.Audio}catch(h){return}for(var d,e=0;e",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null}; +Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new Blockly.utils.global.Audio}catch(h){return}for(var d,e=0;ethis.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()}; Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.callValidator(a);null!==b&&(a=b);b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){}; Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.init=function(){this.textElement_||(this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},null),this.class_&&Blockly.utils.addClass(this.textElement_,this.class_),this.visible_||(this.textElement_.style.display="none"),this.sourceBlock_.getSvgRoot().appendChild(this.textElement_),this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_,Blockly.Tooltip.bindMouseEvents(this.textElement_))}; -Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.getSvgRoot=function(){return this.textElement_};Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; +Blockly.FieldLabel.prototype.initView=function(){this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},this.fieldGroup_);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_);this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_;Blockly.Tooltip.bindMouseEvents(this.textElement_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)}; +Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; Blockly.Input.prototype.setVisible=function(a){var b=[];if(this.visible_==a)return b;for(var c=(this.visible_=a)?"block":"none",d=0,e;e=this.fieldRow[d];d++)e.setVisible(a);this.connection&&(a?b=this.connection.unhideAll():this.connection.hideAll(),d=this.connection.targetBlock())&&(d.getSvgRoot().style.display=c,a||(d.rendered=!1));return b};Blockly.Input.prototype.setCheck=function(a){if(!this.connection)throw Error("This input does not have a connection.");this.connection.setCheck(a);return this}; @@ -1456,7 +1458,8 @@ Blockly.Block.prototype.setMovable=function(a){this.movable_=a};Blockly.Block.pr Blockly.Block.prototype.setInsertionMarker=function(a){this.isInsertionMarker_=a};Blockly.Block.prototype.isEditable=function(){return this.editable_&&!(this.workspace&&this.workspace.options.readOnly)};Blockly.Block.prototype.setEditable=function(a){this.editable_=a;a=0;for(var b;b=this.inputList[a];a++)for(var c=0,d;d=b.fieldRow[c];c++)d.updateEditable()}; Blockly.Block.prototype.setConnectionsHidden=function(a){if(!a&&this.isCollapsed()){if(this.outputConnection&&this.outputConnection.setHidden(a),this.previousConnection&&this.previousConnection.setHidden(a),this.nextConnection){this.nextConnection.setHidden(a);var b=this.nextConnection.targetBlock();b&&b.setConnectionsHidden(a)}}else for(var c=this.getConnections_(!0),d=0;b=c[d];d++)b.setHidden(a),b.isSuperior()&&(b=b.targetBlock())&&b.setConnectionsHidden(a)}; Blockly.Block.prototype.getMatchingConnection=function(a,b){var c=this.getConnections_(!0),d=a.getConnections_(!0);if(c.length!=d.length)throw Error("Connection lists did not match in length.");for(var e=0;e=c)this.hue_=c,this.colour_=Blockly.hueToRgb(c);else if("string"==typeof b&&/^#[0-9a-fA-F]{6}$/.test(b))this.colour_=b,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; Blockly.Block.prototype.setStyle=function(a){var b=Blockly.getTheme();if(!b)throw Error("Trying to set block style to "+a+" before theme was defined via Blockly.setTheme().");b=b.getBlockStyle(a);this.styleName_=a;if(b)this.colourSecondary_=b.colourSecondary,this.colourTertiary_=b.colourTertiary,this.hat=b.hat,this.setColour(b.colourPrimary);else throw Error("Invalid style name: "+a);}; Blockly.Block.prototype.setOnChange=function(a){if(a&&"function"!=typeof a)throw Error("onchange must be a function.");this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);if(this.onchange=a)this.onchangeWrapper_=a.bind(this),this.workspace.addChangeListener(this.onchangeWrapper_)};Blockly.Block.prototype.getField=function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(e.name===a)return e;return null}; @@ -1497,10 +1500,10 @@ Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBo Blockly.ContextMenu.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);var b=a.getElement();Blockly.utils.addClass(b,"blocklyContextMenu");Blockly.bindEventWithChecks_(b,"contextmenu",null,Blockly.utils.noEvent);a.setAllowAutoFocus(!0)};Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_&&Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_)}; Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(c));c.select()}}; Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; -Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!goog.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; +Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; -Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!goog.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/a.scale); -c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= +Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/ +a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= Blockly.utils.is3dSupported()&&!!a.blockDragSurface_;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,a,b,c);this.svgGroup_.dataset&&(this.svgGroup_.dataset.id=this.id)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.prototype.warningTextDb_=null;Blockly.BlockSvg.INLINE=-1;Blockly.BlockSvg.COLLAPSED_WARNING_ID="TEMP_COLLAPSED_WARNING_"; Blockly.BlockSvg.prototype.initSvg=function(){if(!this.workspace.rendered)throw TypeError("Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;ae.bottom)if(d-f.heightc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+ -Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),this.sourceBlock_.getColour());Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b, -"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; +Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a, +"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;a=a.clientY-b.top-Blockly.FieldAngle.HALF;b=Math.atan(-a/c);isNaN(b)||(b=Blockly.utils.toDegrees(b),0>c?b+=180:0a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; -Blockly.FieldCheckbox.prototype.init=function(){if(!this.fieldGroup_){Blockly.FieldCheckbox.superClass_.init.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"}};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; +Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; Blockly.FieldCheckbox.prototype.setValue=function(a){a="string"==typeof a?"TRUE"==a.toUpperCase():!!a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(String(a).toUpperCase())}; Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null; -Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.init=function(){Blockly.FieldColour.superClass_.init.call(this);this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.borderRect_.style.fillOpacity=1;this.borderRect_.setAttribute("width",this.size_.width+Blockly.BlockSvg.SEP_SPACE_X);this.setValue(this.getValue())}; +Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.initView=function(){Blockly.FieldColour.superClass_.initView.call(this);this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.borderRect_.style.fillOpacity=1;this.borderRect_.setAttribute("width",this.size_.width+Blockly.BlockSvg.SEP_SPACE_X);this.setValue(this.getValue())}; Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.updateWidth=function(){};Blockly.FieldColour.prototype.getValue=function(){return this.colour_}; Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); Blockly.FieldColour.TITLES=[];Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a,b){this.colours_=a;void 0!==b&&(this.titles_=b);return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this}; @@ -1631,8 +1634,8 @@ Blockly.FieldColour.prototype.showEditor_=function(){Blockly.DropDownDiv.hideWit Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;ge&&(d.height=e);this.sourceBlock_.RTL&&Blockly.utils.uiMenu.adjustBBoxesForRTL(b,c,d);Blockly.WidgetDiv.positionWithAnchor(b,c,d,this.sourceBlock_.RTL);a.getElement().focus()}; @@ -1642,38 +1645,40 @@ Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.pr c);!d&&!e||c<=d+e||(d&&(this.prefixField=b[0].substring(0,d-1)),e&&(this.suffixField=b[0].substr(1-e)),this.menuGenerator_=Blockly.FieldDropdown.applyTrim_(a,d,e))}}};Blockly.FieldDropdown.applyTrim_=function(a,b,c){for(var d=[],e=0;e-b||a<-180+b||a>180-b?!0:!1}; -Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new goog.math.Rect(b-1E9,-1E9,1E9+a,2E9);if(goog.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new goog.math.Rect(b, +Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new goog.math.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new goog.math.Rect(b, -1E9,1E9+a,2E9)}; Blockly.VerticalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);a=Math.max(a,e)}for(c=0;d=this.buttons_[c];c++)a=Math.max(a,d.width);a+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=a){for(c=0;d=b[c];c++)this.RTL&&(e=d.getRelativeToSurfaceXY().x, d.moveBy(a/this.workspace_.scale-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH-e,0)),d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);if(this.RTL)for(c=0;d=this.buttons_[c];c++)b=d.getPosition().y,d.moveTo(a/this.workspace_.scale-d.width-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH,b);this.width_=a;this.position()}};Blockly.Toolbox=function(a){this.workspace_=a;this.RTL=a.options.RTL;this.horizontalLayout_=a.options.horizontalLayout;this.toolboxPosition=a.options.toolboxPosition;this.config_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"};this.treeSeparatorConfig_={cssTreeRow:"blocklyTreeSeparator"}; @@ -1808,25 +1813,25 @@ c.contentHeight)/d);if(b.contentTopb.viewBottom||b.c n=b.viewBottom-d.bottomRight.y;0>n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; -Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),goog.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, +Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, "orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[],e=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,e,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,e,!0))}; Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; Blockly.onKeyDown_=function(a){var b=Blockly.mainWorkspace;if(!(b.options.readOnly||Blockly.utils.isTargetInput(a)||b.rendered&&!b.isVisible())){var c=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode){a.preventDefault();if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&(c=!0)}else if(a.altKey||a.ctrlKey||a.metaKey){if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&& (67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),Blockly.clipboardTypeCounts_&&b.isCapacityAvailable(Blockly.clipboardTypeCounts_)&&(Blockly.Events.setGroup(!0),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1))):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&& -(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}};Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace;Blockly.clipboardTypeCounts_=a.isComment?null:Blockly.utils.getBlockTypeCounts(a,!0)}; +(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}};Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a,!0);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace;Blockly.clipboardTypeCounts_=a.isComment?null:Blockly.utils.getBlockTypeCounts(a,!0)}; Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c};Blockly.onContextMenu_=function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()}; Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();Blockly.DropDownDiv.hideWithoutAnimation();var b=Blockly.getMainWorkspace();b.trashcan&&b.trashcan.flyout_&&b.trashcan.flyout_.hide();a||b.toolbox_&&b.toolbox_.flyout_&&b.toolbox_.flyout_.autoClose&&b.toolbox_.clearSelection()};Blockly.addChangeListener=function(a){console.warn("Deprecated call to Blockly.addChangeListener, use workspace.addChangeListener instead.");return Blockly.getMainWorkspace().addChangeListener(a)}; -Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){window.alert(a);b&&b()};Blockly.confirm=function(a,b){b(window.confirm(a))};Blockly.prompt=function(a,b,c){c(window.prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; +Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){alert(a);b&&b()};Blockly.confirm=function(a,b){b(confirm(a))};Blockly.prompt=function(a,b,c){c(prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; Blockly.defineBlocksWithJsonArray=function(a){for(var b=0;b (direction * a.compareTo(b)).toInt(),',' "TEXT": (a, b) => direction * a.toString().compareTo(b.toString()),',' "IGNORE_CASE": ', " (a, b) => direction * "," a.toString().toLowerCase().compareTo(b.toString().toLowerCase())"," };"," list = new List.from(list);"," var compare = compareFuncs[type];"," list.sort(compare);"," return list;","}"])+"("+b+', "'+a+'", '+c+")",Blockly.Dart.ORDER_UNARY_POSTFIX]}; Blockly.Dart.lists_split=function(a){var b=Blockly.Dart.valueToCode(a,"INPUT",Blockly.Dart.ORDER_UNARY_POSTFIX),c=Blockly.Dart.valueToCode(a,"DELIM",Blockly.Dart.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="split";else if("JOIN"==a)b||(b="[]"),a="join";else throw Error("Unknown mode: "+a);return[b+"."+a+"("+c+")",Blockly.Dart.ORDER_UNARY_POSTFIX]}; -Blockly.Dart.lists_reverse=function(a){return["new List.from("+(Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_NONE)||"[]")+".reversed)",Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.logic={};Blockly.Dart.controls_if=function(a){var b=0,c="";do{var d=Blockly.Dart.valueToCode(a,"IF"+b,Blockly.Dart.ORDER_NONE)||"false";var e=Blockly.Dart.statementToCode(a,"DO"+b);c+=(0",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.Dart.ORDER_EQUALITY:Blockly.Dart.ORDER_RELATIONAL,d=Blockly.Dart.valueToCode(a,"A",c)||"0";a=Blockly.Dart.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.Dart.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.Dart.ORDER_LOGICAL_AND:Blockly.Dart.ORDER_LOGICAL_OR,d=Blockly.Dart.valueToCode(a,"A",c);a=Blockly.Dart.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.Dart.logic_negate=function(a){var b=Blockly.Dart.ORDER_UNARY_PREFIX;return["!"+(Blockly.Dart.valueToCode(a,"BOOL",b)||"true"),b]}; Blockly.Dart.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.logic_null=function(a){return["null",Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.logic_ternary=function(a){var b=Blockly.Dart.valueToCode(a,"IF",Blockly.Dart.ORDER_CONDITIONAL)||"false",c=Blockly.Dart.valueToCode(a,"THEN",Blockly.Dart.ORDER_CONDITIONAL)||"null";a=Blockly.Dart.valueToCode(a,"ELSE",Blockly.Dart.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.Dart.ORDER_CONDITIONAL]};Blockly.Dart.loops={}; -Blockly.Dart.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.Dart.valueToCode(a,"TIMES",Blockly.Dart.ORDER_ASSIGNMENT)||"0",c=Blockly.Dart.statementToCode(a,"DO");c=Blockly.Dart.addLoopTrap(c,a.id);a="";var d=Blockly.Dart.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.Dart.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+b+";\n"); -return a+("for (int "+d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.Dart.controls_repeat=Blockly.Dart.controls_repeat_ext;Blockly.Dart.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Dart.valueToCode(a,"BOOL",b?Blockly.Dart.ORDER_UNARY_PREFIX:Blockly.Dart.ORDER_NONE)||"false",d=Blockly.Dart.statementToCode(a,"DO");d=Blockly.Dart.addLoopTrap(d,a.id);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; -Blockly.Dart.controls_for=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Dart.valueToCode(a,"FROM",Blockly.Dart.ORDER_ASSIGNMENT)||"0",d=Blockly.Dart.valueToCode(a,"TO",Blockly.Dart.ORDER_ASSIGNMENT)||"0",e=Blockly.Dart.valueToCode(a,"BY",Blockly.Dart.ORDER_ASSIGNMENT)||"1",f=Blockly.Dart.statementToCode(a,"DO");f=Blockly.Dart.addLoopTrap(f,a.id);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<= -parseFloat(d);a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.Dart.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.Dart.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE),a+="var "+c+" = "+d+";\n"),d=Blockly.Dart.variableDB_.getDistinctName(b+ +Blockly.Dart.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.Dart.valueToCode(a,"TIMES",Blockly.Dart.ORDER_ASSIGNMENT)||"0",c=Blockly.Dart.statementToCode(a,"DO");c=Blockly.Dart.addLoopTrap(c,a);a="";var d=Blockly.Dart.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.Dart.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+b+";\n");return a+ +("for (int "+d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.Dart.controls_repeat=Blockly.Dart.controls_repeat_ext;Blockly.Dart.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Dart.valueToCode(a,"BOOL",b?Blockly.Dart.ORDER_UNARY_PREFIX:Blockly.Dart.ORDER_NONE)||"false",d=Blockly.Dart.statementToCode(a,"DO");d=Blockly.Dart.addLoopTrap(d,a);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; +Blockly.Dart.controls_for=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Dart.valueToCode(a,"FROM",Blockly.Dart.ORDER_ASSIGNMENT)||"0",d=Blockly.Dart.valueToCode(a,"TO",Blockly.Dart.ORDER_ASSIGNMENT)||"0",e=Blockly.Dart.valueToCode(a,"BY",Blockly.Dart.ORDER_ASSIGNMENT)||"1",f=Blockly.Dart.statementToCode(a,"DO");f=Blockly.Dart.addLoopTrap(f,a);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d); +a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.Dart.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.Dart.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE),a+="var "+c+" = "+d+";\n"),d=Blockly.Dart.variableDB_.getDistinctName(b+ "_inc",Blockly.Variables.NAME_TYPE),a+="num "+d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("("+e+").abs();\n"),a=a+("if ("+g+" > "+c+") {\n")+(Blockly.Dart.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+f+"}\n";return a}; -Blockly.Dart.controls_forEach=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_ASSIGNMENT)||"[]",d=Blockly.Dart.statementToCode(a,"DO");d=Blockly.Dart.addLoopTrap(d,a.id);return"for (var "+b+" in "+c+") {\n"+d+"}\n"}; -Blockly.Dart.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw Error("Unknown flow statement.");};Blockly.Dart.math={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));if(Infinity==a){a="double.infinity";var b=Blockly.Dart.ORDER_UNARY_POSTFIX}else-Infinity==a?(a="-double.infinity",b=Blockly.Dart.ORDER_UNARY_PREFIX):b=0>a?Blockly.Dart.ORDER_UNARY_PREFIX:Blockly.Dart.ORDER_ATOMIC;return[a,b]}; +Blockly.Dart.controls_forEach=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_ASSIGNMENT)||"[]",d=Blockly.Dart.statementToCode(a,"DO");d=Blockly.Dart.addLoopTrap(d,a);return"for (var "+b+" in "+c+") {\n"+d+"}\n"}; +Blockly.Dart.controls_flow_statements=function(a){var b="";Blockly.Dart.STATEMENT_PREFIX&&(b+=Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX,a));Blockly.Dart.STATEMENT_SUFFIX&&(b+=Blockly.Dart.injectId(Blockly.Dart.STATEMENT_SUFFIX,a));if(Blockly.Dart.STATEMENT_PREFIX){var c=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(a);c&&!c.suppressPrefixSuffix&&(b+=Blockly.Dart.injectId(Blockly.Dart.STATEMENT_PREFIX,c))}switch(a.getFieldValue("FLOW")){case "BREAK":return b+"break;\n"; +case "CONTINUE":return b+"continue;\n"}throw Error("Unknown flow statement.");};Blockly.Dart.math={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));if(Infinity==a){a="double.infinity";var b=Blockly.Dart.ORDER_UNARY_POSTFIX}else-Infinity==a?(a="-double.infinity",b=Blockly.Dart.ORDER_UNARY_PREFIX):b=0>a?Blockly.Dart.ORDER_UNARY_PREFIX:Blockly.Dart.ORDER_ATOMIC;return[a,b]}; Blockly.Dart.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Dart.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Dart.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Dart.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Dart.ORDER_MULTIPLICATIVE],POWER:[null,Blockly.Dart.ORDER_NONE]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.Dart.valueToCode(a,"A",b)||"0";a=Blockly.Dart.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:(Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;",["Math.pow("+d+", "+ a+")",Blockly.Dart.ORDER_UNARY_POSTFIX])}; Blockly.Dart.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_UNARY_PREFIX)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.Dart.ORDER_UNARY_PREFIX];Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";a="ABS"==b||"ROUND"==b.substring(0,5)?Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_UNARY_POSTFIX)||"0":"SIN"==b||"COS"==b||"TAN"==b?Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_MULTIPLICATIVE)||"0": @@ -74,11 +77,10 @@ Blockly.Dart.math_constrain=function(a){Blockly.Dart.definitions_.import_dart_ma Blockly.Dart.math_random_int=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";var b=Blockly.Dart.valueToCode(a,"FROM",Blockly.Dart.ORDER_NONE)||"0";a=Blockly.Dart.valueToCode(a,"TO",Blockly.Dart.ORDER_NONE)||"0";return[Blockly.Dart.provideFunction_("math_random_int",["int "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(num a, num b) {"," if (a > b) {"," // Swap a and b to ensure a is smaller."," num c = a;"," a = b;"," b = c;"," }"," return new Math.Random().nextInt(b - a + 1) + a;", "}"])+"("+b+", "+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.math_random_float=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return["new Math.Random().nextDouble()",Blockly.Dart.ORDER_UNARY_POSTFIX]}; Blockly.Dart.math_atan2=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";var b=Blockly.Dart.valueToCode(a,"X",Blockly.Dart.ORDER_NONE)||"0";return["Math.atan2("+(Blockly.Dart.valueToCode(a,"Y",Blockly.Dart.ORDER_NONE)||"0")+", "+b+") / Math.pi * 180",Blockly.Dart.ORDER_MULTIPLICATIVE]};Blockly.Dart.procedures={}; -Blockly.Dart.procedures_defreturn=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=Blockly.Dart.statementToCode(a,"STACK");if(Blockly.Dart.STATEMENT_PREFIX){var d=a.id.replace(/\$/g,"$$$$");c=Blockly.Dart.prefixLines(Blockly.Dart.STATEMENT_PREFIX.replace(/%1/g,"'"+d+"'"),Blockly.Dart.INDENT)+c}Blockly.Dart.INFINITE_LOOP_TRAP&&(c=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);(d=Blockly.Dart.valueToCode(a,"RETURN",Blockly.Dart.ORDER_NONE)|| -"")&&(d=Blockly.Dart.INDENT+"return "+d+";\n");for(var e=d?"dynamic":"void",f=[],g=0;g b.toString() ? 1 : -1; },", ' "IGNORE_CASE": function(a, b) {'," return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; },"," };"," var compare = compareFuncs[type];"," return function(a, b) { return compare(a, b) * direction; }","}"]);return[b+".slice().sort("+d+'("'+a+'", '+c+"))",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.lists_split=function(a){var b=Blockly.JavaScript.valueToCode(a,"INPUT",Blockly.JavaScript.ORDER_MEMBER),c=Blockly.JavaScript.valueToCode(a,"DELIM",Blockly.JavaScript.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="split";else if("JOIN"==a)b||(b="[]"),a="join";else throw Error("Unknown mode: "+a);return[b+"."+a+"("+c+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; -Blockly.JavaScript.lists_reverse=function(a){return[(Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_FUNCTION_CALL)||"[]")+".slice().reverse()",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.logic={};Blockly.JavaScript.controls_if=function(a){var b=0,c="";do{var d=Blockly.JavaScript.valueToCode(a,"IF"+b,Blockly.JavaScript.ORDER_NONE)||"false";var e=Blockly.JavaScript.statementToCode(a,"DO"+b);c+=(0",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.JavaScript.ORDER_EQUALITY:Blockly.JavaScript.ORDER_RELATIONAL,d=Blockly.JavaScript.valueToCode(a,"A",c)||"0";a=Blockly.JavaScript.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.JavaScript.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.JavaScript.ORDER_LOGICAL_AND:Blockly.JavaScript.ORDER_LOGICAL_OR,d=Blockly.JavaScript.valueToCode(a,"A",c);a=Blockly.JavaScript.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]}; Blockly.JavaScript.logic_negate=function(a){var b=Blockly.JavaScript.ORDER_LOGICAL_NOT;return["!"+(Blockly.JavaScript.valueToCode(a,"BOOL",b)||"true"),b]};Blockly.JavaScript.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.logic_null=function(a){return["null",Blockly.JavaScript.ORDER_ATOMIC]}; Blockly.JavaScript.logic_ternary=function(a){var b=Blockly.JavaScript.valueToCode(a,"IF",Blockly.JavaScript.ORDER_CONDITIONAL)||"false",c=Blockly.JavaScript.valueToCode(a,"THEN",Blockly.JavaScript.ORDER_CONDITIONAL)||"null";a=Blockly.JavaScript.valueToCode(a,"ELSE",Blockly.JavaScript.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.JavaScript.ORDER_CONDITIONAL]};Blockly.JavaScript.loops={}; -Blockly.JavaScript.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.JavaScript.valueToCode(a,"TIMES",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",c=Blockly.JavaScript.statementToCode(a,"DO");c=Blockly.JavaScript.addLoopTrap(c,a.id);a="";var d=Blockly.JavaScript.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.JavaScript.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE), +Blockly.JavaScript.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.JavaScript.valueToCode(a,"TIMES",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",c=Blockly.JavaScript.statementToCode(a,"DO");c=Blockly.JavaScript.addLoopTrap(c,a);a="";var d=Blockly.JavaScript.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.JavaScript.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE), a+="var "+e+" = "+b+";\n");return a+("for (var "+d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.JavaScript.controls_repeat=Blockly.JavaScript.controls_repeat_ext; -Blockly.JavaScript.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.JavaScript.valueToCode(a,"BOOL",b?Blockly.JavaScript.ORDER_LOGICAL_NOT:Blockly.JavaScript.ORDER_NONE)||"false",d=Blockly.JavaScript.statementToCode(a,"DO");d=Blockly.JavaScript.addLoopTrap(d,a.id);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; -Blockly.JavaScript.controls_for=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",d=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",e=Blockly.JavaScript.valueToCode(a,"BY",Blockly.JavaScript.ORDER_ASSIGNMENT)||"1",f=Blockly.JavaScript.statementToCode(a,"DO");f=Blockly.JavaScript.addLoopTrap(f,a.id);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&& +Blockly.JavaScript.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.JavaScript.valueToCode(a,"BOOL",b?Blockly.JavaScript.ORDER_LOGICAL_NOT:Blockly.JavaScript.ORDER_NONE)||"false",d=Blockly.JavaScript.statementToCode(a,"DO");d=Blockly.JavaScript.addLoopTrap(d,a);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; +Blockly.JavaScript.controls_for=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",d=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",e=Blockly.JavaScript.valueToCode(a,"BY",Blockly.JavaScript.ORDER_ASSIGNMENT)||"1",f=Blockly.JavaScript.statementToCode(a,"DO");f=Blockly.JavaScript.addLoopTrap(f,a);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&& Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d);a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.JavaScript.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.JavaScript.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE), a+="var "+c+" = "+d+";\n"),d=Blockly.JavaScript.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE),a+="var "+d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("Math.abs("+e+");\n"),a=a+("if ("+g+" > "+c+") {\n")+(Blockly.JavaScript.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+f+"}\n";return a}; -Blockly.JavaScript.controls_forEach=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_ASSIGNMENT)||"[]",d=Blockly.JavaScript.statementToCode(a,"DO");d=Blockly.JavaScript.addLoopTrap(d,a.id);a="";var e=c;c.match(/^\w+$/)||(e=Blockly.JavaScript.variableDB_.getDistinctName(b+"_list",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+c+";\n");c=Blockly.JavaScript.variableDB_.getDistinctName(b+ -"_index",Blockly.Variables.NAME_TYPE);d=Blockly.JavaScript.INDENT+b+" = "+e+"["+c+"];\n"+d;return a+("for (var "+c+" in "+e+") {\n"+d+"}\n")};Blockly.JavaScript.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw Error("Unknown flow statement.");};Blockly.JavaScript.math={};Blockly.JavaScript.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));return[a,0<=a?Blockly.JavaScript.ORDER_ATOMIC:Blockly.JavaScript.ORDER_UNARY_NEGATION]}; +Blockly.JavaScript.controls_forEach=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_ASSIGNMENT)||"[]",d=Blockly.JavaScript.statementToCode(a,"DO");d=Blockly.JavaScript.addLoopTrap(d,a);a="";var e=c;c.match(/^\w+$/)||(e=Blockly.JavaScript.variableDB_.getDistinctName(b+"_list",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+c+";\n");c=Blockly.JavaScript.variableDB_.getDistinctName(b+ +"_index",Blockly.Variables.NAME_TYPE);d=Blockly.JavaScript.INDENT+b+" = "+e+"["+c+"];\n"+d;return a+("for (var "+c+" in "+e+") {\n"+d+"}\n")}; +Blockly.JavaScript.controls_flow_statements=function(a){var b="";Blockly.JavaScript.STATEMENT_PREFIX&&(b+=Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX,a));Blockly.JavaScript.STATEMENT_SUFFIX&&(b+=Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_SUFFIX,a));if(Blockly.JavaScript.STATEMENT_PREFIX){var c=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(a);c&&!c.suppressPrefixSuffix&&(b+=Blockly.JavaScript.injectId(Blockly.JavaScript.STATEMENT_PREFIX, +c))}switch(a.getFieldValue("FLOW")){case "BREAK":return b+"break;\n";case "CONTINUE":return b+"continue;\n"}throw Error("Unknown flow statement.");};Blockly.JavaScript.math={};Blockly.JavaScript.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));return[a,0<=a?Blockly.JavaScript.ORDER_ATOMIC:Blockly.JavaScript.ORDER_UNARY_NEGATION]}; Blockly.JavaScript.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.JavaScript.ORDER_ADDITION],MINUS:[" - ",Blockly.JavaScript.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.JavaScript.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.JavaScript.ORDER_DIVISION],POWER:[null,Blockly.JavaScript.ORDER_COMMA]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.JavaScript.valueToCode(a,"A",b)||"0";a=Blockly.JavaScript.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:["Math.pow("+d+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.JavaScript.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_DIVISION)||"0":Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_NONE)||"0";switch(b){case "ABS":var c="Math.abs("+a+")";break;case "ROOT":c="Math.sqrt("+ a+")";break;case "LN":c="Math.log("+a+")";break;case "EXP":c="Math.exp("+a+")";break;case "POW10":c="Math.pow(10,"+a+")";break;case "ROUND":c="Math.round("+a+")";break;case "ROUNDUP":c="Math.ceil("+a+")";break;case "ROUNDDOWN":c="Math.floor("+a+")";break;case "SIN":c="Math.sin("+a+" / 180 * Math.PI)";break;case "COS":c="Math.cos("+a+" / 180 * Math.PI)";break;case "TAN":c="Math.tan("+a+" / 180 * Math.PI)"}if(c)return[c,Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="Math.log("+a+ @@ -70,11 +74,12 @@ Blockly.JavaScript.math_on_list=function(a){var b=a.getFieldValue("OP");switch(b Blockly.JavaScript.math_constrain=function(a){var b=Blockly.JavaScript.valueToCode(a,"VALUE",Blockly.JavaScript.ORDER_COMMA)||"0",c=Blockly.JavaScript.valueToCode(a,"LOW",Blockly.JavaScript.ORDER_COMMA)||"0";a=Blockly.JavaScript.valueToCode(a,"HIGH",Blockly.JavaScript.ORDER_COMMA)||"Infinity";return["Math.min(Math.max("+b+", "+c+"), "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.math_random_int=function(a){var b=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_COMMA)||"0";a=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_COMMA)||"0";return[Blockly.JavaScript.provideFunction_("mathRandomInt",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(a, b) {"," if (a > b) {"," // Swap a and b to ensure a is smaller."," var c = a;"," a = b;"," b = c;"," }"," return Math.floor(Math.random() * (b - a + 1) + a);", "}"])+"("+b+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math_random_float=function(a){return["Math.random()",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math_atan2=function(a){var b=Blockly.JavaScript.valueToCode(a,"X",Blockly.JavaScript.ORDER_COMMA)||"0";return["Math.atan2("+(Blockly.JavaScript.valueToCode(a,"Y",Blockly.JavaScript.ORDER_COMMA)||"0")+", "+b+") / Math.PI * 180",Blockly.JavaScript.ORDER_DIVISION]};Blockly.JavaScript.procedures={}; -Blockly.JavaScript.procedures_defreturn=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=Blockly.JavaScript.statementToCode(a,"STACK");if(Blockly.JavaScript.STATEMENT_PREFIX){var d=a.id.replace(/\$/g,"$$$$");c=Blockly.JavaScript.prefixLines(Blockly.JavaScript.STATEMENT_PREFIX.replace(/%1/g,"'"+d+"'"),Blockly.JavaScript.INDENT)+c}Blockly.JavaScript.INFINITE_LOOP_TRAP&&(c=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+ -c);(d=Blockly.JavaScript.valueToCode(a,"RETURN",Blockly.JavaScript.ORDER_NONE)||"")&&(d=Blockly.JavaScript.INDENT+"return "+d+";\n");for(var e=[],f=0;f",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Lua.valueToCode(a,"A",Blockly.Lua.ORDER_RELATIONAL)||"0";a=Blockly.Lua.valueToCode(a,"B",Blockly.Lua.ORDER_RELATIONAL)||"0";return[c+" "+b+" "+a,Blockly.Lua.ORDER_RELATIONAL]}; Blockly.Lua.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"and":"or",c="and"==b?Blockly.Lua.ORDER_AND:Blockly.Lua.ORDER_OR,d=Blockly.Lua.valueToCode(a,"A",c);a=Blockly.Lua.valueToCode(a,"B",c);if(d||a){var e="and"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.Lua.logic_negate=function(a){return["not "+(Blockly.Lua.valueToCode(a,"BOOL",Blockly.Lua.ORDER_UNARY)||"true"),Blockly.Lua.ORDER_UNARY]}; -Blockly.Lua.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.Lua.ORDER_ATOMIC]};Blockly.Lua.logic_null=function(a){return["nil",Blockly.Lua.ORDER_ATOMIC]};Blockly.Lua.logic_ternary=function(a){var b=Blockly.Lua.valueToCode(a,"IF",Blockly.Lua.ORDER_AND)||"false",c=Blockly.Lua.valueToCode(a,"THEN",Blockly.Lua.ORDER_AND)||"nil";a=Blockly.Lua.valueToCode(a,"ELSE",Blockly.Lua.ORDER_OR)||"nil";return[b+" and "+c+" or "+a,Blockly.Lua.ORDER_OR]};Blockly.Lua.loops={};Blockly.Lua.CONTINUE_STATEMENT="goto continue\n";Blockly.Lua.addContinueLabel=function(a){return-1 ("+d+") then\n")+(Blockly.Lua.INDENT+g+" = -"+g+"\n"),a+="end\n";return a+("for "+b+" = "+c+", "+d+", "+g)+(" do\n"+f+"end\n")}; -Blockly.Lua.controls_forEach=function(a){var b=Blockly.Lua.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_NONE)||"{}";a=Blockly.Lua.statementToCode(a,"DO")||"\n";a=Blockly.Lua.addContinueLabel(a);return"for _, "+b+" in ipairs("+c+") do \n"+a+"end\n"}; -Blockly.Lua.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break\n";case "CONTINUE":return Blockly.Lua.CONTINUE_STATEMENT}throw Error("Unknown flow statement.");};Blockly.Lua.math={};Blockly.Lua.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));return[a,0>a?Blockly.Lua.ORDER_UNARY:Blockly.Lua.ORDER_ATOMIC]}; +Blockly.Lua.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.Lua.ORDER_ATOMIC]};Blockly.Lua.logic_null=function(a){return["nil",Blockly.Lua.ORDER_ATOMIC]};Blockly.Lua.logic_ternary=function(a){var b=Blockly.Lua.valueToCode(a,"IF",Blockly.Lua.ORDER_AND)||"false",c=Blockly.Lua.valueToCode(a,"THEN",Blockly.Lua.ORDER_AND)||"nil";a=Blockly.Lua.valueToCode(a,"ELSE",Blockly.Lua.ORDER_OR)||"nil";return[b+" and "+c+" or "+a,Blockly.Lua.ORDER_OR]};Blockly.Lua.loops={};Blockly.Lua.CONTINUE_STATEMENT="goto continue\n";Blockly.Lua.addContinueLabel_=function(a){return-1!=a.indexOf(Blockly.Lua.CONTINUE_STATEMENT)?a+Blockly.Lua.INDENT+"::continue::\n":a}; +Blockly.Lua.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.Lua.valueToCode(a,"TIMES",Blockly.Lua.ORDER_NONE)||"0";b=Blockly.isNumber(b)?parseInt(b,10):"math.floor("+b+")";var c=Blockly.Lua.statementToCode(a,"DO");c=Blockly.Lua.addLoopTrap(c,a);c=Blockly.Lua.addContinueLabel_(c);return"for "+Blockly.Lua.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE)+" = 1, "+b+" do\n"+c+"end\n"};Blockly.Lua.controls_repeat=Blockly.Lua.controls_repeat_ext; +Blockly.Lua.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Lua.valueToCode(a,"BOOL",b?Blockly.Lua.ORDER_UNARY:Blockly.Lua.ORDER_NONE)||"false",d=Blockly.Lua.statementToCode(a,"DO");d=Blockly.Lua.addLoopTrap(d,a);d=Blockly.Lua.addContinueLabel_(d);b&&(c="not "+c);return"while "+c+" do\n"+d+"end\n"}; +Blockly.Lua.controls_for=function(a){var b=Blockly.Lua.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Lua.valueToCode(a,"FROM",Blockly.Lua.ORDER_NONE)||"0",d=Blockly.Lua.valueToCode(a,"TO",Blockly.Lua.ORDER_NONE)||"0",e=Blockly.Lua.valueToCode(a,"BY",Blockly.Lua.ORDER_NONE)||"1",f=Blockly.Lua.statementToCode(a,"DO");f=Blockly.Lua.addLoopTrap(f,a);f=Blockly.Lua.addContinueLabel_(f);a="";if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<= +parseFloat(d);e=Math.abs(parseFloat(e));g=(g?"":"-")+e}else a="",g=Blockly.Lua.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE),a+=g+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+"\n"):a+("math.abs("+e+")\n"),a=a+("if ("+c+") > ("+d+") then\n")+(Blockly.Lua.INDENT+g+" = -"+g+"\n"),a+="end\n";return a+("for "+b+" = "+c+", "+d+", "+g)+(" do\n"+f+"end\n")}; +Blockly.Lua.controls_forEach=function(a){var b=Blockly.Lua.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_NONE)||"{}",d=Blockly.Lua.statementToCode(a,"DO");d=Blockly.Lua.addLoopTrap(d,a);d=Blockly.Lua.addContinueLabel_(d);return"for _, "+b+" in ipairs("+c+") do \n"+d+"end\n"}; +Blockly.Lua.controls_flow_statements=function(a){var b="";Blockly.Lua.STATEMENT_PREFIX&&(b+=Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX,a));Blockly.Lua.STATEMENT_SUFFIX&&(b+=Blockly.Lua.injectId(Blockly.Lua.STATEMENT_SUFFIX,a));if(Blockly.Lua.STATEMENT_PREFIX){var c=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(a);c&&!c.suppressPrefixSuffix&&(b+=Blockly.Lua.injectId(Blockly.Lua.STATEMENT_PREFIX,c))}switch(a.getFieldValue("FLOW")){case "BREAK":return b+"break\n";case "CONTINUE":return b+ +Blockly.Lua.CONTINUE_STATEMENT}throw Error("Unknown flow statement.");};Blockly.Lua.math={};Blockly.Lua.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));return[a,0>a?Blockly.Lua.ORDER_UNARY:Blockly.Lua.ORDER_ATOMIC]}; Blockly.Lua.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Lua.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Lua.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Lua.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Lua.ORDER_MULTIPLICATIVE],POWER:[" ^ ",Blockly.Lua.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.Lua.valueToCode(a,"A",b)||"0";a=Blockly.Lua.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.Lua.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_UNARY)||"0",["-"+a,Blockly.Lua.ORDER_UNARY];if("POW10"==b)return a=Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_EXPONENTIATION)||"0",["10 ^ "+a,Blockly.Lua.ORDER_EXPONENTIATION];a="ROUND"==b?Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_ADDITIVE)||"0":Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_NONE)||"0";switch(b){case "ABS":b="math.abs("+a+")";break; case "ROOT":b="math.sqrt("+a+")";break;case "LN":b="math.log("+a+")";break;case "LOG10":b="math.log("+a+", 10)";break;case "EXP":b="math.exp("+a+")";break;case "ROUND":b="math.floor("+a+" + .5)";break;case "ROUNDUP":b="math.ceil("+a+")";break;case "ROUNDDOWN":b="math.floor("+a+")";break;case "SIN":b="math.sin(math.rad("+a+"))";break;case "COS":b="math.cos(math.rad("+a+"))";break;case "TAN":b="math.tan(math.rad("+a+"))";break;case "ASIN":b="math.deg(math.asin("+a+"))";break;case "ACOS":b="math.deg(math.acos("+ @@ -55,11 +58,10 @@ default:throw Error("Unknown operator: "+c);}return[c+"("+a+")",Blockly.Lua.ORDE Blockly.Lua.math_constrain=function(a){var b=Blockly.Lua.valueToCode(a,"VALUE",Blockly.Lua.ORDER_NONE)||"0",c=Blockly.Lua.valueToCode(a,"LOW",Blockly.Lua.ORDER_NONE)||"-math.huge";a=Blockly.Lua.valueToCode(a,"HIGH",Blockly.Lua.ORDER_NONE)||"math.huge";return["math.min(math.max("+b+", "+c+"), "+a+")",Blockly.Lua.ORDER_HIGH]}; Blockly.Lua.math_random_int=function(a){var b=Blockly.Lua.valueToCode(a,"FROM",Blockly.Lua.ORDER_NONE)||"0";a=Blockly.Lua.valueToCode(a,"TO",Blockly.Lua.ORDER_NONE)||"0";return["math.random("+b+", "+a+")",Blockly.Lua.ORDER_HIGH]};Blockly.Lua.math_random_float=function(a){return["math.random()",Blockly.Lua.ORDER_HIGH]}; Blockly.Lua.math_atan2=function(a){var b=Blockly.Lua.valueToCode(a,"X",Blockly.Lua.ORDER_NONE)||"0";return["math.deg(math.atan2("+(Blockly.Lua.valueToCode(a,"Y",Blockly.Lua.ORDER_NONE)||"0")+", "+b+"))",Blockly.Lua.ORDER_HIGH]};Blockly.Lua.procedures={}; -Blockly.Lua.procedures_defreturn=function(a){var b=Blockly.Lua.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=Blockly.Lua.statementToCode(a,"STACK");if(Blockly.Lua.STATEMENT_PREFIX){var d=a.id.replace(/\$/g,"$$$$");c=Blockly.Lua.prefixLines(Blockly.Lua.STATEMENT_PREFIX.replace(/%1/g,"'"+d+"'"),Blockly.Lua.INDENT)+c}Blockly.Lua.INFINITE_LOOP_TRAP&&(c=Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);(d=Blockly.Lua.valueToCode(a,"RETURN",Blockly.Lua.ORDER_NONE)|| -"")?d=Blockly.Lua.INDENT+"return "+d+"\n":c||(c="");for(var e=[],f=0;f "strnatcasecmp",',' "TEXT" => "strcmp",',' "IGNORE_CASE" => "strcasecmp"'," );"," $sortCmp = $sortCmpFuncs[$type];"," $list2 = $list;"," usort($list2, $sortCmp);", " if ($direction == -1) {"," $list2 = array_reverse($list2);"," }"," return $list2;","}"])+"("+b+', "'+a+'", '+c+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.lists_split=function(a){var b=Blockly.PHP.valueToCode(a,"INPUT",Blockly.PHP.ORDER_COMMA),c=Blockly.PHP.valueToCode(a,"DELIM",Blockly.PHP.ORDER_COMMA)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="explode";else if("JOIN"==a)b||(b="array()"),a="implode";else throw Error("Unknown mode: "+a);return[a+"("+c+", "+b+")",Blockly.PHP.ORDER_FUNCTION_CALL]}; -Blockly.PHP.lists_reverse=function(a){return["array_reverse("+(Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||"[]")+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.logic={};Blockly.PHP.controls_if=function(a){var b=0,c="";do{var d=Blockly.PHP.valueToCode(a,"IF"+b,Blockly.PHP.ORDER_NONE)||"false";var e=Blockly.PHP.statementToCode(a,"DO"+b);c+=(0",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.PHP.ORDER_EQUALITY:Blockly.PHP.ORDER_RELATIONAL,d=Blockly.PHP.valueToCode(a,"A",c)||"0";a=Blockly.PHP.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.PHP.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.PHP.ORDER_LOGICAL_AND:Blockly.PHP.ORDER_LOGICAL_OR,d=Blockly.PHP.valueToCode(a,"A",c);a=Blockly.PHP.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.PHP.logic_negate=function(a){var b=Blockly.PHP.ORDER_LOGICAL_NOT;return["!"+(Blockly.PHP.valueToCode(a,"BOOL",b)||"true"),b]}; Blockly.PHP.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.logic_null=function(a){return["null",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.logic_ternary=function(a){var b=Blockly.PHP.valueToCode(a,"IF",Blockly.PHP.ORDER_CONDITIONAL)||"false",c=Blockly.PHP.valueToCode(a,"THEN",Blockly.PHP.ORDER_CONDITIONAL)||"null";a=Blockly.PHP.valueToCode(a,"ELSE",Blockly.PHP.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.PHP.ORDER_CONDITIONAL]};Blockly.PHP.loops={}; -Blockly.PHP.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.PHP.valueToCode(a,"TIMES",Blockly.PHP.ORDER_ASSIGNMENT)||"0",c=Blockly.PHP.statementToCode(a,"DO");c=Blockly.PHP.addLoopTrap(c,a.id);a="";var d=Blockly.PHP.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.PHP.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),a+=e+" = "+b+";\n");return a+("for ("+ -d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.PHP.controls_repeat=Blockly.PHP.controls_repeat_ext;Blockly.PHP.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.PHP.valueToCode(a,"BOOL",b?Blockly.PHP.ORDER_LOGICAL_NOT:Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO");d=Blockly.PHP.addLoopTrap(d,a.id);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; -Blockly.PHP.controls_for=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"FROM",Blockly.PHP.ORDER_ASSIGNMENT)||"0",d=Blockly.PHP.valueToCode(a,"TO",Blockly.PHP.ORDER_ASSIGNMENT)||"0",e=Blockly.PHP.valueToCode(a,"BY",Blockly.PHP.ORDER_ASSIGNMENT)||"1",f=Blockly.PHP.statementToCode(a,"DO");f=Blockly.PHP.addLoopTrap(f,a.id);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d); +Blockly.PHP.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.PHP.valueToCode(a,"TIMES",Blockly.PHP.ORDER_ASSIGNMENT)||"0",c=Blockly.PHP.statementToCode(a,"DO");c=Blockly.PHP.addLoopTrap(c,a);a="";var d=Blockly.PHP.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.PHP.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),a+=e+" = "+b+";\n");return a+("for ("+ +d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.PHP.controls_repeat=Blockly.PHP.controls_repeat_ext;Blockly.PHP.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.PHP.valueToCode(a,"BOOL",b?Blockly.PHP.ORDER_LOGICAL_NOT:Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO");d=Blockly.PHP.addLoopTrap(d,a);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; +Blockly.PHP.controls_for=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"FROM",Blockly.PHP.ORDER_ASSIGNMENT)||"0",d=Blockly.PHP.valueToCode(a,"TO",Blockly.PHP.ORDER_ASSIGNMENT)||"0",e=Blockly.PHP.valueToCode(a,"BY",Blockly.PHP.ORDER_ASSIGNMENT)||"1",f=Blockly.PHP.statementToCode(a,"DO");f=Blockly.PHP.addLoopTrap(f,a);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d); a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.PHP.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+=g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.PHP.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE),a+=c+" = "+d+";\n"),d=Blockly.PHP.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE), a+=d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("abs("+e+");\n"),a=a+("if ("+g+" > "+c+") {\n")+(Blockly.PHP.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+f+"}\n";return a}; -Blockly.PHP.controls_forEach=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_ASSIGNMENT)||"[]",d=Blockly.PHP.statementToCode(a,"DO");d=Blockly.PHP.addLoopTrap(d,a.id);return"foreach ("+c+" as "+b+") {\n"+d+"}\n"}; -Blockly.PHP.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw Error("Unknown flow statement.");};Blockly.PHP.math={};Blockly.PHP.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));var b=0<=a?Blockly.PHP.ORDER_ATOMIC:Blockly.PHP.ORDER_UNARY_NEGATION;Infinity==a?a="INF":-Infinity==a&&(a="-INF");return[a,b]}; +Blockly.PHP.controls_forEach=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_ASSIGNMENT)||"[]",d=Blockly.PHP.statementToCode(a,"DO");d=Blockly.PHP.addLoopTrap(d,a);return"foreach ("+c+" as "+b+") {\n"+d+"}\n"}; +Blockly.PHP.controls_flow_statements=function(a){var b="";Blockly.PHP.STATEMENT_PREFIX&&(b+=Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX,a));Blockly.PHP.STATEMENT_SUFFIX&&(b+=Blockly.PHP.injectId(Blockly.PHP.STATEMENT_SUFFIX,a));if(Blockly.PHP.STATEMENT_PREFIX){var c=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(a);c&&!c.suppressPrefixSuffix&&(b+=Blockly.PHP.injectId(Blockly.PHP.STATEMENT_PREFIX,c))}switch(a.getFieldValue("FLOW")){case "BREAK":return b+"break;\n";case "CONTINUE":return b+ +"continue;\n"}throw Error("Unknown flow statement.");};Blockly.PHP.math={};Blockly.PHP.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));var b=0<=a?Blockly.PHP.ORDER_ATOMIC:Blockly.PHP.ORDER_UNARY_NEGATION;Infinity==a?a="INF":-Infinity==a&&(a="-INF");return[a,b]}; Blockly.PHP.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.PHP.ORDER_ADDITION],MINUS:[" - ",Blockly.PHP.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.PHP.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.PHP.ORDER_DIVISION],POWER:[" ** ",Blockly.PHP.ORDER_POWER]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.PHP.valueToCode(a,"A",b)||"0";a=Blockly.PHP.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.PHP.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.PHP.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_DIVISION)||"0":Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_NONE)||"0";switch(b){case "ABS":var c="abs("+a+")";break;case "ROOT":c="sqrt("+a+")";break;case "LN":c="log("+a+")";break;case "EXP":c="exp("+ a+")";break;case "POW10":c="pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="ceil("+a+")";break;case "ROUNDDOWN":c="floor("+a+")";break;case "SIN":c="sin("+a+" / 180 * pi())";break;case "COS":c="cos("+a+" / 180 * pi())";break;case "TAN":c="tan("+a+" / 180 * pi())"}if(c)return[c,Blockly.PHP.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="log("+a+") / log(10)";break;case "ASIN":c="asin("+a+") / pi() * 180";break;case "ACOS":c="acos("+a+") / pi() * 180";break;case "ATAN":c="atan("+ a+") / pi() * 180";break;default:throw Error("Unknown math operator: "+b);}return[c,Blockly.PHP.ORDER_DIVISION]};Blockly.PHP.math_constant=function(a){return{PI:["M_PI",Blockly.PHP.ORDER_ATOMIC],E:["M_E",Blockly.PHP.ORDER_ATOMIC],GOLDEN_RATIO:["(1 + sqrt(5)) / 2",Blockly.PHP.ORDER_DIVISION],SQRT2:["M_SQRT2",Blockly.PHP.ORDER_ATOMIC],SQRT1_2:["M_SQRT1_2",Blockly.PHP.ORDER_ATOMIC],INFINITY:["INF",Blockly.PHP.ORDER_ATOMIC]}[a.getFieldValue("CONSTANT")]}; Blockly.PHP.math_number_property=function(a){var b=Blockly.PHP.valueToCode(a,"NUMBER_TO_CHECK",Blockly.PHP.ORDER_MODULUS)||"0",c=a.getFieldValue("PROPERTY");if("PRIME"==c)return[Blockly.PHP.provideFunction_("math_isPrime",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($n) {"," // https://en.wikipedia.org/wiki/Primality_test#Naive_methods"," if ($n == 2 || $n == 3) {"," return true;"," }"," // False if n is NaN, negative, is 1, or not whole."," // And false if n is divisible by 2 or 3.", -" if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 || $n % 3 == 0) {"," return false;"," }"," // Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for ($x = 6; $x <= sqrt($n) + 1; $x += 6) {"," if ($n % ($x - 1) == 0 || $n % ($x + 1) == 0) {"," return false;"," }"," }"," return true;","}"])+"("+b+")",Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(c){case "EVEN":var d=b+" % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d="is_int("+b+")";break;case "POSITIVE":d= +" if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 || $n % 3 == 0) {"," return false;"," }"," // Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for ($x = 6; $x <= sqrt($n) + 1; $x += 6) {"," if ($n % ($x - 1) == 0 || $n % ($x + 1) == 0) {"," return false;"," }"," }"," return true;","}"])+"("+b+")",Blockly.PHP.ORDER_FUNCTION_CALL];switch(c){case "EVEN":var d=b+" % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d="is_int("+b+")";break;case "POSITIVE":d= b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.PHP.valueToCode(a,"DIVISOR",Blockly.PHP.ORDER_MODULUS)||"0",d=b+" % "+a+" == 0"}return[d,Blockly.PHP.ORDER_EQUALITY]};Blockly.PHP.math_change=function(a){var b=Blockly.PHP.valueToCode(a,"DELTA",Blockly.PHP.ORDER_ADDITION)||"0";return Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE)+" += "+b+";\n"};Blockly.PHP.math_round=Blockly.PHP.math_single;Blockly.PHP.math_trig=Blockly.PHP.math_single; Blockly.PHP.math_on_list=function(a){var b=a.getFieldValue("OP");switch(b){case "SUM":a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_FUNCTION_CALL)||"array()";a="array_sum("+a+")";break;case "MIN":a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_FUNCTION_CALL)||"array()";a="min("+a+")";break;case "MAX":a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_FUNCTION_CALL)||"array()";a="max("+a+")";break;case "AVERAGE":b=Blockly.PHP.provideFunction_("math_mean",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+ "($myList) {"," return array_sum($myList) / count($myList);","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)||"array()";a=b+"("+a+")";break;case "MEDIAN":b=Blockly.PHP.provideFunction_("math_median",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($arr) {"," sort($arr,SORT_NUMERIC);"," return (count($arr) % 2) ? $arr[floor(count($arr)/2)] : "," ($arr[floor(count($arr)/2)] + $arr[floor(count($arr)/2) - 1]) / 2;","}"]);a=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_NONE)|| @@ -67,10 +70,10 @@ Blockly.PHP.math_constrain=function(a){var b=Blockly.PHP.valueToCode(a,"VALUE",B Blockly.PHP.math_random_int=function(a){var b=Blockly.PHP.valueToCode(a,"FROM",Blockly.PHP.ORDER_COMMA)||"0";a=Blockly.PHP.valueToCode(a,"TO",Blockly.PHP.ORDER_COMMA)||"0";return[Blockly.PHP.provideFunction_("math_random_int",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($a, $b) {"," if ($a > $b) {"," return rand($b, $a);"," }"," return rand($a, $b);","}"])+"("+b+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]}; Blockly.PHP.math_random_float=function(a){return["(float)rand()/(float)getrandmax()",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.math_atan2=function(a){var b=Blockly.PHP.valueToCode(a,"X",Blockly.PHP.ORDER_COMMA)||"0";return["atan2("+(Blockly.PHP.valueToCode(a,"Y",Blockly.PHP.ORDER_COMMA)||"0")+", "+b+") / pi() * 180",Blockly.PHP.ORDER_DIVISION]};Blockly.PHP.procedures={}; Blockly.PHP.procedures_defreturn=function(a){for(var b=[],c,d=a.workspace,e=Blockly.Variables.allUsedVarModels(d)||[],f=0;c=e[f];f++)c=c.name,-1==a.arguments_.indexOf(c)&&b.push(Blockly.PHP.variableDB_.getName(c,Blockly.Variables.NAME_TYPE));d=Blockly.Variables.allDeveloperVariables(d);for(f=0;f",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Python.ORDER_RELATIONAL,d=Blockly.Python.valueToCode(a,"A",c)||"0";a=Blockly.Python.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.Python.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"and":"or",c="and"==b?Blockly.Python.ORDER_LOGICAL_AND:Blockly.Python.ORDER_LOGICAL_OR,d=Blockly.Python.valueToCode(a,"A",c);a=Blockly.Python.valueToCode(a,"B",c);if(d||a){var e="and"==b?"True":"False";d||(d=e);a||(a=e)}else a=d="False";return[d+" "+b+" "+a,c]};Blockly.Python.logic_negate=function(a){return["not "+(Blockly.Python.valueToCode(a,"BOOL",Blockly.Python.ORDER_LOGICAL_NOT)||"True"),Blockly.Python.ORDER_LOGICAL_NOT]}; Blockly.Python.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"True":"False",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.logic_null=function(a){return["None",Blockly.Python.ORDER_ATOMIC]}; -Blockly.Python.logic_ternary=function(a){var b=Blockly.Python.valueToCode(a,"IF",Blockly.Python.ORDER_CONDITIONAL)||"False",c=Blockly.Python.valueToCode(a,"THEN",Blockly.Python.ORDER_CONDITIONAL)||"None";a=Blockly.Python.valueToCode(a,"ELSE",Blockly.Python.ORDER_CONDITIONAL)||"None";return[c+" if "+b+" else "+a,Blockly.Python.ORDER_CONDITIONAL]};Blockly.Python.loops={};Blockly.Python.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(parseInt(a.getFieldValue("TIMES"),10)):Blockly.Python.valueToCode(a,"TIMES",Blockly.Python.ORDER_NONE)||"0";b=Blockly.isNumber(b)?parseInt(b,10):"int("+b+")";var c=Blockly.Python.statementToCode(a,"DO");c=Blockly.Python.addLoopTrap(c,a.id)||Blockly.Python.PASS;return"for "+Blockly.Python.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE)+" in range("+b+"):\n"+c}; -Blockly.Python.controls_repeat=Blockly.Python.controls_repeat_ext;Blockly.Python.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Python.valueToCode(a,"BOOL",b?Blockly.Python.ORDER_LOGICAL_NOT:Blockly.Python.ORDER_NONE)||"False",d=Blockly.Python.statementToCode(a,"DO");d=Blockly.Python.addLoopTrap(d,a.id)||Blockly.Python.PASS;b&&(c="not "+c);return"while "+c+":\n"+d}; -Blockly.Python.controls_for=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0",d=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0",e=Blockly.Python.valueToCode(a,"BY",Blockly.Python.ORDER_NONE)||"1",f=Blockly.Python.statementToCode(a,"DO");f=Blockly.Python.addLoopTrap(f,a.id)||Blockly.Python.PASS;var g="",h=function(){return Blockly.Python.provideFunction_("upRange", -["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start <= stop:"," yield start"," start += abs(step)"])},k=function(){return Blockly.Python.provideFunction_("downRange",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start >= stop:"," yield start"," start -= abs(step)"])};a=function(a,b,c){return"("+a+" <= "+b+") and "+h()+"("+a+", "+b+", "+c+") or "+k()+"("+a+", "+b+", "+c+")"};if(Blockly.isNumber(c)&&Blockly.isNumber(d)&& -Blockly.isNumber(e))c=parseFloat(c),d=parseFloat(d),e=Math.abs(parseFloat(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0==c&&1==e?d:c+", "+d,1!=e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=ca?Blockly.Python.ORDER_UNARY_SIGN:Blockly.Python.ORDER_ATOMIC;return[a,b]}; +Blockly.Python.logic_ternary=function(a){var b=Blockly.Python.valueToCode(a,"IF",Blockly.Python.ORDER_CONDITIONAL)||"False",c=Blockly.Python.valueToCode(a,"THEN",Blockly.Python.ORDER_CONDITIONAL)||"None";a=Blockly.Python.valueToCode(a,"ELSE",Blockly.Python.ORDER_CONDITIONAL)||"None";return[c+" if "+b+" else "+a,Blockly.Python.ORDER_CONDITIONAL]};Blockly.Python.loops={};Blockly.Python.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(parseInt(a.getFieldValue("TIMES"),10)):Blockly.Python.valueToCode(a,"TIMES",Blockly.Python.ORDER_NONE)||"0";b=Blockly.isNumber(b)?parseInt(b,10):"int("+b+")";var c=Blockly.Python.statementToCode(a,"DO");c=Blockly.Python.addLoopTrap(c,a)||Blockly.Python.PASS;return"for "+Blockly.Python.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE)+" in range("+b+"):\n"+c}; +Blockly.Python.controls_repeat=Blockly.Python.controls_repeat_ext;Blockly.Python.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Python.valueToCode(a,"BOOL",b?Blockly.Python.ORDER_LOGICAL_NOT:Blockly.Python.ORDER_NONE)||"False",d=Blockly.Python.statementToCode(a,"DO");d=Blockly.Python.addLoopTrap(d,a)||Blockly.Python.PASS;b&&(c="not "+c);return"while "+c+":\n"+d}; +Blockly.Python.controls_for=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0",d=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0",e=Blockly.Python.valueToCode(a,"BY",Blockly.Python.ORDER_NONE)||"1",f=Blockly.Python.statementToCode(a,"DO");f=Blockly.Python.addLoopTrap(f,a)||Blockly.Python.PASS;var h="",g=function(){return Blockly.Python.provideFunction_("upRange", +["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start <= stop:"," yield start"," start += abs(step)"])},k=function(){return Blockly.Python.provideFunction_("downRange",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start >= stop:"," yield start"," start -= abs(step)"])};a=function(a,b,c){return"("+a+" <= "+b+") and "+g()+"("+a+", "+b+", "+c+") or "+k()+"("+a+", "+b+", "+c+")"};if(Blockly.isNumber(c)&&Blockly.isNumber(d)&& +Blockly.isNumber(e))c=parseFloat(c),d=parseFloat(d),e=Math.abs(parseFloat(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0==c&&1==e?d:c+", "+d,1!=e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=ca?Blockly.Python.ORDER_UNARY_SIGN:Blockly.Python.ORDER_ATOMIC;return[a,b]}; Blockly.Python.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Python.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Python.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Python.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Python.ORDER_MULTIPLICATIVE],POWER:[" ** ",Blockly.Python.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.Python.valueToCode(a,"A",b)||"0";a=Blockly.Python.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.Python.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b){var c=Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_UNARY_SIGN)||"0";return["-"+c,Blockly.Python.ORDER_UNARY_SIGN]}Blockly.Python.definitions_.import_math="import math";a="SIN"==b||"COS"==b||"TAN"==b?Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_MULTIPLICATIVE)||"0":Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_NONE)||"0";switch(b){case "ABS":c="math.fabs("+a+")";break;case "ROOT":c="math.sqrt("+ a+")";break;case "LN":c="math.log("+a+")";break;case "LOG10":c="math.log10("+a+")";break;case "EXP":c="math.exp("+a+")";break;case "POW10":c="math.pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="math.ceil("+a+")";break;case "ROUNDDOWN":c="math.floor("+a+")";break;case "SIN":c="math.sin("+a+" / 180.0 * math.pi)";break;case "COS":c="math.cos("+a+" / 180.0 * math.pi)";break;case "TAN":c="math.tan("+a+" / 180.0 * math.pi)"}if(c)return[c,Blockly.Python.ORDER_FUNCTION_CALL];switch(b){case "ASIN":c= @@ -62,11 +65,10 @@ Blockly.Python.math_constrain=function(a){var b=Blockly.Python.valueToCode(a,"VA Blockly.Python.math_random_int=function(a){Blockly.Python.definitions_.import_random="import random";var b=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0";return["random.randint("+b+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.math_random_float=function(a){Blockly.Python.definitions_.import_random="import random";return["random.random()",Blockly.Python.ORDER_FUNCTION_CALL]}; Blockly.Python.math_atan2=function(a){Blockly.Python.definitions_.import_math="import math";var b=Blockly.Python.valueToCode(a,"X",Blockly.Python.ORDER_NONE)||"0";return["math.atan2("+(Blockly.Python.valueToCode(a,"Y",Blockly.Python.ORDER_NONE)||"0")+", "+b+") / math.pi * 180",Blockly.Python.ORDER_MULTIPLICATIVE]};Blockly.Python.procedures={}; Blockly.Python.procedures_defreturn=function(a){for(var b=[],c,d=a.workspace,e=Blockly.Variables.allUsedVarModels(d)||[],f=0;c=e[f];f++)c=c.name,-1==a.arguments_.indexOf(c)&&b.push(Blockly.Python.variableDB_.getName(c,Blockly.Variables.NAME_TYPE));d=Blockly.Variables.allDeveloperVariables(d);for(f=0;f Date: Fri, 17 May 2019 16:28:44 -0700 Subject: [PATCH 070/233] Missing semicolon --- core/events.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/events.js b/core/events.js index 285c9d45c98..178a922d690 100644 --- a/core/events.js +++ b/core/events.js @@ -402,7 +402,7 @@ Blockly.Events.fromJson = function(json, workspace) { * Enable/disable a block depending on whether it is properly connected. * Use this on applications where all blocks should be connected to a top block. * Recommend setting the 'disable' option to 'false' in the config so that - * users don't try to reenable disabled orphan blocks. + * users don't try to re-enable disabled orphan blocks. * @param {!Blockly.Events.Abstract} event Custom data for event. */ Blockly.Events.disableOrphans = function(event) { @@ -411,7 +411,7 @@ Blockly.Events.disableOrphans = function(event) { var workspace = Blockly.Workspace.getById(event.workspaceId); var block = workspace.getBlockById(event.blockId); if (block) { - var parent = block.getParent() + var parent = block.getParent(); if (parent && parent.isEnabled()) { var children = block.getDescendants(false); for (var i = 0, child; child = children[i]; i++) { From 23860381389669ded5519787befec34f3f2d1dbf Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Fri, 17 May 2019 17:57:53 -0700 Subject: [PATCH 071/233] Fix bug with in bounds bumping (#2467) Traced one cause of Mocha tests sometimes failing to blocks being bumped back into bounds. It looks like a block being moved to be a child of another block was ended up out of bounds probably because the size of the workspace isn't set yet. When the change handler tried to move it back in it would throw an error since you can't move child blocks with that method. --- core/inject.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/inject.js b/core/inject.js index 8ecd1e1f7d3..4492bae5840 100644 --- a/core/inject.js +++ b/core/inject.js @@ -294,6 +294,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, case Blockly.Events.BLOCK_CREATE: case Blockly.Events.BLOCK_MOVE: var object = mainWorkspace.getBlockById(e.blockId); + object = object.getRootBlock(); break; case Blockly.Events.COMMENT_CREATE: case Blockly.Events.COMMENT_MOVE: From 50cd9c77420274943214183d753d4ce4890b7426 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 20 May 2019 13:40:27 +0200 Subject: [PATCH 072/233] Localisation updates from https://translatewiki.net. --- msg/json/es.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/msg/json/es.json b/msg/json/es.json index d544f7739fb..4e3b750dcc7 100644 --- a/msg/json/es.json +++ b/msg/json/es.json @@ -11,7 +11,8 @@ "Martineduardo", "Julián L", "Luisangelrg", - "MarcoAurelio" + "MarcoAurelio", + "Ryo567" ] }, "VARIABLES_DEFAULT_NAME": "elemento", @@ -39,6 +40,10 @@ "RENAME_VARIABLE": "Renombrar la variable…", "RENAME_VARIABLE_TITLE": "Renombrar todas las variables «%1» a:", "NEW_VARIABLE": "Crear variable…", + "NEW_STRING_VARIABLE": "Crear una cadena variable...", + "NEW_NUMBER_VARIABLE": "Crear un número variable...", + "NEW_COLOUR_VARIABLE": "Crear un color variable...", + "NEW_VARIABLE_TYPE_TITLE": "Nuevo tipo de variable:", "NEW_VARIABLE_TITLE": "Nombre de variable nueva:", "VARIABLE_ALREADY_EXISTS": "Ya existe una variable llamada \"%1\".", "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Ya existe una variable nombrada '%1' para otra variable del tipo: '%2'.", @@ -192,6 +197,8 @@ "MATH_RANDOM_FLOAT_HELPURL": "https://es.wikipedia.org/wiki/Generador_de_números_aleatorios", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fracción aleatoria", "MATH_RANDOM_FLOAT_TOOLTIP": "Devuelve una fracción aleatoria entre 0,0 (ambos inclusive) y 1.0 (exclusivo).", + "MATH_ATAN2_HELPURL": "https://es.wikipedia.org/wiki/Arcotangente_de_dos_par%C3%A1metros", + "MATH_ATAN2_TITLE": "Arcotangente de X:%1 Y:%2", "TEXT_TEXT_HELPURL": "https://es.wikipedia.org/wiki/Cadena_de_caracteres", "TEXT_TEXT_TOOLTIP": "Una letra, palabra o línea de texto.", "TEXT_JOIN_TITLE_CREATEWITH": "crear texto con", From 52c6efb4f4e439fe4ce4a0a4ce9a09c4c1df1455 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 23 May 2019 14:08:56 +0200 Subject: [PATCH 073/233] Localisation updates from https://translatewiki.net. --- msg/json/eo.json | 66 ++++++++++++++++++++++++------------------------ msg/json/ro.json | 3 ++- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/msg/json/eo.json b/msg/json/eo.json index d5d4c7d4291..e50bd987419 100644 --- a/msg/json/eo.json +++ b/msg/json/eo.json @@ -64,7 +64,7 @@ "CONTROLS_REPEAT_TOOLTIP": "Plenumas kelkajn ordonojn plurfoje.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ripeti dum", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ripeti ĝis", - "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Plenumas ordonojn dum la valoro egalas vero.", + "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Plenumi ordonojn dum la valoro egalas veron.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Plenumi ordonojn dum valoro egalas malvero.", "CONTROLS_FOR_TOOLTIP": "Varias la variablon '%1', ekde la komenca nombro ĝis la fina nombro, laŭ la specifita diferenco; dume rulas la specifitajn blokojn.", "CONTROLS_FOR_TITLE": "kalkuli kun variablo %1 ekde %2 ĝis %3 per diferenco %4", @@ -75,7 +75,7 @@ "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Eliri el la enhava ciklo.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Pretersalti la ceteron de tiu ĉi ciklo kaj daŭrigi je la venonta ripeto.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Averto: tiu ĉi bloko uzeblas nur ene de ciklo.", - "CONTROLS_IF_TOOLTIP_1": "Plenumas ordonojn se la valoro estas vero.", + "CONTROLS_IF_TOOLTIP_1": "Plenumi ordonojn se la valoro estas vero.", "CONTROLS_IF_TOOLTIP_2": "Plenumi la unuan blokon de ordonoj se la valoro estas vero, se ne, la duan.", "CONTROLS_IF_TOOLTIP_3": "Se la unua valoro estas vero, do faras la unuan blokon de ordonoj. Alie, se la dua valoro estas vero, do faras la duan blokon de ordonoj.", "CONTROLS_IF_TOOLTIP_4": "Se la unua valoro estas vero, do faras la unuan blokon de ordonoj. Alie, se la dua valoro estas vero, do faras la duan blokon de ordonoj. Se neniu el la du valoroj estas vero, do faras la lastan blokon de ordonoj.", @@ -99,21 +99,21 @@ "IOS_VARIABLES_VARIABLE_NAME": "Nomo de variablo", "IOS_VARIABLES_EMPTY_NAME_ERROR": "La nomo de la variablo devas esti ne malplena.", "LOGIC_COMPARE_HELPURL": "https://eo.wikipedia.org/wiki/Neegala%C4%B5o_(pli_granda,_malpli_granda)", - "LOGIC_COMPARE_TOOLTIP_EQ": "Liveras veron, se la du eniroj egalas.", - "LOGIC_COMPARE_TOOLTIP_NEQ": "Vero estos liverita, se la du eniroj ne egalas.", - "LOGIC_COMPARE_TOOLTIP_LT": "Liveras veron, se la unua eniro estas pli malgranda ol la dua.", + "LOGIC_COMPARE_TOOLTIP_EQ": "Liveri veron, se la du eniroj egalas.", + "LOGIC_COMPARE_TOOLTIP_NEQ": "Liveri veron, se la du eniroj ne egalas.", + "LOGIC_COMPARE_TOOLTIP_LT": "Liveri veron, se la unua eniro estas pli malgranda ol la dua.", "LOGIC_COMPARE_TOOLTIP_LTE": "Vero estos liverita, se la unua eniro estas pli eta aŭ egala al la dua.", - "LOGIC_COMPARE_TOOLTIP_GT": "Liveras veron, se la unua eniro estas pli granda ol la dua.", + "LOGIC_COMPARE_TOOLTIP_GT": "Liveri veron, se la unua eniro estas pli granda ol la dua.", "LOGIC_COMPARE_TOOLTIP_GTE": "Vero estos liverita, se la unua eniro estas pli granda aŭ egala al la dua.", - "LOGIC_OPERATION_TOOLTIP_AND": "Liveras veron, se la du eniroj egalas veron.", + "LOGIC_OPERATION_TOOLTIP_AND": "Liveri veron, se la du eniroj egalas veron.", "LOGIC_OPERATION_AND": "kaj", - "LOGIC_OPERATION_TOOLTIP_OR": "Liveras veron, se almenaŭ unu el la eniroj egalas veron.", + "LOGIC_OPERATION_TOOLTIP_OR": "Liveri veron, se almenaŭ unu el la eniroj egalas veron.", "LOGIC_OPERATION_OR": "aŭ", "LOGIC_NEGATE_TITLE": "maligi %1", - "LOGIC_NEGATE_TOOLTIP": "Liveras veron, se la eniro egalas veron. Liveras malveron, se la eniro egalas malveron.", + "LOGIC_NEGATE_TOOLTIP": "Liveri veron, se la eniro egalas malveron. Liveri malveron, se la eniro egalas veron.", "LOGIC_BOOLEAN_TRUE": "vera", "LOGIC_BOOLEAN_FALSE": "falsa", - "LOGIC_BOOLEAN_TOOLTIP": "Liveras aŭ veron aŭ malveron.", + "LOGIC_BOOLEAN_TOOLTIP": "Liveri ĉu veron ĉu malveron.", "LOGIC_NULL": "senvalora", "LOGIC_NULL_TOOLTIP": "Liveras senvaloron.", "LOGIC_TERNARY_CONDITION": "testi", @@ -123,20 +123,20 @@ "MATH_NUMBER_HELPURL": "https://eo.wikipedia.org/wiki/Nombro", "MATH_NUMBER_TOOLTIP": "Nombro.", "MATH_ARITHMETIC_HELPURL": "https://eo.wikipedia.org/wiki/Aritmetiko", - "MATH_ARITHMETIC_TOOLTIP_ADD": "Liveras la sumon de la du nombroj.", - "MATH_ARITHMETIC_TOOLTIP_MINUS": "La diferenco inter la du nombroj estos liverita.", + "MATH_ARITHMETIC_TOOLTIP_ADD": "Liveri la sumon de la du nombroj.", + "MATH_ARITHMETIC_TOOLTIP_MINUS": "Liveri la diferencon inter la du nombroj.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "La produto de la du numeroj estos liverita.", - "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "La kvociento de la du nombroj estos liverita.", + "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Liveri la kvocienton de la du nombroj.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Livero la tian potencon de la unua nombro, kia la dua nombro estas", "MATH_SINGLE_HELPURL": "https://eo.wikipedia.org/wiki/Kvadrata_radiko", "MATH_SINGLE_OP_ROOT": "kvadrata radiko", - "MATH_SINGLE_TOOLTIP_ROOT": "Liveras la kvadratan radikon de nombro.", + "MATH_SINGLE_TOOLTIP_ROOT": "Liveri la kvadratan radikon de nombro.", "MATH_SINGLE_OP_ABSOLUTE": "absoluta", - "MATH_SINGLE_TOOLTIP_ABS": "Liveras la absolutan valoron de nombro.", + "MATH_SINGLE_TOOLTIP_ABS": "Liveri la absolutan valoron de nombro.", "MATH_SINGLE_TOOLTIP_NEG": "La negativigo de numero estos liverita.", - "MATH_SINGLE_TOOLTIP_LN": "Liveras la naturan logaritmon de nombro.", + "MATH_SINGLE_TOOLTIP_LN": "Liveri la naturan logaritmon de nombro.", "MATH_SINGLE_TOOLTIP_LOG10": "La dekbaza logaritmo de numero estos liverita.", - "MATH_SINGLE_TOOLTIP_EXP": "Liveras ian potencon de e.", + "MATH_SINGLE_TOOLTIP_EXP": "Liveri potencon de e.", "MATH_SINGLE_TOOLTIP_POW10": "Liveri tian potencon de 10, kia la eniro estas.", "MATH_TRIG_HELPURL": "https://eo.wikipedia.org/wiki/Trigonometria_funkcio", "MATH_TRIG_TOOLTIP_SIN": "Liveras la sinuson de angulo en gradoj (ne radianoj).", @@ -157,31 +157,31 @@ "MATH_IS_TOOLTIP": "Vero aŭ malvero estos liverita, depende de la rezulto de kontrolo, ĉu nombro estas para, nepara, pozitiva, negativa, aŭ dividebla de iu nombro.", "MATH_CHANGE_HELPURL": "https://eo.wikipedia.org/wiki/Kremento", "MATH_CHANGE_TITLE": "krementi %1 per %2", - "MATH_CHANGE_TOOLTIP": "Aldoni nombro al variablo '%1'.", + "MATH_CHANGE_TOOLTIP": "Aldoni nombron al variablo '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Rondigi nombroj, supren aŭ malsupren.", "MATH_ROUND_OPERATOR_ROUND": "rondigi", "MATH_ROUND_OPERATOR_ROUNDUP": "Rondigi supren", "MATH_ROUND_OPERATOR_ROUNDDOWN": "rondigi malsupren", "MATH_ONLIST_OPERATOR_SUM": "sumo de listo", - "MATH_ONLIST_TOOLTIP_SUM": "Liveras la sumon de ĉiuj nombroj en la listo.", + "MATH_ONLIST_TOOLTIP_SUM": "Liveri la sumon de ĉiuj nombroj en la listo.", "MATH_ONLIST_OPERATOR_MIN": "listminimumo", - "MATH_ONLIST_TOOLTIP_MIN": "Liveras la plej malgrandan nombron en la listo.", + "MATH_ONLIST_TOOLTIP_MIN": "Liveri la plej malgrandan nombron en la listo.", "MATH_ONLIST_OPERATOR_MAX": "listmaksimumo", - "MATH_ONLIST_TOOLTIP_MAX": "Liveras la plej grandan nombron en la listo.", + "MATH_ONLIST_TOOLTIP_MAX": "Liveri la plej grandan nombron en la listo.", "MATH_ONLIST_OPERATOR_AVERAGE": "listmezumo", - "MATH_ONLIST_TOOLTIP_AVERAGE": "Liveras la aritmetikan meznombron de la nombroj en la listo.", + "MATH_ONLIST_TOOLTIP_AVERAGE": "Liveri la aritmetikan meznombron de la nombroj en la listo.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediano de listo", "MATH_ONLIST_TOOLTIP_MEDIAN": "Liveras la medianan nombron en la listo.", "MATH_ONLIST_OPERATOR_MODE": "modoj de listo", "MATH_ONLIST_TOOLTIP_MODE": "Liveras liston de la plej ofta(j) elemento(j) en la listo.", "MATH_ONLIST_OPERATOR_STD_DEV": "Norma devio de la listo", - "MATH_ONLIST_TOOLTIP_STD_DEV": "Liveras la norman devion de la listo.", + "MATH_ONLIST_TOOLTIP_STD_DEV": "Liveri la norman devion de la listo.", "MATH_ONLIST_OPERATOR_RANDOM": "hazarda elemento el la listo", - "MATH_ONLIST_TOOLTIP_RANDOM": "Liveras hazardan elementon el la listo.", + "MATH_ONLIST_TOOLTIP_RANDOM": "Liveri hazardan elementon el la listo.", "MATH_MODULO_HELPURL": "https://eo.wikipedia.org/wiki/Resto", "MATH_MODULO_TITLE": "resto de %1 ÷ %2", - "MATH_MODULO_TOOLTIP": "Liveras la reston de la divido de la du nombroj.", + "MATH_MODULO_TOOLTIP": "Liveri la reston de la divido de la du nombroj.", "MATH_CONSTRAIN_TITLE": "limigi %1 inter %2 kaj %3", "MATH_CONSTRAIN_TOOLTIP": "La nombro estos limigita tiel ke ĝi egalas la limojn aŭ troviĝas inter ili.", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", @@ -246,18 +246,18 @@ "TEXT_REVERSE_MESSAGE0": "inversigi tekston %1", "TEXT_REVERSE_TOOLTIP": "Inversigi la ordon de la skribsignoj en la teksto.", "LISTS_CREATE_EMPTY_TITLE": "krei malplenan liston", - "LISTS_CREATE_EMPTY_TOOLTIP": "Liveras liston, de longo 0, sen datenaj rikordoj", + "LISTS_CREATE_EMPTY_TOOLTIP": "Liveri liston, de longo 0, sen datenaj rikordoj", "LISTS_CREATE_WITH_TOOLTIP": "Krei liston kun ajna nombro de elementoj.", "LISTS_CREATE_WITH_INPUT_WITH": "krei liston kun", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "listo", - "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Aldonu, forigu aŭ oridigu partojn por reagordi la listan blokon.", + "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Aldoni, forigi aŭ ordigi partojn por reagordi la listan blokon.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Aldoni elementon al la listo.", "LISTS_REPEAT_TOOLTIP": "Listo kun la specifita nombro de elementoj, kiuj havos la donitan valoron, estos kreita.", "LISTS_REPEAT_TITLE": "krei liston kun elemento %1 ripetita %2 fojojn", "LISTS_LENGTH_TITLE": "longo de %1", - "LISTS_LENGTH_TOOLTIP": "Liveras la longon de listo.", + "LISTS_LENGTH_TOOLTIP": "Liveri la longon de listo.", "LISTS_ISEMPTY_TITLE": "%1 malplenas", - "LISTS_ISEMPTY_TOOLTIP": "Liveras veron, se la listo malplenas.", + "LISTS_ISEMPTY_TOOLTIP": "Liveri veron, se la listo malplenas.", "LISTS_INLIST": "en la listo", "LISTS_INDEX_OF_FIRST": "trovi la unuan aperon de elemento", "LISTS_INDEX_OF_LAST": "trovi la lastan aperon de elemento", @@ -271,13 +271,13 @@ "LISTS_GET_INDEX_RANDOM": "hazardan", "LISTS_INDEX_FROM_START_TOOLTIP": "%1 estas la unua elemento.", "LISTS_INDEX_FROM_END_TOOLTIP": "%1 estas la lasta elemento.", - "LISTS_GET_INDEX_TOOLTIP_GET_FROM": "Liveras la elementon ĉe la specifita pozicio en listo.", + "LISTS_GET_INDEX_TOOLTIP_GET_FROM": "Liveri la elementon ĉe la specifita pozicio en listo.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "La unua elemento en la listo esto liverita.", - "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Liveras la lastan elementon en la listo.", + "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Liveri la lastan elementon en la listo.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Hazarda elemento en la listo estos liverita.", - "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM": "Liveras kaj forigas la elementon en la specifita pozicio de la listo.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM": "Liveri kaj forigi la elementon en la specifita pozicio de la listo.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "La unua elemento en la listo estos liverita kaj forigita.", - "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Forigas kaj liveras la lastan elementon en listo.", + "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Forigi kaj liveri la lastan elementon en listo.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Hazarda elemento en la listo estos liverita kaj forigita.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM": "La elemento en la specifita pozicio en la listo estos forigita.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "La unua elemento en la listo estos forigita.", diff --git a/msg/json/ro.json b/msg/json/ro.json index 8f1d7da9352..df3ead9ad49 100644 --- a/msg/json/ro.json +++ b/msg/json/ro.json @@ -363,5 +363,6 @@ "PROCEDURES_CREATE_DO": "Creaţi '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Dacă o valoare este adevărată, atunci returnează valoarea a doua.", "PROCEDURES_IFRETURN_WARNING": "Avertisment: Acest bloc poate fi utilizat numai în definiţia unei funcţii.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Spune ceva..." + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Spune ceva...", + "COLLAPSED_WARNINGS_WARNING": "Blocurile blocate conțin avertismente." } From a4e0091d4e3d9434859688405b259165ed788062 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 24 May 2019 08:43:22 -0700 Subject: [PATCH 074/233] Fix style matching in Firefox 67 (#2485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chrome returns ‘transform: translate(107px, 0px);’ whereas Firefox now returns ‘transform: translate(107px);’ if the y value is 0. This is consistent with existing behaviour in the translate SVG attribute. The comment in our code specifically states: // Accounts for same exceptions as XY_REGEX_ Yet that was not true at all. This PR makes the y argument optional (as falsely described in the comment). It also merges the 2D and 3D regeps together to simplify the code. Resolves issue #2482. Needs to be cherrypicked to Master and everything rebuilt and pushed. --- core/utils.js | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/core/utils.js b/core/utils.js index b41dda36e19..2aaf9b1c0ef 100644 --- a/core/utils.js +++ b/core/utils.js @@ -160,11 +160,8 @@ Blockly.utils.getRelativeXY = function(element) { // Then check for style = transform: translate(...) or translate3d(...) var style = element.getAttribute('style'); if (style && style.indexOf('translate') > -1) { - var styleComponents = style.match(Blockly.utils.getRelativeXY.XY_2D_REGEX_); - // Try transform3d if 2d transform wasn't there. - if (!styleComponents) { - styleComponents = style.match(Blockly.utils.getRelativeXY.XY_3D_REGEX_); - } + var styleComponents = + style.match(Blockly.utils.getRelativeXY.XY_STYLE_REGEX_); if (styleComponents) { xy.x += parseFloat(styleComponents[1]); if (styleComponents[3]) { @@ -209,25 +206,17 @@ Blockly.utils.getInjectionDivXY_ = function(element) { * @private */ Blockly.utils.getRelativeXY.XY_REGEX_ = - /translate\(\s*([-+\d.e]+)([ ,]\s*([-+\d.e]+)\s*\))?/; - -/** - * Static regex to pull the x,y,z values out of a translate3d() style property. - * Accounts for same exceptions as XY_REGEXP_. - * @type {!RegExp} - * @private - */ -Blockly.utils.getRelativeXY.XY_3D_REGEX_ = - /transform:\s*translate3d\(\s*([-+\d.e]+)px([ ,]\s*([-+\d.e]+)\s*)px([ ,]\s*([-+\d.e]+)\s*)px\)?/; + /translate\(\s*([-+\d.e]+)([ ,]\s*([-+\d.e]+)\s*)?/; /** - * Static regex to pull the x,y,z values out of a translate3d() style property. - * Accounts for same exceptions as XY_REGEXP_. + * Static regex to pull the x,y values out of a translate() or translate3d() + * style property. + * Accounts for same exceptions as XY_REGEX_. * @type {!RegExp} * @private */ -Blockly.utils.getRelativeXY.XY_2D_REGEX_ = - /transform:\s*translate\(\s*([-+\d.e]+)px([ ,]\s*([-+\d.e]+)\s*)px\)?/; +Blockly.utils.getRelativeXY.XY_STYLE_REGEX_ = + /transform:\s*translate(?:3d)?\(\s*([-+\d.e]+)\s*px([ ,]\s*([-+\d.e]+)\s*px)?/; /** * Helper method for creating SVG elements. From f16c9c0beb29b31718460a7a012a4fc2b9e09b11 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 2 May 2019 14:41:31 -0700 Subject: [PATCH 075/233] Refactored field validation. --- blocks/lists.js | 1 - blocks/text.js | 4 - core/field.js | 156 +++++-- core/field_angle.js | 84 ++-- core/field_checkbox.js | 151 +++++-- core/field_colour.js | 90 ++-- core/field_date.js | 58 +-- core/field_dropdown.js | 83 ++-- core/field_image.js | 59 +-- core/field_label.js | 28 +- core/field_label_serializable.js | 7 +- core/field_number.js | 46 +- core/field_textinput.js | 215 +++++----- core/field_variable.js | 120 ++++-- tests/blocks/test_blocks.js | 429 +++++++++++++++++++ tests/jsunit/field_angle_test.js | 44 -- tests/jsunit/field_number_test.js | 80 ---- tests/jsunit/field_variable_test.js | 237 ---------- tests/jsunit/index.html | 3 - tests/mocha/field_angle_test.js | 10 +- tests/mocha/field_checkbox_test.js | 2 +- tests/mocha/field_colour_test.js | 30 +- tests/mocha/field_date_test.js | 34 +- tests/mocha/field_dropdown_test.js | 6 +- tests/mocha/field_image_test.js | 2 +- tests/mocha/field_label_serializable_test.js | 8 +- tests/mocha/field_label_test.js | 8 +- tests/mocha/field_number_test.js | 16 +- tests/mocha/field_textinput_test.js | 10 +- tests/mocha/field_variable_test.js | 8 +- tests/playground.html | 126 ++++++ 31 files changed, 1260 insertions(+), 895 deletions(-) delete mode 100644 tests/jsunit/field_angle_test.js delete mode 100644 tests/jsunit/field_number_test.js delete mode 100644 tests/jsunit/field_variable_test.js diff --git a/blocks/lists.js b/blocks/lists.js index 4e9d3b5e25a..6bfa4213995 100644 --- a/blocks/lists.js +++ b/blocks/lists.js @@ -831,7 +831,6 @@ Blockly.Blocks['lists_split'] = { updateType_: function(newMode) { var mode = this.getFieldValue('MODE'); if (mode != newMode) { - this.setFieldValue(newMode, 'MODE'); var inputConnection = this.getInput('INPUT').connection; inputConnection.setShadowDom(null); var inputBlock = inputConnection.targetBlock(); diff --git a/blocks/text.js b/blocks/text.js index b98bd54bef6..244889456f5 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -864,11 +864,7 @@ Blockly.Constants.Text.TEXT_CHARAT_EXTENSION = function() { if (newAt != this.isAt_) { var block = this.sourceBlock_; block.updateAt_(newAt); - // This menu has been destroyed and replaced. Update the replacement. - block.setFieldValue(value, 'WHERE'); - return null; } - return undefined; }); this.updateAt_(true); // Assign 'this' to a variable for use in the tooltip closure below. diff --git a/core/field.js b/core/field.js index 6ce1aa79eb5..f103813fe62 100644 --- a/core/field.js +++ b/core/field.js @@ -39,14 +39,15 @@ goog.require('goog.style'); /** * Abstract class for an editable field. - * @param {string} text The initial content of the field. - * @param {function(string):(string|null|undefined)=} opt_validator An optional - * function that is called to validate user input. See setValidator(). + * @param {*} value The initial value of the field. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a value & returns a validated + * value, or null to abort the change. * @constructor */ -Blockly.Field = function(text, opt_validator) { +Blockly.Field = function(value, opt_validator) { this.size_ = new goog.math.Size(0, Blockly.BlockSvg.MIN_BLOCK_Y); - this.setValue(text); + this.setValue(value); this.setValidator(opt_validator); }; @@ -123,6 +124,14 @@ Blockly.Field.prototype.name = undefined; */ Blockly.Field.prototype.maxDisplayLength = 50; +/** + * Get the current value of the field. + * @return {*} Current value. + */ +Blockly.Field.prototype.getValue = function() { + return this.value_; +}; + /** * Visible text to display. * @type {string} @@ -233,10 +242,11 @@ Blockly.Field.prototype.initView = function() { 'y': 0, 'height': 16 }, this.fieldGroup_); - /** @type {!Element} */ this.textElement_ = Blockly.utils.createSvgElement('text', {'class': 'blocklyText', 'y': this.size_.height - 12.5}, this.fieldGroup_); + var textNode = document.createTextNode(''); + this.textElement_.appendChild(textNode); this.updateEditable(); @@ -375,14 +385,15 @@ Blockly.Field.prototype.setVisible = function(visible) { * Sets a new validation function for editable fields, or clears a previously * set validator. * - * The validator function takes in the text form of the users input, and - * optionally returns the accepted field text. Alternatively, if the function - * returns null, the field value change aborts. If the function does not return - * anything (or returns undefined), the input value is accepted as valid. This - * is a shorthand for fields using the validator function call as a field-level - * change event notification. + * The validator function takes in the new field value, and returns + * validated value. The validated value could be the input value, a modified + * version of the input value, or null to abort the change. + * + * If the function does not return anything (or returns undefined) the new + * value is accepted as valid. This is to allow for fields using the + * validated founction as a field-level change event notification. * - * @param {?function(string):(string|null|undefined)} handler The validator + * @param {Function=} handler The validator * function or null to clear a previous validator. */ Blockly.Field.prototype.setValidator = function(handler) { @@ -401,6 +412,8 @@ Blockly.Field.prototype.getValidator = function() { * Validates a change. Does nothing. Subclasses may override this. * @param {string} text The user's text. * @return {string} No change needed. + * @deprecated May 2019. Override doClassValidation and other relevant 'do' + * functions instead. */ Blockly.Field.prototype.classValidator = function(text) { return text; @@ -411,6 +424,7 @@ Blockly.Field.prototype.classValidator = function(text) { * function for the field's class and its parents. * @param {string} text Proposed text. * @return {?string} Revised text, or null if invalid. + * @deprecated May 2019. setValue now contains all relevant logic. */ Blockly.Field.prototype.callValidator = function(text) { var classResult = this.classValidator(text); @@ -452,15 +466,15 @@ Blockly.Field.prototype.updateColour = function() { }; /** - * Draws the border with the correct width. - * Saves the computed width in a property. + * Used by getSize() to move/resize any dom elements, and get the new size. + * + * All rendering that has an effect on the size/shape of the block should be + * done here, and should be triggered by getSize(). * @protected */ Blockly.Field.prototype.render_ = function() { - // Replace the text. this.textElement_.textContent = this.getDisplayText_(); this.updateWidth(); - this.isDirty_ = false; }; /** @@ -547,6 +561,7 @@ Blockly.Field.stopCache = function() { Blockly.Field.prototype.getSize = function() { if (this.isDirty_) { this.render_(); + this.isDirty_ = false; } else if (this.visible_ && this.size_.width == 0) { // If the field is not visible the width will be 0 as well, one of the // problems with the old system. @@ -644,39 +659,106 @@ Blockly.Field.prototype.forceRerender = function() { }; /** - * By default there is no difference between the human-readable text and - * the language-neutral values. Subclasses (such as dropdown) may define this. - * @return {string} Current value. - */ -Blockly.Field.prototype.getValue = function() { - return this.getText(); -}; - -/** - * By default there is no difference between the human-readable text and - * the language-neutral values. Subclasses (such as dropdown) may define this. - * @param {string} newValue New value. + * Used to change the value of the field. Handles validation and events. + * Subclasses should override doClassValidation_ and doValueUpdate_ rather + * than this method. + * @param {*} newValue New value. */ Blockly.Field.prototype.setValue = function(newValue) { + var doLogging = false; if (newValue === null) { - // No change if null. + doLogging && console.log('null, return'); + // Not a valid value to check. return; } - // Validate input. - var validated = this.callValidator(newValue); - if (validated !== null) { - newValue = validated; + + newValue = this.doClassValidation_(newValue); + if (newValue === null) { + doLogging && console.log('invalid, return'); + this.doValueInvalid_(); + if (this.isDirty_) { + this.forceRerender(); + } + return; + } + + var localValidator = this.getValidator(); + if (localValidator) { + var validatedValue = localValidator.call(this, newValue); + // Sometimes local validators are used as change listeners (bad!) which + // means they might return undefined accidentally, so we'll just ignore that. + if (validatedValue !== undefined) { + newValue = validatedValue; + } + if (newValue === null) { + doLogging && console.log('invalid, return'); + this.doValueInvalid_(); + if (this.isDirty_) { + this.forceRerender(); + } + return; + } } - // Check for change. var oldValue = this.getValue(); - if (oldValue == newValue) { + if (oldValue === newValue) { + doLogging && console.log('same, return'); + // No change. return; } + if (this.sourceBlock_ && Blockly.Events.isEnabled()) { Blockly.Events.fire(new Blockly.Events.BlockChange( this.sourceBlock_, 'field', this.name, oldValue, newValue)); } - this.setText(newValue); + this.doValueUpdate_(newValue); + if (this.isDirty_) { + this.forceRerender(); + } + doLogging && console.log(this.value_); +}; + +/** + * A generic value possessed by the field. + * Should generally be non-null, only null when the field is created. + * @type {*} + * @protected + */ +Blockly.Field.prototype.value_ = null; + +/** + * Used to validate a value. Returns input by default. Can be overridden by + * subclasses, see FieldDropdown. + * @param {*} newValue The value to be validated. + * @return {*} The validated value, same as input by default. + * @protected + */ +Blockly.Field.prototype.doClassValidation_ = function(newValue) { + // For backwards compatibility. + newValue = this.classValidator(newValue); + return newValue; +}; + +/** + * Used to update the value of a field. Can be overridden by subclasses to do + * custom storage of values/updating of external things. + * @param {*} newValue The value to be saved. + * @protected + */ +Blockly.Field.prototype.doValueUpdate_ = function(newValue) { + this.value_ = newValue; + this.isDirty_ = true; + // For backwards compatibility. + this.text_ = String(newValue); +}; + +/** + * Used to notify the field an invalid value was input. Can be overiden by + * subclasses, see FieldTextInput. + * No-op by default. + * @protected + */ +Blockly.Field.prototype.doValueInvalid_ = function() { + // NOP }; /** diff --git a/core/field_angle.js b/core/field_angle.js index 2c29395e4e5..cd1138aec27 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -34,21 +34,19 @@ goog.require('Blockly.utils'); /** * Class for an editable angle field. - * @param {(string|number)=} opt_value The initial content of the field. The - * value should cast to a number, and if it does not, '0' will be used. - * @param {Function=} opt_validator An optional function that is called - * to validate any constraints on what the user entered. Takes the new - * text as an argument and returns the accepted text or null to abort - * the change. + * @param {string|number=} opt_value The initial value of the field. Should cast + * to a number. Defaults to 0. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a number & returns a + * validated number, or null to abort the change. * @extends {Blockly.FieldTextInput} * @constructor */ Blockly.FieldAngle = function(opt_value, opt_validator) { - // Add degree symbol: '360°' (LTR) or '°360' (RTL) - this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null); - this.symbol_.appendChild(document.createTextNode('\u00B0')); - - opt_value = (opt_value && !isNaN(opt_value)) ? String(opt_value) : '0'; + opt_value = this.doClassValidation_(opt_value); + if (opt_value === null) { + opt_value = 0; + } Blockly.FieldAngle.superClass_.constructor.call( this, opt_value, opt_validator); }; @@ -120,18 +118,25 @@ Blockly.FieldAngle.WRAP = 360; Blockly.FieldAngle.RADIUS = Blockly.FieldAngle.HALF - 1; /** - * Adds degree symbol and recalculates width. - * Saves the computed width in a property. + * Create the block UI for this field. + * @package + */ +Blockly.FieldAngle.prototype.initView = function() { + Blockly.FieldAngle.superClass_.initView.call(this); + // Add the degree symbol to the left of the number, even in RTL (issue #2380) + this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null); + this.symbol_.appendChild(document.createTextNode('\u00B0')); +}; + +/** + * Updates the graph when the field rerenders. * @private */ Blockly.FieldAngle.prototype.render_ = function() { - // Update textElement. this.textElement_.textContent = this.getDisplayText_(); - - // Insert degree symbol. - // Degree symbol should be left of number, even in RTL (issue #2380). this.textElement_.appendChild(this.symbol_); this.updateWidth(); + this.updateGraph_(); }; /** @@ -208,7 +213,6 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { }, svg); } - var border = this.sourceBlock_.getColourBorder(); border = border.colourBorder == null ? border.colourLight : border.colourBorder; @@ -244,6 +248,7 @@ Blockly.FieldAngle.prototype.hide_ = function() { * @param {!Event} e Mouse move event. */ Blockly.FieldAngle.prototype.onMouseMove = function(e) { + // Calculate angle. var bBox = this.gauge_.ownerSVGElement.getBoundingClientRect(); var dx = e.clientX - bBox.left - Blockly.FieldAngle.HALF; var dy = e.clientY - bBox.top - Blockly.FieldAngle.HALF; @@ -268,24 +273,16 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) { angle = Math.round(angle / Blockly.FieldAngle.ROUND) * Blockly.FieldAngle.ROUND; } - angle = this.callValidator(angle); - Blockly.FieldTextInput.htmlInput_.value = angle; - this.setValue(angle); - this.validate_(); - this.resizeEditor_(); -}; -/** - * Insert a degree symbol. - * @param {?string} text New text. - */ -Blockly.FieldAngle.prototype.setText = function(text) { - Blockly.FieldAngle.superClass_.setText.call(this, text); - if (!this.textElement_) { - // Not rendered yet. - return; + // Update value. + var angleString = String(angle); + if (angleString != this.text_) { + Blockly.FieldTextInput.htmlInput_.value = angle; + this.setValue(angle); + // Always render the input angle. + this.text_ = angleString; + this.forceRerender(); } - this.updateGraph_(); }; /** @@ -296,6 +293,7 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() { if (!this.gauge_) { return; } + // Always display the input (i.e. getText) even if it is invalid. var angleDegrees = Number(this.getText()) + Blockly.FieldAngle.OFFSET; var angleRadians = Blockly.utils.toRadians(angleDegrees); var path = ['M ', Blockly.FieldAngle.HALF, ',', Blockly.FieldAngle.HALF]; @@ -326,18 +324,16 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() { }; /** - * Ensure that only an angle may be entered. - * @param {string} text The user's text. - * @return {?string} A string representing a valid angle, or null if invalid. + * Ensure that the input value is a valid angle. + * @param {string|number=} newValue The input value. + * @return {?number} A valid angle, or null if invalid. + * @protected */ -Blockly.FieldAngle.prototype.classValidator = function(text) { - if (text === null) { - return null; - } - var n = parseFloat(text || 0); - if (isNaN(n)) { +Blockly.FieldAngle.prototype.doClassValidation_ = function(newValue) { + if (isNaN(newValue)) { return null; } + var n = parseFloat(newValue || 0); n = n % 360; if (n < 0) { n += 360; @@ -345,7 +341,7 @@ Blockly.FieldAngle.prototype.classValidator = function(text) { if (n > Blockly.FieldAngle.WRAP) { n -= 360; } - return String(n); + return n; }; Blockly.Field.register('field_angle', Blockly.FieldAngle); diff --git a/core/field_checkbox.js b/core/field_checkbox.js index f096b1e9a27..67d08237e97 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -32,19 +32,22 @@ goog.require('Blockly.utils'); /** * Class for a checkbox field. - * @param {string=} opt_state The initial state of the field ('TRUE' or - * 'FALSE'), defaults to 'FALSE'. - * @param {Function=} opt_validator A function that is executed when a new - * option is selected. Its sole argument is the new checkbox state. If - * it returns a value, this becomes the new checkbox state, unless the - * value is null, in which case the change is aborted. + * @param {string|boolean=} opt_value The initial value of the field. Should + * either be 'TRUE', 'FALSE' or a boolean. Defaults to 'FALSE'. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a value ('TRUE' or 'FALSE') & + * returns a validated value ('TRUE' or 'FALSE'), or null to abort the + * change. * @extends {Blockly.Field} * @constructor */ -Blockly.FieldCheckbox = function(opt_state, opt_validator) { - Blockly.FieldCheckbox.superClass_.constructor.call(this, '', opt_validator); - // Set the initial state. - this.setValue(opt_state); +Blockly.FieldCheckbox = function(opt_value, opt_validator) { + opt_value = this.doClassValidation_(opt_value); + if (opt_value === null) { + opt_value = 'FALSE'; + } + Blockly.FieldCheckbox.superClass_.constructor.call(this, opt_value, opt_validator); + this.size_.width = Blockly.FieldCheckbox.WIDTH; }; goog.inherits(Blockly.FieldCheckbox, Blockly.Field); @@ -56,22 +59,31 @@ goog.inherits(Blockly.FieldCheckbox, Blockly.Field); * @nocollapse */ Blockly.FieldCheckbox.fromJson = function(options) { - return new Blockly.FieldCheckbox(options['checked'] ? 'TRUE' : 'FALSE'); + return new Blockly.FieldCheckbox(options['checked']); }; /** - * Serializable fields are saved by the XML renderer, non-serializable fields - * are not. Editable fields should also be serializable. - * @type {boolean} + * The width of a checkbox field. + * @type {number} * @const */ -Blockly.FieldCheckbox.prototype.SERIALIZABLE = true; +Blockly.FieldCheckbox.WIDTH = 5; /** * Character for the checkmark. + * @type {string} + * @const */ Blockly.FieldCheckbox.CHECK_CHAR = '\u2713'; +/** + * Serializable fields are saved by the XML renderer, non-serializable fields + * are not. Editable fields should also be serializable. + * @type {boolean} + * @const + */ +Blockly.FieldCheckbox.prototype.SERIALIZABLE = true; + /** * Mouse cursor style when over the hotspot that initiates editability. */ @@ -91,49 +103,98 @@ Blockly.FieldCheckbox.prototype.initView = function() { this.fieldGroup_); var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR); this.checkElement_.appendChild(textNode); - this.checkElement_.style.display = this.state_ ? 'block' : 'none'; + this.checkElement_.style.display = this.value_ ? 'block' : 'none'; + + if (this.borderRect_) { + this.borderRect_.setAttribute('width', + this.size_.width + Blockly.BlockSvg.SEP_SPACE_X); + } }; /** - * Return 'TRUE' if the checkbox is checked, 'FALSE' otherwise. - * @return {string} Current state. + * Checkboxes have a constant width. + * @private */ -Blockly.FieldCheckbox.prototype.getValue = function() { - return String(this.state_).toUpperCase(); +Blockly.FieldCheckbox.prototype.render_ = function() { + this.size_.width = Blockly.FieldCheckbox.WIDTH; +}; + +/** + * Toggle the state of the checkbox on click. + * @protected + */ +Blockly.FieldCheckbox.prototype.showEditor_ = function() { + this.setValue(!this.value_); }; /** - * Set the checkbox to be checked if newBool is 'TRUE' or true, - * unchecks otherwise. - * @param {string|boolean} newBool New state. - */ -Blockly.FieldCheckbox.prototype.setValue = function(newBool) { - var newState = (typeof newBool == 'string') ? - (newBool.toUpperCase() == 'TRUE') : !!newBool; - if (this.state_ !== newState) { - if (this.sourceBlock_ && Blockly.Events.isEnabled()) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.sourceBlock_, 'field', this.name, this.state_, newState)); - } - this.state_ = newState; - if (this.checkElement_) { - this.checkElement_.style.display = newState ? 'block' : 'none'; - } + * Ensure that the input value is valid ('TRUE' or 'FALSE'). + * @param {string|boolean=} newValue The input value. + * @return {?string} A valid value ('TRUE' or 'FALSE), or null if invalid. + * @protected + */ +Blockly.FieldCheckbox.prototype.doClassValidation_ = function(newValue) { + if (newValue === true || newValue === 'TRUE') { + return 'TRUE'; + } + if (newValue === false || newValue === 'FALSE') { + return 'FALSE'; } + return null; }; /** - * Toggle the state of the checkbox. - * @private + * Update the value of the field, and update the checkElement. + * @param {string} newValue The new value ('TRUE' or 'FALSE') of the field. + * @protected */ -Blockly.FieldCheckbox.prototype.showEditor_ = function() { - var newState = !this.state_; - if (this.sourceBlock_) { - // Call any validation function, and allow it to override. - newState = this.callValidator(newState); +Blockly.FieldCheckbox.prototype.doValueUpdate_ = function(newValue) { + this.value_ = this.convertValueToBool_(newValue); + // Update visual. + if (this.checkElement_) { + this.checkElement_.style.display = this.value_ ? 'block' : 'none'; } - if (newState !== null) { - this.setValue(String(newState).toUpperCase()); +}; + +/** + * Get the value of this field, either 'TRUE' or 'FALSE'. + * @return {string} The value of this field. + */ +Blockly.FieldCheckbox.prototype.getValue = function() { + return this.value_ ? 'TRUE' : 'FALSE'; +}; + +/** + * Get the boolean value of this field. + * @return {string} The boolean value of this field. + */ +Blockly.FieldCheckbox.prototype.getValueBoolean = function() { + return this.value_; +}; + +/** + * Get the text of this field. Used when the block is collapsed. + * @return {string} Text representing the value of this field + * ('true' or 'false'). + */ +Blockly.FieldCheckbox.prototype.getText = function() { + return String(this.convertValueToBool_(this.value_)); +}; + +/** + * Convert a value into a pure boolean. + * + * Converts 'TRUE' to true and 'FALSE' to false correctly, everything else + * is cast to a boolean. + * @param {*} value The value to convert. + * @return {boolean} The converted value. + * @private + */ +Blockly.FieldCheckbox.prototype.convertValueToBool_ = function(value) { + if (typeof value == 'string') { + return value == 'TRUE'; + } else { + return !!value; } }; diff --git a/core/field_colour.js b/core/field_colour.js index d0796acf0a6..0e0c830df61 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -34,21 +34,21 @@ goog.require('goog.math.Size'); /** * Class for a colour input field. - * @param {string=} opt_colour The initial colour in '#rrggbb' format, defaults - * to the first value in the default colour array. - * @param {Function=} opt_validator A function that is executed when a new - * colour is selected. Its sole argument is the new colour value. Its - * return value becomes the selected colour, unless it is undefined, in - * which case the new colour stands, or it is null, in which case the change - * is aborted. + * @param {string=} opt_value The initial value of the field. Should be in + * '#rrggbb' format. Defaults to the first value in the default colour array. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a colour string & returns a + * validated colour string ('#rrggbb' format), or null to abort the change. * @extends {Blockly.Field} * @constructor */ -Blockly.FieldColour = function(opt_colour, opt_validator) { - opt_colour = opt_colour || Blockly.FieldColour.COLOURS[0]; - Blockly.FieldColour.superClass_.constructor - .call(this, opt_colour, opt_validator); - this.setText(Blockly.Field.NBSP + Blockly.Field.NBSP + Blockly.Field.NBSP); +Blockly.FieldColour = function(opt_value, opt_validator) { + opt_value = this.doClassValidation_(opt_value); + if (opt_value === null) { + opt_value = Blockly.FieldColour.COLOURS[0]; + } + Blockly.FieldColour.superClass_.constructor.call( + this, opt_value, opt_validator); }; goog.inherits(Blockly.FieldColour, Blockly.Field); @@ -63,14 +63,6 @@ Blockly.FieldColour.fromJson = function(options) { return new Blockly.FieldColour(options['colour']); }; -/** - * Serializable fields are saved by the XML renderer, non-serializable fields - * are not. Editable fields should also be serializable. - * @type {boolean} - * @const - */ -Blockly.FieldColour.prototype.SERIALIZABLE = true; - /** * Default width of a colour field. * @type {number} @@ -87,6 +79,20 @@ Blockly.FieldColour.DEFAULT_WIDTH = 16; */ Blockly.FieldColour.DEFAULT_HEIGHT = 12; +/** + * Regex that defines the form of a colour string. + * @type {RegExp} + */ +Blockly.FieldColour.COLOUR_REGEX = new RegExp('#[0-9a-fA-F]{6}'); + +/** + * Serializable fields are saved by the XML renderer, non-serializable fields + * are not. Editable fields should also be serializable. + * @type {boolean} + * @const + */ +Blockly.FieldColour.prototype.SERIALIZABLE = true; + /** * Array of colours used by this field. If null, use the global list. * @type {Array.} @@ -137,7 +143,7 @@ Blockly.FieldColour.prototype.initView = function() { this.borderRect_.style['fillOpacity'] = 1; this.borderRect_.setAttribute('width', this.size_.width + Blockly.BlockSvg.SEP_SPACE_X); - this.setValue(this.getValue()); + this.borderRect_.style.fill = this.value_; }; /** @@ -154,42 +160,44 @@ Blockly.FieldColour.prototype.dispose = function() { }; /** - * Colour fields are fixed with, no need to update. + * Render the colour field. + * @private */ -Blockly.FieldColour.prototype.updateWidth = function() { - // NOP +Blockly.FieldColour.prototype.render_ = function() { + this.size_.width = Blockly.FieldColour.DEFAULT_WIDTH; }; /** - * Return the current colour. - * @return {string} Current colour in '#rrggbb' format. + * Ensure that the input value is a valid colour. + * @param {string=} newValue The input value. + * @return {?string} A valid colour, or null if invalid. + * @protected */ -Blockly.FieldColour.prototype.getValue = function() { - return this.colour_; +Blockly.FieldColour.prototype.doClassValidation_ = function(newValue) { + if (Blockly.FieldColour.COLOUR_REGEX.test(newValue)) { + return newValue.toLowerCase(); + } + return null; }; /** - * Set the colour. - * @param {string} colour The new colour in '#rrggbb' format. + * Update the value of this colour field, and update the displayed colour. + * @param {string} newValue The new colour in '#rrggbb' format. + * @protected */ -Blockly.FieldColour.prototype.setValue = function(colour) { - if (this.sourceBlock_ && Blockly.Events.isEnabled() && - this.colour_ != colour) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.sourceBlock_, 'field', this.name, this.colour_, colour)); - } - this.colour_ = colour; +Blockly.FieldColour.prototype.doValueUpdate_ = function(newValue) { + this.value_ = newValue; if (this.borderRect_) { - this.borderRect_.style.fill = colour; + this.borderRect_.style.fill = newValue; } }; /** - * Get the text from this field. Used when the block is collapsed. - * @return {string} Current text. + * Get the text for this field. Used when the block is collapsed. + * @return {string} Text representing the value of this field. */ Blockly.FieldColour.prototype.getText = function() { - var colour = this.colour_; + var colour = this.value_; // Try to use #rgb format if possible, rather than #rrggbb. var m = colour.match(/^#(.)\1(.)\2(.)\3$/); if (m) { diff --git a/core/field_date.js b/core/field_date.js index 7cbe31a16f4..c71d0d743fd 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -40,21 +40,20 @@ goog.require('goog.ui.DatePicker'); /** * Class for a date input field. - * @param {string=} opt_date The initial date, defaults to the current day. - * @param {Function=} opt_validator A function that is executed when a new - * date is selected. Its sole argument is the new date value. Its - * return value becomes the selected date, unless it is undefined, in - * which case the new date stands, or it is null, in which case the change - * is aborted. + * @param {string=} opt_value The initial value of the field. Should be in + * 'YYYY-MM-DD' format. Defaults to the current date. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a date string & returns a + * validated date string ('YYYY-MM-DD' format), or null to abort the change. * @extends {Blockly.Field} * @constructor */ -Blockly.FieldDate = function(opt_date, opt_validator) { - if (!opt_date) { - opt_date = new goog.date.Date().toIsoString(true); +Blockly.FieldDate = function(opt_value, opt_validator) { + opt_value = this.doClassValidation_(opt_value); + if (!opt_value) { + opt_value = new goog.date.Date().toIsoString(true); } - Blockly.FieldDate.superClass_.constructor.call(this, opt_date, opt_validator); - this.setValue(opt_date); + Blockly.FieldDate.superClass_.constructor.call(this, opt_value, opt_validator); }; goog.inherits(Blockly.FieldDate, Blockly.Field); @@ -91,28 +90,21 @@ Blockly.FieldDate.prototype.dispose = function() { }; /** - * Return the current date. - * @return {string} Current date. + * Ensure that the input value is a valid date. + * @param {string=} newValue The input value. + * @return {?string} A valid date, or null if invalid. + * @protected */ -Blockly.FieldDate.prototype.getValue = function() { - return this.date_; -}; - -/** - * Set the date. - * @param {string} date The new date. - */ -Blockly.FieldDate.prototype.setValue = function(date) { - if (this.sourceBlock_) { - var validated = this.callValidator(date); - // If the new date is invalid, validation returns null. - // In this case we still want to display the illegal result. - if (validated !== null) { - date = validated; - } +Blockly.FieldDate.prototype.doClassValidation_ = function(newValue) { + if (!newValue) { + return null; + } + // Check if the new value is parsable or not. + var date = goog.date.Date.fromIsoString(newValue); + if (!date || date.toIsoString(true) != newValue) { + return null; } - this.date_ = date; - Blockly.Field.prototype.setText.call(this, date); + return newValue; }; /** @@ -142,10 +134,6 @@ Blockly.FieldDate.prototype.showEditor_ = function() { function(event) { var date = event.date ? event.date.toIsoString(true) : ''; Blockly.WidgetDiv.hide(); - if (thisField.sourceBlock_) { - // Call any validation function, and allow it to override. - date = thisField.callValidator(date); - } thisField.setValue(date); }); }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index cbfded728c9..821ad3b68db 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -42,11 +42,10 @@ goog.require('goog.ui.MenuItem'); * Class for an editable dropdown field. * @param {(!Array.|!Function)} menuGenerator An array of options * for a dropdown list, or a function which generates these options. - * @param {Function=} opt_validator A function that is executed when a new - * option is selected, with the newly selected value as its sole argument. - * If it returns a value, that value (which must be one of the options) will - * become selected in place of the newly selected option, unless the return - * value is null, in which case the change is aborted. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a language-neutral dropdown + * option & returns a validated language-neutral dropdown option, or null to + * abort the change. * @extends {Blockly.Field} * @constructor */ @@ -105,13 +104,6 @@ Blockly.FieldDropdown.ARROW_CHAR = */ Blockly.FieldDropdown.prototype.CURSOR = 'default'; -/** - * Language-neutral currently selected string or image object. - * @type {string|!Object} - * @protected - */ -Blockly.FieldDropdown.prototype.value_ = ''; - /** * SVG image element if currently selected option is an image, or null. * @type {SVGElement} @@ -276,14 +268,7 @@ Blockly.FieldDropdown.prototype.getAnchorDimensions_ = function() { * @param {!goog.ui.MenuItem} menuItem The MenuItem selected within menu. */ Blockly.FieldDropdown.prototype.onItemSelected = function(menu, menuItem) { - var value = menuItem.getValue(); - if (this.sourceBlock_) { - // Call any validation function, and allow it to override. - value = this.callValidator(value); - } - if (value !== null) { - this.setValue(value); - } + this.setValue(menuItem.getValue()); }; /** @@ -386,32 +371,43 @@ Blockly.FieldDropdown.prototype.getOptions = function() { }; /** - * Get the language-neutral value from this dropdown menu. - * @return {string} Current text. + * Ensure that the input value is a valid language-neutral option. + * @param {string=} newValue The input value. + * @return {?string} A valid language-neutral option, or null if invalid. + * @protected */ -Blockly.FieldDropdown.prototype.getValue = function() { - return this.value_; +Blockly.FieldDropdown.prototype.doClassValidation_ = function(newValue) { + var isValueValid = false; + var options = this.getOptions(); + for (var i = 0, option; option = options[i]; i++) { + // Options are tuples of human-readable text and language-neutral values. + if (option[1] == newValue) { + isValueValid = true; + break; + } + } + if (!isValueValid) { + if (this.sourceBlock_) { + console.warn('Cannot set the dropdown\'s value to an unavailable option.' + + ' Block type: ' + this.sourceBlock_.type + ', Field name: ' + this.name + + ', Value: ' + newValue); + } + return null; + } + return newValue; }; /** - * Set the language-neutral value for this dropdown menu. - * @param {string} newValue New value to set. + * Update the value of this dropdown field. + * @param {string} newValue The new language-enutral value. + * @protected */ -Blockly.FieldDropdown.prototype.setValue = function(newValue) { - if (newValue === null || (newValue === this.value_ && this.text_)) { - return; // No change if null and text_ was initialized. - } - if (this.sourceBlock_ && Blockly.Events.isEnabled()) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.sourceBlock_, 'field', this.name, this.value_, newValue)); - } - this.value_ = newValue; - // Look up and display the human-readable text. +Blockly.FieldDropdown.prototype.doValueUpdate_ = function(newValue) { + Blockly.FieldDropdown.superClass_.doValueUpdate_.call(this, newValue); var options = this.getOptions(); - for (var i = 0; i < options.length; i++) { - // Options are tuples of human-readable text and language-neutral values. - if (options[i][1] == newValue) { - var content = options[i][0]; + for (var i = 0, option; option = options[i]; i++) { + if (option[1] == this.value_) { + var content = option[0]; if (typeof content == 'object') { this.imageJson_ = content; this.text_ = content.alt; @@ -419,15 +415,8 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) { this.imageJson_ = null; this.text_ = content; } - // Always rerender if either the value or the text has changed. - this.forceRerender(); - return; } } - // Value not found. Add it, maybe it will become valid once set - // (like variable names). - this.text_ = newValue; - this.forceRerender(); }; /** diff --git a/core/field_image.js b/core/field_image.js index dda92236407..532543c65c5 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -34,7 +34,7 @@ goog.require('goog.math.Size'); /** * Class for an image on a block. - * @param {string=} src The URL of the image, defaults to an empty string. + * @param {string=} src The URL of the image. Defaults to an empty string. * @param {!(string|number)} width Width of the image. * @param {!(string|number)} height Height of the image. * @param {string=} opt_alt Optional alt text for when block is collapsed. @@ -66,8 +66,8 @@ Blockly.FieldImage = function(src, width, height, this.flipRtl_ = opt_flipRtl; this.tooltip_ = ''; + this.text_ = opt_alt || ''; this.setValue(src || ''); - this.setText(opt_alt || ''); if (typeof opt_onClick == 'function') { this.clickHandler_ = opt_onClick; @@ -111,11 +111,12 @@ Blockly.FieldImage.prototype.initView = function() { 'image', { 'height': this.height_ + 'px', - 'width': this.width_ + 'px' + 'width': this.width_ + 'px', + 'alt': this.text_ }, this.fieldGroup_); - this.setValue(this.src_); - this.setText(this.text_); + this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', + 'xlink:href', this.value_); this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); if (this.tooltip_) { @@ -166,28 +167,28 @@ Blockly.FieldImage.prototype.setTooltip = function(newTip) { }; /** - * Get the source URL of this image. - * @return {string} Current text. - * @override + * Ensure that the input value (the source URL) is a string. + * @param {string=} newValue The input value + * @return {?string} A string, or null if invalid. + * @protected */ -Blockly.FieldImage.prototype.getValue = function() { - return this.src_; +Blockly.FieldImage.prototype.doClassValidation_ = function(newValue) { + if (typeof newValue != 'string') { + return null; + } + return newValue; }; /** - * Set the source URL of this image. - * @param {?string} src New source. - * @override + * Update the value of this image field, and update the displayed image. + * @param {string} newValue The new image src. + * @protected */ -Blockly.FieldImage.prototype.setValue = function(src) { - if (src === null) { - // No change if null. - return; - } - this.src_ = src; +Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) { + this.value_ = newValue; if (this.imageElement_) { this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', - 'xlink:href', src || ''); + 'xlink:href', this.value_ || ''); } }; @@ -220,22 +221,8 @@ Blockly.FieldImage.prototype.setText = function(alt) { * @private */ Blockly.FieldImage.prototype.render_ = function() { - // NOP -}; - -/** - * Images are fixed width, no need to render even if forced. - */ -Blockly.FieldImage.prototype.forceRerender = function() { - // NOP -}; - -/** - * Images are fixed width, no need to update. - * @private - */ -Blockly.FieldImage.prototype.updateWidth = function() { - // NOP + this.size_.width = this.width_; + this.size_.height = this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y; }; /** diff --git a/core/field_label.js b/core/field_label.js index 2db51c03a20..f287964e089 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -36,19 +36,20 @@ goog.require('goog.math.Size'); /** * Class for a non-editable, non-serializable text field. - * @param {string=} text The initial content of the field, defaults to an - * empty string. + * @param {string=} opt_value The initial value of the field. Should cast to a + * string. Defaults to an empty string if null or undefined. * @param {string=} opt_class Optional CSS class for the field's text. * @extends {Blockly.Field} * @constructor */ -Blockly.FieldLabel = function(text, opt_class) { +Blockly.FieldLabel = function(opt_value, opt_class) { this.size_ = new goog.math.Size(0, 17.5); this.class_ = opt_class; - if (text === null || text === undefined) { - text = ''; + opt_value = this.doClassValidation_(opt_value); + if (opt_value === null) { + opt_value = ''; } - this.setValue(String(text)); + this.setValue(opt_value); this.tooltip_ = ''; }; goog.inherits(Blockly.FieldLabel, Blockly.Field); @@ -84,6 +85,8 @@ Blockly.FieldLabel.prototype.initView = function() { 'class': 'blocklyText', 'y': this.size_.height - 5 }, this.fieldGroup_); + var textNode = document.createTextNode(''); + this.textElement_.appendChild(textNode); if (this.class_) { Blockly.utils.addClass(this.textElement_, this.class_); } @@ -107,6 +110,19 @@ Blockly.FieldLabel.prototype.dispose = function() { } }; +/** + * Ensure that the input value casts to a valid string. + * @param {string=} newValue The input value. + * @return {?string} A valid string, or null if invalid. + * @protected + */ +Blockly.FieldLabel.prototype.doClassValidation_ = function(newValue) { + if (newValue === null || newValue === undefined) { + return null; + } + return String(newValue); +}; + /** * Change the tooltip text for this field. * @param {string|!Element} newTip Text for tooltip or a parent element to diff --git a/core/field_label_serializable.js b/core/field_label_serializable.js index b8f579f7f2a..833a4c61dcd 100644 --- a/core/field_label_serializable.js +++ b/core/field_label_serializable.js @@ -33,14 +33,15 @@ goog.require('Blockly.utils'); /** * Class for a non-editable, serializable text field. - * @param {!string} text The initial content of the field. + * @param {*} opt_value The initial value of the field. Should cast to a + * string. Defaults to an empty string if null or undefined. * @param {string=} opt_class Optional CSS class for the field's text. * @extends {Blockly.FieldLabel} * @constructor * */ -Blockly.FieldLabelSerializable = function(text, opt_class) { - Blockly.FieldLabelSerializable.superClass_.constructor.call(this, text, +Blockly.FieldLabelSerializable = function(opt_value, opt_class) { + Blockly.FieldLabelSerializable.superClass_.constructor.call(this, opt_value, opt_class); }; goog.inherits(Blockly.FieldLabelSerializable, Blockly.FieldLabel); diff --git a/core/field_number.js b/core/field_number.js index 10e0efdf03c..636621aca80 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -31,22 +31,23 @@ goog.require('Blockly.FieldTextInput'); /** * Class for an editable number field. - * @param {(string|number)=} opt_value The initial content of the field. - * The value should cast to a number, and if it does not, '0' will be used. + * @param {string|number=} opt_value The initial value of the field. Should cast + * to a number. Defaults to 0. * @param {(string|number)=} opt_min Minimum value. * @param {(string|number)=} opt_max Maximum value. * @param {(string|number)=} opt_precision Precision for value. - * @param {Function=} opt_validator An optional function that is called - * to validate any constraints on what the user entered. Takes the new - * text as an argument and returns either the accepted text, a replacement - * text, or null to abort the change. - * @extends {Blockly.FieldTextInput} + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a number & returns a validated + * number, or null to abort the change. * @constructor */ Blockly.FieldNumber = function(opt_value, opt_min, opt_max, opt_precision, opt_validator) { this.setConstraints(opt_min, opt_max, opt_precision); - opt_value = (opt_value && !isNaN(opt_value)) ? String(opt_value) : '0'; + opt_value = this.doClassValidation_(opt_value); + if (opt_value === null) { + opt_value = 0; + } Blockly.FieldNumber.superClass_.constructor.call( this, opt_value, opt_validator); }; @@ -98,21 +99,26 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) { }; /** - * Ensure that only a number in the correct range may be entered. - * @param {string} text The user's text. - * @return {?string} A string representing a valid number, or null if invalid. + * Ensure that the input value is a valid number (must fulfill the + * constraints placed on the field). + * @param {string|number=} newValue The input value. + * @return {?number} A valid number, or null if invalid. + * @protected */ -Blockly.FieldNumber.prototype.classValidator = function(text) { - if (text === null) { +Blockly.FieldNumber.prototype.doClassValidation_ = function(newValue) { + if (newValue === null || newValue === undefined) { return null; } - text = String(text); + // Clean up text. + newValue = String(newValue); // TODO: Handle cases like 'ten', '1.203,14', etc. // 'O' is sometimes mistaken for '0' by inexperienced users. - text = text.replace(/O/ig, '0'); + newValue = newValue.replace(/O/ig, '0'); // Strip out thousands separators. - text = text.replace(/,/g, ''); - var n = parseFloat(text || 0); + newValue = newValue.replace(/,/g, ''); + + // Clean up number. + var n = parseFloat(newValue || 0); if (isNaN(n)) { // Invalid number. return null; @@ -123,8 +129,10 @@ Blockly.FieldNumber.prototype.classValidator = function(text) { if (this.precision_ && isFinite(n)) { n = Math.round(n / this.precision_) * this.precision_; } - return (this.fractionalDigits_ == -1) ? String(n) : - n.toFixed(this.fractionalDigits_); + // Clean up floating point errors. + n = (this.fractionalDigits_ == -1) ? n : + Number(n.toFixed(this.fractionalDigits_)); + return n; }; Blockly.Field.register('field_number', Blockly.FieldNumber); diff --git a/core/field_textinput.js b/core/field_textinput.js index 088a28109af..717f9113e0b 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -37,20 +37,20 @@ goog.require('goog.math.Coordinate'); /** * Class for an editable text field. - * @param {string=} text The initial content of the field, defaults to an - * empty string. - * @param {Function=} opt_validator An optional function that is called - * to validate any constraints on what the user entered. Takes the new - * text as an argument and returns either the accepted text, a replacement - * text, or null to abort the change. + * @param {string=} opt_value The initial value of the field. Should cast to a + * string. Defaults to an empty string if null or undefined. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a string & returns a validated + * string, or null to abort the change. * @extends {Blockly.Field} * @constructor */ -Blockly.FieldTextInput = function(text, opt_validator) { - if (text === null || text === undefined) { - text = ''; +Blockly.FieldTextInput = function(opt_value, opt_validator) { + opt_value = this.doClassValidation_(opt_value); + if (opt_value === null) { + opt_value = ''; } - Blockly.FieldTextInput.superClass_.constructor.call(this, String(text), + Blockly.FieldTextInput.superClass_.constructor.call(this, opt_value, opt_validator); }; goog.inherits(Blockly.FieldTextInput, Blockly.Field); @@ -114,43 +114,75 @@ Blockly.FieldTextInput.prototype.dispose = function() { }; /** - * Set the value of this field. - * @param {?string} newValue New value. - * @override + * Ensure that the input value casts to a valid string. + * @param {string=} newValue The input value. + * @return {?string} A valid string, or null if invalid. + * @protected + */ +Blockly.FieldTextInput.prototype.doClassValidation_ = function(newValue) { + if (newValue === null || newValue === undefined) { + return null; + } + return String(newValue); +}; + +/** + * Called by setValue if the text input is not valid. If the field is + * currently being edited it reverts value of the field to the previous + * value while allowing the display text to be handled by the htmlInput_. + * @protected */ -Blockly.FieldTextInput.prototype.setValue = function(newValue) { - if (newValue !== null) { // No change if null. - if (this.sourceBlock_) { - var validated = this.callValidator(newValue); - // If the new value is invalid, validation returns null. - // In this case we still want to display the illegal result. - if (validated !== null) { - newValue = validated; +Blockly.FieldTextInput.prototype.doValueInvalid_ = function() { + if (this.isBeingEdited_) { + this.isTextValid_ = false; + var htmlInput = Blockly.FieldTextInput.htmlInput_; + if (htmlInput) { + var oldValue = this.value_; + // Revert value when the text becomes invalid. + this.value_ = htmlInput.untypedDefaultValue_; + if (this.sourceBlock_ && Blockly.Events.isEnabled()) { + Blockly.Events.fire(new Blockly.Events.BlockChange( + this.sourceBlock_, 'field', this.name, oldValue, this.value_)); } } - Blockly.Field.prototype.setValue.call(this, newValue); } }; /** - * Set the text in this field and fire a change event. - * @param {*} newText New text. + * Called by setValue if the text input is valid. Updates the value of the + * field, and updates the text of the field if it is not currently being + * edited (i.e. handled by the htmlInput_). + * @param {!string} newValue The new validated value of the field. + * @protected */ -Blockly.FieldTextInput.prototype.setText = function(newText) { - if (newText === null) { - // No change if null. - return; - } - newText = String(newText); - if (newText === this.text_) { - // No change. - return; +Blockly.FieldTextInput.prototype.doValueUpdate_ = function(newValue) { + this.isTextValid_ = true; + this.value_ = newValue; + if (!this.isBeingEdited_) { + // This should only occur if setValue is triggered programmatically. + this.text_ = String(newValue); + this.isDirty_ = true; } - if (this.sourceBlock_ && Blockly.Events.isEnabled()) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.sourceBlock_, 'field', this.name, this.text_, newText)); +}; + +/** + * Updates the colour of the htmlInput given the current validity of the + * field's value. + * @protected + */ +Blockly.FieldTextInput.prototype.render_ = function() { + Blockly.FieldTextInput.superClass_.render_.call(this); + // This logic is done in render_ rather than doValueInvalid_ or + // doValueUpdate_ so that the code is more centralized. + if (this.isBeingEdited_) { + var htmlInput = Blockly.FieldTextInput.htmlInput_; + this.resizeEditor_(); + if (!this.isTextValid_) { + Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput'); + } else { + Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput'); + } } - Blockly.Field.prototype.setText.call(this, newText); }; /** @@ -188,9 +220,6 @@ Blockly.FieldTextInput.prototype.showPromptEditor_ = function() { var fieldText = this; Blockly.prompt(Blockly.Msg['CHANGE_VALUE_TITLE'], this.text_, function(newValue) { - if (fieldText.sourceBlock_) { - newValue = fieldText.callValidator(newValue); - } fieldText.setValue(newValue); }); }; @@ -202,8 +231,13 @@ Blockly.FieldTextInput.prototype.showPromptEditor_ = function() { * @private */ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { + // Start editing. + this.isBeingEdited_ = true; + + // Show the div. Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_()); var div = Blockly.WidgetDiv.DIV; + // Create the input. var htmlInput = document.createElement('input'); htmlInput.className = 'blocklyHtmlInput'; @@ -212,20 +246,25 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; - - Blockly.FieldTextInput.htmlInput_ = htmlInput; div.appendChild(htmlInput); - htmlInput.value = htmlInput.defaultValue = this.text_; + // Assign the current value to the input & resize. + htmlInput.value = htmlInput.defaultValue = this.value_; + htmlInput.untypedDefaultValue_ = this.value_; htmlInput.oldValue_ = null; - this.validate_(); this.resizeEditor_(); + + // Give it focus. if (!quietInput) { htmlInput.focus(); htmlInput.select(); } + // Bind events. this.bindEvents_(htmlInput); + + // Save it. + Blockly.FieldTextInput.htmlInput_ = htmlInput; }; /** @@ -239,7 +278,7 @@ Blockly.FieldTextInput.prototype.bindEvents_ = function(htmlInput) { htmlInput.onKeyDownWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'keydown', this, this.onHtmlInputKeyDown_); - // Bind to keyup -- trap Enter; resize after every keystroke. + // Bind to keyup -- resize after every keystroke. htmlInput.onKeyUpWrapper_ = Blockly.bindEventWithChecks_( htmlInput, 'keyup', this, this.onHtmlInputChange_); @@ -294,7 +333,6 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) { */ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { var htmlInput = Blockly.FieldTextInput.htmlInput_; - // Update source block. var text = htmlInput.value; if (text !== htmlInput.oldValue_) { htmlInput.oldValue_ = text; @@ -304,40 +342,15 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { // broader fix for all field types. Blockly.Events.setGroup(true); this.setValue(text); + // Always render the input text. + this.text_ = Blockly.FieldTextInput.htmlInput_.value; + this.forceRerender(); Blockly.Events.setGroup(false); - this.validate_(); - } else if (Blockly.userAgent.WEBKIT) { - // Cursor key. Render the source block to show the caret moving. - // Chrome only (version 26, OS X). - this.sourceBlock_.render(); } - this.resizeEditor_(); - Blockly.svgResize(this.sourceBlock_.workspace); }; /** - * Check to see if the contents of the editor validates. - * Style the editor accordingly. - * @protected - */ -Blockly.FieldTextInput.prototype.validate_ = function() { - var valid = true; - if (!Blockly.FieldTextInput.htmlInput_) { - throw Error('htmlInput not defined'); - } - var htmlInput = Blockly.FieldTextInput.htmlInput_; - if (this.sourceBlock_) { - valid = this.callValidator(htmlInput.value); - } - if (valid === null) { - Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput'); - } else { - Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput'); - } -}; - -/** - * Resize the editor and the underlying block to fit the text. + * Resize the editor to fit the text. * @protected */ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { @@ -376,12 +389,30 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() { var thisField = this; return function() { var htmlInput = Blockly.FieldTextInput.htmlInput_; - // Save the edit (if it validates). - thisField.maybeSaveEdit_(); + // Finalize value. + thisField.isBeingEdited_ = false; + // No need to call setValue because if the widget is being closed the + // latest input text has already been validated. + if (thisField.value_ != thisField.text_) { + // At the end of an edit the text should be the same as the value. It + // may not be if the input text is different than the validated text. + // We should fix that. + thisField.text_ = String(thisField.value_); + thisField.isTextValid_ = true; + thisField.forceRerender(); + } + // Otherwise don't rerender. + + // Call onFinishEditing + // TODO: Get rid of this or make it less of a hack. + if (thisField.onFinishEditing_) { + thisField.onFinishEditing_(thisField.value_); + } + + // Remove htmlInput. thisField.unbindEvents_(htmlInput); Blockly.FieldTextInput.htmlInput_ = null; - Blockly.Events.setGroup(false); // Delete style properties. var style = Blockly.WidgetDiv.DIV.style; @@ -391,36 +422,11 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() { }; }; -/** - * Attempt to save the text field changes when the user input loses focus. - * If the value is not valid, revert to the default value. - * @private - */ -Blockly.FieldTextInput.prototype.maybeSaveEdit_ = function() { - var htmlInput = Blockly.FieldTextInput.htmlInput_; - // Save the edit (if it validates). - var text = htmlInput.value; - if (this.sourceBlock_) { - var text1 = this.callValidator(text); - if (text1 === null) { - // Invalid edit. - text = htmlInput.defaultValue; - } else { - // Validation function has changed the text. - text = text1; - if (this.onFinishEditing_) { - this.onFinishEditing_(text); - } - } - } - this.setText(text); - this.sourceBlock_.rendered && this.sourceBlock_.render(); -}; - /** * Ensure that only a number may be entered. * @param {string} text The user's text. * @return {?string} A string representing a valid number, or null if invalid. + * @deprecated */ Blockly.FieldTextInput.numberValidator = function(text) { console.warn('Blockly.FieldTextInput.numberValidator is deprecated. ' + @@ -442,6 +448,7 @@ Blockly.FieldTextInput.numberValidator = function(text) { * Ensure that only a nonnegative integer may be entered. * @param {string} text The user's text. * @return {?string} A string representing a valid int, or null if invalid. + * @deprecated */ Blockly.FieldTextInput.nonnegativeIntegerValidator = function(text) { var n = Blockly.FieldTextInput.numberValidator(text); diff --git a/core/field_variable.js b/core/field_variable.js index 6c5561a7f86..5b2fc7d2b9f 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -39,8 +39,9 @@ goog.require('goog.math.Size'); * Class for a variable's dropdown field. * @param {?string} varname The default name for the variable. If null, * a unique variable name will be generated. - * @param {Function=} opt_validator A function that is executed when a new - * option is selected. Its sole argument is the new option value. + * @param {Function=} opt_validator A function that is called to validate + * changes to the field's value. Takes in a variable ID & returns a + * validated variable ID, or null to abort the change. * @param {Array.=} opt_variableTypes A list of the types of variables * to include in the dropdown. * @param {string=} opt_defaultType The type of variable to create if this @@ -78,6 +79,13 @@ Blockly.FieldVariable.fromJson = function(options) { return new Blockly.FieldVariable(varname, null, variableTypes, defaultType); }; +/** + * The workspace that this variable field belongs to. + * @type {?Blockly.Workspace} + * @private + */ +Blockly.FieldVariable.prototype.workspace_ = null; + /** * Serializable fields are saved by the XML renderer, non-serializable fields * are not. Editable fields should also be serializable. @@ -96,28 +104,28 @@ Blockly.FieldVariable.prototype.initModel = function() { if (this.variable_) { return; // Initialization already happened. } - this.workspace_ = this.sourceBlock_.workspace; var variable = Blockly.Variables.getOrCreateVariablePackage( this.workspace_, null, this.defaultVariableName, this.defaultType_); // Don't fire a change event for this setValue. It would have null as the // old value, which is not valid. Blockly.Events.disable(); - try { - this.setValue(variable.getId()); - } finally { - Blockly.Events.enable(); - } + this.setValue(variable.getId()); + Blockly.Events.enable(); }; +/** + * Initialize this field based on the given XML. + * @param {!Element} fieldElement The element containing information about the + * variable field's state. + */ Blockly.FieldVariable.prototype.fromXml = function(fieldElement) { var id = fieldElement.getAttribute('id'); var variableName = fieldElement.textContent; var variableType = fieldElement.getAttribute('variabletype') || ''; var variable = Blockly.Variables.getOrCreateVariablePackage( - this.workspace_ || this.sourceBlock_.workspace, id, - variableName, variableType); + this.workspace_, id, variableName, variableType); // This should never happen :) if (variableType != null && variableType !== variable.type) { @@ -130,6 +138,12 @@ Blockly.FieldVariable.prototype.fromXml = function(fieldElement) { this.setValue(variable.getId()); }; +/** + * Serialize this field to Xml. + * @param {!Element} fieldElement The element to populate with info about the + * field's state. + * @return {!Element} The element containing info about the field's state. + */ Blockly.FieldVariable.prototype.toXml = function(fieldElement) { // Make sure the variable is initialized. this.initModel(); @@ -160,6 +174,7 @@ Blockly.FieldVariable.prototype.setSourceBlock = function(block) { throw Error('Variable fields are not allowed to exist on shadow blocks.'); } Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block); + this.workspace_ = block.workspace; }; /** @@ -192,30 +207,57 @@ Blockly.FieldVariable.prototype.getVariable = function() { }; /** - * Set the variable ID. - * @param {string} id New variable ID, which must reference an existing - * variable. + * Gets the validation function for this field, or null if not set. + * Returns null if the variable is not set, because validators should not + * run on the initial setValue call, because the field won't be attached to + * a block and workspace at that point. + * @return {Function} Validation function, or null. */ -Blockly.FieldVariable.prototype.setValue = function(id) { - var workspace = this.sourceBlock_.workspace; - var variable = Blockly.Variables.getVariable(workspace, id); +Blockly.FieldVariable.prototype.getValidator = function() { + // Validators shouldn't operate on the initial setValue call. + // Normally this is achieved by calling setValidator after setValue, but + // this is not a possibility with variable fields. + if (this.variable_) { + return this.validator_; + } + return null; +}; +/** + * Ensure that the id belongs to a valid variable of an allowed type. + * @param {string} newId The id of the new variable to set. + * @return {?string} The validated id, or null if invalid. + * @protected + */ +Blockly.FieldVariable.prototype.doClassValidation_ = function(newId) { + var variable = Blockly.Variables.getVariable(this.workspace_, newId); if (!variable) { - throw Error('Variable id doesn\'t point to a real variable! ID was ' + id); + console.warn('Variable id doesn\'t point to a real variable! ' + + 'ID was ' + newId); + return null; } - // Type checks! + // Type Checks. var type = variable.type; if (!this.typeIsAllowed_(type)) { - throw Error('Variable type doesn\'t match this field! Type was ' + type); + console.warn('Variable type doesn\'t match this field! Type was ' + type); + return null; } - if (this.sourceBlock_ && Blockly.Events.isEnabled()) { - var oldValue = this.variable_ ? this.variable_.getId() : null; - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.sourceBlock_, 'field', this.name, oldValue, id)); - } - this.variable_ = variable; - this.value_ = id; - this.setText(variable.name); + return newId; +}; + +/** + * Update the value of this variable field, as well as its variable and text. + * + * The variable ID should be valid at this point, but if a variable field + * validator returns a bad ID, this could break. + * @param {string} newId The id of the new variable. + * @protected + */ +Blockly.FieldVariable.prototype.doValueUpdate_ = function(newId) { + this.variable_ = Blockly.Variables.getVariable(this.workspace_, newId); + this.value_ = newId; + this.text_ = (this.variable_.name); + this.isDirty_ = true; }; /** @@ -248,9 +290,8 @@ Blockly.FieldVariable.prototype.getVariableTypes_ = function() { var variableTypes = this.variableTypes; if (variableTypes === null) { // If variableTypes is null, return all variable types. - if (this.sourceBlock_) { - var workspace = this.sourceBlock_.workspace; - return workspace.getVariableTypes(); + if (this.workspace_) { + return this.workspace_.getVariableTypes(); } } variableTypes = variableTypes || ['']; @@ -315,18 +356,14 @@ Blockly.FieldVariable.dropdownCreate = function() { ' variable selected.'); } var name = this.getText(); - var workspace = null; - if (this.sourceBlock_) { - workspace = this.sourceBlock_.workspace; - } var variableModelList = []; - if (workspace) { + if (this.workspace_) { var variableTypes = this.getVariableTypes_(); // Get a copy of the list, so that adding rename and new variable options // doesn't modify the workspace's list. for (var i = 0; i < variableTypes.length; i++) { var variableType = variableTypes[i]; - var variables = workspace.getVariablesOfType(variableType); + var variables = this.workspace_.getVariablesOfType(variableType); variableModelList = variableModelList.concat(variables); } } @@ -359,20 +396,19 @@ Blockly.FieldVariable.dropdownCreate = function() { */ Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) { var id = menuItem.getValue(); - if (this.sourceBlock_ && this.sourceBlock_.workspace) { - var workspace = this.sourceBlock_.workspace; + // Handle special cases. + if (this.workspace_) { if (id == Blockly.RENAME_VARIABLE_ID) { // Rename variable. - Blockly.Variables.renameVariable(workspace, this.variable_); + Blockly.Variables.renameVariable(this.workspace_, this.variable_); return; } else if (id == Blockly.DELETE_VARIABLE_ID) { // Delete variable. - workspace.deleteVariableById(this.variable_.getId()); + this.workspace_.deleteVariableById(this.variable_.getId()); return; } - - // TODO (#1529): Call any validation function, and allow it to override. } + // Handle unspecial case. this.setValue(id); }; diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index 1d5b47b0f54..cc7ca7124fe 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -263,6 +263,21 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT "tooltip": "", "helpUrl": "" }, + { + "type": "test_fields_image", + "message0": "image %1", + "args0": [ + { + "type": "field_image", + "name": "IMAGE", + "src": "https://blockly-demo.appspot.com/static/tests/media/a.png", + "width": 32, + "height": 32, + "alt": "A" + } + ], + "colour": 230 + }, { "type": "test_numbers_float", "message0": "float %1", @@ -670,6 +685,420 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT } ]); // END JSON EXTRACT (Do not delete this comment.) +Blockly.Blocks['test_validators_text_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldTextInput("default", this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All input validates to null (invalid). The display' + + ' text will remain the input text, but the value should be the default' + + ' text. The input should be red after the first keystroke.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_text_A'] = { + init: function() { + this.appendDummyInput() + .appendField("remove \'a\'") + .appendField(new Blockly.FieldTextInput("default", this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All \'a\' characters are removed from field value.' + + ' The display text will include invalid \'a\' characters while the' + + ' field is being edited, but the value will not.'); + }, + + validate: function(newValue) { + return newValue.replace(/\a/g, ''); + } +}; +Blockly.Blocks['test_validators_text_B'] = { + init: function() { + this.appendDummyInput() + .appendField("\'b\' -> null") + .appendField(new Blockly.FieldTextInput("default", this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('Upon detecting a \'b\' character the input will' + + ' validated to null (invalid). Upon removal it should revert to being' + + ' valid. The display text will remain the input text, but if the input' + + ' text is invalid the value should be the default text.'); + }, + + validate: function(newValue) { + if (newValue.indexOf('b') != -1) { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_angle_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldAngle(90, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All input validates to null (invalid). The field' + + ' will display the input while the field is being edited (this' + + ' includes the text and the graphic), but the value should be the' + + ' default value. The input should be red after the first' + + ' keystroke.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_angle_mult30_force'] = { + init: function() { + this.appendDummyInput() + .appendField("force mult of 30") + .appendField(new Blockly.FieldAngle(90, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The input value will be rounded to the nearest' + + ' multiple of 30. The field will display the input while the field is' + + ' being edited (this includes the text and the graphic), but the value' + + ' will be the validated (rounded) value. Note: If you want to do' + + ' rounding this is not the proper way, use the ROUND property of the' + + ' field angle instead.'); + }, + + validate: function(newValue) { + return Math.round(newValue / 30) * 30; + } +}; +Blockly.Blocks['test_validators_angle_mult30_null'] = { + init: function() { + this.appendDummyInput() + .appendField("not mult of 30 -> null") + .appendField(new Blockly.FieldAngle(90, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('If the input value is not a multiple of 30, the' + + ' input will validated to null (invalid). The field will display the' + + ' input while the field is being edited (this includes the text and' + + ' the graphic), but if the input value is invalid the value should be' + + ' the default value.'); + }, + + validate: function(newValue) { + if (newValue % 30 != 0) { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_checkbox_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldCheckbox(true, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The new input always validates to null (invalid).' + + ' This means that the field value should not change.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_checkbox_match'] = { + init: function() { + this.appendDummyInput() + .appendField("force match") + .appendField(new Blockly.FieldCheckbox(true), "MATCH") + .appendField(new Blockly.FieldCheckbox(true, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The validator for this block only works on the' + + ' end-most checkbox. The validator will always return the value of the' + + ' start-most checkbox. Therefor they should always match.') + }, + + validate: function(newValue) { + return this.sourceBlock_.getFieldValue('MATCH'); + } +}; +Blockly.Blocks['test_validators_checkbox_not_match_null'] = { + init: function() { + this.appendDummyInput() + .appendField("not match -> null") + .appendField(new Blockly.FieldCheckbox(true), "MATCH") + .appendField(new Blockly.FieldCheckbox(true, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The validator for this block only works on the' + + ' end-most checkbox. If the new value does not match the value of the' + + ' start-most checkbox, it will return null (invalid), which means the' + + ' field value should not change. Therfore they should always match.'); + }, + + validate: function(newValue) { + if (this.sourceBlock_.getFieldValue('MATCH') != newValue) { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_colour_null'] = { + init: function() { + var colourField = new Blockly.FieldColour('#ff0000', this.validate); + colourField.setColours([ + '#ffffff', '#ffdcdc', '#ffb4b4','#ff8c8c','#ff6464','#ff3c3c','#ff1414', + '#00ffff', '#00dcdc', '#00b4b4','#008c8c','#006464','#003c3c','#001414']); + + this.appendDummyInput() + .appendField("always null") + .appendField(colourField, "INPUT"); + this.setColour(230); + this.setCommentText('All input validates to null (invalid). This means' + + ' the field value should not change.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_colour_force_red'] = { + init: function() { + var colourField = new Blockly.FieldColour('#ff0000', this.validate); + colourField.setColours([ + '#ffffff', '#ffdcdc', '#ffb4b4','#ff8c8c','#ff6464','#ff3c3c','#ff1414', + '#00ffff', '#00dcdc', '#00b4b4','#008c8c','#006464','#003c3c','#001414']); + + this.appendDummyInput() + .appendField("force full red") + .appendField(colourField, "INPUT"); + this.setColour(230); + this.setCommentText('The input will have its red value replaced with' + + ' full red.'); + }, + + validate: function(newValue) { + return '#ff' + newValue.substr(3, 4); + } +}; +Blockly.Blocks['test_validators_colour_red_null'] = { + init: function() { + var colourField = new Blockly.FieldColour('#ff0000', this.validate); + colourField.setColours([ + '#ffffff', '#ffdcdc', '#ffb4b4','#ff8c8c','#ff6464','#ff3c3c','#ff1414', + '#00ffff', '#00dcdc', '#00b4b4','#008c8c','#006464','#003c3c','#001414']); + + this.appendDummyInput() + .appendField("not red -> null") + .appendField(colourField, "INPUT"); + this.setColour(230); + this.setCommentText('If the input does not have full red, the input will' + + ' validate to null (invalid). Otherwise it will return the input value'); + }, + + validate: function(newValue) { + if (newValue.substr(1, 2) != 'ff') { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_date_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldDate("2020-02-20", this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All input validates to null (invalid). This means' + + ' the field value should not change.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_date_force_20s'] = { + init: function() { + this.appendDummyInput() + .appendField("force day 20s") + .appendField(new Blockly.FieldDate("2020-02-20", this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The input\'s date will change to always be in the' + + ' 20s.'); + }, + + validate: function(newValue) { + return newValue.substr(0, 8) + '2' + newValue.substr(9, 1); + } +}; +Blockly.Blocks['test_validators_date_20s_null'] = { + init: function() { + this.appendDummyInput() + .appendField("not 20s -> null") + .appendField(new Blockly.FieldDate("2020-02-20", this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('If the input is not in the 20s, the input will' + + ' validate to null (invalid). Otherwise it will return the input value.'); + }, + + validate: function(newValue) { + if (newValue.charAt(8) != '2') { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_dropdown_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldDropdown([ + ["1a","1A"], ["1b","1B"], ["1c","1C"], + ["2a","2A"], ["2b","2B"], ["2c","2C"]], this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All input validates to null (invalid). This means' + + ' the field value should not change.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_dropdown_force_1s'] = { + init: function() { + this.appendDummyInput() + .appendField("force 1s") + .appendField(new Blockly.FieldDropdown([ + ["1a","1A"], ["1b","1B"], ["1c","1C"], + ["2a","2A"], ["2b","2B"], ["2c","2C"]], this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The input\'s value will always change to start with' + + ' 1.'); + }, + + validate: function(newValue) { + return '1' + newValue.charAt(1); + } +}; +Blockly.Blocks['test_validators_dropdown_1s_null'] = { + init: function() { + this.appendDummyInput() + .appendField("not 1s -> null") + .appendField(new Blockly.FieldDropdown([ + ["1a","1A"], ["1b","1B"], ["1c","1C"], + ["2a","2A"], ["2b","2B"], ["2c","2C"]], this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('If the input does not start with 1, the input will' + + ' validate to null (invalid). Otherwise it will return the input value.'); + }, + + validate: function(newValue) { + if (newValue.charAt(0) != '1') { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_number_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldNumber(123, null, null, null, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All input validates to null (invalid). The field' + + ' will display the input while the field is being edited, but the value' + + ' should be the default value. The input should be red after the first' + + ' keystroke.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_number_mult10_force'] = { + init: function() { + this.appendDummyInput() + .appendField("force mult of 10") + .appendField(new Blockly.FieldNumber(123, null, null, null, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('Theinput value will be rounded to the nearest' + + ' multiple of 10. The field will display the input while the field is' + + ' being edited, but the value should be the validated (rounded) value.' + + ' Note: If you want to do rounding this is not the proper way, use the' + + ' precision option of the number field constructor instead.'); + }, + + validate: function(newValue) { + return Math.round(newValue / 10) * 10; + } +}; +Blockly.Blocks['test_validators_number_mult10_null'] = { + init: function() { + this.appendDummyInput() + .appendField("not mult of 10 -> null") + .appendField(new Blockly.FieldNumber(123, null, null, null, this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('If the input value is not a multiple of 10, the' + + ' input will validate to null (invalid). The field will display the' + + ' input while the field is being edited, but if the input value is' + + ' invalid the value should be the default value.'); + }, + + validate: function(newValue) { + if (newValue % 10 != 0) { + return null; + } + return newValue; + } +}; + +Blockly.Blocks['test_validators_variable_null'] = { + init: function() { + this.appendDummyInput() + .appendField("always null") + .appendField(new Blockly.FieldVariable('1a', this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('All ids validate to null (invalid). This means' + + ' the variable should not change.'); + }, + + validate: function(newValue) { + return null; + } +}; +Blockly.Blocks['test_validators_variable_force_1s'] = { + init: function() { + this.appendDummyInput() + .appendField("force 1s") + .appendField(new Blockly.FieldVariable('1a', this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('The id will always change to start with 1.'); + }, + + validate: function(newValue) { + return '1' + newValue.charAt(1); + } +}; +Blockly.Blocks['test_validators_variable_1s_null'] = { + init: function() { + this.appendDummyInput() + .appendField("not 1s -> null") + .appendField(new Blockly.FieldVariable('1a', this.validate), "INPUT"); + this.setColour(230); + this.setCommentText('If the id does not start with 1, the id will' + + ' validate to null (invalid). Otherwise it will return the id.'); + }, + + validate: function(newValue) { + if (newValue.charAt(0) != '1') { + return null; + } + return newValue; + } +}; + Blockly.Blocks['test_basic_empty_with_mutator'] = { init: function() { this.setMutator(new Blockly.Mutator(['math_number'])); diff --git a/tests/jsunit/field_angle_test.js b/tests/jsunit/field_angle_test.js deleted file mode 100644 index 66b6ab009a2..00000000000 --- a/tests/jsunit/field_angle_test.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @license - * Visual Blocks Editor - * - * Copyright 2017 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /** - * @fileoverview Tests for Blockly.FieldAngle - * @author Anm@anm.me (Andrew n marshall) - */ -'use strict'; - -function test_fieldangle_constructor() { - assertEquals(new Blockly.FieldAngle().getValue(), '0'); - assertEquals(new Blockly.FieldAngle(null).getValue(), '0'); - assertEquals(new Blockly.FieldAngle(undefined).getValue(), '0'); - assertEquals(new Blockly.FieldAngle(1).getValue(), '1'); - assertEquals(new Blockly.FieldAngle(1.5).getValue(), '1.5'); - assertEquals(new Blockly.FieldAngle('2').getValue(), '2'); - assertEquals(new Blockly.FieldAngle('2.5').getValue(), '2.5'); - - // Bad values - assertEquals(new Blockly.FieldAngle('bad').getValue(), '0'); - assertEquals(new Blockly.FieldAngle(NaN).getValue(), '0'); -} - -function test_fieldangle_fromJson() { - assertEquals(Blockly.FieldAngle.fromJson({}).getValue(), '0'); - assertEquals(Blockly.FieldAngle.fromJson({ angle: 1 }).getValue(), '1'); -} diff --git a/tests/jsunit/field_number_test.js b/tests/jsunit/field_number_test.js deleted file mode 100644 index 507af7a4b15..00000000000 --- a/tests/jsunit/field_number_test.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @license - * Visual Blocks Editor - * - * Copyright 2017 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /** - * @fileoverview Tests for Blockly.FieldNumber - * @author Anm@anm.me (Andrew n marshall) - */ -'use strict'; - -function test_fieldnumber_constructor() { - // No arguments - var field = new Blockly.FieldNumber(); - assertEquals(field.getValue(), '0'); - assertEquals(field.min_, -Infinity); - assertEquals(field.max_, Infinity); - assertEquals(field.precision_, 0); - - // Numeric values - field = new Blockly.FieldNumber(1); - assertEquals(field.getValue(), '1'); - field = new Blockly.FieldNumber(1.5); - assertEquals(field.getValue(), '1.5'); - - // String value - field = new Blockly.FieldNumber('2'); - assertEquals(field.getValue(), '2'); - field = new Blockly.FieldNumber('2.5'); - assertEquals(field.getValue(), '2.5'); - - // All values - field = new Blockly.FieldNumber( - /* value */ 0, - /* min */ -128, - /* max */ 127, - /* precision */ 1); - assertEquals(field.getValue(), '0'); - assertEquals(field.min_, -128); - assertEquals(field.max_, 127); - assertEquals(field.precision_, 1); - - // Bad value defaults to '0' - field = new Blockly.FieldNumber('bad'); - assertEquals(field.getValue(), '0'); - field = new Blockly.FieldNumber(NaN); - assertEquals(field.getValue(), '0'); -} - -function test_fieldnumber_fromJson() { - assertEquals(Blockly.FieldNumber.fromJson({}).getValue(), '0'); - assertEquals(Blockly.FieldNumber.fromJson({ value: 1 }).getValue(), '1'); - - // All options - var field = Blockly.FieldNumber.fromJson({ - value: 0, - min: -128, - max: 127, - precision: 1 - }); - assertEquals(field.getValue(), '0'); - assertEquals(field.min_, -128); - assertEquals(field.max_, 127); - assertEquals(field.precision_, 1); -} diff --git a/tests/jsunit/field_variable_test.js b/tests/jsunit/field_variable_test.js deleted file mode 100644 index 3f8785cb9bc..00000000000 --- a/tests/jsunit/field_variable_test.js +++ /dev/null @@ -1,237 +0,0 @@ -/** - * @license - * Visual Blocks Editor - * - * Copyright 2017 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - /** - * @fileoverview Tests for Blockly.FieldVariable - * @author marisaleung@google.com (Marisa Leung) - */ -'use strict'; - -goog.require('goog.testing'); -goog.require('goog.testing.MockControl'); - -var workspace; -var mockControl_; - -function fieldVariableTestWithMocks_setUp() { - workspace = new Blockly.Workspace(); - mockControl_ = new goog.testing.MockControl(); -} - -function fieldVariableTestWithMocks_tearDown() { - mockControl_.$tearDown(); - workspace.dispose(); -} - -function fieldVariable_mockBlock(workspace) { - return {'workspace': workspace, 'isShadow': function(){return false;}}; -} - -function fieldVariable_createAndInitField(workspace) { - var fieldVariable = new Blockly.FieldVariable('name1'); - var mockBlock = fieldVariable_mockBlock(workspace); - fieldVariable.setSourceBlock(mockBlock); - // No view to initialize, but the model still needs work. - fieldVariable.initModel(); - return fieldVariable; -} - -function test_fieldVariable_Constructor() { - workspace = new Blockly.Workspace(); - var fieldVariable = new Blockly.FieldVariable('name1'); - // The field does not have a variable until after init() is called. - assertEquals('', fieldVariable.getText()); - workspace.dispose(); -} - -function test_fieldVariable_setValueMatchId() { - // Expect the fieldVariable value to be set to variable name - fieldVariableTestWithMocks_setUp(); - workspace.createVariable('name2', null, 'id2'); - - var fieldVariable = fieldVariable_createAndInitField(workspace); - - var oldId = fieldVariable.getValue(); - var event = new Blockly.Events.BlockChange( - fieldVariable.sourceBlock_, 'field', undefined, oldId, 'id2'); - setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null); - - fieldVariable.setValue('id2'); - assertEquals('name2', fieldVariable.getText()); - assertEquals('id2', fieldVariable.getValue()); - fieldVariableTestWithMocks_tearDown(); -} - -function test_fieldVariable_setValueNoVariable() { - fieldVariableTestWithMocks_setUp(); - - var fieldVariable = fieldVariable_createAndInitField(workspace); - var mockBlock = fieldVariable.sourceBlock_; - mockBlock.isShadow = function() { - return false; - }; - - try { - fieldVariable.setValue('id1'); - // Calling setValue with a variable that doesn't exist throws an error. - fail(); - } catch (e) { - // expected - } finally { - fieldVariableTestWithMocks_tearDown(); - } -} - -function test_fieldVariable_dropdownCreateVariablesExist() { - // Expect that the dropdown options will contain the variables that exist. - workspace = new Blockly.Workspace(); - workspace.createVariable('name1', '', 'id1'); - workspace.createVariable('name2', '', 'id2'); - - var fieldVariable = fieldVariable_createAndInitField(workspace); - - var result_options = Blockly.FieldVariable.dropdownCreate.call( - fieldVariable); - - assertEquals(result_options.length, 3); - isEqualArrays(result_options[0], ['name1', 'id1']); - isEqualArrays(result_options[1], ['name2', 'id2']); - - workspace.dispose(); -} - -function test_fieldVariable_setValueNull() { - // This should no longer create a variable for the selected option. - fieldVariableTestWithMocks_setUp(); - setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['id1', null]); - - var fieldVariable = fieldVariable_createAndInitField(workspace); - try { - fieldVariable.setValue(null); - fail(); - } catch (e) { - // expected - } finally { - fieldVariableTestWithMocks_tearDown(); - } - -} - -function test_fieldVariable_getVariableTypes_undefinedVariableTypes() { - // Expect that since variableTypes is undefined, only type empty string - // will be returned (regardless of what types are available on the workspace). - workspace = new Blockly.Workspace(); - workspace.createVariable('name1', 'type1'); - workspace.createVariable('name2', 'type2'); - - var fieldVariable = new Blockly.FieldVariable('name1'); - var resultTypes = fieldVariable.getVariableTypes_(); - isEqualArrays(resultTypes, ['']); - workspace.dispose(); -} - -function test_fieldVariable_getVariableTypes_givenVariableTypes() { - // Expect that since variableTypes is defined, it will be the return value, - // regardless of what types are available on the workspace. - workspace = new Blockly.Workspace(); - workspace.createVariable('name1', 'type1'); - workspace.createVariable('name2', 'type2'); - - var fieldVariable = new Blockly.FieldVariable( - 'name1', null, ['type1', 'type2'], 'type1'); - var resultTypes = fieldVariable.getVariableTypes_(); - isEqualArrays(resultTypes, ['type1', 'type2']); - assertEquals('Default type was wrong', 'type1', fieldVariable.defaultType_); - workspace.dispose(); -} - -function test_fieldVariable_getVariableTypes_nullVariableTypes() { - // Expect all variable types to be returned. - // The variable does not need to be initialized to do this--it just needs a - // pointer to the workspace. - workspace = new Blockly.Workspace(); - workspace.createVariable('name1', 'type1'); - workspace.createVariable('name2', 'type2'); - - var fieldVariable = new Blockly.FieldVariable('name1'); - var mockBlock = fieldVariable_mockBlock(workspace); - fieldVariable.setSourceBlock(mockBlock); - fieldVariable.variableTypes = null; - - var resultTypes = fieldVariable.getVariableTypes_(); - // The empty string is always one of the options. - isEqualArrays(resultTypes, ['type1', 'type2', '']); - workspace.dispose(); -} - -function test_fieldVariable_getVariableTypes_emptyListVariableTypes() { - // Expect an error to be thrown. - workspace = new Blockly.Workspace(); - workspace.createVariable('name1', 'type1'); - workspace.createVariable('name2', 'type2'); - - var fieldVariable = new Blockly.FieldVariable('name1'); - var mockBlock = fieldVariable_mockBlock(workspace); - fieldVariable.setSourceBlock(mockBlock); - fieldVariable.variableTypes = []; - - try { - fieldVariable.getVariableTypes_(); - fail(); - } catch (e) { - //expected - } finally { - workspace.dispose(); - } -} - -function test_fieldVariable_defaultType_exists() { - var fieldVariable = new Blockly.FieldVariable(null, null, ['b'], 'b'); - assertEquals('The variable field\'s default type should be "b"', - 'b', fieldVariable.defaultType_); -} - -function test_fieldVariable_noDefaultType() { - var fieldVariable = new Blockly.FieldVariable(null); - assertEquals('The variable field\'s default type should be the empty string', - '', fieldVariable.defaultType_); - assertNull('The variable field\'s allowed types should be null', - fieldVariable.variableTypes); -} - -function test_fieldVariable_defaultTypeMismatch() { - try { - var fieldVariable = new Blockly.FieldVariable(null, null, ['a'], 'b'); - fail('Variable field creation should have failed due to an invalid ' + - 'default type'); - } catch (e) { - // expected - } -} - -function test_fieldVariable_defaultTypeMismatch_empty() { - try { - var fieldVariable = new Blockly.FieldVariable(null, null, ['a']); - fail('Variable field creation should have failed due to an invalid ' + - 'default type'); - } catch (e) { - // expected - } -} diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index 18ee34d329c..ccc72d3a48c 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -18,10 +18,7 @@ - - - diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js index de468e48f6c..8059c01c8b6 100644 --- a/tests/mocha/field_angle_test.js +++ b/tests/mocha/field_angle_test.js @@ -127,7 +127,7 @@ suite ('Angle Fields', function() { this.angleField.setValue(undefined); assertValueDefault(this.angleField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.angleField.setValue('bad'); assertValueDefault(this.angleField); }); @@ -164,15 +164,15 @@ suite ('Angle Fields', function() { this.angleField.setValue(null); assertValue(this.angleField, 1); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.angleField.setValue(undefined); assertValue(this.angleField, 1); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.angleField.setValue('bad'); assertValue(this.angleField, 1); }); - test.skip('NaN', function() { + test('NaN', function() { this.angleField.setValue(NaN); assertValue(this.angleField, 1); }); @@ -198,7 +198,7 @@ suite ('Angle Fields', function() { }); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.angleField = new Blockly.FieldAngle(1); Blockly.FieldTextInput.htmlInput_ = Object.create(null); diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js index 0c909df82b1..2ad0bb3a9ab 100644 --- a/tests/mocha/field_checkbox_test.js +++ b/tests/mocha/field_checkbox_test.js @@ -18,7 +18,7 @@ * limitations under the License. */ -suite.skip('Checkbox Fields', function() { +suite('Checkbox Fields', function() { function assertValue(checkboxField, expectedValue, expectedText) { var actualValue = checkboxField.getValue(); var actualText = checkboxField.getText(); diff --git a/tests/mocha/field_colour_test.js b/tests/mocha/field_colour_test.js index 2979bf0caed..507dd836481 100644 --- a/tests/mocha/field_colour_test.js +++ b/tests/mocha/field_colour_test.js @@ -57,11 +57,11 @@ suite ('Colour Fields', function() { var colourField = new Blockly.FieldColour(undefined); assertValueDefault(colourField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { var colourField = new Blockly.FieldColour('bad'); assertValueDefault(colourField); }); - test.skip('#AAAAAA', function() { + test('#AAAAAA', function() { var colourField = new Blockly.FieldColour('#AAAAAA'); assertValue(colourField, '#aaaaaa', '#aaa'); }); @@ -69,7 +69,7 @@ suite ('Colour Fields', function() { var colourField = new Blockly.FieldColour('#aaaaaa'); assertValue(colourField, '#aaaaaa', '#aaa'); }); - test.skip('#AAAA00', function() { + test('#AAAA00', function() { var colourField = new Blockly.FieldColour('#AAAA00'); assertValue(colourField, '#aaaa00', '#aa0'); }); @@ -77,7 +77,7 @@ suite ('Colour Fields', function() { var colourField = new Blockly.FieldColour('#aaaa00'); assertValue(colourField, '#aaaa00', '#aa0'); }); - test.skip('#BCBCBC', function() { + test('#BCBCBC', function() { var colourField = new Blockly.FieldColour('#BCBCBC'); assertValue(colourField, '#bcbcbc', '#bcbcbc'); }); @@ -99,11 +99,11 @@ suite ('Colour Fields', function() { var colourField = new Blockly.FieldColour.fromJson({ colour:undefined }); assertValueDefault(colourField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { var colourField = new Blockly.FieldColour.fromJson({ colour:'bad' }); assertValueDefault(colourField); }); - test.skip('#AAAAAA', function() { + test('#AAAAAA', function() { var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAAAA' }); assertValue(colourField, '#aaaaaa', '#aaa'); }); @@ -111,7 +111,7 @@ suite ('Colour Fields', function() { var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaaaa' }); assertValue(colourField, '#aaaaaa', '#aaa'); }); - test.skip('#AAAA00', function() { + test('#AAAA00', function() { var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAA00' }); assertValue(colourField, '#aaaa00', '#aa0'); }); @@ -119,7 +119,7 @@ suite ('Colour Fields', function() { var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaa00' }); assertValue(colourField, '#aaaa00', '#aa0'); }); - test.skip('#BCBCBC', function() { + test('#BCBCBC', function() { var colourField = Blockly.FieldColour.fromJson({ colour: '#BCBCBC' }); assertValue(colourField, '#bcbcbc', '#bcbcbc'); }); @@ -133,15 +133,15 @@ suite ('Colour Fields', function() { setup(function() { this.colourField = new Blockly.FieldColour(); }); - test.skip('Null', function() { + test('Null', function() { this.colourField.setValue(null); assertValueDefault(this.colourField); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.colourField.setValue(undefined); assertValueDefault(this.colourField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.colourField.setValue('bad'); assertValueDefault(this.colourField); }); @@ -158,15 +158,15 @@ suite ('Colour Fields', function() { setup(function() { this.colourField = new Blockly.FieldColour('#aaaaaa'); }); - test.skip('Null', function() { + test('Null', function() { this.colourField.setValue(null); assertValue(this.colourField, '#aaaaaa', '#aaa'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.colourField.setValue(undefined); assertValue(this.colourField, '#aaaaaa', '#aaa'); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.colourField.setValue('bad'); assertValue(this.colourField, '#aaaaaa', '#aaa'); }); @@ -180,7 +180,7 @@ suite ('Colour Fields', function() { }); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.colourField = new Blockly.FieldColour('#aaaaaa'); }); diff --git a/tests/mocha/field_date_test.js b/tests/mocha/field_date_test.js index cc95b36ba61..b22177d37ef 100644 --- a/tests/mocha/field_date_test.js +++ b/tests/mocha/field_date_test.js @@ -42,7 +42,7 @@ suite ('Date Fields', function() { var dateField = new Blockly.FieldDate(undefined); assertValueDefault(dateField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { var dateField = new Blockly.FieldDate('bad'); assertValueDefault(dateField); }); @@ -50,11 +50,11 @@ suite ('Date Fields', function() { var dateField = new Blockly.FieldDate('2020-02-20'); assertValue(dateField, '2020-02-20'); }); - test.skip('Invalid Date - Month(2020-13-20)', function() { + test('Invalid Date - Month(2020-13-20)', function() { var dateField = new Blockly.FieldDate('2020-13-20'); assertValueDefault(dateField); }); - test.skip('Invalid Date - Day(2020-02-32)', function() { + test('Invalid Date - Day(2020-02-32)', function() { var dateField = new Blockly.FieldDate('2020-02-32'); assertValueDefault(dateField); }); @@ -72,7 +72,7 @@ suite ('Date Fields', function() { var dateField = Blockly.FieldDate.fromJson({ date: undefined }); assertValueDefault(dateField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { var dateField = Blockly.FieldDate.fromJson({ date: 'bad' }); assertValueDefault(dateField); }); @@ -80,11 +80,11 @@ suite ('Date Fields', function() { var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-20' }); assertValue(dateField, '2020-02-20'); }); - test.skip('Invalid Date - Month(2020-13-20)', function() { + test('Invalid Date - Month(2020-13-20)', function() { var dateField = Blockly.FieldDate.fromJson({ date: '2020-13-20' }); assertValueDefault(dateField); }); - test.skip('Invalid Date - Day(2020-02-32)', function() { + test('Invalid Date - Day(2020-02-32)', function() { var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-32' }); assertValueDefault(dateField); }); @@ -94,23 +94,23 @@ suite ('Date Fields', function() { setup(function() { this.dateField = new Blockly.FieldDate(); }); - test.skip('Null', function() { + test('Null', function() { this.dateField.setValue(null); assertValueDefault(this.dateField); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.dateField.setValue(undefined); assertValueDefault(this.dateField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.dateField.setValue('bad'); assertValueDefault(this.dateField); }); - test.skip('Invalid Date - Month(2020-13-20)', function() { + test('Invalid Date - Month(2020-13-20)', function() { this.dateField.setValue('2020-13-20'); assertValueDefault(this.dateField); }); - test.skip('Invalid Date - Day(2020-02-32)', function() { + test('Invalid Date - Day(2020-02-32)', function() { this.dateField.setValue('2020-02-32'); assertValueDefault(this.dateField); }); @@ -123,23 +123,23 @@ suite ('Date Fields', function() { setup(function() { this.dateField = new Blockly.FieldDate('2020-02-20'); }); - test.skip('Null', function() { + test('Null', function() { this.dateField.setValue(null); assertValue(this.dateField, '2020-02-20'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.dateField.setValue(undefined); assertValue(this.dateField, '2020-02-20'); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.dateField.setValue('bad'); assertValue(this.dateField, '2020-02-20'); }); - test.skip('Invalid Date - Month(2020-13-20)', function() { + test('Invalid Date - Month(2020-13-20)', function() { this.dateField.setValue('2020-13-20'); assertValue(this.dateField, '2020-02-20'); }); - test.skip('Invalid Date - Day(2020-02-32)', function() { + test('Invalid Date - Day(2020-02-32)', function() { this.dateField.setValue('2020-02-32'); assertValue(this.dateField, '2020-02-20'); }); @@ -149,7 +149,7 @@ suite ('Date Fields', function() { }); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.dateField = new Blockly.FieldDate('2020-02-20'); }); diff --git a/tests/mocha/field_dropdown_test.js b/tests/mocha/field_dropdown_test.js index 23c5f8016dd..f8c54d801b2 100644 --- a/tests/mocha/field_dropdown_test.js +++ b/tests/mocha/field_dropdown_test.js @@ -148,11 +148,11 @@ suite ('Dropdown Fields', function() { this.dropdownField.setValue(null); assertValue(this.dropdownField, 'A', 'a'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.dropdownField.setValue(undefined); assertValue(this.dropdownField, 'A', 'a'); }); - test.skip('Invalid ID', function() { + test('Invalid ID', function() { this.dropdownField.setValue('bad'); assertValue(this.dropdownField, 'A', 'a'); }); @@ -161,7 +161,7 @@ suite ('Dropdown Fields', function() { assertValue(this.dropdownField, 'B', 'b'); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.dropdownField = new Blockly.FieldDropdown([ ["1a","1A"], ["1b","1B"], ["1c","1C"], diff --git a/tests/mocha/field_image_test.js b/tests/mocha/field_image_test.js index eb968882cda..ca39f0c2212 100644 --- a/tests/mocha/field_image_test.js +++ b/tests/mocha/field_image_test.js @@ -149,7 +149,7 @@ suite ('Image Fields', function() { this.imageField.setValue(null); assertValue(this.imageField, 'src', 'alt'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.imageField.setValue(undefined); assertValue(this.imageField, 'src', 'alt'); }); diff --git a/tests/mocha/field_label_serializable_test.js b/tests/mocha/field_label_serializable_test.js index e59fd329cea..2b508dd63a9 100644 --- a/tests/mocha/field_label_serializable_test.js +++ b/tests/mocha/field_label_serializable_test.js @@ -108,7 +108,7 @@ suite ('Label Serializable Fields', function() { this.labelField.setValue(null); assertValueDefault(this.labelField); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.labelField.setValue(undefined); assertValueDefault(this.labelField); }); @@ -120,7 +120,7 @@ suite ('Label Serializable Fields', function() { this.labelField.setValue(1); assertValue(this.labelField, '1'); }); - test.skip('Number (Falsy)', function() { + test('Number (Falsy)', function() { this.labelField.setValue(0); assertValue(this.labelField, '0'); }); @@ -128,7 +128,7 @@ suite ('Label Serializable Fields', function() { this.labelField.setValue(true); assertValue(this.labelField, 'true'); }); - test.skip('Boolean False', function() { + test('Boolean False', function() { this.labelField.setValue(false); assertValue(this.labelField, 'false'); }); @@ -141,7 +141,7 @@ suite ('Label Serializable Fields', function() { this.labelField.setValue(null); assertValue(this.labelField, 'value'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.labelField.setValue(undefined); assertValue(this.labelField, 'value'); }); diff --git a/tests/mocha/field_label_test.js b/tests/mocha/field_label_test.js index 1974da55e0d..1f9b8d0f6d2 100644 --- a/tests/mocha/field_label_test.js +++ b/tests/mocha/field_label_test.js @@ -105,7 +105,7 @@ suite ('Label Fields', function() { this.labelField.setValue(null); assertValueDefault(this.labelField); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.labelField.setValue(undefined); assertValueDefault(this.labelField); }); @@ -117,7 +117,7 @@ suite ('Label Fields', function() { this.labelField.setValue(1); assertValue(this.labelField, '1'); }); - test.skip('Number (Falsy)', function() { + test('Number (Falsy)', function() { this.labelField.setValue(0); assertValue(this.labelField, '0'); }); @@ -125,7 +125,7 @@ suite ('Label Fields', function() { this.labelField.setValue(true); assertValue(this.labelField, 'true'); }); - test.skip('Boolean False', function() { + test('Boolean False', function() { this.labelField.setValue(false); assertValue(this.labelField, 'false'); }); @@ -138,7 +138,7 @@ suite ('Label Fields', function() { this.labelField.setValue(null); assertValue(this.labelField, 'value'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.labelField.setValue(undefined); assertValue(this.labelField, 'value'); }); diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index f0c1d1db0f5..3402c67666b 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -136,15 +136,15 @@ suite ('Number Fields', function() { this.numberField.setValue(null); assertValueDefault(this.numberField); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.numberField.setValue(undefined); assertValueDefault(this.numberField); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.numberField.setValue('bad'); assertValueDefault(this.numberField); }); - test.skip('NaN', function() { + test('NaN', function() { this.numberField.setValue(NaN); assertValueDefault(this.numberField); }); @@ -173,15 +173,15 @@ suite ('Number Fields', function() { this.numberField.setValue(null); assertValue(this.numberField, 1); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.numberField.setValue(undefined); assertValue(this.numberField, 1); }); - test.skip('Non-Parsable String', function() { + test('Non-Parsable String', function() { this.numberField.setValue('bad'); assertValue(this.numberField, 1); }); - test.skip('NaN', function() { + test('NaN', function() { this.numberField.setValue(NaN); assertValue(this.numberField, 1); }); @@ -228,7 +228,7 @@ suite ('Number Fields', function() { numberField.setValue(123.456); assertValue(numberField, 123); }); - test.skip('1.5', function() { + test('1.5', function() { var numberField = new Blockly.FieldNumber .fromJson({ precision: 1.5 }); numberField.setValue(123.456); @@ -295,7 +295,7 @@ suite ('Number Fields', function() { }); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.numberFieldField = new Blockly.FieldNumber(1); Blockly.FieldTextInput.htmlInput_ = Object.create(null); diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js index 2a1b72b06c4..64e36d6eda5 100644 --- a/tests/mocha/field_textinput_test.js +++ b/tests/mocha/field_textinput_test.js @@ -107,7 +107,7 @@ suite ('Text Input Fields', function() { this.textInputField.setValue(null); assertValueDefault(this.textInputField); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.textInputField.setValue(undefined); assertValueDefault(this.textInputField); }); @@ -119,7 +119,7 @@ suite ('Text Input Fields', function() { this.textInputField.setValue(1); assertValue(this.textInputField, '1'); }); - test.skip('Number (Falsy)', function() { + test('Number (Falsy)', function() { this.textInputField.setValue(0); assertValue(this.textInputField, '0'); }); @@ -127,7 +127,7 @@ suite ('Text Input Fields', function() { this.textInputField.setValue(true); assertValue(this.textInputField, 'true'); }); - test.skip('Boolean False', function() { + test('Boolean False', function() { this.textInputField.setValue(false); assertValue(this.textInputField, 'false'); }); @@ -140,7 +140,7 @@ suite ('Text Input Fields', function() { this.textInputField.setValue(null); assertValue(this.textInputField, 'value'); }); - test.skip('Undefined', function() { + test('Undefined', function() { this.textInputField.setValue(undefined); assertValue(this.textInputField, 'value'); }); @@ -166,7 +166,7 @@ suite ('Text Input Fields', function() { }); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.textInputField = new Blockly.FieldTextInput('value'); Blockly.FieldTextInput.htmlInput_ = Object.create(null); diff --git a/tests/mocha/field_variable_test.js b/tests/mocha/field_variable_test.js index 8e7026eb6cc..1e93228950e 100644 --- a/tests/mocha/field_variable_test.js +++ b/tests/mocha/field_variable_test.js @@ -127,13 +127,13 @@ suite('Variable Fields', function() { }); }); suite('setValue', function() { - test.skip('Null', function() { + test('Null', function() { var variableField = createAndInitFieldConstructor( this.workspace, 'name1'); variableField.setValue(null); assertValue(variableField, 'name1'); }); - test.skip('Undefined', function() { + test('Undefined', function() { var variableField = createAndInitFieldConstructor( this.workspace, 'name1'); variableField.setValue(undefined); @@ -152,14 +152,14 @@ suite('Variable Fields', function() { assertEquals('id2', variableField.getValue()); chai.assert.notEqual(oldId, variableField.getValue()); }); - test.skip('Variable Does not Exist', function() { + test('Variable Does not Exist', function() { var variableField = createAndInitFieldConstructor( this.workspace, 'name1'); variableField.setValue('id1'); assertValue(variableField, 'name1'); }); }); - suite.skip('Validators', function() { + suite('Validators', function() { setup(function() { this.workspace.createVariable('name1', null, 'id1'); this.workspace.createVariable('name2', null, 'id2'); diff --git a/tests/playground.html b/tests/playground.html index 72d5dbd5d2c..0a0220e1376 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -144,6 +144,15 @@ } function addToolboxButtonCallbacks() { + var addAllBlocksToWorkspace = function(button) { + var workspace = button.getTargetWorkspace(); + var blocks = button.workspace_.getTopBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + var xml = Blockly.Xml.textToDom(''); + xml.appendChild(Blockly.Xml.blockToDom(block)); + Blockly.Xml.appendDomToWorkspace(xml, workspace); + } + }; var randomizeLabelText = function(button) { var blocks = button.targetWorkspace_ .getBlocksByType('test_fields_label_serializable'); @@ -177,13 +186,59 @@ block.setShadow(!block.isShadow()); } }; + var toggleCollapsed = function(button) { + var blocks = button.workspace_.getAllBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + block.setCollapsed(!block.isCollapsed()); + } + }; + var setInput = function(button) { + Blockly.prompt('Input text to set.', 'ab', function(input) { + var blocks = button.getTargetWorkspace().getAllBlocks(); + for(var i = 0, block; block = blocks[i]; i++) { + if (block.getField('INPUT')) { + block.setFieldValue(input, 'INPUT'); + } + } + }) + }; + var changeImage = function(button) { + var blocks = button.workspace_.getBlocksByType('test_fields_image'); + var possible = 'abcdefghijklm'; + var image = possible.charAt(Math.floor(Math.random() * possible.length)); + var src = 'https://blockly-demo.appspot.com/static/tests/media/' + + image + '.png'; + for (var i = 0, block; block = blocks[i]; i++) { + var imageField = block.getField('IMAGE'); + imageField.setValue(src); + imageField.setText(image); + } + }; + var addVariables = function(button) { + workspace.createVariable('1a', '', '1A'); + workspace.createVariable('1b', '', '1B'); + workspace.createVariable('1c', '', '1C'); + workspace.createVariable('2a', '', '2A'); + workspace.createVariable('2b', '', '2B'); + workspace.createVariable('2c', '', '2C'); + }; + workspace.registerButtonCallback( + 'addVariables', addVariables); + workspace.registerButtonCallback( + 'changeImage', changeImage); + workspace.registerButtonCallback( + 'addAllBlocksToWorkspace', addAllBlocksToWorkspace); + workspace.registerButtonCallback( + 'setInput', setInput); workspace.registerButtonCallback( 'setRandomStyle', setRandomStyle); workspace.registerButtonCallback( 'toggleEnabled', toggleEnabled); workspace.registerButtonCallback( 'toggleShadow', toggleShadow); + workspace.registerButtonCallback( + 'toggleCollapsed', toggleCollapsed); workspace.registerButtonCallback( 'randomizeLabelText', randomizeLabelText); workspace.registerButtonCallback( @@ -1236,11 +1291,15 @@

Blockly Playground

+ + + + @@ -1248,7 +1307,11 @@

Blockly Playground

+ + + +
@@ -1298,6 +1361,69 @@

Blockly Playground

Zalgo in text field: B̛̻̦̬̘̰͎̥̈̔͊͞ͅl̡͖̫̺̬̖̣̳̃̀́͑͑̕͟͠͝o̢̹͙̮̫͔͋̉̊̑̿̽̚c̸̹̹̜͙̹̠͋̒͑̊̇͝k̡͉̫͇̖̳͖̊͒́̆̄̎̂̔̕͜͞l̰̙̞̳̩̠͖̯̀̆̈́̿̈̓͗y̨̡̟͇̮͈̬̙̲̏̅̀͘͠
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
From 9f528922a7f7d26c5170bb57a625e594c67891a1 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 24 May 2019 14:33:18 -0700 Subject: [PATCH 076/233] Fix some dependencies --- core/block.js | 1 + core/block_dragger.js | 1 + core/block_svg.js | 2 ++ core/blockly.js | 3 ++- core/bubble_dragger.js | 1 + core/comment.js | 1 + core/connection.js | 1 + core/contextmenu.js | 2 ++ core/events_abstract.js | 1 + core/extensions.js | 1 + core/field.js | 1 + core/field_checkbox.js | 2 ++ core/field_colour.js | 2 ++ core/field_date.js | 1 + core/field_dropdown.js | 2 ++ core/field_image.js | 1 + core/field_textinput.js | 2 ++ core/field_variable.js | 3 +++ core/flyout_base.js | 1 + core/flyout_horizontal.js | 4 +--- core/flyout_vertical.js | 2 -- core/gesture.js | 1 + core/inject.js | 2 ++ core/insertion_marker_manager.js | 2 +- core/mutator.js | 1 + core/procedures.js | 2 ++ core/rendered_connection.js | 1 + core/theme.js | 2 ++ core/theme/classic.js | 1 + core/theme/highcontrast.js | 1 + core/theme/modern.js | 1 + core/toolbox.js | 1 + core/trashcan.js | 1 + core/utils.js | 2 +- core/variable_map.js | 2 ++ core/variable_model.js | 1 + core/variables.js | 3 +-- core/variables_dynamic.js | 4 +--- core/warning.js | 1 + core/widgetdiv.js | 1 + core/workspace.js | 1 + core/workspace_comment.js | 1 + core/workspace_comment_svg.js | 2 ++ core/workspace_events.js | 1 + core/workspace_svg.js | 2 ++ core/xml.js | 1 + 46 files changed, 60 insertions(+), 13 deletions(-) diff --git a/core/block.js b/core/block.js index 3df892d4792..3fd1a43bcb4 100644 --- a/core/block.js +++ b/core/block.js @@ -29,6 +29,7 @@ goog.provide('Blockly.Block'); goog.require('Blockly.Blocks'); goog.require('Blockly.Comment'); goog.require('Blockly.Connection'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.BlockDelete'); diff --git a/core/block_dragger.js b/core/block_dragger.js index 9ba2e63ebc2..ce07de7419a 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -28,6 +28,7 @@ goog.provide('Blockly.BlockDragger'); goog.require('Blockly.BlockAnimations'); goog.require('Blockly.InsertionMarkerManager'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockMove'); goog.require('goog.math.Coordinate'); diff --git a/core/block_svg.js b/core/block_svg.js index 47cee2673c4..8b69d751e99 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -29,9 +29,11 @@ goog.provide('Blockly.BlockSvg'); goog.require('Blockly.Block'); goog.require('Blockly.BlockAnimations'); goog.require('Blockly.ContextMenu'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Events.BlockMove'); goog.require('Blockly.Grid'); +goog.require('Blockly.Msg'); goog.require('Blockly.RenderedConnection'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); diff --git a/core/blockly.js b/core/blockly.js index d9c6764d97e..a5a133d3c9b 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -32,6 +32,7 @@ goog.provide('Blockly'); goog.require('Blockly.BlockSvg.render'); goog.require('Blockly.Events'); +goog.require('Blockly.Events.Ui'); goog.require('Blockly.FieldAngle'); goog.require('Blockly.FieldCheckbox'); goog.require('Blockly.FieldColour'); @@ -45,9 +46,9 @@ goog.require('Blockly.FieldTextInput'); goog.require('Blockly.FieldNumber'); goog.require('Blockly.FieldVariable'); goog.require('Blockly.Generator'); -goog.require('Blockly.Msg'); goog.require('Blockly.Procedures'); goog.require('Blockly.Toolbox'); +goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.WidgetDiv'); goog.require('Blockly.WorkspaceSvg'); diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index 3665d9fd193..701f48f2013 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -27,6 +27,7 @@ goog.provide('Blockly.BubbleDragger'); goog.require('Blockly.Bubble'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceCommentSvg'); diff --git a/core/comment.js b/core/comment.js index 73a9c669528..3176b573c71 100644 --- a/core/comment.js +++ b/core/comment.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Comment'); goog.require('Blockly.Bubble'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); diff --git a/core/connection.js b/core/connection.js index 739ad131461..53f0bb2db8d 100644 --- a/core/connection.js +++ b/core/connection.js @@ -26,6 +26,7 @@ goog.provide('Blockly.Connection'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockMove'); goog.require('Blockly.Xml'); diff --git a/core/contextmenu.js b/core/contextmenu.js index f9e7a39bd3c..6971c3f4930 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -30,7 +30,9 @@ */ goog.provide('Blockly.ContextMenu'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); +goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.uiMenu'); diff --git a/core/events_abstract.js b/core/events_abstract.js index 4fa10c82c2c..387276cf8d9 100644 --- a/core/events_abstract.js +++ b/core/events_abstract.js @@ -29,6 +29,7 @@ goog.provide('Blockly.Events.Abstract'); goog.require('Blockly.Events'); + /** * Abstract class for an event. * @constructor diff --git a/core/extensions.js b/core/extensions.js index 583cdc91030..c15329559ca 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -36,6 +36,7 @@ goog.provide('Blockly.Extensions'); goog.require('Blockly.Mutator'); goog.require('Blockly.utils'); + /** * The set of all registered extensions, keyed by extension name/id. * @private diff --git a/core/field.js b/core/field.js index f103813fe62..0e7929178a0 100644 --- a/core/field.js +++ b/core/field.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Field'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); goog.require('Blockly.userAgent'); diff --git a/core/field_checkbox.js b/core/field_checkbox.js index 67d08237e97..74d6c115a19 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -26,6 +26,8 @@ goog.provide('Blockly.FieldCheckbox'); +goog.require('Blockly.Events'); +goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.utils'); diff --git a/core/field_colour.js b/core/field_colour.js index 0e0c830df61..f9be4933b4e 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -27,6 +27,8 @@ goog.provide('Blockly.FieldColour'); goog.require('Blockly.DropDownDiv'); +goog.require('Blockly.Events'); +goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('goog.math.Size'); diff --git a/core/field_date.js b/core/field_date.js index c71d0d743fd..6b7a2dd31ee 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -26,6 +26,7 @@ goog.provide('Blockly.FieldDate'); +goog.require('Blockly.Events'); goog.require('Blockly.Field'); goog.require('Blockly.utils'); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 821ad3b68db..4083e231c84 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -28,6 +28,8 @@ goog.provide('Blockly.FieldDropdown'); +goog.require('Blockly.Events'); +goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); diff --git a/core/field_image.js b/core/field_image.js index 532543c65c5..0d39a9fcef5 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -27,6 +27,7 @@ goog.provide('Blockly.FieldImage'); goog.require('Blockly.Field'); +goog.require('Blockly.Tooltip'); goog.require('Blockly.utils'); goog.require('goog.math.Size'); diff --git a/core/field_textinput.js b/core/field_textinput.js index 717f9113e0b..068a5ecc41c 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -27,6 +27,8 @@ goog.provide('Blockly.FieldTextInput'); goog.require('Blockly.DropDownDiv'); +goog.require('Blockly.Events'); +goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); diff --git a/core/field_variable.js b/core/field_variable.js index 5b2fc7d2b9f..a2cd7a6bbc7 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -26,11 +26,14 @@ goog.provide('Blockly.FieldVariable'); +goog.require('Blockly.Events'); +goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.FieldDropdown'); goog.require('Blockly.Msg'); goog.require('Blockly.utils'); goog.require('Blockly.VariableModel'); goog.require('Blockly.Variables'); +goog.require('Blockly.Xml'); goog.require('goog.math.Size'); diff --git a/core/flyout_base.js b/core/flyout_base.js index c8fcc79d2a7..0e20bd0d6fd 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -32,6 +32,7 @@ goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.VarCreate'); goog.require('Blockly.FlyoutButton'); goog.require('Blockly.Gesture'); +goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index be8426bb190..da62a8ffe4a 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -27,11 +27,9 @@ goog.provide('Blockly.HorizontalFlyout'); goog.require('Blockly.Block'); -goog.require('Blockly.Events'); -goog.require('Blockly.FlyoutButton'); goog.require('Blockly.Flyout'); +goog.require('Blockly.FlyoutButton'); goog.require('Blockly.utils'); -goog.require('Blockly.WorkspaceSvg'); goog.require('goog.math.Rect'); diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index a2fe351a436..96438050a63 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -27,12 +27,10 @@ goog.provide('Blockly.VerticalFlyout'); goog.require('Blockly.Block'); -goog.require('Blockly.Events'); goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); -goog.require('Blockly.WorkspaceSvg'); goog.require('goog.math.Rect'); diff --git a/core/gesture.js b/core/gesture.js index 4e18a1204a3..990667e222a 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -31,6 +31,7 @@ goog.require('Blockly.BlockAnimations'); goog.require('Blockly.BlockDragger'); goog.require('Blockly.BubbleDragger'); goog.require('Blockly.constants'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.FlyoutDragger'); goog.require('Blockly.Tooltip'); diff --git a/core/inject.js b/core/inject.js index 4492bae5840..11c39035162 100644 --- a/core/inject.js +++ b/core/inject.js @@ -29,8 +29,10 @@ goog.provide('Blockly.inject'); goog.require('Blockly.BlockDragSurfaceSvg'); goog.require('Blockly.Css'); goog.require('Blockly.DropDownDiv'); +goog.require('Blockly.Events'); goog.require('Blockly.Grid'); goog.require('Blockly.Options'); +goog.require('Blockly.Tooltip'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 8b3bd3079ff..de4de3892c7 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -27,7 +27,7 @@ goog.provide('Blockly.InsertionMarkerManager'); goog.require('Blockly.BlockAnimations'); -goog.require('Blockly.Events.BlockMove'); +goog.require('Blockly.Events'); goog.require('Blockly.RenderedConnection'); diff --git a/core/mutator.js b/core/mutator.js index fe499e99672..2e57df43d1d 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Mutator'); goog.require('Blockly.Bubble'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); diff --git a/core/procedures.js b/core/procedures.js index cc84a490242..a226bc9712c 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -32,8 +32,10 @@ goog.provide('Blockly.Procedures'); goog.require('Blockly.Blocks'); goog.require('Blockly.constants'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); +goog.require('Blockly.Msg'); goog.require('Blockly.Names'); goog.require('Blockly.Workspace'); goog.require('Blockly.Xml'); diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 73005308819..4c8b3d0d8e0 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -27,6 +27,7 @@ goog.provide('Blockly.RenderedConnection'); goog.require('Blockly.Connection'); +goog.require('Blockly.Events'); goog.require('Blockly.utils'); goog.require('goog.math.Coordinate'); diff --git a/core/theme.js b/core/theme.js index 1149ebd19ac..0105c96f604 100644 --- a/core/theme.js +++ b/core/theme.js @@ -24,6 +24,8 @@ 'use strict'; goog.provide('Blockly.Theme'); + + /** * Class for a theme. * @param {Object.} blockStyles A map from style diff --git a/core/theme/classic.js b/core/theme/classic.js index 522e444409c..5de42fefe8d 100644 --- a/core/theme/classic.js +++ b/core/theme/classic.js @@ -29,6 +29,7 @@ goog.provide('Blockly.Themes.Classic'); goog.require('Blockly.Theme'); + var defaultBlockStyles = { "colour_blocks":{ "colourPrimary": "20" diff --git a/core/theme/highcontrast.js b/core/theme/highcontrast.js index 93c88ecf95c..56174e2158e 100644 --- a/core/theme/highcontrast.js +++ b/core/theme/highcontrast.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Themes.HighContrast'); goog.require('Blockly.Theme'); + var defaultBlockStyles = { "colour_blocks":{ "colourPrimary": "#a52714", diff --git a/core/theme/modern.js b/core/theme/modern.js index d7e06cf1a79..c218225bcff 100644 --- a/core/theme/modern.js +++ b/core/theme/modern.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Themes.Modern'); goog.require('Blockly.Theme'); + var defaultBlockStyles = { "colour_blocks": { "colourPrimary": "#a5745b", diff --git a/core/toolbox.js b/core/toolbox.js index 3804cbc370a..ef3bd6557bd 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -26,6 +26,7 @@ goog.provide('Blockly.Toolbox'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Flyout'); goog.require('Blockly.HorizontalFlyout'); diff --git a/core/trashcan.js b/core/trashcan.js index 975f1beca87..ccee525bc14 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Trashcan'); goog.require('Blockly.utils'); +goog.require('Blockly.Xml'); goog.require('goog.math.Rect'); diff --git a/core/utils.js b/core/utils.js index 2aaf9b1c0ef..18ee689ddfa 100644 --- a/core/utils.js +++ b/core/utils.js @@ -32,6 +32,7 @@ */ goog.provide('Blockly.utils'); +goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); goog.require('goog.math.Coordinate'); @@ -1021,4 +1022,3 @@ Blockly.utils.clampNumber = function(lowerBound, number, upperBound) { * Reference to the global object. */ Blockly.utils.global = this || self; - diff --git a/core/variable_map.js b/core/variable_map.js index 642cf6a95c4..a444835ca83 100644 --- a/core/variable_map.js +++ b/core/variable_map.js @@ -26,8 +26,10 @@ goog.provide('Blockly.VariableMap'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.VarDelete'); goog.require('Blockly.Events.VarRename'); +goog.require('Blockly.Msg'); goog.require('Blockly.utils'); diff --git a/core/variable_model.js b/core/variable_model.js index e41dd209172..af1230ed71e 100644 --- a/core/variable_model.js +++ b/core/variable_model.js @@ -26,6 +26,7 @@ goog.provide('Blockly.VariableModel'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.VarCreate'); goog.require('Blockly.utils'); diff --git a/core/variables.js b/core/variables.js index 9255cd432ee..a37271702a5 100644 --- a/core/variables.js +++ b/core/variables.js @@ -31,9 +31,8 @@ goog.provide('Blockly.Variables'); goog.require('Blockly.Blocks'); -goog.require('Blockly.constants'); +goog.require('Blockly.Msg'); goog.require('Blockly.VariableModel'); -goog.require('Blockly.Workspace'); goog.require('Blockly.Xml'); goog.require('goog.string'); diff --git a/core/variables_dynamic.js b/core/variables_dynamic.js index d09c2aa0c74..cc95e2b3ee4 100644 --- a/core/variables_dynamic.js +++ b/core/variables_dynamic.js @@ -29,10 +29,8 @@ goog.provide('Blockly.VariablesDynamic'); goog.require('Blockly.Variables'); goog.require('Blockly.Blocks'); -goog.require('Blockly.constants'); +goog.require('Blockly.Msg'); goog.require('Blockly.VariableModel'); -// TODO Fix circular dependencies -// goog.require('Blockly.Workspace'); goog.require('Blockly.Xml'); diff --git a/core/warning.js b/core/warning.js index 9ae3c7ea031..f1633c06ea3 100644 --- a/core/warning.js +++ b/core/warning.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Warning'); goog.require('Blockly.Bubble'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); goog.require('Blockly.utils'); diff --git a/core/widgetdiv.js b/core/widgetdiv.js index 9fc80d82f37..4690b66ad04 100644 --- a/core/widgetdiv.js +++ b/core/widgetdiv.js @@ -33,6 +33,7 @@ goog.provide('Blockly.WidgetDiv'); goog.require('Blockly.Css'); + goog.require('goog.style'); diff --git a/core/workspace.js b/core/workspace.js index 4dd5d2a51a0..6cf93946f1c 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -26,6 +26,7 @@ goog.provide('Blockly.Workspace'); +goog.require('Blockly.Events'); goog.require('Blockly.utils'); goog.require('Blockly.VariableMap'); goog.require('Blockly.WorkspaceComment'); diff --git a/core/workspace_comment.js b/core/workspace_comment.js index fa1b7313077..fc75084437a 100644 --- a/core/workspace_comment.js +++ b/core/workspace_comment.js @@ -26,6 +26,7 @@ goog.provide('Blockly.WorkspaceComment'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentChange'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index b76614f1aa5..287135cb579 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -26,9 +26,11 @@ goog.provide('Blockly.WorkspaceCommentSvg'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); goog.require('Blockly.Events.CommentMove'); +goog.require('Blockly.Events.Ui'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceComment'); diff --git a/core/workspace_events.js b/core/workspace_events.js index b4c78e2defc..02b4a9cd666 100644 --- a/core/workspace_events.js +++ b/core/workspace_events.js @@ -29,6 +29,7 @@ goog.provide('Blockly.Events.FinishedLoading'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Abstract'); + /** * Class for a finished loading event. * Used to notify the developer when the workspace has finished loading (i.e diff --git a/core/workspace_svg.js b/core/workspace_svg.js index f07cdc5f2fc..37625df1a02 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -30,9 +30,11 @@ goog.provide('Blockly.WorkspaceSvg'); //goog.require('Blockly.BlockSvg'); goog.require('Blockly.ConnectionDB'); goog.require('Blockly.constants'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Gesture'); goog.require('Blockly.Grid'); +goog.require('Blockly.Msg'); goog.require('Blockly.Options'); goog.require('Blockly.ScrollbarPair'); goog.require('Blockly.Touch'); diff --git a/core/xml.js b/core/xml.js index eb736afaf70..c542a0e4c33 100644 --- a/core/xml.js +++ b/core/xml.js @@ -30,6 +30,7 @@ */ goog.provide('Blockly.Xml'); +goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.FinishedLoading'); goog.require('Blockly.Events.VarCreate'); From 5c614d73c1bb3e1be6fe556ab089ff1267f40c7b Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 24 May 2019 15:02:21 -0700 Subject: [PATCH 077/233] Add tests for XY regexs. --- core/inject.js | 2 +- tests/jsunit/utils_test.js | 74 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/core/inject.js b/core/inject.js index 11c39035162..4582ee43d63 100644 --- a/core/inject.js +++ b/core/inject.js @@ -66,7 +66,7 @@ Blockly.inject = function(container, opt_options) { var svg = Blockly.createDom_(subContainer, options); // Create surfaces for dragging things. These are optimizations - // so that the broowser does not repaint during the drag. + // so that the browser does not repaint during the drag. var blockDragSurface = new Blockly.BlockDragSurfaceSvg(subContainer); var workspaceDragSurface = new Blockly.WorkspaceDragSurfaceSvg(subContainer); diff --git a/tests/jsunit/utils_test.js b/tests/jsunit/utils_test.js index ca6e77e6325..305dee7d512 100644 --- a/tests/jsunit/utils_test.js +++ b/tests/jsunit/utils_test.js @@ -271,3 +271,77 @@ function test_toDegrees() { assertEquals('360', 360, Blockly.utils.toDegrees(4 * quarter)); assertEquals('450', 360 + 90, Blockly.utils.toDegrees(5 * quarter)); } + +function test_XY_REGEX() { + var regex = Blockly.utils.getRelativeXY.XY_REGEX_; + var m; + m = 'INVALID'.match(regex); + assertNull(m); + + m = 'translate(10)'.match(regex); + assertEquals('translate(10), x', '10', m[1]); + assertUndefined('translate(10), y', m[3]); + + m = 'translate(11, 12)'.match(regex); + assertEquals('translate(11, 12), x', '11', m[1]); + assertEquals('translate(11, 12), y', '12', m[3]); + + m = 'translate(13,14)'.match(regex); + assertEquals('translate(13,14), x', '13', m[1]); + assertEquals('translate(13,14), y', '14', m[3]); + + m = 'translate(15 16)'.match(regex); + assertEquals('translate(15 16), x', '15', m[1]); + assertEquals('translate(15 16), y', '16', m[3]); + + m = 'translate(1.23456e+42 0.123456e-42)'.match(regex); + assertEquals('translate(1.23456e+42 0.123456e-42), x', '1.23456e+42', m[1]); + assertEquals('translate(1.23456e+42 0.123456e-42), y', '0.123456e-42', m[3]); +} + +function XY_STYLE_REGEX_() { + var regex = Blockly.utils.getRelativeXY.XY_STYLE_REGEX_; + var m; + m = 'INVALID'.match(regex); + assertNull(m); + + m = 'transform:translate(9px)'.match(regex); + assertEquals('transform:translate(9px), x', '9', m[1]); + assertUndefined('transform:translate(9px), y', m[3]); + + m = 'transform:translate3d(10px)'.match(regex); + assertEquals('transform:translate3d(10px), x', '10', m[1]); + assertUndefined('transform:translate(10px), y', m[3]); + + m = 'transform: translate(11px, 12px)'.match(regex); + assertEquals('transform: translate(11px, 12px), x', '11', m[1]); + assertEquals('transform: translate(11px, 12px), y', '12', m[3]); + + m = 'transform: translate(13px,14px)'.match(regex); + assertEquals('transform: translate(13px,14px), x', '13', m[1]); + assertEquals('transform: translate(13px,14px), y', '14', m[3]); + + m = 'transform: translate(15px 16px)'.match(regex); + assertEquals('transform: translate(15px 16px), x', '15', m[1]); + assertEquals('transform: translate(15px 16px), y', '16', m[3]); + + m = 'transform: translate(1.23456e+42px 0.123456e-42px)'.match(regex); + assertEquals('transform: translate(1.23456e+42px 0.123456e-42px), x', '1.23456e+42', m[1]); + assertEquals('transform: translate(1.23456e+42px 0.123456e-42px), y', '0.123456e-42', m[3]); + + m = 'transform:translate3d(20px, 21px, 22px)'.match(regex); + assertEquals('transform:translate3d(20px, 21px, 22px), x', '21', m[1]); + assertEquals('transform:translate3d(20px, 21px, 22px), y', '22', m[3]); + + m = 'transform:translate3d(23px,24px,25px)'.match(regex); + assertEquals('transform:translate3d(23px,24px,25px), x', '23', m[1]); + assertEquals('transform:translate3d(23px,24px,25px), y', '24', m[3]); + + m = 'transform:translate3d(26px 27px 28px)'.match(regex); + assertEquals('transform:translate3d(26px 27px 28px), x', '26', m[1]); + assertEquals('transform:translate3d(26px 27px 28px), y', '27', m[3]); + + m = 'transform:translate3d(1.23456e+42px 0.123456e-42px 42px)'.match(regex); + assertEquals('transform:translate3d(1.23456e+42px 0.123456e-42px 42px), x', '1.23456e+42', m[1]); + assertEquals('transform:translate3d(1.23456e+42px 0.123456e-42px 42px), y', '0.123456e-42', m[3]); +} From 06c6d8335507c05d187919251a9c114e9b3e5485 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 24 May 2019 16:13:21 -0700 Subject: [PATCH 078/233] Changed colour field class validator to accept all documented values. --- core/field_colour.js | 8 +++- tests/mocha/field_colour_test.js | 66 ++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/core/field_colour.js b/core/field_colour.js index f9be4933b4e..e92328bb268 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -32,6 +32,7 @@ goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('goog.math.Size'); +goog.require('goog.color'); /** @@ -176,8 +177,11 @@ Blockly.FieldColour.prototype.render_ = function() { * @protected */ Blockly.FieldColour.prototype.doClassValidation_ = function(newValue) { - if (Blockly.FieldColour.COLOUR_REGEX.test(newValue)) { - return newValue.toLowerCase(); + if (typeof newValue != 'string') { + return null; + } + if (goog.color.isValidColor(newValue)) { + return goog.color.parse(newValue).hex; } return null; }; diff --git a/tests/mocha/field_colour_test.js b/tests/mocha/field_colour_test.js index 507dd836481..dba8f04386b 100644 --- a/tests/mocha/field_colour_test.js +++ b/tests/mocha/field_colour_test.js @@ -58,7 +58,7 @@ suite ('Colour Fields', function() { assertValueDefault(colourField); }); test('Non-Parsable String', function() { - var colourField = new Blockly.FieldColour('bad'); + var colourField = new Blockly.FieldColour('not_a_colour'); assertValueDefault(colourField); }); test('#AAAAAA', function() { @@ -85,6 +85,22 @@ suite ('Colour Fields', function() { var colourField = new Blockly.FieldColour('#bcbcbc'); assertValue(colourField, '#bcbcbc', '#bcbcbc'); }); + test('#AA0', function() { + var colourField = new Blockly.FieldColour('#AA0'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('#aa0', function() { + var colourField = new Blockly.FieldColour('#aa0'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('rgb(170, 170, 0)', function() { + var colourField = new Blockly.FieldColour('rgb(170, 170, 0)'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('red', function() { + var colourField = new Blockly.FieldColour('red'); + assertValue(colourField, '#ff0000', '#f00'); + }); }); suite('fromJson', function() { test('Empty', function() { @@ -100,7 +116,8 @@ suite ('Colour Fields', function() { assertValueDefault(colourField); }); test('Non-Parsable String', function() { - var colourField = new Blockly.FieldColour.fromJson({ colour:'bad' }); + var colourField = new Blockly.FieldColour.fromJson( + { colour:'not_a_colour' }); assertValueDefault(colourField); }); test('#AAAAAA', function() { @@ -127,6 +144,23 @@ suite ('Colour Fields', function() { var colourField = Blockly.FieldColour.fromJson({ colour: '#bcbcbc' }); assertValue(colourField, '#bcbcbc', '#bcbcbc'); }); + test('#AA0', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#AA0' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('#aa0', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#aa0' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('rgb(170, 170, 0)', function() { + var colourField = Blockly.FieldColour.fromJson( + { colour: 'rgb(170, 170, 0)' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('red', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: 'red' }); + assertValue(colourField, '#ff0000', '#f00'); + }); }); suite('setValue', function() { suite('Empty -> New Value', function() { @@ -142,7 +176,7 @@ suite ('Colour Fields', function() { assertValueDefault(this.colourField); }); test('Non-Parsable String', function() { - this.colourField.setValue('bad'); + this.colourField.setValue('not_a_colour'); assertValueDefault(this.colourField); }); test('#000000', function() { @@ -153,6 +187,18 @@ suite ('Colour Fields', function() { this.colourField.setValue('#bcbcbc'); assertValue(this.colourField, '#bcbcbc', '#bcbcbc'); }); + test('#aa0', function() { + this.colourField.setValue('#aa0'); + assertValue(this.colourField, '#aaaa00', '#aa0'); + }); + test('rgb(170, 170, 0)', function() { + this.colourField.setValue('rgb(170, 170, 0)'); + assertValue(this.colourField, '#aaaa00', '#aa0'); + }); + test('red', function() { + this.colourField.setValue('red'); + assertValue(this.colourField, '#ff0000', '#f00'); + }); }); suite('Value -> New Value', function() { setup(function() { @@ -167,7 +213,7 @@ suite ('Colour Fields', function() { assertValue(this.colourField, '#aaaaaa', '#aaa'); }); test('Non-Parsable String', function() { - this.colourField.setValue('bad'); + this.colourField.setValue('not_a_colour'); assertValue(this.colourField, '#aaaaaa', '#aaa'); }); test('#000000', function() { @@ -178,6 +224,18 @@ suite ('Colour Fields', function() { this.colourField.setValue('#bcbcbc'); assertValue(this.colourField, '#bcbcbc', '#bcbcbc'); }); + test('#aa0', function() { + this.colourField.setValue('#aa0'); + assertValue(this.colourField, '#aaaa00', '#aa0'); + }); + test('rgb(170, 170, 0)', function() { + this.colourField.setValue('rgb(170, 170, 0)'); + assertValue(this.colourField, '#aaaa00', '#aa0'); + }); + test('red', function() { + this.colourField.setValue('red'); + assertValue(this.colourField, '#ff0000', '#f00'); + }); }); }); suite('Validators', function() { From e6caa501313e3b77cf5b127c061301d7939f6740 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 24 May 2019 16:13:21 -0700 Subject: [PATCH 079/233] Added more setValue test coverage. --- core/field.js | 9 +- tests/mocha/field_angle_test.js | 17 ++ tests/mocha/field_checkbox_test.js | 12 ++ tests/mocha/field_colour_test.js | 12 ++ tests/mocha/field_date_test.js | 12 ++ tests/mocha/field_dropdown_test.js | 36 +++- tests/mocha/field_number_test.js | 54 ++++-- tests/mocha/field_test.js | 273 +++++++++++++++++++++++++++- tests/mocha/field_textinput_test.js | 20 ++ tests/mocha/field_variable_test.js | 18 ++ 10 files changed, 436 insertions(+), 27 deletions(-) diff --git a/core/field.js b/core/field.js index 0e7929178a0..c96a216739d 100644 --- a/core/field.js +++ b/core/field.js @@ -673,7 +673,11 @@ Blockly.Field.prototype.setValue = function(newValue) { return; } - newValue = this.doClassValidation_(newValue); + var validatedValue = this.doClassValidation_(newValue); + // Class validators might accidentally forget to return, we'll ignore that. + if (validatedValue !== undefined) { + newValue = validatedValue; + } if (newValue === null) { doLogging && console.log('invalid, return'); this.doValueInvalid_(); @@ -686,8 +690,7 @@ Blockly.Field.prototype.setValue = function(newValue) { var localValidator = this.getValidator(); if (localValidator) { var validatedValue = localValidator.call(this, newValue); - // Sometimes local validators are used as change listeners (bad!) which - // means they might return undefined accidentally, so we'll just ignore that. + // Local validators might accidentally forget to return, we'll ignore that. if (validatedValue !== undefined) { newValue = validatedValue; } diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js index 8059c01c8b6..7453c0a81ca 100644 --- a/tests/mocha/field_angle_test.js +++ b/tests/mocha/field_angle_test.js @@ -206,6 +206,7 @@ suite ('Angle Fields', function() { Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; }); teardown(function() { + this.angleField.setValidator(null); Blockly.FieldTextInput.htmlInput_ = null; }); suite('Null Validator', function() { @@ -244,5 +245,21 @@ suite ('Angle Fields', function() { assertValue(this.angleField, 30); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.angleField.setValidator(function() {}); + }); + test('When Editing', function() { + this.angleField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '2'; + this.angleField.onHtmlInputChange_(null); + assertValue(this.angleField, 2); + this.angleField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 2); + }); + }); }); }); diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js index 2ad0bb3a9ab..dc55e2b3b36 100644 --- a/tests/mocha/field_checkbox_test.js +++ b/tests/mocha/field_checkbox_test.js @@ -136,6 +136,9 @@ suite('Checkbox Fields', function() { setup(function() { this.checkboxField = new Blockly.FieldCheckbox(true); }); + teardown(function() { + this.checkboxField.setValidator(null); + }); suite('Null Validator', function() { setup(function() { this.checkboxField.setValidator(function() { @@ -169,5 +172,14 @@ suite('Checkbox Fields', function() { assertValue(this.checkboxField, 'FALSE', 'false'); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() {}); + }); + test('New Value', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + }); }); }); diff --git a/tests/mocha/field_colour_test.js b/tests/mocha/field_colour_test.js index 507dd836481..5433431ca66 100644 --- a/tests/mocha/field_colour_test.js +++ b/tests/mocha/field_colour_test.js @@ -184,6 +184,9 @@ suite ('Colour Fields', function() { setup(function() { this.colourField = new Blockly.FieldColour('#aaaaaa'); }); + teardown(function() { + this.colourField.setValidator(null); + }); suite('Null Validator', function() { setup(function() { this.colourField.setValidator(function() { @@ -206,5 +209,14 @@ suite ('Colour Fields', function() { assertValue(this.colourField, '#ff0000', '#f00'); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.colourField.setValidator(function() {}); + }); + test('New Value', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#000000', '#000'); + }); + }); }); }); diff --git a/tests/mocha/field_date_test.js b/tests/mocha/field_date_test.js index b22177d37ef..326a6eb8669 100644 --- a/tests/mocha/field_date_test.js +++ b/tests/mocha/field_date_test.js @@ -153,6 +153,9 @@ suite ('Date Fields', function() { setup(function() { this.dateField = new Blockly.FieldDate('2020-02-20'); }); + teardown(function() { + this.dateField.setValidator(null); + }); suite('Null Validator', function() { setup(function() { this.dateField.setValidator(function() { @@ -175,5 +178,14 @@ suite ('Date Fields', function() { assertValue(this.dateField, '3030-03-20'); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.dateField.setValidator(function() {}); + }); + test('New Value', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-30'); + }); + }); }); }); diff --git a/tests/mocha/field_dropdown_test.js b/tests/mocha/field_dropdown_test.js index f8c54d801b2..aec3de6de77 100644 --- a/tests/mocha/field_dropdown_test.js +++ b/tests/mocha/field_dropdown_test.js @@ -42,22 +42,28 @@ suite ('Dropdown Fields', function() { }); }); test('Array Items not Arrays', function() { - console.log('You should see three console warnings after this message.'); + var stub = sinon.stub(console, 'error'); chai.assert.throws(function() { new Blockly.FieldDropdown([1, 2, 3]); }); + chai.assert(stub.calledThrice); + stub.restore(); }); test('Array Items with Invalid IDs', function() { - console.log('You should see three console warnings after this message.'); + var stub = sinon.stub(console, 'error'); chai.assert.throws(function() { new Blockly.FieldDropdown([['1', 1], ['2', 2], ['3', 3]]); }); + chai.assert(stub.calledThrice); + stub.restore(); }); test('Array Items with Invalid Content', function() { - console.log('You should see three console warnings after this message.'); + var stub = sinon.stub(console, 'error'); chai.assert.throws(function() { new Blockly.FieldDropdown([[1, '1'], [2, '2'], [3, '3']]); }); + chai.assert(stub.calledThrice); + stub.restore(); }); test('Text Dropdown', function() { var dropdownField = new Blockly.FieldDropdown( @@ -107,24 +113,30 @@ suite ('Dropdown Fields', function() { }); }); test('Array Items not Arrays', function() { - console.log('You should see three console warnings after this message.'); + var stub = sinon.stub(console, 'error'); chai.assert.throws(function() { Blockly.FieldDropdown.fromJson({ options: [1, 2, 3] }); }); + chai.assert(stub.calledThrice); + stub.restore(); }); test('Array Items with Invalid IDs', function() { - console.log('You should see three console warnings after this message.'); + var stub = sinon.stub(console, 'error'); chai.assert.throws(function() { Blockly.FieldDropdown.fromJson( { options:[['1', 1], ['2', 2], ['3', 3]] }); }); + chai.assert(stub.calledThrice); + stub.restore(); }); test('Array Items with Invalid Content', function() { - console.log('You should see three console warnings after this message.'); + var stub = sinon.stub(console, 'error'); chai.assert.throws(function() { Blockly.FieldDropdown.fromJson( { options:[[1, '1'], [2, '2'], [3, '3']] }); }); + chai.assert(stub.calledThrice); + stub.restore(); }); test('Text Dropdown', function() { var dropdownField = Blockly.FieldDropdown.fromJson( @@ -167,6 +179,9 @@ suite ('Dropdown Fields', function() { ["1a","1A"], ["1b","1B"], ["1c","1C"], ["2a","2A"], ["2b","2B"], ["2c","2C"]]); }); + teardown(function() { + this.dropdownField.setValidator(null); + }); suite('Null Validator', function() { setup(function() { this.dropdownField.setValidator(function() { @@ -189,5 +204,14 @@ suite ('Dropdown Fields', function() { assertValue(this.dropdownField, '1B', '1b'); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.dropdownField.setValidator(function() {}); + }); + test('New Value', function() { + this.dropdownField.setValue('1B'); + assertValue(this.dropdownField, '1B', '1b'); + }); + }); }); }); diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index 3402c67666b..5485c2d9421 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -27,8 +27,8 @@ suite ('Number Fields', function() { assertEquals(parseFloat(actualValue), expectedValue); assertEquals(actualText, opt_expectedText); } - function assertValueDefault(numberFieldField) { - assertValue(numberFieldField, 0); + function assertValueDefault(numberField) { + assertValue(numberField, 0); } function assertNumberField(numberField, expectedMin, expectedMax, expectedPrecision, expectedValue) { @@ -297,45 +297,65 @@ suite ('Number Fields', function() { }); suite('Validators', function() { setup(function() { - this.numberFieldField = new Blockly.FieldNumber(1); + this.numberField = new Blockly.FieldNumber(1); Blockly.FieldTextInput.htmlInput_ = Object.create(null); Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; }); + teardown(function() { + this.numberField.setValidator(null); + Blockly.FieldTextInput.htmlInput_ = null; + }); suite('Null Validator', function() { setup(function() { - this.numberFieldField.setValidator(function() { + this.numberField.setValidator(function() { return null; }); }); test('When Editing', function() { - this.numberFieldField.isBeingEdited_ = true; + this.numberField.isBeingEdited_ = true; Blockly.FieldTextInput.htmlInput_.value = '2'; - this.numberFieldField.onHtmlInputChange_(null); - assertValue(this.numberFieldField, 1, '2'); - this.numberFieldField.isBeingEdited_ = false; + this.numberField.onHtmlInputChange_(null); + assertValue(this.numberField, 1, '2'); + this.numberField.isBeingEdited_ = false; }); test('When Not Editing', function() { - this.numberFieldField.setValue(2); - assertValue(this.numberFieldField, 1); + this.numberField.setValue(2); + assertValue(this.numberField, 1); }); }); suite('Force End with 6 Validator', function() { setup(function() { - this.numberFieldField.setValidator(function(newValue) { + this.numberField.setValidator(function(newValue) { return String(newValue).replace(/.$/, "6"); }); }); test('When Editing', function() { - this.numberFieldField.isBeingEdited_ = true; + this.numberField.isBeingEdited_ = true; Blockly.FieldTextInput.htmlInput_.value = '25'; - this.numberFieldField.onHtmlInputChange_(null); - assertValue(this.numberFieldField, 26, '25'); - this.numberFieldField.isBeingEdited_ = false; + this.numberField.onHtmlInputChange_(null); + assertValue(this.numberField, 26, '25'); + this.numberField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.numberField.setValue(25); + assertValue(this.numberField, 26); + }); + }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.numberField.setValidator(function() {}); + }); + test('When Editing', function() { + this.numberField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '2'; + this.numberField.onHtmlInputChange_(null); + assertValue(this.numberField, 2); + this.numberField.isBeingEdited_ = false; }); test('When Not Editing', function() { - this.numberFieldField.setValue(25); - assertValue(this.numberFieldField, 26); + this.numberField.setValue(2); + assertValue(this.numberField, 2); }); }); }); diff --git a/tests/mocha/field_test.js b/tests/mocha/field_test.js index 655f968247c..7e976c8a51f 100644 --- a/tests/mocha/field_test.js +++ b/tests/mocha/field_test.js @@ -49,8 +49,10 @@ suite ('Abstract Fields', function() { test('Editable Default(true), Serializable Default(false)', function() { // An old default field should be serialized. var field = new FieldDefault(); - console.log('You should receive a warning after this message'); + var stub = sinon.stub(console, 'warn'); assertEquals(true, field.isSerializable()); + chai.assert(stub.calledOnce); + stub.restore(); }); test('Editable False, Serializable Default(false)', function() { // An old non-editable field should not be serialized. @@ -70,4 +72,273 @@ suite ('Abstract Fields', function() { assertEquals(true, field.isSerializable()); }); }); + suite ('setValue', function() { + function addSpies(field) { + if (!this.isSpying) { + sinon.spy(field, 'doValueInvalid_'); + sinon.spy(field, 'doValueUpdate_'); + sinon.spy(field, 'forceRerender'); + this.isSpying = true; + } + } + function removeSpies(field) { + if (this.isSpying) { + field.doValueInvalid_.restore(); + field.doValueUpdate_.restore(); + field.forceRerender.restore(); + this.isSpying = false; + } + } + setup(function() { + this.field = new Blockly.Field(); + this.field.isDirty_ = false; + this.cachedDoClassValidation = this.field.doClassValidation_; + this.cachedDoValueUpdate = this.field.doValueUpdate_; + this.cachedDoValueInvalid = this.field.doValueInvalid_; + }); + teardown(function() { + removeSpies(this.field); + this.field.doClassValidation_ = this.cachedDoClassValidation; + this.field.doValueUpdate_ = this.cachedDoValueUpdate; + this.field.doValueInvalid_ = this.cachedDoValueInvalid; + this.field.setValidator(null); + }); + test('Null', function() { + addSpies(this.field); + this.field.setValue(null); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.notCalled); + }); + test('No Validators, Dirty (Default)', function() { + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + chai.assert(this.field.forceRerender.calledOnce); + }); + test('No Validators, Not Dirty', function() { + this.field.doValueUpdate_ = function(newValue) { + this.value_ = newValue; + this.isDirty_ = false; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + chai.assert(this.field.forceRerender.notCalled); + }); + test('Class Validator Returns Invalid, Not Dirty (Default)', function() { + this.field.doClassValidation_ = function() { + return null; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.calledOnce); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.notCalled); + }); + test('Class Validator Returns Invalid, Dirty', function() { + this.field.doClassValidation_ = function() { + return null; + }; + this.field.doValueInvalid_ = function() { + this.isDirty_ = true; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.calledOnce); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.calledOnce); + }); + test('Class Validator Returns Valid, Not Dirty', function() { + this.field.doClassValidation_ = function(newValue) { + return newValue; + }; + this.field.doValueUpdate_ = function() { + this.isDirty_ = false; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + chai.assert(this.field.forceRerender.notCalled); + }); + test('Class Validator Returns Valid, Dirty (Default)', function() { + this.field.doClassValidation_ = function(newValue) { + return newValue; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + chai.assert(this.field.forceRerender.calledOnce); + }); + test('Local Validator Returns Invalid, Not Dirty (Default)', function() { + this.field.setValidator(function() { + return null; + }); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.calledOnce); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.notCalled); + }); + test('Local Validator Returns Invalid, Dirty', function() { + this.field.setValidator(function() { + return null; + }); + this.field.doValueInvalid_ = function() { + this.isDirty_ = true; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.calledOnce); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.calledOnce); + }); + test('Local Validator Returns Valid, Not Dirty', function() { + this.field.setValidator(function(newValue) { + return newValue; + }); + this.field.doValueUpdate_ = function() { + this.isDirty_ = false; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + chai.assert(this.field.forceRerender.notCalled); + }); + test('Local Validator Returns Valid, Dirty (Default)', function() { + this.field.setValidator(function(newValue) { + return newValue; + }); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + chai.assert(this.field.forceRerender.calledOnce); + }); + test('New Value Matches Old Value', function() { + this.field.setValue('value'); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.notCalled); + }); + test('New Value (Class)Validates to Old Value', function() { + this.field.setValue('value'); + this.field.doClassValidation_ = function() { + return 'value'; + }; + addSpies(this.field); + this.field.setValue('notValue'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.notCalled); + }); + test('New Value (Local)Validates to Old Value', function() { + this.field.setValue('value'); + this.field.setValidator(function() { + return 'value'; + }); + addSpies(this.field); + this.field.setValue('notValue'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.notCalled); + chai.assert(this.field.forceRerender.notCalled); + }); + test('New Value (Class)Validates to not Old Value', function() { + this.field.setValue('value'); + this.field.doClassValidation_ = function() { + return 'notValue'; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('New Value (Local)Validates to not Old Value', function() { + this.field.setValue('value'); + this.field.setValidator(function() { + return 'notValue'; + }); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('Class Validator Returns Null', function() { + this.field.doClassValidation_ = function() { + return null; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.calledOnce); + chai.assert(this.field.doValueUpdate_.notCalled); + }); + test('Class Validator Returns Same', function() { + this.field.doClassValidation_ = function(newValue) { + return newValue; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('Class Validator Returns Different', function() { + this.field.doClassValidation_ = function() { + return 'differentValue'; + }; + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('Class Validator Returns Undefined', function() { + this.field.doClassValidation_ = function() {}; + addSpies(this.field); + this.field.setValue('value'); + chai.assert.equal(this.field.getValue(), 'value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('Local Validator Returns Null', function() { + this.field.setValidator(function() { + return null; + }); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.calledOnce); + chai.assert(this.field.doValueUpdate_.notCalled); + }); + test('Local Validator Returns Same', function() { + this.field.setValidator(function(newValue) { + return newValue; + }); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('Local Validator Returns Different', function() { + this.field.setValidator(function() { + return 'differentValue'; + }); + addSpies(this.field); + this.field.setValue('value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + test('Local Validator Returns Undefined', function() { + this.field.setValidator(function() {}); + addSpies(this.field); + this.field.setValue('value'); + chai.assert.equal(this.field.getValue(), 'value'); + chai.assert(this.field.doValueInvalid_.notCalled); + chai.assert(this.field.doValueUpdate_.calledOnce); + }); + }); }); diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js index 64e36d6eda5..30ed5b6886d 100644 --- a/tests/mocha/field_textinput_test.js +++ b/tests/mocha/field_textinput_test.js @@ -173,6 +173,10 @@ suite ('Text Input Fields', function() { Blockly.FieldTextInput.htmlInput_.oldValue_ = 'value'; Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 'value'; }); + teardown(function() { + this.textInputField.setValidator(null); + Blockly.FieldTextInput.htmlInput_ = null; + }); suite('Null Validator', function() { setup(function() { this.textInputField.setValidator(function() { @@ -209,5 +213,21 @@ suite ('Text Input Fields', function() { assertValue(this.textInputField, 'bbb'); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.textInputField.setValidator(function() {}); + }); + test('When Editing', function() { + this.textInputField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = 'newValue'; + this.textInputField.onHtmlInputChange_(null); + assertValue(this.textInputField, 'newValue'); + this.textInputField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'newValue'); + }); + }); }); }); diff --git a/tests/mocha/field_variable_test.js b/tests/mocha/field_variable_test.js index 1e93228950e..d38117e85f4 100644 --- a/tests/mocha/field_variable_test.js +++ b/tests/mocha/field_variable_test.js @@ -136,8 +136,11 @@ suite('Variable Fields', function() { test('Undefined', function() { var variableField = createAndInitFieldConstructor( this.workspace, 'name1'); + var stub = sinon.stub(console, 'warn'); variableField.setValue(undefined); assertValue(variableField, 'name1'); + chai.assert(stub.calledOnce); + stub.restore(); }); test('New Variable ID', function() { this.workspace.createVariable('name2', null, 'id2'); @@ -155,8 +158,11 @@ suite('Variable Fields', function() { test('Variable Does not Exist', function() { var variableField = createAndInitFieldConstructor( this.workspace, 'name1'); + var stub = sinon.stub(console, 'warn'); variableField.setValue('id1'); assertValue(variableField, 'name1'); + chai.assert(stub.calledOnce); + stub.restore(); }); }); suite('Validators', function() { @@ -166,6 +172,9 @@ suite('Variable Fields', function() { this.workspace.createVariable('name3', null, 'id3'); this.variableField = createAndInitFieldConstructor(this.workspace, 'name1'); }); + teardown(function() { + this.variableField.setValidator(null); + }); suite('Null Validator', function() { setup(function() { this.variableField.setValidator(function() { @@ -190,6 +199,15 @@ suite('Variable Fields', function() { assertValue(this.variableField, 'name2', 'id2'); }); }); + suite('Returns Undefined Validator', function() { + setup(function() { + this.variableField.setValidator(function() {}); + }); + test('New Value', function() { + this.variableField.setValue('id2'); + assertValue(this.variableField, 'name2', 'id2'); + }); + }); }); suite('Get variable types', function() { setup(function() { From 7e7d7062012856b10b8b043a572a25628d0cf36d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 25 May 2019 16:24:20 -0700 Subject: [PATCH 080/233] Fixed angle offset property. --- core/field_angle.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/field_angle.js b/core/field_angle.js index cd1138aec27..de6f2c7f2aa 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -267,7 +267,10 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) { if (Blockly.FieldAngle.CLOCKWISE) { angle = Blockly.FieldAngle.OFFSET + 360 - angle; } else { - angle -= Blockly.FieldAngle.OFFSET; + angle = 360 - (Blockly.FieldAngle.OFFSET - angle); + } + if (angle > 360) { + angle -= 360; } if (Blockly.FieldAngle.ROUND) { angle = Math.round(angle / Blockly.FieldAngle.ROUND) * From 378fbfd87992eeebd9630f1ac77269b161f813e8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 25 May 2019 16:51:42 -0700 Subject: [PATCH 081/233] Fixed wrap not displaying the correct text. --- core/field_angle.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/field_angle.js b/core/field_angle.js index de6f2c7f2aa..df1d6252a0e 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -264,6 +264,8 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) { } else if (dy > 0) { angle += 360; } + + // Do offsetting. if (Blockly.FieldAngle.CLOCKWISE) { angle = Blockly.FieldAngle.OFFSET + 360 - angle; } else { @@ -272,11 +274,18 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) { if (angle > 360) { angle -= 360; } + + // Do rounding. if (Blockly.FieldAngle.ROUND) { angle = Math.round(angle / Blockly.FieldAngle.ROUND) * Blockly.FieldAngle.ROUND; } + // Do wrapping. + if (angle > Blockly.FieldAngle.WRAP) { + angle -= 360; + } + // Update value. var angleString = String(angle); if (angleString != this.text_) { From bace90e538cb4a4d1cf6d09a1b4045c89600d304 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 25 May 2019 16:58:38 -0700 Subject: [PATCH 082/233] Fixed gauge breaking at high angle values. --- core/field_angle.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/field_angle.js b/core/field_angle.js index df1d6252a0e..0e6f05be58f 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -307,6 +307,7 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() { } // Always display the input (i.e. getText) even if it is invalid. var angleDegrees = Number(this.getText()) + Blockly.FieldAngle.OFFSET; + angleDegrees = angleDegrees % 360; var angleRadians = Blockly.utils.toRadians(angleDegrees); var path = ['M ', Blockly.FieldAngle.HALF, ',', Blockly.FieldAngle.HALF]; var x2 = Blockly.FieldAngle.HALF; From 38f437a87e174e75ed106dc78bbc48cf16c9b846 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 25 May 2019 17:36:27 -0700 Subject: [PATCH 083/233] Fixed angle fields not displaying 0 when given an empty string. --- core/field_textinput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/field_textinput.js b/core/field_textinput.js index 068a5ecc41c..7e3e8e65f11 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -396,7 +396,7 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() { thisField.isBeingEdited_ = false; // No need to call setValue because if the widget is being closed the // latest input text has already been validated. - if (thisField.value_ != thisField.text_) { + if (thisField.value_ !== thisField.text_) { // At the end of an edit the text should be the same as the value. It // may not be if the input text is different than the validated text. // We should fix that. From c8704689e5a5943cdbdff15dbe6b029434cdbc02 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 27 May 2019 16:33:04 +0200 Subject: [PATCH 084/233] Localisation updates from https://translatewiki.net. --- msg/json/es.json | 23 +++++++++++++---------- msg/json/he.json | 7 ++++++- msg/json/nb.json | 2 ++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/msg/json/es.json b/msg/json/es.json index 4e3b750dcc7..25b33f3e9b7 100644 --- a/msg/json/es.json +++ b/msg/json/es.json @@ -12,7 +12,8 @@ "Julián L", "Luisangelrg", "MarcoAurelio", - "Ryo567" + "Ryo567", + "Harvest" ] }, "VARIABLES_DEFAULT_NAME": "elemento", @@ -37,18 +38,18 @@ "UNDO": "Deshacer", "REDO": "Rehacer", "CHANGE_VALUE_TITLE": "Cambiar el valor:", - "RENAME_VARIABLE": "Renombrar la variable…", + "RENAME_VARIABLE": "Cambiar nombre de variable…", "RENAME_VARIABLE_TITLE": "Renombrar todas las variables «%1» a:", "NEW_VARIABLE": "Crear variable…", "NEW_STRING_VARIABLE": "Crear una cadena variable...", - "NEW_NUMBER_VARIABLE": "Crear un número variable...", - "NEW_COLOUR_VARIABLE": "Crear un color variable...", + "NEW_NUMBER_VARIABLE": "Crear una variable de número...", + "NEW_COLOUR_VARIABLE": "Crear una variable de color...", "NEW_VARIABLE_TYPE_TITLE": "Nuevo tipo de variable:", "NEW_VARIABLE_TITLE": "Nombre de variable nueva:", - "VARIABLE_ALREADY_EXISTS": "Ya existe una variable llamada \"%1\".", + "VARIABLE_ALREADY_EXISTS": "Ya existe una variable llamada '%1'.", "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Ya existe una variable nombrada '%1' para otra variable del tipo: '%2'.", - "DELETE_VARIABLE_CONFIRMATION": "¿Borrar %1 usos de la variable \"%2\"?", - "CANNOT_DELETE_VARIABLE_PROCEDURE": "No se puede eliminar la variable \"%1\" porque es parte de la definición de la función \"%2\"", + "DELETE_VARIABLE_CONFIRMATION": "¿Borrar %1 usos de la variable '%2'?", + "CANNOT_DELETE_VARIABLE_PROCEDURE": "No se puede eliminar la variable '%1' porque es parte de la definición de la función '%2'", "DELETE_VARIABLE": "Borrar la variable \"%1\"", "COLOUR_PICKER_HELPURL": "https://es.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Elige un color de la paleta.", @@ -63,8 +64,8 @@ "COLOUR_BLEND_COLOUR1": "color 1", "COLOUR_BLEND_COLOUR2": "color 2", "COLOUR_BLEND_RATIO": "proporción", - "COLOUR_BLEND_TOOLTIP": "Combina dos colores con una proporción determinada (0,0–1,0).", - "CONTROLS_REPEAT_HELPURL": "https://es.wikipedia.org/wiki/Bucle_for", + "COLOUR_BLEND_TOOLTIP": "Combina dos colores con una proporción determinada (0,0-1,0).", + "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "repetir %1 veces", "CONTROLS_REPEAT_INPUT_DO": "hacer", "CONTROLS_REPEAT_TOOLTIP": "Hacer algunas declaraciones varias veces.", @@ -199,6 +200,7 @@ "MATH_RANDOM_FLOAT_TOOLTIP": "Devuelve una fracción aleatoria entre 0,0 (ambos inclusive) y 1.0 (exclusivo).", "MATH_ATAN2_HELPURL": "https://es.wikipedia.org/wiki/Arcotangente_de_dos_par%C3%A1metros", "MATH_ATAN2_TITLE": "Arcotangente de X:%1 Y:%2", + "MATH_ATAN2_TOOLTIP": "Regresar el arcotangente del punto (X,Y) en grados de -180 a 180.", "TEXT_TEXT_HELPURL": "https://es.wikipedia.org/wiki/Cadena_de_caracteres", "TEXT_TEXT_TOOLTIP": "Una letra, palabra o línea de texto.", "TEXT_JOIN_TITLE_CREATEWITH": "crear texto con", @@ -355,5 +357,6 @@ "PROCEDURES_CREATE_DO": "Crear '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Si un valor es verdadero, entonces devuelve un segundo valor.", "PROCEDURES_IFRETURN_WARNING": "Advertencia: Este bloque solo puede ser utilizado dentro de la definición de una función.", - "WORKSPACE_COMMENT_DEFAULT_TEXT": "Di algo…" + "WORKSPACE_COMMENT_DEFAULT_TEXT": "Di algo…", + "COLLAPSED_WARNINGS_WARNING": "Bloques colapsados contienen advertencias." } diff --git a/msg/json/he.json b/msg/json/he.json index 93e4aee4a6b..0c89ad2eff3 100644 --- a/msg/json/he.json +++ b/msg/json/he.json @@ -14,7 +14,8 @@ "Guycn2", "Deborahjay", "נדב ס", - "Motife" + "Motife", + "Steeve815" ] }, "VARIABLES_DEFAULT_NAME": "פריט", @@ -44,11 +45,13 @@ "NEW_VARIABLE": "צור משתנה...", "NEW_STRING_VARIABLE": "צור משתנה מחרוזת", "NEW_NUMBER_VARIABLE": "צור משתנה מחרוזת", + "NEW_COLOUR_VARIABLE": "יצירת משתנה צבע...", "NEW_VARIABLE_TYPE_TITLE": "סוג המשתנה החדש:", "NEW_VARIABLE_TITLE": "שם המשתנה החדש:", "VARIABLE_ALREADY_EXISTS": "קיים כבר משתנה בשם \"%1\".", "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "קיים כבר משתנה בשם \"%1\" מסוג אחר: \"%2\"", "CANNOT_DELETE_VARIABLE_PROCEDURE": "אי אפשר למחוק את המשתנה \"%1\", מכיוון שהגדרת הפונקציה \"%2\" משתמשת בו.", + "DELETE_VARIABLE": "מחק את משתנה ה'%1'", "COLOUR_PICKER_HELPURL": "http://he.wikipedia.org/wiki/%D7%A6%D7%91%D7%A2", "COLOUR_PICKER_TOOLTIP": "בחר צבע מן הצבעים.", "COLOUR_RANDOM_TITLE": "צבע אקראי", @@ -268,6 +271,7 @@ "LISTS_SORT_HELPURL": "https://github.com/google/blockly/wiki/Lists#sorting-a-list", "LISTS_SORT_ORDER_ASCENDING": "סדר עולה", "LISTS_SORT_ORDER_DESCENDING": "סדר יורד", + "LISTS_SORT_TYPE_NUMERIC": "נומרי", "LISTS_SORT_TYPE_TEXT": "סדר אלפביתי", "LISTS_SORT_TYPE_IGNORECASE": "סדר אלפביתי, לא תלוי רישיות", "LISTS_SPLIT_LIST_FROM_TEXT": "יצירת רשימה מטקסט", @@ -282,6 +286,7 @@ "PROCEDURES_BEFORE_PARAMS": "עם:", "PROCEDURES_CALL_BEFORE_PARAMS": "עם:", "PROCEDURES_DEFNORETURN_TOOLTIP": "יצירת פונקציה ללא פלט.", + "PROCEDURES_DEFNORETURN_COMMENT": "תאר את הפונקציה הזו...", "PROCEDURES_DEFRETURN_RETURN": "להחזיר", "PROCEDURES_DEFRETURN_TOOLTIP": "יצירת פונקציה עם פלט.", "PROCEDURES_ALLOW_STATEMENTS": "לאפשר פעולות", diff --git a/msg/json/nb.json b/msg/json/nb.json index 3c022999fd4..ca5f3052ac8 100644 --- a/msg/json/nb.json +++ b/msg/json/nb.json @@ -204,6 +204,8 @@ "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "tilfeldig flyttall", "MATH_RANDOM_FLOAT_TOOLTIP": "Returner et tilfeldig flyttall mellom 0.0 (inkludert) og 1.0 (ikke inkludert).", + "MATH_ATAN2_HELPURL": "https://en.wikipedia.org/wiki/Atan2", + "MATH_ATAN2_TITLE": "atan2 av X:%1 Y:%2", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "En bokstav, ett ord eller en linje med tekst.", "TEXT_JOIN_TITLE_CREATEWITH": "lag tekst med", From 00619316868363c1ef1bbd541ca1102383a1d79c Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 27 May 2019 07:41:01 -0700 Subject: [PATCH 085/233] Change applicable locations to use the modulo assignment operator. --- core/field_angle.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index 0e6f05be58f..7f521ec9d86 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -307,7 +307,7 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() { } // Always display the input (i.e. getText) even if it is invalid. var angleDegrees = Number(this.getText()) + Blockly.FieldAngle.OFFSET; - angleDegrees = angleDegrees % 360; + angleDegrees %= 360; var angleRadians = Blockly.utils.toRadians(angleDegrees); var path = ['M ', Blockly.FieldAngle.HALF, ',', Blockly.FieldAngle.HALF]; var x2 = Blockly.FieldAngle.HALF; @@ -347,7 +347,7 @@ Blockly.FieldAngle.prototype.doClassValidation_ = function(newValue) { return null; } var n = parseFloat(newValue || 0); - n = n % 360; + n %= 360; if (n < 0) { n += 360; } From 4d9c0f01f53f4c3e23f42711949d47fd8ba4aa4c Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 27 May 2019 15:45:18 -0700 Subject: [PATCH 086/233] Moved the date field to the dropdown div, and restyled it. --- core/field_date.js | 283 +++++++++++++++++------------------- tests/blocks/test_blocks.js | 5 +- 2 files changed, 139 insertions(+), 149 deletions(-) diff --git a/core/field_date.js b/core/field_date.js index 6b7a2dd31ee..c9cddc29fdf 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -82,6 +82,22 @@ Blockly.FieldDate.prototype.SERIALIZABLE = true; */ Blockly.FieldDate.prototype.CURSOR = 'text'; +/** + * Border colour for the dropdown div showing the date picker. Must be a CSS + * string. + * @type {string} + * @private + */ +Blockly.FieldDate.prototype.DROPDOWN_BORDER_COLOUR = 'silver'; + +/** + * Background colour for the dropdown div showing the date picker. Must be a + * CSS string. + * @type {string} + * @private + */ +Blockly.FieldDate.prototype.DROPDOWN_BACKGROUND_COLOUR = 'white'; + /** * Close the colour picker if this input is being deleted. */ @@ -109,34 +125,102 @@ Blockly.FieldDate.prototype.doClassValidation_ = function(newValue) { }; /** - * Create a date picker under the date field. + * Called when the given value is invalid. If the picker is shown, set + * isDirty to true so that it gets reset to the previous selection. + * @protected + */ +Blockly.FieldDate.prototype.doValueInvalid_ = function() { + if (this.picker_) { + this.isDirty_ = true; + } +}; + +/** + * Render the field. If the picker is shown make sure it has the current + * date selected. + * @protected + */ +Blockly.FieldDate.prototype.render_ = function() { + Blockly.FieldDate.superClass_.render_.call(this); + if (this.picker_) { + this.picker_.setDate(goog.date.Date.fromIsoString(this.getValue())); + this.updateEditor_(); + } +}; + +/** + * Updates the field's colours to match those of the block. + * @package + */ +Blockly.FieldDate.prototype.updateColour = function() { + this.todayColour_ = this.sourceBlock_.getColour(); + this.selectedColour_ = this.sourceBlock_.getColourShadow(); + this.updateEditor_(); +}; + +/** + * Updates the picker to show the current date and currently selected date. * @private */ -Blockly.FieldDate.prototype.showEditor_ = function() { - Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, - Blockly.FieldDate.widgetDispose_); +Blockly.FieldDate.prototype.updateEditor_ = function() { + if (!this.picker_) { + // Nothing to update. + return; + } + + // Updating today should come before updating selected, so that if the + // current day is selected, it will appear so. + if (this.oldTodayElement_) { + this.oldTodayElement_.style.backgroundColor = null; + this.oldTodayElement_.style.color = null; + } + var today = this.picker_.getElementByClass('goog-date-picker-today'); + this.oldTodayElement_ = today; + if (today) { + today.style.backgroundColor = this.todayColour_; + today.style.color = 'white'; + } - // Record viewport dimensions before adding the picker. - var viewportBBox = Blockly.utils.getViewportBBox(); - var anchorBBox = this.getScaledBBox_(); + if (this.oldSelectedElement_ && this.oldSelectedElement_ != today) { + this.oldSelectedElement_.style.backgroundColor = null; + this.oldSelectedElement_.style.color = null; + } + var selected = this.picker_.getElementByClass('goog-date-picker-selected'); + this.oldSelectedElement_ = selected; + if (selected) { + selected.style.backgroundColor = this.selectedColour_; + selected.style.color = this.todayColour_; + } +}; - // Create and add the date picker, then record the size. - var picker = this.createWidget_(); - var pickerSize = goog.style.getSize(picker.getElement()); +/** + * Create a date picker under the date field. + * @private + */ +Blockly.FieldDate.prototype.showEditor_ = function() { + Blockly.DropDownDiv.hideWithoutAnimation(); + Blockly.DropDownDiv.clearContent(); - // Position the picker to line up with the field. - Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, pickerSize, - this.sourceBlock_.RTL); + this.picker_ = this.createWidget_(); + this.picker_.render(Blockly.DropDownDiv.getContentDiv()); + Blockly.utils.addClass(this.picker_.getElement(), 'blocklyDatePicker'); + Blockly.DropDownDiv.showPositionedByField(this); + Blockly.DropDownDiv.setColour( + this.DROPDOWN_BACKGROUND_COLOUR, this.DROPDOWN_BORDER_COLOUR); + this.updateEditor_(); - // Configure event handler. var thisField = this; - Blockly.FieldDate.changeEventKey_ = goog.events.listen(picker, + Blockly.FieldDate.changeEventKey_ = goog.events.listen(this.picker_, goog.ui.DatePicker.Events.CHANGE, function(event) { var date = event.date ? event.date.toIsoString(true) : ''; - Blockly.WidgetDiv.hide(); thisField.setValue(date); }); + Blockly.FieldDate.changeEventKey_ = goog.events.listen(this.picker_, + goog.ui.DatePicker.Events.CHANGE_ACTIVE_MONTH, + function(_e) { + thisField.updateEditor_(); + }); }; /** @@ -150,8 +234,8 @@ Blockly.FieldDate.prototype.createWidget_ = function() { var picker = new goog.ui.DatePicker(); picker.setAllowNone(false); picker.setShowWeekNum(false); - var div = Blockly.WidgetDiv.DIV; - picker.render(div); + picker.setUseNarrowWeekdayNames(true); + picker.setUseSimpleNavigationMenu(true); picker.setDate(goog.date.DateTime.fromIsoString(this.getValue())); return picker; }; @@ -164,6 +248,7 @@ Blockly.FieldDate.widgetDispose_ = function() { if (Blockly.FieldDate.changeEventKey_) { goog.events.unlistenByKey(Blockly.FieldDate.changeEventKey_); } + this.picker_ = null; Blockly.Events.setGroup(false); }; @@ -189,159 +274,61 @@ Blockly.FieldDate.loadLanguage_ = function() { * CSS for date picker. See css.js for use. */ Blockly.FieldDate.CSS = [ - /* Copied from: goog/css/datepicker.css */ - /** - * Copyright 2009 The Closure Library Authors. All Rights Reserved. - * - * Use of this source code is governed by the Apache License, Version 2.0. - * See the COPYING file for details. - */ - - /** - * Standard styling for a goog.ui.DatePicker. - * - * @author arv@google.com (Erik Arvidsson) - */ - - '.blocklyWidgetDiv .goog-date-picker,', - '.blocklyWidgetDiv .goog-date-picker th,', - '.blocklyWidgetDiv .goog-date-picker td {', + '.blocklyDatePicker,', + '.blocklyDatePicker th,', + '.blocklyDatePicker td {', ' font: 13px Arial, sans-serif;', + ' color: #3c4043;', '}', - '.blocklyWidgetDiv .goog-date-picker {', - ' -moz-user-focus: normal;', - ' -moz-user-select: none;', - ' position: relative;', - ' border: 1px solid #000;', - ' float: left;', - ' padding: 2px;', - ' color: #000;', - ' background: #c3d9ff;', - ' cursor: default;', - '}', - - '.blocklyWidgetDiv .goog-date-picker th {', - ' text-align: center;', - '}', - - '.blocklyWidgetDiv .goog-date-picker td {', + '.blocklyDatePicker th,', + '.blocklyDatePicker td {', ' text-align: center;', ' vertical-align: middle;', - ' padding: 1px 3px;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-menu {', - ' position: absolute;', - ' background: threedface;', - ' border: 1px solid gray;', - ' -moz-user-focus: normal;', - ' z-index: 1;', - ' outline: none;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-menu ul {', - ' list-style: none;', - ' margin: 0px;', - ' padding: 0px;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-menu ul li {', - ' cursor: default;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-menu-selected {', - ' background: #ccf;', - '}', - - '.blocklyWidgetDiv .goog-date-picker th {', - ' font-size: .9em;', '}', - '.blocklyWidgetDiv .goog-date-picker td div {', - ' float: left;', + '.blocklyDatePicker .goog-date-picker-wday,', + '.blocklyDatePicker .goog-date-picker-date {', + ' padding: 6px 6px;', '}', - '.blocklyWidgetDiv .goog-date-picker button {', - ' padding: 0px;', + '.blocklyDatePicker button {', + ' cursor: pointer;', + ' padding: 6px 6px;', ' margin: 1px 0;', ' border: 0;', - ' color: #20c;', + ' color: #3c4043;', ' font-weight: bold;', ' background: transparent;', '}', - '.blocklyWidgetDiv .goog-date-picker-date {', - ' background: #fff;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-week,', - '.blocklyWidgetDiv .goog-date-picker-wday {', - ' padding: 1px 3px;', - ' border: 0;', - ' border-color: #a2bbdd;', - ' border-style: solid;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-week {', - ' border-right-width: 1px;', + '.blocklyDatePicker .goog-date-picker-previousMonth,', + '.blocklyDatePicker .goog-date-picker-nextMonth {', + ' height: 24px;', + ' width: 24px;', '}', - '.blocklyWidgetDiv .goog-date-picker-wday {', - ' border-bottom-width: 1px;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-head td {', - ' text-align: center;', - '}', - - /** Use td.className instead of !important */ - '.blocklyWidgetDiv td.goog-date-picker-today-cont {', - ' text-align: center;', - '}', - - /** Use td.className instead of !important */ - '.blocklyWidgetDiv td.goog-date-picker-none-cont {', - ' text-align: center;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-month {', - ' min-width: 11ex;', - ' white-space: nowrap;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-year {', - ' min-width: 6ex;', - ' white-space: nowrap;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-monthyear {', - ' white-space: nowrap;', - '}', - - '.blocklyWidgetDiv .goog-date-picker table {', - ' border-collapse: collapse;', - '}', - - '.blocklyWidgetDiv .goog-date-picker-other-month {', - ' color: #888;', + '.blocklyDatePicker .goog-date-picker-monthyear {', + ' font-weight: bold;', '}', - '.blocklyWidgetDiv .goog-date-picker-wkend-start,', - '.blocklyWidgetDiv .goog-date-picker-wkend-end {', - ' background: #eee;', + '.blocklyDatePicker .goog-date-picker-wday, ', + '.blocklyDatePicker .goog-date-picker-other-month {', + ' color: #70757a;', + ' border-radius: 12px;', '}', - /** Use td.className instead of !important */ - '.blocklyWidgetDiv td.goog-date-picker-selected {', - ' background: #c3d9ff;', + '.blocklyDatePicker button,', + '.blocklyDatePicker .goog-date-picker-date {', + ' cursor: pointer;', + ' background-color: rgb(218, 220, 224, 0);', + ' border-radius: 12px;', + ' transition: background-color,opacity 100ms linear;', '}', - '.blocklyWidgetDiv .goog-date-picker-today {', - ' background: #9ab;', - ' font-weight: bold !important;', - ' border-color: #246 #9bd #9bd #246;', - ' color: #fff;', + '.blocklyDatePicker button:hover,', + '.blocklyDatePicker .goog-date-picker-date:hover {', + ' background-color: rgb(218, 220, 224, .5);', '}' ]; diff --git a/tests/blocks/test_blocks.js b/tests/blocks/test_blocks.js index cc7ca7124fe..9b1fdede128 100644 --- a/tests/blocks/test_blocks.js +++ b/tests/blocks/test_blocks.js @@ -914,7 +914,10 @@ Blockly.Blocks['test_validators_date_null'] = { }, validate: function(newValue) { - return null; + // We should be able to expect validators to like their initial values. + if (newValue != '2020-02-20') { + return null; + } } }; Blockly.Blocks['test_validators_date_force_20s'] = { From 459961c3cb9a1e0af6a7f28bbee7b07a302f872c Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Sat, 25 May 2019 23:35:19 -0700 Subject: [PATCH 087/233] Replace Element constants with Node constants. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Element constants apparently don’t exist in IE or Edge. Node constants apparently do. --- core/xml.js | 10 +++++----- externs/browser-externs.js | 32 -------------------------------- tests/compile/compile.sh | 1 - 3 files changed, 5 insertions(+), 38 deletions(-) delete mode 100644 externs/browser-externs.js diff --git a/core/xml.js b/core/xml.js index c542a0e4c33..3006663a106 100644 --- a/core/xml.js +++ b/core/xml.js @@ -252,7 +252,7 @@ Blockly.Xml.cloneShadow_ = function(shadow) { while (node && !node.nextSibling) { textNode = node; node = node.parentNode; - if (textNode.nodeType == Element.TEXT_NODE && + if (textNode.nodeType == Node.TEXT_NODE && textNode.data.trim() == '' && node.firstChild != textNode) { // Prune whitespace after a tag. Blockly.utils.removeNode(textNode); @@ -261,7 +261,7 @@ Blockly.Xml.cloneShadow_ = function(shadow) { if (node) { textNode = node; node = node.nextSibling; - if (textNode.nodeType == Element.TEXT_NODE && + if (textNode.nodeType == Node.TEXT_NODE && textNode.data.trim() == '') { // Prune whitespace before a tag. Blockly.utils.removeNode(textNode); @@ -568,7 +568,7 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { */ Blockly.Xml.domToVariables = function(xmlVariables, workspace) { for (var i = 0, xmlChild; xmlChild = xmlVariables.childNodes[i]; i++) { - if (xmlChild.nodeType != Element.ELEMENT_NODE) { + if (xmlChild.nodeType != Node.ELEMENT_NODE) { continue; // Skip text nodes. } var type = xmlChild.getAttribute('type'); @@ -601,7 +601,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { var blockChild = null; for (var i = 0, xmlChild; xmlChild = xmlBlock.childNodes[i]; i++) { - if (xmlChild.nodeType == Element.TEXT_NODE) { + if (xmlChild.nodeType == Node.TEXT_NODE) { // Ignore any text at the level. It's all whitespace anyway. continue; } @@ -611,7 +611,7 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { var childBlockElement = null; var childShadowElement = null; for (var j = 0, grandchild; grandchild = xmlChild.childNodes[j]; j++) { - if (grandchild.nodeType == Element.ELEMENT_NODE) { + if (grandchild.nodeType == Node.ELEMENT_NODE) { if (grandchild.nodeName.toLowerCase() == 'block') { childBlockElement = /** @type {!Element} */ (grandchild); } else if (grandchild.nodeName.toLowerCase() == 'shadow') { diff --git a/externs/browser-externs.js b/externs/browser-externs.js deleted file mode 100644 index 38a84fdd9fb..00000000000 --- a/externs/browser-externs.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Visual Blocks Editor - * - * Copyright 2019 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Property definitions in browsers that Closure Compiler is - * unaware of. - * @author fraser@google.com (Neil Fraser) - * - * @externs - */ -'use strict'; - - -Element.ELEMENT_NODE = 1; -Element.TEXT_NODE = 3; diff --git a/tests/compile/compile.sh b/tests/compile/compile.sh index 6352746a3b4..f60c37cb179 100755 --- a/tests/compile/compile.sh +++ b/tests/compile/compile.sh @@ -82,7 +82,6 @@ COMPILATION_COMMAND="java -jar $COMPILER --js='$BLOCKLY_ROOT/tests/compile/main. --js='$CLOSURE_LIB_ROOT/closure/goog/**.js' \ --js='$CLOSURE_LIB_ROOT/third_party/closure/goog/**.js' \ --generate_exports \ - --externs $BLOCKLY_ROOT/externs/browser-externs.js \ --externs $BLOCKLY_ROOT/externs/svg-externs.js \ --compilation_level ADVANCED_OPTIMIZATIONS \ --dependency_mode=STRICT --entry_point=Main \ From 9099ee8c1456652a6f585e0817b3d6fb9cfad029 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 29 May 2019 12:48:55 -0700 Subject: [PATCH 088/233] Readded reevaluating values when constraints are set. (#2507) --- core/field_number.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/field_number.js b/core/field_number.js index 636621aca80..2e729d193d4 100644 --- a/core/field_number.js +++ b/core/field_number.js @@ -96,6 +96,7 @@ Blockly.FieldNumber.prototype.setConstraints = function(min, max, precision) { this.min_ = isNaN(min) ? -Infinity : min; max = parseFloat(max); this.max_ = isNaN(max) ? Infinity : max; + this.setValue(this.getValue()); }; /** From 73ff710a4d113cf4c441ebc8eddaa3cdce179aa0 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 29 May 2019 12:50:00 -0700 Subject: [PATCH 089/233] Added getSourceBlock function to field. (#2508) --- blocks/lists.js | 9 ++++----- blocks/math.js | 2 +- blocks/procedures.js | 8 ++++---- blocks/text.js | 4 ++-- core/dropdowndiv.js | 4 ++-- core/field.js | 8 ++++++++ core/procedures.js | 4 ++-- demos/blockfactory/blocks.js | 6 +++--- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/blocks/lists.js b/blocks/lists.js index 6bfa4213995..9e9217f1299 100644 --- a/blocks/lists.js +++ b/blocks/lists.js @@ -334,7 +334,7 @@ Blockly.Blocks['lists_getIndex'] = { this.setStyle('list_blocks'); var modeMenu = new Blockly.FieldDropdown(MODE, function(value) { var isStatement = (value == 'REMOVE'); - this.sourceBlock_.updateStatement_(isStatement); + this.getSourceBlock().updateStatement_(isStatement); }); this.appendValueInput('VALUE') .setCheck('Array') @@ -480,7 +480,7 @@ Blockly.Blocks['lists_getIndex'] = { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); // The 'isAt' variable is available due to this function being a closure. if (newAt != isAt) { - var block = this.sourceBlock_; + var block = this.getSourceBlock(); block.updateAt_(newAt); // This menu has been destroyed and replaced. Update the replacement. block.setFieldValue(value, 'WHERE'); @@ -618,7 +618,7 @@ Blockly.Blocks['lists_setIndex'] = { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); // The 'isAt' variable is available due to this function being a closure. if (newAt != isAt) { - var block = this.sourceBlock_; + var block = this.getSourceBlock(); block.updateAt_(newAt); // This menu has been destroyed and replaced. Update the replacement. block.setFieldValue(value, 'WHERE'); @@ -723,14 +723,13 @@ Blockly.Blocks['lists_getSublist'] = { // The 'isAt' variable is available due to this function being a // closure. if (newAt != isAt) { - var block = this.sourceBlock_; + var block = this.getSourceBlock(); block.updateAt_(n, newAt); // This menu has been destroyed and replaced. // Update the replacement. block.setFieldValue(value, 'WHERE' + n); return null; } - return undefined; }); this.getInput('AT' + n) .appendField(menu, 'WHERE' + n); diff --git a/blocks/math.js b/blocks/math.js index 3d4f337ae6b..4bc690916be 100644 --- a/blocks/math.js +++ b/blocks/math.js @@ -504,7 +504,7 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = { Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION = function() { this.getField('PROPERTY').setValidator(function(option) { var divisorInput = (option == 'DIVISIBLE_BY'); - this.sourceBlock_.updateShape_(divisorInput); + this.getSourceBlock().updateShape_(divisorInput); }); }; diff --git a/blocks/procedures.js b/blocks/procedures.js index 5188ac8b96e..c679ce54dd8 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -572,15 +572,15 @@ Blockly.Blocks['procedures_mutatorarg'] = { * @this Blockly.FieldTextInput */ validator_: function(varName) { - var outerWs = Blockly.Mutator.findParentWs(this.sourceBlock_.workspace); + var outerWs = Blockly.Mutator.findParentWs(this.getSourceBlock().workspace); varName = varName.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); if (!varName) { return null; } // Prevents duplicate parameter names in functions - var blocks = this.sourceBlock_.workspace.getAllBlocks(); + var blocks = this.getSourceBlock().workspace.getAllBlocks(); for (var i = 0; i < blocks.length; i += 1) { - if (blocks[i].id == this.sourceBlock_.id) { + if (blocks[i].id == this.getSourceBlock().id) { continue; } if (blocks[i].getFieldValue('NAME') == varName) { @@ -609,7 +609,7 @@ Blockly.Blocks['procedures_mutatorarg'] = { * @this Blockly.FieldTextInput */ deleteIntermediateVars_: function(newText) { - var outerWs = Blockly.Mutator.findParentWs(this.sourceBlock_.workspace); + var outerWs = Blockly.Mutator.findParentWs(this.getSourceBlock().workspace); if (!outerWs) { return; } diff --git a/blocks/text.js b/blocks/text.js index 244889456f5..91ed6c1fa52 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -296,7 +296,7 @@ Blockly.Blocks['text_getSubstring'] = { // The 'isAt' variable is available due to this function being a // closure. if (newAt != isAt) { - var block = this.sourceBlock_; + var block = this.getSourceBlock(); block.updateAt_(n, newAt); // This menu has been destroyed and replaced. // Update the replacement. @@ -862,7 +862,7 @@ Blockly.Constants.Text.TEXT_CHARAT_EXTENSION = function() { dropdown.setValidator(function(value) { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); if (newAt != this.isAt_) { - var block = this.sourceBlock_; + var block = this.getSourceBlock(); block.updateAt_(newAt); } }); diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 5af33b8c971..f5eefa06b07 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -250,7 +250,7 @@ Blockly.DropDownDiv.showPositionedByField = function(owner, // Set bounds to workspace; show the drop-down. Blockly.DropDownDiv.positionToField_ = true; Blockly.DropDownDiv.setBoundsElement( - owner.sourceBlock_.workspace.getParentSvg().parentNode); + owner.getSourceBlock().workspace.getParentSvg().parentNode); return Blockly.DropDownDiv.show( owner, primaryX, primaryY, secondaryX, secondaryY, opt_onHide); }; @@ -514,7 +514,7 @@ Blockly.DropDownDiv.repositionForWindowResize = function() { // when a field is focused, the soft keyboard opens triggering a window resize // event and we want the dropdown div to stick around so users can type into it. if (Blockly.DropDownDiv.owner_) { - var block = Blockly.DropDownDiv.owner_.sourceBlock_; + var block = Blockly.DropDownDiv.owner_.getSourceBlock(); var scale = block.workspace.scale; var bBox = { width: Blockly.DropDownDiv.positionToField_ ? diff --git a/core/field.js b/core/field.js index 0e7929178a0..ef66659b6b8 100644 --- a/core/field.js +++ b/core/field.js @@ -211,6 +211,14 @@ Blockly.Field.prototype.setSourceBlock = function(block) { this.sourceBlock_ = block; }; +/** + * Get the block this field is attached to. + * @return {Blockly.Block} The block containing this field. + */ +Blockly.Field.prototype.getSourceBlock = function() { + return this.sourceBlock_; +}; + /** * Initialize everything to render this field. Override * methods initModel and initView rather than this method. diff --git a/core/procedures.js b/core/procedures.js index a226bc9712c..6923a7d3bbf 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -163,11 +163,11 @@ Blockly.Procedures.rename = function(name) { name = name.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); // Ensure two identically-named procedures don't exist. - var legalName = Blockly.Procedures.findLegalName(name, this.sourceBlock_); + var legalName = Blockly.Procedures.findLegalName(name, this.getSourceBlock()); var oldName = this.text_; if (oldName != name && oldName != legalName) { // Rename any callers. - var blocks = this.sourceBlock_.workspace.getAllBlocks(false); + var blocks = this.getSourceBlock().workspace.getAllBlocks(false); for (var i = 0; i < blocks.length; i++) { if (blocks[i].renameProcedure) { blocks[i].renameProcedure(oldName, legalName); diff --git a/demos/blockfactory/blocks.js b/demos/blockfactory/blocks.js index 4ff1af61d06..19f8a15e6eb 100644 --- a/demos/blockfactory/blocks.js +++ b/demos/blockfactory/blocks.js @@ -46,9 +46,9 @@ Blockly.Blocks['factory_base'] = { ['↑ top connection', 'TOP'], ['↓ bottom connection', 'BOTTOM']], function(option) { - this.sourceBlock_.updateShape_(option); + this.getSourceBlock().updateShape_(option); // Connect a shadow block to this new input. - this.sourceBlock_.spawnOutputShadow_(option); + this.getSourceBlock().spawnOutputShadow_(option); }); this.appendDummyInput() .appendField(dropdown, 'CONNECTIONS'); @@ -863,7 +863,7 @@ Blockly.Blocks['colour_hue'] = { // Update the current block's colour to match. var hue = parseInt(text, 10); if (!isNaN(hue)) { - this.sourceBlock_.setColour(hue); + this.getSourceBlock().setColour(hue); } }, mutationToDom: function(workspace) { From dce0b774248b8f8311f3626573faf8d56c41cb94 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 30 May 2019 10:05:06 -0700 Subject: [PATCH 090/233] Fix 19 warnings in theme-related code. (#2523) * Fix 19 warnings in theme-related code. Resolves #2414 * Remove suppressPrefixSuffix property definition The mixin code throws an error if property exists on both objects. * eslint has strange ideas about indentation. --- core/block.js | 1 - core/blockly.js | 10 ++--- core/theme.js | 31 +++++++++------ core/theme/classic.js | 24 ++++++------ core/theme/highcontrast.js | 78 +++++++++++++++++++------------------- core/theme/modern.js | 34 +++++++++-------- core/toolbox.js | 3 +- core/xml.js | 3 +- 8 files changed, 99 insertions(+), 85 deletions(-) diff --git a/core/block.js b/core/block.js index 3fd1a43bcb4..db95e20a51a 100644 --- a/core/block.js +++ b/core/block.js @@ -265,7 +265,6 @@ Blockly.Block.prototype.colourTertiary_ = null; */ Blockly.Block.prototype.styleName_ = null; - /** * Dispose of this block. * @param {boolean} healStack If true, then try to heal any gap by connecting diff --git a/core/blockly.js b/core/blockly.js index a5a133d3c9b..27f12aba6cd 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -691,11 +691,11 @@ Blockly.checkBlockColourConstant_ = function( * @param {!Blockly.Theme} theme Theme for Blockly. */ Blockly.setTheme = function(theme) { - this.theme_ = theme; + Blockly.theme_ = theme; var ws = Blockly.getMainWorkspace(); if (ws) { - this.refreshTheme_(ws); + Blockly.refreshTheme_(ws); } }; @@ -706,7 +706,7 @@ Blockly.setTheme = function(theme) { */ Blockly.refreshTheme_ = function(ws) { // Update all blocks in workspace that have a style name. - this.updateBlockStyles_(ws.getAllBlocks().filter( + Blockly.updateBlockStyles_(ws.getAllBlocks().filter( function(block) { return block.getStyleName() !== undefined; } @@ -714,7 +714,7 @@ Blockly.refreshTheme_ = function(ws) { // Update blocks in the flyout. if (!ws.toolbox_ && ws.flyout_ && ws.flyout_.workspace_) { - this.updateBlockStyles_(ws.flyout_.workspace_.getAllBlocks()); + Blockly.updateBlockStyles_(ws.flyout_.workspace_.getAllBlocks()); } else { ws.refreshToolboxSelection(); } @@ -750,7 +750,7 @@ Blockly.updateBlockStyles_ = function(blocks) { * @return {Blockly.Theme} Theme for Blockly. */ Blockly.getTheme = function() { - return this.theme_; + return Blockly.theme_; }; // Export symbols that would otherwise be renamed by Closure compiler. diff --git a/core/theme.js b/core/theme.js index 0105c96f604..cda37fd5ba7 100644 --- a/core/theme.js +++ b/core/theme.js @@ -26,11 +26,17 @@ goog.provide('Blockly.Theme'); +/** + * A block style or a category style. + * @typedef {!Object.} + */ +Blockly.Theme.Style; + /** * Class for a theme. - * @param {Object.} blockStyles A map from style + * @param {!Object.} blockStyles A map from style * names (strings) to objects with style attributes relating to blocks. - * @param {Object.} categoryStyles A map from + * @param {!Object.} categoryStyles A map from * style names (strings) to objects with style attributes relating to * categories. * @constructor @@ -42,8 +48,8 @@ Blockly.Theme = function(blockStyles, categoryStyles) { /** * Overrides or adds all values from blockStyles to blockStyles_ - * @param {Object.} blockStyles List of - * block styles. + * @param {Object.} blockStyles Map of + * block styles. */ Blockly.Theme.prototype.setAllBlockStyles = function(blockStyles) { for (var key in blockStyles) { @@ -52,8 +58,8 @@ Blockly.Theme.prototype.setAllBlockStyles = function(blockStyles) { }; /** - * Gets a list of all the block style names. - * @return {Array.} List of blockstyle names. + * Gets a map of all the block style names. + * @return {!Object.} Map of block styles. */ Blockly.Theme.prototype.getAllBlockStyles = function() { return this.blockStyles_; @@ -62,7 +68,7 @@ Blockly.Theme.prototype.getAllBlockStyles = function() { /** * Gets the BlockStyle for the given block style name. * @param {string} blockStyleName The name of the block style. - * @return {Blockly.BlockStyle} The style with the block style name. + * @return {Blockly.Theme.Style|undefined} The named block style. */ Blockly.Theme.prototype.getBlockStyle = function(blockStyleName) { return this.blockStyles_[blockStyleName]; @@ -71,7 +77,7 @@ Blockly.Theme.prototype.getBlockStyle = function(blockStyleName) { /** * Overrides or adds a style to the blockStyles map. * @param {string} blockStyleName The name of the block style. - * @param {Blockly.BlockStyle} blockStyle The block style + * @param {Blockly.Theme.Style} blockStyle The block style. */ Blockly.Theme.prototype.setBlockStyle = function(blockStyleName, blockStyle) { this.blockStyles_[blockStyleName] = blockStyle; @@ -79,8 +85,8 @@ Blockly.Theme.prototype.setBlockStyle = function(blockStyleName, blockStyle) { /** * Gets the CategoryStyle for the given category style name. - * @param {string} categoryStyleName The name of the block style. - * @return {Blockly.CategoryStyle} The style with the block style name. + * @param {string} categoryStyleName The name of the category style. + * @return {Blockly.Theme.Style|undefined} The named category style. */ Blockly.Theme.prototype.getCategoryStyle = function(categoryStyleName) { return this.categoryStyles_[categoryStyleName]; @@ -89,8 +95,9 @@ Blockly.Theme.prototype.getCategoryStyle = function(categoryStyleName) { /** * Overrides or adds a style to the categoryStyles map. * @param {string} categoryStyleName The name of the category style. - * @param {Blockly.CategoryStyle} categoryStyle The category style + * @param {Blockly.Theme.Style} categoryStyle The category style. */ -Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName, categoryStyle) { +Blockly.Theme.prototype.setCategoryStyle = function(categoryStyleName, + categoryStyle) { this.categoryStyles_[categoryStyleName] = categoryStyle; }; diff --git a/core/theme/classic.js b/core/theme/classic.js index 5de42fefe8d..d3bb2cfbcaf 100644 --- a/core/theme/classic.js +++ b/core/theme/classic.js @@ -20,7 +20,7 @@ /** * @fileoverview Classic theme. - * Contains multi colored border to create shadow effect. + * Contains multi-coloured border to create shadow effect. */ 'use strict'; @@ -30,8 +30,8 @@ goog.provide('Blockly.Themes.Classic'); goog.require('Blockly.Theme'); -var defaultBlockStyles = { - "colour_blocks":{ +Blockly.Themes.Classic.defaultBlockStyles = { + "colour_blocks": { "colourPrimary": "20" }, "list_blocks": { @@ -55,17 +55,17 @@ var defaultBlockStyles = { "variable_blocks": { "colourPrimary": "330" }, - "variable_dynamic_blocks":{ + "variable_dynamic_blocks": { "colourPrimary": "310" }, - "hat_blocks":{ - "colourPrimary":"330", - "hat":"cap" + "hat_blocks": { + "colourPrimary": "330", + "hat": "cap" } }; -var categoryStyles = { - "colour_category":{ +Blockly.Themes.Classic.categoryStyles = { + "colour_category": { "colour": "20" }, "list_category": { @@ -89,9 +89,11 @@ var categoryStyles = { "variable_category": { "colour": "330" }, - "variable_dynamic_category":{ + "variable_dynamic_category": { "colour": "310" } }; -Blockly.Themes.Classic = new Blockly.Theme(defaultBlockStyles, categoryStyles); +Blockly.Themes.Classic = + new Blockly.Theme(Blockly.Themes.Classic.defaultBlockStyles, + Blockly.Themes.Classic.categoryStyles); diff --git a/core/theme/highcontrast.js b/core/theme/highcontrast.js index 56174e2158e..5dfc1bb8004 100644 --- a/core/theme/highcontrast.js +++ b/core/theme/highcontrast.js @@ -20,7 +20,7 @@ /** * @fileoverview High contrast theme. - * Darker colors to contrast the white font. + * Darker colours to contrast the white font. */ 'use strict'; @@ -29,89 +29,91 @@ goog.provide('Blockly.Themes.HighContrast'); goog.require('Blockly.Theme'); -var defaultBlockStyles = { - "colour_blocks":{ +Blockly.Themes.HighContrast.defaultBlockStyles = { + "colour_blocks": { "colourPrimary": "#a52714", - "colourSecondary":"#FB9B8C", - "colourTertiary":"#FBE1DD" + "colourSecondary": "#FB9B8C", + "colourTertiary": "#FBE1DD" }, "list_blocks": { "colourPrimary": "#4a148c", - "colourSecondary":"#AD7BE9", - "colourTertiary":"#CDB6E9" + "colourSecondary": "#AD7BE9", + "colourTertiary": "#CDB6E9" }, "logic_blocks": { "colourPrimary": "#01579b", - "colourSecondary":"#64C7FF", - "colourTertiary":"#C5EAFF" + "colourSecondary": "#64C7FF", + "colourTertiary": "#C5EAFF" }, "loop_blocks": { "colourPrimary": "#33691e", - "colourSecondary":"#9AFF78", - "colourTertiary":"#E1FFD7" + "colourSecondary": "#9AFF78", + "colourTertiary": "#E1FFD7" }, "math_blocks": { "colourPrimary": "#1a237e", - "colourSecondary":"#8A9EFF", - "colourTertiary":"#DCE2FF" + "colourSecondary": "#8A9EFF", + "colourTertiary": "#DCE2FF" }, "procedure_blocks": { "colourPrimary": "#006064", - "colourSecondary":"#77E6EE", - "colourTertiary":"#CFECEE" + "colourSecondary": "#77E6EE", + "colourTertiary": "#CFECEE" }, "text_blocks": { "colourPrimary": "#004d40", - "colourSecondary":"#5ae27c", - "colourTertiary":"#D2FFDD" + "colourSecondary": "#5ae27c", + "colourTertiary": "#D2FFDD" }, "variable_blocks": { "colourPrimary": "#880e4f", - "colourSecondary":"#FF73BE", - "colourTertiary":"#FFD4EB" + "colourSecondary": "#FF73BE", + "colourTertiary": "#FFD4EB" }, "variable_dynamic_blocks": { "colourPrimary": "#880e4f", - "colourSecondary":"#FF73BE", - "colourTertiary":"#FFD4EB" + "colourSecondary": "#FF73BE", + "colourTertiary": "#FFD4EB" }, - "hat_blocks" : { + "hat_blocks": { "colourPrimary": "#880e4f", - "colourSecondary":"#FF73BE", - "colourTertiary":"#FFD4EB", + "colourSecondary": "#FF73BE", + "colourTertiary": "#FFD4EB", "hat": "cap" } }; -var categoryStyles = { - "colour_category":{ - "colour": "#a52714", +Blockly.Themes.HighContrast.categoryStyles = { + "colour_category": { + "colour": "#a52714" }, "list_category": { - "colour": "#4a148c", + "colour": "#4a148c" }, "logic_category": { - "colour": "#01579b", + "colour": "#01579b" }, "loop_category": { - "colour": "#33691e", + "colour": "#33691e" }, "math_category": { - "colour": "#1a237e", + "colour": "#1a237e" }, "procedure_category": { - "colour": "#006064", + "colour": "#006064" }, "text_category": { - "colour": "#004d40", + "colour": "#004d40" }, "variable_category": { - "colour": "#880e4f", + "colour": "#880e4f" }, - "variable_dynamic_category":{ - "colour": "#880e4f", + "variable_dynamic_category": { + "colour": "#880e4f" } }; -//This style is still being fleshed out and may change. -Blockly.Themes.HighContrast = new Blockly.Theme(defaultBlockStyles, categoryStyles); +// This style is still being fleshed out and may change. +Blockly.Themes.HighContrast = + new Blockly.Theme(Blockly.Themes.HighContrast.defaultBlockStyles, + Blockly.Themes.HighContrast.categoryStyles); diff --git a/core/theme/modern.js b/core/theme/modern.js index c218225bcff..0dc0181e459 100644 --- a/core/theme/modern.js +++ b/core/theme/modern.js @@ -20,7 +20,7 @@ /** * @fileoverview Modern theme. - * Same colors as classic, but single colored border. + * Same colours as classic, but single coloured border. */ 'use strict'; @@ -29,7 +29,7 @@ goog.provide('Blockly.Themes.Modern'); goog.require('Blockly.Theme'); -var defaultBlockStyles = { +Blockly.Themes.Modern.defaultBlockStyles = { "colour_blocks": { "colourPrimary": "#a5745b", "colourSecondary": "#dbc7bd", @@ -83,35 +83,37 @@ var defaultBlockStyles = { } }; -var categoryStyles = { - "colour_category":{ - "colour": "#a5745b", +Blockly.Themes.Modern.categoryStyles = { + "colour_category": { + "colour": "#a5745b" }, "list_category": { - "colour": "#745ba5", + "colour": "#745ba5" }, "logic_category": { - "colour": "#5b80a5", + "colour": "#5b80a5" }, "loop_category": { - "colour": "#5ba55b", + "colour": "#5ba55b" }, "math_category": { - "colour": "#5b67a5", + "colour": "#5b67a5" }, "procedure_category": { - "colour": "#995ba5", + "colour": "#995ba5" }, "text_category": { - "colour": "#5ba58c", + "colour": "#5ba58c" }, "variable_category": { - "colour": "#a55b99", + "colour": "#a55b99" }, - "variable_dynamic_category":{ - "colour": "#a55b99", + "variable_dynamic_category": { + "colour": "#a55b99" } }; -//This style is still being fleshed out and may change. -Blockly.Themes.Modern = new Blockly.Theme(defaultBlockStyles, categoryStyles); +// This style is still being fleshed out and may change. +Blockly.Themes.Modern = + new Blockly.Theme(Blockly.Themes.Modern.defaultBlockStyles, + Blockly.Themes.Modern.categoryStyles); diff --git a/core/toolbox.js b/core/toolbox.js index ef3bd6557bd..7f61dcaac67 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -424,7 +424,8 @@ Blockly.Toolbox.prototype.setColourFromStyle_ = function( if (style && style.colour) { this.setColour_(style.colour, childOut, categoryName); } else { - console.warn('Style "' + styleName + '" must exist and contain a colour value'); + console.warn('Style "' + styleName + + '" must exist and contain a colour value'); } } }; diff --git a/core/xml.js b/core/xml.js index 3006663a106..5dbbfab5f99 100644 --- a/core/xml.js +++ b/core/xml.js @@ -201,7 +201,8 @@ Blockly.Xml.blockToDom = function(block, opt_noId) { element.appendChild(container); } } - if (block.inputsInlineDefault != block.inputsInline) { + if (block.inputsInline != undefined && + block.inputsInline != block.inputsInlineDefault) { element.setAttribute('inline', block.inputsInline); } if (block.isCollapsed()) { From 3fbd183ed8eaef9e4e759ad0c43491e8f2452678 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 30 May 2019 19:13:24 +0200 Subject: [PATCH 091/233] Localisation updates from https://translatewiki.net. --- msg/json/ko.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/msg/json/ko.json b/msg/json/ko.json index 0a23d0fd863..24449904e1d 100644 --- a/msg/json/ko.json +++ b/msg/json/ko.json @@ -13,7 +13,8 @@ "Jerrykim306", "Onebone", "JeonHK", - "Liuxinyu970226" + "Liuxinyu970226", + "Peurocs4" ] }, "VARIABLES_DEFAULT_NAME": "항목", @@ -281,7 +282,10 @@ "TEXT_PROMPT_TYPE_NUMBER": "메시지를 활용해 수 입력", "TEXT_PROMPT_TOOLTIP_NUMBER": "수에 대해 사용자의 입력을 받습니다.", "TEXT_PROMPT_TOOLTIP_TEXT": "문장에 대해 사용자의 입력을 받습니다.", + "TEXT_COUNT_MESSAGE0": "%2에서 %1 숫자 세기", "TEXT_COUNT_HELPURL": "https://github.com/google/blockly/wiki/Text#counting-substrings", + "TEXT_COUNT_TOOLTIP": "다른 어떤 텍스트에서 어떤 텍스트가 나타난 횟수를 셉니다.", + "TEXT_REPLACE_MESSAGE0": "%3에서 %2을(를) %1(으)로 바꾸기", "TEXT_REPLACE_HELPURL": "https://github.com/google/blockly/wiki/Text#replacing-substrings", "TEXT_REVERSE_HELPURL": "https://github.com/google/blockly/wiki/Text#reversing-text", "LISTS_CREATE_EMPTY_HELPURL": "https://github.com/google/blockly/wiki/Lists#create-empty-list", From e1e746b845c907c22091ad8f537f9658a360619a Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Sat, 25 May 2019 13:22:11 -0700 Subject: [PATCH 092/233] Fixed how fields handle size. --- core/field.js | 32 ++++++++++++++++++++++++-------- core/field_angle.js | 2 +- core/field_checkbox.js | 17 +++++++++-------- core/field_colour.js | 27 ++++++++++++++------------- core/field_dropdown.js | 22 ---------------------- core/field_image.js | 18 +++++++++--------- 6 files changed, 57 insertions(+), 61 deletions(-) diff --git a/core/field.js b/core/field.js index debb7411f28..70b97f7f06b 100644 --- a/core/field.js +++ b/core/field.js @@ -230,6 +230,9 @@ Blockly.Field.prototype.init = function() { return; } this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); + if (!this.isVisible()) { + this.fieldGroup_.style.display = 'none'; + } this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); this.initView(); this.initModel(); @@ -240,9 +243,6 @@ Blockly.Field.prototype.init = function() { * @package */ Blockly.Field.prototype.initView = function() { - if (!this.visible_) { - this.fieldGroup_.style.display = 'none'; - } this.borderRect_ = Blockly.utils.createSvgElement('rect', { 'rx': 4, @@ -386,7 +386,6 @@ Blockly.Field.prototype.setVisible = function(visible) { var root = this.getSvgRoot(); if (root) { root.style.display = visible ? 'block' : 'none'; - this.size_.width = 0; } }; @@ -483,15 +482,28 @@ Blockly.Field.prototype.updateColour = function() { */ Blockly.Field.prototype.render_ = function() { this.textElement_.textContent = this.getDisplayText_(); - this.updateWidth(); + this.updateSize_(); }; /** - * Updates the width of the field. This calls getCachedWidth which won't cache - * the approximated width on IE/Edge when `getComputedTextLength` fails. Once - * it eventually does succeed, the result will be cached. + * Updates the width of the field. Redirects to updateSize_(). + * @deprecated May 2019 Use Blockly.Field.updateSize_() to force an update + * to the size of the field, or Blockly.Field.getCachedWidth() to check the + * size of the field.. */ Blockly.Field.prototype.updateWidth = function() { + console.warn('Deprecated call to updateWidth, call' + + ' Blockly.Field.updateSize_ to force an update to the size of the' + + ' field, or Blockly.Field.getCachedWidth() to check the size of the' + + ' field.'); + this.updateSize_(); +}; + +/** + * Updates the size of the field based on the text. + * @protected + */ +Blockly.Field.prototype.updateSize_ = function() { var width = Blockly.Field.getCachedWidth(this.textElement_); if (this.borderRect_) { this.borderRect_.setAttribute('width', @@ -568,6 +580,10 @@ Blockly.Field.stopCache = function() { * @return {!goog.math.Size} Height and width. */ Blockly.Field.prototype.getSize = function() { + if (!this.isVisible()) { + return new goog.math.Size(0, 0); + } + if (this.isDirty_) { this.render_(); this.isDirty_ = false; diff --git a/core/field_angle.js b/core/field_angle.js index 7f521ec9d86..f5f189730da 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -135,7 +135,7 @@ Blockly.FieldAngle.prototype.initView = function() { Blockly.FieldAngle.prototype.render_ = function() { this.textElement_.textContent = this.getDisplayText_(); this.textElement_.appendChild(this.symbol_); - this.updateWidth(); + this.updateSize_(); this.updateGraph_(); }; diff --git a/core/field_checkbox.js b/core/field_checkbox.js index 74d6c115a19..43f3cd6a36c 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -91,6 +91,15 @@ Blockly.FieldCheckbox.prototype.SERIALIZABLE = true; */ Blockly.FieldCheckbox.prototype.CURSOR = 'default'; +/** + * Used to tell if the field needs to be rendered the next time the block is + * rendered. Checkbox fields are statically sized, and only need to be + * rendered at initialization. + * @type {boolean} + * @private + */ +Blockly.FieldCheckbox.prototype.isDirty_ = false; + /** * Create the block UI for this checkbox. * @package @@ -113,14 +122,6 @@ Blockly.FieldCheckbox.prototype.initView = function() { } }; -/** - * Checkboxes have a constant width. - * @private - */ -Blockly.FieldCheckbox.prototype.render_ = function() { - this.size_.width = Blockly.FieldCheckbox.WIDTH; -}; - /** * Toggle the state of the checkbox on click. * @protected diff --git a/core/field_colour.js b/core/field_colour.js index e92328bb268..c01aaafea68 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -96,6 +96,20 @@ Blockly.FieldColour.COLOUR_REGEX = new RegExp('#[0-9a-fA-F]{6}'); */ Blockly.FieldColour.prototype.SERIALIZABLE = true; +/** + * Mouse cursor style when over the hotspot that initiates the editor. + */ +Blockly.FieldColour.prototype.CURSOR = 'default'; + +/** + * Used to tell if the field needs to be rendered the next time the block is + * rendered. Colour fields are statically sized, and only need to be + * rendered at initialization. + * @type {boolean} + * @private + */ +Blockly.FieldColour.prototype.isDirty_ = false; + /** * Array of colours used by this field. If null, use the global list. * @type {Array.} @@ -149,11 +163,6 @@ Blockly.FieldColour.prototype.initView = function() { this.borderRect_.style.fill = this.value_; }; -/** - * Mouse cursor style when over the hotspot that initiates the editor. - */ -Blockly.FieldColour.prototype.CURSOR = 'default'; - /** * Close the colour picker if this input is being deleted. */ @@ -162,14 +171,6 @@ Blockly.FieldColour.prototype.dispose = function() { Blockly.FieldColour.superClass_.dispose.call(this); }; -/** - * Render the colour field. - * @private - */ -Blockly.FieldColour.prototype.render_ = function() { - this.size_.width = Blockly.FieldColour.DEFAULT_WIDTH; -}; - /** * Ensure that the input value is a valid colour. * @param {string=} newValue The input value. diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 4083e231c84..4b9d6f850be 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -510,28 +510,6 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { this.size_.width = Blockly.Field.getCachedWidth(this.textElement_); }; -/** - * Updates the width of the field. Overrides field.prototype.updateWidth to - * deal with image selections on IE and Edge. If the selected item is not an - * image, or if the browser is not IE / Edge, this simply calls the parent - * implementation. - */ -Blockly.FieldDropdown.prototype.updateWidth = function() { - if (this.imageJson_ && - (Blockly.userAgent.IE || Blockly.userAgent.EDGE)) { - // Recalculate the full width. - var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_); - var width = Number(this.imageJson_.width) + arrowWidth + - Blockly.BlockSvg.SEP_SPACE_X; - if (this.borderRect_) { - this.borderRect_.setAttribute('width', width); - } - this.size_.width = width; - } else { - Blockly.Field.prototype.updateWidth.call(this); - } -}; - /** * Close the dropdown menu if this input is being deleted. */ diff --git a/core/field_image.js b/core/field_image.js index 0d39a9fcef5..44bc0c2b282 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -103,6 +103,15 @@ Blockly.FieldImage.fromJson = function(options) { */ Blockly.FieldImage.prototype.EDITABLE = false; +/** + * Used to tell if the field needs to be rendered the next time the block is + * rendered. Image fields are statically sized, and only need to be + * rendered at initialization. + * @type {boolean} + * @private + */ +Blockly.FieldImage.prototype.isDirty_ = false; + /** * Create the block UI for this image. * @package @@ -217,15 +226,6 @@ Blockly.FieldImage.prototype.setText = function(alt) { } }; -/** - * Images are fixed width, no need to render. - * @private - */ -Blockly.FieldImage.prototype.render_ = function() { - this.size_.width = this.width_; - this.size_.height = this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y; -}; - /** * If field click is called, and click handler defined, * call the handler. From 2f0b02525a4a168c17cc05a207fcbbffd332382c Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 31 May 2019 10:12:57 -0700 Subject: [PATCH 093/233] Moved serializing the field's name up to xml.js --- core/field.js | 1 - core/field_variable.js | 1 - core/xml.js | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/field.js b/core/field.js index debb7411f28..49da12a0ca2 100644 --- a/core/field.js +++ b/core/field.js @@ -292,7 +292,6 @@ Blockly.Field.prototype.fromXml = function(fieldElement) { * @package */ Blockly.Field.prototype.toXml = function(fieldElement) { - fieldElement.setAttribute('name', this.name); fieldElement.textContent = this.getValue(); return fieldElement; }; diff --git a/core/field_variable.js b/core/field_variable.js index a2cd7a6bbc7..29aa44a0c30 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -151,7 +151,6 @@ Blockly.FieldVariable.prototype.toXml = function(fieldElement) { // Make sure the variable is initialized. this.initModel(); - fieldElement.setAttribute('name', this.name); fieldElement.setAttribute('id', this.variable_.getId()); fieldElement.textContent = this.variable_.name; fieldElement.setAttribute('variableType', this.variable_.type); diff --git a/core/xml.js b/core/xml.js index 5dbbfab5f99..812e46b1b82 100644 --- a/core/xml.js +++ b/core/xml.js @@ -109,6 +109,7 @@ Blockly.Xml.blockToDomWithXY = function(block, opt_noId) { Blockly.Xml.fieldToDom_ = function(field) { if (field.isSerializable()) { var container = Blockly.Xml.utils.createElement('field'); + container.setAttribute('name', field.name); return field.toXml(container); } return null; From f0d6fbd192e4f387839b5d41ffcf8e5d977f2d2e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 27 May 2019 14:31:15 -0700 Subject: [PATCH 094/233] Reorganized field view initialization. --- core/field.js | 71 +++++++++++++++++++++++++++++------- core/field_angle.js | 5 +-- core/field_checkbox.js | 36 +++++++++++------- core/field_colour.js | 5 +-- core/field_dropdown.js | 62 ++++++++++++++----------------- core/field_image.js | 37 ------------------- core/field_label.js | 30 +-------------- core/field_textinput.js | 8 ++-- core/gesture.js | 8 ++-- core/tooltip.js | 2 +- tests/jsunit/gesture_test.js | 2 + 11 files changed, 123 insertions(+), 143 deletions(-) diff --git a/core/field.js b/core/field.js index 70b97f7f06b..512f9451bef 100644 --- a/core/field.js +++ b/core/field.js @@ -235,6 +235,9 @@ Blockly.Field.prototype.init = function() { } this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); this.initView(); + this.updateEditable(); + this.setTooltip(); + this.bindEvents_(); this.initModel(); }; @@ -243,26 +246,54 @@ Blockly.Field.prototype.init = function() { * @package */ Blockly.Field.prototype.initView = function() { + this.createBorderRect_(); + this.createTextElement_(); +}; + +/** + * Create a field border rect element. Not to be overridden by subclasses. + * Instead modify the result of the function inside initView, or create a + * separate function to call. + * @protected + */ +Blockly.Field.prototype.createBorderRect_ = function() { this.borderRect_ = Blockly.utils.createSvgElement('rect', { 'rx': 4, 'ry': 4, 'x': -Blockly.BlockSvg.SEP_SPACE_X / 2, 'y': 0, - 'height': 16 + 'height': 16, + 'width': this.size_.width + Blockly.BlockSvg.SEP_SPACE_X }, this.fieldGroup_); - this.textElement_ = Blockly.utils.createSvgElement('text', - {'class': 'blocklyText', 'y': this.size_.height - 12.5}, - this.fieldGroup_); - var textNode = document.createTextNode(''); - this.textElement_.appendChild(textNode); +}; - this.updateEditable(); +/** + * Create a field text element. Not to be overridden by subclasses. Instead + * modify the result of the function inside initView, or create a separate + * function to call. + * @protected + */ +Blockly.Field.prototype.createTextElement_ = function() { + this.textElement_ = Blockly.utils.createSvgElement('text', + { + 'class': 'blocklyText', + 'y': this.size_.height - 12.5 + }, this.fieldGroup_); + this.textContent_ = document.createTextNode(''); + this.textElement_.appendChild(this.textContent_); +}; - this.clickTarget_ = this.getSvgRoot(); +/** + * Bind events to the field. Can be overridden by subclasses if they need to do + * custom input handling. + * @protected + */ +Blockly.Field.prototype.bindEvents_ = function() { + Blockly.Tooltip.bindMouseEvents(this.getClickTarget_()); this.mouseDownWrapper_ = Blockly.bindEventWithChecks_( - this.clickTarget_, 'mousedown', this, this.onMouseDown_); + this.getClickTarget_(), 'mousedown', this, this.onMouseDown_); }; /** @@ -334,6 +365,14 @@ Blockly.Field.prototype.updateEditable = function() { } }; +/** + * Check whether this field defines the showEditor_ function. + * @return {boolean} Whether this field is clickable. + */ +Blockly.Field.prototype.isClickable = function() { + return !!this.showEditor_ && (typeof this.showEditor_ === 'function'); +}; + /** * Check whether this field is currently editable. Some fields are never * EDITABLE (e.g. text labels). Other fields may be EDITABLE but may exist on @@ -481,7 +520,7 @@ Blockly.Field.prototype.updateColour = function() { * @protected */ Blockly.Field.prototype.render_ = function() { - this.textElement_.textContent = this.getDisplayText_(); + this.textContent_.nodeValue = this.getDisplayText_(); this.updateSize_(); }; @@ -806,11 +845,15 @@ Blockly.Field.prototype.onMouseDown_ = function(e) { /** * Change the tooltip text for this field. - * @param {string|!Element} _newTip Text for tooltip or a parent element to - * link to for its tooltip. + * @param {string|function|!Element} newTip Text for tooltip or a parent + * element to link to for its tooltip. */ -Blockly.Field.prototype.setTooltip = function(_newTip) { - // Non-abstract sub-classes may wish to implement this. See FieldLabel. +Blockly.Field.prototype.setTooltip = function(newTip) { + if (!newTip && newTip !== '') { // If null or undefined. + this.getClickTarget_().tooltip = this.sourceBlock_; + } else { + this.getClickTarget_().tooltip = newTip; + } }; /** diff --git a/core/field_angle.js b/core/field_angle.js index f5f189730da..ef6f90977cf 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -126,6 +126,7 @@ Blockly.FieldAngle.prototype.initView = function() { // Add the degree symbol to the left of the number, even in RTL (issue #2380) this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null); this.symbol_.appendChild(document.createTextNode('\u00B0')); + this.textElement_.appendChild(this.symbol_); }; /** @@ -133,9 +134,7 @@ Blockly.FieldAngle.prototype.initView = function() { * @private */ Blockly.FieldAngle.prototype.render_ = function() { - this.textElement_.textContent = this.getDisplayText_(); - this.textElement_.appendChild(this.symbol_); - this.updateSize_(); + Blockly.FieldAngle.superClass_.render_.call(this); this.updateGraph_(); }; diff --git a/core/field_checkbox.js b/core/field_checkbox.js index 43f3cd6a36c..cbb73933c24 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -78,6 +78,20 @@ Blockly.FieldCheckbox.WIDTH = 5; */ Blockly.FieldCheckbox.CHECK_CHAR = '\u2713'; +/** + * Used to correctly position the check mark. + * @type {number} + * @const + */ +Blockly.FieldCheckbox.CHECK_X_OFFSET = -3; + +/** + * Used to correctly position the check mark. + * @type {number} + * @const + */ +Blockly.FieldCheckbox.CHECK_Y_OFFSET = 14; + /** * Serializable fields are saved by the XML renderer, non-serializable fields * are not. Editable fields should also be serializable. @@ -107,19 +121,13 @@ Blockly.FieldCheckbox.prototype.isDirty_ = false; Blockly.FieldCheckbox.prototype.initView = function() { Blockly.FieldCheckbox.superClass_.initView.call(this); - // The checkbox doesn't use the inherited text element. - // Instead it uses a custom checkmark element that is either visible or not. - this.checkElement_ = Blockly.utils.createSvgElement('text', - {'class': 'blocklyText blocklyCheckbox', 'x': -3, 'y': 14}, - this.fieldGroup_); - var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR); - this.checkElement_.appendChild(textNode); - this.checkElement_.style.display = this.value_ ? 'block' : 'none'; + this.textElement_.setAttribute('x', Blockly.FieldCheckbox.CHECK_X_OFFSET); + this.textElement_.setAttribute('y', Blockly.FieldCheckbox.CHECK_Y_OFFSET); + Blockly.utils.addClass(this.textElement_, 'blocklyCheckbox'); - if (this.borderRect_) { - this.borderRect_.setAttribute('width', - this.size_.width + Blockly.BlockSvg.SEP_SPACE_X); - } + var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR); + this.textElement_.appendChild(textNode); + this.textElement_.style.display = this.value_ ? 'block' : 'none'; }; /** @@ -154,8 +162,8 @@ Blockly.FieldCheckbox.prototype.doClassValidation_ = function(newValue) { Blockly.FieldCheckbox.prototype.doValueUpdate_ = function(newValue) { this.value_ = this.convertValueToBool_(newValue); // Update visual. - if (this.checkElement_) { - this.checkElement_.style.display = this.value_ ? 'block' : 'none'; + if (this.textElement_) { + this.textElement_.style.display = this.value_ ? 'block' : 'none'; } }; diff --git a/core/field_colour.js b/core/field_colour.js index c01aaafea68..c76b5612f27 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -153,13 +153,10 @@ Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR = 'white'; * @package */ Blockly.FieldColour.prototype.initView = function() { - Blockly.FieldColour.superClass_.initView.call(this); - this.size_ = new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH, Blockly.FieldColour.DEFAULT_HEIGHT); + this.createBorderRect_(); this.borderRect_.style['fillOpacity'] = 1; - this.borderRect_.setAttribute('width', - this.size_.width + Blockly.BlockSvg.SEP_SPACE_X); this.borderRect_.style.fill = this.value_; }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 4b9d6f850be..c7eed2f96dc 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -95,6 +95,13 @@ Blockly.FieldDropdown.CHECKMARK_OVERHANG = 25; */ Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45; +/** + * Used to position the imageElement_ correctly. + * @type {number} + * @const + */ +Blockly.FieldDropdown.IMAGE_Y_OFFSET = 5; + /** * Android can't (in 2014) display "▾", so use "▼" instead. */ @@ -128,11 +135,19 @@ Blockly.FieldDropdown.prototype.imageJson_ = null; Blockly.FieldDropdown.prototype.initView = function() { Blockly.FieldDropdown.superClass_.initView.call(this); - // Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL) - this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, null); - this.arrow_.appendChild(document.createTextNode(this.sourceBlock_.RTL ? - Blockly.FieldDropdown.ARROW_CHAR + ' ' : - ' ' + Blockly.FieldDropdown.ARROW_CHAR)); + this.imageElement_ = Blockly.utils.createSvgElement( 'image', + { + 'y': Blockly.FieldDropdown.IMAGE_Y_OFFSET + }, this.fieldGroup_); + + this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, this.textElement_); + this.arrow_.appendChild(document.createTextNode( + Blockly.FieldDropdown.ARROW_CHAR)); + if (this.sourceBlock_.RTL) { + this.textElement_.insertBefore(this.arrow_, this.textContent_); + } else { + this.textElement_.appendChild(this.arrow_); + } }; /** @@ -441,15 +456,6 @@ Blockly.FieldDropdown.prototype.updateColour = function() { * @private */ Blockly.FieldDropdown.prototype.render_ = function() { - var child; - while ((child = this.textElement_.firstChild)) { - this.textElement_.removeChild(child); - } - if (this.imageElement_) { - Blockly.utils.removeNode(this.imageElement_); - this.imageElement_ = null; - } - if (this.imageJson_) { this.renderSelectedImage_(); } else { @@ -465,20 +471,18 @@ Blockly.FieldDropdown.prototype.render_ = function() { * @private */ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function() { - // Image option is selected. - this.imageElement_ = Blockly.utils.createSvgElement('image', - { - 'y': 5, - 'height': this.imageJson_.height + 'px', - 'width': this.imageJson_.width + 'px' - }, this.fieldGroup_); this.imageElement_.setAttributeNS( 'http://www.w3.org/1999/xlink', 'xlink:href', this.imageJson_.src); - // Insert dropdown arrow. - this.textElement_.appendChild(this.arrow_); + this.imageElement_.setAttribute('height', this.imageJson_.height); + this.imageElement_.setAttribute('width', this.imageJson_.width); + var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_); + // TODO: Standardize sizing, need to talk to rachel and abby about rendering + // redux. + // I think really this means plus 10? this.size_.height = Number(this.imageJson_.height) + 19; this.size_.width = Number(this.imageJson_.width) + arrowWidth; + if (this.sourceBlock_.RTL) { this.imageElement_.setAttribute('x', arrowWidth); this.textElement_.setAttribute('x', -1); @@ -493,19 +497,9 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function() { * @private */ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { - // Text option is selected. - // Replace the text. - var textNode = document.createTextNode(this.getDisplayText_()); - this.textElement_.appendChild(textNode); - // Insert dropdown arrow. - if (this.sourceBlock_.RTL) { - this.textElement_.insertBefore(this.arrow_, this.textElement_.firstChild); - } else { - this.textElement_.appendChild(this.arrow_); - } + this.textContent_.nodeValue = this.getDisplayText_(); this.textElement_.setAttribute('text-anchor', 'start'); this.textElement_.setAttribute('x', 0); - this.size_.height = Blockly.BlockSvg.MIN_BLOCK_Y; this.size_.width = Blockly.Field.getCachedWidth(this.textElement_); }; diff --git a/core/field_image.js b/core/field_image.js index 44bc0c2b282..9188935d640 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -66,7 +66,6 @@ Blockly.FieldImage = function(src, width, height, this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y); this.flipRtl_ = opt_flipRtl; - this.tooltip_ = ''; this.text_ = opt_alt || ''; this.setValue(src || ''); @@ -127,17 +126,6 @@ Blockly.FieldImage.prototype.initView = function() { this.fieldGroup_); this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', this.value_); - this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); - - if (this.tooltip_) { - this.imageElement_.tooltip = this.tooltip_; - } else { - // Configure the field to be transparent with respect to tooltips. - this.setTooltip(this.sourceBlock_); - } - Blockly.Tooltip.bindMouseEvents(this.imageElement_); - - this.maybeAddClickHandler_(); }; /** @@ -151,31 +139,6 @@ Blockly.FieldImage.prototype.dispose = function() { this.imageElement_ = null; }; -/** - * Bind events for a mouse down on the image, but only if a click handler has - * been defined. - * @private - */ -Blockly.FieldImage.prototype.maybeAddClickHandler_ = function() { - if (this.clickHandler_) { - this.mouseDownWrapper_ = - Blockly.bindEventWithChecks_( - this.fieldGroup_, 'mousedown', this, this.clickHandler_); - } -}; - -/** - * Change the tooltip text for this field. - * @param {string|!Element} newTip Text for tooltip or a parent element to - * link to for its tooltip. - */ -Blockly.FieldImage.prototype.setTooltip = function(newTip) { - this.tooltip_ = newTip; - if (this.imageElement_) { - this.imageElement_.tooltip = newTip; - } -}; - /** * Ensure that the input value (the source URL) is a string. * @param {string=} newValue The input value diff --git a/core/field_label.js b/core/field_label.js index f287964e089..b752f74bbe9 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -50,7 +50,6 @@ Blockly.FieldLabel = function(opt_value, opt_class) { opt_value = ''; } this.setValue(opt_value); - this.tooltip_ = ''; }; goog.inherits(Blockly.FieldLabel, Blockly.Field); @@ -80,24 +79,11 @@ Blockly.FieldLabel.prototype.EDITABLE = false; * @package */ Blockly.FieldLabel.prototype.initView = function() { - this.textElement_ = Blockly.utils.createSvgElement('text', - { - 'class': 'blocklyText', - 'y': this.size_.height - 5 - }, this.fieldGroup_); - var textNode = document.createTextNode(''); - this.textElement_.appendChild(textNode); + this.createTextElement_(); + this.textElement_.setAttribute('y', this.size_.height - 5); if (this.class_) { Blockly.utils.addClass(this.textElement_, this.class_); } - - if (this.tooltip_) { - this.textElement_.tooltip = this.tooltip_; - } else { - // Configure the field to be transparent with respect to tooltips. - this.textElement_.tooltip = this.sourceBlock_; - } - Blockly.Tooltip.bindMouseEvents(this.textElement_); }; /** @@ -123,16 +109,4 @@ Blockly.FieldLabel.prototype.doClassValidation_ = function(newValue) { return String(newValue); }; -/** - * Change the tooltip text for this field. - * @param {string|!Element} newTip Text for tooltip or a parent element to - * link to for its tooltip. - */ -Blockly.FieldLabel.prototype.setTooltip = function(newTip) { - this.tooltip_ = newTip; - if (this.textElement_) { - this.textElement_.tooltip = newTip; - } -}; - Blockly.Field.register('field_label', Blockly.FieldLabel); diff --git a/core/field_textinput.js b/core/field_textinput.js index 7e3e8e65f11..116309bb6db 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -263,7 +263,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { } // Bind events. - this.bindEvents_(htmlInput); + this.bindInputEvents_(htmlInput); // Save it. Blockly.FieldTextInput.htmlInput_ = htmlInput; @@ -275,7 +275,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { * which event handlers will be bound. * @private */ -Blockly.FieldTextInput.prototype.bindEvents_ = function(htmlInput) { +Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { // Bind to keydown -- trap Enter without IME and Esc to hide. htmlInput.onKeyDownWrapper_ = Blockly.bindEventWithChecks_( @@ -297,7 +297,7 @@ Blockly.FieldTextInput.prototype.bindEvents_ = function(htmlInput) { * @param {!HTMLInputElement} htmlInput The html for this text input. * @private */ -Blockly.FieldTextInput.prototype.unbindEvents_ = function(htmlInput) { +Blockly.FieldTextInput.prototype.unbindInputEvents_ = function(htmlInput) { Blockly.unbindEvent_(htmlInput.onKeyDownWrapper_); Blockly.unbindEvent_(htmlInput.onKeyUpWrapper_); Blockly.unbindEvent_(htmlInput.onKeyPressWrapper_); @@ -413,7 +413,7 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() { } // Remove htmlInput. - thisField.unbindEvents_(htmlInput); + thisField.unbindInputEvents_(htmlInput); Blockly.FieldTextInput.htmlInput_ = null; // Delete style properties. diff --git a/core/gesture.js b/core/gesture.js index 990667e222a..ebf67584a86 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -899,10 +899,10 @@ Blockly.Gesture.prototype.isBlockClick_ = function() { * @private */ Blockly.Gesture.prototype.isFieldClick_ = function() { - var fieldEditable = this.startField_ ? - this.startField_.isCurrentlyEditable() : false; - return fieldEditable && !this.hasExceededDragRadius_ && (!this.flyout_ || - !this.flyout_.autoClose); + var fieldClickable = this.startField_ ? + this.startField_.isClickable() : false; + return fieldClickable && !this.hasExceededDragRadius_ && + (!this.flyout_ || !this.flyout_.autoClose); }; /** diff --git a/core/tooltip.js b/core/tooltip.js index a423f31dc1a..06d22f85f8f 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -165,7 +165,7 @@ Blockly.Tooltip.onMouseOver_ = function(e) { } // If the tooltip is an object, treat it as a pointer to the next object in // the chain to look at. Terminate when a string or function is found. - var element = e.target; + var element = e.currentTarget; while ((typeof element.tooltip != 'string') && (typeof element.tooltip != 'function')) { element = element.tooltip; diff --git a/tests/jsunit/gesture_test.js b/tests/jsunit/gesture_test.js index 19ba1864ea3..5642c4e40e9 100644 --- a/tests/jsunit/gesture_test.js +++ b/tests/jsunit/gesture_test.js @@ -49,6 +49,7 @@ function test_gestureIsField_ClickInWorkspace() { var block = new Blockly.Block(workspace); var field = new Blockly.Field(); field.setSourceBlock(block); + field.showEditor_ = function() {}; var gesture = new Blockly.Gesture(e, workspace); gesture.setStartField(field); @@ -64,6 +65,7 @@ function gestureIsFieldClick_InFlyoutHelper(flyout, expectedResult){ var block = new Blockly.Block(workspace); var field = new Blockly.Field(); field.setSourceBlock(block); + field.showEditor_ = function() {}; // Create gesture from the flyout var gesture = new Blockly.Gesture(e, workspace.flyout_); // Populate gesture with click start information From 4b70215db8afa5067f4e39cea7f952629bac24cb Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 31 May 2019 11:56:21 -0700 Subject: [PATCH 095/233] Fixed dropdown arrow being to close to option. --- core/field_dropdown.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/field_dropdown.js b/core/field_dropdown.js index c7eed2f96dc..71f587fcfb4 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -142,7 +142,9 @@ Blockly.FieldDropdown.prototype.initView = function() { this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, this.textElement_); this.arrow_.appendChild(document.createTextNode( - Blockly.FieldDropdown.ARROW_CHAR)); + this.sourceBlock_.RTL ? + Blockly.FieldDropdown.ARROW_CHAR + ' ' : + ' ' + Blockly.FieldDropdown.ARROW_CHAR)); if (this.sourceBlock_.RTL) { this.textElement_.insertBefore(this.arrow_, this.textContent_); } else { From 02de44c06f2a4e2ba2c1678f48c8a955c8ff6d77 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 3 Jun 2019 17:23:44 +0200 Subject: [PATCH 096/233] Localisation updates from https://translatewiki.net. --- msg/json/el.json | 7 ++++--- msg/json/zh-hans.json | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/msg/json/el.json b/msg/json/el.json index 5efe5818fa8..1ebd50a995d 100644 --- a/msg/json/el.json +++ b/msg/json/el.json @@ -16,7 +16,8 @@ "Themelis", "KATRINE1992", "Vicng", - "Nikosgranturismogt" + "Nikosgranturismogt", + "Sarri.greek" ] }, "VARIABLES_DEFAULT_NAME": "αντικείμενο", @@ -43,7 +44,7 @@ "CHANGE_VALUE_TITLE": "Άλλαξε την τιμή:", "RENAME_VARIABLE": "Μετονόμασε τη μεταβλητή...", "RENAME_VARIABLE_TITLE": "Μετονόμασε όλες τις μεταβλητές «%1» σε:", - "NEW_VARIABLE": "Δημιουργείστε μεταβλητή", + "NEW_VARIABLE": "Δημιουργήστε μεταβλητή", "NEW_STRING_VARIABLE": "Δημιουργία μεταβλητή συμβολοσειράς...", "NEW_NUMBER_VARIABLE": "Δημιουργία μεταβλητής αριθμού...", "NEW_COLOUR_VARIABLE": "Δημιουργία μεταβλητής χρώματος...", @@ -53,7 +54,7 @@ "VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE": "Μια μεταβλητή με όνομα '%1' υπάρχει πάντα για έναν άλλο τύπο: '%2'.", "DELETE_VARIABLE_CONFIRMATION": "Θέλετε να διαγράψετε το %1 που χρησιμοποιείτε της μεταβλητής '%2'?", "CANNOT_DELETE_VARIABLE_PROCEDURE": "Δεν μπορώ να διαγράψω την μεταβλητή '%1' διότι είναι μέρος του ορισμού της λειτουργίας '%2'", - "DELETE_VARIABLE": "Διαγράψετε την μεταβλητή '%1'", + "DELETE_VARIABLE": "Διαγράψτε την μεταβλητή '%1'", "COLOUR_PICKER_HELPURL": "https://el.wikipedia.org/wiki/%CE%A7%CF%81%CF%8E%CE%BC%CE%B1", "COLOUR_PICKER_TOOLTIP": "Επιτρέπει επιλογή χρώματος από την παλέτα.", "COLOUR_RANDOM_TITLE": "τυχαίο χρώμα", diff --git a/msg/json/zh-hans.json b/msg/json/zh-hans.json index 59ed2af504c..1b552d81418 100644 --- a/msg/json/zh-hans.json +++ b/msg/json/zh-hans.json @@ -15,7 +15,8 @@ "WindWood", "Deathkon", "Muhaoying", - "佛壁灯" + "佛壁灯", + "Htq110219891" ] }, "VARIABLES_DEFAULT_NAME": "项目", @@ -167,7 +168,7 @@ "MATH_IS_DIVISIBLE_BY": "可被整除", "MATH_IS_TOOLTIP": "检查一个数值是否是偶数、奇数、质数、自然数、正数、负数或者是否能被某数整除。返回真或假。", "MATH_CHANGE_HELPURL": "https://zh.wikipedia.org/wiki/加法", - "MATH_CHANGE_TITLE": "将 %1 改为 %2", + "MATH_CHANGE_TITLE": "将 %1 增加 %2", "MATH_CHANGE_TOOLTIP": "为变量“%1”增加一个数值。", "MATH_ROUND_HELPURL": "https://zh.wikipedia.org/wiki/数值修约", "MATH_ROUND_TOOLTIP": "数字向上或向下舍入。", From 54eb7260631cafa0daa41c0a504d4d0b14d6f980 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 3 Jun 2019 11:02:05 -0700 Subject: [PATCH 097/233] Removed extra DropDownDiv calls. (#2532) --- core/field_angle.js | 3 --- core/field_colour.js | 4 ---- core/field_date.js | 3 --- 3 files changed, 10 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index ef6f90977cf..0b1e4d865e8 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -172,9 +172,6 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { // Mobile browsers have issues with in-line textareas (focus & keyboards). Blockly.FieldAngle.superClass_.showEditor_.call(this, noFocus); - // If there is an existing drop-down someone else owns, hide it immediately and clear it. - Blockly.DropDownDiv.hideWithoutAnimation(); - Blockly.DropDownDiv.clearContent(); var div = Blockly.DropDownDiv.getContentDiv(); // Build the SVG DOM. diff --git a/core/field_colour.js b/core/field_colour.js index c76b5612f27..1847bb9a9ef 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -285,10 +285,6 @@ Blockly.FieldColour.prototype.setColumns = function(columns) { * @private */ Blockly.FieldColour.prototype.showEditor_ = function() { - - Blockly.DropDownDiv.hideWithoutAnimation(); - Blockly.DropDownDiv.clearContent(); - var picker = this.createWidget_(); Blockly.DropDownDiv.getContentDiv().appendChild(picker); Blockly.DropDownDiv.setColour( diff --git a/core/field_date.js b/core/field_date.js index c9cddc29fdf..7603524035a 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -198,9 +198,6 @@ Blockly.FieldDate.prototype.updateEditor_ = function() { * @private */ Blockly.FieldDate.prototype.showEditor_ = function() { - Blockly.DropDownDiv.hideWithoutAnimation(); - Blockly.DropDownDiv.clearContent(); - this.picker_ = this.createWidget_(); this.picker_.render(Blockly.DropDownDiv.getContentDiv()); Blockly.utils.addClass(this.picker_.getElement(), 'blocklyDatePicker'); From 985bf3af3b1acb2372a1c8e2d019cbd90193d7fa Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Wed, 5 Jun 2019 09:53:56 -0700 Subject: [PATCH 098/233] Fixed how the trashcan handled shadow blocks. (#2545) --- core/trashcan.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/trashcan.js b/core/trashcan.js index ccee525bc14..2eb5cc8b61c 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -470,7 +470,8 @@ Blockly.Trashcan.prototype.onDelete_ = function() { if (trashcan.workspace_.options.maxTrashcanContents <= 0) { return; } - if (event.type == Blockly.Events.BLOCK_DELETE) { + if (event.type == Blockly.Events.BLOCK_DELETE && + event.oldXml.tagName.toLowerCase() != 'shadow') { var cleanedXML = trashcan.cleanBlockXML_(event.oldXml); if (trashcan.contents_.indexOf(cleanedXML) != -1) { return; From 4f20264128631062072b597a64c7fd0de24e911b Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 4 Jun 2019 21:22:12 -0700 Subject: [PATCH 099/233] Remove orphaned regexp. --- core/field_colour.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/field_colour.js b/core/field_colour.js index 1847bb9a9ef..c30f2bb7687 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -82,12 +82,6 @@ Blockly.FieldColour.DEFAULT_WIDTH = 16; */ Blockly.FieldColour.DEFAULT_HEIGHT = 12; -/** - * Regex that defines the form of a colour string. - * @type {RegExp} - */ -Blockly.FieldColour.COLOUR_REGEX = new RegExp('#[0-9a-fA-F]{6}'); - /** * Serializable fields are saved by the XML renderer, non-serializable fields * are not. Editable fields should also be serializable. From cdaded42962b7763c114b9e8f96c5755213e2863 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 4 Jun 2019 23:26:09 -0700 Subject: [PATCH 100/233] Remove goog.color.parse --- core/field_colour.js | 7 +-- core/utils_colour.js | 106 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 core/utils_colour.js diff --git a/core/field_colour.js b/core/field_colour.js index c30f2bb7687..d7cd85a3300 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -30,9 +30,9 @@ goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); +goog.require('Blockly.utils.colour'); goog.require('goog.math.Size'); -goog.require('goog.color'); /** @@ -172,10 +172,7 @@ Blockly.FieldColour.prototype.doClassValidation_ = function(newValue) { if (typeof newValue != 'string') { return null; } - if (goog.color.isValidColor(newValue)) { - return goog.color.parse(newValue).hex; - } - return null; + return Blockly.utils.colour.parse(newValue); }; /** diff --git a/core/utils_colour.js b/core/utils_colour.js new file mode 100644 index 00000000000..7f4f02333ed --- /dev/null +++ b/core/utils_colour.js @@ -0,0 +1,106 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utility methods for colour manipulation. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.utils.colour + * @namespace + */ +goog.provide('Blockly.utils.colour'); + +goog.require('Blockly.utils'); + +goog.require('goog.color'); + + +/** + * Parses a colour from a string. + * .parse('red') -> '#ff0000' + * .parse('#f00') -> '#ff0000' + * .parse('#ff0000') -> '#ff0000' + * .parse('rgb(255, 0, 0)') -> '#ff0000' + * @param {string} str Colour in some CSS format. + * @return {string|null} A string containing a hex representation of the colour, + * or null if can't be parsed. + */ +Blockly.utils.colour.parse = function(str) { + str = String(str).toLowerCase().trim(); + var hex = Blockly.utils.colour.names[str]; + if (hex) { + // e.g. 'red' + return hex; + } + hex = str[0] == '#' ? str : '#' + str; + if (/^#[0-9a-f]{6}$/.test(hex)) { + // e.g. '#00ff88' + return hex; + } + if (/^#[0-9a-f]{3}$/.test(hex)) { + // e.g. '#0f8' + return ['#', hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]].join(''); + } + var rgb = str.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/); + if (rgb) { + // e.g. 'rgb(0, 128, 255)' + var r = Number(rgb[1]); + var g = Number(rgb[2]); + var b = Number(rgb[3]); + if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) { + return goog.color.rgbArrayToHex([r, g, b]); + } + } + return null; +}; + + + +/** + * A map that contains the 16 basic colour keywords as defined by W3C: + * https://www.w3.org/TR/2018/REC-css-color-3-20180619/#html4 + * The keys of this map are the lowercase "readable" names of the colours, + * while the values are the "hex" values. + * + * @type {!Object} + */ +Blockly.utils.colour.names = { + 'aqua': '#00ffff', + 'black': '#000000', + 'blue': '#0000ff', + 'fuchsia': '#ff00ff', + 'gray': '#808080', + 'green': '#008000', + 'lime': '#00ff00', + 'maroon': '#800000', + 'navy': '#000080', + 'olive': '#808000', + 'purple': '#800080', + 'red': '#ff0000', + 'silver': '#c0c0c0', + 'teal': '#008080', + 'white': '#ffffff', + 'yellow': '#ffff00' +}; From ed9330cf576b1c040550034743d7005f1e890d7f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 5 Jun 2019 13:11:17 -0700 Subject: [PATCH 101/233] Move Blockly.hueToRgb to Blockly.utils.colour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also adds support for ‘#f00’, ‘rgb(255, 0, 0)’ and ‘red’ for block colours, in addition to ‘#ff0000’ (and of course hue). --- core/block.js | 26 ++++++++++++++------------ core/blockly.js | 12 ------------ core/toolbox.js | 2 +- core/utils_colour.js | 10 ++++++++++ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core/block.js b/core/block.js index db95e20a51a..c1c429aba72 100644 --- a/core/block.js +++ b/core/block.js @@ -931,8 +931,8 @@ Blockly.Block.prototype.getStyleName = function() { }; /** - * Get the HSV hue value of a block. Null if hue not set. - * @return {?number} Hue value (0-360) + * Get the HSV hue value of a block. Null if hue not set. + * @return {?number} Hue value (0-360). */ Blockly.Block.prototype.getHue = function() { return this.hue_; @@ -950,18 +950,20 @@ Blockly.Block.prototype.setColour = function(colour) { var hue = Number(dereferenced); if (!isNaN(hue) && 0 <= hue && hue <= 360) { this.hue_ = hue; - this.colour_ = Blockly.hueToRgb(hue); - } else if ((typeof dereferenced == 'string') && - /^#[0-9a-fA-F]{6}$/.test(dereferenced)) { - this.colour_ = dereferenced; - // Only store hue if colour is set as a hue. - this.hue_ = null; + this.colour_ = Blockly.utils.colour.hueToRgb(hue); } else { - var errorMsg = 'Invalid colour: "' + dereferenced + '"'; - if (colour != dereferenced) { - errorMsg += ' (from "' + colour + '")'; + var hex = Blockly.utils.colour.parse(dereferenced); + if (hex) { + this.colour_ = hex; + // Only store hue if colour is set as a hue. + this.hue_ = null; + } else { + var errorMsg = 'Invalid colour: "' + dereferenced + '"'; + if (colour != dereferenced) { + errorMsg += ' (from "' + colour + '")'; + } + throw Error(errorMsg); } - throw Error(errorMsg); } }; diff --git a/core/blockly.js b/core/blockly.js index 27f12aba6cd..eea9c7902e6 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -57,8 +57,6 @@ goog.require('Blockly.inject'); goog.require('Blockly.utils'); goog.require('Blockly.Xml'); -goog.require('goog.color'); - // Turn off debugging when compiled. // Unused within the Blockly library, but used in Closure. @@ -121,16 +119,6 @@ Blockly.cache3dSupported_ = null; */ Blockly.theme_ = null; -/** - * Convert a hue (HSV model) into an RGB hex triplet. - * @param {number} hue Hue on a colour wheel (0-360). - * @return {string} RGB code, e.g. '#5ba65b'. - */ -Blockly.hueToRgb = function(hue) { - return goog.color.hsvToHex(hue, Blockly.HSV_SATURATION, - Blockly.HSV_VALUE * 255); -}; - /** * Returns the dimensions of the specified SVG image. * @param {!Element} svg SVG image. diff --git a/core/toolbox.js b/core/toolbox.js index 7f61dcaac67..040707b8b3a 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -400,7 +400,7 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryN this.hasColours_ = true; } else if (typeof colour === 'number' || (typeof colour === 'string' && !isNaN(Number(colour)))) { - childOut.hexColour = Blockly.hueToRgb(Number(colour)); + childOut.hexColour = Blockly.utils.colour.hueToRgb(Number(colour)); this.hasColours_ = true; } else { childOut.hexColour = ''; diff --git a/core/utils_colour.js b/core/utils_colour.js index 7f4f02333ed..14edb440a8a 100644 --- a/core/utils_colour.js +++ b/core/utils_colour.js @@ -78,6 +78,16 @@ Blockly.utils.colour.parse = function(str) { +/** + * Convert a hue (HSV model) into an RGB hex triplet. + * @param {number} hue Hue on a colour wheel (0-360). + * @return {string} RGB code, e.g. '#5ba65b'. + */ +Blockly.utils.colour.hueToRgb = function(hue) { + return goog.color.hsvToHex(hue, Blockly.HSV_SATURATION, + Blockly.HSV_VALUE * 255); +}; + /** * A map that contains the 16 basic colour keywords as defined by W3C: * https://www.w3.org/TR/2018/REC-css-color-3-20180619/#html4 From 069423e7cd05f492a86da252344b20f495386085 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 5 Jun 2019 13:44:05 -0700 Subject: [PATCH 102/233] Remove last traces of goog.color. --- core/block.js | 13 ++--- core/toolbox.js | 2 +- core/utils_colour.js | 112 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 113 insertions(+), 14 deletions(-) diff --git a/core/block.js b/core/block.js index c1c429aba72..a8da3905a50 100644 --- a/core/block.js +++ b/core/block.js @@ -42,7 +42,6 @@ goog.require('Blockly.Warning'); goog.require('Blockly.Workspace'); goog.require('goog.math.Coordinate'); -goog.require('goog.color'); /** @@ -891,9 +890,7 @@ Blockly.Block.prototype.getColourShadow = function() { if (colourSecondary) { return colourSecondary; } - var rgb = goog.color.hexToRgb(this.getColour()); - rgb = goog.color.lighten(rgb, 0.6); - return goog.color.rgbArrayToHex(rgb); + return Blockly.utils.colour.blend('white', this.getColour(), 0.6); }; /** @@ -914,11 +911,11 @@ Blockly.Block.prototype.getColourBorder = function() { colourDark: null }; } - var rgb = goog.color.hexToRgb(this.getColour()); + var colour = this.getColour(); return { colourBorder: null, - colourLight: goog.color.rgbArrayToHex(goog.color.lighten(rgb, 0.3)), - colourDark: goog.color.rgbArrayToHex(goog.color.darken(rgb, 0.2)) + colourLight: Blockly.utils.colour.blend('white',colour, 0.3), + colourDark: Blockly.utils.colour.blend('black', colour, 0.2) }; }; @@ -950,7 +947,7 @@ Blockly.Block.prototype.setColour = function(colour) { var hue = Number(dereferenced); if (!isNaN(hue) && 0 <= hue && hue <= 360) { this.hue_ = hue; - this.colour_ = Blockly.utils.colour.hueToRgb(hue); + this.colour_ = Blockly.utils.colour.hueToHex(hue); } else { var hex = Blockly.utils.colour.parse(dereferenced); if (hex) { diff --git a/core/toolbox.js b/core/toolbox.js index 040707b8b3a..661535cb5da 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -400,7 +400,7 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryN this.hasColours_ = true; } else if (typeof colour === 'number' || (typeof colour === 'string' && !isNaN(Number(colour)))) { - childOut.hexColour = Blockly.utils.colour.hueToRgb(Number(colour)); + childOut.hexColour = Blockly.utils.colour.hueToHex(Number(colour)); this.hasColours_ = true; } else { childOut.hexColour = ''; diff --git a/core/utils_colour.js b/core/utils_colour.js index 14edb440a8a..549cd1c61b4 100644 --- a/core/utils_colour.js +++ b/core/utils_colour.js @@ -34,8 +34,6 @@ goog.provide('Blockly.utils.colour'); goog.require('Blockly.utils'); -goog.require('goog.color'); - /** * Parses a colour from a string. @@ -70,24 +68,128 @@ Blockly.utils.colour.parse = function(str) { var g = Number(rgb[2]); var b = Number(rgb[3]); if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) { - return goog.color.rgbArrayToHex([r, g, b]); + return Blockly.utils.colour.rgbToHex(r, g, b); } } return null; }; +/** + * Converts a colour from RGB to hex representation. + * @param {number} r Amount of red, int between 0 and 255. + * @param {number} g Amount of green, int between 0 and 255. + * @param {number} b Amount of blue, int between 0 and 255. + * @return {string} Hex representation of the colour. + */ +Blockly.utils.colour.rgbToHex = function(r, g, b) { + var rgb = (r << 16) | (g << 8) | b; + if (r < 0x10) { + return '#' + (0x1000000 | rgb).toString(16).substr(1); + } + return '#' + rgb.toString(16); +}; + +/** + * Converts a hex representation of a colour to RGB. + * @param {string} hexColor Colour in '#ff0000' format. + * @return {!Array.} RGB representation of the colour. + */ +Blockly.utils.colour.hexToRgb = function(hexColor) { + var rgb = parseInt(hexColor.substr(1), 16); + var r = rgb >> 16; + var g = (rgb >> 8) & 255; + var b = rgb & 255; + return [r, g, b]; +}; /** * Convert a hue (HSV model) into an RGB hex triplet. * @param {number} hue Hue on a colour wheel (0-360). * @return {string} RGB code, e.g. '#5ba65b'. */ -Blockly.utils.colour.hueToRgb = function(hue) { - return goog.color.hsvToHex(hue, Blockly.HSV_SATURATION, +Blockly.utils.colour.hueToHex = function(hue) { + return Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION, Blockly.HSV_VALUE * 255); }; +/** + * Converts an HSV triplet to hex representation. + * @param {number} h Hue value in [0, 360]. + * @param {number} s Saturation value in [0, 1]. + * @param {number} v Brightness in [0, 255]. + * @return {string} Hex representation of the colour. + */ +Blockly.utils.colour.hsvToHex = function(h, s, v) { + var red = 0; + var green = 0; + var blue = 0; + if (s == 0) { + red = v; + green = v; + blue = v; + } else { + var sextant = Math.floor(h / 60); + var remainder = (h / 60) - sextant; + var val1 = v * (1 - s); + var val2 = v * (1 - (s * remainder)); + var val3 = v * (1 - (s * (1 - remainder))); + switch (sextant) { + case 1: + red = val2; + green = v; + blue = val1; + break; + case 2: + red = val1; + green = v; + blue = val3; + break; + case 3: + red = val1; + green = val2; + blue = v; + break; + case 4: + red = val3; + green = val1; + blue = v; + break; + case 5: + red = v; + green = val1; + blue = val2; + break; + case 6: + case 0: + red = v; + green = val3; + blue = val1; + break; + } + } + return Blockly.utils.colour.rgbToHex( + Math.floor(red), Math.floor(green), Math.floor(blue)); +}; + +/** + * Blend two colours together, using the specified factor to indicate the + * weight given to the first colour. + * @param {string} colour1 First colour. + * @param {string} colour2 Second colour. + * @param {number} factor The weight to be given to colour1 over colour2. + * Values should be in the range [0, 1]. + * @return {string} Combined colour represented in hex. + */ +Blockly.utils.colour.blend = function(colour1, colour2, factor) { + var rgb1 = Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(colour1)); + var rgb2 = Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(colour2)); + var r = Math.round(rgb2[0] + factor * (rgb1[0] - rgb2[0])); + var g = Math.round(rgb2[1] + factor * (rgb1[1] - rgb2[1])); + var b = Math.round(rgb2[2] + factor * (rgb1[2] - rgb2[2])); + return Blockly.utils.colour.rgbToHex(r, g, b); +}; + /** * A map that contains the 16 basic colour keywords as defined by W3C: * https://www.w3.org/TR/2018/REC-css-color-3-20180619/#html4 From 2d11b6f0adef398b8f7cc20a9dfb080d6f76b03c Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 5 Jun 2019 13:46:48 -0700 Subject: [PATCH 103/233] Recompile due to changed dependencies. --- blockly_accessible_compressed.js | 241 ++++++++++++++--------------- blockly_accessible_uncompressed.js | 78 +++++----- blockly_compressed.js | 241 ++++++++++++++--------------- blockly_uncompressed.js | 78 +++++----- 4 files changed, 306 insertions(+), 332 deletions(-) diff --git a/blockly_accessible_compressed.js b/blockly_accessible_compressed.js index f336370527d..def228f6bf2 100644 --- a/blockly_accessible_compressed.js +++ b/blockly_accessible_compressed.js @@ -115,25 +115,7 @@ goog.math.safeCeil=function(a,b){goog.asserts.assert(!goog.isDef(b)||0>16,a>>8&255,a&255]}; -goog.color.rgbToHex=function(a,b,c){a=Number(a);b=Number(b);c=Number(c);if(a!=(a&255)||b!=(b&255)||c!=(c&255))throw Error('"('+a+","+b+","+c+'") is not a valid RGB color');b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};goog.color.rgbArrayToHex=function(a){return goog.color.rgbToHex(a[0],a[1],a[2])}; -goog.color.rgbToHsl=function(a,b,c){a/=255;b/=255;c/=255;var d=Math.max(a,b,c),e=Math.min(a,b,c),f=0,g=0,h=.5*(d+e);d!=e&&(d==a?f=60*(b-c)/(d-e):d==b?f=60*(c-a)/(d-e)+120:d==c&&(f=60*(a-b)/(d-e)+240),g=0=h?(d-e)/(2*h):(d-e)/(2-2*h));return[Math.round(f+360)%360,g,h]};goog.color.rgbArrayToHsl=function(a){return goog.color.rgbToHsl(a[0],a[1],a[2])};goog.color.hueToRgb_=function(a,b,c){0>c?c+=1:16*c?a+6*(b-a)*c:1>2*c?b:2>3*c?a+(b-a)*(2/3-c)*6:a}; -goog.color.hslToRgb=function(a,b,c){a/=360;if(0==b)c=b=a=255*c;else{var d=.5>c?c*(1+b):c+b-b*c;var e=2*c-d;c=255*goog.color.hueToRgb_(e,d,a+1/3);b=255*goog.color.hueToRgb_(e,d,a);a=255*goog.color.hueToRgb_(e,d,a-1/3)}return[Math.round(c),Math.round(b),Math.round(a)]};goog.color.hslArrayToRgb=function(a){return goog.color.hslToRgb(a[0],a[1],a[2])};goog.color.validHexColorRe_=/^#(?:[0-9a-f]{3}){1,2}$/i;goog.color.isValidHexColor_=function(a){return goog.color.validHexColorRe_.test(a)}; -goog.color.rgbColorRe_=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;goog.color.isValidRgbColor_=function(a){var b=a.match(goog.color.rgbColorRe_);if(b){a=Number(b[1]);var c=Number(b[2]);b=Number(b[3]);if(0<=a&&255>=a&&0<=c&&255>=c&&0<=b&&255>=b)return[a,c,b]}return[]};goog.color.prependZeroIfNecessaryHelper=function(a){return 1==a.length?"0"+a:a};goog.color.prependHashIfNecessaryHelper=function(a){return"#"==a.charAt(0)?a:"#"+a}; -goog.color.rgbStyle_=function(a){return"rgb("+a.join(",")+")"};goog.color.hsvToRgb=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return[Math.floor(d),Math.floor(e),Math.floor(f)]}; -goog.color.rgbToHsv=function(a,b,c){var d=Math.max(Math.max(a,b),c),e=Math.min(Math.min(a,b),c);if(e==d)e=a=0;else{var f=d-e;e=f/d;a=60*(a==d?(b-c)/f:b==d?2+(c-a)/f:4+(a-b)/f);0>a&&(a+=360);360=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2]))]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)}; -goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)};goog.color.highContrast=function(a,b){for(var c=[],d=0;d"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=Blockly.Xml.utils.textToDomDocument(a);if(!a||!a.documentElement||"xml"!=a.documentElement.nodeName.toLowerCase())throw TypeError("Blockly.Xml.textToDom expected an document.");return a.documentElement};Blockly.Xml.clearWorkspaceAndLoadFromXml=function(a,b){b.setResizesEnabled(!1);b.clear();a=Blockly.Xml.domToWorkspace(a,b);b.setResizesEnabled(!0);return a}; Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());c=[];Blockly.Field.startCache();var e=a.childNodes.length,f=Blockly.Events.getGroup();f||Blockly.Events.setGroup(!0);b.setResizesEnabled&&b.setResizesEnabled(!1);var g=!0;try{for(var h=0;hBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,Blockly.Tooltip.showPid_= setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));Blockly.Tooltip.showPid_&&clearTimeout(Blockly.Tooltip.showPid_)};Blockly.Tooltip.block=function(){Blockly.Tooltip.hide();Blockly.Tooltip.blocked_=!0};Blockly.Tooltip.unblock=function(){Blockly.Tooltip.blocked_=!1}; @@ -1201,15 +1183,14 @@ Blockly.Gesture.prototype.doBubbleClick_=function(){this.startBubble_.setFocus&& Blockly.Gesture.prototype.doBlockClick_=function(){this.flyout_&&this.flyout_.autoClose?this.targetBlock_.isEnabled()&&(Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.flyout_.createBlock(this.targetBlock_).scheduleSnapAndBump()):Blockly.Events.fire(new Blockly.Events.Ui(this.startBlock_,"click",void 0,void 0));this.bringBlockToFront_();Blockly.Events.setGroup(!1)};Blockly.Gesture.prototype.doWorkspaceClick_=function(){Blockly.selected&&Blockly.selected.unselect()}; Blockly.Gesture.prototype.bringBlockToFront_=function(){this.targetBlock_&&!this.flyout_&&this.targetBlock_.bringToFront()};Blockly.Gesture.prototype.setStartField=function(a){if(this.hasStarted_)throw Error("Tried to call gesture.setStartField, but the gesture had already been started.");this.startField_||(this.startField_=a)};Blockly.Gesture.prototype.setStartBubble=function(a){this.startBubble_||(this.startBubble_=a)}; Blockly.Gesture.prototype.setStartBlock=function(a){this.startBlock_||this.startBubble_||(this.startBlock_=a,a.isInFlyout&&a!=a.getRootBlock()?this.setTargetBlock_(a.getRootBlock()):this.setTargetBlock_(a))};Blockly.Gesture.prototype.setTargetBlock_=function(a){a.isShadow()?this.setTargetBlock_(a.getParent()):this.targetBlock_=a};Blockly.Gesture.prototype.setStartWorkspace_=function(a){this.startWorkspace_||(this.startWorkspace_=a)}; -Blockly.Gesture.prototype.setStartFlyout_=function(a){this.flyout_||(this.flyout_=a)};Blockly.Gesture.prototype.isBubbleClick_=function(){return!!this.startBubble_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isBlockClick_=function(){return!!this.startBlock_&&!this.hasExceededDragRadius_&&!this.isFieldClick_()};Blockly.Gesture.prototype.isFieldClick_=function(){return(this.startField_?this.startField_.isCurrentlyEditable():!1)&&!this.hasExceededDragRadius_&&(!this.flyout_||!this.flyout_.autoClose)}; +Blockly.Gesture.prototype.setStartFlyout_=function(a){this.flyout_||(this.flyout_=a)};Blockly.Gesture.prototype.isBubbleClick_=function(){return!!this.startBubble_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isBlockClick_=function(){return!!this.startBlock_&&!this.hasExceededDragRadius_&&!this.isFieldClick_()};Blockly.Gesture.prototype.isFieldClick_=function(){return(this.startField_?this.startField_.isClickable():!1)&&!this.hasExceededDragRadius_&&(!this.flyout_||!this.flyout_.autoClose)}; Blockly.Gesture.prototype.isWorkspaceClick_=function(){return!this.startBlock_&&!this.startBubble_&&!this.startField_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isDragging=function(){return this.isDraggingWorkspace_||this.isDraggingBlock_||this.isDraggingBubble_};Blockly.Gesture.prototype.hasStarted=function(){return this.hasStarted_};Blockly.Gesture.prototype.getInsertionMarkers=function(){return this.blockDragger_?this.blockDragger_.getInsertionMarkers():[]}; Blockly.Gesture.inProgress=function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)if(c.currentGesture_)return!0;return!1};Blockly.Grid=function(a,b){this.gridPattern_=a;this.spacing_=b.spacing;this.length_=b.length;this.line2_=(this.line1_=a.firstChild)&&this.line1_.nextSibling;this.snapToGrid_=b.snap};Blockly.Grid.prototype.scale_=1;Blockly.Grid.prototype.dispose=function(){this.gridPattern_=null};Blockly.Grid.prototype.shouldSnap=function(){return this.snapToGrid_};Blockly.Grid.prototype.getSpacing=function(){return this.spacing_};Blockly.Grid.prototype.getPatternId=function(){return this.gridPattern_.id}; Blockly.Grid.prototype.update=function(a){this.scale_=a;var b=this.spacing_*a||100;this.gridPattern_.setAttribute("width",b);this.gridPattern_.setAttribute("height",b);b=Math.floor(this.spacing_/2)+.5;var c=b-this.length_/2,d=b+this.length_/2;b*=a;c*=a;d*=a;this.setLineAttributes_(this.line1_,a,c,d,b,b);this.setLineAttributes_(this.line2_,a,b,b,c,d)}; Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(Blockly.userAgent.IE||Blockly.userAgent.EDGE)&&this.update(this.scale_)}; Blockly.Grid.createDom=function(a,b,c){a=Blockly.utils.createSvgElement("pattern",{id:"blocklyGridPattern"+a,patternUnits:"userSpaceOnUse"},c);0this.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; -Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()}; -Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.callValidator(a);null!==b&&(a=b);b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){}; -Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.initView=function(){this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},this.fieldGroup_);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_);this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_;Blockly.Tooltip.bindMouseEvents(this.textElement_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)}; -Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; +Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())}; +Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.doClassValidation_(a);void 0!==b&&(a=b);if(null===a)this.doValueInvalid_(),this.isDirty_&&this.forceRerender();else{if(b=this.getValidator())if(b=b.call(this,a),void 0!==b&&(a=b),null===a){this.doValueInvalid_();this.isDirty_&&this.forceRerender();return}b=this.getValue();b!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.doValueUpdate_(a), +this.isDirty_&&this.forceRerender())}}};Blockly.Field.prototype.value_=null;Blockly.Field.prototype.doClassValidation_=function(a){return a=this.classValidator(a)};Blockly.Field.prototype.doValueUpdate_=function(a){this.value_=a;this.isDirty_=!0;this.text_=String(a)};Blockly.Field.prototype.doValueInvalid_=function(){};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)}; +Blockly.Field.prototype.setTooltip=function(a){a||""===a?this.getClickTarget_().tooltip=a:this.getClickTarget_().tooltip=this.sourceBlock_};Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;a=this.doClassValidation_(a);null===a&&(a="");this.setValue(a)};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; +Blockly.FieldLabel.prototype.initView=function(){this.createTextElement_();this.textElement_.setAttribute("y",this.size_.height-5);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.doClassValidation_=function(a){return null===a||void 0===a?null:String(a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; Blockly.Input.prototype.setVisible=function(a){var b=[];if(this.visible_==a)return b;for(var c=(this.visible_=a)?"block":"none",d=0,e;e=this.fieldRow[d];d++)e.setVisible(a);this.connection&&(a?b=this.connection.unhideAll():this.connection.hideAll(),d=this.connection.targetBlock())&&(d.getSvgRoot().style.display=c,a||(d.rendered=!1));return b};Blockly.Input.prototype.setCheck=function(a){if(!this.connection)throw Error("This input does not have a connection.");this.connection.setCheck(a);return this}; @@ -1454,9 +1436,9 @@ Blockly.Block.prototype.setMovable=function(a){this.movable_=a};Blockly.Block.pr Blockly.Block.prototype.setInsertionMarker=function(a){this.isInsertionMarker_=a};Blockly.Block.prototype.isEditable=function(){return this.editable_&&!(this.workspace&&this.workspace.options.readOnly)};Blockly.Block.prototype.setEditable=function(a){this.editable_=a;a=0;for(var b;b=this.inputList[a];a++)for(var c=0,d;d=b.fieldRow[c];c++)d.updateEditable()}; Blockly.Block.prototype.setConnectionsHidden=function(a){if(!a&&this.isCollapsed()){if(this.outputConnection&&this.outputConnection.setHidden(a),this.previousConnection&&this.previousConnection.setHidden(a),this.nextConnection){this.nextConnection.setHidden(a);var b=this.nextConnection.targetBlock();b&&b.setConnectionsHidden(a)}}else for(var c=this.getConnections_(!0),d=0;b=c[d];d++)b.setHidden(a),b.isSuperior()&&(b=b.targetBlock())&&b.setConnectionsHidden(a)}; Blockly.Block.prototype.getMatchingConnection=function(a,b){var c=this.getConnections_(!0);a=a.getConnections_(!0);if(c.length!=a.length)throw Error("Connection lists did not match in length.");for(var d=0;d=c)this.hue_=c,this.colour_=Blockly.hueToRgb(c);else if("string"==typeof b&&/^#[0-9a-fA-F]{6}$/.test(b))this.colour_=b,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; +Blockly.Block.prototype.getColourTertiary=function(){return this.colourTertiary_};Blockly.Block.prototype.getColourShadow=function(){var a=this.getColourSecondary();return a?a:Blockly.utils.colour.blend("white",this.getColour(),.6)}; +Blockly.Block.prototype.getColourBorder=function(){var a=this.getColourTertiary();if(a)return{colourBorder:a,colourLight:null,colourDark:null};a=this.getColour();return{colourBorder:null,colourLight:Blockly.utils.colour.blend("white",a,.3),colourDark:Blockly.utils.colour.blend("black",a,.2)}};Blockly.Block.prototype.getStyleName=function(){return this.styleName_};Blockly.Block.prototype.getHue=function(){return this.hue_}; +Blockly.Block.prototype.setColour=function(a){var b="string"==typeof a?Blockly.utils.replaceMessageReferences(a):a,c=Number(b);if(!isNaN(c)&&0<=c&&360>=c)this.hue_=c,this.colour_=Blockly.utils.colour.hueToHex(c);else if(c=Blockly.utils.colour.parse(b))this.colour_=c,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; Blockly.Block.prototype.setStyle=function(a){var b=Blockly.getTheme();if(!b)throw Error("Trying to set block style to "+a+" before theme was defined via Blockly.setTheme().");b=b.getBlockStyle(a);this.styleName_=a;if(b)this.colourSecondary_=b.colourSecondary,this.colourTertiary_=b.colourTertiary,this.hat=b.hat,this.setColour(b.colourPrimary);else throw Error("Invalid style name: "+a);}; Blockly.Block.prototype.setOnChange=function(a){if(a&&"function"!=typeof a)throw Error("onchange must be a function.");this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);if(this.onchange=a)this.onchangeWrapper_=a.bind(this),this.workspace.addChangeListener(this.onchangeWrapper_)};Blockly.Block.prototype.getField=function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(e.name===a)return e;return null}; Blockly.Block.prototype.getVars=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&a.push(e.getValue());return a};Blockly.Block.prototype.getVarModels=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&(e=this.workspace.getVariableById(e.getValue()))&&a.push(e);return a}; @@ -1580,7 +1562,7 @@ Blockly.DropDownDiv=function(){};Blockly.DropDownDiv.DIV_=null;Blockly.DropDownD Blockly.DropDownDiv.createDom=function(){if(!Blockly.DropDownDiv.DIV_){var a=document.createElement("div");a.className="blocklyDropDownDiv";document.body.appendChild(a);Blockly.DropDownDiv.DIV_=a;var b=document.createElement("div");b.className="blocklyDropDownContent";a.appendChild(b);Blockly.DropDownDiv.content_=b;b=document.createElement("div");b.className="blocklyDropDownArrow";a.appendChild(b);Blockly.DropDownDiv.arrow_=b;Blockly.DropDownDiv.DIV_.style.transition="transform "+Blockly.DropDownDiv.ANIMATION_TIME+ "s, opacity "+Blockly.DropDownDiv.ANIMATION_TIME+"s"}};Blockly.DropDownDiv.setBoundsElement=function(a){Blockly.DropDownDiv.boundsElement_=a};Blockly.DropDownDiv.getContentDiv=function(){return Blockly.DropDownDiv.content_};Blockly.DropDownDiv.clearContent=function(){Blockly.DropDownDiv.content_.innerHTML="";Blockly.DropDownDiv.content_.style.width=""};Blockly.DropDownDiv.setColour=function(a,b){Blockly.DropDownDiv.DIV_.style.backgroundColor=a;Blockly.DropDownDiv.DIV_.style.borderColor=b}; Blockly.DropDownDiv.setCategory=function(a){Blockly.DropDownDiv.DIV_.setAttribute("data-category",a)};Blockly.DropDownDiv.showPositionedByBlock=function(a,b,c,d){var e=b.workspace.scale,f=b.width,g=b.height;f*=e;g*=e;e=b.getSvgRoot().getBoundingClientRect();f=e.left+f/2;g=e.top+g;e=e.top;d&&(e+=d);Blockly.DropDownDiv.setBoundsElement(b.workspace.getParentSvg().parentNode);return Blockly.DropDownDiv.show(a,f,g,f,e,c)}; -Blockly.DropDownDiv.showPositionedByField=function(a,b,c){var d=a.fieldGroup_.getBoundingClientRect(),e=d.left+d.width/2,f=d.bottom;d=d.top;c&&(d+=c);Blockly.DropDownDiv.positionToField_=!0;Blockly.DropDownDiv.setBoundsElement(a.sourceBlock_.workspace.getParentSvg().parentNode);return Blockly.DropDownDiv.show(a,e,f,e,d,b)}; +Blockly.DropDownDiv.showPositionedByField=function(a,b,c){var d=a.fieldGroup_.getBoundingClientRect(),e=d.left+d.width/2,f=d.bottom;d=d.top;c&&(d+=c);Blockly.DropDownDiv.positionToField_=!0;Blockly.DropDownDiv.setBoundsElement(a.getSourceBlock().workspace.getParentSvg().parentNode);return Blockly.DropDownDiv.show(a,e,f,e,d,b)}; Blockly.DropDownDiv.show=function(a,b,c,d,e,f){Blockly.DropDownDiv.owner_=a;Blockly.DropDownDiv.onHide_=f;a=Blockly.DropDownDiv.getPositionMetrics(b,c,d,e);Blockly.DropDownDiv.arrow_.style.transform="translate("+a.arrowX+"px,"+a.arrowY+"px) rotate(45deg)";Blockly.DropDownDiv.arrow_.setAttribute("class",a.arrowAtTop?"blocklyDropDownArrow arrowTop":"blocklyDropDownArrow arrowBottom");Blockly.DropDownDiv.arrow_.style.display=a.arrowVisible?"":"none";Blockly.DropDownDiv.positionInternal_(a.initialX,a.initialY, a.finalX,a.finalY);return a.arrowAtTop};Blockly.DropDownDiv.getBoundsInfo_=function(){var a=Blockly.DropDownDiv.boundsElement_.getBoundingClientRect(),b=goog.style.getSize(Blockly.DropDownDiv.boundsElement_);return{left:a.left,right:a.left+b.width,top:a.top,bottom:a.top+b.height,width:b.width,height:b.height}}; Blockly.DropDownDiv.getPositionMetrics=function(a,b,c,d){var e=Blockly.DropDownDiv.getBoundsInfo_(),f=goog.style.getSize(Blockly.DropDownDiv.DIV_);if(b+f.height>e.bottom)if(d-f.heightc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+ -Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a, -"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; -Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;a=a.clientY-b.top-Blockly.FieldAngle.HALF;b=Math.atan(-a/c);isNaN(b)||(b=Blockly.utils.toDegrees(b),0>c?b+=180:0c;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+ +Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove", +this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; +Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& +(a-=360),c=String(a),c!=this.text_&&(Blockly.FieldTextInput.htmlInput_.value=a,this.setValue(a),this.text_=c,this.forceRerender()))}; +Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; d-=Math.sin(b)*Blockly.FieldAngle.RADIUS;b=Math.abs(Math.floor((b-e)/Math.PI)%2);Blockly.FieldAngle.CLOCKWISE&&(b=1-b);a.push(" l ",f,",",g," A ",Blockly.FieldAngle.RADIUS,",",Blockly.FieldAngle.RADIUS," 0 ",b," ",Number(Blockly.FieldAngle.CLOCKWISE)," ",c,",",d," z")}this.gauge_.setAttribute("d",a.join(""));this.line_.setAttribute("x2",c);this.line_.setAttribute("y2",d)}}; -Blockly.FieldAngle.prototype.classValidator=function(a){if(null===a)return null;a=parseFloat(a||0);if(isNaN(a))return null;a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; -Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; -Blockly.FieldCheckbox.prototype.setValue=function(a){a="string"==typeof a?"TRUE"==a.toUpperCase():!!a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(String(a).toUpperCase())}; -Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null; -Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.initView=function(){Blockly.FieldColour.superClass_.initView.call(this);this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.borderRect_.style.fillOpacity=1;this.borderRect_.setAttribute("width",this.size_.width+Blockly.BlockSvg.SEP_SPACE_X);this.setValue(this.getValue())}; -Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.updateWidth=function(){};Blockly.FieldColour.prototype.getValue=function(){return this.colour_}; -Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); +Blockly.FieldAngle.prototype.doClassValidation_=function(a){if(isNaN(a))return null;a=parseFloat(a||0);a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return a};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){a=this.doClassValidation_(a);null===a&&(a="FALSE");Blockly.FieldCheckbox.superClass_.constructor.call(this,a,b);this.size_.width=Blockly.FieldCheckbox.WIDTH};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked)};Blockly.FieldCheckbox.WIDTH=5;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.CHECK_X_OFFSET=-3;Blockly.FieldCheckbox.CHECK_Y_OFFSET=14; +Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.prototype.CURSOR="default";Blockly.FieldCheckbox.prototype.isDirty_=!1; +Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.textElement_.setAttribute("x",Blockly.FieldCheckbox.CHECK_X_OFFSET);this.textElement_.setAttribute("y",Blockly.FieldCheckbox.CHECK_Y_OFFSET);Blockly.utils.addClass(this.textElement_,"blocklyCheckbox");var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.textElement_.appendChild(a);this.textElement_.style.display=this.value_?"block":"none"}; +Blockly.FieldCheckbox.prototype.showEditor_=function(){this.setValue(!this.value_)};Blockly.FieldCheckbox.prototype.doClassValidation_=function(a){return!0===a||"TRUE"===a?"TRUE":!1===a||"FALSE"===a?"FALSE":null};Blockly.FieldCheckbox.prototype.doValueUpdate_=function(a){this.value_=this.convertValueToBool_(a);this.textElement_&&(this.textElement_.style.display=this.value_?"block":"none")};Blockly.FieldCheckbox.prototype.getValue=function(){return this.value_?"TRUE":"FALSE"}; +Blockly.FieldCheckbox.prototype.getValueBoolean=function(){return this.value_};Blockly.FieldCheckbox.prototype.getText=function(){return String(this.convertValueToBool_(this.value_))};Blockly.FieldCheckbox.prototype.convertValueToBool_=function(a){return"string"==typeof a?"TRUE"==a:!!a};Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.utils.colour={};Blockly.utils.colour.parse=function(a){a=String(a).toLowerCase().trim();var b=Blockly.utils.colour.names[a];if(b)return b;b="#"==a[0]?a:"#"+a;if(/^#[0-9a-f]{6}$/.test(b))return b;if(/^#[0-9a-f]{3}$/.test(b))return["#",b[1],b[1],b[2],b[2],b[3],b[3]].join("");var c=a.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);return c&&(a=Number(c[1]),b=Number(c[2]),c=Number(c[3]),0<=a&&256>a&&0<=b&&256>b&&0<=c&&256>c)?Blockly.utils.colour.rgbToHex(a,b,c):null}; +Blockly.utils.colour.rgbToHex=function(a,b,c){b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};Blockly.utils.colour.hexToRgb=function(a){a=parseInt(a.substr(1),16);return[a>>16,a>>8&255,a&255]};Blockly.utils.colour.hueToHex=function(a){return Blockly.utils.colour.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)}; +Blockly.utils.colour.hsvToHex=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return Blockly.utils.colour.rgbToHex(Math.floor(d),Math.floor(e),Math.floor(f))}; +Blockly.utils.colour.blend=function(a,b,c){a=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(a));b=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(b));return Blockly.utils.colour.rgbToHex(Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2])))}; +Blockly.utils.colour.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00"};Blockly.FieldColour=function(a,b){a=this.doClassValidation_(a);null===a&&(a=Blockly.FieldColour.COLOURS[0]);Blockly.FieldColour.superClass_.constructor.call(this,a,b)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.prototype.CURSOR="default"; +Blockly.FieldColour.prototype.isDirty_=!1;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null;Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white"; +Blockly.FieldColour.prototype.initView=function(){this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.createBorderRect_();this.borderRect_.style.fillOpacity=1;this.borderRect_.style.fill=this.value_};Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.doClassValidation_=function(a){return"string"!=typeof a?null:Blockly.utils.colour.parse(a)}; +Blockly.FieldColour.prototype.doValueUpdate_=function(a){this.value_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.value_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); Blockly.FieldColour.TITLES=[];Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a,b){this.colours_=a;void 0!==b&&(this.titles_=b);return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this}; -Blockly.FieldColour.prototype.showEditor_=function(){Blockly.DropDownDiv.hideWithoutAnimation();Blockly.DropDownDiv.clearContent();var a=this.createWidget_();Blockly.DropDownDiv.getContentDiv().appendChild(a);Blockly.DropDownDiv.setColour(this.DROPDOWN_BACKGROUND_COLOUR,this.DROPDOWN_BORDER_COLOUR);Blockly.DropDownDiv.showPositionedByField(this);Blockly.FieldColour.onUpWrapper_=Blockly.bindEvent_(a,"mouseup",this,this.onClick_)}; +Blockly.FieldColour.prototype.showEditor_=function(){var a=this.createWidget_();Blockly.DropDownDiv.getContentDiv().appendChild(a);Blockly.DropDownDiv.setColour(this.DROPDOWN_BACKGROUND_COLOUR,this.DROPDOWN_BORDER_COLOUR);Blockly.DropDownDiv.showPositionedByField(this);Blockly.FieldColour.onUpWrapper_=Blockly.bindEvent_(a,"mouseup",this,this.onClick_)}; Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;ge&&(d.height=e);this.sourceBlock_.RTL&&Blockly.utils.uiMenu.adjustBBoxesForRTL(b,c,d);Blockly.WidgetDiv.positionWithAnchor(b,c,d,this.sourceBlock_.RTL);a.getElement().focus()}; -Blockly.FieldDropdown.prototype.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);Blockly.utils.addClass(a.getElement(),"blocklyDropdownMenu");a.setAllowAutoFocus(!0)};Blockly.FieldDropdown.prototype.getAnchorDimensions_=function(){var a=this.getScaledBBox_();this.sourceBlock_.RTL?a.right+=Blockly.FieldDropdown.CHECKMARK_OVERHANG:a.left-=Blockly.FieldDropdown.CHECKMARK_OVERHANG;return a}; -Blockly.FieldDropdown.prototype.onItemSelected=function(a,b){a=b.getValue();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; +Blockly.FieldDropdown.prototype.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);Blockly.utils.addClass(a.getElement(),"blocklyDropdownMenu");a.setAllowAutoFocus(!0)};Blockly.FieldDropdown.prototype.getAnchorDimensions_=function(){var a=this.getScaledBBox_();this.sourceBlock_.RTL?a.right+=Blockly.FieldDropdown.CHECKMARK_OVERHANG:a.left-=Blockly.FieldDropdown.CHECKMARK_OVERHANG;return a};Blockly.FieldDropdown.prototype.onItemSelected=function(a,b){this.setValue(b.getValue())}; Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(Array.isArray(a)){for(var b=!1,c=0;ca.length)){b=[];for(c=0;c=this.height_||0>=this.width_)throw Error("Height and width values of an image field must be greater than 0.");this.size_=new goog.math.Size(this.width_,this.height_+2*Blockly.BlockSvg.INLINE_PADDING_Y);this.flipRtl_=f;this.text_=d||"";this.setValue(a||"");"function"==typeof e&&(this.clickHandler_= +e)};goog.inherits(Blockly.FieldImage,Blockly.Field);Blockly.FieldImage.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.src),c=Number(Blockly.utils.replaceMessageReferences(a.width)),d=Number(Blockly.utils.replaceMessageReferences(a.height)),e=Blockly.utils.replaceMessageReferences(a.alt);return new Blockly.FieldImage(b,c,d,e,null,!!a.flipRtl)};Blockly.FieldImage.prototype.EDITABLE=!1;Blockly.FieldImage.prototype.isDirty_=!1; +Blockly.FieldImage.prototype.initView=function(){this.imageElement_=Blockly.utils.createSvgElement("image",{height:this.height_+"px",width:this.width_+"px",alt:this.text_},this.fieldGroup_);this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_)};Blockly.FieldImage.prototype.dispose=function(){this.fieldGroup_&&(Blockly.utils.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.imageElement_=null}; +Blockly.FieldImage.prototype.doClassValidation_=function(a){return"string"!=typeof a?null:a};Blockly.FieldImage.prototype.doValueUpdate_=function(a){this.value_=a;this.imageElement_&&this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_||"")};Blockly.FieldImage.prototype.getFlipRtl=function(){return this.flipRtl_};Blockly.FieldImage.prototype.setText=function(a){null!==a&&(this.text_=a,this.imageElement_&&this.imageElement_.setAttribute("alt",a||""))}; +Blockly.FieldImage.prototype.showEditor_=function(){this.clickHandler_&&this.clickHandler_(this)};Blockly.Field.register("field_image",Blockly.FieldImage);Blockly.FieldNumber=function(a,b,c,d,e){this.setConstraints(b,c,d);a=this.doClassValidation_(a);null===a&&(a=0);Blockly.FieldNumber.superClass_.constructor.call(this,a,e)};goog.inherits(Blockly.FieldNumber,Blockly.FieldTextInput);Blockly.FieldNumber.fromJson=function(a){return new Blockly.FieldNumber(a.value,a.min,a.max,a.precision)};Blockly.FieldNumber.prototype.SERIALIZABLE=!0; +Blockly.FieldNumber.prototype.setConstraints=function(a,b,c){c=parseFloat(c);this.precision_=isNaN(c)?0:c;c=this.precision_.toString();var d=c.indexOf(".");this.fractionalDigits_=-1==d?-1:c.length-(d+1);a=parseFloat(a);this.min_=isNaN(a)?-Infinity:a;b=parseFloat(b);this.max_=isNaN(b)?Infinity:b;this.setValue(this.getValue())}; +Blockly.FieldNumber.prototype.doClassValidation_=function(a){if(null===a||void 0===a)return null;a=String(a);a=a.replace(/O/ig,"0");a=a.replace(/,/g,"");a=parseFloat(a||0);if(isNaN(a))return null;a=Math.min(Math.max(a,this.min_),this.max_);this.precision_&&isFinite(a)&&(a=Math.round(a/this.precision_)*this.precision_);return a=-1==this.fractionalDigits_?a:Number(a.toFixed(this.fractionalDigits_))};Blockly.Field.register("field_number",Blockly.FieldNumber);Blockly.FieldVariable=function(a,b,c,d){this.menuGenerator_=Blockly.FieldVariable.dropdownCreate;this.size_=new goog.math.Size(0,Blockly.BlockSvg.MIN_BLOCK_Y);this.setValidator(b);this.defaultVariableName=a||"";this.setTypes_(c,d);this.value_=null};goog.inherits(Blockly.FieldVariable,Blockly.FieldDropdown);Blockly.FieldVariable.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.variable);return new Blockly.FieldVariable(b,null,a.variableTypes,a.defaultType)}; +Blockly.FieldVariable.prototype.workspace_=null;Blockly.FieldVariable.prototype.SERIALIZABLE=!0;Blockly.FieldVariable.prototype.initModel=function(){if(!this.variable_){var a=Blockly.Variables.getOrCreateVariablePackage(this.workspace_,null,this.defaultVariableName,this.defaultType_);Blockly.Events.disable();this.setValue(a.getId());Blockly.Events.enable()}}; +Blockly.FieldVariable.prototype.fromXml=function(a){var b=a.getAttribute("id"),c=a.textContent,d=a.getAttribute("variabletype")||"";b=Blockly.Variables.getOrCreateVariablePackage(this.workspace_,b,c,d);if(null!=d&&d!==b.type)throw Error("Serialized variable type with id '"+b.getId()+"' had type "+b.type+", and does not match variable field that references it: "+Blockly.Xml.domToText(a)+".");this.setValue(b.getId())}; +Blockly.FieldVariable.prototype.toXml=function(a){this.initModel();a.setAttribute("id",this.variable_.getId());a.textContent=this.variable_.name;a.setAttribute("variableType",this.variable_.type);return a};Blockly.FieldVariable.prototype.dispose=function(){Blockly.FieldVariable.superClass_.dispose.call(this);this.variableMap_=this.workspace_=null}; +Blockly.FieldVariable.prototype.setSourceBlock=function(a){if(a.isShadow())throw Error("Variable fields are not allowed to exist on shadow blocks.");Blockly.FieldVariable.superClass_.setSourceBlock.call(this,a);this.workspace_=a.workspace};Blockly.FieldVariable.prototype.getValue=function(){return this.variable_?this.variable_.getId():null};Blockly.FieldVariable.prototype.getText=function(){return this.variable_?this.variable_.name:""};Blockly.FieldVariable.prototype.getVariable=function(){return this.variable_}; +Blockly.FieldVariable.prototype.getValidator=function(){return this.variable_?this.validator_:null};Blockly.FieldVariable.prototype.doClassValidation_=function(a){var b=Blockly.Variables.getVariable(this.workspace_,a);if(!b)return console.warn("Variable id doesn't point to a real variable! ID was "+a),null;b=b.type;return this.typeIsAllowed_(b)?a:(console.warn("Variable type doesn't match this field! Type was "+b),null)}; +Blockly.FieldVariable.prototype.doValueUpdate_=function(a){this.variable_=Blockly.Variables.getVariable(this.workspace_,a);this.value_=a;this.text_=this.variable_.name;this.isDirty_=!0};Blockly.FieldVariable.prototype.typeIsAllowed_=function(a){var b=this.getVariableTypes_();if(!b)return!0;for(var c=0;cb.viewBottom||b.contentLeftb.viewRight){c=null;a&&(c=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));switch(a.type){case Blockly.Events.BLOCK_CREATE:case Blockly.Events.BLOCK_MOVE:var f=e.getBlockById(a.blockId);break;case Blockly.Events.COMMENT_CREATE:case Blockly.Events.COMMENT_MOVE:f=e.getCommentById(a.commentId)}if(f){d=f.getBoundingRectangle();var n=b.viewTop-d.topLeft.y;0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; +c.contentHeight)/d);if(b.contentTopb.viewBottom||b.contentLeftb.viewRight){c=null;a&&(c=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));switch(a.type){case Blockly.Events.BLOCK_CREATE:case Blockly.Events.BLOCK_MOVE:var f=e.getBlockById(a.blockId);f=f.getRootBlock();break;case Blockly.Events.COMMENT_CREATE:case Blockly.Events.COMMENT_MOVE:f=e.getCommentById(a.commentId)}if(f){d=f.getBoundingRectangle();var n=b.viewTop-d.topLeft.y; +0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, "orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[];a=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,a,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,a,!0))}; -Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; +Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; Blockly.onKeyDown_=function(a){var b=Blockly.mainWorkspace;if(!(b.options.readOnly||Blockly.utils.isTargetInput(a)||b.rendered&&!b.isVisible())){var c=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode){a.preventDefault();if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&(c=!0)}else if(a.altKey||a.ctrlKey||a.metaKey){if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&& (67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),Blockly.clipboardTypeCounts_&&b.isCapacityAvailable(Blockly.clipboardTypeCounts_)&&(Blockly.Events.setGroup(!0),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1))):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&& @@ -1828,9 +1813,9 @@ k,!1),f.push([a,h,k])}return f};Blockly.unbindEvent_=function(a){for(;a.length;) Blockly.checkBlockColourConstants=function(){Blockly.checkBlockColourConstant_("LOGIC_HUE",["Blocks","logic","HUE"],void 0);Blockly.checkBlockColourConstant_("LOGIC_HUE",["Constants","Logic","HUE"],210);Blockly.checkBlockColourConstant_("LOOPS_HUE",["Blocks","loops","HUE"],void 0);Blockly.checkBlockColourConstant_("LOOPS_HUE",["Constants","Loops","HUE"],120);Blockly.checkBlockColourConstant_("MATH_HUE",["Blocks","math","HUE"],void 0);Blockly.checkBlockColourConstant_("MATH_HUE",["Constants","Math", "HUE"],230);Blockly.checkBlockColourConstant_("TEXTS_HUE",["Blocks","texts","HUE"],void 0);Blockly.checkBlockColourConstant_("TEXTS_HUE",["Constants","Text","HUE"],160);Blockly.checkBlockColourConstant_("LISTS_HUE",["Blocks","lists","HUE"],void 0);Blockly.checkBlockColourConstant_("LISTS_HUE",["Constants","Lists","HUE"],260);Blockly.checkBlockColourConstant_("COLOUR_HUE",["Blocks","colour","HUE"],void 0);Blockly.checkBlockColourConstant_("COLOUR_HUE",["Constants","Colour","HUE"],20);Blockly.checkBlockColourConstant_("VARIABLES_HUE", ["Blocks","variables","HUE"],void 0);Blockly.checkBlockColourConstant_("VARIABLES_HUE",["Constants","Variables","HUE"],330);Blockly.checkBlockColourConstant_("VARIABLES_DYNAMIC_HUE",["Constants","VariablesDynamic","HUE"],310);Blockly.checkBlockColourConstant_("PROCEDURES_HUE",["Blocks","procedures","HUE"],void 0)}; -Blockly.checkBlockColourConstant_=function(a,b,c){for(var d="Blockly",e=Blockly,f=0;f>16,a>>8&255,a&255]}; -goog.color.rgbToHex=function(a,b,c){a=Number(a);b=Number(b);c=Number(c);if(a!=(a&255)||b!=(b&255)||c!=(c&255))throw Error('"('+a+","+b+","+c+'") is not a valid RGB color');b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};goog.color.rgbArrayToHex=function(a){return goog.color.rgbToHex(a[0],a[1],a[2])}; -goog.color.rgbToHsl=function(a,b,c){a/=255;b/=255;c/=255;var d=Math.max(a,b,c),e=Math.min(a,b,c),f=0,g=0,h=.5*(d+e);d!=e&&(d==a?f=60*(b-c)/(d-e):d==b?f=60*(c-a)/(d-e)+120:d==c&&(f=60*(a-b)/(d-e)+240),g=0=h?(d-e)/(2*h):(d-e)/(2-2*h));return[Math.round(f+360)%360,g,h]};goog.color.rgbArrayToHsl=function(a){return goog.color.rgbToHsl(a[0],a[1],a[2])};goog.color.hueToRgb_=function(a,b,c){0>c?c+=1:16*c?a+6*(b-a)*c:1>2*c?b:2>3*c?a+(b-a)*(2/3-c)*6:a}; -goog.color.hslToRgb=function(a,b,c){a/=360;if(0==b)c=b=a=255*c;else{var d=.5>c?c*(1+b):c+b-b*c;var e=2*c-d;c=255*goog.color.hueToRgb_(e,d,a+1/3);b=255*goog.color.hueToRgb_(e,d,a);a=255*goog.color.hueToRgb_(e,d,a-1/3)}return[Math.round(c),Math.round(b),Math.round(a)]};goog.color.hslArrayToRgb=function(a){return goog.color.hslToRgb(a[0],a[1],a[2])};goog.color.validHexColorRe_=/^#(?:[0-9a-f]{3}){1,2}$/i;goog.color.isValidHexColor_=function(a){return goog.color.validHexColorRe_.test(a)}; -goog.color.rgbColorRe_=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;goog.color.isValidRgbColor_=function(a){var b=a.match(goog.color.rgbColorRe_);if(b){a=Number(b[1]);var c=Number(b[2]);b=Number(b[3]);if(0<=a&&255>=a&&0<=c&&255>=c&&0<=b&&255>=b)return[a,c,b]}return[]};goog.color.prependZeroIfNecessaryHelper=function(a){return 1==a.length?"0"+a:a};goog.color.prependHashIfNecessaryHelper=function(a){return"#"==a.charAt(0)?a:"#"+a}; -goog.color.rgbStyle_=function(a){return"rgb("+a.join(",")+")"};goog.color.hsvToRgb=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return[Math.floor(d),Math.floor(e),Math.floor(f)]}; -goog.color.rgbToHsv=function(a,b,c){var d=Math.max(Math.max(a,b),c),e=Math.min(Math.min(a,b),c);if(e==d)e=a=0;else{var f=d-e;e=f/d;a=60*(a==d?(b-c)/f:b==d?2+(c-a)/f:4+(a-b)/f);0>a&&(a+=360);360=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2]))]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)}; -goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)};goog.color.highContrast=function(a,b){for(var c=[],d=0;d"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=Blockly.Xml.utils.textToDomDocument(a);if(!a||!a.documentElement||"xml"!=a.documentElement.nodeName.toLowerCase())throw TypeError("Blockly.Xml.textToDom expected an document.");return a.documentElement};Blockly.Xml.clearWorkspaceAndLoadFromXml=function(a,b){b.setResizesEnabled(!1);b.clear();var c=Blockly.Xml.domToWorkspace(a,b);b.setResizesEnabled(!0);return c}; Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());c=[];Blockly.Field.startCache();var e=a.childNodes.length,f=Blockly.Events.getGroup();f||Blockly.Events.setGroup(!0);b.setResizesEnabled&&b.setResizesEnabled(!1);var g=!0;try{for(var h=0;hBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,Blockly.Tooltip.showPid_= setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));Blockly.Tooltip.showPid_&&clearTimeout(Blockly.Tooltip.showPid_)};Blockly.Tooltip.block=function(){Blockly.Tooltip.hide();Blockly.Tooltip.blocked_=!0};Blockly.Tooltip.unblock=function(){Blockly.Tooltip.blocked_=!1}; @@ -1205,15 +1187,14 @@ Blockly.Gesture.prototype.doBubbleClick_=function(){this.startBubble_.setFocus&& Blockly.Gesture.prototype.doBlockClick_=function(){this.flyout_&&this.flyout_.autoClose?this.targetBlock_.isEnabled()&&(Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.flyout_.createBlock(this.targetBlock_).scheduleSnapAndBump()):Blockly.Events.fire(new Blockly.Events.Ui(this.startBlock_,"click",void 0,void 0));this.bringBlockToFront_();Blockly.Events.setGroup(!1)};Blockly.Gesture.prototype.doWorkspaceClick_=function(){Blockly.selected&&Blockly.selected.unselect()}; Blockly.Gesture.prototype.bringBlockToFront_=function(){this.targetBlock_&&!this.flyout_&&this.targetBlock_.bringToFront()};Blockly.Gesture.prototype.setStartField=function(a){if(this.hasStarted_)throw Error("Tried to call gesture.setStartField, but the gesture had already been started.");this.startField_||(this.startField_=a)};Blockly.Gesture.prototype.setStartBubble=function(a){this.startBubble_||(this.startBubble_=a)}; Blockly.Gesture.prototype.setStartBlock=function(a){this.startBlock_||this.startBubble_||(this.startBlock_=a,a.isInFlyout&&a!=a.getRootBlock()?this.setTargetBlock_(a.getRootBlock()):this.setTargetBlock_(a))};Blockly.Gesture.prototype.setTargetBlock_=function(a){a.isShadow()?this.setTargetBlock_(a.getParent()):this.targetBlock_=a};Blockly.Gesture.prototype.setStartWorkspace_=function(a){this.startWorkspace_||(this.startWorkspace_=a)}; -Blockly.Gesture.prototype.setStartFlyout_=function(a){this.flyout_||(this.flyout_=a)};Blockly.Gesture.prototype.isBubbleClick_=function(){return!!this.startBubble_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isBlockClick_=function(){return!!this.startBlock_&&!this.hasExceededDragRadius_&&!this.isFieldClick_()};Blockly.Gesture.prototype.isFieldClick_=function(){return(this.startField_?this.startField_.isCurrentlyEditable():!1)&&!this.hasExceededDragRadius_&&(!this.flyout_||!this.flyout_.autoClose)}; +Blockly.Gesture.prototype.setStartFlyout_=function(a){this.flyout_||(this.flyout_=a)};Blockly.Gesture.prototype.isBubbleClick_=function(){return!!this.startBubble_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isBlockClick_=function(){return!!this.startBlock_&&!this.hasExceededDragRadius_&&!this.isFieldClick_()};Blockly.Gesture.prototype.isFieldClick_=function(){return(this.startField_?this.startField_.isClickable():!1)&&!this.hasExceededDragRadius_&&(!this.flyout_||!this.flyout_.autoClose)}; Blockly.Gesture.prototype.isWorkspaceClick_=function(){return!this.startBlock_&&!this.startBubble_&&!this.startField_&&!this.hasExceededDragRadius_};Blockly.Gesture.prototype.isDragging=function(){return this.isDraggingWorkspace_||this.isDraggingBlock_||this.isDraggingBubble_};Blockly.Gesture.prototype.hasStarted=function(){return this.hasStarted_};Blockly.Gesture.prototype.getInsertionMarkers=function(){return this.blockDragger_?this.blockDragger_.getInsertionMarkers():[]}; Blockly.Gesture.inProgress=function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)if(c.currentGesture_)return!0;return!1};Blockly.Grid=function(a,b){this.gridPattern_=a;this.spacing_=b.spacing;this.length_=b.length;this.line2_=(this.line1_=a.firstChild)&&this.line1_.nextSibling;this.snapToGrid_=b.snap};Blockly.Grid.prototype.scale_=1;Blockly.Grid.prototype.dispose=function(){this.gridPattern_=null};Blockly.Grid.prototype.shouldSnap=function(){return this.snapToGrid_};Blockly.Grid.prototype.getSpacing=function(){return this.spacing_};Blockly.Grid.prototype.getPatternId=function(){return this.gridPattern_.id}; Blockly.Grid.prototype.update=function(a){this.scale_=a;var b=this.spacing_*a||100;this.gridPattern_.setAttribute("width",b);this.gridPattern_.setAttribute("height",b);b=Math.floor(this.spacing_/2)+.5;var c=b-this.length_/2,d=b+this.length_/2;b*=a;c*=a;d*=a;this.setLineAttributes_(this.line1_,a,c,d,b,b);this.setLineAttributes_(this.line2_,a,b,b,c,d)}; Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(Blockly.userAgent.IE||Blockly.userAgent.EDGE)&&this.update(this.scale_)}; Blockly.Grid.createDom=function(a,b,c){a=Blockly.utils.createSvgElement("pattern",{id:"blocklyGridPattern"+a,patternUnits:"userSpaceOnUse"},c);0this.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; -Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())};Blockly.Field.prototype.getValue=function(){return this.getText()}; -Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.callValidator(a);null!==b&&(a=b);b=this.getValue();b!=a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.setText(a))}};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)};Blockly.Field.prototype.setTooltip=function(a){}; -Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;this.setValue(a);this.tooltip_=""};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.initView=function(){this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-5},this.fieldGroup_);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_);this.textElement_.tooltip=this.tooltip_?this.tooltip_:this.sourceBlock_;Blockly.Tooltip.bindMouseEvents(this.textElement_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)}; -Blockly.FieldLabel.prototype.setTooltip=function(a){this.tooltip_=a;this.textElement_&&(this.textElement_.tooltip=a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; +Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())}; +Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.doClassValidation_(a);void 0!==b&&(a=b);if(null===a)this.doValueInvalid_(),this.isDirty_&&this.forceRerender();else{if(b=this.getValidator())if(b=b.call(this,a),void 0!==b&&(a=b),null===a){this.doValueInvalid_();this.isDirty_&&this.forceRerender();return}b=this.getValue();b!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.doValueUpdate_(a), +this.isDirty_&&this.forceRerender())}}};Blockly.Field.prototype.value_=null;Blockly.Field.prototype.doClassValidation_=function(a){return a=this.classValidator(a)};Blockly.Field.prototype.doValueUpdate_=function(a){this.value_=a;this.isDirty_=!0;this.text_=String(a)};Blockly.Field.prototype.doValueInvalid_=function(){};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)}; +Blockly.Field.prototype.setTooltip=function(a){a||""===a?this.getClickTarget_().tooltip=a:this.getClickTarget_().tooltip=this.sourceBlock_};Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;a=this.doClassValidation_(a);null===a&&(a="");this.setValue(a)};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; +Blockly.FieldLabel.prototype.initView=function(){this.createTextElement_();this.textElement_.setAttribute("y",this.size_.height-5);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.doClassValidation_=function(a){return null===a||void 0===a?null:String(a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; Blockly.Input.prototype.setVisible=function(a){var b=[];if(this.visible_==a)return b;for(var c=(this.visible_=a)?"block":"none",d=0,e;e=this.fieldRow[d];d++)e.setVisible(a);this.connection&&(a?b=this.connection.unhideAll():this.connection.hideAll(),d=this.connection.targetBlock())&&(d.getSvgRoot().style.display=c,a||(d.rendered=!1));return b};Blockly.Input.prototype.setCheck=function(a){if(!this.connection)throw Error("This input does not have a connection.");this.connection.setCheck(a);return this}; @@ -1458,9 +1440,9 @@ Blockly.Block.prototype.setMovable=function(a){this.movable_=a};Blockly.Block.pr Blockly.Block.prototype.setInsertionMarker=function(a){this.isInsertionMarker_=a};Blockly.Block.prototype.isEditable=function(){return this.editable_&&!(this.workspace&&this.workspace.options.readOnly)};Blockly.Block.prototype.setEditable=function(a){this.editable_=a;a=0;for(var b;b=this.inputList[a];a++)for(var c=0,d;d=b.fieldRow[c];c++)d.updateEditable()}; Blockly.Block.prototype.setConnectionsHidden=function(a){if(!a&&this.isCollapsed()){if(this.outputConnection&&this.outputConnection.setHidden(a),this.previousConnection&&this.previousConnection.setHidden(a),this.nextConnection){this.nextConnection.setHidden(a);var b=this.nextConnection.targetBlock();b&&b.setConnectionsHidden(a)}}else for(var c=this.getConnections_(!0),d=0;b=c[d];d++)b.setHidden(a),b.isSuperior()&&(b=b.targetBlock())&&b.setConnectionsHidden(a)}; Blockly.Block.prototype.getMatchingConnection=function(a,b){var c=this.getConnections_(!0),d=a.getConnections_(!0);if(c.length!=d.length)throw Error("Connection lists did not match in length.");for(var e=0;e=c)this.hue_=c,this.colour_=Blockly.hueToRgb(c);else if("string"==typeof b&&/^#[0-9a-fA-F]{6}$/.test(b))this.colour_=b,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; +Blockly.Block.prototype.getColourTertiary=function(){return this.colourTertiary_};Blockly.Block.prototype.getColourShadow=function(){var a=this.getColourSecondary();return a?a:Blockly.utils.colour.blend("white",this.getColour(),.6)}; +Blockly.Block.prototype.getColourBorder=function(){var a=this.getColourTertiary();if(a)return{colourBorder:a,colourLight:null,colourDark:null};a=this.getColour();return{colourBorder:null,colourLight:Blockly.utils.colour.blend("white",a,.3),colourDark:Blockly.utils.colour.blend("black",a,.2)}};Blockly.Block.prototype.getStyleName=function(){return this.styleName_};Blockly.Block.prototype.getHue=function(){return this.hue_}; +Blockly.Block.prototype.setColour=function(a){var b="string"==typeof a?Blockly.utils.replaceMessageReferences(a):a,c=Number(b);if(!isNaN(c)&&0<=c&&360>=c)this.hue_=c,this.colour_=Blockly.utils.colour.hueToHex(c);else if(c=Blockly.utils.colour.parse(b))this.colour_=c,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; Blockly.Block.prototype.setStyle=function(a){var b=Blockly.getTheme();if(!b)throw Error("Trying to set block style to "+a+" before theme was defined via Blockly.setTheme().");b=b.getBlockStyle(a);this.styleName_=a;if(b)this.colourSecondary_=b.colourSecondary,this.colourTertiary_=b.colourTertiary,this.hat=b.hat,this.setColour(b.colourPrimary);else throw Error("Invalid style name: "+a);}; Blockly.Block.prototype.setOnChange=function(a){if(a&&"function"!=typeof a)throw Error("onchange must be a function.");this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);if(this.onchange=a)this.onchangeWrapper_=a.bind(this),this.workspace.addChangeListener(this.onchangeWrapper_)};Blockly.Block.prototype.getField=function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(e.name===a)return e;return null}; Blockly.Block.prototype.getVars=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&a.push(e.getValue());return a};Blockly.Block.prototype.getVarModels=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&(e=this.workspace.getVariableById(e.getValue()))&&a.push(e);return a}; @@ -1589,7 +1571,7 @@ Blockly.DropDownDiv=function(){};Blockly.DropDownDiv.DIV_=null;Blockly.DropDownD Blockly.DropDownDiv.createDom=function(){if(!Blockly.DropDownDiv.DIV_){var a=document.createElement("div");a.className="blocklyDropDownDiv";document.body.appendChild(a);Blockly.DropDownDiv.DIV_=a;var b=document.createElement("div");b.className="blocklyDropDownContent";a.appendChild(b);Blockly.DropDownDiv.content_=b;b=document.createElement("div");b.className="blocklyDropDownArrow";a.appendChild(b);Blockly.DropDownDiv.arrow_=b;Blockly.DropDownDiv.DIV_.style.transition="transform "+Blockly.DropDownDiv.ANIMATION_TIME+ "s, opacity "+Blockly.DropDownDiv.ANIMATION_TIME+"s"}};Blockly.DropDownDiv.setBoundsElement=function(a){Blockly.DropDownDiv.boundsElement_=a};Blockly.DropDownDiv.getContentDiv=function(){return Blockly.DropDownDiv.content_};Blockly.DropDownDiv.clearContent=function(){Blockly.DropDownDiv.content_.innerHTML="";Blockly.DropDownDiv.content_.style.width=""};Blockly.DropDownDiv.setColour=function(a,b){Blockly.DropDownDiv.DIV_.style.backgroundColor=a;Blockly.DropDownDiv.DIV_.style.borderColor=b}; Blockly.DropDownDiv.setCategory=function(a){Blockly.DropDownDiv.DIV_.setAttribute("data-category",a)};Blockly.DropDownDiv.showPositionedByBlock=function(a,b,c,d){var e=b.workspace.scale,f=b.width,g=b.height;f*=e;g*=e;e=b.getSvgRoot().getBoundingClientRect();f=e.left+f/2;g=e.top+g;e=e.top;d&&(e+=d);Blockly.DropDownDiv.setBoundsElement(b.workspace.getParentSvg().parentNode);return Blockly.DropDownDiv.show(a,f,g,f,e,c)}; -Blockly.DropDownDiv.showPositionedByField=function(a,b,c){var d=a.fieldGroup_.getBoundingClientRect(),e=d.left+d.width/2,f=d.bottom;d=d.top;c&&(d+=c);Blockly.DropDownDiv.positionToField_=!0;Blockly.DropDownDiv.setBoundsElement(a.sourceBlock_.workspace.getParentSvg().parentNode);return Blockly.DropDownDiv.show(a,e,f,e,d,b)}; +Blockly.DropDownDiv.showPositionedByField=function(a,b,c){var d=a.fieldGroup_.getBoundingClientRect(),e=d.left+d.width/2,f=d.bottom;d=d.top;c&&(d+=c);Blockly.DropDownDiv.positionToField_=!0;Blockly.DropDownDiv.setBoundsElement(a.getSourceBlock().workspace.getParentSvg().parentNode);return Blockly.DropDownDiv.show(a,e,f,e,d,b)}; Blockly.DropDownDiv.show=function(a,b,c,d,e,f){Blockly.DropDownDiv.owner_=a;Blockly.DropDownDiv.onHide_=f;a=Blockly.DropDownDiv.getPositionMetrics(b,c,d,e);Blockly.DropDownDiv.arrow_.style.transform="translate("+a.arrowX+"px,"+a.arrowY+"px) rotate(45deg)";Blockly.DropDownDiv.arrow_.setAttribute("class",a.arrowAtTop?"blocklyDropDownArrow arrowTop":"blocklyDropDownArrow arrowBottom");Blockly.DropDownDiv.arrow_.style.display=a.arrowVisible?"":"none";Blockly.DropDownDiv.positionInternal_(a.initialX,a.initialY, a.finalX,a.finalY);return a.arrowAtTop};Blockly.DropDownDiv.getBoundsInfo_=function(){var a=Blockly.DropDownDiv.boundsElement_.getBoundingClientRect(),b=goog.style.getSize(Blockly.DropDownDiv.boundsElement_);return{left:a.left,right:a.left+b.width,top:a.top,bottom:a.top+b.height,width:b.width,height:b.height}}; Blockly.DropDownDiv.getPositionMetrics=function(a,b,c,d){var e=Blockly.DropDownDiv.getBoundsInfo_(),f=goog.style.getSize(Blockly.DropDownDiv.DIV_);if(b+f.height>e.bottom)if(d-f.heightc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+ -Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a, -"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; -Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;a=a.clientY-b.top-Blockly.FieldAngle.HALF;b=Math.atan(-a/c);isNaN(b)||(b=Blockly.utils.toDegrees(b),0>c?b+=180:0c;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+ +Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove", +this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; +Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& +(a-=360),c=String(a),c!=this.text_&&(Blockly.FieldTextInput.htmlInput_.value=a,this.setValue(a),this.text_=c,this.forceRerender()))}; +Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; d-=Math.sin(b)*Blockly.FieldAngle.RADIUS;b=Math.abs(Math.floor((b-e)/Math.PI)%2);Blockly.FieldAngle.CLOCKWISE&&(b=1-b);a.push(" l ",f,",",g," A ",Blockly.FieldAngle.RADIUS,",",Blockly.FieldAngle.RADIUS," 0 ",b," ",Number(Blockly.FieldAngle.CLOCKWISE)," ",c,",",d," z")}this.gauge_.setAttribute("d",a.join(""));this.line_.setAttribute("x2",c);this.line_.setAttribute("y2",d)}}; -Blockly.FieldAngle.prototype.classValidator=function(a){if(null===a)return null;a=parseFloat(a||0);if(isNaN(a))return null;a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return String(a)};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked?"TRUE":"FALSE")};Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; -Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.checkElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_);var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.checkElement_.appendChild(a);this.checkElement_.style.display=this.state_?"block":"none"};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; -Blockly.FieldCheckbox.prototype.setValue=function(a){a="string"==typeof a?"TRUE"==a.toUpperCase():!!a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(String(a).toUpperCase())}; -Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null; -Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white";Blockly.FieldColour.prototype.initView=function(){Blockly.FieldColour.superClass_.initView.call(this);this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.borderRect_.style.fillOpacity=1;this.borderRect_.setAttribute("width",this.size_.width+Blockly.BlockSvg.SEP_SPACE_X);this.setValue(this.getValue())}; -Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.updateWidth=function(){};Blockly.FieldColour.prototype.getValue=function(){return this.colour_}; -Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); +Blockly.FieldAngle.prototype.doClassValidation_=function(a){if(isNaN(a))return null;a=parseFloat(a||0);a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return a};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){a=this.doClassValidation_(a);null===a&&(a="FALSE");Blockly.FieldCheckbox.superClass_.constructor.call(this,a,b);this.size_.width=Blockly.FieldCheckbox.WIDTH};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked)};Blockly.FieldCheckbox.WIDTH=5;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.CHECK_X_OFFSET=-3;Blockly.FieldCheckbox.CHECK_Y_OFFSET=14; +Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.prototype.CURSOR="default";Blockly.FieldCheckbox.prototype.isDirty_=!1; +Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.textElement_.setAttribute("x",Blockly.FieldCheckbox.CHECK_X_OFFSET);this.textElement_.setAttribute("y",Blockly.FieldCheckbox.CHECK_Y_OFFSET);Blockly.utils.addClass(this.textElement_,"blocklyCheckbox");var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.textElement_.appendChild(a);this.textElement_.style.display=this.value_?"block":"none"}; +Blockly.FieldCheckbox.prototype.showEditor_=function(){this.setValue(!this.value_)};Blockly.FieldCheckbox.prototype.doClassValidation_=function(a){return!0===a||"TRUE"===a?"TRUE":!1===a||"FALSE"===a?"FALSE":null};Blockly.FieldCheckbox.prototype.doValueUpdate_=function(a){this.value_=this.convertValueToBool_(a);this.textElement_&&(this.textElement_.style.display=this.value_?"block":"none")};Blockly.FieldCheckbox.prototype.getValue=function(){return this.value_?"TRUE":"FALSE"}; +Blockly.FieldCheckbox.prototype.getValueBoolean=function(){return this.value_};Blockly.FieldCheckbox.prototype.getText=function(){return String(this.convertValueToBool_(this.value_))};Blockly.FieldCheckbox.prototype.convertValueToBool_=function(a){return"string"==typeof a?"TRUE"==a:!!a};Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.utils.colour={};Blockly.utils.colour.parse=function(a){a=String(a).toLowerCase().trim();var b=Blockly.utils.colour.names[a];if(b)return b;b="#"==a[0]?a:"#"+a;if(/^#[0-9a-f]{6}$/.test(b))return b;if(/^#[0-9a-f]{3}$/.test(b))return["#",b[1],b[1],b[2],b[2],b[3],b[3]].join("");var c=a.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);return c&&(a=Number(c[1]),b=Number(c[2]),c=Number(c[3]),0<=a&&256>a&&0<=b&&256>b&&0<=c&&256>c)?Blockly.utils.colour.rgbToHex(a,b,c):null}; +Blockly.utils.colour.rgbToHex=function(a,b,c){b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};Blockly.utils.colour.hexToRgb=function(a){a=parseInt(a.substr(1),16);return[a>>16,a>>8&255,a&255]};Blockly.utils.colour.hueToHex=function(a){return Blockly.utils.colour.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)}; +Blockly.utils.colour.hsvToHex=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return Blockly.utils.colour.rgbToHex(Math.floor(d),Math.floor(e),Math.floor(f))}; +Blockly.utils.colour.blend=function(a,b,c){a=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(a));b=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(b));return Blockly.utils.colour.rgbToHex(Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2])))}; +Blockly.utils.colour.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00"};Blockly.FieldColour=function(a,b){a=this.doClassValidation_(a);null===a&&(a=Blockly.FieldColour.COLOURS[0]);Blockly.FieldColour.superClass_.constructor.call(this,a,b)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.prototype.CURSOR="default"; +Blockly.FieldColour.prototype.isDirty_=!1;Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.titles_=null;Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.DROPDOWN_BORDER_COLOUR="silver";Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR="white"; +Blockly.FieldColour.prototype.initView=function(){this.size_=new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,Blockly.FieldColour.DEFAULT_HEIGHT);this.createBorderRect_();this.borderRect_.style.fillOpacity=1;this.borderRect_.style.fill=this.value_};Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.doClassValidation_=function(a){return"string"!=typeof a?null:Blockly.utils.colour.parse(a)}; +Blockly.FieldColour.prototype.doValueUpdate_=function(a){this.value_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.value_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS="#ffffff #cccccc #c0c0c0 #999999 #666666 #333333 #000000 #ffcccc #ff6666 #ff0000 #cc0000 #990000 #660000 #330000 #ffcc99 #ff9966 #ff9900 #ff6600 #cc6600 #993300 #663300 #ffff99 #ffff66 #ffcc66 #ffcc33 #cc9933 #996633 #663333 #ffffcc #ffff33 #ffff00 #ffcc00 #999900 #666600 #333300 #99ff99 #66ff99 #33ff33 #33cc00 #009900 #006600 #003300 #99ffff #33ffff #66cccc #00cccc #339999 #336666 #003333 #ccffff #66ffff #33ccff #3366ff #3333ff #000099 #000066 #ccccff #9999ff #6666cc #6633ff #6600cc #333399 #330099 #ffccff #ff99ff #cc66cc #cc33cc #993399 #663366 #330033".split(" "); Blockly.FieldColour.TITLES=[];Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a,b){this.colours_=a;void 0!==b&&(this.titles_=b);return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this}; -Blockly.FieldColour.prototype.showEditor_=function(){Blockly.DropDownDiv.hideWithoutAnimation();Blockly.DropDownDiv.clearContent();var a=this.createWidget_();Blockly.DropDownDiv.getContentDiv().appendChild(a);Blockly.DropDownDiv.setColour(this.DROPDOWN_BACKGROUND_COLOUR,this.DROPDOWN_BORDER_COLOUR);Blockly.DropDownDiv.showPositionedByField(this);Blockly.FieldColour.onUpWrapper_=Blockly.bindEvent_(a,"mouseup",this,this.onClick_)}; +Blockly.FieldColour.prototype.showEditor_=function(){var a=this.createWidget_();Blockly.DropDownDiv.getContentDiv().appendChild(a);Blockly.DropDownDiv.setColour(this.DROPDOWN_BACKGROUND_COLOUR,this.DROPDOWN_BORDER_COLOUR);Blockly.DropDownDiv.showPositionedByField(this);Blockly.FieldColour.onUpWrapper_=Blockly.bindEvent_(a,"mouseup",this,this.onClick_)}; Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;ge&&(d.height=e);this.sourceBlock_.RTL&&Blockly.utils.uiMenu.adjustBBoxesForRTL(b,c,d);Blockly.WidgetDiv.positionWithAnchor(b,c,d,this.sourceBlock_.RTL);a.getElement().focus()}; -Blockly.FieldDropdown.prototype.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);Blockly.utils.addClass(a.getElement(),"blocklyDropdownMenu");a.setAllowAutoFocus(!0)};Blockly.FieldDropdown.prototype.getAnchorDimensions_=function(){var a=this.getScaledBBox_();this.sourceBlock_.RTL?a.right+=Blockly.FieldDropdown.CHECKMARK_OVERHANG:a.left-=Blockly.FieldDropdown.CHECKMARK_OVERHANG;return a}; -Blockly.FieldDropdown.prototype.onItemSelected=function(a,b){var c=b.getValue();this.sourceBlock_&&(c=this.callValidator(c));null!==c&&this.setValue(c)}; +Blockly.FieldDropdown.prototype.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);Blockly.utils.addClass(a.getElement(),"blocklyDropdownMenu");a.setAllowAutoFocus(!0)};Blockly.FieldDropdown.prototype.getAnchorDimensions_=function(){var a=this.getScaledBBox_();this.sourceBlock_.RTL?a.right+=Blockly.FieldDropdown.CHECKMARK_OVERHANG:a.left-=Blockly.FieldDropdown.CHECKMARK_OVERHANG;return a};Blockly.FieldDropdown.prototype.onItemSelected=function(a,b){this.setValue(b.getValue())}; Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(Array.isArray(a)){for(var b=!1,c=0;ca.length)){b=[];for(c=0;c=this.height_||0>=this.width_)throw Error("Height and width values of an image field must be greater than 0.");this.size_=new goog.math.Size(this.width_,this.height_+2*Blockly.BlockSvg.INLINE_PADDING_Y);this.flipRtl_=f;this.text_=d||"";this.setValue(a||"");"function"==typeof e&&(this.clickHandler_= +e)};goog.inherits(Blockly.FieldImage,Blockly.Field);Blockly.FieldImage.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.src),c=Number(Blockly.utils.replaceMessageReferences(a.width)),d=Number(Blockly.utils.replaceMessageReferences(a.height)),e=Blockly.utils.replaceMessageReferences(a.alt);return new Blockly.FieldImage(b,c,d,e,null,!!a.flipRtl)};Blockly.FieldImage.prototype.EDITABLE=!1;Blockly.FieldImage.prototype.isDirty_=!1; +Blockly.FieldImage.prototype.initView=function(){this.imageElement_=Blockly.utils.createSvgElement("image",{height:this.height_+"px",width:this.width_+"px",alt:this.text_},this.fieldGroup_);this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_)};Blockly.FieldImage.prototype.dispose=function(){this.fieldGroup_&&(Blockly.utils.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.imageElement_=null}; +Blockly.FieldImage.prototype.doClassValidation_=function(a){return"string"!=typeof a?null:a};Blockly.FieldImage.prototype.doValueUpdate_=function(a){this.value_=a;this.imageElement_&&this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_||"")};Blockly.FieldImage.prototype.getFlipRtl=function(){return this.flipRtl_};Blockly.FieldImage.prototype.setText=function(a){null!==a&&(this.text_=a,this.imageElement_&&this.imageElement_.setAttribute("alt",a||""))}; +Blockly.FieldImage.prototype.showEditor_=function(){this.clickHandler_&&this.clickHandler_(this)};Blockly.Field.register("field_image",Blockly.FieldImage);Blockly.FieldNumber=function(a,b,c,d,e){this.setConstraints(b,c,d);a=this.doClassValidation_(a);null===a&&(a=0);Blockly.FieldNumber.superClass_.constructor.call(this,a,e)};goog.inherits(Blockly.FieldNumber,Blockly.FieldTextInput);Blockly.FieldNumber.fromJson=function(a){return new Blockly.FieldNumber(a.value,a.min,a.max,a.precision)};Blockly.FieldNumber.prototype.SERIALIZABLE=!0; +Blockly.FieldNumber.prototype.setConstraints=function(a,b,c){c=parseFloat(c);this.precision_=isNaN(c)?0:c;c=this.precision_.toString();var d=c.indexOf(".");this.fractionalDigits_=-1==d?-1:c.length-(d+1);a=parseFloat(a);this.min_=isNaN(a)?-Infinity:a;b=parseFloat(b);this.max_=isNaN(b)?Infinity:b;this.setValue(this.getValue())}; +Blockly.FieldNumber.prototype.doClassValidation_=function(a){if(null===a||void 0===a)return null;a=String(a);a=a.replace(/O/ig,"0");a=a.replace(/,/g,"");a=parseFloat(a||0);if(isNaN(a))return null;a=Math.min(Math.max(a,this.min_),this.max_);this.precision_&&isFinite(a)&&(a=Math.round(a/this.precision_)*this.precision_);return a=-1==this.fractionalDigits_?a:Number(a.toFixed(this.fractionalDigits_))};Blockly.Field.register("field_number",Blockly.FieldNumber);Blockly.FieldVariable=function(a,b,c,d){this.menuGenerator_=Blockly.FieldVariable.dropdownCreate;this.size_=new goog.math.Size(0,Blockly.BlockSvg.MIN_BLOCK_Y);this.setValidator(b);this.defaultVariableName=a||"";this.setTypes_(c,d);this.value_=null};goog.inherits(Blockly.FieldVariable,Blockly.FieldDropdown);Blockly.FieldVariable.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.variable);return new Blockly.FieldVariable(b,null,a.variableTypes,a.defaultType)}; +Blockly.FieldVariable.prototype.workspace_=null;Blockly.FieldVariable.prototype.SERIALIZABLE=!0;Blockly.FieldVariable.prototype.initModel=function(){if(!this.variable_){var a=Blockly.Variables.getOrCreateVariablePackage(this.workspace_,null,this.defaultVariableName,this.defaultType_);Blockly.Events.disable();this.setValue(a.getId());Blockly.Events.enable()}}; +Blockly.FieldVariable.prototype.fromXml=function(a){var b=a.getAttribute("id"),c=a.textContent,d=a.getAttribute("variabletype")||"";b=Blockly.Variables.getOrCreateVariablePackage(this.workspace_,b,c,d);if(null!=d&&d!==b.type)throw Error("Serialized variable type with id '"+b.getId()+"' had type "+b.type+", and does not match variable field that references it: "+Blockly.Xml.domToText(a)+".");this.setValue(b.getId())}; +Blockly.FieldVariable.prototype.toXml=function(a){this.initModel();a.setAttribute("id",this.variable_.getId());a.textContent=this.variable_.name;a.setAttribute("variableType",this.variable_.type);return a};Blockly.FieldVariable.prototype.dispose=function(){Blockly.FieldVariable.superClass_.dispose.call(this);this.variableMap_=this.workspace_=null}; +Blockly.FieldVariable.prototype.setSourceBlock=function(a){if(a.isShadow())throw Error("Variable fields are not allowed to exist on shadow blocks.");Blockly.FieldVariable.superClass_.setSourceBlock.call(this,a);this.workspace_=a.workspace};Blockly.FieldVariable.prototype.getValue=function(){return this.variable_?this.variable_.getId():null};Blockly.FieldVariable.prototype.getText=function(){return this.variable_?this.variable_.name:""};Blockly.FieldVariable.prototype.getVariable=function(){return this.variable_}; +Blockly.FieldVariable.prototype.getValidator=function(){return this.variable_?this.validator_:null};Blockly.FieldVariable.prototype.doClassValidation_=function(a){var b=Blockly.Variables.getVariable(this.workspace_,a);if(!b)return console.warn("Variable id doesn't point to a real variable! ID was "+a),null;b=b.type;return this.typeIsAllowed_(b)?a:(console.warn("Variable type doesn't match this field! Type was "+b),null)}; +Blockly.FieldVariable.prototype.doValueUpdate_=function(a){this.variable_=Blockly.Variables.getVariable(this.workspace_,a);this.value_=a;this.text_=this.variable_.name;this.isDirty_=!0};Blockly.FieldVariable.prototype.typeIsAllowed_=function(a){var b=this.getVariableTypes_();if(!b)return!0;for(var c=0;cb.viewBottom||b.contentLeftb.viewRight){c=null;a&&(c=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));switch(a.type){case Blockly.Events.BLOCK_CREATE:case Blockly.Events.BLOCK_MOVE:var f=e.getBlockById(a.blockId);break;case Blockly.Events.COMMENT_CREATE:case Blockly.Events.COMMENT_MOVE:f=e.getCommentById(a.commentId)}if(f){d=f.getBoundingRectangle();var n=b.viewTop-d.topLeft.y;0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; +c.contentHeight)/d);if(b.contentTopb.viewBottom||b.contentLeftb.viewRight){c=null;a&&(c=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));switch(a.type){case Blockly.Events.BLOCK_CREATE:case Blockly.Events.BLOCK_MOVE:var f=e.getBlockById(a.blockId);f=f.getRootBlock();break;case Blockly.Events.COMMENT_CREATE:case Blockly.Events.COMMENT_MOVE:f=e.getCommentById(a.commentId)}if(f){d=f.getBoundingRectangle();var n=b.viewTop-d.topLeft.y; +0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, "orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[],e=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,e,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,e,!0))}; -Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; +Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; Blockly.onKeyDown_=function(a){var b=Blockly.mainWorkspace;if(!(b.options.readOnly||Blockly.utils.isTargetInput(a)||b.rendered&&!b.isVisible())){var c=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode){a.preventDefault();if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&(c=!0)}else if(a.altKey||a.ctrlKey||a.metaKey){if(Blockly.Gesture.inProgress())return;Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&& (67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),Blockly.clipboardTypeCounts_&&b.isCapacityAvailable(Blockly.clipboardTypeCounts_)&&(Blockly.Events.setGroup(!0),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1))):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&& @@ -1832,6 +1817,6 @@ k,!1),f.push([a,h,k])}return f};Blockly.unbindEvent_=function(a){for(;a.length;) Blockly.checkBlockColourConstants=function(){Blockly.checkBlockColourConstant_("LOGIC_HUE",["Blocks","logic","HUE"],void 0);Blockly.checkBlockColourConstant_("LOGIC_HUE",["Constants","Logic","HUE"],210);Blockly.checkBlockColourConstant_("LOOPS_HUE",["Blocks","loops","HUE"],void 0);Blockly.checkBlockColourConstant_("LOOPS_HUE",["Constants","Loops","HUE"],120);Blockly.checkBlockColourConstant_("MATH_HUE",["Blocks","math","HUE"],void 0);Blockly.checkBlockColourConstant_("MATH_HUE",["Constants","Math", "HUE"],230);Blockly.checkBlockColourConstant_("TEXTS_HUE",["Blocks","texts","HUE"],void 0);Blockly.checkBlockColourConstant_("TEXTS_HUE",["Constants","Text","HUE"],160);Blockly.checkBlockColourConstant_("LISTS_HUE",["Blocks","lists","HUE"],void 0);Blockly.checkBlockColourConstant_("LISTS_HUE",["Constants","Lists","HUE"],260);Blockly.checkBlockColourConstant_("COLOUR_HUE",["Blocks","colour","HUE"],void 0);Blockly.checkBlockColourConstant_("COLOUR_HUE",["Constants","Colour","HUE"],20);Blockly.checkBlockColourConstant_("VARIABLES_HUE", ["Blocks","variables","HUE"],void 0);Blockly.checkBlockColourConstant_("VARIABLES_HUE",["Constants","Variables","HUE"],330);Blockly.checkBlockColourConstant_("VARIABLES_DYNAMIC_HUE",["Constants","VariablesDynamic","HUE"],310);Blockly.checkBlockColourConstant_("PROCEDURES_HUE",["Blocks","procedures","HUE"],void 0)}; -Blockly.checkBlockColourConstant_=function(a,b,c){for(var d="Blockly",e=Blockly,f=0;f Date: Wed, 5 Jun 2019 14:48:06 -0700 Subject: [PATCH 104/233] Update colour tests Blockly now normalizes colours lowercase. --- tests/jsunit/block_test.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/jsunit/block_test.js b/tests/jsunit/block_test.js index 81e49f9478b..a450e51a6b8 100644 --- a/tests/jsunit/block_test.js +++ b/tests/jsunit/block_test.js @@ -100,7 +100,7 @@ function setUpRowBlocks() { A: blockA, B: blockB, C: blockC - } + }; } function setUpStackBlocks() { @@ -117,7 +117,7 @@ function setUpStackBlocks() { A: blockA, B: blockB, C: blockC - } + }; } @@ -219,7 +219,7 @@ function test_block_row_unplug_multi_inputs_parent() { try { var blocks = setUpRowBlocks(); // Add extra input to parent - blocks.A.appendValueInput("INPUT").setCheck(null); + blocks.A.appendValueInput('INPUT').setCheck(null); // Parent block has multiple inputs. blocks.B.unplug(true); @@ -234,7 +234,7 @@ function test_block_row_unplug_multi_inputs_middle() { try { var blocks = setUpRowBlocks(); // Add extra input to middle block - blocks.B.appendValueInput("INPUT").setCheck(null); + blocks.B.appendValueInput('INPUT').setCheck(null); // Middle block has multiple inputs. blocks.B.unplug(true); @@ -249,7 +249,7 @@ function test_block_row_unplug_multi_inputs_child() { try { var blocks = setUpRowBlocks(); // Add extra input to child block - blocks.C.appendValueInput("INPUT").setCheck(null); + blocks.C.appendValueInput('INPUT').setCheck(null); // Child block input count doesn't matter. blocks.B.unplug(true); @@ -263,10 +263,10 @@ function test_set_style() { blockTest_setUp(); var styleStub = { getBlockStyle: function() { - return{ - "colourPrimary": "#FFFFFF", - "colourSecondary":"#AABBCC", - "colourTertiary":"#DDEEFF" + return { + "colourPrimary": "#ffffff", + "colourSecondary": "#aabbcc", + "colourTertiary": "#ddeeff" } } }; @@ -274,9 +274,9 @@ function test_set_style() { var blockA = workspace.newBlock('row_block'); blockA.setStyle('styleOne'); - assertEquals(blockA.colour_, '#FFFFFF'); - assertEquals(blockA.colourSecondary_, '#AABBCC'); - assertEquals(blockA.colourTertiary_, '#DDEEFF'); + assertEquals('#ffffff', blockA.colour_); + assertEquals('#aabbcc', blockA.colourSecondary_); + assertEquals('#ddeeff', blockA.colourTertiary_); blockTest_tearDown(); } @@ -292,9 +292,9 @@ function test_set_style_throw_exception() { var blockA = workspace.newBlock('row_block'); try { blockA.setStyle('styleOne'); - }catch(error) { - assertEquals(error.message, "Invalid style name: styleOne"); - }finally { + } catch(error) { + assertEquals(error.message, 'Invalid style name: styleOne'); + } finally { blockTest_tearDown(); } } From e8d8798ecf670701be3f1fcf1d63063dd660b965 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 5 Jun 2019 17:01:32 -0700 Subject: [PATCH 105/233] Remove goog.events.BrowserFeature dependency. --- core/scrollbar.js | 4 ++-- core/toolbox.js | 3 +-- core/touch.js | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/core/scrollbar.js b/core/scrollbar.js index 116d6df67df..42892673e1f 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -27,9 +27,9 @@ goog.provide('Blockly.Scrollbar'); goog.provide('Blockly.ScrollbarPair'); +goog.require('Blockly.Touch'); goog.require('Blockly.utils'); -goog.require('goog.events.BrowserFeature'); goog.require('goog.math.Coordinate'); @@ -303,7 +303,7 @@ Blockly.Scrollbar.prototype.containerVisible_ = true; * Scrollbars should be larger on touch devices. */ Blockly.Scrollbar.scrollbarThickness = 15; -if (goog.events.BrowserFeature.TOUCH_ENABLED) { +if (Blockly.Touch.TOUCH_ENABLED) { Blockly.Scrollbar.scrollbarThickness = 25; } diff --git a/core/toolbox.js b/core/toolbox.js index 661535cb5da..dbfdad80197 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -35,7 +35,6 @@ goog.require('Blockly.utils'); goog.require('Blockly.VerticalFlyout'); goog.require('goog.events'); -goog.require('goog.events.BrowserFeature'); goog.require('goog.events.EventType'); goog.require('goog.html.SafeHtml'); goog.require('goog.math.Rect'); @@ -600,7 +599,7 @@ Blockly.Toolbox.TreeControl.prototype.enterDocument = function() { Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this); // Add touch handler. - if (goog.events.BrowserFeature.TOUCH_ENABLED) { + if (Blockly.Touch.TOUCH_ENABLED) { var el = this.getElement(); Blockly.bindEventWithChecks_(el, goog.events.EventType.TOUCHEND, this, this.handleTouchEvent_); diff --git a/core/touch.js b/core/touch.js index 9ca395b306e..052128cde9a 100644 --- a/core/touch.js +++ b/core/touch.js @@ -32,8 +32,19 @@ goog.provide('Blockly.Touch'); goog.require('Blockly.utils'); -goog.require('goog.events.BrowserFeature'); +/** + * Whether touch is enabled in the browser. + * Copied from Closure's goog.events.BrowserFeature.TOUCH_ENABLED + */ +Blockly.Touch.TOUCH_ENABLED = + ('ontouchstart' in Blockly.utils.global || + !!(Blockly.utils.global['document'] && document.documentElement && + 'ontouchstart' in document.documentElement) || + // IE10 uses non-standard touch events, so it has a different check. + !!(Blockly.utils.global['navigator'] && + (Blockly.utils.global['navigator']['maxTouchPoints'] || + Blockly.utils.global['navigator']['msMaxTouchPoints']))) /** * Which touch events are we currently paying attention to? @@ -60,7 +71,7 @@ if (Blockly.utils.global['PointerEvent']) { 'touchend': ['pointerup'], 'touchcancel': ['pointercancel'] }; -} else if (goog.events.BrowserFeature.TOUCH_ENABLED) { +} else if (Blockly.Touch.TOUCH_ENABLED) { Blockly.Touch.TOUCH_MAP = { 'mousedown': ['touchstart'], 'mousemove': ['touchmove'], From 931cc85c8380f2fb74ba9fc9e3a4f1ce3e3c477f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 5 Jun 2019 17:12:32 -0700 Subject: [PATCH 106/233] Remove last goog.dom dependency. --- core/utils.js | 18 ++++++++++++++++++ core/workspace_svg.js | 3 +-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/core/utils.js b/core/utils.js index 18ee689ddfa..a2d6da5fb71 100644 --- a/core/utils.js +++ b/core/utils.js @@ -972,6 +972,24 @@ Blockly.utils.containsNode = function(parent, descendant) { Node.DOCUMENT_POSITION_CONTAINED_BY); }; +/** + * Gets the document scroll distance as a coordinate object. + * Copied from Closure's goog.dom.getDocumentScroll. + * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. + */ +Blockly.utils.getDocumentScroll = function() { + var el = document.documentElement; + var win = window; + if (Blockly.userAgent.IE && win.pageYOffset != el.scrollTop) { + // The keyboard on IE10 touch devices shifts the page using the pageYOffset + // without modifying scrollTop. For this case, we want the body scroll + // offsets. + return new goog.math.Coordinate(el.scrollLeft, el.scrollTop); + } + return new goog.math.Coordinate( + win.pageXOffset || el.scrollLeft, win.pageYOffset || el.scrollTop); +}; + /** * Get a map of all the block's descendants mapping their type to the number of * children with that type. diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 37625df1a02..a4b28dfb5a5 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -51,7 +51,6 @@ goog.require('Blockly.WorkspaceDragSurfaceSvg'); goog.require('Blockly.Xml'); goog.require('Blockly.ZoomControls'); -goog.require('goog.dom'); goog.require('goog.math.Coordinate'); @@ -774,7 +773,7 @@ Blockly.WorkspaceSvg.prototype.resize = function() { Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = function() { /* eslint-disable indent */ - var currScroll = goog.dom.getDocumentScroll(); + var currScroll = Blockly.utils.getDocumentScroll(); if (!goog.math.Coordinate.equals(this.lastRecordedPageScroll_, currScroll)) { this.lastRecordedPageScroll_ = currScroll; this.updateScreenCalculations_(); From f2c57dea1b01f9b3b039175b32a0c0f7fc3dfb07 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 14:34:59 -0700 Subject: [PATCH 107/233] Remove goog.math.Rect dependency --- core/flyout_horizontal.js | 9 +++-- core/flyout_vertical.js | 9 +++-- core/toolbox.js | 12 +++---- core/trashcan.js | 8 ++--- core/utils_rect.js | 71 +++++++++++++++++++++++++++++++++++++++ core/workspace_svg.js | 7 ++-- 6 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 core/utils_rect.js diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index da62a8ffe4a..c5e092cb08c 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -30,8 +30,7 @@ goog.require('Blockly.Block'); goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); goog.require('Blockly.utils'); - -goog.require('goog.math.Rect'); +goog.require('Blockly.utils.Rect'); /** @@ -336,7 +335,7 @@ Blockly.HorizontalFlyout.prototype.isDragTowardWorkspace = function( /** * Return the deletion rectangle for this flyout in viewport coordinates. - * @return {goog.math.Rect} Rectangle in which to delete. + * @return {Blockly.utils.Rect} Rectangle in which to delete. */ Blockly.HorizontalFlyout.prototype.getClientRect = function() { if (!this.svgGroup_) { @@ -352,10 +351,10 @@ Blockly.HorizontalFlyout.prototype.getClientRect = function() { var height = flyoutRect.height; if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) { - return new goog.math.Rect(-BIG_NUM, y - BIG_NUM, BIG_NUM * 2, + return new Blockly.utils.Rect(-BIG_NUM, y - BIG_NUM, BIG_NUM * 2, BIG_NUM + height); } else if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_BOTTOM) { - return new goog.math.Rect(-BIG_NUM, y, BIG_NUM * 2, + return new Blockly.utils.Rect(-BIG_NUM, y, BIG_NUM * 2, BIG_NUM + height); } // TODO: Else throw error (should never happen). diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 96438050a63..f14750e3aa8 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -31,8 +31,7 @@ goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); - -goog.require('goog.math.Rect'); +goog.require('Blockly.utils.Rect'); /** @@ -314,7 +313,7 @@ Blockly.VerticalFlyout.prototype.isDragTowardWorkspace = function( /** * Return the deletion rectangle for this flyout in viewport coordinates. - * @return {goog.math.Rect} Rectangle in which to delete. + * @return {Blockly.utils.Rect} Rectangle in which to delete. */ Blockly.VerticalFlyout.prototype.getClientRect = function() { if (!this.svgGroup_) { @@ -330,7 +329,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { var width = flyoutRect.width; if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) { - return new goog.math.Rect(x - BIG_NUM, -BIG_NUM, BIG_NUM + width, + return new Blockly.utils.Rect(x - BIG_NUM, -BIG_NUM, BIG_NUM + width, BIG_NUM * 2); } else { // Right // Firefox sometimes reports the wrong value for the client rect. @@ -357,7 +356,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { x = x + this.leftEdge_ * scale; } } - return new goog.math.Rect(x, -BIG_NUM, BIG_NUM + width, BIG_NUM * 2); + return new Blockly.utils.Rect(x, -BIG_NUM, BIG_NUM + width, BIG_NUM * 2); } }; diff --git a/core/toolbox.js b/core/toolbox.js index dbfdad80197..758b184c84a 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -32,12 +32,12 @@ goog.require('Blockly.Flyout'); goog.require('Blockly.HorizontalFlyout'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Rect'); goog.require('Blockly.VerticalFlyout'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.html.SafeHtml'); -goog.require('goog.math.Rect'); goog.require('goog.ui.tree.BaseNode'); goog.require('goog.ui.tree.TreeControl'); goog.require('goog.ui.tree.TreeNode'); @@ -530,7 +530,7 @@ Blockly.Toolbox.prototype.removeStyle = function(style) { /** * Return the deletion rectangle for this toolbox. - * @return {goog.math.Rect} Rectangle in which to delete. + * @return {Blockly.utils.Rect} Rectangle in which to delete. */ Blockly.Toolbox.prototype.getClientRect = function() { if (!this.HtmlDiv) { @@ -551,15 +551,15 @@ Blockly.Toolbox.prototype.getClientRect = function() { // Assumes that the toolbox is on the SVG edge. If this changes // (e.g. toolboxes in mutators) then this code will need to be more complex. if (this.toolboxPosition == Blockly.TOOLBOX_AT_LEFT) { - return new goog.math.Rect(-BIG_NUM, -BIG_NUM, BIG_NUM + x + width, + return new Blockly.utils.Rect(-BIG_NUM, -BIG_NUM, BIG_NUM + x + width, 2 * BIG_NUM); } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT) { - return new goog.math.Rect(x, -BIG_NUM, BIG_NUM + width, 2 * BIG_NUM); + return new Blockly.utils.Rect(x, -BIG_NUM, BIG_NUM + width, 2 * BIG_NUM); } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_TOP) { - return new goog.math.Rect(-BIG_NUM, -BIG_NUM, 2 * BIG_NUM, + return new Blockly.utils.Rect(-BIG_NUM, -BIG_NUM, 2 * BIG_NUM, BIG_NUM + y + height); } else { // Bottom - return new goog.math.Rect(0, y, 2 * BIG_NUM, BIG_NUM + width); + return new Blockly.utils.Rect(0, y, 2 * BIG_NUM, BIG_NUM + width); } }; diff --git a/core/trashcan.js b/core/trashcan.js index 2eb5cc8b61c..2059ff42a49 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -27,10 +27,9 @@ goog.provide('Blockly.Trashcan'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Rect'); goog.require('Blockly.Xml'); -goog.require('goog.math.Rect'); - /** * Class for a trash can. @@ -354,7 +353,7 @@ Blockly.Trashcan.prototype.position = function() { /** * Return the deletion rectangle for this trash can. - * @return {goog.math.Rect} Rectangle in which to delete. + * @return {Blockly.utils.Rect} Rectangle in which to delete. */ Blockly.Trashcan.prototype.getClientRect = function() { if (!this.svgGroup_) { @@ -366,8 +365,7 @@ Blockly.Trashcan.prototype.getClientRect = function() { var top = trashRect.top + this.SPRITE_TOP_ - this.MARGIN_HOTSPOT_; var width = this.WIDTH_ + 2 * this.MARGIN_HOTSPOT_; var height = this.LID_HEIGHT_ + this.BODY_HEIGHT_ + 2 * this.MARGIN_HOTSPOT_; - return new goog.math.Rect(left, top, width, height); - + return new Blockly.utils.Rect(left, top, width, height); }; /** diff --git a/core/utils_rect.js b/core/utils_rect.js new file mode 100644 index 00000000000..c9cefbeec15 --- /dev/null +++ b/core/utils_rect.js @@ -0,0 +1,71 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utility methods for rectangle manipulation. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.utils.Rect + * @namespace + */ +goog.provide('Blockly.utils.Rect'); + + +/** + * Class for representing rectangular regions. + * @param {number} x Left. + * @param {number} y Top. + * @param {number} w Width. + * @param {number} h Height. + * @struct + * @constructor + * @implements {goog.math.IRect} + */ +Blockly.utils.Rect = function(x, y, w, h) { + /** @type {number} */ + this.left = x; + + /** @type {number} */ + this.top = y; + + /** @type {number} */ + this.width = w; + + /** @type {number} */ + this.height = h; +}; + +/** + * Tests whether this rectangle entirely contains another rectangle or + * coordinate. + * + * @param {number} x The x coordinate to test for containment. + * @param {number} y The y coordinate to test for containment. + * @return {boolean} Whether this rectangle contains given coordinate. + */ +Blockly.utils.Rect.prototype.contains = function(x, y) { + return x >= this.left && x <= this.left + this.width && + y >= this.top && y <= this.top + this.height; +}; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index a4b28dfb5a5..bbcae5589db 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1201,11 +1201,12 @@ Blockly.WorkspaceSvg.prototype.recordDeleteAreas = function() { * which delete area the event is over. */ Blockly.WorkspaceSvg.prototype.isDeleteArea = function(e) { - var xy = new goog.math.Coordinate(e.clientX, e.clientY); - if (this.deleteAreaTrash_ && this.deleteAreaTrash_.contains(xy)) { + if (this.deleteAreaTrash_ && + this.deleteAreaTrash_.contains(e.clientX, e.clientY)) { return Blockly.DELETE_AREA_TRASH; } - if (this.deleteAreaToolbox_ && this.deleteAreaToolbox_.contains(xy)) { + if (this.deleteAreaToolbox_ && + this.deleteAreaToolbox_.contains(e.clientX, e.clientY)) { return Blockly.DELETE_AREA_TOOLBOX; } return Blockly.DELETE_AREA_NONE; From 5bf7069a2f741e7713b15fea6598c9540df32c72 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 14:51:01 -0700 Subject: [PATCH 108/233] Remove goog.math.Coordinate --- core/block.js | 9 +- core/block_drag_surface.js | 12 +-- core/block_dragger.js | 32 +++--- core/block_events.js | 7 +- core/block_svg.js | 23 +++-- core/bubble.js | 17 ++-- core/bubble_dragger.js | 21 ++-- core/connection_db.js | 7 +- core/contextmenu.js | 13 ++- core/dragged_connection_manager.js | 4 +- core/field.js | 2 +- core/field_textinput.js | 5 +- core/flyout_base.js | 19 ++-- core/flyout_button.js | 9 +- core/flyout_horizontal.js | 2 +- core/flyout_vertical.js | 2 +- core/gesture.js | 17 ++-- core/icon.js | 13 ++- core/insertion_marker_manager.js | 6 +- core/rendered_connection.js | 11 +-- core/scrollbar.js | 15 ++- core/touch_gesture.js | 13 ++- core/utils.js | 16 +-- core/utils_coordinate.js | 139 +++++++++++++++++++++++++++ core/workspace_comment.js | 13 ++- core/workspace_comment_render_svg.js | 5 +- core/workspace_comment_svg.js | 25 +++-- core/workspace_drag_surface_svg.js | 2 +- core/workspace_dragger.js | 12 +-- core/workspace_svg.js | 25 +++-- core/ws_comment_events.js | 13 ++- 31 files changed, 314 insertions(+), 195 deletions(-) create mode 100644 core/utils_coordinate.js diff --git a/core/block.js b/core/block.js index a8da3905a50..0179e526fe0 100644 --- a/core/block.js +++ b/core/block.js @@ -29,6 +29,7 @@ goog.provide('Blockly.Block'); goog.require('Blockly.Blocks'); goog.require('Blockly.Comment'); goog.require('Blockly.Connection'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.BlockCreate'); @@ -41,8 +42,6 @@ goog.require('Blockly.utils'); goog.require('Blockly.Warning'); goog.require('Blockly.Workspace'); -goog.require('goog.math.Coordinate'); - /** * Class for one block. @@ -134,10 +133,10 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { /** * The block's position in workspace units. (0, 0) is at the workspace's * origin; scale does not change this value. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ - this.xy_ = new goog.math.Coordinate(0, 0); + this.xy_ = new Blockly.utils.Coordinate(0, 0); /** @type {!Blockly.Workspace} */ this.workspace = workspace; @@ -1846,7 +1845,7 @@ Blockly.Block.prototype.setMutator = function(_mutator) { /** * Return the coordinates of the top-left corner of this block relative to the * drawing surface's origin (0,0), in workspace units. - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. */ Blockly.Block.prototype.getRelativeToSurfaceXY = function() { return this.xy_; diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 0592e92cfc2..853b176362f 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -30,8 +30,8 @@ 'use strict'; goog.provide('Blockly.BlockDragSurfaceSvg'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); /** @@ -83,7 +83,7 @@ Blockly.BlockDragSurfaceSvg.prototype.scale_ = 1; * Cached value for the translation of the drag surface. * This translation is in pixel units, because the scale is applied to the * drag group rather than the top-level SVG. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ Blockly.BlockDragSurfaceSvg.prototype.surfaceXY_ = null; @@ -118,7 +118,7 @@ Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow = function(blocks) { // appendChild removes the blocks from the previous parent this.dragGroup_.appendChild(blocks); this.SVG_.style.display = 'block'; - this.surfaceXY_ = new goog.math.Coordinate(0, 0); + this.surfaceXY_ = new Blockly.utils.Coordinate(0, 0); }; /** @@ -165,18 +165,18 @@ Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() { * @param {number} y Y translation for the entire surface. */ Blockly.BlockDragSurfaceSvg.prototype.translateSurface = function(x, y) { - this.surfaceXY_ = new goog.math.Coordinate(x * this.scale_, y * this.scale_); + this.surfaceXY_ = new Blockly.utils.Coordinate(x * this.scale_, y * this.scale_); this.translateSurfaceInternal_(); }; /** * Reports the surface translation in scaled workspace coordinates. * Use this when finishing a drag to return blocks to the correct position. - * @return {!goog.math.Coordinate} Current translation of the surface. + * @return {!Blockly.utils.Coordinate} Current translation of the surface. */ Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation = function() { var xy = Blockly.utils.getRelativeXY(this.SVG_); - return new goog.math.Coordinate(xy.x / this.scale_, xy.y / this.scale_); + return new Blockly.utils.Coordinate(xy.x / this.scale_, xy.y / this.scale_); }; /** diff --git a/core/block_dragger.js b/core/block_dragger.js index ce07de7419a..3b0a60398b1 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -27,12 +27,11 @@ goog.provide('Blockly.BlockDragger'); goog.require('Blockly.BlockAnimations'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.InsertionMarkerManager'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockMove'); -goog.require('goog.math.Coordinate'); - /** * Class for a block dragger. It moves blocks around the workspace when they @@ -83,7 +82,7 @@ Blockly.BlockDragger = function(block, workspace) { /** * The location of the top left corner of the dragging block at the beginning * of the drag in workspace coordinates. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY(); @@ -130,7 +129,7 @@ Blockly.BlockDragger.initIconData_ = function(block) { var icons = descendant.getIcons(); for (var j = 0; j < icons.length; j++) { var data = { - // goog.math.Coordinate with x and y properties (workspace coordinates). + // Blockly.utils.Coordinate with x and y properties (workspace coordinates). location: icons[j].getIconLocation(), // Blockly.Icon icon: icons[j] @@ -143,7 +142,7 @@ Blockly.BlockDragger.initIconData_ = function(block) { /** * Start dragging a block. This includes moving it to the drag surface. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at mouse down, in pixel units. * @param {boolean} healStack Whether or not to heal the stack after * disconnecting. @@ -174,7 +173,7 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, this.draggingBlock_.nextConnection.targetBlock())) { this.draggingBlock_.unplug(healStack); var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = goog.math.Coordinate.sum(this.startXY_, delta); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); this.draggingBlock_.translate(newLoc.x, newLoc.y); Blockly.BlockAnimations.disconnectUiEffect(this.draggingBlock_); @@ -197,13 +196,13 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, * Execute a step of block dragging, based on the given event. Update the * display accordingly. * @param {!Event} e The most recent move event. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. * @package */ Blockly.BlockDragger.prototype.dragBlock = function(e, currentDragDeltaXY) { var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = goog.math.Coordinate.sum(this.startXY_, delta); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); this.draggingBlock_.moveDuringDrag(newLoc); this.dragIcons_(delta); @@ -217,7 +216,7 @@ Blockly.BlockDragger.prototype.dragBlock = function(e, currentDragDeltaXY) { /** * Finish a block drag and put the block back on the workspace. * @param {!Event} e The mouseup/touchend event. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. * @package */ @@ -231,7 +230,7 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { Blockly.BlockAnimations.disconnectUiStop(); var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = goog.math.Coordinate.sum(this.startXY_, delta); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); this.draggingBlock_.moveOffDragSurface_(newLoc); var deleted = this.maybeDeleteBlock_(); @@ -319,14 +318,15 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() { * correction for mutator workspaces. * This function does not consider differing origins. It simply scales the * input's x and y values. - * @param {!goog.math.Coordinate} pixelCoord A coordinate with x and y values + * @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y values * in css pixel units. - * @return {!goog.math.Coordinate} The input coordinate divided by the workspace + * @return {!Blockly.utils.Coordinate} The input coordinate divided by the workspace * scale. * @private */ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { - var result = new goog.math.Coordinate(pixelCoord.x / this.workspace_.scale, + var result = new Blockly.utils.Coordinate( + pixelCoord.x / this.workspace_.scale, pixelCoord.y / this.workspace_.scale); if (this.workspace_.isMutator) { // If we're in a mutator, its scale is always 1, purely because of some @@ -334,14 +334,14 @@ Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { // the scale on the parent workspace. // Fix that for dragging. var mainScale = this.workspace_.options.parentWorkspace.scale; - result = result.scale(1 / mainScale); + result.scale(1 / mainScale); } return result; }; /** * Move all of the icons connected to this drag. - * @param {!goog.math.Coordinate} dxy How far to move the icons from their + * @param {!Blockly.utils.Coordinate} dxy How far to move the icons from their * original positions, in workspace units. * @private */ @@ -349,7 +349,7 @@ Blockly.BlockDragger.prototype.dragIcons_ = function(dxy) { // Moving icons moves their associated bubbles. for (var i = 0; i < this.dragIconData_.length; i++) { var data = this.dragIconData_[i]; - data.icon.setIconLocation(goog.math.Coordinate.sum(data.location, dxy)); + data.icon.setIconLocation(Blockly.utils.Coordinate.sum(data.location, dxy)); } }; diff --git a/core/block_events.js b/core/block_events.js index 137798eccb7..4d4283d0682 100644 --- a/core/block_events.js +++ b/core/block_events.js @@ -34,12 +34,11 @@ goog.provide('Blockly.Events.Create'); // Deprecated. goog.provide('Blockly.Events.Delete'); // Deprecated. goog.provide('Blockly.Events.Move'); // Deprecated. +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Abstract'); goog.require('Blockly.Xml.utils'); -goog.require('goog.math.Coordinate'); - /** * Abstract class for a block event. @@ -431,7 +430,7 @@ Blockly.Events.Move.prototype.fromJson = function(json) { if (json['newCoordinate']) { var xy = json['newCoordinate'].split(','); this.newCoordinate = - new goog.math.Coordinate(parseFloat(xy[0]), parseFloat(xy[1])); + new Blockly.utils.Coordinate(parseFloat(xy[0]), parseFloat(xy[1])); } }; @@ -475,7 +474,7 @@ Blockly.Events.Move.prototype.currentLocation_ = function() { Blockly.Events.Move.prototype.isNull = function() { return this.oldParentId == this.newParentId && this.oldInputName == this.newInputName && - goog.math.Coordinate.equals(this.oldCoordinate, this.newCoordinate); + Blockly.utils.Coordinate.equals(this.oldCoordinate, this.newCoordinate); }; /** diff --git a/core/block_svg.js b/core/block_svg.js index 8b69d751e99..529e67dacad 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -29,6 +29,7 @@ goog.provide('Blockly.BlockSvg'); goog.require('Blockly.Block'); goog.require('Blockly.BlockAnimations'); goog.require('Blockly.ContextMenu'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Events.BlockMove'); @@ -39,8 +40,6 @@ goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /** * Class for a block's SVG representation. @@ -121,7 +120,7 @@ Blockly.BlockSvg.prototype.width = 0; /** * Original location of block being dragged. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ Blockly.BlockSvg.prototype.dragStartXY_ = null; @@ -301,7 +300,7 @@ Blockly.BlockSvg.prototype.setParent = function(newParent) { * If the block is on the workspace, (0, 0) is the origin of the workspace * coordinate system. * This does not change with workspace scale. - * @return {!goog.math.Coordinate} Object with .x and .y properties in + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties in * workspace coordinates. */ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { @@ -331,7 +330,7 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { } while (element && element != this.workspace.getCanvas() && element != dragSurfaceGroup); } - return new goog.math.Coordinate(x, y); + return new Blockly.utils.Coordinate(x, y); }; /** @@ -393,7 +392,7 @@ Blockly.BlockSvg.prototype.moveToDragSurface_ = function() { * Move this block back to the workspace block canvas. * Generally should be called at the same time as setDragging_(false). * Does nothing if useDragSurface_ is false. - * @param {!goog.math.Coordinate} newXY The position the block should take on + * @param {!Blockly.utils.Coordinate} newXY The position the block should take on * on the workspace canvas, in workspace coordinates. * @private */ @@ -410,7 +409,7 @@ Blockly.BlockSvg.prototype.moveOffDragSurface_ = function(newXY) { * Move this block during a drag, taking into account whether we are using a * drag surface to translate blocks. * This block must be a top-level block. - * @param {!goog.math.Coordinate} newLoc The location to translate to, in + * @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in * workspace coordinates. * @package */ @@ -469,7 +468,7 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { * Returns the coordinates of a bounding box describing the dimensions of this * block and any blocks stacked below it. * Coordinate system: workspace coordinates. - * @return {!{topLeft: goog.math.Coordinate, bottomRight: goog.math.Coordinate}} + * @return {!{topLeft: Blockly.utils.Coordinate, bottomRight: Blockly.utils.Coordinate}} * Object with top left and bottom right coordinates of the bounding box. */ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { @@ -480,18 +479,18 @@ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { var bottomRight; if (this.RTL) { // Width has the tab built into it already so subtract it here. - topLeft = new goog.math.Coordinate(blockXY.x - (blockBounds.width - tab), + topLeft = new Blockly.utils.Coordinate(blockXY.x - (blockBounds.width - tab), blockXY.y); // Add the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - bottomRight = new goog.math.Coordinate(blockXY.x + tab, + bottomRight = new Blockly.utils.Coordinate(blockXY.x + tab, blockXY.y + blockBounds.height); } else { // Subtract the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - topLeft = new goog.math.Coordinate(blockXY.x - tab, blockXY.y); + topLeft = new Blockly.utils.Coordinate(blockXY.x - tab, blockXY.y); // Width has the tab built into it already so subtract it here. - bottomRight = new goog.math.Coordinate(blockXY.x + blockBounds.width - tab, + bottomRight = new Blockly.utils.Coordinate(blockXY.x + blockBounds.width - tab, blockXY.y + blockBounds.height); } return {topLeft: topLeft, bottomRight: bottomRight}; diff --git a/core/bubble.js b/core/bubble.js index 3d3ace56c53..28c1f59f601 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -26,13 +26,12 @@ goog.provide('Blockly.Bubble'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.Workspace'); -goog.require('goog.math.Coordinate'); - /** * Class for UI bubble. @@ -40,7 +39,7 @@ goog.require('goog.math.Coordinate'); * bubble. * @param {!Element} content SVG content for the bubble. * @param {Element} shape SVG element to avoid eclipsing. - * @param {!goog.math.Coordinate} anchorXY Absolute position of bubble's anchor + * @param {!Blockly.utils.Coordinate} anchorXY Absolute position of bubble's anchor * point. * @param {?number} bubbleWidth Width of bubble, or null if not resizable. * @param {?number} bubbleHeight Height of bubble, or null if not resizable. @@ -163,7 +162,7 @@ Blockly.Bubble.prototype.rendered_ = false; /** * Absolute coordinate of anchor point, in workspace coordinates. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ Blockly.Bubble.prototype.anchorXY_ = null; @@ -336,7 +335,7 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { return; } // Left-click (or middle click) - this.workspace_.startDrag(e, new goog.math.Coordinate( + this.workspace_.startDrag(e, new Blockly.utils.Coordinate( this.workspace_.RTL ? -this.width_ : this.width_, this.height_)); Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(document, @@ -388,7 +387,7 @@ Blockly.Bubble.prototype.promote_ = function() { /** * Notification that the anchor has moved. * Update the arrow and bubble accordingly. - * @param {!goog.math.Coordinate} xy Absolute location. + * @param {!Blockly.utils.Coordinate} xy Absolute location. */ Blockly.Bubble.prototype.setAnchorLocation = function(xy) { this.anchorXY_ = xy; @@ -774,7 +773,7 @@ Blockly.Bubble.prototype.dispose = function() { * a drag surface. * @param {Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries * rendered items during a drag, or null if no drag surface is in use. - * @param {!goog.math.Coordinate} newLoc The location to translate to, in + * @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in * workspace coordinates. * @package */ @@ -796,10 +795,10 @@ Blockly.Bubble.prototype.moveDuringDrag = function(dragSurface, newLoc) { /** * Return the coordinates of the top-left corner of this bubble's body relative * to the drawing surface's origin (0,0), in workspace units. - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. */ Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() { - return new goog.math.Coordinate( + return new Blockly.utils.Coordinate( this.anchorXY_.x + this.relativeLeft_, this.anchorXY_.y + this.relativeTop_); }; diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index 701f48f2013..42dfc9bd099 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -27,13 +27,12 @@ goog.provide('Blockly.BubbleDragger'); goog.require('Blockly.Bubble'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceCommentSvg'); -goog.require('goog.math.Coordinate'); - /** * Class for a bubble dragger. It moves things on the bubble canvas around the @@ -78,7 +77,7 @@ Blockly.BubbleDragger = function(bubble, workspace) { /** * The location of the top left corner of the dragging bubble's body at the * beginning of the drag, in workspace coordinates. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ this.startXY_ = this.draggingBubble_.getRelativeToSurfaceXY(); @@ -133,13 +132,13 @@ Blockly.BubbleDragger.prototype.startBubbleDrag = function() { * Execute a step of bubble dragging, based on the given event. Update the * display accordingly. * @param {!Event} e The most recent move event. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. * @package */ Blockly.BubbleDragger.prototype.dragBubble = function(e, currentDragDeltaXY) { var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = goog.math.Coordinate.sum(this.startXY_, delta); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); this.draggingBubble_.moveDuringDrag(this.dragSurface_, newLoc); @@ -196,7 +195,7 @@ Blockly.BubbleDragger.prototype.updateCursorDuringBubbleDrag_ = function() { /** * Finish a bubble drag and put the bubble back on the workspace. * @param {!Event} e The mouseup/touchend event. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel units. * @package */ @@ -206,7 +205,7 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function( this.dragBubble(e, currentDragDeltaXY); var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); - var newLoc = goog.math.Coordinate.sum(this.startXY_, delta); + var newLoc = Blockly.utils.Coordinate.sum(this.startXY_, delta); // Move the bubble to its final location. this.draggingBubble_.moveTo(newLoc.x, newLoc.y); @@ -251,14 +250,14 @@ Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() { * correction for mutator workspaces. * This function does not consider differing origins. It simply scales the * input's x and y values. - * @param {!goog.math.Coordinate} pixelCoord A coordinate with x and y values + * @param {!Blockly.utils.Coordinate} pixelCoord A coordinate with x and y values * in css pixel units. - * @return {!goog.math.Coordinate} The input coordinate divided by the workspace + * @return {!Blockly.utils.Coordinate} The input coordinate divided by the workspace * scale. * @private */ Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { - var result = new goog.math.Coordinate(pixelCoord.x / this.workspace_.scale, + var result = new Blockly.utils.Coordinate(pixelCoord.x / this.workspace_.scale, pixelCoord.y / this.workspace_.scale); if (this.workspace_.isMutator) { // If we're in a mutator, its scale is always 1, purely because of some @@ -266,7 +265,7 @@ Blockly.BubbleDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) { // the scale on the parent workspace. // Fix that for dragging. var mainScale = this.workspace_.options.parentWorkspace.scale; - result = result.scale(1 / mainScale); + result.scale(1 / mainScale); } return result; }; diff --git a/core/connection_db.js b/core/connection_db.js index c538fad7561..192e88f6ef7 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -226,16 +226,17 @@ Blockly.ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) { * @param {!Blockly.Connection} conn The connection searching for a compatible * mate. * @param {number} maxRadius The maximum radius to another connection. - * @param {!goog.math.Coordinate} dxy Offset between this connection's location - * in the database and the current location (as a result of dragging). + * @param {!Blockly.utils.Coordinate} dxy Offset between this connection's + * location in the database and the current location (as a result of + * dragging). * @return {!{connection: ?Blockly.Connection, radius: number}} Contains two * properties:' connection' which is either another connection or null, * and 'radius' which is the distance. */ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius, dxy) { - // Don't bother. if (!this.connections_.length) { + // Don't bother. return {connection: null, radius: maxRadius}; } diff --git a/core/contextmenu.js b/core/contextmenu.js index 6971c3f4930..017b11808da 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -30,6 +30,7 @@ */ goog.provide('Blockly.ContextMenu'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Msg'); @@ -39,7 +40,6 @@ goog.require('Blockly.utils.uiMenu'); goog.require('Blockly.Xml'); goog.require('goog.events'); -goog.require('goog.math.Coordinate'); goog.require('goog.ui.Menu'); goog.require('goog.ui.MenuItem'); @@ -362,7 +362,7 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { var boundingRect = injectionDiv.getBoundingClientRect(); // The client coordinates offset by the injection div's upper left corner. - var clientOffsetPixels = new goog.math.Coordinate( + var clientOffsetPixels = new Blockly.utils.Coordinate( e.clientX - boundingRect.left, e.clientY - boundingRect.top); // The offset in pixels between the main workspace's origin and the upper @@ -371,14 +371,13 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { // The position of the new comment in pixels relative to the origin of the // main workspace. - var finalOffsetPixels = goog.math.Coordinate.difference(clientOffsetPixels, + var finalOffset = Blockly.utils.Coordinate.difference(clientOffsetPixels, mainOffsetPixels); - // The position of the new comment in main workspace coordinates. - var finalOffsetMainWs = finalOffsetPixels.scale(1 / ws.scale); + finalOffset.scale(1 / ws.scale); - var commentX = finalOffsetMainWs.x; - var commentY = finalOffsetMainWs.y; + var commentX = finalOffset.x; + var commentY = finalOffset.y; comment.moveBy(commentX, commentY); if (ws.rendered) { comment.initSvg(); diff --git a/core/dragged_connection_manager.js b/core/dragged_connection_manager.js index 09cfdab01e4..98138b29348 100644 --- a/core/dragged_connection_manager.js +++ b/core/dragged_connection_manager.js @@ -161,7 +161,7 @@ Blockly.DraggedConnectionManager.prototype.applyConnections = function() { /** * Update highlighted connections based on the most recent move location. - * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, * in workspace units. * @param {?number} deleteArea One of {@link Blockly.DELETE_AREA_TRASH}, * {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}. @@ -234,7 +234,7 @@ Blockly.DraggedConnectionManager.prototype.initAvailableConnections_ = function( /** * Find the new closest connection, and update internal state in response. - * @param {!goog.math.Coordinate} dxy Position relative to the drag start, + * @param {!Blockly.utils.Coordinate} dxy Position relative to the drag start, * in workspace units. * @return {boolean} Whether the closest connection has changed. * @private diff --git a/core/field.js b/core/field.js index 8d9d54b0188..ccfd0551804 100644 --- a/core/field.js +++ b/core/field.js @@ -869,7 +869,7 @@ Blockly.Field.prototype.getClickTarget_ = function() { /** * Return the absolute coordinates of the top-left corner of this field. * The origin (0,0) is the top-left corner of the page body. - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. * @private */ Blockly.Field.prototype.getAbsoluteXY_ = function() { diff --git a/core/field_textinput.js b/core/field_textinput.js index 116309bb6db..b791bcc2085 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -26,6 +26,7 @@ goog.provide('Blockly.FieldTextInput'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); @@ -34,8 +35,6 @@ goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /** * Class for an editable text field. @@ -364,7 +363,7 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { // In RTL mode block fields and LTR input fields the left edge moves, // whereas the right edge is fixed. Reposition the editor. var x = this.sourceBlock_.RTL ? bBox.right - div.offsetWidth : bBox.left; - var xy = new goog.math.Coordinate(x, bBox.top); + var xy = new Blockly.utils.Coordinate(x, bBox.top); // Shift by a few pixels to line up exactly. xy.y += 1; diff --git a/core/flyout_base.js b/core/flyout_base.js index 0e20bd0d6fd..e3f08137658 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Flyout'); goog.require('Blockly.Block'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.VarCreate'); @@ -38,8 +39,6 @@ goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.Xml'); -goog.require('goog.math.Coordinate'); - /** * Class for a flyout. @@ -817,25 +816,23 @@ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) { var flyoutOffsetPixels = this.workspace_.getOriginOffsetInPixels(); // The position of the old block in flyout workspace coordinates. - var oldBlockPosWs = oldBlock.getRelativeToSurfaceXY(); - + var oldBlockPos = oldBlock.getRelativeToSurfaceXY(); // The position of the old block in pixels relative to the flyout // workspace's origin. - var oldBlockPosPixels = oldBlockPosWs.scale(this.workspace_.scale); + oldBlockPos.scale(this.workspace_.scale); // The position of the old block in pixels relative to the upper left corner // of the injection div. - var oldBlockOffsetPixels = goog.math.Coordinate.sum(flyoutOffsetPixels, - oldBlockPosPixels); + var oldBlockOffsetPixels = Blockly.utils.Coordinate.sum(flyoutOffsetPixels, + oldBlockPos); // The position of the old block in pixels relative to the origin of the // main workspace. - var finalOffsetPixels = goog.math.Coordinate.difference(oldBlockOffsetPixels, + var finalOffset = Blockly.utils.Coordinate.difference(oldBlockOffsetPixels, mainOffsetPixels); - // The position of the old block in main workspace coordinates. - var finalOffsetMainWs = finalOffsetPixels.scale(1 / targetWorkspace.scale); + finalOffset.scale(1 / targetWorkspace.scale); - block.moveBy(finalOffsetMainWs.x, finalOffsetMainWs.y); + block.moveBy(finalOffset.x, finalOffset.y); return block; }; diff --git a/core/flyout_button.js b/core/flyout_button.js index 4cd12fab944..17f8d60460e 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -26,10 +26,9 @@ goog.provide('Blockly.FlyoutButton'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /** * Class for a button in the flyout. @@ -62,10 +61,10 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, xml, isLabel) { this.text_ = xml.getAttribute('text'); /** - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ - this.position_ = new goog.math.Coordinate(0, 0); + this.position_ = new Blockly.utils.Coordinate(0, 0); /** * Whether this button should be styled as a label. @@ -205,7 +204,7 @@ Blockly.FlyoutButton.prototype.moveTo = function(x, y) { /** * Location of the button. - * @return {!goog.math.Coordinate} x, y coordinates. + * @return {!Blockly.utils.Coordinate} x, y coordinates. * @package */ Blockly.FlyoutButton.prototype.getPosition = function() { diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index c5e092cb08c..4b10c05f2da 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -312,7 +312,7 @@ Blockly.HorizontalFlyout.prototype.layout_ = function(contents, gaps) { * Determine if a drag delta is toward the workspace, based on the position * and orientation of the flyout. This is used in determineDragIntention_ to * determine if a new block should be created or if the flyout should scroll. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at mouse down, in pixel units. * @return {boolean} True if the drag is toward the workspace. * @package diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index f14750e3aa8..51035194e70 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -290,7 +290,7 @@ Blockly.VerticalFlyout.prototype.layout_ = function(contents, gaps) { * Determine if a drag delta is toward the workspace, based on the position * and orientation of the flyout. This is used in determineDragIntention_ to * determine if a new block should be created or if the flyout should scroll. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at mouse down, in pixel units. * @return {boolean} True if the drag is toward the workspace. * @package diff --git a/core/gesture.js b/core/gesture.js index ebf67584a86..a0cc3baf0ac 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -31,6 +31,7 @@ goog.require('Blockly.BlockAnimations'); goog.require('Blockly.BlockDragger'); goog.require('Blockly.BubbleDragger'); goog.require('Blockly.constants'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.FlyoutDragger'); @@ -39,8 +40,6 @@ goog.require('Blockly.Touch'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceDragger'); -goog.require('goog.math.Coordinate'); - /* * Note: In this file "start" refers to touchstart, mousedown, and pointerstart @@ -60,14 +59,14 @@ Blockly.Gesture = function(e, creatorWorkspace) { /** * The position of the mouse when the gesture started. Units are css pixels, * with (0, 0) at the top left of the browser window (mouseEvent clientX/Y). - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} */ this.mouseDownXY_ = null; /** * How far the mouse has moved during this drag, in pixel units. * (0, 0) is at this.mouseDownXY_. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ this.currentDragDeltaXY_ = null; @@ -281,7 +280,7 @@ Blockly.Gesture.prototype.dispose = function() { * @private */ Blockly.Gesture.prototype.updateFromEvent_ = function(e) { - var currentXY = new goog.math.Coordinate(e.clientX, e.clientY); + var currentXY = new Blockly.utils.Coordinate(e.clientX, e.clientY); var changed = this.updateDragDelta_(currentXY); // Exceeded the drag radius for the first time. if (changed) { @@ -293,18 +292,18 @@ Blockly.Gesture.prototype.updateFromEvent_ = function(e) { /** * DO MATH to set currentDragDeltaXY_ based on the most recent mouse position. - * @param {!goog.math.Coordinate} currentXY The most recent mouse/pointer + * @param {!Blockly.utils.Coordinate} currentXY The most recent mouse/pointer * position, in pixel units, with (0, 0) at the window's top left corner. * @return {boolean} True if the drag just exceeded the drag radius for the * first time. * @private */ Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) { - this.currentDragDeltaXY_ = goog.math.Coordinate.difference(currentXY, + this.currentDragDeltaXY_ = Blockly.utils.Coordinate.difference(currentXY, this.mouseDownXY_); if (!this.hasExceededDragRadius_) { - var currentDragDelta = goog.math.Coordinate.magnitude( + var currentDragDelta = Blockly.utils.Coordinate.magnitude( this.currentDragDeltaXY_); // The flyout has a different drag radius from the rest of Blockly. @@ -513,7 +512,7 @@ Blockly.Gesture.prototype.doStart = function(e) { Blockly.longStart_(e, this); } - this.mouseDownXY_ = new goog.math.Coordinate(e.clientX, e.clientY); + this.mouseDownXY_ = new Blockly.utils.Coordinate(e.clientX, e.clientY); this.healStack_ = e.altKey || e.ctrlKey || e.metaKey; this.bindMouseEvents(e); diff --git a/core/icon.js b/core/icon.js index 0d3f2ddd316..119f3ae9c7d 100644 --- a/core/icon.js +++ b/core/icon.js @@ -26,10 +26,9 @@ goog.provide('Blockly.Icon'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /** * Class for an icon. @@ -59,7 +58,7 @@ Blockly.Icon.prototype.bubble_ = null; /** * Absolute coordinate of icon's center. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @protected */ Blockly.Icon.prototype.iconXY_ = null; @@ -172,7 +171,7 @@ Blockly.Icon.prototype.renderIcon = function(cursorX) { /** * Notification that the icon has moved. Update the arrow accordingly. - * @param {!goog.math.Coordinate} xy Absolute location in workspace coordinates. + * @param {!Blockly.utils.Coordinate} xy Absolute location in workspace coordinates. */ Blockly.Icon.prototype.setIconLocation = function(xy) { this.iconXY_ = xy; @@ -189,17 +188,17 @@ Blockly.Icon.prototype.computeIconLocation = function() { // Find coordinates for the centre of the icon and update the arrow. var blockXY = this.block_.getRelativeToSurfaceXY(); var iconXY = Blockly.utils.getRelativeXY(this.iconGroup_); - var newXY = new goog.math.Coordinate( + var newXY = new Blockly.utils.Coordinate( blockXY.x + iconXY.x + this.SIZE / 2, blockXY.y + iconXY.y + this.SIZE / 2); - if (!goog.math.Coordinate.equals(this.getIconLocation(), newXY)) { + if (!Blockly.utils.Coordinate.equals(this.getIconLocation(), newXY)) { this.setIconLocation(newXY); } }; /** * Returns the center of the block's icon relative to the surface. - * @return {!goog.math.Coordinate} Object with x and y properties in workspace + * @return {!Blockly.utils.Coordinate} Object with x and y properties in workspace * coordinates. */ Blockly.Icon.prototype.getIconLocation = function() { diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index de4de3892c7..8cd58f14aca 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -223,7 +223,7 @@ Blockly.InsertionMarkerManager.prototype.applyConnections = function() { /** * Update highlighted connections based on the most recent move location. - * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, * in workspace units. * @param {?number} deleteArea One of {@link Blockly.DELETE_AREA_TRASH}, * {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}. @@ -317,7 +317,7 @@ Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function() * updated based on the closest candidate and the current drag distance. * @param {!Object} candidate An object containing a local connection, a closest * connection, and a radius. Returned by getCandidate_. - * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, * in workspace units. * @return {boolean} Whether the preview should be updated. * @private @@ -362,7 +362,7 @@ Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function( /** * Find the nearest valid connection, which may be the same as the current * closest connection. - * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * @param {!Blockly.utils.Coordinate} dxy Position relative to drag start, * in workspace units. * @return {!Object} An object containing a local connection, a closest * connection, and a radius. diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 4c8b3d0d8e0..b9ab8f2418a 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -27,11 +27,10 @@ goog.provide('Blockly.RenderedConnection'); goog.require('Blockly.Connection'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /** * Class for a connection between blocks that may be rendered on screen. @@ -45,10 +44,10 @@ Blockly.RenderedConnection = function(source, type) { /** * Workspace units, (0, 0) is top left of block. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ - this.offsetInBlock_ = new goog.math.Coordinate(0, 0); + this.offsetInBlock_ = new Blockly.utils.Coordinate(0, 0); }; goog.inherits(Blockly.RenderedConnection, Blockly.Connection); @@ -144,7 +143,7 @@ Blockly.RenderedConnection.prototype.moveBy = function(dx, dy) { /** * Move this connection to the location given by its offset within the block and * the location of the block's top left corner. - * @param {!goog.math.Coordinate} blockTL The location of the top left corner + * @param {!Blockly.utils.Coordinate} blockTL The location of the top left corner * of the block, in workspace coordinates. */ Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) { @@ -187,7 +186,7 @@ Blockly.RenderedConnection.prototype.tighten_ = function() { * Find the closest compatible connection to this connection. * All parameters are in workspace units. * @param {number} maxLimit The maximum radius to another connection. - * @param {!goog.math.Coordinate} dxy Offset between this connection's location + * @param {!Blockly.utils.Coordinate} dxy Offset between this connection's location * in the database and the current location (as a result of dragging). * @return {!{connection: ?Blockly.Connection, radius: number}} Contains two * properties: 'connection' which is either another connection or null, diff --git a/core/scrollbar.js b/core/scrollbar.js index 42892673e1f..afec9fdc98c 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -27,11 +27,10 @@ goog.provide('Blockly.Scrollbar'); goog.provide('Blockly.ScrollbarPair'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /** * A note on units: most of the numbers that are in CSS pixels are scaled if the @@ -211,10 +210,10 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair, opt_class) { * The upper left corner of the scrollbar's SVG group in CSS pixels relative * to the scrollbar's origin. This is usually relative to the injection div * origin. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ - this.position_ = new goog.math.Coordinate(0, 0); + this.position_ = new Blockly.utils.Coordinate(0, 0); // Store the thickness in a temp variable for readability. var scrollbarThickness = Blockly.Scrollbar.scrollbarThickness; @@ -246,10 +245,10 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair, opt_class) { * The location of the origin of the workspace that the scrollbar is in, * measured in CSS pixels relative to the injection div origin. This is usually * (0, 0). When the scrollbar is in a flyout it may have a different origin. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ -Blockly.Scrollbar.prototype.origin_ = new goog.math.Coordinate(0, 0); +Blockly.Scrollbar.prototype.origin_ = new Blockly.utils.Coordinate(0, 0); /** * The position of the mouse along this scrollbar's major axis at the start of @@ -257,7 +256,7 @@ Blockly.Scrollbar.prototype.origin_ = new goog.math.Coordinate(0, 0); * Units are CSS pixels, with (0, 0) at the top left of the browser window. * For a horizontal scrollbar this is the x coordinate of the mouse down event; * for a vertical scrollbar it's the y coordinate of the mouse down event. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} */ Blockly.Scrollbar.prototype.startDragMouse_ = 0; @@ -860,5 +859,5 @@ Blockly.Scrollbar.prototype.set = function(value) { * @param {number} y The y coordinate of the scrollbar's origin, in CSS pixels. */ Blockly.Scrollbar.prototype.setOrigin = function(x, y) { - this.origin_ = new goog.math.Coordinate(x, y); + this.origin_ = new Blockly.utils.Coordinate(x, y); }; diff --git a/core/touch_gesture.js b/core/touch_gesture.js index fb84ed727bb..9dcfbddeda6 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -27,11 +27,10 @@ goog.provide('Blockly.TouchGesture'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Gesture'); goog.require('Blockly.utils'); -goog.require('goog.math.Coordinate'); - /* * Note: In this file "start" refers to touchstart, mousedown, and pointerstart @@ -58,7 +57,7 @@ Blockly.TouchGesture = function(e, creatorWorkspace) { /** * A map of cached points used for tracking multi-touch gestures. - * @type {Object} + * @type {Object} * @private */ this.cachedPoints_ = {}; @@ -240,7 +239,7 @@ Blockly.TouchGesture.prototype.handleTouchStart = function(e) { if (pointers.length == 2) { var point0 = this.cachedPoints_[pointers[0]]; var point1 = this.cachedPoints_[pointers[1]]; - this.startDistance_ = goog.math.Coordinate.distance(point0, point1); + this.startDistance_ = Blockly.utils.Coordinate.distance(point0, point1); this.isMultiTouch_ = true; e.preventDefault(); } @@ -263,7 +262,7 @@ Blockly.TouchGesture.prototype.handleTouchMove = function(e) { // Calculate the distance between the two pointers var point0 = this.cachedPoints_[pointers[0]]; var point1 = this.cachedPoints_[pointers[1]]; - var moveDistance = goog.math.Coordinate.distance(point0, point1); + var moveDistance = Blockly.utils.Coordinate.distance(point0, point1); var startDistance = this.startDistance_; var scale = this.touchScale_ = moveDistance / startDistance; @@ -301,14 +300,14 @@ Blockly.TouchGesture.prototype.handleTouchEnd = function(e) { /** * Helper function returning the current touch point coordinate. * @param {!Event} e A touch or pointer event. - * @return {goog.math.Coordinate} The current touch point coordinate + * @return {Blockly.utils.Coordinate} The current touch point coordinate * @package */ Blockly.TouchGesture.prototype.getTouchPoint = function(e) { if (!this.startWorkspace_) { return null; } - return new goog.math.Coordinate( + return new Blockly.utils.Coordinate( (e.pageX ? e.pageX : e.changedTouches[0].pageX), (e.pageY ? e.pageY : e.changedTouches[0].pageY) ); diff --git a/core/utils.js b/core/utils.js index a2d6da5fb71..6a4bf79f433 100644 --- a/core/utils.js +++ b/core/utils.js @@ -32,10 +32,10 @@ */ goog.provide('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); -goog.require('goog.math.Coordinate'); goog.require('goog.style'); @@ -135,10 +135,10 @@ Blockly.utils.isTargetInput = function(e) { * Return the coordinates of the top-left corner of this element relative to * its parent. Only for SVG elements and children (e.g. rect, g, path). * @param {!Element} element SVG element to find the coordinates of. - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. */ Blockly.utils.getRelativeXY = function(element) { - var xy = new goog.math.Coordinate(0, 0); + var xy = new Blockly.utils.Coordinate(0, 0); // First, check for x and y attributes. var x = element.getAttribute('x'); if (x) { @@ -179,7 +179,7 @@ Blockly.utils.getRelativeXY = function(element) { * @param {!Element} element SVG element to find the coordinates of. If this is * not a child of the div Blockly was injected into, the behaviour is * undefined. - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. */ Blockly.utils.getInjectionDivXY_ = function(element) { var x = 0; @@ -194,7 +194,7 @@ Blockly.utils.getInjectionDivXY_ = function(element) { } element = element.parentNode; } - return new goog.math.Coordinate(x, y); + return new Blockly.utils.Coordinate(x, y); }; /** @@ -975,7 +975,7 @@ Blockly.utils.containsNode = function(parent, descendant) { /** * Gets the document scroll distance as a coordinate object. * Copied from Closure's goog.dom.getDocumentScroll. - * @return {!goog.math.Coordinate} Object with values 'x' and 'y'. + * @return {!Blockly.utils.Coordinate} Object with values 'x' and 'y'. */ Blockly.utils.getDocumentScroll = function() { var el = document.documentElement; @@ -984,9 +984,9 @@ Blockly.utils.getDocumentScroll = function() { // The keyboard on IE10 touch devices shifts the page using the pageYOffset // without modifying scrollTop. For this case, we want the body scroll // offsets. - return new goog.math.Coordinate(el.scrollLeft, el.scrollTop); + return new Blockly.utils.Coordinate(el.scrollLeft, el.scrollTop); } - return new goog.math.Coordinate( + return new Blockly.utils.Coordinate( win.pageXOffset || el.scrollLeft, win.pageYOffset || el.scrollTop); }; diff --git a/core/utils_coordinate.js b/core/utils_coordinate.js new file mode 100644 index 00000000000..3d66561e28f --- /dev/null +++ b/core/utils_coordinate.js @@ -0,0 +1,139 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utility methods for coordinate manipulation. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.utils.Coordinate + * @namespace + */ +goog.provide('Blockly.utils.Coordinate'); + + +/** + * Class for representing coordinates and positions. + * @param {number=} opt_x Left, defaults to 0. + * @param {number=} opt_y Top, defaults to 0. + * @struct + * @constructor + */ +Blockly.utils.Coordinate = function(x, y) { + /** + * X-value + * @type {number} + */ + this.x = x; + + /** + * Y-value + * @type {number} + */ + this.y = y; +}; + +/** + * Compares coordinates for equality. + * @param {Blockly.utils.Coordinate} a A Coordinate. + * @param {Blockly.utils.Coordinate} b A Coordinate. + * @return {boolean} True iff the coordinates are equal, or if both are null. + */ +Blockly.utils.Coordinate.equals = function(a, b) { + if (a == b) { + return true; + } + if (!a || !b) { + return false; + } + return a.x == b.x && a.y == b.y; +}; + +/** + * Returns the distance between two coordinates. + * @param {!Blockly.utils.Coordinate} a A Coordinate. + * @param {!Blockly.utils.Coordinate} b A Coordinate. + * @return {number} The distance between `a` and `b`. + */ +Blockly.utils.Coordinate.distance = function(a, b) { + var dx = a.x - b.x; + var dy = a.y - b.y; + return Math.sqrt(dx * dx + dy * dy); +}; + +/** + * Returns the magnitude of a coordinate. + * @param {!Blockly.utils.Coordinate} a A Coordinate. + * @return {number} The distance between the origin and `a`. + */ +Blockly.utils.Coordinate.magnitude = function(a) { + return Math.sqrt(a.x * a.x + a.y * a.y); +}; + +/** + * Returns the difference between two coordinates as a new + * Blockly.utils.Coordinate. + * @param {!Blockly.utils.Coordinate} a A Coordinate. + * @param {!Blockly.utils.Coordinate} b A Coordinate. + * @return {!Blockly.utils.Coordinate} A Coordinate representing the difference + * between `a` and `b`. + */ +Blockly.utils.Coordinate.difference = function(a, b) { + return new Blockly.utils.Coordinate(a.x - b.x, a.y - b.y); +}; + +/** + * Returns the sum of two coordinates as a new Blockly.utils.Coordinate. + * @param {!Blockly.utils.Coordinate} a A Coordinate. + * @param {!Blockly.utils.Coordinate} b A Coordinate. + * @return {!Blockly.utils.Coordinate} A Coordinate representing the sum of the two + * coordinates. + */ +Blockly.utils.Coordinate.sum = function(a, b) { + return new Blockly.utils.Coordinate(a.x + b.x, a.y + b.y); +}; + +/** + * Scales this coordinate by the given scale factor. + * @param {number} s The scale factor to use for both x and y dimensions. + * @return {!Blockly.utils.Coordinate} This coordinate after scaling. + */ +Blockly.utils.Coordinate.prototype.scale = function(s) { + this.x *= s; + this.y *= s; + return this; +}; + +/** + * Translates this coordinate by the given offsets. + * respectively. + * @param {number} tx The value to translate x by. + * @param {number} ty The value to translate y by. + * @return {!Blockly.utils.Coordinate} This coordinate after translating. + */ +Blockly.utils.Coordinate.prototype.translate = function(tx, ty) { + this.x += tx; + this.y += ty; + return this; +}; diff --git a/core/workspace_comment.js b/core/workspace_comment.js index fc75084437a..9b418d7cede 100644 --- a/core/workspace_comment.js +++ b/core/workspace_comment.js @@ -26,6 +26,7 @@ goog.provide('Blockly.WorkspaceComment'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentChange'); goog.require('Blockly.Events.CommentCreate'); @@ -34,8 +35,6 @@ goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.utils'); goog.require('Blockly.Xml.utils'); -goog.require('goog.math.Coordinate'); - /** * Class for a workspace comment. @@ -57,10 +56,10 @@ Blockly.WorkspaceComment = function(workspace, content, height, width, opt_id) { /** * The comment's position in workspace units. (0, 0) is at the workspace's * origin; scale does not change this value. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @protected */ - this.xy_ = new goog.math.Coordinate(0, 0); + this.xy_ = new Blockly.utils.Coordinate(0, 0); /** * The comment's height in workspace units. Scale does not change this value. @@ -174,12 +173,12 @@ Blockly.WorkspaceComment.prototype.setWidth = function(width) { /** * Get stored location. - * @return {!goog.math.Coordinate} The comment's stored location. This is not - * valid if the comment is currently being dragged. + * @return {!Blockly.utils.Coordinate} The comment's stored location. + * This is not valid if the comment is currently being dragged. * @package */ Blockly.WorkspaceComment.prototype.getXY = function() { - return this.xy_.clone(); + return new Blockly.utils.Coordinate(this.xy_.x, this.xy_.y); }; /** diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index 51fb738bbc8..6aff07c457c 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -26,11 +26,10 @@ goog.provide('Blockly.WorkspaceCommentSvg.render'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceCommentSvg'); -goog.require('goog.math.Coordinate'); - /** * Size of the resize icon. @@ -265,7 +264,7 @@ Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_ = function(e) { return; } // Left-click (or middle click) - this.workspace.startDrag(e, new goog.math.Coordinate( + this.workspace.startDrag(e, new Blockly.utils.Coordinate( this.workspace.RTL ? -this.width_ : this.width_, this.height_)); this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_( diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 287135cb579..9fb2776aa82 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -26,6 +26,7 @@ goog.provide('Blockly.WorkspaceCommentSvg'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); @@ -34,8 +35,6 @@ goog.require('Blockly.Events.Ui'); goog.require('Blockly.utils'); goog.require('Blockly.WorkspaceComment'); -goog.require('goog.math.Coordinate'); - /** * Class for a workspace comment's SVG representation. @@ -273,7 +272,7 @@ Blockly.WorkspaceCommentSvg.prototype.removeFocus = function() { * If the comment is on the workspace, (0, 0) is the origin of the workspace * coordinate system. * This does not change with workspace scale. - * @return {!goog.math.Coordinate} Object with .x and .y properties in + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties in * workspace coordinates. * @package */ @@ -304,7 +303,7 @@ Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() { } while (element && element != this.workspace.getBubbleCanvas() && element != dragSurfaceGroup); } - this.xy_ = new goog.math.Coordinate(x, y); + this.xy_ = new Blockly.utils.Coordinate(x, y); return this.xy_; }; @@ -319,7 +318,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) { // TODO: Do I need to look up the relative to surface XY position here? var xy = this.getRelativeToSurfaceXY(); this.translate(xy.x + dx, xy.y + dy); - this.xy_ = new goog.math.Coordinate(xy.x + dx, xy.y + dy); + this.xy_ = new Blockly.utils.Coordinate(xy.x + dx, xy.y + dy); event.recordNew(); Blockly.Events.fire(event); this.workspace.resizeContents(); @@ -333,7 +332,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) { * @package */ Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) { - this.xy_ = new goog.math.Coordinate(x, y); + this.xy_ = new Blockly.utils.Coordinate(x, y); this.getSvgRoot().setAttribute('transform', 'translate(' + x + ',' + y + ')'); }; @@ -363,7 +362,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface_ = function() { * Move this comment back to the workspace block canvas. * Generally should be called at the same time as setDragging(false). * Does nothing if useDragSurface_ is false. - * @param {!goog.math.Coordinate} newXY The position the comment should take on + * @param {!Blockly.utils.Coordinate} newXY The position the comment should take on * on the workspace canvas, in workspace coordinates. * @private */ @@ -381,7 +380,7 @@ Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface_ = function(newXY) { * drag surface to translate blocks. * @param {Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries * rendered items during a drag, or null if no drag surface is in use. - * @param {!goog.math.Coordinate} newLoc The location to translate to, in + * @param {!Blockly.utils.Coordinate} newLoc The location to translate to, in * workspace coordinates. * @package */ @@ -419,7 +418,7 @@ Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { * Returns the coordinates of a bounding box describing the dimensions of this * comment. * Coordinate system: workspace coordinates. - * @return {!{topLeft: goog.math.Coordinate, bottomRight: goog.math.Coordinate}} + * @return {!{topLeft: Blockly.utils.Coordinate, bottomRight: Blockly.utils.Coordinate}} * Object with top left and bottom right coordinates of the bounding box. * @package */ @@ -429,17 +428,17 @@ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { var topLeft; var bottomRight; if (this.RTL) { - topLeft = new goog.math.Coordinate(blockXY.x - (commentBounds.width), + topLeft = new Blockly.utils.Coordinate(blockXY.x - (commentBounds.width), blockXY.y); // Add the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - bottomRight = new goog.math.Coordinate(blockXY.x, + bottomRight = new Blockly.utils.Coordinate(blockXY.x, blockXY.y + commentBounds.height); } else { // Subtract the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - topLeft = new goog.math.Coordinate(blockXY.x, blockXY.y); - bottomRight = new goog.math.Coordinate(blockXY.x + commentBounds.width, + topLeft = new Blockly.utils.Coordinate(blockXY.x, blockXY.y); + bottomRight = new Blockly.utils.Coordinate(blockXY.x + commentBounds.width, blockXY.y + commentBounds.height); } return {topLeft: topLeft, bottomRight: bottomRight}; diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index b1123987431..1a31a9ab709 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -119,7 +119,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) { /** * Reports the surface translation in scaled workspace coordinates. * Use this when finishing a drag to return blocks to the correct position. - * @return {!goog.math.Coordinate} Current translation of the surface + * @return {!Blockly.utils.Coordinate} Current translation of the surface * @package */ Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() { diff --git a/core/workspace_dragger.js b/core/workspace_dragger.js index 00c28818738..ce3288e5cb8 100644 --- a/core/workspace_dragger.js +++ b/core/workspace_dragger.js @@ -26,7 +26,7 @@ goog.provide('Blockly.WorkspaceDragger'); -goog.require('goog.math.Coordinate'); +goog.require('Blockly.utils.Coordinate'); /** @@ -48,10 +48,10 @@ Blockly.WorkspaceDragger = function(workspace) { /** * The scroll position of the workspace at the beginning of the drag. * Coordinate system: pixel coordinates. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ - this.startScrollXY_ = new goog.math.Coordinate( + this.startScrollXY_ = new Blockly.utils.Coordinate( workspace.scrollX, workspace.scrollY); }; @@ -76,7 +76,7 @@ Blockly.WorkspaceDragger.prototype.startDrag = function() { /** * Finish dragging the workspace and put everything back where it belongs. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel coordinates. * @package */ @@ -88,11 +88,11 @@ Blockly.WorkspaceDragger.prototype.endDrag = function(currentDragDeltaXY) { /** * Move the workspace based on the most recent mouse movements. - * @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has + * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has * moved from the position at the start of the drag, in pixel coordinates. * @package */ Blockly.WorkspaceDragger.prototype.drag = function(currentDragDeltaXY) { - var newXY = goog.math.Coordinate.sum(this.startScrollXY_, currentDragDeltaXY); + var newXY = Blockly.utils.Coordinate.sum(this.startScrollXY_, currentDragDeltaXY); this.workspace_.scroll(newXY.x, newXY.y); }; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index bbcae5589db..b92337759ce 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -30,6 +30,7 @@ goog.provide('Blockly.WorkspaceSvg'); //goog.require('Blockly.BlockSvg'); goog.require('Blockly.ConnectionDB'); goog.require('Blockly.constants'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Gesture'); @@ -51,8 +52,6 @@ goog.require('Blockly.WorkspaceDragSurfaceSvg'); goog.require('Blockly.Xml'); goog.require('Blockly.ZoomControls'); -goog.require('goog.math.Coordinate'); - /** * Class for a workspace. This is an onscreen area with optional trashcan, @@ -250,7 +249,7 @@ Blockly.WorkspaceSvg.prototype.startScrollY = 0; /** * Distance from mouse to object being dragged. - * @type {goog.math.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ Blockly.WorkspaceSvg.prototype.dragDeltaXY_ = null; @@ -339,7 +338,7 @@ Blockly.WorkspaceSvg.prototype.injectionDiv_ = null; * Last known position of the page scroll. * This is used to determine whether we have recalculated screen coordinate * stuff since the page scrolled. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} * @private */ Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; @@ -429,7 +428,7 @@ Blockly.WorkspaceSvg.prototype.isVisible = function() { * scales that after canvas SVG element, if it's a descendant. * The origin (0,0) is the top-left corner of the Blockly SVG. * @param {!Element} element Element to find the coordinates of. - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. * @private */ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { @@ -453,7 +452,7 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { y += xy.y * scale; element = element.parentNode; } while (element && element != this.getParentSvg()); - return new goog.math.Coordinate(x, y); + return new Blockly.utils.Coordinate(x, y); }; /** @@ -461,7 +460,7 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { * origin in pixels. * The workspace origin is where a block would render at position (0, 0). * It is not the upper left corner of the workspace SVG. - * @return {!goog.math.Coordinate} Offset in pixels. + * @return {!Blockly.utils.Coordinate} Offset in pixels. * @package */ Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { @@ -774,7 +773,7 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = function() { /* eslint-disable indent */ var currScroll = Blockly.utils.getDocumentScroll(); - if (!goog.math.Coordinate.equals(this.lastRecordedPageScroll_, currScroll)) { + if (!Blockly.utils.Coordinate.equals(this.lastRecordedPageScroll_, currScroll)) { this.lastRecordedPageScroll_ = currScroll; this.updateScreenCalculations_(); } @@ -1063,7 +1062,7 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { var connections = block.getConnections_(false); for (var i = 0, connection; connection = connections[i]; i++) { var neighbour = connection.closest(Blockly.SNAP_RADIUS, - new goog.math.Coordinate(blockX, blockY)); + new Blockly.utils.Coordinate(blockX, blockY)); if (neighbour.connection) { collide = true; break; @@ -1227,7 +1226,7 @@ Blockly.WorkspaceSvg.prototype.onMouseDown_ = function(e) { /** * Start tracking a drag of an object on this workspace. * @param {!Event} e Mouse down event. - * @param {!goog.math.Coordinate} xy Starting location of object. + * @param {!Blockly.utils.Coordinate} xy Starting location of object. */ Blockly.WorkspaceSvg.prototype.startDrag = function(e, xy) { // Record the starting offset between the bubble's location and the mouse. @@ -1236,13 +1235,13 @@ Blockly.WorkspaceSvg.prototype.startDrag = function(e, xy) { // Fix scale of mouse event. point.x /= this.scale; point.y /= this.scale; - this.dragDeltaXY_ = goog.math.Coordinate.difference(xy, point); + this.dragDeltaXY_ = Blockly.utils.Coordinate.difference(xy, point); }; /** * Track a drag of an object on this workspace. * @param {!Event} e Mouse move event. - * @return {!goog.math.Coordinate} New location of object. + * @return {!Blockly.utils.Coordinate} New location of object. */ Blockly.WorkspaceSvg.prototype.moveDrag = function(e) { var point = Blockly.utils.mouseToSvg(e, this.getParentSvg(), @@ -1250,7 +1249,7 @@ Blockly.WorkspaceSvg.prototype.moveDrag = function(e) { // Fix scale of mouse event. point.x /= this.scale; point.y /= this.scale; - return goog.math.Coordinate.sum(this.dragDeltaXY_, point); + return Blockly.utils.Coordinate.sum(this.dragDeltaXY_, point); }; /** diff --git a/core/ws_comment_events.js b/core/ws_comment_events.js index cc71a036811..ac5e7c8d701 100644 --- a/core/ws_comment_events.js +++ b/core/ws_comment_events.js @@ -30,13 +30,12 @@ goog.provide('Blockly.Events.CommentCreate'); goog.provide('Blockly.Events.CommentDelete'); goog.provide('Blockly.Events.CommentMove'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Abstract'); goog.require('Blockly.Xml'); goog.require('Blockly.Xml.utils'); -goog.require('goog.math.Coordinate'); - /** * Abstract class for a comment event. @@ -312,13 +311,13 @@ Blockly.Events.CommentMove = function(comment) { /** * The location before the move, in workspace coordinates. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} */ this.oldCoordinate_ = comment.getXY(); /** * The location after the move, in workspace coordinates. - * @type {!goog.math.Coordinate} + * @type {!Blockly.utils.Coordinate} */ this.newCoordinate_ = null; }; @@ -346,7 +345,7 @@ Blockly.Events.CommentMove.prototype.type = Blockly.Events.COMMENT_MOVE; /** * Override the location before the move. Use this if you don't create the * event until the end of the move, but you know the original location. - * @param {!goog.math.Coordinate} xy The location before the move, in workspace + * @param {!Blockly.utils.Coordinate} xy The location before the move, in workspace * coordinates. */ Blockly.Events.CommentMove.prototype.setOldCoordinate = function(xy) { @@ -377,7 +376,7 @@ Blockly.Events.CommentMove.prototype.fromJson = function(json) { if (json['newCoordinate']) { var xy = json['newCoordinate'].split(','); this.newCoordinate_ = - new goog.math.Coordinate(parseFloat(xy[0]), parseFloat(xy[1])); + new Blockly.utils.Coordinate(parseFloat(xy[0]), parseFloat(xy[1])); } }; @@ -386,7 +385,7 @@ Blockly.Events.CommentMove.prototype.fromJson = function(json) { * @return {boolean} False if something changed. */ Blockly.Events.CommentMove.prototype.isNull = function() { - return goog.math.Coordinate.equals(this.oldCoordinate_, this.newCoordinate_); + return Blockly.utils.Coordinate.equals(this.oldCoordinate_, this.newCoordinate_); }; /** From 42b4897f0ebf1c86e2384366b251644e2129fbf9 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 14:52:07 -0700 Subject: [PATCH 109/233] Routine recompile due to changed dependencies. --- blockly_accessible_compressed.js | 165 +++++++++++++++-------------- blockly_accessible_uncompressed.js | 60 ++++++----- blockly_compressed.js | 165 +++++++++++++++-------------- blockly_uncompressed.js | 60 ++++++----- blocks_compressed.js | 27 +++-- msg/js/el.js | 4 +- msg/js/eo.js | 66 ++++++------ msg/js/es.js | 28 ++--- msg/js/he.js | 8 +- msg/js/ko.js | 6 +- msg/js/nb.js | 4 +- msg/js/ro.js | 2 +- msg/js/zh-hans.js | 2 +- 13 files changed, 305 insertions(+), 292 deletions(-) diff --git a/blockly_accessible_compressed.js b/blockly_accessible_compressed.js index def228f6bf2..b58003a0b64 100644 --- a/blockly_accessible_compressed.js +++ b/blockly_accessible_compressed.js @@ -80,7 +80,9 @@ goog.asserts.assertString=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isS goog.asserts.assertObject=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isObject(a)&&goog.asserts.doAssertFailure_("Expected object but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a};goog.asserts.assertArray=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isArray(a)&&goog.asserts.doAssertFailure_("Expected array but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a}; goog.asserts.assertBoolean=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isBoolean(a)&&goog.asserts.doAssertFailure_("Expected boolean but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a};goog.asserts.assertElement=function(a,b,c){!goog.asserts.ENABLE_ASSERTS||goog.isObject(a)&&a.nodeType==goog.dom.NodeType.ELEMENT||goog.asserts.doAssertFailure_("Expected Element but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a}; goog.asserts.assertInstanceof=function(a,b,c,d){!goog.asserts.ENABLE_ASSERTS||a instanceof b||goog.asserts.doAssertFailure_("Expected instanceof %s but got %s.",[goog.asserts.getType_(b),goog.asserts.getType_(a)],c,Array.prototype.slice.call(arguments,3));return a};goog.asserts.assertFinite=function(a,b,c){!goog.asserts.ENABLE_ASSERTS||"number"==typeof a&&isFinite(a)||goog.asserts.doAssertFailure_("Expected %s to be a finite number but it is not.",[a],b,Array.prototype.slice.call(arguments,2));return a}; -goog.asserts.assertObjectPrototypeIsIntact=function(){for(var a in Object.prototype)goog.asserts.fail(a+" should not be enumerable in Object.prototype.")};goog.asserts.getType_=function(a){return a instanceof Function?a.displayName||a.name||"unknown type name":a instanceof Object?a.constructor.displayName||a.constructor.name||Object.prototype.toString.call(a):null===a?"null":typeof a};goog.array={};goog.NATIVE_ARRAY_PROTOTYPES=goog.TRUSTED_SITE;goog.array.ASSUME_NATIVE_FUNCTIONS=!1;goog.array.peek=function(a){return a[a.length-1]};goog.array.last=goog.array.peek; +goog.asserts.assertObjectPrototypeIsIntact=function(){for(var a in Object.prototype)goog.asserts.fail(a+" should not be enumerable in Object.prototype.")};goog.asserts.getType_=function(a){return a instanceof Function?a.displayName||a.name||"unknown type name":a instanceof Object?a.constructor.displayName||a.constructor.name||Object.prototype.toString.call(a):null===a?"null":typeof a};goog.debug.entryPointRegistry={};goog.debug.EntryPointMonitor=function(){};goog.debug.entryPointRegistry.refList_=[];goog.debug.entryPointRegistry.monitors_=[];goog.debug.entryPointRegistry.monitorsMayExist_=!1;goog.debug.entryPointRegistry.register=function(a){goog.debug.entryPointRegistry.refList_[goog.debug.entryPointRegistry.refList_.length]=a;if(goog.debug.entryPointRegistry.monitorsMayExist_)for(var b=goog.debug.entryPointRegistry.monitors_,c=0;cc?Math.max(0,a.length+c):c;if(goog.isString(a))return goog.isString(b)&&1==b.length?a.indexOf(b,c):-1;for(;cc&&(c=Math.max(0,a.length+c));if(goog.isString(a))return goog.isString(b)&&1==b.length?a.lastIndexOf(b,c):-1;for(;0<=c;c--)if(c in a&&a[c]===b)return c;return-1}; goog.array.forEach=goog.NATIVE_ARRAY_PROTOTYPES&&(goog.array.ASSUME_NATIVE_FUNCTIONS||Array.prototype.forEach)?function(a,b,c){goog.asserts.assert(null!=a.length);Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=goog.isString(a)?a.split(""):a,f=0;fb&&Array.prototype.push.apply(a,a.splice(0,-b)));return a};goog.array.moveItem=function(a,b,c){goog.asserts.assert(0<=b&&ba*b?a+b:a};goog.math.lerp=function(a,b,c){return a+c*(b-a)};goog.math.nearlyEquals=function(a,b,c){return Math.abs(a-b)<=(c||1E-6)};goog.math.standardAngle=function(a){return goog.math.modulo(a,360)}; -goog.math.standardAngleInRadians=function(a){return goog.math.modulo(a,2*Math.PI)};goog.math.toRadians=function(a){return a*Math.PI/180};goog.math.toDegrees=function(a){return 180*a/Math.PI};goog.math.angleDx=function(a,b){return b*Math.cos(goog.math.toRadians(a))};goog.math.angleDy=function(a,b){return b*Math.sin(goog.math.toRadians(a))};goog.math.angle=function(a,b,c,d){return goog.math.standardAngle(goog.math.toDegrees(Math.atan2(d-b,c-a)))}; -goog.math.angleDifference=function(a,b){a=goog.math.standardAngle(b)-goog.math.standardAngle(a);180=a&&(a=360+a);return a};goog.math.sign=function(a){return 0a?-1:a}; -goog.math.longestCommonSubsequence=function(a,b,c,d){c=c||function(a,b){return a==b};d=d||function(b,c){return a[b]};for(var e=a.length,f=b.length,g=[],h=0;hg[h][k-1]?h--:k--;return l}; -goog.math.sum=function(a){return goog.array.reduce(arguments,function(a,c){return a+c},0)};goog.math.average=function(a){return goog.math.sum.apply(null,arguments)/arguments.length};goog.math.sampleVariance=function(a){var b=arguments.length;if(2>b)return 0;var c=goog.math.average.apply(null,arguments);return goog.math.sum.apply(null,goog.array.map(arguments,function(a){return Math.pow(a-c,2)}))/(b-1)};goog.math.standardDeviation=function(a){return Math.sqrt(goog.math.sampleVariance.apply(null,arguments))}; -goog.math.isInt=function(a){return isFinite(a)&&0==a%1};goog.math.isFiniteNumber=function(a){return isFinite(a)};goog.math.isNegativeZero=function(a){return 0==a&&0>1/a};goog.math.log10Floor=function(a){if(0a?1:0)}return 0==a?-Infinity:NaN};goog.math.safeFloor=function(a,b){goog.asserts.assert(!goog.isDef(b)||0":"
")}; goog.string.internal.htmlEscape=function(a,b){if(b)a=a.replace(goog.string.internal.AMP_RE_,"&").replace(goog.string.internal.LT_RE_,"<").replace(goog.string.internal.GT_RE_,">").replace(goog.string.internal.QUOT_RE_,""").replace(goog.string.internal.SINGLE_QUOTE_RE_,"'").replace(goog.string.internal.NULL_RE_,"�");else{if(!goog.string.internal.ALL_RE_.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(goog.string.internal.AMP_RE_,"&"));-1!=a.indexOf("<")&&(a=a.replace(goog.string.internal.LT_RE_, @@ -384,7 +374,17 @@ goog.events.protectBrowserEventEntryPoint=function(a){goog.events.handleBrowserE goog.events.handleBrowserEvent_=function(a,b){if(a.removed)return!0;if(!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT){var c=b||goog.getObjectByName("window.event");b=new goog.events.BrowserEvent(c,this);var d=!0;if(goog.events.CAPTURE_SIMULATION_MODE==goog.events.CaptureSimulationMode.ON){if(!goog.events.isMarkedIeEvent_(c)){goog.events.markIeEvent_(c);c=[];for(var e=b.currentTarget;e;e=e.parentNode)c.push(e);a=a.type;for(e=c.length-1;!b.propagationStopped_&&0<=e;e--){b.currentTarget=c[e];var f= goog.events.fireListeners_(c[e],a,!0,b);d=d&&f}for(e=0;!b.propagationStopped_&&ea.keyCode||void 0!=a.returnValue}; goog.events.uniqueIdCounter_=0;goog.events.getUniqueId=function(a){return a+"_"+goog.events.uniqueIdCounter_++};goog.events.getListenerMap_=function(a){a=a[goog.events.LISTENER_MAP_PROP_];return a instanceof goog.events.ListenerMap?a:null};goog.events.LISTENER_WRAPPER_PROP_="__closure_events_fn_"+(1E9*Math.random()>>>0); -goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.dom.BrowserFeature={CAN_ADD_NAME_OR_TYPE_ATTRIBUTES:!goog.userAgent.IE||goog.userAgent.isDocumentModeOrHigher(9),CAN_USE_CHILDREN_ATTRIBUTE:!goog.userAgent.GECKO&&!goog.userAgent.IE||goog.userAgent.IE&&goog.userAgent.isDocumentModeOrHigher(9)||goog.userAgent.GECKO&&goog.userAgent.isVersionOrHigher("1.9.1"),CAN_USE_INNER_TEXT:goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("9"),CAN_USE_PARENT_ELEMENT_PROPERTY:goog.userAgent.IE||goog.userAgent.OPERA||goog.userAgent.WEBKIT,INNER_HTML_NEEDS_SCOPED_ELEMENT:goog.userAgent.IE, +goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.math={};goog.math.randomInt=function(a){return Math.floor(Math.random()*a)};goog.math.uniformRandom=function(a,b){return a+Math.random()*(b-a)};goog.math.clamp=function(a,b,c){return Math.min(Math.max(a,b),c)};goog.math.modulo=function(a,b){a%=b;return 0>a*b?a+b:a};goog.math.lerp=function(a,b,c){return a+c*(b-a)};goog.math.nearlyEquals=function(a,b,c){return Math.abs(a-b)<=(c||1E-6)};goog.math.standardAngle=function(a){return goog.math.modulo(a,360)}; +goog.math.standardAngleInRadians=function(a){return goog.math.modulo(a,2*Math.PI)};goog.math.toRadians=function(a){return a*Math.PI/180};goog.math.toDegrees=function(a){return 180*a/Math.PI};goog.math.angleDx=function(a,b){return b*Math.cos(goog.math.toRadians(a))};goog.math.angleDy=function(a,b){return b*Math.sin(goog.math.toRadians(a))};goog.math.angle=function(a,b,c,d){return goog.math.standardAngle(goog.math.toDegrees(Math.atan2(d-b,c-a)))}; +goog.math.angleDifference=function(a,b){a=goog.math.standardAngle(b)-goog.math.standardAngle(a);180=a&&(a=360+a);return a};goog.math.sign=function(a){return 0a?-1:a}; +goog.math.longestCommonSubsequence=function(a,b,c,d){c=c||function(a,b){return a==b};d=d||function(b,c){return a[b]};for(var e=a.length,f=b.length,g=[],h=0;hg[h][k-1]?h--:k--;return l}; +goog.math.sum=function(a){return goog.array.reduce(arguments,function(a,c){return a+c},0)};goog.math.average=function(a){return goog.math.sum.apply(null,arguments)/arguments.length};goog.math.sampleVariance=function(a){var b=arguments.length;if(2>b)return 0;var c=goog.math.average.apply(null,arguments);return goog.math.sum.apply(null,goog.array.map(arguments,function(a){return Math.pow(a-c,2)}))/(b-1)};goog.math.standardDeviation=function(a){return Math.sqrt(goog.math.sampleVariance.apply(null,arguments))}; +goog.math.isInt=function(a){return isFinite(a)&&0==a%1};goog.math.isFiniteNumber=function(a){return isFinite(a)};goog.math.isNegativeZero=function(a){return 0==a&&0>1/a};goog.math.log10Floor=function(a){if(0a?1:0)}return 0==a?-Infinity:NaN};goog.math.safeFloor=function(a,b){goog.asserts.assert(!goog.isDef(b)||0e&&(g=2*Math.PI-g);var h=g+Math.PI/2;h>2*Math.PI&&(h-=2*Math.PI);var k=Math.sin(h),l=Math.cos(h),n=this.getBubbleSize();h=(n.width+n.height)/Blockly.Bubble.ARROW_THICKNESS;h=Math.min(h,n.width,n.height)/4;n=1-Blockly.Bubble.ANCHOR_RADIUS/f;d=b+ n*d;e=c+n*e;n=b+h*l;var m=c+h*k;b-=h*l;c-=h*k;k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+n+","+m);a.push("C"+(n+f)+","+(m+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)}; Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();Blockly.utils.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Bubble.prototype.moveDuringDrag=function(a,b){a?a.translateSurface(b.x,b.y):this.moveTo(b.x,b.y);this.relativeLeft_=this.workspace_.RTL?this.anchorXY_.x-b.x-this.width_:b.x-this.anchorXY_.x;this.relativeTop_=b.y-this.anchorXY_.y;this.renderArrow_()}; -Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new goog.math.Coordinate(this.anchorXY_.x+this.relativeLeft_,this.anchorXY_.y+this.relativeTop_)};Blockly.Bubble.prototype.setAutoLayout=function(a){this.autoLayout_=a};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this);this.blockId=a?a.id:null;this.workspaceId=a?a.workspace.id:null;this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; +Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new Blockly.utils.Coordinate(this.anchorXY_.x+this.relativeLeft_,this.anchorXY_.y+this.relativeTop_)};Blockly.Bubble.prototype.setAutoLayout=function(a){this.autoLayout_=a};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this);this.blockId=a?a.id:null;this.workspaceId=a?a.workspace.id:null;this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);this.blockId&&(a.blockId=this.blockId);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue;this.blockId=a.blockId};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null; Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; Blockly.Icon.prototype.dispose=function(){Blockly.utils.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed()||this.block_.isInsertionMarker())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; -Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new goog.math.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);goog.math.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; +Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new Blockly.utils.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);Blockly.utils.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; Blockly.Comment.prototype.drawIcon_=function(a){Blockly.utils.createSvgElement("circle",{"class":"blocklyIconShape",r:"8",cx:"8",cy:"8"},a);Blockly.utils.createSvgElement("path",{"class":"blocklyIconSymbol",d:"m6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.4050.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25-1.201,0.998 -1.201,1.528 -1.204,2.19z"},a);Blockly.utils.createSvgElement("rect",{"class":"blocklyIconSymbol",x:"6.8",y:"10.78",height:"2",width:"2"},a)}; Blockly.Comment.prototype.createEditor_=function(){this.foreignObject_=Blockly.utils.createSvgElement("foreignObject",{x:Blockly.Bubble.BORDER_WIDTH,y:Blockly.Bubble.BORDER_WIDTH},null);var a=document.createElementNS(Blockly.HTML_NS,"body");a.setAttribute("xmlns",Blockly.HTML_NS);a.className="blocklyMinimalBody";var b=document.createElementNS(Blockly.HTML_NS,"textarea");b.className="blocklyCommentTextarea";b.setAttribute("dir",this.block_.RTL?"RTL":"LTR");a.appendChild(b);this.textarea_=b;this.foreignObject_.appendChild(a); @@ -1080,7 +1082,7 @@ Blockly.BlockAnimations.connectionUiEffect=function(a){var b=a.workspace,c=b.sca Blockly.BlockAnimations.connectionUiStep_=function(a,b,c){var d=(new Date-b)/150;1a.workspace.scale)){var b=a.getHeightWidth().height;b=Math.atan(10/b)/Math.PI*180;a.RTL||(b*=-1);Blockly.BlockAnimations.disconnectUiStep_(a.getSvgRoot(),b,new Date)}}; Blockly.BlockAnimations.disconnectUiStep_=function(a,b,c){var d=(new Date-c)/200;1b+window.scrollX-2*Blockly.Tooltip.MARGINS&&(d=b-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=e+"px";Blockly.Tooltip.DIV.style.left=d+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; this.healStack_=!Blockly.DRAG_STACK}; Blockly.Gesture.prototype.dispose=function(){Blockly.Touch.clearTouchIdentifier();Blockly.Tooltip.unblock();this.creatorWorkspace_.clearGesture();this.onMoveWrapper_&&Blockly.unbindEvent_(this.onMoveWrapper_);this.onUpWrapper_&&Blockly.unbindEvent_(this.onUpWrapper_);this.flyout_=this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=null;this.blockDragger_&&(this.blockDragger_.dispose(),this.blockDragger_=null);this.workspaceDragger_&&(this.workspaceDragger_.dispose(),this.workspaceDragger_= -null);this.bubbleDragger_&&(this.bubbleDragger_.dispose(),this.bubbleDragger_=null)};Blockly.Gesture.prototype.updateFromEvent_=function(a){var b=new goog.math.Coordinate(a.clientX,a.clientY);this.updateDragDelta_(b)&&(this.updateIsDragging_(),Blockly.longStop_());this.mostRecentEvent_=a}; -Blockly.Gesture.prototype.updateDragDelta_=function(a){this.currentDragDeltaXY_=goog.math.Coordinate.difference(a,this.mouseDownXY_);return this.hasExceededDragRadius_?!1:this.hasExceededDragRadius_=goog.math.Coordinate.magnitude(this.currentDragDeltaXY_)>(this.flyout_?Blockly.FLYOUT_DRAG_RADIUS:Blockly.DRAG_RADIUS)}; +null);this.bubbleDragger_&&(this.bubbleDragger_.dispose(),this.bubbleDragger_=null)};Blockly.Gesture.prototype.updateFromEvent_=function(a){var b=new Blockly.utils.Coordinate(a.clientX,a.clientY);this.updateDragDelta_(b)&&(this.updateIsDragging_(),Blockly.longStop_());this.mostRecentEvent_=a}; +Blockly.Gesture.prototype.updateDragDelta_=function(a){this.currentDragDeltaXY_=Blockly.utils.Coordinate.difference(a,this.mouseDownXY_);return this.hasExceededDragRadius_?!1:this.hasExceededDragRadius_=Blockly.utils.Coordinate.magnitude(this.currentDragDeltaXY_)>(this.flyout_?Blockly.FLYOUT_DRAG_RADIUS:Blockly.DRAG_RADIUS)}; Blockly.Gesture.prototype.updateIsDraggingFromFlyout_=function(){return this.flyout_.isBlockCreatable_(this.targetBlock_)?!this.flyout_.isScrollable()||this.flyout_.isDragTowardWorkspace(this.currentDragDeltaXY_)?(this.startWorkspace_=this.flyout_.targetWorkspace_,this.startWorkspace_.updateScreenCalculationsIfScrolled(),Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.startBlock_=null,this.targetBlock_=this.flyout_.createBlock(this.targetBlock_),this.targetBlock_.select(),!0):!1:!1}; Blockly.Gesture.prototype.updateIsDraggingBubble_=function(){if(!this.startBubble_)return!1;this.isDraggingBubble_=!0;this.startDraggingBubble_();return!0};Blockly.Gesture.prototype.updateIsDraggingBlock_=function(){if(!this.targetBlock_)return!1;this.flyout_?this.isDraggingBlock_=this.updateIsDraggingFromFlyout_():this.targetBlock_.isMovable()&&(this.isDraggingBlock_=!0);return this.isDraggingBlock_?(this.startDraggingBlock_(),!0):!1}; Blockly.Gesture.prototype.updateIsDraggingWorkspace_=function(){if(this.flyout_?this.flyout_.isScrollable():this.startWorkspace_&&this.startWorkspace_.isDraggable())this.workspaceDragger_=this.flyout_?new Blockly.FlyoutDragger(this.flyout_):new Blockly.WorkspaceDragger(this.startWorkspace_),this.isDraggingWorkspace_=!0,this.workspaceDragger_.startDrag()}; @@ -1170,7 +1172,7 @@ Blockly.Gesture.prototype.updateIsDragging_=function(){if(this.calledUpdateIsDra Blockly.Gesture.prototype.startDraggingBlock_=function(){this.blockDragger_=new Blockly.BlockDragger(this.targetBlock_,this.startWorkspace_);this.blockDragger_.startBlockDrag(this.currentDragDeltaXY_,this.healStack_);this.blockDragger_.dragBlock(this.mostRecentEvent_,this.currentDragDeltaXY_)}; Blockly.Gesture.prototype.startDraggingBubble_=function(){this.bubbleDragger_=new Blockly.BubbleDragger(this.startBubble_,this.startWorkspace_);this.bubbleDragger_.startBubbleDrag();this.bubbleDragger_.dragBubble(this.mostRecentEvent_,this.currentDragDeltaXY_)}; Blockly.Gesture.prototype.doStart=function(a){Blockly.utils.isTargetInput(a)?this.cancel():(this.hasStarted_=!0,Blockly.BlockAnimations.disconnectUiStop(),this.startWorkspace_.updateScreenCalculationsIfScrolled(),this.startWorkspace_.isMutator&&this.startWorkspace_.resize(),this.startWorkspace_.markFocused(),this.mostRecentEvent_=a,Blockly.hideChaff(!!this.flyout_),Blockly.Tooltip.block(),this.targetBlock_&&this.targetBlock_.select(),Blockly.utils.isRightButton(a)?this.handleRightClick(a):("touchstart"!= -a.type.toLowerCase()&&"pointerdown"!=a.type.toLowerCase()||"mouse"==a.pointerType||Blockly.longStart_(a,this),this.mouseDownXY_=new goog.math.Coordinate(a.clientX,a.clientY),this.healStack_=a.altKey||a.ctrlKey||a.metaKey,this.bindMouseEvents(a)))}; +a.type.toLowerCase()&&"pointerdown"!=a.type.toLowerCase()||"mouse"==a.pointerType||Blockly.longStart_(a,this),this.mouseDownXY_=new Blockly.utils.Coordinate(a.clientX,a.clientY),this.healStack_=a.altKey||a.ctrlKey||a.metaKey,this.bindMouseEvents(a)))}; Blockly.Gesture.prototype.bindMouseEvents=function(a){this.onMoveWrapper_=Blockly.bindEventWithChecks_(document,"mousemove",null,this.handleMove.bind(this));this.onUpWrapper_=Blockly.bindEventWithChecks_(document,"mouseup",null,this.handleUp.bind(this));a.preventDefault();a.stopPropagation()}; Blockly.Gesture.prototype.handleMove=function(a){this.updateFromEvent_(a);this.isDraggingWorkspace_?this.workspaceDragger_.drag(this.currentDragDeltaXY_):this.isDraggingBlock_?this.blockDragger_.dragBlock(this.mostRecentEvent_,this.currentDragDeltaXY_):this.isDraggingBubble_&&this.bubbleDragger_.dragBubble(this.mostRecentEvent_,this.currentDragDeltaXY_);a.preventDefault();a.stopPropagation()}; Blockly.Gesture.prototype.handleUp=function(a){this.updateFromEvent_(a);Blockly.longStop_();this.isEnding_?console.log("Trying to end a gesture recursively."):(this.isEnding_=!0,this.isDraggingBubble_?this.bubbleDragger_.endBubbleDrag(a,this.currentDragDeltaXY_):this.isDraggingBlock_?this.blockDragger_.endBlockDrag(a,this.currentDragDeltaXY_):this.isDraggingWorkspace_?this.workspaceDragger_.endDrag(this.currentDragDeltaXY_):this.isBubbleClick_()?this.doBubbleClick_():this.isFieldClick_()?this.doFieldClick_(): @@ -1200,9 +1202,9 @@ Blockly.ScrollbarPair.prototype.dispose=function(){Blockly.utils.removeNode(this Blockly.ScrollbarPair.prototype.resize=function(){var a=this.workspace_.getMetrics();if(a){var b=!1,c=!1;this.oldHostMetrics_&&this.oldHostMetrics_.viewWidth==a.viewWidth&&this.oldHostMetrics_.viewHeight==a.viewHeight&&this.oldHostMetrics_.absoluteTop==a.absoluteTop&&this.oldHostMetrics_.absoluteLeft==a.absoluteLeft?(this.oldHostMetrics_&&this.oldHostMetrics_.contentWidth==a.contentWidth&&this.oldHostMetrics_.viewLeft==a.viewLeft&&this.oldHostMetrics_.contentLeft==a.contentLeft||(b=!0),this.oldHostMetrics_&& this.oldHostMetrics_.contentHeight==a.contentHeight&&this.oldHostMetrics_.viewTop==a.viewTop&&this.oldHostMetrics_.contentTop==a.contentTop||(c=!0)):c=b=!0;b&&this.hScroll.resize(a);c&&this.vScroll.resize(a);this.oldHostMetrics_&&this.oldHostMetrics_.viewWidth==a.viewWidth&&this.oldHostMetrics_.absoluteLeft==a.absoluteLeft||this.corner_.setAttribute("x",this.vScroll.position_.x);this.oldHostMetrics_&&this.oldHostMetrics_.viewHeight==a.viewHeight&&this.oldHostMetrics_.absoluteTop==a.absoluteTop||this.corner_.setAttribute("y", this.hScroll.position_.y);this.oldHostMetrics_=a}};Blockly.ScrollbarPair.prototype.set=function(a,b){var c={};a*=this.hScroll.ratio_;b*=this.vScroll.ratio_;var d=this.vScroll.scrollViewSize_;c.x=this.getRatio_(a,this.hScroll.scrollViewSize_);c.y=this.getRatio_(b,d);this.workspace_.setMetrics(c);this.hScroll.setHandlePosition(a);this.vScroll.setHandlePosition(b)};Blockly.ScrollbarPair.prototype.getRatio_=function(a,b){a/=b;return isNaN(a)?0:a}; -Blockly.Scrollbar=function(a,b,c,d){this.workspace_=a;this.pair_=c||!1;this.horizontal_=b;this.oldHostMetrics_=null;this.createDom_(d);this.position_=new goog.math.Coordinate(0,0);a=Blockly.Scrollbar.scrollbarThickness;b?(this.svgBackground_.setAttribute("height",a),this.outerSvg_.setAttribute("height",a),this.svgHandle_.setAttribute("height",a-5),this.svgHandle_.setAttribute("y",2.5),this.lengthAttribute_="width",this.positionAttribute_="x"):(this.svgBackground_.setAttribute("width",a),this.outerSvg_.setAttribute("width", -a),this.svgHandle_.setAttribute("width",a-5),this.svgHandle_.setAttribute("x",2.5),this.lengthAttribute_="height",this.positionAttribute_="y");this.onMouseDownBarWrapper_=Blockly.bindEventWithChecks_(this.svgBackground_,"mousedown",this,this.onMouseDownBar_);this.onMouseDownHandleWrapper_=Blockly.bindEventWithChecks_(this.svgHandle_,"mousedown",this,this.onMouseDownHandle_)};Blockly.Scrollbar.prototype.origin_=new goog.math.Coordinate(0,0);Blockly.Scrollbar.prototype.startDragMouse_=0; -Blockly.Scrollbar.prototype.scrollViewSize_=0;Blockly.Scrollbar.prototype.handleLength_=0;Blockly.Scrollbar.prototype.handlePosition_=0;Blockly.Scrollbar.prototype.isVisible_=!0;Blockly.Scrollbar.prototype.containerVisible_=!0;Blockly.Scrollbar.scrollbarThickness=15;goog.events.BrowserFeature.TOUCH_ENABLED&&(Blockly.Scrollbar.scrollbarThickness=25); +Blockly.Scrollbar=function(a,b,c,d){this.workspace_=a;this.pair_=c||!1;this.horizontal_=b;this.oldHostMetrics_=null;this.createDom_(d);this.position_=new Blockly.utils.Coordinate(0,0);a=Blockly.Scrollbar.scrollbarThickness;b?(this.svgBackground_.setAttribute("height",a),this.outerSvg_.setAttribute("height",a),this.svgHandle_.setAttribute("height",a-5),this.svgHandle_.setAttribute("y",2.5),this.lengthAttribute_="width",this.positionAttribute_="x"):(this.svgBackground_.setAttribute("width",a),this.outerSvg_.setAttribute("width", +a),this.svgHandle_.setAttribute("width",a-5),this.svgHandle_.setAttribute("x",2.5),this.lengthAttribute_="height",this.positionAttribute_="y");this.onMouseDownBarWrapper_=Blockly.bindEventWithChecks_(this.svgBackground_,"mousedown",this,this.onMouseDownBar_);this.onMouseDownHandleWrapper_=Blockly.bindEventWithChecks_(this.svgHandle_,"mousedown",this,this.onMouseDownHandle_)};Blockly.Scrollbar.prototype.origin_=new Blockly.utils.Coordinate(0,0);Blockly.Scrollbar.prototype.startDragMouse_=0; +Blockly.Scrollbar.prototype.scrollViewSize_=0;Blockly.Scrollbar.prototype.handleLength_=0;Blockly.Scrollbar.prototype.handlePosition_=0;Blockly.Scrollbar.prototype.isVisible_=!0;Blockly.Scrollbar.prototype.containerVisible_=!0;Blockly.Scrollbar.scrollbarThickness=15;Blockly.Touch.TOUCH_ENABLED&&(Blockly.Scrollbar.scrollbarThickness=25); Blockly.Scrollbar.metricsAreEquivalent_=function(a,b){return a&&b&&a.viewWidth==b.viewWidth&&a.viewHeight==b.viewHeight&&a.viewLeft==b.viewLeft&&a.viewTop==b.viewTop&&a.absoluteTop==b.absoluteTop&&a.absoluteLeft==b.absoluteLeft&&a.contentWidth==b.contentWidth&&a.contentHeight==b.contentHeight&&a.contentLeft==b.contentLeft&&a.contentTop==b.contentTop?!0:!1}; Blockly.Scrollbar.prototype.dispose=function(){this.cleanUp_();Blockly.unbindEvent_(this.onMouseDownBarWrapper_);this.onMouseDownBarWrapper_=null;Blockly.unbindEvent_(this.onMouseDownHandleWrapper_);this.onMouseDownHandleWrapper_=null;Blockly.utils.removeNode(this.outerSvg_);this.workspace_=this.svgHandle_=this.svgBackground_=this.svgGroup_=this.outerSvg_=null};Blockly.Scrollbar.prototype.setHandleLength_=function(a){this.handleLength_=a;this.svgHandle_.setAttribute(this.lengthAttribute_,this.handleLength_)}; Blockly.Scrollbar.prototype.setHandlePosition=function(a){this.handlePosition_=a;this.svgHandle_.setAttribute(this.positionAttribute_,this.handlePosition_)};Blockly.Scrollbar.prototype.setScrollViewSize_=function(a){this.scrollViewSize_=a;this.outerSvg_.setAttribute(this.lengthAttribute_,this.scrollViewSize_);this.svgBackground_.setAttribute(this.lengthAttribute_,this.scrollViewSize_)};Blockly.ScrollbarPair.prototype.setContainerVisible=function(a){this.hScroll.setContainerVisible(a);this.vScroll.setContainerVisible(a)}; @@ -1220,14 +1222,14 @@ Blockly.Scrollbar.prototype.onMouseDownHandle_=function(a){this.workspace_.markF a.stopPropagation(),a.preventDefault())};Blockly.Scrollbar.prototype.onMouseMoveHandle_=function(a){this.setHandlePosition(this.constrainHandle_(this.startDragHandle+((this.horizontal_?a.clientX:a.clientY)-this.startDragMouse_)));this.onScroll_()};Blockly.Scrollbar.prototype.onMouseUpHandle_=function(){this.workspace_.resetDragSurface();Blockly.Touch.clearTouchIdentifier();this.cleanUp_()}; Blockly.Scrollbar.prototype.cleanUp_=function(){Blockly.hideChaff(!0);Blockly.Scrollbar.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Scrollbar.onMouseUpWrapper_),Blockly.Scrollbar.onMouseUpWrapper_=null);Blockly.Scrollbar.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Scrollbar.onMouseMoveWrapper_),Blockly.Scrollbar.onMouseMoveWrapper_=null)}; Blockly.Scrollbar.prototype.constrainHandle_=function(a){return a=0>=a||isNaN(a)||this.scrollViewSize_this.previousScale_){var c=b-this.previousScale_;c=0Object.keys(this.cachedPoints_).length&&(this.cachedPoints_={},this.previousScale_=0)}; -Blockly.TouchGesture.prototype.getTouchPoint=function(a){return this.startWorkspace_?new goog.math.Coordinate(a.pageX?a.pageX:a.changedTouches[0].pageX,a.pageY?a.pageY:a.changedTouches[0].pageY):null};Blockly.Trashcan=function(a){this.workspace_=a;this.hasBlocks_=!1;this.contents_=[];0>=this.workspace_.options.maxTrashcanContents||(a={scrollbars:!0,disabledPatternId:this.workspace_.options.disabledPatternId,parentWorkspace:this.workspace_,RTL:this.workspace_.RTL,oneBasedIndex:this.workspace_.options.oneBasedIndex},this.workspace_.horizontalLayout?(a.toolboxPosition=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_TOP?Blockly.TOOLBOX_AT_BOTTOM:Blockly.TOOLBOX_AT_TOP,this.flyout_=new Blockly.HorizontalFlyout(a)): +Blockly.TouchGesture.prototype.dispose=function(){Blockly.TouchGesture.superClass_.dispose.call(this);this.onStartWrapper_&&Blockly.unbindEvent_(this.onStartWrapper_)};Blockly.TouchGesture.prototype.handleTouchStart=function(a){var b=Blockly.Touch.getTouchIdentifierFromEvent(a);this.cachedPoints_[b]=this.getTouchPoint(a);b=Object.keys(this.cachedPoints_);2==b.length&&(this.startDistance_=Blockly.utils.Coordinate.distance(this.cachedPoints_[b[0]],this.cachedPoints_[b[1]]),this.isMultiTouch_=!0,a.preventDefault())}; +Blockly.TouchGesture.prototype.handleTouchMove=function(a){var b=Blockly.Touch.getTouchIdentifierFromEvent(a);this.cachedPoints_[b]=this.getTouchPoint(a);b=Object.keys(this.cachedPoints_);if(2==b.length){b=this.touchScale_=Blockly.utils.Coordinate.distance(this.cachedPoints_[b[0]],this.cachedPoints_[b[1]])/this.startDistance_;if(0this.previousScale_){var c=b-this.previousScale_;c=0Object.keys(this.cachedPoints_).length&&(this.cachedPoints_={},this.previousScale_=0)}; +Blockly.TouchGesture.prototype.getTouchPoint=function(a){return this.startWorkspace_?new Blockly.utils.Coordinate(a.pageX?a.pageX:a.changedTouches[0].pageX,a.pageY?a.pageY:a.changedTouches[0].pageY):null};Blockly.utils.Rect=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};Blockly.utils.Rect.prototype.contains=function(a,b){return a>=this.left&&a<=this.left+this.width&&b>=this.top&&b<=this.top+this.height};Blockly.Trashcan=function(a){this.workspace_=a;this.hasBlocks_=!1;this.contents_=[];0>=this.workspace_.options.maxTrashcanContents||(a={scrollbars:!0,disabledPatternId:this.workspace_.options.disabledPatternId,parentWorkspace:this.workspace_,RTL:this.workspace_.RTL,oneBasedIndex:this.workspace_.options.oneBasedIndex},this.workspace_.horizontalLayout?(a.toolboxPosition=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_TOP?Blockly.TOOLBOX_AT_BOTTOM:Blockly.TOOLBOX_AT_TOP,this.flyout_=new Blockly.HorizontalFlyout(a)): (a.toolboxPosition=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?Blockly.TOOLBOX_AT_LEFT:Blockly.TOOLBOX_AT_RIGHT,this.flyout_=new Blockly.VerticalFlyout(a)),this.workspace_.addChangeListener(this.onDelete_()))};Blockly.Trashcan.prototype.WIDTH_=47;Blockly.Trashcan.prototype.BODY_HEIGHT_=44;Blockly.Trashcan.prototype.LID_HEIGHT_=16;Blockly.Trashcan.prototype.MARGIN_BOTTOM_=20;Blockly.Trashcan.prototype.MARGIN_SIDE_=20;Blockly.Trashcan.prototype.MARGIN_HOTSPOT_=10; Blockly.Trashcan.prototype.SPRITE_LEFT_=0;Blockly.Trashcan.prototype.SPRITE_TOP_=32;Blockly.Trashcan.prototype.HAS_BLOCKS_LID_ANGLE=.1;Blockly.Trashcan.prototype.isOpen=!1;Blockly.Trashcan.prototype.minOpenness_=0;Blockly.Trashcan.prototype.svgGroup_=null;Blockly.Trashcan.prototype.svgLid_=null;Blockly.Trashcan.prototype.lidTask_=0;Blockly.Trashcan.prototype.lidOpen_=0;Blockly.Trashcan.prototype.left_=0;Blockly.Trashcan.prototype.top_=0; Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyTrash"},null);var a=String(Math.random()).substring(2);var b=Blockly.utils.createSvgElement("clipPath",{id:"blocklyTrashBodyClipPath"+a},this.svgGroup_);Blockly.utils.createSvgElement("rect",{width:this.WIDTH_,height:this.BODY_HEIGHT_,y:this.LID_HEIGHT_},b);var c=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,x:-this.SPRITE_LEFT_,height:Blockly.SPRITE.height,y:-this.SPRITE_TOP_, @@ -1236,12 +1238,12 @@ Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.utils.cre Blockly.Trashcan.prototype.init=function(a){0this.minOpenness_&&1>this.lidOpen_&&(this.lidTask_=setTimeout(this.animateLid_.bind(this),20))}; Blockly.Trashcan.prototype.setLidAngle_=function(a){var b=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT||this.workspace_.horizontalLayout&&this.workspace_.RTL;this.svgLid_.setAttribute("transform","rotate("+(b?-a:a)+","+(b?4:this.WIDTH_-4)+","+(this.LID_HEIGHT_-2)+")")};Blockly.Trashcan.prototype.close=function(){this.setOpen_(!1)};Blockly.Trashcan.prototype.click=function(){if(this.hasBlocks_){for(var a=[],b=0,c;c=this.contents_[b];b++)a[b]=Blockly.Xml.textToDom(c).firstChild;this.flyout_.show(a)}}; Blockly.Trashcan.prototype.mouseOver_=function(){this.hasBlocks_&&this.setOpen_(!0)};Blockly.Trashcan.prototype.mouseOut_=function(){this.setOpen_(!1)}; -Blockly.Trashcan.prototype.onDelete_=function(){var a=this;return function(b){0>=a.workspace_.options.maxTrashcanContents||b.type!=Blockly.Events.BLOCK_DELETE||(b=a.cleanBlockXML_(b.oldXml),-1==a.contents_.indexOf(b)&&(a.contents_.unshift(b),a.contents_.length>a.workspace_.options.maxTrashcanContents&&a.contents_.splice(a.workspace_.options.maxTrashcanContents,a.contents_.length-a.workspace_.options.maxTrashcanContents),a.hasBlocks_=!0,a.minOpenness_=a.HAS_BLOCKS_LID_ANGLE,a.setLidAngle_(45*a.minOpenness_)))}}; -Blockly.Trashcan.prototype.cleanBlockXML_=function(a){for(var b=a=a.cloneNode(!0);b;){b.removeAttribute&&(b.removeAttribute("x"),b.removeAttribute("y"),b.removeAttribute("id"));var c=b.firstChild||b.nextSibling;if(!c)for(c=b.parentNode;c;){if(c.nextSibling){c=c.nextSibling;break}c=c.parentNode}b=c}return""+Blockly.Xml.domToText(a)+""};Blockly.VariableModel=function(a,b,c,d){this.workspace=a;this.name=b;this.type=c||"";this.id_=d||Blockly.utils.genUid();Blockly.Events.fire(new Blockly.Events.VarCreate(this))};Blockly.VariableModel.prototype.getId=function(){return this.id_};Blockly.VariableModel.compareByName=function(a,b){a=a.name.toLowerCase();b=b.name.toLowerCase();return a=a.workspace_.options.maxTrashcanContents||b.type!=Blockly.Events.BLOCK_DELETE||"shadow"==b.oldXml.tagName.toLowerCase()||(b=a.cleanBlockXML_(b.oldXml),-1==a.contents_.indexOf(b)&&(a.contents_.unshift(b),a.contents_.length>a.workspace_.options.maxTrashcanContents&&a.contents_.splice(a.workspace_.options.maxTrashcanContents,a.contents_.length-a.workspace_.options.maxTrashcanContents),a.hasBlocks_=!0,a.minOpenness_=a.HAS_BLOCKS_LID_ANGLE, +a.setLidAngle_(45*a.minOpenness_)))}};Blockly.Trashcan.prototype.cleanBlockXML_=function(a){for(var b=a=a.cloneNode(!0);b;){b.removeAttribute&&(b.removeAttribute("x"),b.removeAttribute("y"),b.removeAttribute("id"));var c=b.firstChild||b.nextSibling;if(!c)for(c=b.parentNode;c;){if(c.nextSibling){c=c.nextSibling;break}c=c.parentNode}b=c}return""+Blockly.Xml.domToText(a)+""};Blockly.VariableModel=function(a,b,c,d){this.workspace=a;this.name=b;this.type=c||"";this.id_=d||Blockly.utils.genUid();Blockly.Events.fire(new Blockly.Events.VarCreate(this))};Blockly.VariableModel.prototype.getId=function(){return this.id_};Blockly.VariableModel.compareByName=function(a,b){a=a.name.toLowerCase();b=b.name.toLowerCase();return a=this.remainingCapacity()||(this.currentGesture_&&this.currentGesture_.cancel(),"comment"==a.tagName.toLowerCase()?this.pasteWorkspaceComment_(a):this.pasteBlock_(a))}; -Blockly.WorkspaceSvg.prototype.pasteBlock_=function(a){Blockly.Events.disable();try{var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(d)){this.RTL&&(c=-c);do{a=!1;for(var e=this.getAllBlocks(!1),f=0,g;g=e[f];f++){var h=g.getRelativeToSurfaceXY();if(1>=Math.abs(c-h.x)&&1>=Math.abs(d-h.y)){a=!0;break}}if(!a){var k=b.getConnections_(!1);f=0;for(var l;l=k[f];f++)if(l.closest(Blockly.SNAP_RADIUS,new goog.math.Coordinate(c,d)).connection){a= -!0;break}}a&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,d+=2*Blockly.SNAP_RADIUS)}while(a);b.moveBy(c,d)}}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(b));b.select()}; +Blockly.WorkspaceSvg.prototype.pasteBlock_=function(a){Blockly.Events.disable();try{var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(d)){this.RTL&&(c=-c);do{a=!1;for(var e=this.getAllBlocks(!1),f=0,g;g=e[f];f++){var h=g.getRelativeToSurfaceXY();if(1>=Math.abs(c-h.x)&&1>=Math.abs(d-h.y)){a=!0;break}}if(!a){var k=b.getConnections_(!1);f=0;for(var l;l=k[f];f++)if(l.closest(Blockly.SNAP_RADIUS,new Blockly.utils.Coordinate(c, +d)).connection){a=!0;break}}a&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,d+=2*Blockly.SNAP_RADIUS)}while(a);b.moveBy(c,d)}}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(b));b.select()}; Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_=function(a){Blockly.Events.disable();try{var b=Blockly.WorkspaceCommentSvg.fromXml(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);isNaN(c)||isNaN(d)||(this.RTL&&(c=-c),b.moveBy(c+50,d+50))}finally{Blockly.Events.enable()}Blockly.Events.isEnabled();b.select()}; Blockly.WorkspaceSvg.prototype.refreshToolboxSelection=function(){var a=this.isFlyout?this.targetWorkspace:this;a&&!a.currentGesture_&&a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.refreshSelection()};Blockly.WorkspaceSvg.prototype.renameVariableById=function(a,b){Blockly.WorkspaceSvg.superClass_.renameVariableById.call(this,a,b);this.refreshToolboxSelection()};Blockly.WorkspaceSvg.prototype.deleteVariableById=function(a){Blockly.WorkspaceSvg.superClass_.deleteVariableById.call(this,a);this.refreshToolboxSelection()}; Blockly.WorkspaceSvg.prototype.createVariable=function(a,b,c){a=Blockly.WorkspaceSvg.superClass_.createVariable.call(this,a,b,c);this.refreshToolboxSelection();return a};Blockly.WorkspaceSvg.prototype.recordDeleteAreas=function(){this.deleteAreaTrash_=this.trashcan&&this.svgGroup_.parentNode?this.trashcan.getClientRect():null;this.deleteAreaToolbox_=this.flyout_?this.flyout_.getClientRect():this.toolbox_?this.toolbox_.getClientRect():null}; -Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){a=new goog.math.Coordinate(a.clientX,a.clientY);return this.deleteAreaTrash_&&this.deleteAreaTrash_.contains(a)?Blockly.DELETE_AREA_TRASH:this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a)?Blockly.DELETE_AREA_TOOLBOX:Blockly.DELETE_AREA_NONE};Blockly.WorkspaceSvg.prototype.onMouseDown_=function(a){var b=this.getGesture(a);b&&b.handleWsStart(a,this)}; -Blockly.WorkspaceSvg.prototype.startDrag=function(a,b){a=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;this.dragDeltaXY_=goog.math.Coordinate.difference(b,a)};Blockly.WorkspaceSvg.prototype.moveDrag=function(a){a=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;return goog.math.Coordinate.sum(this.dragDeltaXY_,a)}; +Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){return this.deleteAreaTrash_&&this.deleteAreaTrash_.contains(a.clientX,a.clientY)?Blockly.DELETE_AREA_TRASH:this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a.clientX,a.clientY)?Blockly.DELETE_AREA_TOOLBOX:Blockly.DELETE_AREA_NONE};Blockly.WorkspaceSvg.prototype.onMouseDown_=function(a){var b=this.getGesture(a);b&&b.handleWsStart(a,this)}; +Blockly.WorkspaceSvg.prototype.startDrag=function(a,b){a=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;this.dragDeltaXY_=Blockly.utils.Coordinate.difference(b,a)};Blockly.WorkspaceSvg.prototype.moveDrag=function(a){a=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;return Blockly.utils.Coordinate.sum(this.dragDeltaXY_,a)}; Blockly.WorkspaceSvg.prototype.isDragging=function(){return null!=this.currentGesture_&&this.currentGesture_.isDragging()};Blockly.WorkspaceSvg.prototype.isDraggable=function(){return this.options.moveOptions&&this.options.moveOptions.drag}; Blockly.WorkspaceSvg.prototype.isContentBounded=function(){return this.options.moveOptions&&this.options.moveOptions.scrollbars||this.options.moveOptions&&this.options.moveOptions.wheel||this.options.moveOptions&&this.options.moveOptions.drag||this.options.zoomOptions&&this.options.zoomOptions.controls||this.options.zoomOptions&&this.options.zoomOptions.wheel}; Blockly.WorkspaceSvg.prototype.isMovable=function(){return this.options.moveOptions&&this.options.moveOptions.scrollbars||this.options.moveOptions&&this.options.moveOptions.wheel||this.options.moveOptions&&this.options.moveOptions.drag||this.options.zoomOptions&&this.options.zoomOptions.wheel}; @@ -1418,7 +1421,7 @@ Blockly.Warning.textToDom_=function(a){var b=Blockly.utils.createSvgElement("tex Blockly.Warning.prototype.setVisible=function(a){if(a!=this.isVisible())if(Blockly.Events.fire(new Blockly.Events.Ui(this.block_,"warningOpen",!a,a)),a){a=Blockly.Warning.textToDom_(this.getText());this.bubble_=new Blockly.Bubble(this.block_.workspace,a,this.block_.svgPath_,this.iconXY_,null,null);this.bubble_.setSvgId(this.block_.id);if(this.block_.RTL)for(var b=a.getBBox().width,c=0,d;d=a.childNodes[c];c++)d.setAttribute("text-anchor","end"),d.setAttribute("x",b+Blockly.Bubble.BORDER_WIDTH);this.updateColour(); a=this.bubble_.getBubbleSize();this.bubble_.setBubbleSize(a.width,a.height)}else this.bubble_.dispose(),this.body_=this.bubble_=null};Blockly.Warning.prototype.bodyFocus_=function(a){this.bubble_.promote_()};Blockly.Warning.prototype.setText=function(a,b){this.text_[b]!=a&&(a?this.text_[b]=a:delete this.text_[b],this.isVisible()&&(this.setVisible(!1),this.setVisible(!0)))};Blockly.Warning.prototype.getText=function(){var a=[],b;for(b in this.text_)a.push(this.text_[b]);return a.join("\n")}; Blockly.Warning.prototype.dispose=function(){this.block_.warning=null;Blockly.Icon.prototype.dispose.call(this)};Blockly.Block=function(a,b,c){if("undefined"!==typeof Blockly.Generator.prototype[b])throw Error('Block prototypeName "'+b+'" conflicts with Blockly.Generator members.');this.id=c&&!a.getBlockById(c)?c:Blockly.utils.genUid();a.blockDB_[this.id]=this;this.previousConnection=this.nextConnection=this.outputConnection=null;this.inputList=[];this.inputsInline=void 0;this.disabled=!1;this.tooltip="";this.contextMenu=!0;this.parentBlock_=null;this.childBlocks_=[];this.editable_=this.movable_=this.deletable_= -!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new goog.math.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;this.hat=void 0;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);a.addTypedBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a= +!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new Blockly.utils.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;this.hat=void 0;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);a.addTypedBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a= Blockly.Events.getGroup())||Blockly.Events.setGroup(!0);try{Blockly.Events.fire(new Blockly.Events.BlockCreate(this))}finally{a||Blockly.Events.setGroup(!1)}}"function"==typeof this.onchange&&this.setOnChange(this.onchange)};Blockly.Block.obtain=function(a,b){console.warn("Deprecated call to Blockly.Block.obtain, use workspace.newBlock instead.");return a.newBlock(b)};Blockly.Block.prototype.data=null;Blockly.Block.prototype.hue_=null;Blockly.Block.prototype.colour_="#000000"; Blockly.Block.prototype.colourSecondary_=null;Blockly.Block.prototype.colourTertiary_=null;Blockly.Block.prototype.styleName_=null; Blockly.Block.prototype.dispose=function(a){if(this.workspace){this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);this.unplug(a);Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockDelete(this));Blockly.Events.disable();try{this.workspace&&(this.workspace.removeTopBlock(this),this.workspace.removeTypedBlock(this),delete this.workspace.blockDB_[this.id],this.workspace=null);Blockly.selected==this&&(Blockly.selected=null);for(var b=this.childBlocks_.length- @@ -1475,20 +1478,20 @@ Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Even Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; -Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/ -a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= +Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new Blockly.utils.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=Blockly.utils.Coordinate.difference(e,f); +e.scale(1/a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= Blockly.utils.is3dSupported()&&!!a.blockDragSurface_;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,a,b,c);this.svgGroup_.dataset&&(this.svgGroup_.dataset.id=this.id)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.prototype.warningTextDb_=null;Blockly.BlockSvg.INLINE=-1;Blockly.BlockSvg.COLLAPSED_WARNING_ID="TEMP_COLLAPSED_WARNING_"; Blockly.BlockSvg.prototype.initSvg=function(){if(!this.workspace.rendered)throw TypeError("Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;a90-b||a>-90-b&&a<-90+b?!0:!1}; -Blockly.HorizontalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.top;a=a.height;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_TOP)return new goog.math.Rect(-1E9,b-1E9,2E9,1E9+a);if(this.toolboxPosition_==Blockly.TOOLBOX_AT_BOTTOM)return new goog.math.Rect(-1E9,b,2E9,1E9+a)}; +Blockly.HorizontalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.top;a=a.height;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_TOP)return new Blockly.utils.Rect(-1E9,b-1E9,2E9,1E9+a);if(this.toolboxPosition_==Blockly.TOOLBOX_AT_BOTTOM)return new Blockly.utils.Rect(-1E9,b,2E9,1E9+a)}; Blockly.HorizontalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++)a=Math.max(a,d.getHeightWidth().height);a+=1.5*this.MARGIN;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.height_!=a){for(c=0;d=b[c];c++)d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);this.height_=a;this.position()}};Blockly.VerticalFlyout=function(a){a.getMetrics=this.getMetrics_.bind(this);a.setMetrics=this.setMetrics_.bind(this);Blockly.VerticalFlyout.superClass_.constructor.call(this,a);this.horizontalLayout_=!1};goog.inherits(Blockly.VerticalFlyout,Blockly.Flyout); Blockly.VerticalFlyout.prototype.getMetrics_=function(){if(!this.isVisible())return null;try{var a=this.workspace_.getCanvas().getBBox()}catch(e){a={height:0,y:0,width:0,x:0}}var b=this.SCROLLBAR_PADDING,c=this.height_-2*this.SCROLLBAR_PADDING,d=this.width_;this.RTL||(d-=this.SCROLLBAR_PADDING);return{viewHeight:c,viewWidth:d,contentHeight:a.height*this.workspace_.scale+2*this.MARGIN,contentWidth:a.width*this.workspace_.scale+2*this.MARGIN,viewTop:-this.workspace_.scrollY+a.y,viewLeft:-this.workspace_.scrollX, contentTop:a.y,contentLeft:a.x,absoluteTop:b,absoluteLeft:0}};Blockly.VerticalFlyout.prototype.setMetrics_=function(a){var b=this.getMetrics_();b&&("number"==typeof a.y&&(this.workspace_.scrollY=-b.contentHeight*a.y),this.workspace_.translate(this.workspace_.scrollX+b.absoluteLeft,this.workspace_.scrollY+b.absoluteTop))}; @@ -1717,7 +1720,7 @@ Blockly.VerticalFlyout.prototype.setBackgroundPath_=function(a,b){var c=this.too d.join(" "))};Blockly.VerticalFlyout.prototype.scrollToStart=function(){this.scrollbar_.set(0)};Blockly.VerticalFlyout.prototype.wheel_=function(a){var b=Blockly.utils.getScrollDeltaPixels(a);if(b.y){var c=this.getMetrics_();b=c.viewTop-c.contentTop+b.y;b=Math.min(b,c.contentHeight-c.viewHeight);b=Math.max(b,0);this.scrollbar_.set(b);Blockly.WidgetDiv.hide()}a.preventDefault();a.stopPropagation()}; Blockly.VerticalFlyout.prototype.layout_=function(a,b){this.workspace_.scale=this.targetWorkspace_.scale;for(var c=this.MARGIN,d=this.RTL?c:c+Blockly.BlockSvg.TAB_WIDTH,e=0,f;f=a[e];e++)if("block"==f.type){f=f.block;for(var g=f.getDescendants(!1),h=0,k;k=g[h];h++)k.isInFlyout=!0;f.render();g=f.getSvgRoot();h=f.getHeightWidth();f.moveBy(d,c);k=this.createRect_(f,this.RTL?d-h.width:d,c,h,e);this.addBlockListeners_(g,f,k);c+=h.height+b[e]}else"button"==f.type&&(this.initFlyoutButton_(f.button,d,c),c+= f.button.height+b[e])};Blockly.VerticalFlyout.prototype.isDragTowardWorkspace=function(a){a=Math.atan2(a.y,a.x)/Math.PI*180;var b=this.dragAngleRange_;return a-b||a<-180+b||a>180-b?!0:!1}; -Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new goog.math.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new goog.math.Rect(b, +Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new Blockly.utils.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new Blockly.utils.Rect(b, -1E9,1E9+a,2E9)}; Blockly.VerticalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);a=Math.max(a,e)}for(c=0;d=this.buttons_[c];c++)a=Math.max(a,d.width);a+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=a){for(c=0;d=b[c];c++)this.RTL&&(e=d.getRelativeToSurfaceXY().x, d.moveBy(a/this.workspace_.scale-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH-e,0)),d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);if(this.RTL)for(c=0;d=this.buttons_[c];c++)b=d.getPosition().y,d.moveTo(a/this.workspace_.scale-d.width-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH,b);this.width_=a;this.position()}};Blockly.Toolbox=function(a){this.workspace_=a;this.RTL=a.options.RTL;this.horizontalLayout_=a.options.horizontalLayout;this.toolboxPosition=a.options.toolboxPosition;this.config_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"};this.treeSeparatorConfig_={cssTreeRow:"blocklyTreeSeparator"}; @@ -1735,9 +1738,9 @@ Blockly.Toolbox.prototype.setColourFromStyle_=function(a,b,c){if((b.styleName=a) Blockly.Toolbox.prototype.updateColourFromTheme=function(){var a=this.tree_;a&&(this.updateColourFromTheme_(a),this.updateSelectedItemColour_(a))};Blockly.Toolbox.prototype.updateSelectedItemColour_=function(a){var b=a.selectedItem_;if(b){var c=b.hexColour||"#57e";b.getRowElement().style.backgroundColor=c;a.toolbox_.addColour_(b)}}; Blockly.Toolbox.prototype.addColour_=function(a){a=(a||this.tree_).getChildren(!1);for(var b=0,c;c=a[b];b++){var d=c.getRowElement();if(d){var e=this.hasColours_?"8px solid "+(c.hexColour||"#ddd"):"none";this.workspace_.RTL?d.style.borderRight=e:d.style.borderLeft=e}this.addColour_(c)}};Blockly.Toolbox.prototype.clearSelection=function(){this.tree_.setSelectedItem(null)};Blockly.Toolbox.prototype.addStyle=function(a){Blockly.utils.addClass(this.HtmlDiv,a)}; Blockly.Toolbox.prototype.removeStyle=function(a){Blockly.utils.removeClass(this.HtmlDiv,a)}; -Blockly.Toolbox.prototype.getClientRect=function(){if(!this.HtmlDiv)return null;var a=this.HtmlDiv.getBoundingClientRect(),b=a.left,c=a.top,d=a.width;a=a.height;return this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT?new goog.math.Rect(-1E7,-1E7,1E7+b+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?new goog.math.Rect(b,-1E7,1E7+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?new goog.math.Rect(-1E7,-1E7,2E7,1E7+c+a):new goog.math.Rect(0,c,2E7,1E7+d)}; +Blockly.Toolbox.prototype.getClientRect=function(){if(!this.HtmlDiv)return null;var a=this.HtmlDiv.getBoundingClientRect(),b=a.left,c=a.top,d=a.width;a=a.height;return this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT?new Blockly.utils.Rect(-1E7,-1E7,1E7+b+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?new Blockly.utils.Rect(b,-1E7,1E7+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?new Blockly.utils.Rect(-1E7,-1E7,2E7,1E7+c+a):new Blockly.utils.Rect(0,c,2E7,1E7+d)}; Blockly.Toolbox.prototype.refreshSelection=function(){var a=this.tree_.getSelectedItem();a&&a.blocks&&this.flyout_.show(a.blocks)};Blockly.Toolbox.TreeControl=function(a,b){this.toolbox_=a;goog.ui.tree.TreeControl.call(this,goog.html.SafeHtml.EMPTY,b)};goog.inherits(Blockly.Toolbox.TreeControl,goog.ui.tree.TreeControl); -Blockly.Toolbox.TreeControl.prototype.enterDocument=function(){Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this);if(goog.events.BrowserFeature.TOUCH_ENABLED){var a=this.getElement();Blockly.bindEventWithChecks_(a,goog.events.EventType.TOUCHEND,this,this.handleTouchEvent_)}};Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_=function(a){var b=this.getNodeFromEvent_(a);b&&a.type===goog.events.EventType.TOUCHEND&&setTimeout(function(){b.onClick_(a)},1)}; +Blockly.Toolbox.TreeControl.prototype.enterDocument=function(){Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this);if(Blockly.Touch.TOUCH_ENABLED){var a=this.getElement();Blockly.bindEventWithChecks_(a,goog.events.EventType.TOUCHEND,this,this.handleTouchEvent_)}};Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_=function(a){var b=this.getNodeFromEvent_(a);b&&a.type===goog.events.EventType.TOUCHEND&&setTimeout(function(){b.onClick_(a)},1)}; Blockly.Toolbox.TreeControl.prototype.createNode=function(a){a=a?goog.html.SafeHtml.htmlEscape(a):goog.html.SafeHtml.EMPTY;return new Blockly.Toolbox.TreeNode(this.toolbox_,a,this.getConfig())}; Blockly.Toolbox.TreeControl.prototype.setSelectedItem=function(a){var b=this.toolbox_;if(a!=this.selectedItem_&&a!=b.tree_){b.lastCategory_&&(b.lastCategory_.getRowElement().style.backgroundColor="");if(a){var c=a.hexColour||"#57e";a.getRowElement().style.backgroundColor=c;b.addColour_(a)}c=this.getSelectedItem();goog.ui.tree.TreeControl.prototype.setSelectedItem.call(this,a);a&&a.blocks&&a.blocks.length?(b.flyout_.show(a.blocks),b.lastCategory_!=a&&b.flyout_.scrollToStart()):b.flyout_.hide();c!= a&&c!=this&&(c=new Blockly.Events.Ui(null,"category",c&&c.getHtml(),a&&a.getHtml()),c.workspaceId=b.workspace_.id,Blockly.Events.fire(c));a&&(b.lastCategory_=a)}};Blockly.Toolbox.TreeNode=function(a,b,c){goog.ui.tree.TreeNode.call(this,b,c);a&&(b=function(){Blockly.svgResize(a.workspace_)},goog.events.listen(a.tree_,goog.ui.tree.BaseNode.EventType.EXPAND,b),goog.events.listen(a.tree_,goog.ui.tree.BaseNode.EventType.COLLAPSE,b))};goog.inherits(Blockly.Toolbox.TreeNode,goog.ui.tree.TreeNode); @@ -1780,9 +1783,9 @@ Blockly.WidgetDiv.hide=function(){Blockly.WidgetDiv.owner_&&(Blockly.WidgetDiv.o Blockly.WidgetDiv.positionInternal_=function(a,b,c){Blockly.WidgetDiv.DIV.style.left=a+"px";Blockly.WidgetDiv.DIV.style.top=b+"px";Blockly.WidgetDiv.DIV.style.height=c+"px"};Blockly.WidgetDiv.positionWithAnchor=function(a,b,c,d){var e=Blockly.WidgetDiv.calculateY_(a,b,c);a=Blockly.WidgetDiv.calculateX_(a,b,c,d);0>e?Blockly.WidgetDiv.positionInternal_(a,0,c.height+e):Blockly.WidgetDiv.positionInternal_(a,e,c.height)}; Blockly.WidgetDiv.calculateX_=function(a,b,c,d){if(d)return b=Math.max(b.right-c.width,a.left),Math.min(b,a.right-c.width);b=Math.min(b.left,a.right-c.width);return Math.max(b,a.left)};Blockly.WidgetDiv.calculateY_=function(a,b,c){return b.bottom+c.height>=a.bottom?b.top-c.height:b.bottom};Blockly.BlockDragSurfaceSvg=function(a){this.container_=a;this.createDom()};Blockly.BlockDragSurfaceSvg.prototype.SVG_=null;Blockly.BlockDragSurfaceSvg.prototype.dragGroup_=null;Blockly.BlockDragSurfaceSvg.prototype.container_=null;Blockly.BlockDragSurfaceSvg.prototype.scale_=1;Blockly.BlockDragSurfaceSvg.prototype.surfaceXY_=null; Blockly.BlockDragSurfaceSvg.prototype.createDom=function(){this.SVG_||(this.SVG_=Blockly.utils.createSvgElement("svg",{xmlns:Blockly.SVG_NS,"xmlns:html":Blockly.HTML_NS,"xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklyBlockDragSurface"},this.container_),this.dragGroup_=Blockly.utils.createSvgElement("g",{},this.SVG_))}; -Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow=function(a){if(this.dragGroup_.childNodes.length)throw Error("Already dragging a block.");this.dragGroup_.appendChild(a);this.SVG_.style.display="block";this.surfaceXY_=new goog.math.Coordinate(0,0)};Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup=function(a,b,c){this.scale_=c;a=a.toFixed(0);b=b.toFixed(0);this.dragGroup_.setAttribute("transform","translate("+a+","+b+") scale("+c+")")}; -Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_=function(){var a=this.surfaceXY_.x,b=this.surfaceXY_.y;a=a.toFixed(0);b=b.toFixed(0);this.SVG_.style.display="block";Blockly.utils.setCssTransform(this.SVG_,"translate3d("+a+"px, "+b+"px, 0px)")};Blockly.BlockDragSurfaceSvg.prototype.translateSurface=function(a,b){this.surfaceXY_=new goog.math.Coordinate(a*this.scale_,b*this.scale_);this.translateSurfaceInternal_()}; -Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation=function(){var a=Blockly.utils.getRelativeXY(this.SVG_);return new goog.math.Coordinate(a.x/this.scale_,a.y/this.scale_)};Blockly.BlockDragSurfaceSvg.prototype.getGroup=function(){return this.dragGroup_};Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock=function(){return this.dragGroup_.firstChild}; +Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow=function(a){if(this.dragGroup_.childNodes.length)throw Error("Already dragging a block.");this.dragGroup_.appendChild(a);this.SVG_.style.display="block";this.surfaceXY_=new Blockly.utils.Coordinate(0,0)};Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup=function(a,b,c){this.scale_=c;a=a.toFixed(0);b=b.toFixed(0);this.dragGroup_.setAttribute("transform","translate("+a+","+b+") scale("+c+")")}; +Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_=function(){var a=this.surfaceXY_.x,b=this.surfaceXY_.y;a=a.toFixed(0);b=b.toFixed(0);this.SVG_.style.display="block";Blockly.utils.setCssTransform(this.SVG_,"translate3d("+a+"px, "+b+"px, 0px)")};Blockly.BlockDragSurfaceSvg.prototype.translateSurface=function(a,b){this.surfaceXY_=new Blockly.utils.Coordinate(a*this.scale_,b*this.scale_);this.translateSurfaceInternal_()}; +Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation=function(){var a=Blockly.utils.getRelativeXY(this.SVG_);return new Blockly.utils.Coordinate(a.x/this.scale_,a.y/this.scale_)};Blockly.BlockDragSurfaceSvg.prototype.getGroup=function(){return this.dragGroup_};Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock=function(){return this.dragGroup_.firstChild}; Blockly.BlockDragSurfaceSvg.prototype.clearAndHide=function(a){a?a.appendChild(this.getCurrentBlock()):this.dragGroup_.removeChild(this.getCurrentBlock());this.SVG_.style.display="none";if(this.dragGroup_.childNodes.length)throw Error("Drag group was not cleared.");this.surfaceXY_=null};Blockly.inject=function(a,b){Blockly.checkBlockColourConstants();"string"==typeof a&&(a=document.getElementById(a)||document.querySelector(a));if(!Blockly.utils.containsNode(document,a))throw Error("Error: container is not in current document.");b=new Blockly.Options(b||{});var c=document.createElement("div");c.className="injectionDiv";a.appendChild(c);a=Blockly.createDom_(c,b);var d=new Blockly.BlockDragSurfaceSvg(c);c=new Blockly.WorkspaceDragSurfaceSvg(c);c=Blockly.createMainWorkspace_(a,b,d,c); Blockly.setTheme(b.theme);Blockly.init_(c);Blockly.mainWorkspace=c;Blockly.svgResize(c);return c}; Blockly.createDom_=function(a,b){a.setAttribute("dir","LTR");goog.ui.Component.setDefaultRightToLeft(b.RTL);Blockly.Css.inject(b.hasCss,b.pathToMedia);a=Blockly.utils.createSvgElement("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:html":"http://www.w3.org/1999/xhtml","xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklySvg"},a);var c=Blockly.utils.createSvgElement("defs",{},a),d=String(Math.random()).substring(2),e=Blockly.utils.createSvgElement("filter",{id:"blocklyEmbossFilter"+ diff --git a/blockly_accessible_uncompressed.js b/blockly_accessible_uncompressed.js index 813e1f721ca..437723c52d8 100644 --- a/blockly_accessible_uncompressed.js +++ b/blockly_accessible_uncompressed.js @@ -60,22 +60,22 @@ goog.addDependency("../../../" + dir + "/accessible/variable-remove-modal.compon goog.addDependency("../../../" + dir + "/accessible/variable-rename-modal.component.js", ['blocklyApp.VariableRenameModalComponent'], ['Blockly.CommonModal', 'blocklyApp.AudioService', 'blocklyApp.KeyboardInputService', 'blocklyApp.TranslatePipe', 'blocklyApp.VariableModalService']); goog.addDependency("../../../" + dir + "/accessible/workspace-block.component.js", ['blocklyApp.WorkspaceBlockComponent'], ['blocklyApp.UtilsService', 'blocklyApp.AudioService', 'blocklyApp.BlockConnectionService', 'blocklyApp.FieldSegmentComponent', 'blocklyApp.TranslatePipe', 'blocklyApp.TreeService']); goog.addDependency("../../../" + dir + "/accessible/workspace.component.js", ['blocklyApp.WorkspaceComponent'], ['blocklyApp.NotificationsService', 'blocklyApp.ToolboxModalService', 'blocklyApp.TranslatePipe', 'blocklyApp.TreeService', 'blocklyApp.WorkspaceBlockComponent']); -goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.utils', 'Blockly.Warning', 'Blockly.Workspace', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.utils', 'Blockly.Warning', 'Blockly.Workspace']); goog.addDependency("../../../" + dir + "/core/block_animations.js", ['Blockly.BlockAnimations'], ['Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.InsertionMarkerManager', 'Blockly.Events', 'Blockly.Events.BlockMove', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils.Coordinate', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.utils.Coordinate', 'Blockly.InsertionMarkerManager', 'Blockly.Events', 'Blockly.Events.BlockMove']); +goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []); -goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.Workspace', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.Workspace']); +goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg']); goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']); goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []); -goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.math.Coordinate', 'goog.ui.Menu', 'goog.ui.MenuItem']); +goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []); goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/dropdowndiv.js", ['Blockly.DropDownDiv'], ['Blockly.utils', 'goog.style']); @@ -92,17 +92,17 @@ goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldIm goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.FieldTextInput']); -goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.utils.Coordinate', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.utils', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'goog.math.Size']); -goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); +goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils.Coordinate', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.FlyoutDragger'], ['Blockly.WorkspaceDragger']); -goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'goog.math.Rect']); -goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'goog.math.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'Blockly.utils.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.Rect']); goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block']); -goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger']); goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.userAgent', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils.Coordinate', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.Tooltip', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../../" + dir + "/core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.BlockAnimations', 'Blockly.Events', 'Blockly.RenderedConnection']); @@ -111,22 +111,24 @@ goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], goog.addDependency("../../../" + dir + "/core/names.js", ['Blockly.Names'], []); goog.addDependency("../../../" + dir + "/core/options.js", ['Blockly.Options'], ['Blockly.Xml', 'Blockly.Themes.Classic']); goog.addDependency("../../../" + dir + "/core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.Xml.utils']); -goog.addDependency("../../../" + dir + "/core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.utils', 'goog.events.BrowserFeature', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/theme.js", ['Blockly.Theme'], []); goog.addDependency("../../../" + dir + "/core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); goog.addDependency("../../../" + dir + "/core/theme/highcontrast.js", ['Blockly.Themes.HighContrast'], ['Blockly.Theme']); goog.addDependency("../../../" + dir + "/core/theme/modern.js", ['Blockly.Themes.Modern'], ['Blockly.Theme']); -goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Flyout', 'Blockly.HorizontalFlyout', 'Blockly.Touch', 'Blockly.utils', 'Blockly.VerticalFlyout', 'goog.events', 'goog.events.BrowserFeature', 'goog.events.EventType', 'goog.html.SafeHtml', 'goog.math.Rect', 'goog.ui.tree.BaseNode', 'goog.ui.tree.TreeControl', 'goog.ui.tree.TreeNode']); +goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Flyout', 'Blockly.HorizontalFlyout', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.VerticalFlyout', 'goog.events', 'goog.events.EventType', 'goog.html.SafeHtml', 'goog.ui.tree.BaseNode', 'goog.ui.tree.TreeControl', 'goog.ui.tree.TreeNode']); goog.addDependency("../../../" + dir + "/core/tooltip.js", ['Blockly.Tooltip'], ['Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/touch.js", ['Blockly.Touch'], ['Blockly.utils', 'goog.events.BrowserFeature']); -goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.TouchGesture'], ['Blockly.Gesture', 'Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'Blockly.Xml', 'goog.math.Rect']); +goog.addDependency("../../../" + dir + "/core/touch.js", ['Blockly.Touch'], ['Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.TouchGesture'], ['Blockly.utils.Coordinate', 'Blockly.Gesture', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'Blockly.utils.Rect', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], ['goog.style']); goog.addDependency("../../../" + dir + "/core/useragent.js", ['Blockly.userAgent'], []); -goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.Msg', 'Blockly.userAgent', 'goog.math.Coordinate', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.utils.Coordinate', 'Blockly.Msg', 'Blockly.userAgent', 'goog.style']); goog.addDependency("../../../" + dir + "/core/utils_colour.js", ['Blockly.utils.colour'], ['Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/utils_coordinate.js", ['Blockly.utils.Coordinate'], []); +goog.addDependency("../../../" + dir + "/core/utils_rect.js", ['Blockly.utils.Rect'], []); goog.addDependency("../../../" + dir + "/core/variable_events.js", ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/variable_map.js", ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/variable_model.js", ['Blockly.VariableModel'], ['Blockly.Events', 'Blockly.Events.VarCreate', 'Blockly.utils']); @@ -136,14 +138,14 @@ goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.style']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.Events', 'Blockly.utils', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']); goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.userAgent']); -goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.WorkspaceComment', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils']); +goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils.Coordinate', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg']); +goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.WorkspaceComment']); goog.addDependency("../../../" + dir + "/core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']); goog.addDependency("../../../" + dir + "/core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract']); -goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.utils', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.dom', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.Xml.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.utils', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls']); +goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.utils', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/xml_utils.js", ['Blockly.Xml.utils'], []); goog.addDependency("../../../" + dir + "/core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Touch', 'Blockly.utils']); @@ -1873,6 +1875,8 @@ goog.require('Blockly.constants'); goog.require('Blockly.inject'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.Rect'); goog.require('Blockly.utils.colour'); goog.require('Blockly.utils.uiMenu'); goog.require('blocklyApp.AppComponent'); diff --git a/blockly_compressed.js b/blockly_compressed.js index 69afca47f3d..e91b797a52b 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -80,7 +80,9 @@ goog.asserts.assertString=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isS goog.asserts.assertObject=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isObject(a)&&goog.asserts.doAssertFailure_("Expected object but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a};goog.asserts.assertArray=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isArray(a)&&goog.asserts.doAssertFailure_("Expected array but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a}; goog.asserts.assertBoolean=function(a,b,c){goog.asserts.ENABLE_ASSERTS&&!goog.isBoolean(a)&&goog.asserts.doAssertFailure_("Expected boolean but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a};goog.asserts.assertElement=function(a,b,c){!goog.asserts.ENABLE_ASSERTS||goog.isObject(a)&&a.nodeType==goog.dom.NodeType.ELEMENT||goog.asserts.doAssertFailure_("Expected Element but got %s: %s.",[goog.typeOf(a),a],b,Array.prototype.slice.call(arguments,2));return a}; goog.asserts.assertInstanceof=function(a,b,c,d){!goog.asserts.ENABLE_ASSERTS||a instanceof b||goog.asserts.doAssertFailure_("Expected instanceof %s but got %s.",[goog.asserts.getType_(b),goog.asserts.getType_(a)],c,Array.prototype.slice.call(arguments,3));return a};goog.asserts.assertFinite=function(a,b,c){!goog.asserts.ENABLE_ASSERTS||"number"==typeof a&&isFinite(a)||goog.asserts.doAssertFailure_("Expected %s to be a finite number but it is not.",[a],b,Array.prototype.slice.call(arguments,2));return a}; -goog.asserts.assertObjectPrototypeIsIntact=function(){for(var a in Object.prototype)goog.asserts.fail(a+" should not be enumerable in Object.prototype.")};goog.asserts.getType_=function(a){return a instanceof Function?a.displayName||a.name||"unknown type name":a instanceof Object?a.constructor.displayName||a.constructor.name||Object.prototype.toString.call(a):null===a?"null":typeof a};goog.array={};goog.NATIVE_ARRAY_PROTOTYPES=goog.TRUSTED_SITE;goog.array.ASSUME_NATIVE_FUNCTIONS=!1;goog.array.peek=function(a){return a[a.length-1]};goog.array.last=goog.array.peek; +goog.asserts.assertObjectPrototypeIsIntact=function(){for(var a in Object.prototype)goog.asserts.fail(a+" should not be enumerable in Object.prototype.")};goog.asserts.getType_=function(a){return a instanceof Function?a.displayName||a.name||"unknown type name":a instanceof Object?a.constructor.displayName||a.constructor.name||Object.prototype.toString.call(a):null===a?"null":typeof a};goog.debug.entryPointRegistry={};goog.debug.EntryPointMonitor=function(){};goog.debug.entryPointRegistry.refList_=[];goog.debug.entryPointRegistry.monitors_=[];goog.debug.entryPointRegistry.monitorsMayExist_=!1;goog.debug.entryPointRegistry.register=function(a){goog.debug.entryPointRegistry.refList_[goog.debug.entryPointRegistry.refList_.length]=a;if(goog.debug.entryPointRegistry.monitorsMayExist_)for(var b=goog.debug.entryPointRegistry.monitors_,c=0;cc?Math.max(0,a.length+c):c;if(goog.isString(a))return goog.isString(b)&&1==b.length?a.indexOf(b,c):-1;for(;cc&&(c=Math.max(0,a.length+c));if(goog.isString(a))return goog.isString(b)&&1==b.length?a.lastIndexOf(b,c):-1;for(;0<=c;c--)if(c in a&&a[c]===b)return c;return-1}; goog.array.forEach=goog.NATIVE_ARRAY_PROTOTYPES&&(goog.array.ASSUME_NATIVE_FUNCTIONS||Array.prototype.forEach)?function(a,b,c){goog.asserts.assert(null!=a.length);Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=goog.isString(a)?a.split(""):a,f=0;fb&&Array.prototype.push.apply(a,a.splice(0,-b)));return a};goog.array.moveItem=function(a,b,c){goog.asserts.assert(0<=b&&bc*b?c+b:c};goog.math.lerp=function(a,b,c){return a+c*(b-a)};goog.math.nearlyEquals=function(a,b,c){return Math.abs(a-b)<=(c||1E-6)};goog.math.standardAngle=function(a){return goog.math.modulo(a,360)}; -goog.math.standardAngleInRadians=function(a){return goog.math.modulo(a,2*Math.PI)};goog.math.toRadians=function(a){return a*Math.PI/180};goog.math.toDegrees=function(a){return 180*a/Math.PI};goog.math.angleDx=function(a,b){return b*Math.cos(goog.math.toRadians(a))};goog.math.angleDy=function(a,b){return b*Math.sin(goog.math.toRadians(a))};goog.math.angle=function(a,b,c,d){return goog.math.standardAngle(goog.math.toDegrees(Math.atan2(d-b,c-a)))}; -goog.math.angleDifference=function(a,b){var c=goog.math.standardAngle(b)-goog.math.standardAngle(a);180=c&&(c=360+c);return c};goog.math.sign=function(a){return 0a?-1:a}; -goog.math.longestCommonSubsequence=function(a,b,c,d){c=c||function(a,b){return a==b};d=d||function(b,c){return a[b]};for(var e=a.length,f=b.length,g=[],h=0;hg[h][k-1]?h--:k--;return l}; -goog.math.sum=function(a){return goog.array.reduce(arguments,function(a,c){return a+c},0)};goog.math.average=function(a){return goog.math.sum.apply(null,arguments)/arguments.length};goog.math.sampleVariance=function(a){var b=arguments.length;if(2>b)return 0;var c=goog.math.average.apply(null,arguments);return goog.math.sum.apply(null,goog.array.map(arguments,function(a){return Math.pow(a-c,2)}))/(b-1)};goog.math.standardDeviation=function(a){return Math.sqrt(goog.math.sampleVariance.apply(null,arguments))}; -goog.math.isInt=function(a){return isFinite(a)&&0==a%1};goog.math.isFiniteNumber=function(a){return isFinite(a)};goog.math.isNegativeZero=function(a){return 0==a&&0>1/a};goog.math.log10Floor=function(a){if(0a?1:0)}return 0==a?-Infinity:NaN};goog.math.safeFloor=function(a,b){goog.asserts.assert(!goog.isDef(b)||0":"
")}; goog.string.internal.htmlEscape=function(a,b){if(b)a=a.replace(goog.string.internal.AMP_RE_,"&").replace(goog.string.internal.LT_RE_,"<").replace(goog.string.internal.GT_RE_,">").replace(goog.string.internal.QUOT_RE_,""").replace(goog.string.internal.SINGLE_QUOTE_RE_,"'").replace(goog.string.internal.NULL_RE_,"�");else{if(!goog.string.internal.ALL_RE_.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(goog.string.internal.AMP_RE_,"&"));-1!=a.indexOf("<")&&(a=a.replace(goog.string.internal.LT_RE_, @@ -385,7 +375,17 @@ goog.events.protectBrowserEventEntryPoint=function(a){goog.events.handleBrowserE goog.events.handleBrowserEvent_=function(a,b){if(a.removed)return!0;if(!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT){var c=b||goog.getObjectByName("window.event"),d=new goog.events.BrowserEvent(c,this),e=!0;if(goog.events.CAPTURE_SIMULATION_MODE==goog.events.CaptureSimulationMode.ON){if(!goog.events.isMarkedIeEvent_(c)){goog.events.markIeEvent_(c);c=[];for(var f=d.currentTarget;f;f=f.parentNode)c.push(f);f=a.type;for(var g=c.length-1;!d.propagationStopped_&&0<=g;g--){d.currentTarget=c[g];var h= goog.events.fireListeners_(c[g],f,!0,d);e=e&&h}for(g=0;!d.propagationStopped_&&ga.keyCode||void 0!=a.returnValue}; goog.events.uniqueIdCounter_=0;goog.events.getUniqueId=function(a){return a+"_"+goog.events.uniqueIdCounter_++};goog.events.getListenerMap_=function(a){a=a[goog.events.LISTENER_MAP_PROP_];return a instanceof goog.events.ListenerMap?a:null};goog.events.LISTENER_WRAPPER_PROP_="__closure_events_fn_"+(1E9*Math.random()>>>0); -goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.dom.BrowserFeature={CAN_ADD_NAME_OR_TYPE_ATTRIBUTES:!goog.userAgent.IE||goog.userAgent.isDocumentModeOrHigher(9),CAN_USE_CHILDREN_ATTRIBUTE:!goog.userAgent.GECKO&&!goog.userAgent.IE||goog.userAgent.IE&&goog.userAgent.isDocumentModeOrHigher(9)||goog.userAgent.GECKO&&goog.userAgent.isVersionOrHigher("1.9.1"),CAN_USE_INNER_TEXT:goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("9"),CAN_USE_PARENT_ELEMENT_PROPERTY:goog.userAgent.IE||goog.userAgent.OPERA||goog.userAgent.WEBKIT,INNER_HTML_NEEDS_SCOPED_ELEMENT:goog.userAgent.IE, +goog.events.wrapListener=function(a){goog.asserts.assert(a,"Listener can not be null.");if(goog.isFunction(a))return a;goog.asserts.assert(a.handleEvent,"An object listener must have handleEvent method.");a[goog.events.LISTENER_WRAPPER_PROP_]||(a[goog.events.LISTENER_WRAPPER_PROP_]=function(b){return a.handleEvent(b)});return a[goog.events.LISTENER_WRAPPER_PROP_]};goog.debug.entryPointRegistry.register(function(a){goog.events.handleBrowserEvent_=a(goog.events.handleBrowserEvent_)});goog.math={};goog.math.randomInt=function(a){return Math.floor(Math.random()*a)};goog.math.uniformRandom=function(a,b){return a+Math.random()*(b-a)};goog.math.clamp=function(a,b,c){return Math.min(Math.max(a,b),c)};goog.math.modulo=function(a,b){var c=a%b;return 0>c*b?c+b:c};goog.math.lerp=function(a,b,c){return a+c*(b-a)};goog.math.nearlyEquals=function(a,b,c){return Math.abs(a-b)<=(c||1E-6)};goog.math.standardAngle=function(a){return goog.math.modulo(a,360)}; +goog.math.standardAngleInRadians=function(a){return goog.math.modulo(a,2*Math.PI)};goog.math.toRadians=function(a){return a*Math.PI/180};goog.math.toDegrees=function(a){return 180*a/Math.PI};goog.math.angleDx=function(a,b){return b*Math.cos(goog.math.toRadians(a))};goog.math.angleDy=function(a,b){return b*Math.sin(goog.math.toRadians(a))};goog.math.angle=function(a,b,c,d){return goog.math.standardAngle(goog.math.toDegrees(Math.atan2(d-b,c-a)))}; +goog.math.angleDifference=function(a,b){var c=goog.math.standardAngle(b)-goog.math.standardAngle(a);180=c&&(c=360+c);return c};goog.math.sign=function(a){return 0a?-1:a}; +goog.math.longestCommonSubsequence=function(a,b,c,d){c=c||function(a,b){return a==b};d=d||function(b,c){return a[b]};for(var e=a.length,f=b.length,g=[],h=0;hg[h][k-1]?h--:k--;return l}; +goog.math.sum=function(a){return goog.array.reduce(arguments,function(a,c){return a+c},0)};goog.math.average=function(a){return goog.math.sum.apply(null,arguments)/arguments.length};goog.math.sampleVariance=function(a){var b=arguments.length;if(2>b)return 0;var c=goog.math.average.apply(null,arguments);return goog.math.sum.apply(null,goog.array.map(arguments,function(a){return Math.pow(a-c,2)}))/(b-1)};goog.math.standardDeviation=function(a){return Math.sqrt(goog.math.sampleVariance.apply(null,arguments))}; +goog.math.isInt=function(a){return isFinite(a)&&0==a%1};goog.math.isFiniteNumber=function(a){return isFinite(a)};goog.math.isNegativeZero=function(a){return 0==a&&0>1/a};goog.math.log10Floor=function(a){if(0a?1:0)}return 0==a?-Infinity:NaN};goog.math.safeFloor=function(a,b){goog.asserts.assert(!goog.isDef(b)||0e&&(g=2*Math.PI-g);var h=g+Math.PI/2;h>2*Math.PI&&(h-=2*Math.PI);var k=Math.sin(h),l=Math.cos(h),n=this.getBubbleSize();h=(n.width+n.height)/Blockly.Bubble.ARROW_THICKNESS;h=Math.min(h,n.width,n.height)/4;n=1-Blockly.Bubble.ANCHOR_RADIUS/f;d=b+ n*d;e=c+n*e;n=b+h*l;var m=c+h*k;b-=h*l;c-=h*k;k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+n+","+m);a.push("C"+(n+f)+","+(m+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)}; Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();Blockly.utils.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Bubble.prototype.moveDuringDrag=function(a,b){a?a.translateSurface(b.x,b.y):this.moveTo(b.x,b.y);this.relativeLeft_=this.workspace_.RTL?this.anchorXY_.x-b.x-this.width_:b.x-this.anchorXY_.x;this.relativeTop_=b.y-this.anchorXY_.y;this.renderArrow_()}; -Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new goog.math.Coordinate(this.anchorXY_.x+this.relativeLeft_,this.anchorXY_.y+this.relativeTop_)};Blockly.Bubble.prototype.setAutoLayout=function(a){this.autoLayout_=a};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this);this.blockId=a?a.id:null;this.workspaceId=a?a.workspace.id:null;this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; +Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new Blockly.utils.Coordinate(this.anchorXY_.x+this.relativeLeft_,this.anchorXY_.y+this.relativeTop_)};Blockly.Bubble.prototype.setAutoLayout=function(a){this.autoLayout_=a};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this);this.blockId=a?a.id:null;this.workspaceId=a?a.workspace.id:null;this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);this.blockId&&(a.blockId=this.blockId);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue;this.blockId=a.blockId};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null; Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; Blockly.Icon.prototype.dispose=function(){Blockly.utils.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed()||this.block_.isInsertionMarker())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; -Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new goog.math.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);goog.math.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; +Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new Blockly.utils.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);Blockly.utils.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; Blockly.Comment.prototype.drawIcon_=function(a){Blockly.utils.createSvgElement("circle",{"class":"blocklyIconShape",r:"8",cx:"8",cy:"8"},a);Blockly.utils.createSvgElement("path",{"class":"blocklyIconSymbol",d:"m6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.4050.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25-1.201,0.998 -1.201,1.528 -1.204,2.19z"},a);Blockly.utils.createSvgElement("rect",{"class":"blocklyIconSymbol",x:"6.8",y:"10.78",height:"2",width:"2"},a)}; Blockly.Comment.prototype.createEditor_=function(){this.foreignObject_=Blockly.utils.createSvgElement("foreignObject",{x:Blockly.Bubble.BORDER_WIDTH,y:Blockly.Bubble.BORDER_WIDTH},null);var a=document.createElementNS(Blockly.HTML_NS,"body");a.setAttribute("xmlns",Blockly.HTML_NS);a.className="blocklyMinimalBody";var b=document.createElementNS(Blockly.HTML_NS,"textarea");b.className="blocklyCommentTextarea";b.setAttribute("dir",this.block_.RTL?"RTL":"LTR");a.appendChild(b);this.textarea_=b;this.foreignObject_.appendChild(a); @@ -1084,7 +1086,7 @@ Blockly.BlockAnimations.connectionUiEffect=function(a){var b=a.workspace,c=b.sca Blockly.BlockAnimations.connectionUiStep_=function(a,b,c){var d=(new Date-b)/150;1a.workspace.scale)){var b=a.getHeightWidth().height;b=Math.atan(10/b)/Math.PI*180;a.RTL||(b*=-1);Blockly.BlockAnimations.disconnectUiStep_(a.getSvgRoot(),b,new Date)}}; Blockly.BlockAnimations.disconnectUiStep_=function(a,b,c){var d=(new Date-c)/200;1b+window.scrollX-2*Blockly.Tooltip.MARGINS&&(d=b-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=e+"px";Blockly.Tooltip.DIV.style.left=d+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; this.healStack_=!Blockly.DRAG_STACK}; Blockly.Gesture.prototype.dispose=function(){Blockly.Touch.clearTouchIdentifier();Blockly.Tooltip.unblock();this.creatorWorkspace_.clearGesture();this.onMoveWrapper_&&Blockly.unbindEvent_(this.onMoveWrapper_);this.onUpWrapper_&&Blockly.unbindEvent_(this.onUpWrapper_);this.flyout_=this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=null;this.blockDragger_&&(this.blockDragger_.dispose(),this.blockDragger_=null);this.workspaceDragger_&&(this.workspaceDragger_.dispose(),this.workspaceDragger_= -null);this.bubbleDragger_&&(this.bubbleDragger_.dispose(),this.bubbleDragger_=null)};Blockly.Gesture.prototype.updateFromEvent_=function(a){var b=new goog.math.Coordinate(a.clientX,a.clientY);this.updateDragDelta_(b)&&(this.updateIsDragging_(),Blockly.longStop_());this.mostRecentEvent_=a}; -Blockly.Gesture.prototype.updateDragDelta_=function(a){this.currentDragDeltaXY_=goog.math.Coordinate.difference(a,this.mouseDownXY_);return this.hasExceededDragRadius_?!1:this.hasExceededDragRadius_=goog.math.Coordinate.magnitude(this.currentDragDeltaXY_)>(this.flyout_?Blockly.FLYOUT_DRAG_RADIUS:Blockly.DRAG_RADIUS)}; +null);this.bubbleDragger_&&(this.bubbleDragger_.dispose(),this.bubbleDragger_=null)};Blockly.Gesture.prototype.updateFromEvent_=function(a){var b=new Blockly.utils.Coordinate(a.clientX,a.clientY);this.updateDragDelta_(b)&&(this.updateIsDragging_(),Blockly.longStop_());this.mostRecentEvent_=a}; +Blockly.Gesture.prototype.updateDragDelta_=function(a){this.currentDragDeltaXY_=Blockly.utils.Coordinate.difference(a,this.mouseDownXY_);return this.hasExceededDragRadius_?!1:this.hasExceededDragRadius_=Blockly.utils.Coordinate.magnitude(this.currentDragDeltaXY_)>(this.flyout_?Blockly.FLYOUT_DRAG_RADIUS:Blockly.DRAG_RADIUS)}; Blockly.Gesture.prototype.updateIsDraggingFromFlyout_=function(){return this.flyout_.isBlockCreatable_(this.targetBlock_)?!this.flyout_.isScrollable()||this.flyout_.isDragTowardWorkspace(this.currentDragDeltaXY_)?(this.startWorkspace_=this.flyout_.targetWorkspace_,this.startWorkspace_.updateScreenCalculationsIfScrolled(),Blockly.Events.getGroup()||Blockly.Events.setGroup(!0),this.startBlock_=null,this.targetBlock_=this.flyout_.createBlock(this.targetBlock_),this.targetBlock_.select(),!0):!1:!1}; Blockly.Gesture.prototype.updateIsDraggingBubble_=function(){if(!this.startBubble_)return!1;this.isDraggingBubble_=!0;this.startDraggingBubble_();return!0};Blockly.Gesture.prototype.updateIsDraggingBlock_=function(){if(!this.targetBlock_)return!1;this.flyout_?this.isDraggingBlock_=this.updateIsDraggingFromFlyout_():this.targetBlock_.isMovable()&&(this.isDraggingBlock_=!0);return this.isDraggingBlock_?(this.startDraggingBlock_(),!0):!1}; Blockly.Gesture.prototype.updateIsDraggingWorkspace_=function(){if(this.flyout_?this.flyout_.isScrollable():this.startWorkspace_&&this.startWorkspace_.isDraggable())this.workspaceDragger_=this.flyout_?new Blockly.FlyoutDragger(this.flyout_):new Blockly.WorkspaceDragger(this.startWorkspace_),this.isDraggingWorkspace_=!0,this.workspaceDragger_.startDrag()}; @@ -1174,7 +1176,7 @@ Blockly.Gesture.prototype.updateIsDragging_=function(){if(this.calledUpdateIsDra Blockly.Gesture.prototype.startDraggingBlock_=function(){this.blockDragger_=new Blockly.BlockDragger(this.targetBlock_,this.startWorkspace_);this.blockDragger_.startBlockDrag(this.currentDragDeltaXY_,this.healStack_);this.blockDragger_.dragBlock(this.mostRecentEvent_,this.currentDragDeltaXY_)}; Blockly.Gesture.prototype.startDraggingBubble_=function(){this.bubbleDragger_=new Blockly.BubbleDragger(this.startBubble_,this.startWorkspace_);this.bubbleDragger_.startBubbleDrag();this.bubbleDragger_.dragBubble(this.mostRecentEvent_,this.currentDragDeltaXY_)}; Blockly.Gesture.prototype.doStart=function(a){Blockly.utils.isTargetInput(a)?this.cancel():(this.hasStarted_=!0,Blockly.BlockAnimations.disconnectUiStop(),this.startWorkspace_.updateScreenCalculationsIfScrolled(),this.startWorkspace_.isMutator&&this.startWorkspace_.resize(),this.startWorkspace_.markFocused(),this.mostRecentEvent_=a,Blockly.hideChaff(!!this.flyout_),Blockly.Tooltip.block(),this.targetBlock_&&this.targetBlock_.select(),Blockly.utils.isRightButton(a)?this.handleRightClick(a):("touchstart"!= -a.type.toLowerCase()&&"pointerdown"!=a.type.toLowerCase()||"mouse"==a.pointerType||Blockly.longStart_(a,this),this.mouseDownXY_=new goog.math.Coordinate(a.clientX,a.clientY),this.healStack_=a.altKey||a.ctrlKey||a.metaKey,this.bindMouseEvents(a)))}; +a.type.toLowerCase()&&"pointerdown"!=a.type.toLowerCase()||"mouse"==a.pointerType||Blockly.longStart_(a,this),this.mouseDownXY_=new Blockly.utils.Coordinate(a.clientX,a.clientY),this.healStack_=a.altKey||a.ctrlKey||a.metaKey,this.bindMouseEvents(a)))}; Blockly.Gesture.prototype.bindMouseEvents=function(a){this.onMoveWrapper_=Blockly.bindEventWithChecks_(document,"mousemove",null,this.handleMove.bind(this));this.onUpWrapper_=Blockly.bindEventWithChecks_(document,"mouseup",null,this.handleUp.bind(this));a.preventDefault();a.stopPropagation()}; Blockly.Gesture.prototype.handleMove=function(a){this.updateFromEvent_(a);this.isDraggingWorkspace_?this.workspaceDragger_.drag(this.currentDragDeltaXY_):this.isDraggingBlock_?this.blockDragger_.dragBlock(this.mostRecentEvent_,this.currentDragDeltaXY_):this.isDraggingBubble_&&this.bubbleDragger_.dragBubble(this.mostRecentEvent_,this.currentDragDeltaXY_);a.preventDefault();a.stopPropagation()}; Blockly.Gesture.prototype.handleUp=function(a){this.updateFromEvent_(a);Blockly.longStop_();this.isEnding_?console.log("Trying to end a gesture recursively."):(this.isEnding_=!0,this.isDraggingBubble_?this.bubbleDragger_.endBubbleDrag(a,this.currentDragDeltaXY_):this.isDraggingBlock_?this.blockDragger_.endBlockDrag(a,this.currentDragDeltaXY_):this.isDraggingWorkspace_?this.workspaceDragger_.endDrag(this.currentDragDeltaXY_):this.isBubbleClick_()?this.doBubbleClick_():this.isFieldClick_()?this.doFieldClick_(): @@ -1204,9 +1206,9 @@ Blockly.ScrollbarPair.prototype.dispose=function(){Blockly.utils.removeNode(this Blockly.ScrollbarPair.prototype.resize=function(){var a=this.workspace_.getMetrics();if(a){var b=!1,c=!1;this.oldHostMetrics_&&this.oldHostMetrics_.viewWidth==a.viewWidth&&this.oldHostMetrics_.viewHeight==a.viewHeight&&this.oldHostMetrics_.absoluteTop==a.absoluteTop&&this.oldHostMetrics_.absoluteLeft==a.absoluteLeft?(this.oldHostMetrics_&&this.oldHostMetrics_.contentWidth==a.contentWidth&&this.oldHostMetrics_.viewLeft==a.viewLeft&&this.oldHostMetrics_.contentLeft==a.contentLeft||(b=!0),this.oldHostMetrics_&& this.oldHostMetrics_.contentHeight==a.contentHeight&&this.oldHostMetrics_.viewTop==a.viewTop&&this.oldHostMetrics_.contentTop==a.contentTop||(c=!0)):c=b=!0;b&&this.hScroll.resize(a);c&&this.vScroll.resize(a);this.oldHostMetrics_&&this.oldHostMetrics_.viewWidth==a.viewWidth&&this.oldHostMetrics_.absoluteLeft==a.absoluteLeft||this.corner_.setAttribute("x",this.vScroll.position_.x);this.oldHostMetrics_&&this.oldHostMetrics_.viewHeight==a.viewHeight&&this.oldHostMetrics_.absoluteTop==a.absoluteTop||this.corner_.setAttribute("y", this.hScroll.position_.y);this.oldHostMetrics_=a}};Blockly.ScrollbarPair.prototype.set=function(a,b){var c={},d=a*this.hScroll.ratio_,e=b*this.vScroll.ratio_,f=this.vScroll.scrollViewSize_;c.x=this.getRatio_(d,this.hScroll.scrollViewSize_);c.y=this.getRatio_(e,f);this.workspace_.setMetrics(c);this.hScroll.setHandlePosition(d);this.vScroll.setHandlePosition(e)};Blockly.ScrollbarPair.prototype.getRatio_=function(a,b){var c=a/b;return isNaN(c)?0:c}; -Blockly.Scrollbar=function(a,b,c,d){this.workspace_=a;this.pair_=c||!1;this.horizontal_=b;this.oldHostMetrics_=null;this.createDom_(d);this.position_=new goog.math.Coordinate(0,0);a=Blockly.Scrollbar.scrollbarThickness;b?(this.svgBackground_.setAttribute("height",a),this.outerSvg_.setAttribute("height",a),this.svgHandle_.setAttribute("height",a-5),this.svgHandle_.setAttribute("y",2.5),this.lengthAttribute_="width",this.positionAttribute_="x"):(this.svgBackground_.setAttribute("width",a),this.outerSvg_.setAttribute("width", -a),this.svgHandle_.setAttribute("width",a-5),this.svgHandle_.setAttribute("x",2.5),this.lengthAttribute_="height",this.positionAttribute_="y");this.onMouseDownBarWrapper_=Blockly.bindEventWithChecks_(this.svgBackground_,"mousedown",this,this.onMouseDownBar_);this.onMouseDownHandleWrapper_=Blockly.bindEventWithChecks_(this.svgHandle_,"mousedown",this,this.onMouseDownHandle_)};Blockly.Scrollbar.prototype.origin_=new goog.math.Coordinate(0,0);Blockly.Scrollbar.prototype.startDragMouse_=0; -Blockly.Scrollbar.prototype.scrollViewSize_=0;Blockly.Scrollbar.prototype.handleLength_=0;Blockly.Scrollbar.prototype.handlePosition_=0;Blockly.Scrollbar.prototype.isVisible_=!0;Blockly.Scrollbar.prototype.containerVisible_=!0;Blockly.Scrollbar.scrollbarThickness=15;goog.events.BrowserFeature.TOUCH_ENABLED&&(Blockly.Scrollbar.scrollbarThickness=25); +Blockly.Scrollbar=function(a,b,c,d){this.workspace_=a;this.pair_=c||!1;this.horizontal_=b;this.oldHostMetrics_=null;this.createDom_(d);this.position_=new Blockly.utils.Coordinate(0,0);a=Blockly.Scrollbar.scrollbarThickness;b?(this.svgBackground_.setAttribute("height",a),this.outerSvg_.setAttribute("height",a),this.svgHandle_.setAttribute("height",a-5),this.svgHandle_.setAttribute("y",2.5),this.lengthAttribute_="width",this.positionAttribute_="x"):(this.svgBackground_.setAttribute("width",a),this.outerSvg_.setAttribute("width", +a),this.svgHandle_.setAttribute("width",a-5),this.svgHandle_.setAttribute("x",2.5),this.lengthAttribute_="height",this.positionAttribute_="y");this.onMouseDownBarWrapper_=Blockly.bindEventWithChecks_(this.svgBackground_,"mousedown",this,this.onMouseDownBar_);this.onMouseDownHandleWrapper_=Blockly.bindEventWithChecks_(this.svgHandle_,"mousedown",this,this.onMouseDownHandle_)};Blockly.Scrollbar.prototype.origin_=new Blockly.utils.Coordinate(0,0);Blockly.Scrollbar.prototype.startDragMouse_=0; +Blockly.Scrollbar.prototype.scrollViewSize_=0;Blockly.Scrollbar.prototype.handleLength_=0;Blockly.Scrollbar.prototype.handlePosition_=0;Blockly.Scrollbar.prototype.isVisible_=!0;Blockly.Scrollbar.prototype.containerVisible_=!0;Blockly.Scrollbar.scrollbarThickness=15;Blockly.Touch.TOUCH_ENABLED&&(Blockly.Scrollbar.scrollbarThickness=25); Blockly.Scrollbar.metricsAreEquivalent_=function(a,b){return a&&b&&a.viewWidth==b.viewWidth&&a.viewHeight==b.viewHeight&&a.viewLeft==b.viewLeft&&a.viewTop==b.viewTop&&a.absoluteTop==b.absoluteTop&&a.absoluteLeft==b.absoluteLeft&&a.contentWidth==b.contentWidth&&a.contentHeight==b.contentHeight&&a.contentLeft==b.contentLeft&&a.contentTop==b.contentTop?!0:!1}; Blockly.Scrollbar.prototype.dispose=function(){this.cleanUp_();Blockly.unbindEvent_(this.onMouseDownBarWrapper_);this.onMouseDownBarWrapper_=null;Blockly.unbindEvent_(this.onMouseDownHandleWrapper_);this.onMouseDownHandleWrapper_=null;Blockly.utils.removeNode(this.outerSvg_);this.workspace_=this.svgHandle_=this.svgBackground_=this.svgGroup_=this.outerSvg_=null};Blockly.Scrollbar.prototype.setHandleLength_=function(a){this.handleLength_=a;this.svgHandle_.setAttribute(this.lengthAttribute_,this.handleLength_)}; Blockly.Scrollbar.prototype.setHandlePosition=function(a){this.handlePosition_=a;this.svgHandle_.setAttribute(this.positionAttribute_,this.handlePosition_)};Blockly.Scrollbar.prototype.setScrollViewSize_=function(a){this.scrollViewSize_=a;this.outerSvg_.setAttribute(this.lengthAttribute_,this.scrollViewSize_);this.svgBackground_.setAttribute(this.lengthAttribute_,this.scrollViewSize_)};Blockly.ScrollbarPair.prototype.setContainerVisible=function(a){this.hScroll.setContainerVisible(a);this.vScroll.setContainerVisible(a)}; @@ -1224,14 +1226,14 @@ Blockly.Scrollbar.prototype.onMouseDownHandle_=function(a){this.workspace_.markF a.stopPropagation(),a.preventDefault())};Blockly.Scrollbar.prototype.onMouseMoveHandle_=function(a){this.setHandlePosition(this.constrainHandle_(this.startDragHandle+((this.horizontal_?a.clientX:a.clientY)-this.startDragMouse_)));this.onScroll_()};Blockly.Scrollbar.prototype.onMouseUpHandle_=function(){this.workspace_.resetDragSurface();Blockly.Touch.clearTouchIdentifier();this.cleanUp_()}; Blockly.Scrollbar.prototype.cleanUp_=function(){Blockly.hideChaff(!0);Blockly.Scrollbar.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Scrollbar.onMouseUpWrapper_),Blockly.Scrollbar.onMouseUpWrapper_=null);Blockly.Scrollbar.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Scrollbar.onMouseMoveWrapper_),Blockly.Scrollbar.onMouseMoveWrapper_=null)}; Blockly.Scrollbar.prototype.constrainHandle_=function(a){return a=0>=a||isNaN(a)||this.scrollViewSize_this.previousScale_){var c=b-this.previousScale_;c=0Object.keys(this.cachedPoints_).length&&(this.cachedPoints_={},this.previousScale_=0)}; -Blockly.TouchGesture.prototype.getTouchPoint=function(a){return this.startWorkspace_?new goog.math.Coordinate(a.pageX?a.pageX:a.changedTouches[0].pageX,a.pageY?a.pageY:a.changedTouches[0].pageY):null};Blockly.Trashcan=function(a){this.workspace_=a;this.hasBlocks_=!1;this.contents_=[];0>=this.workspace_.options.maxTrashcanContents||(a={scrollbars:!0,disabledPatternId:this.workspace_.options.disabledPatternId,parentWorkspace:this.workspace_,RTL:this.workspace_.RTL,oneBasedIndex:this.workspace_.options.oneBasedIndex},this.workspace_.horizontalLayout?(a.toolboxPosition=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_TOP?Blockly.TOOLBOX_AT_BOTTOM:Blockly.TOOLBOX_AT_TOP,this.flyout_=new Blockly.HorizontalFlyout(a)): +Blockly.TouchGesture.prototype.dispose=function(){Blockly.TouchGesture.superClass_.dispose.call(this);this.onStartWrapper_&&Blockly.unbindEvent_(this.onStartWrapper_)};Blockly.TouchGesture.prototype.handleTouchStart=function(a){var b=Blockly.Touch.getTouchIdentifierFromEvent(a);this.cachedPoints_[b]=this.getTouchPoint(a);b=Object.keys(this.cachedPoints_);2==b.length&&(this.startDistance_=Blockly.utils.Coordinate.distance(this.cachedPoints_[b[0]],this.cachedPoints_[b[1]]),this.isMultiTouch_=!0,a.preventDefault())}; +Blockly.TouchGesture.prototype.handleTouchMove=function(a){var b=Blockly.Touch.getTouchIdentifierFromEvent(a);this.cachedPoints_[b]=this.getTouchPoint(a);b=Object.keys(this.cachedPoints_);if(2==b.length){b=this.touchScale_=Blockly.utils.Coordinate.distance(this.cachedPoints_[b[0]],this.cachedPoints_[b[1]])/this.startDistance_;if(0this.previousScale_){var c=b-this.previousScale_;c=0Object.keys(this.cachedPoints_).length&&(this.cachedPoints_={},this.previousScale_=0)}; +Blockly.TouchGesture.prototype.getTouchPoint=function(a){return this.startWorkspace_?new Blockly.utils.Coordinate(a.pageX?a.pageX:a.changedTouches[0].pageX,a.pageY?a.pageY:a.changedTouches[0].pageY):null};Blockly.utils.Rect=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};Blockly.utils.Rect.prototype.contains=function(a,b){return a>=this.left&&a<=this.left+this.width&&b>=this.top&&b<=this.top+this.height};Blockly.Trashcan=function(a){this.workspace_=a;this.hasBlocks_=!1;this.contents_=[];0>=this.workspace_.options.maxTrashcanContents||(a={scrollbars:!0,disabledPatternId:this.workspace_.options.disabledPatternId,parentWorkspace:this.workspace_,RTL:this.workspace_.RTL,oneBasedIndex:this.workspace_.options.oneBasedIndex},this.workspace_.horizontalLayout?(a.toolboxPosition=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_TOP?Blockly.TOOLBOX_AT_BOTTOM:Blockly.TOOLBOX_AT_TOP,this.flyout_=new Blockly.HorizontalFlyout(a)): (a.toolboxPosition=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?Blockly.TOOLBOX_AT_LEFT:Blockly.TOOLBOX_AT_RIGHT,this.flyout_=new Blockly.VerticalFlyout(a)),this.workspace_.addChangeListener(this.onDelete_()))};Blockly.Trashcan.prototype.WIDTH_=47;Blockly.Trashcan.prototype.BODY_HEIGHT_=44;Blockly.Trashcan.prototype.LID_HEIGHT_=16;Blockly.Trashcan.prototype.MARGIN_BOTTOM_=20;Blockly.Trashcan.prototype.MARGIN_SIDE_=20;Blockly.Trashcan.prototype.MARGIN_HOTSPOT_=10; Blockly.Trashcan.prototype.SPRITE_LEFT_=0;Blockly.Trashcan.prototype.SPRITE_TOP_=32;Blockly.Trashcan.prototype.HAS_BLOCKS_LID_ANGLE=.1;Blockly.Trashcan.prototype.isOpen=!1;Blockly.Trashcan.prototype.minOpenness_=0;Blockly.Trashcan.prototype.svgGroup_=null;Blockly.Trashcan.prototype.svgLid_=null;Blockly.Trashcan.prototype.lidTask_=0;Blockly.Trashcan.prototype.lidOpen_=0;Blockly.Trashcan.prototype.left_=0;Blockly.Trashcan.prototype.top_=0; Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyTrash"},null);var a=String(Math.random()).substring(2);var b=Blockly.utils.createSvgElement("clipPath",{id:"blocklyTrashBodyClipPath"+a},this.svgGroup_);Blockly.utils.createSvgElement("rect",{width:this.WIDTH_,height:this.BODY_HEIGHT_,y:this.LID_HEIGHT_},b);var c=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,x:-this.SPRITE_LEFT_,height:Blockly.SPRITE.height,y:-this.SPRITE_TOP_, @@ -1240,12 +1242,12 @@ Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.utils.cre Blockly.Trashcan.prototype.init=function(a){0this.minOpenness_&&1>this.lidOpen_&&(this.lidTask_=setTimeout(this.animateLid_.bind(this),20))}; Blockly.Trashcan.prototype.setLidAngle_=function(a){var b=this.workspace_.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT||this.workspace_.horizontalLayout&&this.workspace_.RTL;this.svgLid_.setAttribute("transform","rotate("+(b?-a:a)+","+(b?4:this.WIDTH_-4)+","+(this.LID_HEIGHT_-2)+")")};Blockly.Trashcan.prototype.close=function(){this.setOpen_(!1)};Blockly.Trashcan.prototype.click=function(){if(this.hasBlocks_){for(var a=[],b=0,c;c=this.contents_[b];b++)a[b]=Blockly.Xml.textToDom(c).firstChild;this.flyout_.show(a)}}; Blockly.Trashcan.prototype.mouseOver_=function(){this.hasBlocks_&&this.setOpen_(!0)};Blockly.Trashcan.prototype.mouseOut_=function(){this.setOpen_(!1)}; -Blockly.Trashcan.prototype.onDelete_=function(){var a=this;return function(b){0>=a.workspace_.options.maxTrashcanContents||b.type!=Blockly.Events.BLOCK_DELETE||(b=a.cleanBlockXML_(b.oldXml),-1==a.contents_.indexOf(b)&&(a.contents_.unshift(b),a.contents_.length>a.workspace_.options.maxTrashcanContents&&a.contents_.splice(a.workspace_.options.maxTrashcanContents,a.contents_.length-a.workspace_.options.maxTrashcanContents),a.hasBlocks_=!0,a.minOpenness_=a.HAS_BLOCKS_LID_ANGLE,a.setLidAngle_(45*a.minOpenness_)))}}; -Blockly.Trashcan.prototype.cleanBlockXML_=function(a){for(var b=a=a.cloneNode(!0);b;){b.removeAttribute&&(b.removeAttribute("x"),b.removeAttribute("y"),b.removeAttribute("id"));var c=b.firstChild||b.nextSibling;if(!c)for(c=b.parentNode;c;){if(c.nextSibling){c=c.nextSibling;break}c=c.parentNode}b=c}return""+Blockly.Xml.domToText(a)+""};Blockly.VariableModel=function(a,b,c,d){this.workspace=a;this.name=b;this.type=c||"";this.id_=d||Blockly.utils.genUid();Blockly.Events.fire(new Blockly.Events.VarCreate(this))};Blockly.VariableModel.prototype.getId=function(){return this.id_};Blockly.VariableModel.compareByName=function(a,b){var c=a.name.toLowerCase(),d=b.name.toLowerCase();return c=a.workspace_.options.maxTrashcanContents||b.type!=Blockly.Events.BLOCK_DELETE||"shadow"==b.oldXml.tagName.toLowerCase()||(b=a.cleanBlockXML_(b.oldXml),-1==a.contents_.indexOf(b)&&(a.contents_.unshift(b),a.contents_.length>a.workspace_.options.maxTrashcanContents&&a.contents_.splice(a.workspace_.options.maxTrashcanContents,a.contents_.length-a.workspace_.options.maxTrashcanContents),a.hasBlocks_=!0,a.minOpenness_=a.HAS_BLOCKS_LID_ANGLE, +a.setLidAngle_(45*a.minOpenness_)))}};Blockly.Trashcan.prototype.cleanBlockXML_=function(a){for(var b=a=a.cloneNode(!0);b;){b.removeAttribute&&(b.removeAttribute("x"),b.removeAttribute("y"),b.removeAttribute("id"));var c=b.firstChild||b.nextSibling;if(!c)for(c=b.parentNode;c;){if(c.nextSibling){c=c.nextSibling;break}c=c.parentNode}b=c}return""+Blockly.Xml.domToText(a)+""};Blockly.VariableModel=function(a,b,c,d){this.workspace=a;this.name=b;this.type=c||"";this.id_=d||Blockly.utils.genUid();Blockly.Events.fire(new Blockly.Events.VarCreate(this))};Blockly.VariableModel.prototype.getId=function(){return this.id_};Blockly.VariableModel.compareByName=function(a,b){var c=a.name.toLowerCase(),d=b.name.toLowerCase();return c=this.remainingCapacity()||(this.currentGesture_&&this.currentGesture_.cancel(),"comment"==a.tagName.toLowerCase()?this.pasteWorkspaceComment_(a):this.pasteBlock_(a))}; -Blockly.WorkspaceSvg.prototype.pasteBlock_=function(a){Blockly.Events.disable();try{var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(d)){this.RTL&&(c=-c);do{a=!1;for(var e=this.getAllBlocks(!1),f=0,g;g=e[f];f++){var h=g.getRelativeToSurfaceXY();if(1>=Math.abs(c-h.x)&&1>=Math.abs(d-h.y)){a=!0;break}}if(!a){var k=b.getConnections_(!1);f=0;for(var l;l=k[f];f++)if(l.closest(Blockly.SNAP_RADIUS,new goog.math.Coordinate(c,d)).connection){a= -!0;break}}a&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,d+=2*Blockly.SNAP_RADIUS)}while(a);b.moveBy(c,d)}}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(b));b.select()}; +Blockly.WorkspaceSvg.prototype.pasteBlock_=function(a){Blockly.Events.disable();try{var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(d)){this.RTL&&(c=-c);do{a=!1;for(var e=this.getAllBlocks(!1),f=0,g;g=e[f];f++){var h=g.getRelativeToSurfaceXY();if(1>=Math.abs(c-h.x)&&1>=Math.abs(d-h.y)){a=!0;break}}if(!a){var k=b.getConnections_(!1);f=0;for(var l;l=k[f];f++)if(l.closest(Blockly.SNAP_RADIUS,new Blockly.utils.Coordinate(c, +d)).connection){a=!0;break}}a&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,d+=2*Blockly.SNAP_RADIUS)}while(a);b.moveBy(c,d)}}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(b));b.select()}; Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_=function(a){Blockly.Events.disable();try{var b=Blockly.WorkspaceCommentSvg.fromXml(a,this),c=parseInt(a.getAttribute("x"),10),d=parseInt(a.getAttribute("y"),10);isNaN(c)||isNaN(d)||(this.RTL&&(c=-c),b.moveBy(c+50,d+50))}finally{Blockly.Events.enable()}Blockly.Events.isEnabled();b.select()}; Blockly.WorkspaceSvg.prototype.refreshToolboxSelection=function(){var a=this.isFlyout?this.targetWorkspace:this;a&&!a.currentGesture_&&a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.refreshSelection()};Blockly.WorkspaceSvg.prototype.renameVariableById=function(a,b){Blockly.WorkspaceSvg.superClass_.renameVariableById.call(this,a,b);this.refreshToolboxSelection()};Blockly.WorkspaceSvg.prototype.deleteVariableById=function(a){Blockly.WorkspaceSvg.superClass_.deleteVariableById.call(this,a);this.refreshToolboxSelection()}; Blockly.WorkspaceSvg.prototype.createVariable=function(a,b,c){a=Blockly.WorkspaceSvg.superClass_.createVariable.call(this,a,b,c);this.refreshToolboxSelection();return a};Blockly.WorkspaceSvg.prototype.recordDeleteAreas=function(){this.deleteAreaTrash_=this.trashcan&&this.svgGroup_.parentNode?this.trashcan.getClientRect():null;this.deleteAreaToolbox_=this.flyout_?this.flyout_.getClientRect():this.toolbox_?this.toolbox_.getClientRect():null}; -Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){a=new goog.math.Coordinate(a.clientX,a.clientY);return this.deleteAreaTrash_&&this.deleteAreaTrash_.contains(a)?Blockly.DELETE_AREA_TRASH:this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a)?Blockly.DELETE_AREA_TOOLBOX:Blockly.DELETE_AREA_NONE};Blockly.WorkspaceSvg.prototype.onMouseDown_=function(a){var b=this.getGesture(a);b&&b.handleWsStart(a,this)}; -Blockly.WorkspaceSvg.prototype.startDrag=function(a,b){var c=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());c.x/=this.scale;c.y/=this.scale;this.dragDeltaXY_=goog.math.Coordinate.difference(b,c)};Blockly.WorkspaceSvg.prototype.moveDrag=function(a){a=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;return goog.math.Coordinate.sum(this.dragDeltaXY_,a)}; +Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){return this.deleteAreaTrash_&&this.deleteAreaTrash_.contains(a.clientX,a.clientY)?Blockly.DELETE_AREA_TRASH:this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a.clientX,a.clientY)?Blockly.DELETE_AREA_TOOLBOX:Blockly.DELETE_AREA_NONE};Blockly.WorkspaceSvg.prototype.onMouseDown_=function(a){var b=this.getGesture(a);b&&b.handleWsStart(a,this)}; +Blockly.WorkspaceSvg.prototype.startDrag=function(a,b){var c=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());c.x/=this.scale;c.y/=this.scale;this.dragDeltaXY_=Blockly.utils.Coordinate.difference(b,c)};Blockly.WorkspaceSvg.prototype.moveDrag=function(a){a=Blockly.utils.mouseToSvg(a,this.getParentSvg(),this.getInverseScreenCTM());a.x/=this.scale;a.y/=this.scale;return Blockly.utils.Coordinate.sum(this.dragDeltaXY_,a)}; Blockly.WorkspaceSvg.prototype.isDragging=function(){return null!=this.currentGesture_&&this.currentGesture_.isDragging()};Blockly.WorkspaceSvg.prototype.isDraggable=function(){return this.options.moveOptions&&this.options.moveOptions.drag}; Blockly.WorkspaceSvg.prototype.isContentBounded=function(){return this.options.moveOptions&&this.options.moveOptions.scrollbars||this.options.moveOptions&&this.options.moveOptions.wheel||this.options.moveOptions&&this.options.moveOptions.drag||this.options.zoomOptions&&this.options.zoomOptions.controls||this.options.zoomOptions&&this.options.zoomOptions.wheel}; Blockly.WorkspaceSvg.prototype.isMovable=function(){return this.options.moveOptions&&this.options.moveOptions.scrollbars||this.options.moveOptions&&this.options.moveOptions.wheel||this.options.moveOptions&&this.options.moveOptions.drag||this.options.zoomOptions&&this.options.zoomOptions.wheel}; @@ -1422,7 +1425,7 @@ Blockly.Warning.textToDom_=function(a){var b=Blockly.utils.createSvgElement("tex Blockly.Warning.prototype.setVisible=function(a){if(a!=this.isVisible())if(Blockly.Events.fire(new Blockly.Events.Ui(this.block_,"warningOpen",!a,a)),a){a=Blockly.Warning.textToDom_(this.getText());this.bubble_=new Blockly.Bubble(this.block_.workspace,a,this.block_.svgPath_,this.iconXY_,null,null);this.bubble_.setSvgId(this.block_.id);if(this.block_.RTL)for(var b=a.getBBox().width,c=0,d;d=a.childNodes[c];c++)d.setAttribute("text-anchor","end"),d.setAttribute("x",b+Blockly.Bubble.BORDER_WIDTH);this.updateColour(); a=this.bubble_.getBubbleSize();this.bubble_.setBubbleSize(a.width,a.height)}else this.bubble_.dispose(),this.body_=this.bubble_=null};Blockly.Warning.prototype.bodyFocus_=function(a){this.bubble_.promote_()};Blockly.Warning.prototype.setText=function(a,b){this.text_[b]!=a&&(a?this.text_[b]=a:delete this.text_[b],this.isVisible()&&(this.setVisible(!1),this.setVisible(!0)))};Blockly.Warning.prototype.getText=function(){var a=[],b;for(b in this.text_)a.push(this.text_[b]);return a.join("\n")}; Blockly.Warning.prototype.dispose=function(){this.block_.warning=null;Blockly.Icon.prototype.dispose.call(this)};Blockly.Block=function(a,b,c){if("undefined"!==typeof Blockly.Generator.prototype[b])throw Error('Block prototypeName "'+b+'" conflicts with Blockly.Generator members.');this.id=c&&!a.getBlockById(c)?c:Blockly.utils.genUid();a.blockDB_[this.id]=this;this.previousConnection=this.nextConnection=this.outputConnection=null;this.inputList=[];this.inputsInline=void 0;this.disabled=!1;this.tooltip="";this.contextMenu=!0;this.parentBlock_=null;this.childBlocks_=[];this.editable_=this.movable_=this.deletable_= -!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new goog.math.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;this.hat=void 0;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);a.addTypedBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a= +!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new Blockly.utils.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;this.hat=void 0;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);a.addTypedBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a= Blockly.Events.getGroup())||Blockly.Events.setGroup(!0);try{Blockly.Events.fire(new Blockly.Events.BlockCreate(this))}finally{a||Blockly.Events.setGroup(!1)}}"function"==typeof this.onchange&&this.setOnChange(this.onchange)};Blockly.Block.obtain=function(a,b){console.warn("Deprecated call to Blockly.Block.obtain, use workspace.newBlock instead.");return a.newBlock(b)};Blockly.Block.prototype.data=null;Blockly.Block.prototype.hue_=null;Blockly.Block.prototype.colour_="#000000"; Blockly.Block.prototype.colourSecondary_=null;Blockly.Block.prototype.colourTertiary_=null;Blockly.Block.prototype.styleName_=null; Blockly.Block.prototype.dispose=function(a){if(this.workspace){this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);this.unplug(a);Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockDelete(this));Blockly.Events.disable();try{this.workspace&&(this.workspace.removeTopBlock(this),this.workspace.removeTypedBlock(this),delete this.workspace.blockDB_[this.id],this.workspace=null);Blockly.selected==this&&(Blockly.selected=null);for(var b=this.childBlocks_.length- @@ -1473,9 +1476,9 @@ Blockly.Block.prototype.getInputTargetBlock=function(a){return(a=this.getInput(a Blockly.Block.prototype.getRelativeToSurfaceXY=function(){return this.xy_};Blockly.Block.prototype.moveBy=function(a,b){if(this.parentBlock_)throw Error("Block has parent.");var c=new Blockly.Events.BlockMove(this);this.xy_.translate(a,b);c.recordNew();Blockly.Events.fire(c)};Blockly.Block.prototype.makeConnection_=function(a){return new Blockly.Connection(this,a)}; Blockly.Block.prototype.allInputsFilled=function(a){void 0===a&&(a=!0);if(!a&&this.isShadow())return!1;for(var b=0,c;c=this.inputList[b];b++)if(c.connection&&(c=c.connection.targetBlock(),!c||!c.allInputsFilled(a)))return!1;return(b=this.getNextBlock())?b.allInputsFilled(a):!0};Blockly.Block.prototype.toDevString=function(){var a=this.type?'"'+this.type+'" block':"Block";this.id&&(a+=' (id="'+this.id+'")');return a};Blockly.BlockDragSurfaceSvg=function(a){this.container_=a;this.createDom()};Blockly.BlockDragSurfaceSvg.prototype.SVG_=null;Blockly.BlockDragSurfaceSvg.prototype.dragGroup_=null;Blockly.BlockDragSurfaceSvg.prototype.container_=null;Blockly.BlockDragSurfaceSvg.prototype.scale_=1;Blockly.BlockDragSurfaceSvg.prototype.surfaceXY_=null; Blockly.BlockDragSurfaceSvg.prototype.createDom=function(){this.SVG_||(this.SVG_=Blockly.utils.createSvgElement("svg",{xmlns:Blockly.SVG_NS,"xmlns:html":Blockly.HTML_NS,"xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklyBlockDragSurface"},this.container_),this.dragGroup_=Blockly.utils.createSvgElement("g",{},this.SVG_))}; -Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow=function(a){if(this.dragGroup_.childNodes.length)throw Error("Already dragging a block.");this.dragGroup_.appendChild(a);this.SVG_.style.display="block";this.surfaceXY_=new goog.math.Coordinate(0,0)};Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup=function(a,b,c){this.scale_=c;a=a.toFixed(0);b=b.toFixed(0);this.dragGroup_.setAttribute("transform","translate("+a+","+b+") scale("+c+")")}; -Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_=function(){var a=this.surfaceXY_.x,b=this.surfaceXY_.y;a=a.toFixed(0);b=b.toFixed(0);this.SVG_.style.display="block";Blockly.utils.setCssTransform(this.SVG_,"translate3d("+a+"px, "+b+"px, 0px)")};Blockly.BlockDragSurfaceSvg.prototype.translateSurface=function(a,b){this.surfaceXY_=new goog.math.Coordinate(a*this.scale_,b*this.scale_);this.translateSurfaceInternal_()}; -Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation=function(){var a=Blockly.utils.getRelativeXY(this.SVG_);return new goog.math.Coordinate(a.x/this.scale_,a.y/this.scale_)};Blockly.BlockDragSurfaceSvg.prototype.getGroup=function(){return this.dragGroup_};Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock=function(){return this.dragGroup_.firstChild}; +Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow=function(a){if(this.dragGroup_.childNodes.length)throw Error("Already dragging a block.");this.dragGroup_.appendChild(a);this.SVG_.style.display="block";this.surfaceXY_=new Blockly.utils.Coordinate(0,0)};Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup=function(a,b,c){this.scale_=c;a=a.toFixed(0);b=b.toFixed(0);this.dragGroup_.setAttribute("transform","translate("+a+","+b+") scale("+c+")")}; +Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_=function(){var a=this.surfaceXY_.x,b=this.surfaceXY_.y;a=a.toFixed(0);b=b.toFixed(0);this.SVG_.style.display="block";Blockly.utils.setCssTransform(this.SVG_,"translate3d("+a+"px, "+b+"px, 0px)")};Blockly.BlockDragSurfaceSvg.prototype.translateSurface=function(a,b){this.surfaceXY_=new Blockly.utils.Coordinate(a*this.scale_,b*this.scale_);this.translateSurfaceInternal_()}; +Blockly.BlockDragSurfaceSvg.prototype.getSurfaceTranslation=function(){var a=Blockly.utils.getRelativeXY(this.SVG_);return new Blockly.utils.Coordinate(a.x/this.scale_,a.y/this.scale_)};Blockly.BlockDragSurfaceSvg.prototype.getGroup=function(){return this.dragGroup_};Blockly.BlockDragSurfaceSvg.prototype.getCurrentBlock=function(){return this.dragGroup_.firstChild}; Blockly.BlockDragSurfaceSvg.prototype.clearAndHide=function(a){a?a.appendChild(this.getCurrentBlock()):this.dragGroup_.removeChild(this.getCurrentBlock());this.SVG_.style.display="none";if(this.dragGroup_.childNodes.length)throw Error("Drag group was not cleared.");this.surfaceXY_=null};Blockly.utils.uiMenu={};Blockly.utils.uiMenu.getSize=function(a){a=a.getElement();var b=goog.style.getSize(a);b.height=a.scrollHeight;return b};Blockly.utils.uiMenu.adjustBBoxesForRTL=function(a,b,c){b.left+=c.width;b.right+=c.width;a.left+=c.width;a.right+=c.width};Blockly.ContextMenu={};Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_=null;Blockly.ContextMenu.show=function(a,b,c){Blockly.WidgetDiv.show(Blockly.ContextMenu,c,null);if(b.length){var d=Blockly.ContextMenu.populate_(b,c);goog.events.listen(d,goog.ui.Component.EventType.ACTION,Blockly.ContextMenu.hide);Blockly.ContextMenu.position_(d,a,c);setTimeout(function(){d.getElement().focus()},1);Blockly.ContextMenu.currentBlock=null}else Blockly.ContextMenu.hide()}; Blockly.ContextMenu.populate_=function(a,b){var c=new goog.ui.Menu;c.setRightToLeft(b);for(var d=0,e;e=a[d];d++){var f=new goog.ui.MenuItem(e.text);f.setRightToLeft(b);c.addChild(f,!0);f.setEnabled(e.enabled);e.enabled&&(goog.events.listen(f,goog.ui.Component.EventType.ACTION,e.callback),f.handleContextMenu=function(){goog.events.dispatchEvent(this,goog.ui.Component.EventType.ACTION)})}return c}; Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBox();b={top:b.clientY+d.top,bottom:b.clientY+d.top,left:b.clientX+d.left,right:b.clientX+d.left};Blockly.ContextMenu.createWidget_(a);var e=Blockly.utils.uiMenu.getSize(a);c&&Blockly.utils.uiMenu.adjustBBoxesForRTL(d,b,e);Blockly.WidgetDiv.positionWithAnchor(d,b,e,c);a.getElement().focus()}; @@ -1484,20 +1487,20 @@ Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Even Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; -Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/ -a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= +Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new Blockly.utils.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=Blockly.utils.Coordinate.difference(e,f); +e.scale(1/a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= Blockly.utils.is3dSupported()&&!!a.blockDragSurface_;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,a,b,c);this.svgGroup_.dataset&&(this.svgGroup_.dataset.id=this.id)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.prototype.warningTextDb_=null;Blockly.BlockSvg.INLINE=-1;Blockly.BlockSvg.COLLAPSED_WARNING_ID="TEMP_COLLAPSED_WARNING_"; Blockly.BlockSvg.prototype.initSvg=function(){if(!this.workspace.rendered)throw TypeError("Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;a90-b||a>-90-b&&a<-90+b?!0:!1}; -Blockly.HorizontalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.top;a=a.height;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_TOP)return new goog.math.Rect(-1E9,b-1E9,2E9,1E9+a);if(this.toolboxPosition_==Blockly.TOOLBOX_AT_BOTTOM)return new goog.math.Rect(-1E9,b,2E9,1E9+a)}; +Blockly.HorizontalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.top;a=a.height;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_TOP)return new Blockly.utils.Rect(-1E9,b-1E9,2E9,1E9+a);if(this.toolboxPosition_==Blockly.TOOLBOX_AT_BOTTOM)return new Blockly.utils.Rect(-1E9,b,2E9,1E9+a)}; Blockly.HorizontalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++)a=Math.max(a,d.getHeightWidth().height);a+=1.5*this.MARGIN;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.height_!=a){for(c=0;d=b[c];c++)d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);this.height_=a;this.position()}};Blockly.VerticalFlyout=function(a){a.getMetrics=this.getMetrics_.bind(this);a.setMetrics=this.setMetrics_.bind(this);Blockly.VerticalFlyout.superClass_.constructor.call(this,a);this.horizontalLayout_=!1};goog.inherits(Blockly.VerticalFlyout,Blockly.Flyout); Blockly.VerticalFlyout.prototype.getMetrics_=function(){if(!this.isVisible())return null;try{var a=this.workspace_.getCanvas().getBBox()}catch(e){a={height:0,y:0,width:0,x:0}}var b=this.SCROLLBAR_PADDING,c=this.height_-2*this.SCROLLBAR_PADDING,d=this.width_;this.RTL||(d-=this.SCROLLBAR_PADDING);return{viewHeight:c,viewWidth:d,contentHeight:a.height*this.workspace_.scale+2*this.MARGIN,contentWidth:a.width*this.workspace_.scale+2*this.MARGIN,viewTop:-this.workspace_.scrollY+a.y,viewLeft:-this.workspace_.scrollX, contentTop:a.y,contentLeft:a.x,absoluteTop:b,absoluteLeft:0}};Blockly.VerticalFlyout.prototype.setMetrics_=function(a){var b=this.getMetrics_();b&&("number"==typeof a.y&&(this.workspace_.scrollY=-b.contentHeight*a.y),this.workspace_.translate(this.workspace_.scrollX+b.absoluteLeft,this.workspace_.scrollY+b.absoluteTop))}; @@ -1726,7 +1729,7 @@ Blockly.VerticalFlyout.prototype.setBackgroundPath_=function(a,b){var c=this.too d.join(" "))};Blockly.VerticalFlyout.prototype.scrollToStart=function(){this.scrollbar_.set(0)};Blockly.VerticalFlyout.prototype.wheel_=function(a){var b=Blockly.utils.getScrollDeltaPixels(a);if(b.y){var c=this.getMetrics_();b=c.viewTop-c.contentTop+b.y;b=Math.min(b,c.contentHeight-c.viewHeight);b=Math.max(b,0);this.scrollbar_.set(b);Blockly.WidgetDiv.hide()}a.preventDefault();a.stopPropagation()}; Blockly.VerticalFlyout.prototype.layout_=function(a,b){this.workspace_.scale=this.targetWorkspace_.scale;for(var c=this.MARGIN,d=this.RTL?c:c+Blockly.BlockSvg.TAB_WIDTH,e=0,f;f=a[e];e++)if("block"==f.type){f=f.block;for(var g=f.getDescendants(!1),h=0,k;k=g[h];h++)k.isInFlyout=!0;f.render();g=f.getSvgRoot();h=f.getHeightWidth();f.moveBy(d,c);k=this.createRect_(f,this.RTL?d-h.width:d,c,h,e);this.addBlockListeners_(g,f,k);c+=h.height+b[e]}else"button"==f.type&&(this.initFlyoutButton_(f.button,d,c),c+= f.button.height+b[e])};Blockly.VerticalFlyout.prototype.isDragTowardWorkspace=function(a){a=Math.atan2(a.y,a.x)/Math.PI*180;var b=this.dragAngleRange_;return a-b||a<-180+b||a>180-b?!0:!1}; -Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new goog.math.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new goog.math.Rect(b, +Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new Blockly.utils.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new Blockly.utils.Rect(b, -1E9,1E9+a,2E9)}; Blockly.VerticalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);a=Math.max(a,e)}for(c=0;d=this.buttons_[c];c++)a=Math.max(a,d.width);a+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=a){for(c=0;d=b[c];c++)this.RTL&&(e=d.getRelativeToSurfaceXY().x, d.moveBy(a/this.workspace_.scale-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH-e,0)),d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);if(this.RTL)for(c=0;d=this.buttons_[c];c++)b=d.getPosition().y,d.moveTo(a/this.workspace_.scale-d.width-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH,b);this.width_=a;this.position()}};Blockly.Toolbox=function(a){this.workspace_=a;this.RTL=a.options.RTL;this.horizontalLayout_=a.options.horizontalLayout;this.toolboxPosition=a.options.toolboxPosition;this.config_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"};this.treeSeparatorConfig_={cssTreeRow:"blocklyTreeSeparator"}; @@ -1744,9 +1747,9 @@ Blockly.Toolbox.prototype.setColourFromStyle_=function(a,b,c){if((b.styleName=a) Blockly.Toolbox.prototype.updateColourFromTheme=function(){var a=this.tree_;a&&(this.updateColourFromTheme_(a),this.updateSelectedItemColour_(a))};Blockly.Toolbox.prototype.updateSelectedItemColour_=function(a){var b=a.selectedItem_;if(b){var c=b.hexColour||"#57e";b.getRowElement().style.backgroundColor=c;a.toolbox_.addColour_(b)}}; Blockly.Toolbox.prototype.addColour_=function(a){a=(a||this.tree_).getChildren(!1);for(var b=0,c;c=a[b];b++){var d=c.getRowElement();if(d){var e=this.hasColours_?"8px solid "+(c.hexColour||"#ddd"):"none";this.workspace_.RTL?d.style.borderRight=e:d.style.borderLeft=e}this.addColour_(c)}};Blockly.Toolbox.prototype.clearSelection=function(){this.tree_.setSelectedItem(null)};Blockly.Toolbox.prototype.addStyle=function(a){Blockly.utils.addClass(this.HtmlDiv,a)}; Blockly.Toolbox.prototype.removeStyle=function(a){Blockly.utils.removeClass(this.HtmlDiv,a)}; -Blockly.Toolbox.prototype.getClientRect=function(){if(!this.HtmlDiv)return null;var a=this.HtmlDiv.getBoundingClientRect(),b=a.left,c=a.top,d=a.width;a=a.height;return this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT?new goog.math.Rect(-1E7,-1E7,1E7+b+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?new goog.math.Rect(b,-1E7,1E7+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?new goog.math.Rect(-1E7,-1E7,2E7,1E7+c+a):new goog.math.Rect(0,c,2E7,1E7+d)}; +Blockly.Toolbox.prototype.getClientRect=function(){if(!this.HtmlDiv)return null;var a=this.HtmlDiv.getBoundingClientRect(),b=a.left,c=a.top,d=a.width;a=a.height;return this.toolboxPosition==Blockly.TOOLBOX_AT_LEFT?new Blockly.utils.Rect(-1E7,-1E7,1E7+b+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT?new Blockly.utils.Rect(b,-1E7,1E7+d,2E7):this.toolboxPosition==Blockly.TOOLBOX_AT_TOP?new Blockly.utils.Rect(-1E7,-1E7,2E7,1E7+c+a):new Blockly.utils.Rect(0,c,2E7,1E7+d)}; Blockly.Toolbox.prototype.refreshSelection=function(){var a=this.tree_.getSelectedItem();a&&a.blocks&&this.flyout_.show(a.blocks)};Blockly.Toolbox.TreeControl=function(a,b){this.toolbox_=a;goog.ui.tree.TreeControl.call(this,goog.html.SafeHtml.EMPTY,b)};goog.inherits(Blockly.Toolbox.TreeControl,goog.ui.tree.TreeControl); -Blockly.Toolbox.TreeControl.prototype.enterDocument=function(){Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this);if(goog.events.BrowserFeature.TOUCH_ENABLED){var a=this.getElement();Blockly.bindEventWithChecks_(a,goog.events.EventType.TOUCHEND,this,this.handleTouchEvent_)}};Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_=function(a){var b=this.getNodeFromEvent_(a);b&&a.type===goog.events.EventType.TOUCHEND&&setTimeout(function(){b.onClick_(a)},1)}; +Blockly.Toolbox.TreeControl.prototype.enterDocument=function(){Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this);if(Blockly.Touch.TOUCH_ENABLED){var a=this.getElement();Blockly.bindEventWithChecks_(a,goog.events.EventType.TOUCHEND,this,this.handleTouchEvent_)}};Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_=function(a){var b=this.getNodeFromEvent_(a);b&&a.type===goog.events.EventType.TOUCHEND&&setTimeout(function(){b.onClick_(a)},1)}; Blockly.Toolbox.TreeControl.prototype.createNode=function(a){a=a?goog.html.SafeHtml.htmlEscape(a):goog.html.SafeHtml.EMPTY;return new Blockly.Toolbox.TreeNode(this.toolbox_,a,this.getConfig())}; Blockly.Toolbox.TreeControl.prototype.setSelectedItem=function(a){var b=this.toolbox_;if(a!=this.selectedItem_&&a!=b.tree_){b.lastCategory_&&(b.lastCategory_.getRowElement().style.backgroundColor="");if(a){var c=a.hexColour||"#57e";a.getRowElement().style.backgroundColor=c;b.addColour_(a)}c=this.getSelectedItem();goog.ui.tree.TreeControl.prototype.setSelectedItem.call(this,a);a&&a.blocks&&a.blocks.length?(b.flyout_.show(a.blocks),b.lastCategory_!=a&&b.flyout_.scrollToStart()):b.flyout_.hide();c!= a&&c!=this&&(c=new Blockly.Events.Ui(null,"category",c&&c.getHtml(),a&&a.getHtml()),c.workspaceId=b.workspace_.id,Blockly.Events.fire(c));a&&(b.lastCategory_=a)}};Blockly.Toolbox.TreeNode=function(a,b,c){goog.ui.tree.TreeNode.call(this,b,c);a&&(b=function(){Blockly.svgResize(a.workspace_)},goog.events.listen(a.tree_,goog.ui.tree.BaseNode.EventType.EXPAND,b),goog.events.listen(a.tree_,goog.ui.tree.BaseNode.EventType.COLLAPSE,b))};goog.inherits(Blockly.Toolbox.TreeNode,goog.ui.tree.TreeNode); diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index b1a9b6c6d00..51a663b6974 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -34,22 +34,22 @@ this.BLOCKLY_BOOT = function(root) { dir = this.BLOCKLY_DIR.match(/[^\/]+$/)[0]; } // Execute after Closure has loaded. -goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.utils', 'Blockly.Warning', 'Blockly.Workspace', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.utils', 'Blockly.Warning', 'Blockly.Workspace']); goog.addDependency("../../../" + dir + "/core/block_animations.js", ['Blockly.BlockAnimations'], ['Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.InsertionMarkerManager', 'Blockly.Events', 'Blockly.Events.BlockMove', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils.Coordinate', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.BlockAnimations', 'Blockly.utils.Coordinate', 'Blockly.InsertionMarkerManager', 'Blockly.Events', 'Blockly.Events.BlockMove']); +goog.addDependency("../../../" + dir + "/core/block_events.js", ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.BlockSvg.render'], ['Blockly.BlockSvg', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []); -goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.Workspace', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.Workspace']); +goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg']); goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']); goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []); -goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.math.Coordinate', 'goog.ui.Menu', 'goog.ui.MenuItem']); +goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []); goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/dropdowndiv.js", ['Blockly.DropDownDiv'], ['Blockly.utils', 'goog.style']); @@ -66,17 +66,17 @@ goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldIm goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.FieldTextInput']); -goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.utils.Coordinate', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.utils', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'goog.math.Size']); -goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); +goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils.Coordinate', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.FlyoutDragger'], ['Blockly.WorkspaceDragger']); -goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'goog.math.Rect']); -goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'goog.math.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'Blockly.utils.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.Rect']); goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block']); -goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger']); goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.userAgent', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils.Coordinate', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.Tooltip', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../../" + dir + "/core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.BlockAnimations', 'Blockly.Events', 'Blockly.RenderedConnection']); @@ -85,22 +85,24 @@ goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], goog.addDependency("../../../" + dir + "/core/names.js", ['Blockly.Names'], []); goog.addDependency("../../../" + dir + "/core/options.js", ['Blockly.Options'], ['Blockly.Xml', 'Blockly.Themes.Classic']); goog.addDependency("../../../" + dir + "/core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.Xml.utils']); -goog.addDependency("../../../" + dir + "/core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.utils', 'goog.events.BrowserFeature', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/theme.js", ['Blockly.Theme'], []); goog.addDependency("../../../" + dir + "/core/theme/classic.js", ['Blockly.Themes.Classic'], ['Blockly.Theme']); goog.addDependency("../../../" + dir + "/core/theme/highcontrast.js", ['Blockly.Themes.HighContrast'], ['Blockly.Theme']); goog.addDependency("../../../" + dir + "/core/theme/modern.js", ['Blockly.Themes.Modern'], ['Blockly.Theme']); -goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Flyout', 'Blockly.HorizontalFlyout', 'Blockly.Touch', 'Blockly.utils', 'Blockly.VerticalFlyout', 'goog.events', 'goog.events.BrowserFeature', 'goog.events.EventType', 'goog.html.SafeHtml', 'goog.math.Rect', 'goog.ui.tree.BaseNode', 'goog.ui.tree.TreeControl', 'goog.ui.tree.TreeNode']); +goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Flyout', 'Blockly.HorizontalFlyout', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.VerticalFlyout', 'goog.events', 'goog.events.EventType', 'goog.html.SafeHtml', 'goog.ui.tree.BaseNode', 'goog.ui.tree.TreeControl', 'goog.ui.tree.TreeNode']); goog.addDependency("../../../" + dir + "/core/tooltip.js", ['Blockly.Tooltip'], ['Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/touch.js", ['Blockly.Touch'], ['Blockly.utils', 'goog.events.BrowserFeature']); -goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.TouchGesture'], ['Blockly.Gesture', 'Blockly.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'Blockly.Xml', 'goog.math.Rect']); +goog.addDependency("../../../" + dir + "/core/touch.js", ['Blockly.Touch'], ['Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.TouchGesture'], ['Blockly.utils.Coordinate', 'Blockly.Gesture', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'Blockly.utils.Rect', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], ['goog.style']); goog.addDependency("../../../" + dir + "/core/useragent.js", ['Blockly.userAgent'], []); -goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.Msg', 'Blockly.userAgent', 'goog.math.Coordinate', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.utils.Coordinate', 'Blockly.Msg', 'Blockly.userAgent', 'goog.style']); goog.addDependency("../../../" + dir + "/core/utils_colour.js", ['Blockly.utils.colour'], ['Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/utils_coordinate.js", ['Blockly.utils.Coordinate'], []); +goog.addDependency("../../../" + dir + "/core/utils_rect.js", ['Blockly.utils.Rect'], []); goog.addDependency("../../../" + dir + "/core/variable_events.js", ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/variable_map.js", ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/variable_model.js", ['Blockly.VariableModel'], ['Blockly.Events', 'Blockly.Events.VarCreate', 'Blockly.utils']); @@ -110,14 +112,14 @@ goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.style']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.Events', 'Blockly.utils', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']); goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.userAgent']); -goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.WorkspaceCommentSvg', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.WorkspaceComment', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils']); +goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils.Coordinate', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg']); +goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.WorkspaceComment']); goog.addDependency("../../../" + dir + "/core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']); goog.addDependency("../../../" + dir + "/core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract']); -goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.utils', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.dom', 'goog.math.Coordinate']); -goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.Xml.utils', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.utils', 'Blockly.VariablesDynamic', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceCommentSvg.render', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls']); +goog.addDependency("../../../" + dir + "/core/ws_comment_events.js", ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.utils', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/xml_utils.js", ['Blockly.Xml.utils'], []); goog.addDependency("../../../" + dir + "/core/zoom_controls.js", ['Blockly.ZoomControls'], ['Blockly.Touch', 'Blockly.utils']); @@ -1846,6 +1848,8 @@ goog.require('Blockly.constants'); goog.require('Blockly.inject'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.Rect'); goog.require('Blockly.utils.colour'); goog.require('Blockly.utils.uiMenu'); diff --git a/blocks_compressed.js b/blocks_compressed.js index 00ee48044b5..2ee96693411 100644 --- a/blocks_compressed.js +++ b/blocks_compressed.js @@ -18,27 +18,27 @@ Blockly.Blocks.lists_create_with_item={init:function(){this.setStyle("list_block Blockly.Blocks.lists_indexOf={init:function(){var a=[[Blockly.Msg.LISTS_INDEX_OF_FIRST,"FIRST"],[Blockly.Msg.LISTS_INDEX_OF_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL);this.setStyle("list_blocks");this.setOutput(!0,"Number");this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST);this.appendValueInput("FIND").appendField(new Blockly.FieldDropdown(a),"END");this.setInputsInline(!0);var b=this;this.setTooltip(function(){return Blockly.Msg.LISTS_INDEX_OF_TOOLTIP.replace("%1", b.workspace.options.oneBasedIndex?"0":"-1")})}}; Blockly.Blocks.lists_getIndex={init:function(){var a=[[Blockly.Msg.LISTS_GET_INDEX_GET,"GET"],[Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE,"GET_REMOVE"],[Blockly.Msg.LISTS_GET_INDEX_REMOVE,"REMOVE"]];this.WHERE_OPTIONS=[[Blockly.Msg.LISTS_GET_INDEX_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_INDEX_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_INDEX_FIRST,"FIRST"],[Blockly.Msg.LISTS_GET_INDEX_LAST,"LAST"],[Blockly.Msg.LISTS_GET_INDEX_RANDOM,"RANDOM"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL);this.setStyle("list_blocks"); -a=new Blockly.FieldDropdown(a,function(a){this.sourceBlock_.updateStatement_("REMOVE"==a)});this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);this.appendDummyInput().appendField(a,"MODE").appendField("","SPACE");this.appendDummyInput("AT");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL);this.setInputsInline(!0);this.setOutput(!0);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a= +a=new Blockly.FieldDropdown(a,function(a){a="REMOVE"==a;this.getSourceBlock().updateStatement_(a)});this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);this.appendDummyInput().appendField(a,"MODE").appendField("","SPACE");this.appendDummyInput("AT");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL);this.setInputsInline(!0);this.setOutput(!0);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a= b.getFieldValue("MODE"),d=b.getFieldValue("WHERE"),e="";switch(a+" "+d){case "GET FROM_START":case "GET FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM;break;case "GET FIRST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST;break;case "GET LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST;break;case "GET RANDOM":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM;break;case "GET_REMOVE FROM_START":case "GET_REMOVE FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM;break;case "GET_REMOVE FIRST":e= Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST;break;case "GET_REMOVE LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST;break;case "GET_REMOVE RANDOM":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM;break;case "REMOVE FROM_START":case "REMOVE FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM;break;case "REMOVE FIRST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST;break;case "REMOVE LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST;break;case "REMOVE RANDOM":e= Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM}if("FROM_START"==d||"FROM_END"==d)e+=" "+("FROM_START"==d?Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP:Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP).replace("%1",b.workspace.options.oneBasedIndex?"#1":"#0");return e})},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("statement",!this.outputConnection);var b=this.getInput("AT").type==Blockly.INPUT_VALUE;a.setAttribute("at",b);return a},domToMutation:function(a){var b="true"== a.getAttribute("statement");this.updateStatement_(b);a="false"!=a.getAttribute("at");this.updateAt_(a)},updateStatement_:function(a){a!=!this.outputConnection&&(this.unplug(!0,!0),a?(this.setOutput(!1),this.setPreviousStatement(!0),this.setNextStatement(!0)):(this.setPreviousStatement(!1),this.setNextStatement(!1),this.setOutput(!0)))},updateAt_:function(a){this.removeInput("AT");this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)): -this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.sourceBlock_;e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.getInput("AT").appendField(b,"WHERE");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.moveInputBefore("TAIL",null)}}; +this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.getSourceBlock();e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.getInput("AT").appendField(b,"WHERE");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.moveInputBefore("TAIL",null)}}; Blockly.Blocks.lists_setIndex={init:function(){var a=[[Blockly.Msg.LISTS_SET_INDEX_SET,"SET"],[Blockly.Msg.LISTS_SET_INDEX_INSERT,"INSERT"]];this.WHERE_OPTIONS=[[Blockly.Msg.LISTS_GET_INDEX_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_INDEX_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_INDEX_FIRST,"FIRST"],[Blockly.Msg.LISTS_GET_INDEX_LAST,"LAST"],[Blockly.Msg.LISTS_GET_INDEX_RANDOM,"RANDOM"]];this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL);this.setStyle("list_blocks");this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST); this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"MODE").appendField("","SPACE");this.appendDummyInput("AT");this.appendValueInput("TO").appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO);this.setInputsInline(!0);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("MODE"),d=b.getFieldValue("WHERE"),e="";switch(a+" "+d){case "SET FROM_START":case "SET FROM_END":e= Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM;break;case "SET FIRST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST;break;case "SET LAST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST;break;case "SET RANDOM":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM;break;case "INSERT FROM_START":case "INSERT FROM_END":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM;break;case "INSERT FIRST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST;break;case "INSERT LAST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST; break;case "INSERT RANDOM":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM}if("FROM_START"==d||"FROM_END"==d)e+=" "+Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP.replace("%1",b.workspace.options.oneBasedIndex?"#1":"#0");return e})},mutationToDom:function(){var a=document.createElement("mutation"),b=this.getInput("AT").type==Blockly.INPUT_VALUE;a.setAttribute("at",b);return a},domToMutation:function(a){a="false"!=a.getAttribute("at");this.updateAt_(a)},updateAt_:function(a){this.removeInput("AT"); -this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.sourceBlock_;e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.moveInputBefore("AT","TO");this.getInput("ORDINAL")&&this.moveInputBefore("ORDINAL", +this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.getSourceBlock();e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.moveInputBefore("AT","TO");this.getInput("ORDINAL")&&this.moveInputBefore("ORDINAL", "TO");this.getInput("AT").appendField(b,"WHERE")}}; Blockly.Blocks.lists_getSublist={init:function(){this.WHERE_OPTIONS_1=[[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST,"FIRST"]];this.WHERE_OPTIONS_2=[[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);this.setStyle("list_blocks"); this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);this.appendDummyInput("AT1");this.appendDummyInput("AT2");Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);this.setInputsInline(!0);this.setOutput(!0,"Array");this.updateAt_(1,!0);this.updateAt_(2,!0);this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation"),b=this.getInput("AT1").type== Blockly.INPUT_VALUE;a.setAttribute("at1",b);b=this.getInput("AT2").type==Blockly.INPUT_VALUE;a.setAttribute("at2",b);return a},domToMutation:function(a){var b="true"==a.getAttribute("at1");a="true"==a.getAttribute("at2");this.updateAt_(1,b);this.updateAt_(2,a)},updateAt_:function(a,b){this.removeInput("AT"+a);this.removeInput("ORDINAL"+a,!0);b?(this.appendValueInput("AT"+a).setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL"+a).appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)): -this.appendDummyInput("AT"+a);var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var d="FROM_START"==c||"FROM_END"==c;if(d!=b){var f=this.sourceBlock_;f.updateAt_(a,d);f.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&this.moveInputBefore("ORDINAL1","AT2"));Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.moveInputBefore("TAIL",null)}}; +this.appendDummyInput("AT"+a);var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var d="FROM_START"==c||"FROM_END"==c;if(d!=b){var f=this.getSourceBlock();f.updateAt_(a,d);f.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&this.moveInputBefore("ORDINAL1","AT2"));Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.moveInputBefore("TAIL",null)}}; Blockly.Blocks.lists_sort={init:function(){this.jsonInit({message0:Blockly.Msg.LISTS_SORT_TITLE,args0:[{type:"field_dropdown",name:"TYPE",options:[[Blockly.Msg.LISTS_SORT_TYPE_NUMERIC,"NUMERIC"],[Blockly.Msg.LISTS_SORT_TYPE_TEXT,"TEXT"],[Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE,"IGNORE_CASE"]]},{type:"field_dropdown",name:"DIRECTION",options:[[Blockly.Msg.LISTS_SORT_ORDER_ASCENDING,"1"],[Blockly.Msg.LISTS_SORT_ORDER_DESCENDING,"-1"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Array",style:"list_blocks", tooltip:Blockly.Msg.LISTS_SORT_TOOLTIP,helpUrl:Blockly.Msg.LISTS_SORT_HELPURL})}}; Blockly.Blocks.lists_split={init:function(){var a=this,b=new Blockly.FieldDropdown([[Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT,"SPLIT"],[Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST,"JOIN"]],function(b){a.updateType_(b)});this.setHelpUrl(Blockly.Msg.LISTS_SPLIT_HELPURL);this.setStyle("list_blocks");this.appendValueInput("INPUT").setCheck("String").appendField(b,"MODE");this.appendValueInput("DELIM").setCheck("String").appendField(Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER);this.setInputsInline(!0);this.setOutput(!0, -"Array");this.setTooltip(function(){var b=a.getFieldValue("MODE");if("SPLIT"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT;if("JOIN"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN;throw Error("Unknown mode: "+b);})},updateType_:function(a){if(this.getFieldValue("MODE")!=a){this.setFieldValue(a,"MODE");var b=this.getInput("INPUT").connection;b.setShadowDom(null);var c=b.targetBlock();c&&(b.disconnect(),c.isShadow()?c.dispose():this.bumpNeighbours_())}"SPLIT"==a?(this.outputConnection.setCheck("Array"), -this.getInput("INPUT").setCheck("String")):(this.outputConnection.setCheck("String"),this.getInput("INPUT").setCheck("Array"))},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("mode",this.getFieldValue("MODE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("mode"))}};Blockly.Blocks.logic={};Blockly.Constants.Logic={};Blockly.Constants.Logic.HUE=210; +"Array");this.setTooltip(function(){var b=a.getFieldValue("MODE");if("SPLIT"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT;if("JOIN"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN;throw Error("Unknown mode: "+b);})},updateType_:function(a){if(this.getFieldValue("MODE")!=a){var b=this.getInput("INPUT").connection;b.setShadowDom(null);var c=b.targetBlock();c&&(b.disconnect(),c.isShadow()?c.dispose():this.bumpNeighbours_())}"SPLIT"==a?(this.outputConnection.setCheck("Array"),this.getInput("INPUT").setCheck("String")): +(this.outputConnection.setCheck("String"),this.getInput("INPUT").setCheck("Array"))},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("mode",this.getFieldValue("MODE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("mode"))}};Blockly.Blocks.logic={};Blockly.Constants.Logic={};Blockly.Constants.Logic.HUE=210; Blockly.defineBlocksWithJsonArray([{type:"logic_boolean",message0:"%1",args0:[{type:"field_dropdown",name:"BOOL",options:[["%{BKY_LOGIC_BOOLEAN_TRUE}","TRUE"],["%{BKY_LOGIC_BOOLEAN_FALSE}","FALSE"]]}],output:"Boolean",style:"logic_blocks",tooltip:"%{BKY_LOGIC_BOOLEAN_TOOLTIP}",helpUrl:"%{BKY_LOGIC_BOOLEAN_HELPURL}"},{type:"controls_if",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement", name:"DO0"}],previousStatement:null,nextStatement:null,style:"logic_blocks",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",mutator:"controls_if_mutator",extensions:["controls_if_tooltip"]},{type:"controls_ifelse",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",name:"DO0"}],message2:"%{BKY_CONTROLS_IF_MSG_ELSE} %1",args2:[{type:"input_statement",name:"ELSE"}],previousStatement:null,nextStatement:null, style:"logic_blocks",tooltip:"%{BKYCONTROLS_IF_TOOLTIP_2}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",extensions:["controls_if_tooltip"]},{type:"logic_compare",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A"},{type:"field_dropdown",name:"OP",options:[["=","EQ"],["\u2260","NEQ"],["\u200f<","LT"],["\u200f\u2264","LTE"],["\u200f>","GT"],["\u200f\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:"Boolean",style:"logic_blocks",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",extensions:["logic_compare", @@ -85,7 +85,7 @@ Blockly.Constants.Math.TOOLTIPS_BY_OP={ADD:"%{BKY_MATH_ARITHMETIC_TOOLTIP_ADD}", SIN:"%{BKY_MATH_TRIG_TOOLTIP_SIN}",COS:"%{BKY_MATH_TRIG_TOOLTIP_COS}",TAN:"%{BKY_MATH_TRIG_TOOLTIP_TAN}",ASIN:"%{BKY_MATH_TRIG_TOOLTIP_ASIN}",ACOS:"%{BKY_MATH_TRIG_TOOLTIP_ACOS}",ATAN:"%{BKY_MATH_TRIG_TOOLTIP_ATAN}",SUM:"%{BKY_MATH_ONLIST_TOOLTIP_SUM}",MIN:"%{BKY_MATH_ONLIST_TOOLTIP_MIN}",MAX:"%{BKY_MATH_ONLIST_TOOLTIP_MAX}",AVERAGE:"%{BKY_MATH_ONLIST_TOOLTIP_AVERAGE}",MEDIAN:"%{BKY_MATH_ONLIST_TOOLTIP_MEDIAN}",MODE:"%{BKY_MATH_ONLIST_TOOLTIP_MODE}",STD_DEV:"%{BKY_MATH_ONLIST_TOOLTIP_STD_DEV}",RANDOM:"%{BKY_MATH_ONLIST_TOOLTIP_RANDOM}"}; Blockly.Extensions.register("math_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Math.TOOLTIPS_BY_OP)); Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN={mutationToDom:function(){var a=document.createElement("mutation"),b="DIVISIBLE_BY"==this.getFieldValue("PROPERTY");a.setAttribute("divisor_input",b);return a},domToMutation:function(a){a="true"==a.getAttribute("divisor_input");this.updateShape_(a)},updateShape_:function(a){var b=this.getInput("DIVISOR");a?b||this.appendValueInput("DIVISOR").setCheck("Number"):b&&this.removeInput("DIVISOR")}}; -Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION=function(){this.getField("PROPERTY").setValidator(function(a){this.sourceBlock_.updateShape_("DIVISIBLE_BY"==a)})};Blockly.Extensions.registerMutator("math_is_divisibleby_mutator",Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);Blockly.Extensions.register("math_change_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_MATH_CHANGE_TOOLTIP}","VAR")); +Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION=function(){this.getField("PROPERTY").setValidator(function(a){a="DIVISIBLE_BY"==a;this.getSourceBlock().updateShape_(a)})};Blockly.Extensions.registerMutator("math_is_divisibleby_mutator",Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);Blockly.Extensions.register("math_change_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_MATH_CHANGE_TOOLTIP}","VAR")); Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN={updateType_:function(a){"MODE"==a?this.outputConnection.setCheck("Array"):this.outputConnection.setCheck("Number")},mutationToDom:function(){var a=document.createElement("mutation");a.setAttribute("op",this.getFieldValue("OP"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("op"))}};Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION=function(){this.getField("OP").setValidator(function(a){this.updateType_(a)}.bind(this))}; Blockly.Extensions.registerMutator("math_modes_of_list_mutator",Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN,Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION);Blockly.Blocks.procedures={}; Blockly.Blocks.procedures_defnoreturn={init:function(){var a=new Blockly.FieldTextInput("",Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));(this.workspace.options.comments||this.workspace.options.parentWorkspace&&this.workspace.options.parentWorkspace.options.comments)&&Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT&&this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT); @@ -107,8 +107,8 @@ Blockly.Blocks.procedures_mutatorcontainer={init:function(){this.appendDummyInpu (a.type==Blockly.Events.BLOCK_DELETE||a.type==Blockly.Events.BLOCK_CREATE)){var b=this.workspace.getAllBlocks(),c=this.workspace.getAllVariables();if(a.type==Blockly.Events.BLOCK_DELETE){a=[];for(var d=0;d Date: Thu, 6 Jun 2019 15:39:50 -0700 Subject: [PATCH 110/233] Fix three new and ten existing Closure warnings. Current count: 638 --- blocks/loops.js | 4 ++-- blocks/procedures.js | 4 ++-- blocks/variables_dynamic.js | 8 +++++++- core/connection.js | 4 ++-- core/field.js | 2 +- core/utils_coordinate.js | 4 ++-- core/utils_rect.js | 4 +--- core/workspace_comment_render_svg.js | 4 ++-- 8 files changed, 19 insertions(+), 15 deletions(-) diff --git a/blocks/loops.js b/blocks/loops.js index d8dae09bac4..a60df7b8bcc 100644 --- a/blocks/loops.js +++ b/blocks/loops.js @@ -336,10 +336,10 @@ Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { /** * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. - * @param {!Blockly.Events.Abstract} e Change event. + * @param {!Blockly.Events.Abstract} _e Change event. * @this Blockly.Block */ - onchange: function(/* e */) { + onchange: function(_e) { if (!this.workspace.isDragging || this.workspace.isDragging()) { return; // Don't change state at the start of a drag. } diff --git a/blocks/procedures.js b/blocks/procedures.js index c679ce54dd8..591a751a1d8 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -1048,10 +1048,10 @@ Blockly.Blocks['procedures_ifreturn'] = { /** * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. - * @param {!Blockly.Events.Abstract} e Change event. + * @param {!Blockly.Events.Abstract} _e Change event. * @this Blockly.Block */ - onchange: function(/* e */) { + onchange: function(_e) { if (!this.workspace.isDragging || this.workspace.isDragging()) { return; // Don't change state at the start of a drag. } diff --git a/blocks/variables_dynamic.js b/blocks/variables_dynamic.js index 03b34c2cb34..b0ad6206bea 100644 --- a/blocks/variables_dynamic.js +++ b/blocks/variables_dynamic.js @@ -142,7 +142,13 @@ Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MI } } }, - onchange: function() { + /** + * Called whenever anything on the workspace changes. + * Set the connection type for this block. + * @param {!Blockly.Events.Abstract} _e Change event. + * @this Blockly.Block + */ + onchange: function(_e) { var id = this.getFieldValue('VAR'); var variableModel = this.workspace.getVariableById(id); if (this.type == 'variables_get_dynamic') { diff --git a/core/connection.js b/core/connection.js index 53f0bb2db8d..320039fd24c 100644 --- a/core/connection.js +++ b/core/connection.js @@ -704,11 +704,11 @@ Blockly.Connection.prototype.getShadowDom = function() { * and always return an empty list (the default). * {@link Blockly.RenderedConnection} overrides this behavior with a list * computed from the rendered positioning. - * @param {number} maxLimit The maximum radius to another connection. + * @param {number} _maxLimit The maximum radius to another connection. * @return {!Array.} List of connections. * @private */ -Blockly.Connection.prototype.neighbours_ = function(/* maxLimit */) { +Blockly.Connection.prototype.neighbours_ = function(_maxLimit) { return []; }; diff --git a/core/field.js b/core/field.js index ccfd0551804..8d9d54b0188 100644 --- a/core/field.js +++ b/core/field.js @@ -869,7 +869,7 @@ Blockly.Field.prototype.getClickTarget_ = function() { /** * Return the absolute coordinates of the top-left corner of this field. * The origin (0,0) is the top-left corner of the page body. - * @return {!Blockly.utils.Coordinate} Object with .x and .y properties. + * @return {!goog.math.Coordinate} Object with .x and .y properties. * @private */ Blockly.Field.prototype.getAbsoluteXY_ = function() { diff --git a/core/utils_coordinate.js b/core/utils_coordinate.js index 3d66561e28f..7d08362d35b 100644 --- a/core/utils_coordinate.js +++ b/core/utils_coordinate.js @@ -35,8 +35,8 @@ goog.provide('Blockly.utils.Coordinate'); /** * Class for representing coordinates and positions. - * @param {number=} opt_x Left, defaults to 0. - * @param {number=} opt_y Top, defaults to 0. + * @param {number} x Left. + * @param {number} y Top. * @struct * @constructor */ diff --git a/core/utils_rect.js b/core/utils_rect.js index c9cefbeec15..bc87b5abc7f 100644 --- a/core/utils_rect.js +++ b/core/utils_rect.js @@ -41,7 +41,6 @@ goog.provide('Blockly.utils.Rect'); * @param {number} h Height. * @struct * @constructor - * @implements {goog.math.IRect} */ Blockly.utils.Rect = function(x, y, w, h) { /** @type {number} */ @@ -58,8 +57,7 @@ Blockly.utils.Rect = function(x, y, w, h) { }; /** - * Tests whether this rectangle entirely contains another rectangle or - * coordinate. + * Tests whether this rectangle contains a x/y coordinate. * * @param {number} x The x coordinate to test for containment. * @param {number} y The y coordinate to test for containment. diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index 6aff07c457c..02414037639 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -292,10 +292,10 @@ Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) { /** * Handle a mouse-out on comment's delete icon. - * @param {!Event} e Mouse out event. + * @param {!Event} _e Mouse out event. * @private */ -Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(/*e*/) { +Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(_e) { // Restore highlight on the delete icon. Blockly.utils.removeClass( /** @type {!Element} */ (this.deleteIconBorder_), From d1a29739d85bb9c484b749a7c20db972ef9af698 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 17:30:34 -0700 Subject: [PATCH 111/233] Move utilities into own directory. TODO: There are more functions which may be migrated into dom and string. --- blockly_accessible_compressed.js | 187 ++++---- blockly_accessible_uncompressed.js | 80 ++-- blockly_compressed.js | 187 ++++---- blockly_uncompressed.js | 80 ++-- blocks_compressed.js | 6 +- build.py | 10 +- core/block.js | 5 +- core/block_animations.js | 5 +- core/block_render_svg.js | 6 +- core/block_svg.js | 27 +- core/blockly.js | 10 + core/bubble.js | 6 +- core/contextmenu.js | 3 +- core/dropdowndiv.js | 32 +- core/field.js | 11 +- core/field_angle.js | 7 +- core/field_checkbox.js | 4 +- core/field_date.js | 4 +- core/field_dropdown.js | 10 +- core/field_image.js | 3 +- core/field_label.js | 5 +- core/field_textinput.js | 5 +- core/flyout_base.js | 5 +- core/flyout_button.js | 3 +- core/icon.js | 5 +- core/inject.js | 5 +- core/mutator.js | 5 +- core/rendered_connection.js | 5 +- core/scrollbar.js | 9 +- core/theme/classic.js | 4 +- core/theme/highcontrast.js | 3 + core/theme/modern.js | 3 + core/toolbox.js | 14 +- core/tooltip.js | 4 +- core/touch.js | 13 +- core/trashcan.js | 5 +- core/ui_menu_utils.js | 2 +- core/utils.js | 407 +----------------- core/{utils_colour.js => utils/colour.js} | 10 - .../coordinate.js} | 0 core/utils/dom.js | 132 ++++++ core/utils/math.js | 70 +++ core/{utils_rect.js => utils/rect.js} | 0 core/utils/string.js | 298 +++++++++++++ core/workspace.js | 7 +- core/workspace_audio.js | 1 + core/workspace_comment_render_svg.js | 15 +- core/workspace_comment_svg.js | 23 +- core/workspace_drag_surface_svg.js | 9 +- core/workspace_svg.js | 17 +- core/xml.js | 5 +- core/zoom_controls.js | 3 +- dart_compressed.js | 4 +- generators/dart.js | 3 +- generators/javascript.js | 4 +- generators/lua.js | 3 +- generators/php.js | 3 +- generators/python.js | 4 +- javascript_compressed.js | 2 +- lua_compressed.js | 2 +- php_compressed.js | 2 +- python_compressed.js | 2 +- tests/jsunit/index.html | 3 + tests/jsunit/utils_dom_test.js | 61 +++ tests/jsunit/utils_math_test.js | 42 ++ tests/jsunit/utils_string_test.js | 81 ++++ tests/jsunit/utils_test.js | 123 ------ 67 files changed, 1168 insertions(+), 946 deletions(-) rename core/{utils_colour.js => utils/colour.js} (94%) rename core/{utils_coordinate.js => utils/coordinate.js} (100%) create mode 100644 core/utils/dom.js create mode 100644 core/utils/math.js rename core/{utils_rect.js => utils/rect.js} (100%) create mode 100644 core/utils/string.js create mode 100644 tests/jsunit/utils_dom_test.js create mode 100644 tests/jsunit/utils_math_test.js create mode 100644 tests/jsunit/utils_string_test.js diff --git a/blockly_accessible_compressed.js b/blockly_accessible_compressed.js index b58003a0b64..82578834fc8 100644 --- a/blockly_accessible_compressed.js +++ b/blockly_accessible_compressed.js @@ -878,37 +878,35 @@ var Blockly={};Blockly.Blocks=Object(null); Blockly.utils={};Blockly.utils.Coordinate=function(a,b){this.x=a;this.y=b};Blockly.utils.Coordinate.equals=function(a,b){return a==b?!0:a&&b?a.x==b.x&&a.y==b.y:!1};Blockly.utils.Coordinate.distance=function(a,b){var c=a.x-b.x;a=a.y-b.y;return Math.sqrt(c*c+a*a)};Blockly.utils.Coordinate.magnitude=function(a){return Math.sqrt(a.x*a.x+a.y*a.y)};Blockly.utils.Coordinate.difference=function(a,b){return new Blockly.utils.Coordinate(a.x-b.x,a.y-b.y)}; Blockly.utils.Coordinate.sum=function(a,b){return new Blockly.utils.Coordinate(a.x+b.x,a.y+b.y)};Blockly.utils.Coordinate.prototype.scale=function(a){this.x*=a;this.y*=a;return this};Blockly.utils.Coordinate.prototype.translate=function(a,b){this.x+=a;this.y+=b;return this};Blockly.Msg={};goog.getMsgOrig=goog.getMsg;goog.getMsg=function(a,b){var c=goog.getMsg.blocklyMsgMap[a];c&&(a=Blockly.Msg[c]);return goog.getMsgOrig(a,b)};goog.getMsg.blocklyMsgMap={Today:"TODAY"};Blockly.userAgent={}; (function(a){function b(a){return-1!=c.indexOf(a.toUpperCase())}Blockly.userAgent.raw=a;var c=Blockly.userAgent.raw.toUpperCase();Blockly.userAgent.IE=b("Trident")||b("MSIE");Blockly.userAgent.EDGE=b("Edge");Blockly.userAgent.JAVA_FX=b("JavaFX");Blockly.userAgent.WEBKIT=b("WebKit")&&!Blockly.userAgent.EDGE;Blockly.userAgent.GECKO=b("Gecko")&&!Blockly.userAgent.WEBKIT&&!Blockly.userAgent.IE&&!Blockly.userAgent.EDGE;Blockly.userAgent.ANDROID=b("Android");Blockly.userAgent.IPAD=b("iPad");Blockly.userAgent.IPOD= -b("iPod");Blockly.userAgent.IPHONE=b("iPhone")&&!Blockly.userAgent.IPAD&&!Blockly.userAgent.IPOD;Blockly.userAgent.MAC=b("Macintosh");Blockly.userAgent.TABLET=Blockly.userAgent.IPAD||Blockly.userAgent.ANDROID&&!b("Mobile")||b("Silk");Blockly.userAgent.MOBILE=!Blockly.userAgent.TABLET&&(Blockly.userAgent.IPOD||Blockly.userAgent.IPHONE||Blockly.userAgent.ANDROID||b("IEMobile"))})(this.navigator&&this.navigator.userAgent||""); -Blockly.utils.addClass=function(a,b){var c=a.getAttribute("class")||"";if(-1!=(" "+c+" ").indexOf(" "+b+" "))return!1;c&&(c+=" ");a.setAttribute("class",c+b);return!0};Blockly.utils.removeClass=function(a,b){var c=a.getAttribute("class");if(-1==(" "+c+" ").indexOf(" "+b+" "))return!1;c=c.split(/\s+/);for(var d=0;db&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;a=[];var h=c.length/e,k=1;for(d=0;df);return g}; +Blockly.utils.string.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.utils.string.wrapMutate_(a,e,c):b};Blockly.utils.string.wrapToText_=function(a,b){for(var c=[],d=0;d=h?(e=2,f=h,(h=a.join(""))&&c.push(h),a.length=0):"{"==h?e=3:(a.push("%",h),e=0):2==e?"0"<=h&&"9">=h?f+=h:(c.push(parseInt(f,10)),g--,e=0):3==e&&(""==h?(a.splice(0,0,"%{"),g--,e=0):"}"!=h?a.push(h):(e=a.join(""),/[a-zA-Z][a-zA-Z0-9_]*/.test(e)?(h=e.toUpperCase(), -(h=Blockly.utils.startsWith(h,"BKY_")?h.substring(4):null)&&h in Blockly.Msg?(e=Blockly.Msg[h],"string"==typeof e?Array.prototype.push.apply(c,Blockly.utils.tokenizeInterpolation_(e,b)):b?c.push(String(e)):c.push(e)):c.push("%{"+e+"}")):c.push("%{"+e+"}"),e=a.length=0))}(h=a.join(""))&&c.push(h);b=[];for(g=a.length=0;gc;c++)b[c]=Blockly.utils.genUid.soup_.charAt(Math.random()*a);return b.join("")};Blockly.utils.genUid.soup_="!#$%()*+,-./:;=?@[]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";Blockly.utils.wrap=function(a,b){a=a.split("\n");for(var c=0;cb&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;a=[];var h=c.length/e,k=1;for(d=0;df);return g}; -Blockly.utils.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.utils.wrapMutate_(a,e,c):b};Blockly.utils.wrapToText_=function(a,b){for(var c=[],d=0;dc;c++)b[c]=Blockly.utils.genUid.soup_.charAt(Math.random()*a);return b.join("")};Blockly.utils.genUid.soup_="!#$%()*+,-./:;=?@[]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Blockly.utils.is3dSupported=function(){if(void 0!==Blockly.utils.is3dSupported.cached_)return Blockly.utils.is3dSupported.cached_;if(!Blockly.utils.global.getComputedStyle)return!1;var a=document.createElement("p"),b="none",c={webkitTransform:"-webkit-transform",OTransform:"-o-transform",msTransform:"-ms-transform",MozTransform:"-moz-transform",transform:"transform"};document.body.insertBefore(a,null);for(var d in c)if(void 0!==a.style[d]){a.style[d]="translate3d(1px,1px,1px)";b=Blockly.utils.global.getComputedStyle(a); -if(!b)return document.body.removeChild(a),!1;b=b.getPropertyValue(c[d])}document.body.removeChild(a);Blockly.utils.is3dSupported.cached_="none"!==b;return Blockly.utils.is3dSupported.cached_};Blockly.utils.insertAfter=function(a,b){var c=b.nextSibling;b=b.parentNode;if(!b)throw Error("Reference node has no parent.");c?b.insertBefore(a,c):b.appendChild(a)}; -Blockly.utils.runAfterPageLoad=function(a){if("object"!=typeof document)throw Error("Blockly.utils.runAfterPageLoad() requires browser document.");if("complete"==document.readyState)a();else var b=setInterval(function(){"complete"==document.readyState&&(clearInterval(b),a())},10)};Blockly.utils.setCssTransform=function(a,b){a.style.transform=b;a.style["-webkit-transform"]=b}; -Blockly.utils.getViewportBBox=function(){var a=goog.style.getViewportPageOffset(document);return{right:document.documentElement.clientWidth+a.x,bottom:document.documentElement.clientHeight+a.y,top:a.y,left:a.x}};Blockly.utils.startsWith=function(a,b){return 0==a.lastIndexOf(b,0)};Blockly.utils.arrayRemove=function(a,b){b=a.indexOf(b);if(-1==b)return!1;a.splice(b,1);return!0};Blockly.utils.toRadians=function(a){return a*Math.PI/180};Blockly.utils.toDegrees=function(a){return 180*a/Math.PI}; -Blockly.utils.containsNode=function(a,b){return!!(a.compareDocumentPosition(b)&Node.DOCUMENT_POSITION_CONTAINED_BY)};Blockly.utils.getDocumentScroll=function(){var a=document.documentElement,b=window;return Blockly.userAgent.IE&&b.pageYOffset!=a.scrollTop?new Blockly.utils.Coordinate(a.scrollLeft,a.scrollTop):new Blockly.utils.Coordinate(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}; -Blockly.utils.getBlockTypeCounts=function(a,b){var c=Object.create(null),d=a.getDescendants(!0);b&&(a=a.getNextBlock())&&(a=d.indexOf(a),d.splice(a,d.length-a));for(a=0;b=d[a];a++)c[b.type]?c[b.type]++:c[b.type]=1;return c};Blockly.utils.clampNumber=function(a,b,c){if(c"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=Blockly.Xml.utils.textToDomDocument(a);if(!a||!a.documentElement||"xml"!=a.documentElement.nodeName.toLowerCase())throw TypeError("Blockly.Xml.textToDom expected an document.");return a.documentElement};Blockly.Xml.clearWorkspaceAndLoadFromXml=function(a,b){b.setResizesEnabled(!1);b.clear();a=Blockly.Xml.domToWorkspace(a,b);b.setResizesEnabled(!0);return a}; Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());c=[];Blockly.Field.startCache();var e=a.childNodes.length,f=Blockly.Events.getGroup();f||Blockly.Events.setGroup(!0);b.setResizesEnabled&&b.setResizesEnabled(!1);var g=!0;try{for(var h=0;hthis.MAX_UNDO&&0<=this.MAX_UNDO;)this.undoStack_.shift();for(var b=0,c;c=this.listeners_[b];b++)c(a)}; Blockly.Workspace.prototype.getBlockById=function(a){return this.blockDB_[a]||null};Blockly.Workspace.prototype.getCommentById=function(a){return this.commentDB_[a]||null};Blockly.Workspace.prototype.allInputsFilled=function(a){for(var b=this.getTopBlocks(!1),c=0,d;d=b[c];c++)if(!d.allInputsFilled(a))return!1;return!0};Blockly.Workspace.prototype.getPotentialVariableMap=function(){return this.potentialVariableMap_}; Blockly.Workspace.prototype.createPotentialVariableMap=function(){this.potentialVariableMap_=new Blockly.VariableMap(this)};Blockly.Workspace.prototype.getVariableMap=function(){return this.variableMap_};Blockly.Workspace.WorkspaceDB_=Object.create(null);Blockly.Workspace.getById=function(a){return Blockly.Workspace.WorkspaceDB_[a]||null};Blockly.Workspace.getAll=function(){var a=[],b;for(b in Blockly.Workspace.WorkspaceDB_)a.push(Blockly.Workspace.WorkspaceDB_[b]);return a}; -Blockly.Workspace.prototype.clear=Blockly.Workspace.prototype.clear;Blockly.Workspace.prototype.clearUndo=Blockly.Workspace.prototype.clearUndo;Blockly.Workspace.prototype.addChangeListener=Blockly.Workspace.prototype.addChangeListener;Blockly.Workspace.prototype.removeChangeListener=Blockly.Workspace.prototype.removeChangeListener;Blockly.Bubble=function(a,b,c,d,e,f){this.workspace_=a;this.content_=b;this.shape_=c;c=Blockly.Bubble.ARROW_ANGLE;this.workspace_.RTL&&(c=-c);this.arrow_radians_=Blockly.utils.toRadians(c);a.getBubbleCanvas().appendChild(this.createDom_(b,!(!e||!f)));this.setAnchorLocation(d);e&&f||(b=this.content_.getBBox(),e=b.width+2*Blockly.Bubble.BORDER_WIDTH,f=b.height+2*Blockly.Bubble.BORDER_WIDTH);this.setBubbleSize(e,f);this.positionBubble_();this.renderArrow_();this.rendered_=!0;a.options.readOnly||(Blockly.bindEventWithChecks_(this.bubbleBack_, -"mousedown",this,this.bubbleMouseDown_),this.resizeGroup_&&Blockly.bindEventWithChecks_(this.resizeGroup_,"mousedown",this,this.resizeMouseDown_))};Blockly.Bubble.BORDER_WIDTH=6;Blockly.Bubble.ARROW_THICKNESS=5;Blockly.Bubble.ARROW_ANGLE=20;Blockly.Bubble.ARROW_BEND=4;Blockly.Bubble.ANCHOR_RADIUS=8;Blockly.Bubble.onMouseUpWrapper_=null;Blockly.Bubble.onMouseMoveWrapper_=null;Blockly.Bubble.prototype.resizeCallback_=null; +Blockly.Workspace.prototype.clear=Blockly.Workspace.prototype.clear;Blockly.Workspace.prototype.clearUndo=Blockly.Workspace.prototype.clearUndo;Blockly.Workspace.prototype.addChangeListener=Blockly.Workspace.prototype.addChangeListener;Blockly.Workspace.prototype.removeChangeListener=Blockly.Workspace.prototype.removeChangeListener;Blockly.Bubble=function(a,b,c,d,e,f){this.workspace_=a;this.content_=b;this.shape_=c;c=Blockly.Bubble.ARROW_ANGLE;this.workspace_.RTL&&(c=-c);this.arrow_radians_=Blockly.utils.math.toRadians(c);a.getBubbleCanvas().appendChild(this.createDom_(b,!(!e||!f)));this.setAnchorLocation(d);e&&f||(b=this.content_.getBBox(),e=b.width+2*Blockly.Bubble.BORDER_WIDTH,f=b.height+2*Blockly.Bubble.BORDER_WIDTH);this.setBubbleSize(e,f);this.positionBubble_();this.renderArrow_();this.rendered_=!0;a.options.readOnly|| +(Blockly.bindEventWithChecks_(this.bubbleBack_,"mousedown",this,this.bubbleMouseDown_),this.resizeGroup_&&Blockly.bindEventWithChecks_(this.resizeGroup_,"mousedown",this,this.resizeMouseDown_))};Blockly.Bubble.BORDER_WIDTH=6;Blockly.Bubble.ARROW_THICKNESS=5;Blockly.Bubble.ARROW_ANGLE=20;Blockly.Bubble.ARROW_BEND=4;Blockly.Bubble.ANCHOR_RADIUS=8;Blockly.Bubble.onMouseUpWrapper_=null;Blockly.Bubble.onMouseMoveWrapper_=null;Blockly.Bubble.prototype.resizeCallback_=null; Blockly.Bubble.unbindDragEvents_=function(){Blockly.Bubble.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Bubble.onMouseUpWrapper_),Blockly.Bubble.onMouseUpWrapper_=null);Blockly.Bubble.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Bubble.onMouseMoveWrapper_),Blockly.Bubble.onMouseMoveWrapper_=null)};Blockly.Bubble.bubbleMouseUp_=function(){Blockly.Touch.clearTouchIdentifier();Blockly.Bubble.unbindDragEvents_()};Blockly.Bubble.prototype.rendered_=!1;Blockly.Bubble.prototype.anchorXY_=null; Blockly.Bubble.prototype.relativeLeft_=0;Blockly.Bubble.prototype.relativeTop_=0;Blockly.Bubble.prototype.width_=0;Blockly.Bubble.prototype.height_=0;Blockly.Bubble.prototype.autoLayout_=!0; Blockly.Bubble.prototype.createDom_=function(a,b){this.bubbleGroup_=Blockly.utils.createSvgElement("g",{},null);var c={filter:"url(#"+this.workspace_.options.embossFilterId+")"};Blockly.userAgent.JAVA_FX&&(c={});c=Blockly.utils.createSvgElement("g",c,this.bubbleGroup_);this.bubbleArrow_=Blockly.utils.createSvgElement("path",{},c);this.bubbleBack_=Blockly.utils.createSvgElement("rect",{"class":"blocklyDraggable",x:0,y:0,rx:Blockly.Bubble.BORDER_WIDTH,ry:Blockly.Bubble.BORDER_WIDTH},c);b?(this.resizeGroup_= @@ -1031,11 +1029,12 @@ Blockly.Bubble.prototype.setBubbleSize=function(a,b){var c=2*Blockly.Bubble.BORD this.layoutBubble_(),this.positionBubble_(),this.renderArrow_());this.resizeCallback_&&this.resizeCallback_()}; Blockly.Bubble.prototype.renderArrow_=function(){var a=[],b=this.width_/2,c=this.height_/2,d=-this.relativeLeft_,e=-this.relativeTop_;if(b==d&&c==e)a.push("M "+b+","+c);else{e-=c;d-=b;this.workspace_.RTL&&(d*=-1);var f=Math.sqrt(e*e+d*d),g=Math.acos(d/f);0>e&&(g=2*Math.PI-g);var h=g+Math.PI/2;h>2*Math.PI&&(h-=2*Math.PI);var k=Math.sin(h),l=Math.cos(h),n=this.getBubbleSize();h=(n.width+n.height)/Blockly.Bubble.ARROW_THICKNESS;h=Math.min(h,n.width,n.height)/4;n=1-Blockly.Bubble.ANCHOR_RADIUS/f;d=b+ n*d;e=c+n*e;n=b+h*l;var m=c+h*k;b-=h*l;c-=h*k;k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+n+","+m);a.push("C"+(n+f)+","+(m+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)}; -Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();Blockly.utils.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Bubble.prototype.moveDuringDrag=function(a,b){a?a.translateSurface(b.x,b.y):this.moveTo(b.x,b.y);this.relativeLeft_=this.workspace_.RTL?this.anchorXY_.x-b.x-this.width_:b.x-this.anchorXY_.x;this.relativeTop_=b.y-this.anchorXY_.y;this.renderArrow_()}; +Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();Blockly.utils.dom.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Bubble.prototype.moveDuringDrag=function(a,b){a?a.translateSurface(b.x,b.y):this.moveTo(b.x,b.y);this.relativeLeft_=this.workspace_.RTL?this.anchorXY_.x-b.x-this.width_:b.x-this.anchorXY_.x;this.relativeTop_=b.y-this.anchorXY_.y;this.renderArrow_()}; Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new Blockly.utils.Coordinate(this.anchorXY_.x+this.relativeLeft_,this.anchorXY_.y+this.relativeTop_)};Blockly.Bubble.prototype.setAutoLayout=function(a){this.autoLayout_=a};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this);this.blockId=a?a.id:null;this.workspaceId=a?a.workspace.id:null;this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);this.blockId&&(a.blockId=this.blockId);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue;this.blockId=a.blockId};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null; -Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; -Blockly.Icon.prototype.dispose=function(){Blockly.utils.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; +Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.dom.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; +Blockly.Icon.prototype.dispose=function(){Blockly.utils.dom.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())}; +Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed()||this.block_.isInsertionMarker())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new Blockly.utils.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);Blockly.utils.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; @@ -1065,7 +1064,7 @@ Blockly.Connection.prototype.disconnect=function(){var a=this.targetConnection;i Blockly.Connection.prototype.disconnectInternal_=function(a,b){var c;Blockly.Events.isEnabled()&&(c=new Blockly.Events.BlockMove(b));this.targetConnection=this.targetConnection.targetConnection=null;b.setParent(null);c&&(c.recordNew(),Blockly.Events.fire(c))}; Blockly.Connection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo)if(a=Blockly.Xml.domToBlock(b,a.workspace),a.outputConnection)this.connect(a.outputConnection);else if(a.previousConnection)this.connect(a.previousConnection);else throw Error("Child block does not have output or previous statement.");}; Blockly.Connection.prototype.targetBlock=function(){return this.isConnected()?this.targetConnection.getSourceBlock():null};Blockly.Connection.prototype.checkType_=function(a){if(!this.check_||!a.check_)return!0;for(var b=0;b=this.connections_.length)return-1;for(var c=a.y_,d=b;0<=d&&this.connections_[d].y_==c;){if(this.connections_[d]==a)return d;d--}for(;bc)){var d=b.getSvgXY(a.getSvgRoot());a.outputConnection?(d.x+=(a.RTL?3:-3)*c,d.y+=13*c):a.previousConnection&&(d.x+=(a.RTL?-23:23)*c,d.y+=3*c);a=Blockly.utils.createSvgElement("circle",{cx:d.x,cy:d.y,r:0,fill:"none",stroke:"#888","stroke-width":10},b.getParentSvg());Blockly.BlockAnimations.connectionUiStep_(a,new Date,c)}}; -Blockly.BlockAnimations.connectionUiStep_=function(a,b,c){var d=(new Date-b)/150;1a.workspace.scale)){var b=a.getHeightWidth().height;b=Math.atan(10/b)/Math.PI*180;a.RTL||(b*=-1);Blockly.BlockAnimations.disconnectUiStep_(a.getSvgRoot(),b,new Date)}}; Blockly.BlockAnimations.disconnectUiStep_=function(a,b,c){var d=(new Date-c)/200;1b?!1:Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,a)}; Blockly.RenderedConnection.prototype.connect=function(a){Blockly.RenderedConnection.superClass_.connect.call(this,a);if(this.hidden_||a.hidden_){a=this.isSuperior()?this:a;a.hidden_?a.hideAll():a.unhideAll();var b=a.targetBlock(),c=a.hidden_?"none":"block";b.getSvgRoot().style.display=c;b.rendered=!a.hidden_}}; Blockly.RenderedConnection.prototype.disconnect=function(){var a=this.isSuperior()?this:this.targetConnection;if(this.targetConnection&&a.hidden_){a.unhideAll();var b=a.targetBlock();b.getSvgRoot().style.display="block";b.rendered=!0;a.setHidden(!0)}Blockly.RenderedConnection.superClass_.disconnect.call(this)}; @@ -1129,20 +1128,20 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_=function(){this.woul Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_=function(a){a=new Blockly.utils.Coordinate(a.x/this.workspace_.scale,a.y/this.workspace_.scale);this.workspace_.isMutator&&a.scale(1/this.workspace_.options.parentWorkspace.scale);return a};Blockly.BlockDragger.prototype.dragIcons_=function(a){for(var b=0;bBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,Blockly.Tooltip.showPid_= setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));Blockly.Tooltip.showPid_&&clearTimeout(Blockly.Tooltip.showPid_)};Blockly.Tooltip.block=function(){Blockly.Tooltip.hide();Blockly.Tooltip.blocked_=!0};Blockly.Tooltip.unblock=function(){Blockly.Tooltip.blocked_=!1}; -Blockly.Tooltip.show_=function(){if(!Blockly.Tooltip.blocked_&&(Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_,Blockly.Tooltip.DIV)){Blockly.Tooltip.DIV.innerHTML="";for(var a=Blockly.Tooltip.element_.tooltip;"function"==typeof a;)a=a();a=Blockly.utils.wrap(a,Blockly.Tooltip.LIMIT);a=a.split("\n");for(var b=0;bc+window.scrollY&&(e-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?d=Math.max(Blockly.Tooltip.MARGINS-window.scrollX, d):d+Blockly.Tooltip.DIV.offsetWidth>b+window.scrollX-2*Blockly.Tooltip.MARGINS&&(d=b-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=e+"px";Blockly.Tooltip.DIV.style.left=d+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; this.healStack_=!Blockly.DRAG_STACK}; @@ -1191,14 +1190,14 @@ Blockly.Gesture.inProgress=function(){for(var a=Blockly.Workspace.getAll(),b=0,c Blockly.Grid.prototype.update=function(a){this.scale_=a;var b=this.spacing_*a||100;this.gridPattern_.setAttribute("width",b);this.gridPattern_.setAttribute("height",b);b=Math.floor(this.spacing_/2)+.5;var c=b-this.length_/2,d=b+this.length_/2;b*=a;c*=a;d*=a;this.setLineAttributes_(this.line1_,a,c,d,b,b);this.setLineAttributes_(this.line2_,a,b,b,c,d)}; Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(Blockly.userAgent.IE||Blockly.userAgent.EDGE)&&this.update(this.scale_)}; Blockly.Grid.createDom=function(a,b,c){a=Blockly.utils.createSvgElement("pattern",{id:"blocklyGridPattern"+a,patternUnits:"userSpaceOnUse"},c);0=c+this.handleLength_&&(d+= e);this.setHandlePosition(this.constrainHandle_(d));this.onScroll_();a.stopPropagation();a.preventDefault()}}; @@ -1235,8 +1234,8 @@ Blockly.Trashcan.prototype.SPRITE_LEFT_=0;Blockly.Trashcan.prototype.SPRITE_TOP_ Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyTrash"},null);var a=String(Math.random()).substring(2);var b=Blockly.utils.createSvgElement("clipPath",{id:"blocklyTrashBodyClipPath"+a},this.svgGroup_);Blockly.utils.createSvgElement("rect",{width:this.WIDTH_,height:this.BODY_HEIGHT_,y:this.LID_HEIGHT_},b);var c=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,x:-this.SPRITE_LEFT_,height:Blockly.SPRITE.height,y:-this.SPRITE_TOP_, "clip-path":"url(#blocklyTrashBodyClipPath"+a+")"},this.svgGroup_);c.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.workspace_.options.pathToMedia+Blockly.SPRITE.url);b=Blockly.utils.createSvgElement("clipPath",{id:"blocklyTrashLidClipPath"+a},this.svgGroup_);Blockly.utils.createSvgElement("rect",{width:this.WIDTH_,height:this.LID_HEIGHT_},b);this.svgLid_=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,x:-this.SPRITE_LEFT_,height:Blockly.SPRITE.height,y:-this.SPRITE_TOP_, "clip-path":"url(#blocklyTrashLidClipPath"+a+")"},this.svgGroup_);this.svgLid_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.workspace_.options.pathToMedia+Blockly.SPRITE.url);Blockly.bindEventWithChecks_(this.svgGroup_,"mouseup",this,this.click);Blockly.bindEvent_(c,"mouseover",this,this.mouseOver_);Blockly.bindEvent_(c,"mouseout",this,this.mouseOut_);this.animateLid_();return this.svgGroup_}; -Blockly.Trashcan.prototype.init=function(a){0this.minOpenness_&&1>this.lidOpen_&&(this.lidTask_=setTimeout(this.animateLid_.bind(this),20))}; @@ -1274,22 +1273,22 @@ x1:2*a/3,y1:a-1,x2:a-1,y2:2*a/3},this.resizeGroup_)}; Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_=function(){this.deleteGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyCommentDeleteIcon"},this.svgGroup_);this.deleteIconBorder_=Blockly.utils.createSvgElement("circle",{"class":"blocklyDeleteIconShape",r:"7",cx:"7.5",cy:"7.5"},this.deleteGroup_);Blockly.utils.createSvgElement("line",{x1:"5",y1:"10",x2:"10",y2:"5",stroke:"#fff","stroke-width":"2"},this.deleteGroup_);Blockly.utils.createSvgElement("line",{x1:"5",y1:"5",x2:"10",y2:"10", stroke:"#fff","stroke-width":"2"},this.deleteGroup_)}; Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_=function(a){this.unbindDragEvents_();Blockly.utils.isRightButton(a)||(this.workspace.startDrag(a,new Blockly.utils.Coordinate(this.workspace.RTL?-this.width_:this.width_,this.height_)),this.onMouseUpWrapper_=Blockly.bindEventWithChecks_(document,"mouseup",this,this.resizeMouseUp_),this.onMouseMoveWrapper_=Blockly.bindEventWithChecks_(document,"mousemove",this,this.resizeMouseMove_),Blockly.hideChaff());a.stopPropagation()}; -Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_=function(a){Blockly.utils.addClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted");a.stopPropagation()};Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_=function(){Blockly.utils.removeClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted")};Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_=function(a){this.dispose(!0,!0);a.stopPropagation()}; +Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_=function(a){Blockly.utils.dom.addClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted");a.stopPropagation()};Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_=function(a){Blockly.utils.dom.removeClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted")};Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_=function(a){this.dispose(!0,!0);a.stopPropagation()}; Blockly.WorkspaceCommentSvg.prototype.unbindDragEvents_=function(){this.onMouseUpWrapper_&&(Blockly.unbindEvent_(this.onMouseUpWrapper_),this.onMouseUpWrapper_=null);this.onMouseMoveWrapper_&&(Blockly.unbindEvent_(this.onMouseMoveWrapper_),this.onMouseMoveWrapper_=null)};Blockly.WorkspaceCommentSvg.prototype.resizeMouseUp_=function(){Blockly.Touch.clearTouchIdentifier();this.unbindDragEvents_()}; Blockly.WorkspaceCommentSvg.prototype.resizeMouseMove_=function(a){this.autoLayout_=!1;a=this.workspace.moveDrag(a);this.setSize_(this.RTL?-a.x:a.x,a.y)}; Blockly.WorkspaceCommentSvg.prototype.resizeComment_=function(){var a=this.getHeightWidth(),b=Blockly.WorkspaceCommentSvg.TOP_OFFSET,c=2*Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET;this.foreignObject_.setAttribute("width",a.width);this.foreignObject_.setAttribute("height",a.height-b);this.RTL&&this.foreignObject_.setAttribute("x",-a.width);this.textarea_.style.width=a.width-c+"px";this.textarea_.style.height=a.height-c-b+"px"}; Blockly.WorkspaceCommentSvg.prototype.setSize_=function(a,b){a=Math.max(a,45);b=Math.max(b,20+Blockly.WorkspaceCommentSvg.TOP_OFFSET);this.width_=a;this.height_=b;this.svgRect_.setAttribute("width",a);this.svgRect_.setAttribute("height",b);this.svgRectTarget_.setAttribute("width",a);this.svgRectTarget_.setAttribute("height",b);this.svgHandleTarget_.setAttribute("width",a);this.svgHandleTarget_.setAttribute("height",Blockly.WorkspaceCommentSvg.TOP_OFFSET);this.RTL&&(this.svgRect_.setAttribute("transform", "scale(-1 1)"),this.svgRectTarget_.setAttribute("transform","scale(-1 1)"));var c=Blockly.WorkspaceCommentSvg.RESIZE_SIZE;this.resizeGroup_&&(this.RTL?(this.resizeGroup_.setAttribute("transform","translate("+(-a+c)+","+(b-c)+") scale(-1 1)"),this.deleteGroup_.setAttribute("transform","translate("+(-a+c)+","+-c+") scale(-1 1)")):(this.resizeGroup_.setAttribute("transform","translate("+(a-c)+","+(b-c)+")"),this.deleteGroup_.setAttribute("transform","translate("+(a-c)+","+-c+")")));this.resizeComment_()}; -Blockly.WorkspaceCommentSvg.prototype.disposeInternal_=function(){this.svgHandleTarget_=this.svgRectTarget_=this.foreignObject_=this.textarea_=null;this.disposed_=!0};Blockly.WorkspaceCommentSvg.prototype.setFocus=function(){var a=this;this.focused_=!0;setTimeout(function(){a.disposed_||(a.textarea_.focus(),a.addFocus(),Blockly.utils.addClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.addClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)}; -Blockly.WorkspaceCommentSvg.prototype.blurFocus=function(){var a=this;this.focused_=!1;setTimeout(function(){a.disposed_||(a.textarea_.blur(),a.removeFocus(),Blockly.utils.removeClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.removeClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)};Blockly.WorkspaceDragSurfaceSvg=function(a){this.container_=a;this.createDom()};Blockly.WorkspaceDragSurfaceSvg.prototype.SVG_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.dragGroup_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.container_=null; +Blockly.WorkspaceCommentSvg.prototype.disposeInternal_=function(){this.svgHandleTarget_=this.svgRectTarget_=this.foreignObject_=this.textarea_=null;this.disposed_=!0};Blockly.WorkspaceCommentSvg.prototype.setFocus=function(){var a=this;this.focused_=!0;setTimeout(function(){a.disposed_||(a.textarea_.focus(),a.addFocus(),Blockly.utils.dom.addClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.dom.addClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)}; +Blockly.WorkspaceCommentSvg.prototype.blurFocus=function(){var a=this;this.focused_=!1;setTimeout(function(){a.disposed_||(a.textarea_.blur(),a.removeFocus(),Blockly.utils.dom.removeClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.dom.removeClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)};Blockly.WorkspaceDragSurfaceSvg=function(a){this.container_=a;this.createDom()};Blockly.WorkspaceDragSurfaceSvg.prototype.SVG_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.dragGroup_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.container_=null; Blockly.WorkspaceDragSurfaceSvg.prototype.createDom=function(){this.SVG_||(this.SVG_=Blockly.utils.createSvgElement("svg",{xmlns:Blockly.SVG_NS,"xmlns:html":Blockly.HTML_NS,"xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklyWsDragSurface blocklyOverflowVisible"},null),this.container_.appendChild(this.SVG_))}; Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface=function(a,b){a=a.toFixed(0);b=b.toFixed(0);this.SVG_.style.display="block";Blockly.utils.setCssTransform(this.SVG_,"translate3d("+a+"px, "+b+"px, 0px)")};Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation=function(){return Blockly.utils.getRelativeXY(this.SVG_)}; -Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide=function(a){if(!a)throw Error("Couldn't clear and hide the drag surface: missing new surface.");var b=this.SVG_.childNodes[0],c=this.SVG_.childNodes[1];if(!(b&&c&&Blockly.utils.hasClass(b,"blocklyBlockCanvas")&&Blockly.utils.hasClass(c,"blocklyBubbleCanvas")))throw Error("Couldn't clear and hide the drag surface. A node was missing.");null!=this.previousSibling_?Blockly.utils.insertAfter(b,this.previousSibling_):a.insertBefore(b,a.firstChild); -Blockly.utils.insertAfter(c,b);this.SVG_.style.display="none";if(this.SVG_.childNodes.length)throw Error("Drag surface was not cleared.");Blockly.utils.setCssTransform(this.SVG_,"");this.previousSibling_=null}; +Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide=function(a){if(!a)throw Error("Couldn't clear and hide the drag surface: missing new surface.");var b=this.SVG_.childNodes[0],c=this.SVG_.childNodes[1];if(!(b&&c&&Blockly.utils.dom.hasClass(b,"blocklyBlockCanvas")&&Blockly.utils.dom.hasClass(c,"blocklyBubbleCanvas")))throw Error("Couldn't clear and hide the drag surface. A node was missing.");null!=this.previousSibling_?Blockly.utils.dom.insertAfter(b,this.previousSibling_):a.insertBefore(b,a.firstChild); +Blockly.utils.dom.insertAfter(c,b);this.SVG_.style.display="none";if(this.SVG_.childNodes.length)throw Error("Drag surface was not cleared.");Blockly.utils.setCssTransform(this.SVG_,"");this.previousSibling_=null}; Blockly.WorkspaceDragSurfaceSvg.prototype.setContentsAndShow=function(a,b,c,d,e,f){if(this.SVG_.childNodes.length)throw Error("Already dragging a block.");this.previousSibling_=c;a.setAttribute("transform","translate(0, 0) scale("+f+")");b.setAttribute("transform","translate(0, 0) scale("+f+")");this.SVG_.setAttribute("width",d);this.SVG_.setAttribute("height",e);this.SVG_.appendChild(a);this.SVG_.appendChild(b);this.SVG_.style.display="block"}; Blockly.ZoomControls=function(a){this.workspace_=a};Blockly.ZoomControls.prototype.WIDTH_=32;Blockly.ZoomControls.prototype.HEIGHT_=110;Blockly.ZoomControls.prototype.MARGIN_BOTTOM_=20;Blockly.ZoomControls.prototype.MARGIN_SIDE_=20;Blockly.ZoomControls.prototype.svgGroup_=null;Blockly.ZoomControls.prototype.left_=0;Blockly.ZoomControls.prototype.top_=0; Blockly.ZoomControls.prototype.createDom=function(){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);var a=String(Math.random()).substring(2);this.createZoomOutSvg_(a);this.createZoomInSvg_(a);this.workspace_.isMovable()&&this.createZoomResetSvg_(a);return this.svgGroup_};Blockly.ZoomControls.prototype.init=function(a){this.verticalSpacing_=this.MARGIN_BOTTOM_+a;return this.verticalSpacing_+this.HEIGHT_}; -Blockly.ZoomControls.prototype.dispose=function(){this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.workspace_=null}; +Blockly.ZoomControls.prototype.dispose=function(){this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.workspace_=null}; Blockly.ZoomControls.prototype.position=function(){if(this.verticalSpacing_){var a=this.workspace_.getMetrics();a&&(this.left_=a.toolboxPosition==Blockly.TOOLBOX_AT_LEFT||this.workspace_.horizontalLayout&&!this.workspace_.RTL?a.viewWidth+a.absoluteLeft-this.WIDTH_-this.MARGIN_SIDE_-Blockly.Scrollbar.scrollbarThickness:this.MARGIN_SIDE_+Blockly.Scrollbar.scrollbarThickness,a.toolboxPosition==Blockly.TOOLBOX_AT_BOTTOM?(this.top_=this.verticalSpacing_,this.zoomInGroup_.setAttribute("transform","translate(0, 34)"), this.zoomResetGroup_&&this.zoomResetGroup_.setAttribute("transform","translate(0, 77)")):(this.top_=a.viewHeight+a.absoluteTop-this.HEIGHT_-this.verticalSpacing_,this.zoomInGroup_.setAttribute("transform","translate(0, 43)"),this.zoomOutGroup_.setAttribute("transform","translate(0, 77)")),this.svgGroup_.setAttribute("transform","translate("+this.left_+","+this.top_+")"))}}; Blockly.ZoomControls.prototype.createZoomOutSvg_=function(a){var b=this.workspace_;this.zoomOutGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyZoom"},this.svgGroup_);var c=Blockly.utils.createSvgElement("clipPath",{id:"blocklyZoomoutClipPath"+a},this.zoomOutGroup_);Blockly.utils.createSvgElement("rect",{width:32,height:32},c);a=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,height:Blockly.SPRITE.height,x:-64,y:-92,"clip-path":"url(#blocklyZoomoutClipPath"+a+")"},this.zoomOutGroup_); @@ -1304,12 +1303,12 @@ Blockly.Procedures.flyoutCategory)};goog.inherits(Blockly.WorkspaceSvg,Blockly.W Blockly.WorkspaceSvg.prototype.startScrollY=0;Blockly.WorkspaceSvg.prototype.dragDeltaXY_=null;Blockly.WorkspaceSvg.prototype.scale=1;Blockly.WorkspaceSvg.prototype.trashcan=null;Blockly.WorkspaceSvg.prototype.scrollbar=null;Blockly.WorkspaceSvg.prototype.flyout_=null;Blockly.WorkspaceSvg.prototype.toolbox_=null;Blockly.WorkspaceSvg.prototype.currentGesture_=null;Blockly.WorkspaceSvg.prototype.blockDragSurface_=null;Blockly.WorkspaceSvg.prototype.workspaceDragSurface_=null; Blockly.WorkspaceSvg.prototype.useWorkspaceDragSurface_=!1;Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_=!1;Blockly.WorkspaceSvg.prototype.injectionDiv_=null;Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_=null;Blockly.WorkspaceSvg.prototype.flyoutButtonCallbacks_={};Blockly.WorkspaceSvg.prototype.toolboxCategoryCallbacks_={};Blockly.WorkspaceSvg.prototype.configureContextMenu=null;Blockly.WorkspaceSvg.prototype.targetWorkspace=null;Blockly.WorkspaceSvg.prototype.inverseScreenCTM_=null; Blockly.WorkspaceSvg.prototype.inverseScreenCTMDirty_=!0;Blockly.WorkspaceSvg.prototype.getInverseScreenCTM=function(){if(this.inverseScreenCTMDirty_){var a=this.getParentSvg().getScreenCTM();a&&(this.inverseScreenCTM_=a.inverse(),this.inverseScreenCTMDirty_=!1)}return this.inverseScreenCTM_};Blockly.WorkspaceSvg.prototype.updateInverseScreenCTM=function(){this.inverseScreenCTMDirty_=!0};Blockly.WorkspaceSvg.prototype.isVisible=function(){return this.isVisible_}; -Blockly.WorkspaceSvg.prototype.getSvgXY=function(a){var b=0,c=0,d=1;if(Blockly.utils.containsNode(this.getCanvas(),a)||Blockly.utils.containsNode(this.getBubbleCanvas(),a))d=this.scale;do{var e=Blockly.utils.getRelativeXY(a);if(a==this.getCanvas()||a==this.getBubbleCanvas())d=1;b+=e.x*d;c+=e.y*d;a=a.parentNode}while(a&&a!=this.getParentSvg());return new Blockly.utils.Coordinate(b,c)};Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels=function(){return Blockly.utils.getInjectionDivXY_(this.svgBlockCanvas_)}; +Blockly.WorkspaceSvg.prototype.getSvgXY=function(a){var b=0,c=0,d=1;if(Blockly.utils.dom.containsNode(this.getCanvas(),a)||Blockly.utils.dom.containsNode(this.getBubbleCanvas(),a))d=this.scale;do{var e=Blockly.utils.getRelativeXY(a);if(a==this.getCanvas()||a==this.getBubbleCanvas())d=1;b+=e.x*d;c+=e.y*d;a=a.parentNode}while(a&&a!=this.getParentSvg());return new Blockly.utils.Coordinate(b,c)};Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels=function(){return Blockly.utils.getInjectionDivXY_(this.svgBlockCanvas_)}; Blockly.WorkspaceSvg.prototype.getInjectionDiv=function(){if(!this.injectionDiv_)for(var a=this.svgGroup_;a;){if(-1!=(" "+(a.getAttribute("class")||"")+" ").indexOf(" injectionDiv ")){this.injectionDiv_=a;break}a=a.parentNode}return this.injectionDiv_};Blockly.WorkspaceSvg.prototype.setResizeHandlerWrapper=function(a){this.resizeHandlerWrapper_=a}; Blockly.WorkspaceSvg.prototype.createDom=function(a){this.svgGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyWorkspace"},null);a&&(this.svgBackground_=Blockly.utils.createSvgElement("rect",{height:"100%",width:"100%","class":a},this.svgGroup_),"blocklyMainBackground"==a&&this.grid_&&(this.svgBackground_.style.fill="url(#"+this.grid_.getPatternId()+")"));this.svgBlockCanvas_=Blockly.utils.createSvgElement("g",{"class":"blocklyBlockCanvas"},this.svgGroup_);this.svgBubbleCanvas_=Blockly.utils.createSvgElement("g", {"class":"blocklyBubbleCanvas"},this.svgGroup_);this.isFlyout||(Blockly.bindEventWithChecks_(this.svgGroup_,"mousedown",this,this.onMouseDown_,!1,!0),Blockly.bindEventWithChecks_(this.svgGroup_,"wheel",this,this.onMouseWheel_));this.options.hasCategories&&(this.toolbox_=new Blockly.Toolbox(this));this.grid_&&this.grid_.update(this.scale);this.recordDeleteAreas();return this.svgGroup_}; -Blockly.WorkspaceSvg.prototype.dispose=function(){this.rendered=!1;this.currentGesture_&&this.currentGesture_.cancel();Blockly.WorkspaceSvg.superClass_.dispose.call(this);this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.svgBubbleCanvas_=this.svgBlockCanvas_=null;this.toolbox_&&(this.toolbox_.dispose(),this.toolbox_=null);this.flyout_&&(this.flyout_.dispose(),this.flyout_=null);this.trashcan&&(this.trashcan.dispose(),this.trashcan=null);this.scrollbar&&(this.scrollbar.dispose(), -this.scrollbar=null);this.zoomControls_&&(this.zoomControls_.dispose(),this.zoomControls_=null);this.audioManager_&&(this.audioManager_.dispose(),this.audioManager_=null);this.grid_&&(this.grid_.dispose(),this.grid_=null);this.flyoutButtonCallbacks_=this.toolboxCategoryCallbacks_=null;if(!this.options.parentWorkspace){var a=this.getParentSvg().parentNode;a&&Blockly.utils.removeNode(a)}this.resizeHandlerWrapper_&&(Blockly.unbindEvent_(this.resizeHandlerWrapper_),this.resizeHandlerWrapper_=null)}; +Blockly.WorkspaceSvg.prototype.dispose=function(){this.rendered=!1;this.currentGesture_&&this.currentGesture_.cancel();Blockly.WorkspaceSvg.superClass_.dispose.call(this);this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.svgBubbleCanvas_=this.svgBlockCanvas_=null;this.toolbox_&&(this.toolbox_.dispose(),this.toolbox_=null);this.flyout_&&(this.flyout_.dispose(),this.flyout_=null);this.trashcan&&(this.trashcan.dispose(),this.trashcan=null);this.scrollbar&&(this.scrollbar.dispose(), +this.scrollbar=null);this.zoomControls_&&(this.zoomControls_.dispose(),this.zoomControls_=null);this.audioManager_&&(this.audioManager_.dispose(),this.audioManager_=null);this.grid_&&(this.grid_.dispose(),this.grid_=null);this.flyoutButtonCallbacks_=this.toolboxCategoryCallbacks_=null;if(!this.options.parentWorkspace){var a=this.getParentSvg().parentNode;a&&Blockly.utils.dom.removeNode(a)}this.resizeHandlerWrapper_&&(Blockly.unbindEvent_(this.resizeHandlerWrapper_),this.resizeHandlerWrapper_=null)}; Blockly.WorkspaceSvg.prototype.newBlock=function(a,b){return new Blockly.BlockSvg(this,a,b)};Blockly.WorkspaceSvg.prototype.addTrashcan=function(){this.trashcan=new Blockly.Trashcan(this);var a=this.trashcan.createDom();this.svgGroup_.insertBefore(a,this.svgBlockCanvas_)};Blockly.WorkspaceSvg.prototype.addZoomControls=function(){this.zoomControls_=new Blockly.ZoomControls(this);var a=this.zoomControls_.createDom();this.svgGroup_.appendChild(a)}; Blockly.WorkspaceSvg.prototype.addFlyout_=function(a){var b={disabledPatternId:this.options.disabledPatternId,parentWorkspace:this,RTL:this.RTL,oneBasedIndex:this.options.oneBasedIndex,horizontalLayout:this.horizontalLayout,toolboxPosition:this.options.toolboxPosition};this.flyout_=this.horizontalLayout?new Blockly.HorizontalFlyout(b):new Blockly.VerticalFlyout(b);this.flyout_.autoClose=!1;return this.flyout_.createDom(a)}; Blockly.WorkspaceSvg.prototype.getFlyout=function(){return this.flyout_?this.flyout_:this.toolbox_?this.toolbox_.flyout_:null};Blockly.WorkspaceSvg.prototype.getToolbox=function(){return this.toolbox_};Blockly.WorkspaceSvg.prototype.updateScreenCalculations_=function(){this.updateInverseScreenCTM();this.recordDeleteAreas()}; @@ -1348,7 +1347,7 @@ this.options.languageTree=a;this.flyout_.show(a.childNodes)}}else if(this.option Blockly.WorkspaceSvg.prototype.zoom=function(a,b,c){c=Math.pow(this.options.zoomOptions.scaleSpeed,c);var d=this.scale*c;if(this.scale!=d){d>this.options.zoomOptions.maxScale?c=this.options.zoomOptions.maxScale/this.scale:dthis.options.zoomOptions.maxScale?a=this.options.zoomOptions.maxScale:this.options.zoomOptions.minScale&&aa||Math.abs(this.workspaceHeight_-b)>a)this.workspaceWidth_=c,this.workspaceHeight_=b,this.bubble_.setBubbleSize(c+a,b+a),this.svgDialog_.setAttribute("width",this.workspaceWidth_), this.svgDialog_.setAttribute("height",this.workspaceHeight_);this.block_.RTL&&(a="translate("+this.workspaceWidth_+",0)",this.workspace_.getCanvas().setAttribute("transform",a));this.workspace_.resize()}; Blockly.Mutator.prototype.setVisible=function(a){if(a!=this.isVisible())if(Blockly.Events.fire(new Blockly.Events.Ui(this.block_,"mutatorOpen",!a,a)),a){this.bubble_=new Blockly.Bubble(this.block_.workspace,this.createEditor_(),this.block_.svgPath_,this.iconXY_,null,null);this.bubble_.setSvgId(this.block_.id);if(a=this.workspace_.options.languageTree)this.workspace_.flyout_.init(this.workspace_),this.workspace_.flyout_.show(a.childNodes);this.rootBlock_=this.block_.decompose(this.workspace_);a=this.rootBlock_.getDescendants(!1); @@ -1397,8 +1396,8 @@ Blockly.Field.prototype.SERIALIZABLE=!1;Blockly.Field.prototype.setSourceBlock=f Blockly.Field.prototype.init=function(){this.fieldGroup_||(this.fieldGroup_=Blockly.utils.createSvgElement("g",{},null),this.isVisible()||(this.fieldGroup_.style.display="none"),this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_),this.initView(),this.updateEditable(),this.setTooltip(),this.bindEvents_(),this.initModel())};Blockly.Field.prototype.initView=function(){this.createBorderRect_();this.createTextElement_()}; Blockly.Field.prototype.createBorderRect_=function(){this.borderRect_=Blockly.utils.createSvgElement("rect",{rx:4,ry:4,x:-Blockly.BlockSvg.SEP_SPACE_X/2,y:0,height:16,width:this.size_.width+Blockly.BlockSvg.SEP_SPACE_X},this.fieldGroup_)};Blockly.Field.prototype.createTextElement_=function(){this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-12.5},this.fieldGroup_);this.textContent_=document.createTextNode("");this.textElement_.appendChild(this.textContent_)}; Blockly.Field.prototype.bindEvents_=function(){Blockly.Tooltip.bindMouseEvents(this.getClickTarget_());this.mouseDownWrapper_=Blockly.bindEventWithChecks_(this.getClickTarget_(),"mousedown",this,this.onMouseDown_)};Blockly.Field.prototype.initModel=function(){};Blockly.Field.prototype.fromXml=function(a){this.setValue(a.textContent)};Blockly.Field.prototype.toXml=function(a){a.textContent=this.getValue();return a}; -Blockly.Field.prototype.dispose=function(){this.mouseDownWrapper_&&(Blockly.unbindEvent_(this.mouseDownWrapper_),this.mouseDownWrapper_=null);this.sourceBlock_=null;this.fieldGroup_&&(Blockly.utils.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.validator_=this.borderRect_=this.textElement_=null}; -Blockly.Field.prototype.updateEditable=function(){var a=this.getClickTarget_();this.EDITABLE&&a&&(this.sourceBlock_.isEditable()?(Blockly.utils.addClass(a,"blocklyEditableText"),Blockly.utils.removeClass(a,"blocklyNonEditableText"),a.style.cursor=this.CURSOR):(Blockly.utils.addClass(a,"blocklyNonEditableText"),Blockly.utils.removeClass(a,"blocklyEditableText"),a.style.cursor=""))};Blockly.Field.prototype.isClickable=function(){return!!this.showEditor_&&"function"===typeof this.showEditor_}; +Blockly.Field.prototype.dispose=function(){this.mouseDownWrapper_&&(Blockly.unbindEvent_(this.mouseDownWrapper_),this.mouseDownWrapper_=null);this.sourceBlock_=null;this.fieldGroup_&&(Blockly.utils.dom.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.validator_=this.borderRect_=this.textElement_=null}; +Blockly.Field.prototype.updateEditable=function(){var a=this.getClickTarget_();this.EDITABLE&&a&&(this.sourceBlock_.isEditable()?(Blockly.utils.dom.addClass(a,"blocklyEditableText"),Blockly.utils.dom.removeClass(a,"blocklyNonEditableText"),a.style.cursor=this.CURSOR):(Blockly.utils.dom.addClass(a,"blocklyNonEditableText"),Blockly.utils.dom.removeClass(a,"blocklyEditableText"),a.style.cursor=""))};Blockly.Field.prototype.isClickable=function(){return!!this.showEditor_&&"function"===typeof this.showEditor_}; Blockly.Field.prototype.isCurrentlyEditable=function(){return this.EDITABLE&&!!this.sourceBlock_&&this.sourceBlock_.isEditable()};Blockly.Field.prototype.isSerializable=function(){var a=!1;this.name&&(this.SERIALIZABLE?a=!0:this.EDITABLE&&(console.warn("Detected an editable field that was not serializable. Please define SERIALIZABLE property as true on all editable custom fields. Proceeding with serialization."),a=!0));return a};Blockly.Field.prototype.isVisible=function(){return this.visible_}; Blockly.Field.prototype.setVisible=function(a){if(this.visible_!=a){this.visible_=a;var b=this.getSvgRoot();b&&(b.style.display=a?"block":"none")}};Blockly.Field.prototype.setValidator=function(a){this.validator_=a};Blockly.Field.prototype.getValidator=function(){return this.validator_};Blockly.Field.prototype.classValidator=function(a){return a}; Blockly.Field.prototype.callValidator=function(a){var b=this.classValidator(a);if(null===b)return null;void 0!==b&&(a=b);if(b=this.getValidator()){b=b.call(this,a);if(null===b)return null;void 0!==b&&(a=b)}return a};Blockly.Field.prototype.getSvgRoot=function(){return this.fieldGroup_};Blockly.Field.prototype.updateColour=function(){};Blockly.Field.prototype.render_=function(){this.textContent_.nodeValue=this.getDisplayText_();this.updateSize_()}; @@ -1411,7 +1410,7 @@ Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlo Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.doClassValidation_(a);void 0!==b&&(a=b);if(null===a)this.doValueInvalid_(),this.isDirty_&&this.forceRerender();else{if(b=this.getValidator())if(b=b.call(this,a),void 0!==b&&(a=b),null===a){this.doValueInvalid_();this.isDirty_&&this.forceRerender();return}b=this.getValue();b!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.doValueUpdate_(a), this.isDirty_&&this.forceRerender())}}};Blockly.Field.prototype.value_=null;Blockly.Field.prototype.doClassValidation_=function(a){return a=this.classValidator(a)};Blockly.Field.prototype.doValueUpdate_=function(a){this.value_=a;this.isDirty_=!0;this.text_=String(a)};Blockly.Field.prototype.doValueInvalid_=function(){};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)}; Blockly.Field.prototype.setTooltip=function(a){a||""===a?this.getClickTarget_().tooltip=a:this.getClickTarget_().tooltip=this.sourceBlock_};Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;a=this.doClassValidation_(a);null===a&&(a="");this.setValue(a)};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.initView=function(){this.createTextElement_();this.textElement_.setAttribute("y",this.size_.height-5);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.doClassValidation_=function(a){return null===a||void 0===a?null:String(a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; +Blockly.FieldLabel.prototype.initView=function(){this.createTextElement_();this.textElement_.setAttribute("y",this.size_.height-5);this.class_&&Blockly.utils.dom.addClass(this.textElement_,this.class_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.dom.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.doClassValidation_=function(a){return null===a||void 0===a?null:String(a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; Blockly.Input.prototype.setVisible=function(a){var b=[];if(this.visible_==a)return b;for(var c=(this.visible_=a)?"block":"none",d=0,e;e=this.fieldRow[d];d++)e.setVisible(a);this.connection&&(a?b=this.connection.unhideAll():this.connection.hideAll(),d=this.connection.targetBlock())&&(d.getSvgRoot().style.display=c,a||(d.rendered=!1));return b};Blockly.Input.prototype.setCheck=function(a){if(!this.connection)throw Error("This input does not have a connection.");this.connection.setCheck(a);return this}; @@ -1441,7 +1440,7 @@ Blockly.Block.prototype.setConnectionsHidden=function(a){if(!a&&this.isCollapsed Blockly.Block.prototype.getMatchingConnection=function(a,b){var c=this.getConnections_(!0);a=a.getConnections_(!0);if(c.length!=a.length)throw Error("Connection lists did not match in length.");for(var d=0;d=c)this.hue_=c,this.colour_=Blockly.utils.colour.hueToHex(c);else if(c=Blockly.utils.colour.parse(b))this.colour_=c,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; +Blockly.Block.prototype.setColour=function(a){var b="string"==typeof a?Blockly.utils.replaceMessageReferences(a):a,c=Number(b);if(!isNaN(c)&&0<=c&&360>=c)this.hue_=c,this.colour_=Blockly.hueToHex(c);else if(c=Blockly.utils.colour.parse(b))this.colour_=c,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; Blockly.Block.prototype.setStyle=function(a){var b=Blockly.getTheme();if(!b)throw Error("Trying to set block style to "+a+" before theme was defined via Blockly.setTheme().");b=b.getBlockStyle(a);this.styleName_=a;if(b)this.colourSecondary_=b.colourSecondary,this.colourTertiary_=b.colourTertiary,this.hat=b.hat,this.setColour(b.colourPrimary);else throw Error("Invalid style name: "+a);}; Blockly.Block.prototype.setOnChange=function(a){if(a&&"function"!=typeof a)throw Error("onchange must be a function.");this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);if(this.onchange=a)this.onchangeWrapper_=a.bind(this),this.workspace.addChangeListener(this.onchangeWrapper_)};Blockly.Block.prototype.getField=function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(e.name===a)return e;return null}; Blockly.Block.prototype.getVars=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&a.push(e.getValue());return a};Blockly.Block.prototype.getVarModels=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&(e=this.workspace.getVariableById(e.getValue()))&&a.push(e);return a}; @@ -1462,7 +1461,7 @@ a.inputsInline&&this.setInputsInline(a.inputsInline);void 0!==a.output&&this.set Blockly.Block.prototype.jsonInitColour_=function(a,b){if("colour"in a)if(void 0===a.colour)console.warn(b+"Undefined colour value.");else{a=a.colour;try{this.setColour(a)}catch(c){console.warn(b+"Illegal colour value: ",a)}}};Blockly.Block.prototype.jsonInitStyle_=function(a,b){a=a.style;try{this.setStyle(a)}catch(c){console.warn(b+"Style does not exist: ",a)}}; Blockly.Block.prototype.mixin=function(a,b){if(void 0!==b&&"boolean"!=typeof b)throw Error("opt_disableCheck must be a boolean if provided");if(!b){b=[];for(var c in a)void 0!==this[c]&&b.push(c);if(b.length)throw Error("Mixin will overwrite block members: "+JSON.stringify(b));}goog.mixin(this,a)}; Blockly.Block.prototype.interpolate_=function(a,b,c){var d=Blockly.utils.tokenizeInterpolation(a),e=[],f=0;a=[];for(var g=0;g=h||h>b.length)throw Error('Block "'+this.type+'": Message index %'+h+" out of range.");if(e[h])throw Error('Block "'+this.type+'": Message index %'+h+" duplicated.");e[h]=!0;f++;a.push(b[h-1])}else(h=h.trim())&&a.push(h)}if(f!=b.length)throw Error('Block "'+this.type+'": Message does not reference all '+b.length+" arg(s)."); -a.length&&("string"==typeof a[a.length-1]||Blockly.utils.startsWith(a[a.length-1].type,"field_"))&&(g={type:"input_dummy"},c&&(g.align=c),a.push(g));c={LEFT:Blockly.ALIGN_LEFT,RIGHT:Blockly.ALIGN_RIGHT,CENTRE:Blockly.ALIGN_CENTRE};b=[];for(g=0;ge.bottom)if(d-f.heighte.bottom)if(d-f.heightc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+ Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove", this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; -Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& +Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.math.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& (a-=360),c=String(a),c!=this.text_&&(Blockly.FieldTextInput.htmlInput_.value=a,this.setValue(a),this.text_=c,this.forceRerender()))}; -Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; +Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.math.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.math.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; d-=Math.sin(b)*Blockly.FieldAngle.RADIUS;b=Math.abs(Math.floor((b-e)/Math.PI)%2);Blockly.FieldAngle.CLOCKWISE&&(b=1-b);a.push(" l ",f,",",g," A ",Blockly.FieldAngle.RADIUS,",",Blockly.FieldAngle.RADIUS," 0 ",b," ",Number(Blockly.FieldAngle.CLOCKWISE)," ",c,",",d," z")}this.gauge_.setAttribute("d",a.join(""));this.line_.setAttribute("x2",c);this.line_.setAttribute("y2",d)}}; Blockly.FieldAngle.prototype.doClassValidation_=function(a){if(isNaN(a))return null;a=parseFloat(a||0);a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return a};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){a=this.doClassValidation_(a);null===a&&(a="FALSE");Blockly.FieldCheckbox.superClass_.constructor.call(this,a,b);this.size_.width=Blockly.FieldCheckbox.WIDTH};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked)};Blockly.FieldCheckbox.WIDTH=5;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.CHECK_X_OFFSET=-3;Blockly.FieldCheckbox.CHECK_Y_OFFSET=14; Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.prototype.CURSOR="default";Blockly.FieldCheckbox.prototype.isDirty_=!1; -Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.textElement_.setAttribute("x",Blockly.FieldCheckbox.CHECK_X_OFFSET);this.textElement_.setAttribute("y",Blockly.FieldCheckbox.CHECK_Y_OFFSET);Blockly.utils.addClass(this.textElement_,"blocklyCheckbox");var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.textElement_.appendChild(a);this.textElement_.style.display=this.value_?"block":"none"}; +Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.textElement_.setAttribute("x",Blockly.FieldCheckbox.CHECK_X_OFFSET);this.textElement_.setAttribute("y",Blockly.FieldCheckbox.CHECK_Y_OFFSET);Blockly.utils.dom.addClass(this.textElement_,"blocklyCheckbox");var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.textElement_.appendChild(a);this.textElement_.style.display=this.value_?"block":"none"}; Blockly.FieldCheckbox.prototype.showEditor_=function(){this.setValue(!this.value_)};Blockly.FieldCheckbox.prototype.doClassValidation_=function(a){return!0===a||"TRUE"===a?"TRUE":!1===a||"FALSE"===a?"FALSE":null};Blockly.FieldCheckbox.prototype.doValueUpdate_=function(a){this.value_=this.convertValueToBool_(a);this.textElement_&&(this.textElement_.style.display=this.value_?"block":"none")};Blockly.FieldCheckbox.prototype.getValue=function(){return this.value_?"TRUE":"FALSE"}; Blockly.FieldCheckbox.prototype.getValueBoolean=function(){return this.value_};Blockly.FieldCheckbox.prototype.getText=function(){return String(this.convertValueToBool_(this.value_))};Blockly.FieldCheckbox.prototype.convertValueToBool_=function(a){return"string"==typeof a?"TRUE"==a:!!a};Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.utils.colour={};Blockly.utils.colour.parse=function(a){a=String(a).toLowerCase().trim();var b=Blockly.utils.colour.names[a];if(b)return b;b="#"==a[0]?a:"#"+a;if(/^#[0-9a-f]{6}$/.test(b))return b;if(/^#[0-9a-f]{3}$/.test(b))return["#",b[1],b[1],b[2],b[2],b[3],b[3]].join("");var c=a.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);return c&&(a=Number(c[1]),b=Number(c[2]),c=Number(c[3]),0<=a&&256>a&&0<=b&&256>b&&0<=c&&256>c)?Blockly.utils.colour.rgbToHex(a,b,c):null}; -Blockly.utils.colour.rgbToHex=function(a,b,c){b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};Blockly.utils.colour.hexToRgb=function(a){a=parseInt(a.substr(1),16);return[a>>16,a>>8&255,a&255]};Blockly.utils.colour.hueToHex=function(a){return Blockly.utils.colour.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)}; +Blockly.utils.colour.rgbToHex=function(a,b,c){b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};Blockly.utils.colour.hexToRgb=function(a){a=parseInt(a.substr(1),16);return[a>>16,a>>8&255,a&255]}; Blockly.utils.colour.hsvToHex=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return Blockly.utils.colour.rgbToHex(Math.floor(d),Math.floor(e),Math.floor(f))}; Blockly.utils.colour.blend=function(a,b,c){a=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(a));b=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(b));return Blockly.utils.colour.rgbToHex(Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2])))}; Blockly.utils.colour.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00"};Blockly.FieldColour=function(a,b){a=this.doClassValidation_(a);null===a&&(a=Blockly.FieldColour.COLOURS[0]);Blockly.FieldColour.superClass_.constructor.call(this,a,b)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.prototype.CURSOR="default"; @@ -1620,9 +1619,9 @@ Blockly.FieldDropdown.prototype.initView=function(){Blockly.FieldDropdown.superC this.textContent_):this.textElement_.appendChild(this.arrow_)};Blockly.FieldDropdown.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,null);var a=this.createMenu_();this.addActionListener_(a);this.positionMenu_(a)};Blockly.FieldDropdown.prototype.addActionListener_=function(a){var b=this;goog.events.listen(a,goog.ui.Component.EventType.ACTION,function(a){if(a=a.target)b.onItemSelected(this,a);Blockly.WidgetDiv.hideIfOwner(b);Blockly.Events.setGroup(!1)})}; Blockly.FieldDropdown.prototype.createMenu_=function(){var a=new goog.ui.Menu;a.setRightToLeft(this.sourceBlock_.RTL);for(var b=this.getOptions(),c=0;ce&&(d.height=e);this.sourceBlock_.RTL&&Blockly.utils.uiMenu.adjustBBoxesForRTL(b,c,d);Blockly.WidgetDiv.positionWithAnchor(b,c,d,this.sourceBlock_.RTL);a.getElement().focus()}; -Blockly.FieldDropdown.prototype.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);Blockly.utils.addClass(a.getElement(),"blocklyDropdownMenu");a.setAllowAutoFocus(!0)};Blockly.FieldDropdown.prototype.getAnchorDimensions_=function(){var a=this.getScaledBBox_();this.sourceBlock_.RTL?a.right+=Blockly.FieldDropdown.CHECKMARK_OVERHANG:a.left-=Blockly.FieldDropdown.CHECKMARK_OVERHANG;return a};Blockly.FieldDropdown.prototype.onItemSelected=function(a,b){this.setValue(b.getValue())}; -Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(Array.isArray(a)){for(var b=!1,c=0;ca.length)){b=[];for(c=0;ca.length)){b=[];for(c=0;c=this.height_||0>=this.width_)throw Error("Height and width values of an image field must be greater than 0.");this.size_=new goog.math.Size(this.width_,this.height_+2*Blockly.BlockSvg.INLINE_PADDING_Y);this.flipRtl_=f;this.text_=d||"";this.setValue(a||"");"function"==typeof e&&(this.clickHandler_= e)};goog.inherits(Blockly.FieldImage,Blockly.Field);Blockly.FieldImage.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.src),c=Number(Blockly.utils.replaceMessageReferences(a.width)),d=Number(Blockly.utils.replaceMessageReferences(a.height)),e=Blockly.utils.replaceMessageReferences(a.alt);return new Blockly.FieldImage(b,c,d,e,null,!!a.flipRtl)};Blockly.FieldImage.prototype.EDITABLE=!1;Blockly.FieldImage.prototype.isDirty_=!1; -Blockly.FieldImage.prototype.initView=function(){this.imageElement_=Blockly.utils.createSvgElement("image",{height:this.height_+"px",width:this.width_+"px",alt:this.text_},this.fieldGroup_);this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_)};Blockly.FieldImage.prototype.dispose=function(){this.fieldGroup_&&(Blockly.utils.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.imageElement_=null}; +Blockly.FieldImage.prototype.initView=function(){this.imageElement_=Blockly.utils.createSvgElement("image",{height:this.height_+"px",width:this.width_+"px",alt:this.text_},this.fieldGroup_);this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_)};Blockly.FieldImage.prototype.dispose=function(){this.fieldGroup_&&(Blockly.utils.dom.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.imageElement_=null}; Blockly.FieldImage.prototype.doClassValidation_=function(a){return"string"!=typeof a?null:a};Blockly.FieldImage.prototype.doValueUpdate_=function(a){this.value_=a;this.imageElement_&&this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_||"")};Blockly.FieldImage.prototype.getFlipRtl=function(){return this.flipRtl_};Blockly.FieldImage.prototype.setText=function(a){null!==a&&(this.text_=a,this.imageElement_&&this.imageElement_.setAttribute("alt",a||""))}; Blockly.FieldImage.prototype.showEditor_=function(){this.clickHandler_&&this.clickHandler_(this)};Blockly.Field.register("field_image",Blockly.FieldImage);Blockly.FieldNumber=function(a,b,c,d,e){this.setConstraints(b,c,d);a=this.doClassValidation_(a);null===a&&(a=0);Blockly.FieldNumber.superClass_.constructor.call(this,a,e)};goog.inherits(Blockly.FieldNumber,Blockly.FieldTextInput);Blockly.FieldNumber.fromJson=function(a){return new Blockly.FieldNumber(a.value,a.min,a.max,a.precision)};Blockly.FieldNumber.prototype.SERIALIZABLE=!0; Blockly.FieldNumber.prototype.setConstraints=function(a,b,c){c=parseFloat(c);this.precision_=isNaN(c)?0:c;c=this.precision_.toString();var d=c.indexOf(".");this.fractionalDigits_=-1==d?-1:c.length-(d+1);a=parseFloat(a);this.min_=isNaN(a)?-Infinity:a;b=parseFloat(b);this.max_=isNaN(b)?Infinity:b;this.setValue(this.getValue())}; @@ -1676,21 +1675,21 @@ Blockly.FlyoutButton.prototype.createDom=function(){var a=this.isLabel_?"blockly rx:4,ry:4},this.svgGroup_);var c=Blockly.utils.createSvgElement("text",{"class":this.isLabel_?"blocklyFlyoutLabelText":"blocklyText",x:0,y:0,"text-anchor":"middle"},this.svgGroup_);c.textContent=Blockly.utils.replaceMessageReferences(this.text_);this.width=Blockly.Field.getCachedWidth(c);this.height=20;this.isLabel_||(this.width+=2*Blockly.FlyoutButton.MARGIN,b.setAttribute("width",this.width),b.setAttribute("height",this.height));a.setAttribute("width",this.width);a.setAttribute("height",this.height); c.setAttribute("x",this.width/2);c.setAttribute("y",this.height-Blockly.FlyoutButton.MARGIN);this.updateTransform_();this.onMouseUpWrapper_=Blockly.bindEventWithChecks_(this.svgGroup_,"mouseup",this,this.onMouseUp_);return this.svgGroup_};Blockly.FlyoutButton.prototype.show=function(){this.updateTransform_();this.svgGroup_.setAttribute("display","block")}; Blockly.FlyoutButton.prototype.updateTransform_=function(){this.svgGroup_.setAttribute("transform","translate("+this.position_.x+","+this.position_.y+")")};Blockly.FlyoutButton.prototype.moveTo=function(a,b){this.position_.x=a;this.position_.y=b;this.updateTransform_()};Blockly.FlyoutButton.prototype.getPosition=function(){return this.position_};Blockly.FlyoutButton.prototype.getTargetWorkspace=function(){return this.targetWorkspace_}; -Blockly.FlyoutButton.prototype.dispose=function(){this.onMouseUpWrapper_&&Blockly.unbindEvent_(this.onMouseUpWrapper_);this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.workspace_=null}; +Blockly.FlyoutButton.prototype.dispose=function(){this.onMouseUpWrapper_&&Blockly.unbindEvent_(this.onMouseUpWrapper_);this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.workspace_=null}; Blockly.FlyoutButton.prototype.onMouseUp_=function(a){(a=this.targetWorkspace_.getGesture(a))&&a.cancel();this.isLabel_&&this.callbackKey_?console.warn("Labels should not have callbacks. Label text: "+this.text_):this.isLabel_||this.callbackKey_&&this.targetWorkspace_.getButtonCallback(this.callbackKey_)?this.isLabel_||this.targetWorkspace_.getButtonCallback(this.callbackKey_)(this):console.warn("Buttons should have callbacks. Button text: "+this.text_)};Blockly.Flyout=function(a){a.getMetrics=this.getMetrics_.bind(this);a.setMetrics=this.setMetrics_.bind(this);this.workspace_=new Blockly.WorkspaceSvg(a);this.workspace_.isFlyout=!0;this.RTL=!!a.RTL;this.toolboxPosition_=a.toolboxPosition;this.eventWrappers_=[];this.mats_=[];this.buttons_=[];this.listeners_=[];this.permanentlyDisabled_=[]};Blockly.Flyout.prototype.autoClose=!0;Blockly.Flyout.prototype.isVisible_=!1;Blockly.Flyout.prototype.containerVisible_=!0; Blockly.Flyout.prototype.CORNER_RADIUS=8;Blockly.Flyout.prototype.MARGIN=Blockly.Flyout.prototype.CORNER_RADIUS;Blockly.Flyout.prototype.GAP_X=3*Blockly.Flyout.prototype.MARGIN;Blockly.Flyout.prototype.GAP_Y=3*Blockly.Flyout.prototype.MARGIN;Blockly.Flyout.prototype.SCROLLBAR_PADDING=2;Blockly.Flyout.prototype.width_=0;Blockly.Flyout.prototype.height_=0;Blockly.Flyout.prototype.dragAngleRange_=70; Blockly.Flyout.prototype.createDom=function(a){this.svgGroup_=Blockly.utils.createSvgElement(a,{"class":"blocklyFlyout",style:"display: none"},null);this.svgBackground_=Blockly.utils.createSvgElement("path",{"class":"blocklyFlyoutBackground"},this.svgGroup_);this.svgGroup_.appendChild(this.workspace_.createDom());return this.svgGroup_}; Blockly.Flyout.prototype.init=function(a){this.targetWorkspace_=a;this.workspace_.targetWorkspace=a;this.scrollbar_=new Blockly.Scrollbar(this.workspace_,this.horizontalLayout_,!1,"blocklyFlyoutScrollbar");this.hide();Array.prototype.push.apply(this.eventWrappers_,Blockly.bindEventWithChecks_(this.svgGroup_,"wheel",this,this.wheel_));this.autoClose||(this.filterWrapper_=this.filterForCapacity_.bind(this),this.targetWorkspace_.addChangeListener(this.filterWrapper_));Array.prototype.push.apply(this.eventWrappers_, Blockly.bindEventWithChecks_(this.svgBackground_,"mousedown",this,this.onMouseDown_));this.workspace_.getGesture=this.targetWorkspace_.getGesture.bind(this.targetWorkspace_);this.workspace_.variableMap_=this.targetWorkspace_.getVariableMap();this.workspace_.createPotentialVariableMap()}; -Blockly.Flyout.prototype.dispose=function(){this.hide();Blockly.unbindEvent_(this.eventWrappers_);this.filterWrapper_&&(this.targetWorkspace_.removeChangeListener(this.filterWrapper_),this.filterWrapper_=null);this.scrollbar_&&(this.scrollbar_.dispose(),this.scrollbar_=null);this.workspace_&&(this.workspace_.targetWorkspace=null,this.workspace_.dispose(),this.workspace_=null);this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.svgBackground_=null}; -Blockly.Flyout.prototype.getWidth=function(){return this.width_};Blockly.Flyout.prototype.getHeight=function(){return this.height_};Blockly.Flyout.prototype.getWorkspace=function(){return this.workspace_};Blockly.Flyout.prototype.isVisible=function(){return this.isVisible_};Blockly.Flyout.prototype.setVisible=function(a){var b=a!=this.isVisible();this.isVisible_=a;b&&this.updateDisplay_()}; +Blockly.Flyout.prototype.dispose=function(){this.hide();Blockly.unbindEvent_(this.eventWrappers_);this.filterWrapper_&&(this.targetWorkspace_.removeChangeListener(this.filterWrapper_),this.filterWrapper_=null);this.scrollbar_&&(this.scrollbar_.dispose(),this.scrollbar_=null);this.workspace_&&(this.workspace_.targetWorkspace=null,this.workspace_.dispose(),this.workspace_=null);this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.svgBackground_= +null};Blockly.Flyout.prototype.getWidth=function(){return this.width_};Blockly.Flyout.prototype.getHeight=function(){return this.height_};Blockly.Flyout.prototype.getWorkspace=function(){return this.workspace_};Blockly.Flyout.prototype.isVisible=function(){return this.isVisible_};Blockly.Flyout.prototype.setVisible=function(a){var b=a!=this.isVisible();this.isVisible_=a;b&&this.updateDisplay_()}; Blockly.Flyout.prototype.setContainerVisible=function(a){var b=a!=this.containerVisible_;this.containerVisible_=a;b&&this.updateDisplay_()};Blockly.Flyout.prototype.updateDisplay_=function(){var a=this.containerVisible_?this.isVisible():!1;this.svgGroup_.style.display=a?"block":"none";this.scrollbar_.setContainerVisible(a)}; Blockly.Flyout.prototype.positionAt_=function(a,b,c,d){this.svgGroup_.setAttribute("width",a);this.svgGroup_.setAttribute("height",b);"svg"==this.svgGroup_.tagName?Blockly.utils.setCssTransform(this.svgGroup_,"translate("+c+"px,"+d+"px)"):this.svgGroup_.setAttribute("transform","translate("+c+","+d+")");this.scrollbar_&&(this.scrollbar_.setOrigin(c,d),this.scrollbar_.resize(),this.scrollbar_.setPosition_(this.scrollbar_.position_.x,this.scrollbar_.position_.y))}; Blockly.Flyout.prototype.hide=function(){if(this.isVisible()){this.setVisible(!1);for(var a=0,b;b=this.listeners_[a];a++)Blockly.unbindEvent_(b);this.listeners_.length=0;this.reflowWrapper_&&(this.workspace_.removeChangeListener(this.reflowWrapper_),this.reflowWrapper_=null)}}; Blockly.Flyout.prototype.show=function(a){this.workspace_.setResizesEnabled(!1);this.hide();this.clearOldBlocks_();if("string"==typeof a){a=this.workspace_.targetWorkspace.getToolboxCategoryCallback(a);if("function"!=typeof a)throw TypeError("Couldn't find a callback function when opening a toolbox category.");a=a(this.workspace_.targetWorkspace);if(!Array.isArray(a))throw TypeError("Result of toolbox category callback must be an array.");}this.setVisible(!0);var b=[],c=[];this.permanentlyDisabled_.length= 0;for(var d=this.horizontalLayout_?this.GAP_X:this.GAP_Y,e=0,f;f=a[e];e++)if(f.tagName)switch(f.tagName.toUpperCase()){case "BLOCK":var g=Blockly.Xml.domToBlock(f,this.workspace_);g.isEnabled()||this.permanentlyDisabled_.push(g);b.push({type:"block",block:g});f=parseInt(f.getAttribute("gap"),10);c.push(isNaN(f)?d:f);break;case "SEP":f=parseInt(f.getAttribute("gap"),10);!isNaN(f)&&0b.viewBottom||b.contentLeftb.viewRight){c=null;a&&(c=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));switch(a.type){case Blockly.Events.BLOCK_CREATE:case Blockly.Events.BLOCK_MOVE:var f=e.getBlockById(a.blockId);f=f.getRootBlock();break;case Blockly.Events.COMMENT_CREATE:case Blockly.Events.COMMENT_MOVE:f=e.getCommentById(a.commentId)}if(f){d=f.getBoundingRectangle();var n=b.viewTop-d.topLeft.y; 0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; @@ -1812,7 +1811,7 @@ Blockly.defineBlocksWithJsonArray=function(a){for(var b=0;bb&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;var h=[],k=c.length/e,l=1;for(d=0;df);return g}; +Blockly.utils.string.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.utils.string.wrapMutate_(a,e,c):b};Blockly.utils.string.wrapToText_=function(a,b){for(var c=[],d=0;d=k?(e=2,g=k,(k=f.join(""))&&c.push(k),f.length=0):"{"==k?e=3:(f.push("%",k),e=0):2==e?"0"<=k&&"9">=k?g+=k:(c.push(parseInt(g,10)),h--,e=0):3==e&&(""==k?(f.splice(0,0,"%{"),h--,e=0):"}"!=k?f.push(k):(e=f.join(""),/[a-zA-Z][a-zA-Z0-9_]*/.test(e)?(k=e.toUpperCase(), -(k=Blockly.utils.startsWith(k,"BKY_")?k.substring(4):null)&&k in Blockly.Msg?(e=Blockly.Msg[k],"string"==typeof e?Array.prototype.push.apply(c,Blockly.utils.tokenizeInterpolation_(e,b)):b?c.push(String(e)):c.push(e)):c.push("%{"+e+"}")):c.push("%{"+e+"}"),e=f.length=0))}(k=f.join(""))&&c.push(k);d=[];for(h=f.length=0;hc;c++)b[c]=Blockly.utils.genUid.soup_.charAt(Math.random()*a);return b.join("")};Blockly.utils.genUid.soup_="!#$%()*+,-./:;=?@[]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";Blockly.utils.wrap=function(a,b){for(var c=a.split("\n"),d=0;db&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;var h=[],k=c.length/e,l=1;for(d=0;df);return g}; -Blockly.utils.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.utils.wrapMutate_(a,e,c):b};Blockly.utils.wrapToText_=function(a,b){for(var c=[],d=0;dc;c++)b[c]=Blockly.utils.genUid.soup_.charAt(Math.random()*a);return b.join("")};Blockly.utils.genUid.soup_="!#$%()*+,-./:;=?@[]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Blockly.utils.is3dSupported=function(){if(void 0!==Blockly.utils.is3dSupported.cached_)return Blockly.utils.is3dSupported.cached_;if(!Blockly.utils.global.getComputedStyle)return!1;var a=document.createElement("p"),b="none",c={webkitTransform:"-webkit-transform",OTransform:"-o-transform",msTransform:"-ms-transform",MozTransform:"-moz-transform",transform:"transform"};document.body.insertBefore(a,null);for(var d in c)if(void 0!==a.style[d]){a.style[d]="translate3d(1px,1px,1px)";b=Blockly.utils.global.getComputedStyle(a); -if(!b)return document.body.removeChild(a),!1;b=b.getPropertyValue(c[d])}document.body.removeChild(a);Blockly.utils.is3dSupported.cached_="none"!==b;return Blockly.utils.is3dSupported.cached_};Blockly.utils.insertAfter=function(a,b){var c=b.nextSibling,d=b.parentNode;if(!d)throw Error("Reference node has no parent.");c?d.insertBefore(a,c):d.appendChild(a)}; -Blockly.utils.runAfterPageLoad=function(a){if("object"!=typeof document)throw Error("Blockly.utils.runAfterPageLoad() requires browser document.");if("complete"==document.readyState)a();else var b=setInterval(function(){"complete"==document.readyState&&(clearInterval(b),a())},10)};Blockly.utils.setCssTransform=function(a,b){a.style.transform=b;a.style["-webkit-transform"]=b}; -Blockly.utils.getViewportBBox=function(){var a=goog.style.getViewportPageOffset(document);return{right:document.documentElement.clientWidth+a.x,bottom:document.documentElement.clientHeight+a.y,top:a.y,left:a.x}};Blockly.utils.startsWith=function(a,b){return 0==a.lastIndexOf(b,0)};Blockly.utils.arrayRemove=function(a,b){var c=a.indexOf(b);if(-1==c)return!1;a.splice(c,1);return!0};Blockly.utils.toRadians=function(a){return a*Math.PI/180};Blockly.utils.toDegrees=function(a){return 180*a/Math.PI}; -Blockly.utils.containsNode=function(a,b){return!!(a.compareDocumentPosition(b)&Node.DOCUMENT_POSITION_CONTAINED_BY)};Blockly.utils.getDocumentScroll=function(){var a=document.documentElement,b=window;return Blockly.userAgent.IE&&b.pageYOffset!=a.scrollTop?new Blockly.utils.Coordinate(a.scrollLeft,a.scrollTop):new Blockly.utils.Coordinate(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}; -Blockly.utils.getBlockTypeCounts=function(a,b){var c=Object.create(null),d=a.getDescendants(!0);if(b){var e=a.getNextBlock();e&&(e=d.indexOf(e),d.splice(e,d.length-e))}e=0;for(var f;f=d[e];e++)c[f.type]?c[f.type]++:c[f.type]=1;return c};Blockly.utils.clampNumber=function(a,b,c){if(c"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=Blockly.Xml.utils.textToDomDocument(a);if(!a||!a.documentElement||"xml"!=a.documentElement.nodeName.toLowerCase())throw TypeError("Blockly.Xml.textToDom expected an document.");return a.documentElement};Blockly.Xml.clearWorkspaceAndLoadFromXml=function(a,b){b.setResizesEnabled(!1);b.clear();var c=Blockly.Xml.domToWorkspace(a,b);b.setResizesEnabled(!0);return c}; Blockly.Xml.domToWorkspace=function(a,b){if(a instanceof Blockly.Workspace){var c=a;a=b;b=c;console.warn("Deprecated call to Blockly.Xml.domToWorkspace, swap the arguments.")}var d;b.RTL&&(d=b.getWidth());c=[];Blockly.Field.startCache();var e=a.childNodes.length,f=Blockly.Events.getGroup();f||Blockly.Events.setGroup(!0);b.setResizesEnabled&&b.setResizesEnabled(!1);var g=!0;try{for(var h=0;hthis.MAX_UNDO&&0<=this.MAX_UNDO;)this.undoStack_.shift();for(var b=0,c;c=this.listeners_[b];b++)c(a)}; Blockly.Workspace.prototype.getBlockById=function(a){return this.blockDB_[a]||null};Blockly.Workspace.prototype.getCommentById=function(a){return this.commentDB_[a]||null};Blockly.Workspace.prototype.allInputsFilled=function(a){for(var b=this.getTopBlocks(!1),c=0,d;d=b[c];c++)if(!d.allInputsFilled(a))return!1;return!0};Blockly.Workspace.prototype.getPotentialVariableMap=function(){return this.potentialVariableMap_}; Blockly.Workspace.prototype.createPotentialVariableMap=function(){this.potentialVariableMap_=new Blockly.VariableMap(this)};Blockly.Workspace.prototype.getVariableMap=function(){return this.variableMap_};Blockly.Workspace.WorkspaceDB_=Object.create(null);Blockly.Workspace.getById=function(a){return Blockly.Workspace.WorkspaceDB_[a]||null};Blockly.Workspace.getAll=function(){var a=[],b;for(b in Blockly.Workspace.WorkspaceDB_)a.push(Blockly.Workspace.WorkspaceDB_[b]);return a}; -Blockly.Workspace.prototype.clear=Blockly.Workspace.prototype.clear;Blockly.Workspace.prototype.clearUndo=Blockly.Workspace.prototype.clearUndo;Blockly.Workspace.prototype.addChangeListener=Blockly.Workspace.prototype.addChangeListener;Blockly.Workspace.prototype.removeChangeListener=Blockly.Workspace.prototype.removeChangeListener;Blockly.Bubble=function(a,b,c,d,e,f){this.workspace_=a;this.content_=b;this.shape_=c;c=Blockly.Bubble.ARROW_ANGLE;this.workspace_.RTL&&(c=-c);this.arrow_radians_=Blockly.utils.toRadians(c);a.getBubbleCanvas().appendChild(this.createDom_(b,!(!e||!f)));this.setAnchorLocation(d);e&&f||(b=this.content_.getBBox(),e=b.width+2*Blockly.Bubble.BORDER_WIDTH,f=b.height+2*Blockly.Bubble.BORDER_WIDTH);this.setBubbleSize(e,f);this.positionBubble_();this.renderArrow_();this.rendered_=!0;a.options.readOnly||(Blockly.bindEventWithChecks_(this.bubbleBack_, -"mousedown",this,this.bubbleMouseDown_),this.resizeGroup_&&Blockly.bindEventWithChecks_(this.resizeGroup_,"mousedown",this,this.resizeMouseDown_))};Blockly.Bubble.BORDER_WIDTH=6;Blockly.Bubble.ARROW_THICKNESS=5;Blockly.Bubble.ARROW_ANGLE=20;Blockly.Bubble.ARROW_BEND=4;Blockly.Bubble.ANCHOR_RADIUS=8;Blockly.Bubble.onMouseUpWrapper_=null;Blockly.Bubble.onMouseMoveWrapper_=null;Blockly.Bubble.prototype.resizeCallback_=null; +Blockly.Workspace.prototype.clear=Blockly.Workspace.prototype.clear;Blockly.Workspace.prototype.clearUndo=Blockly.Workspace.prototype.clearUndo;Blockly.Workspace.prototype.addChangeListener=Blockly.Workspace.prototype.addChangeListener;Blockly.Workspace.prototype.removeChangeListener=Blockly.Workspace.prototype.removeChangeListener;Blockly.Bubble=function(a,b,c,d,e,f){this.workspace_=a;this.content_=b;this.shape_=c;c=Blockly.Bubble.ARROW_ANGLE;this.workspace_.RTL&&(c=-c);this.arrow_radians_=Blockly.utils.math.toRadians(c);a.getBubbleCanvas().appendChild(this.createDom_(b,!(!e||!f)));this.setAnchorLocation(d);e&&f||(b=this.content_.getBBox(),e=b.width+2*Blockly.Bubble.BORDER_WIDTH,f=b.height+2*Blockly.Bubble.BORDER_WIDTH);this.setBubbleSize(e,f);this.positionBubble_();this.renderArrow_();this.rendered_=!0;a.options.readOnly|| +(Blockly.bindEventWithChecks_(this.bubbleBack_,"mousedown",this,this.bubbleMouseDown_),this.resizeGroup_&&Blockly.bindEventWithChecks_(this.resizeGroup_,"mousedown",this,this.resizeMouseDown_))};Blockly.Bubble.BORDER_WIDTH=6;Blockly.Bubble.ARROW_THICKNESS=5;Blockly.Bubble.ARROW_ANGLE=20;Blockly.Bubble.ARROW_BEND=4;Blockly.Bubble.ANCHOR_RADIUS=8;Blockly.Bubble.onMouseUpWrapper_=null;Blockly.Bubble.onMouseMoveWrapper_=null;Blockly.Bubble.prototype.resizeCallback_=null; Blockly.Bubble.unbindDragEvents_=function(){Blockly.Bubble.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Bubble.onMouseUpWrapper_),Blockly.Bubble.onMouseUpWrapper_=null);Blockly.Bubble.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Bubble.onMouseMoveWrapper_),Blockly.Bubble.onMouseMoveWrapper_=null)};Blockly.Bubble.bubbleMouseUp_=function(){Blockly.Touch.clearTouchIdentifier();Blockly.Bubble.unbindDragEvents_()};Blockly.Bubble.prototype.rendered_=!1;Blockly.Bubble.prototype.anchorXY_=null; Blockly.Bubble.prototype.relativeLeft_=0;Blockly.Bubble.prototype.relativeTop_=0;Blockly.Bubble.prototype.width_=0;Blockly.Bubble.prototype.height_=0;Blockly.Bubble.prototype.autoLayout_=!0; Blockly.Bubble.prototype.createDom_=function(a,b){this.bubbleGroup_=Blockly.utils.createSvgElement("g",{},null);var c={filter:"url(#"+this.workspace_.options.embossFilterId+")"};Blockly.userAgent.JAVA_FX&&(c={});c=Blockly.utils.createSvgElement("g",c,this.bubbleGroup_);this.bubbleArrow_=Blockly.utils.createSvgElement("path",{},c);this.bubbleBack_=Blockly.utils.createSvgElement("rect",{"class":"blocklyDraggable",x:0,y:0,rx:Blockly.Bubble.BORDER_WIDTH,ry:Blockly.Bubble.BORDER_WIDTH},c);b?(this.resizeGroup_= @@ -1035,11 +1033,12 @@ Blockly.Bubble.prototype.setBubbleSize=function(a,b){var c=2*Blockly.Bubble.BORD this.layoutBubble_(),this.positionBubble_(),this.renderArrow_());this.resizeCallback_&&this.resizeCallback_()}; Blockly.Bubble.prototype.renderArrow_=function(){var a=[],b=this.width_/2,c=this.height_/2,d=-this.relativeLeft_,e=-this.relativeTop_;if(b==d&&c==e)a.push("M "+b+","+c);else{e-=c;d-=b;this.workspace_.RTL&&(d*=-1);var f=Math.sqrt(e*e+d*d),g=Math.acos(d/f);0>e&&(g=2*Math.PI-g);var h=g+Math.PI/2;h>2*Math.PI&&(h-=2*Math.PI);var k=Math.sin(h),l=Math.cos(h),n=this.getBubbleSize();h=(n.width+n.height)/Blockly.Bubble.ARROW_THICKNESS;h=Math.min(h,n.width,n.height)/4;n=1-Blockly.Bubble.ANCHOR_RADIUS/f;d=b+ n*d;e=c+n*e;n=b+h*l;var m=c+h*k;b-=h*l;c-=h*k;k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+n+","+m);a.push("C"+(n+f)+","+(m+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)}; -Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();Blockly.utils.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Bubble.prototype.moveDuringDrag=function(a,b){a?a.translateSurface(b.x,b.y):this.moveTo(b.x,b.y);this.relativeLeft_=this.workspace_.RTL?this.anchorXY_.x-b.x-this.width_:b.x-this.anchorXY_.x;this.relativeTop_=b.y-this.anchorXY_.y;this.renderArrow_()}; +Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();Blockly.utils.dom.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.resizeGroup_=this.bubbleBack_=this.bubbleArrow_=this.bubbleGroup_=null};Blockly.Bubble.prototype.moveDuringDrag=function(a,b){a?a.translateSurface(b.x,b.y):this.moveTo(b.x,b.y);this.relativeLeft_=this.workspace_.RTL?this.anchorXY_.x-b.x-this.width_:b.x-this.anchorXY_.x;this.relativeTop_=b.y-this.anchorXY_.y;this.renderArrow_()}; Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new Blockly.utils.Coordinate(this.anchorXY_.x+this.relativeLeft_,this.anchorXY_.y+this.relativeTop_)};Blockly.Bubble.prototype.setAutoLayout=function(a){this.autoLayout_=a};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this);this.blockId=a?a.id:null;this.workspaceId=a?a.workspace.id:null;this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);this.blockId&&(a.blockId=this.blockId);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue;this.blockId=a.blockId};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null; -Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; -Blockly.Icon.prototype.dispose=function(){Blockly.utils.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; +Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.dom.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; +Blockly.Icon.prototype.dispose=function(){Blockly.utils.dom.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())}; +Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed()||this.block_.isInsertionMarker())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new Blockly.utils.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);Blockly.utils.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; @@ -1069,7 +1068,7 @@ Blockly.Connection.prototype.disconnect=function(){var a=this.targetConnection;i Blockly.Connection.prototype.disconnectInternal_=function(a,b){var c;Blockly.Events.isEnabled()&&(c=new Blockly.Events.BlockMove(b));this.targetConnection=this.targetConnection.targetConnection=null;b.setParent(null);c&&(c.recordNew(),Blockly.Events.fire(c))}; Blockly.Connection.prototype.respawnShadow_=function(){var a=this.getSourceBlock(),b=this.getShadowDom();if(a.workspace&&b&&Blockly.Events.recordUndo)if(a=Blockly.Xml.domToBlock(b,a.workspace),a.outputConnection)this.connect(a.outputConnection);else if(a.previousConnection)this.connect(a.previousConnection);else throw Error("Child block does not have output or previous statement.");}; Blockly.Connection.prototype.targetBlock=function(){return this.isConnected()?this.targetConnection.getSourceBlock():null};Blockly.Connection.prototype.checkType_=function(a){if(!this.check_||!a.check_)return!0;for(var b=0;b=this.connections_.length)return-1;for(var c=a.y_,d=b;0<=d&&this.connections_[d].y_==c;){if(this.connections_[d]==a)return d;d--}for(;bc)){var d=b.getSvgXY(a.getSvgRoot());a.outputConnection?(d.x+=(a.RTL?3:-3)*c,d.y+=13*c):a.previousConnection&&(d.x+=(a.RTL?-23:23)*c,d.y+=3*c);a=Blockly.utils.createSvgElement("circle",{cx:d.x,cy:d.y,r:0,fill:"none",stroke:"#888","stroke-width":10},b.getParentSvg());Blockly.BlockAnimations.connectionUiStep_(a,new Date,c)}}; -Blockly.BlockAnimations.connectionUiStep_=function(a,b,c){var d=(new Date-b)/150;1a.workspace.scale)){var b=a.getHeightWidth().height;b=Math.atan(10/b)/Math.PI*180;a.RTL||(b*=-1);Blockly.BlockAnimations.disconnectUiStep_(a.getSvgRoot(),b,new Date)}}; Blockly.BlockAnimations.disconnectUiStep_=function(a,b,c){var d=(new Date-c)/200;1b?!1:Blockly.RenderedConnection.superClass_.isConnectionAllowed.call(this,a)}; Blockly.RenderedConnection.prototype.connect=function(a){Blockly.RenderedConnection.superClass_.connect.call(this,a);if(this.hidden_||a.hidden_){a=this.isSuperior()?this:a;a.hidden_?a.hideAll():a.unhideAll();var b=a.targetBlock(),c=a.hidden_?"none":"block";b.getSvgRoot().style.display=c;b.rendered=!a.hidden_}}; Blockly.RenderedConnection.prototype.disconnect=function(){var a=this.isSuperior()?this:this.targetConnection;if(this.targetConnection&&a.hidden_){a.unhideAll();var b=a.targetBlock();b.getSvgRoot().style.display="block";b.rendered=!0;a.setHidden(!0)}Blockly.RenderedConnection.superClass_.disconnect.call(this)}; @@ -1133,20 +1132,20 @@ Blockly.BlockDragger.prototype.updateCursorDuringBlockDrag_=function(){this.woul Blockly.BlockDragger.prototype.pixelsToWorkspaceUnits_=function(a){a=new Blockly.utils.Coordinate(a.x/this.workspace_.scale,a.y/this.workspace_.scale);this.workspace_.isMutator&&a.scale(1/this.workspace_.options.parentWorkspace.scale);return a};Blockly.BlockDragger.prototype.dragIcons_=function(a){for(var b=0;bBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.pageX,Blockly.Tooltip.lastY_=a.pageY,Blockly.Tooltip.showPid_= setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));Blockly.Tooltip.showPid_&&clearTimeout(Blockly.Tooltip.showPid_)};Blockly.Tooltip.block=function(){Blockly.Tooltip.hide();Blockly.Tooltip.blocked_=!0};Blockly.Tooltip.unblock=function(){Blockly.Tooltip.blocked_=!1}; -Blockly.Tooltip.show_=function(){if(!Blockly.Tooltip.blocked_&&(Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_,Blockly.Tooltip.DIV)){Blockly.Tooltip.DIV.innerHTML="";for(var a=Blockly.Tooltip.element_.tooltip;"function"==typeof a;)a=a();a=Blockly.utils.wrap(a,Blockly.Tooltip.LIMIT);a=a.split("\n");for(var b=0;bc+window.scrollY&&(e-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?d=Math.max(Blockly.Tooltip.MARGINS-window.scrollX, d):d+Blockly.Tooltip.DIV.offsetWidth>b+window.scrollX-2*Blockly.Tooltip.MARGINS&&(d=b-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.DIV.style.top=e+"px";Blockly.Tooltip.DIV.style.left=d+"px"}};Blockly.Gesture=function(a,b){this.startWorkspace_=this.targetBlock_=this.startBlock_=this.startField_=this.startBubble_=this.currentDragDeltaXY_=this.mouseDownXY_=null;this.creatorWorkspace_=b;this.isDraggingBubble_=this.isDraggingBlock_=this.isDraggingWorkspace_=this.hasExceededDragRadius_=!1;this.mostRecentEvent_=a;this.flyout_=this.workspaceDragger_=this.blockDragger_=this.bubbleDragger_=this.onUpWrapper_=this.onMoveWrapper_=null;this.isEnding_=this.hasStarted_=this.calledUpdateIsDragging_=!1; this.healStack_=!Blockly.DRAG_STACK}; @@ -1195,14 +1194,14 @@ Blockly.Gesture.inProgress=function(){for(var a=Blockly.Workspace.getAll(),b=0,c Blockly.Grid.prototype.update=function(a){this.scale_=a;var b=this.spacing_*a||100;this.gridPattern_.setAttribute("width",b);this.gridPattern_.setAttribute("height",b);b=Math.floor(this.spacing_/2)+.5;var c=b-this.length_/2,d=b+this.length_/2;b*=a;c*=a;d*=a;this.setLineAttributes_(this.line1_,a,c,d,b,b);this.setLineAttributes_(this.line2_,a,b,b,c,d)}; Blockly.Grid.prototype.setLineAttributes_=function(a,b,c,d,e,f){a&&(a.setAttribute("stroke-width",b),a.setAttribute("x1",c),a.setAttribute("y1",e),a.setAttribute("x2",d),a.setAttribute("y2",f))};Blockly.Grid.prototype.moveTo=function(a,b){this.gridPattern_.setAttribute("x",a);this.gridPattern_.setAttribute("y",b);(Blockly.userAgent.IE||Blockly.userAgent.EDGE)&&this.update(this.scale_)}; Blockly.Grid.createDom=function(a,b,c){a=Blockly.utils.createSvgElement("pattern",{id:"blocklyGridPattern"+a,patternUnits:"userSpaceOnUse"},c);0=c+this.handleLength_&&(d+= e);this.setHandlePosition(this.constrainHandle_(d));this.onScroll_();a.stopPropagation();a.preventDefault()}}; @@ -1239,8 +1238,8 @@ Blockly.Trashcan.prototype.SPRITE_LEFT_=0;Blockly.Trashcan.prototype.SPRITE_TOP_ Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyTrash"},null);var a=String(Math.random()).substring(2);var b=Blockly.utils.createSvgElement("clipPath",{id:"blocklyTrashBodyClipPath"+a},this.svgGroup_);Blockly.utils.createSvgElement("rect",{width:this.WIDTH_,height:this.BODY_HEIGHT_,y:this.LID_HEIGHT_},b);var c=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,x:-this.SPRITE_LEFT_,height:Blockly.SPRITE.height,y:-this.SPRITE_TOP_, "clip-path":"url(#blocklyTrashBodyClipPath"+a+")"},this.svgGroup_);c.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.workspace_.options.pathToMedia+Blockly.SPRITE.url);b=Blockly.utils.createSvgElement("clipPath",{id:"blocklyTrashLidClipPath"+a},this.svgGroup_);Blockly.utils.createSvgElement("rect",{width:this.WIDTH_,height:this.LID_HEIGHT_},b);this.svgLid_=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,x:-this.SPRITE_LEFT_,height:Blockly.SPRITE.height,y:-this.SPRITE_TOP_, "clip-path":"url(#blocklyTrashLidClipPath"+a+")"},this.svgGroup_);this.svgLid_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.workspace_.options.pathToMedia+Blockly.SPRITE.url);Blockly.bindEventWithChecks_(this.svgGroup_,"mouseup",this,this.click);Blockly.bindEvent_(c,"mouseover",this,this.mouseOver_);Blockly.bindEvent_(c,"mouseout",this,this.mouseOut_);this.animateLid_();return this.svgGroup_}; -Blockly.Trashcan.prototype.init=function(a){0this.minOpenness_&&1>this.lidOpen_&&(this.lidTask_=setTimeout(this.animateLid_.bind(this),20))}; @@ -1278,22 +1277,22 @@ x1:2*a/3,y1:a-1,x2:a-1,y2:2*a/3},this.resizeGroup_)}; Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_=function(){this.deleteGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyCommentDeleteIcon"},this.svgGroup_);this.deleteIconBorder_=Blockly.utils.createSvgElement("circle",{"class":"blocklyDeleteIconShape",r:"7",cx:"7.5",cy:"7.5"},this.deleteGroup_);Blockly.utils.createSvgElement("line",{x1:"5",y1:"10",x2:"10",y2:"5",stroke:"#fff","stroke-width":"2"},this.deleteGroup_);Blockly.utils.createSvgElement("line",{x1:"5",y1:"5",x2:"10",y2:"10", stroke:"#fff","stroke-width":"2"},this.deleteGroup_)}; Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_=function(a){this.unbindDragEvents_();Blockly.utils.isRightButton(a)||(this.workspace.startDrag(a,new Blockly.utils.Coordinate(this.workspace.RTL?-this.width_:this.width_,this.height_)),this.onMouseUpWrapper_=Blockly.bindEventWithChecks_(document,"mouseup",this,this.resizeMouseUp_),this.onMouseMoveWrapper_=Blockly.bindEventWithChecks_(document,"mousemove",this,this.resizeMouseMove_),Blockly.hideChaff());a.stopPropagation()}; -Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_=function(a){Blockly.utils.addClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted");a.stopPropagation()};Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_=function(){Blockly.utils.removeClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted")};Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_=function(a){this.dispose(!0,!0);a.stopPropagation()}; +Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_=function(a){Blockly.utils.dom.addClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted");a.stopPropagation()};Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_=function(a){Blockly.utils.dom.removeClass(this.deleteIconBorder_,"blocklyDeleteIconHighlighted")};Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_=function(a){this.dispose(!0,!0);a.stopPropagation()}; Blockly.WorkspaceCommentSvg.prototype.unbindDragEvents_=function(){this.onMouseUpWrapper_&&(Blockly.unbindEvent_(this.onMouseUpWrapper_),this.onMouseUpWrapper_=null);this.onMouseMoveWrapper_&&(Blockly.unbindEvent_(this.onMouseMoveWrapper_),this.onMouseMoveWrapper_=null)};Blockly.WorkspaceCommentSvg.prototype.resizeMouseUp_=function(){Blockly.Touch.clearTouchIdentifier();this.unbindDragEvents_()}; Blockly.WorkspaceCommentSvg.prototype.resizeMouseMove_=function(a){this.autoLayout_=!1;a=this.workspace.moveDrag(a);this.setSize_(this.RTL?-a.x:a.x,a.y)}; Blockly.WorkspaceCommentSvg.prototype.resizeComment_=function(){var a=this.getHeightWidth(),b=Blockly.WorkspaceCommentSvg.TOP_OFFSET,c=2*Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET;this.foreignObject_.setAttribute("width",a.width);this.foreignObject_.setAttribute("height",a.height-b);this.RTL&&this.foreignObject_.setAttribute("x",-a.width);this.textarea_.style.width=a.width-c+"px";this.textarea_.style.height=a.height-c-b+"px"}; Blockly.WorkspaceCommentSvg.prototype.setSize_=function(a,b){a=Math.max(a,45);b=Math.max(b,20+Blockly.WorkspaceCommentSvg.TOP_OFFSET);this.width_=a;this.height_=b;this.svgRect_.setAttribute("width",a);this.svgRect_.setAttribute("height",b);this.svgRectTarget_.setAttribute("width",a);this.svgRectTarget_.setAttribute("height",b);this.svgHandleTarget_.setAttribute("width",a);this.svgHandleTarget_.setAttribute("height",Blockly.WorkspaceCommentSvg.TOP_OFFSET);this.RTL&&(this.svgRect_.setAttribute("transform", "scale(-1 1)"),this.svgRectTarget_.setAttribute("transform","scale(-1 1)"));var c=Blockly.WorkspaceCommentSvg.RESIZE_SIZE;this.resizeGroup_&&(this.RTL?(this.resizeGroup_.setAttribute("transform","translate("+(-a+c)+","+(b-c)+") scale(-1 1)"),this.deleteGroup_.setAttribute("transform","translate("+(-a+c)+","+-c+") scale(-1 1)")):(this.resizeGroup_.setAttribute("transform","translate("+(a-c)+","+(b-c)+")"),this.deleteGroup_.setAttribute("transform","translate("+(a-c)+","+-c+")")));this.resizeComment_()}; -Blockly.WorkspaceCommentSvg.prototype.disposeInternal_=function(){this.svgHandleTarget_=this.svgRectTarget_=this.foreignObject_=this.textarea_=null;this.disposed_=!0};Blockly.WorkspaceCommentSvg.prototype.setFocus=function(){var a=this;this.focused_=!0;setTimeout(function(){a.disposed_||(a.textarea_.focus(),a.addFocus(),Blockly.utils.addClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.addClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)}; -Blockly.WorkspaceCommentSvg.prototype.blurFocus=function(){var a=this;this.focused_=!1;setTimeout(function(){a.disposed_||(a.textarea_.blur(),a.removeFocus(),Blockly.utils.removeClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.removeClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)};Blockly.WorkspaceDragSurfaceSvg=function(a){this.container_=a;this.createDom()};Blockly.WorkspaceDragSurfaceSvg.prototype.SVG_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.dragGroup_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.container_=null; +Blockly.WorkspaceCommentSvg.prototype.disposeInternal_=function(){this.svgHandleTarget_=this.svgRectTarget_=this.foreignObject_=this.textarea_=null;this.disposed_=!0};Blockly.WorkspaceCommentSvg.prototype.setFocus=function(){var a=this;this.focused_=!0;setTimeout(function(){a.disposed_||(a.textarea_.focus(),a.addFocus(),Blockly.utils.dom.addClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.dom.addClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)}; +Blockly.WorkspaceCommentSvg.prototype.blurFocus=function(){var a=this;this.focused_=!1;setTimeout(function(){a.disposed_||(a.textarea_.blur(),a.removeFocus(),Blockly.utils.dom.removeClass(a.svgRectTarget_,"blocklyCommentTargetFocused"),Blockly.utils.dom.removeClass(a.svgHandleTarget_,"blocklyCommentHandleTargetFocused"))},0)};Blockly.WorkspaceDragSurfaceSvg=function(a){this.container_=a;this.createDom()};Blockly.WorkspaceDragSurfaceSvg.prototype.SVG_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.dragGroup_=null;Blockly.WorkspaceDragSurfaceSvg.prototype.container_=null; Blockly.WorkspaceDragSurfaceSvg.prototype.createDom=function(){this.SVG_||(this.SVG_=Blockly.utils.createSvgElement("svg",{xmlns:Blockly.SVG_NS,"xmlns:html":Blockly.HTML_NS,"xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklyWsDragSurface blocklyOverflowVisible"},null),this.container_.appendChild(this.SVG_))}; Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface=function(a,b){var c=a.toFixed(0),d=b.toFixed(0);this.SVG_.style.display="block";Blockly.utils.setCssTransform(this.SVG_,"translate3d("+c+"px, "+d+"px, 0px)")};Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation=function(){return Blockly.utils.getRelativeXY(this.SVG_)}; -Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide=function(a){if(!a)throw Error("Couldn't clear and hide the drag surface: missing new surface.");var b=this.SVG_.childNodes[0],c=this.SVG_.childNodes[1];if(!(b&&c&&Blockly.utils.hasClass(b,"blocklyBlockCanvas")&&Blockly.utils.hasClass(c,"blocklyBubbleCanvas")))throw Error("Couldn't clear and hide the drag surface. A node was missing.");null!=this.previousSibling_?Blockly.utils.insertAfter(b,this.previousSibling_):a.insertBefore(b,a.firstChild); -Blockly.utils.insertAfter(c,b);this.SVG_.style.display="none";if(this.SVG_.childNodes.length)throw Error("Drag surface was not cleared.");Blockly.utils.setCssTransform(this.SVG_,"");this.previousSibling_=null}; +Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide=function(a){if(!a)throw Error("Couldn't clear and hide the drag surface: missing new surface.");var b=this.SVG_.childNodes[0],c=this.SVG_.childNodes[1];if(!(b&&c&&Blockly.utils.dom.hasClass(b,"blocklyBlockCanvas")&&Blockly.utils.dom.hasClass(c,"blocklyBubbleCanvas")))throw Error("Couldn't clear and hide the drag surface. A node was missing.");null!=this.previousSibling_?Blockly.utils.dom.insertAfter(b,this.previousSibling_):a.insertBefore(b,a.firstChild); +Blockly.utils.dom.insertAfter(c,b);this.SVG_.style.display="none";if(this.SVG_.childNodes.length)throw Error("Drag surface was not cleared.");Blockly.utils.setCssTransform(this.SVG_,"");this.previousSibling_=null}; Blockly.WorkspaceDragSurfaceSvg.prototype.setContentsAndShow=function(a,b,c,d,e,f){if(this.SVG_.childNodes.length)throw Error("Already dragging a block.");this.previousSibling_=c;a.setAttribute("transform","translate(0, 0) scale("+f+")");b.setAttribute("transform","translate(0, 0) scale("+f+")");this.SVG_.setAttribute("width",d);this.SVG_.setAttribute("height",e);this.SVG_.appendChild(a);this.SVG_.appendChild(b);this.SVG_.style.display="block"}; Blockly.ZoomControls=function(a){this.workspace_=a};Blockly.ZoomControls.prototype.WIDTH_=32;Blockly.ZoomControls.prototype.HEIGHT_=110;Blockly.ZoomControls.prototype.MARGIN_BOTTOM_=20;Blockly.ZoomControls.prototype.MARGIN_SIDE_=20;Blockly.ZoomControls.prototype.svgGroup_=null;Blockly.ZoomControls.prototype.left_=0;Blockly.ZoomControls.prototype.top_=0; Blockly.ZoomControls.prototype.createDom=function(){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);var a=String(Math.random()).substring(2);this.createZoomOutSvg_(a);this.createZoomInSvg_(a);this.workspace_.isMovable()&&this.createZoomResetSvg_(a);return this.svgGroup_};Blockly.ZoomControls.prototype.init=function(a){this.verticalSpacing_=this.MARGIN_BOTTOM_+a;return this.verticalSpacing_+this.HEIGHT_}; -Blockly.ZoomControls.prototype.dispose=function(){this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.workspace_=null}; +Blockly.ZoomControls.prototype.dispose=function(){this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.workspace_=null}; Blockly.ZoomControls.prototype.position=function(){if(this.verticalSpacing_){var a=this.workspace_.getMetrics();a&&(this.left_=a.toolboxPosition==Blockly.TOOLBOX_AT_LEFT||this.workspace_.horizontalLayout&&!this.workspace_.RTL?a.viewWidth+a.absoluteLeft-this.WIDTH_-this.MARGIN_SIDE_-Blockly.Scrollbar.scrollbarThickness:this.MARGIN_SIDE_+Blockly.Scrollbar.scrollbarThickness,a.toolboxPosition==Blockly.TOOLBOX_AT_BOTTOM?(this.top_=this.verticalSpacing_,this.zoomInGroup_.setAttribute("transform","translate(0, 34)"), this.zoomResetGroup_&&this.zoomResetGroup_.setAttribute("transform","translate(0, 77)")):(this.top_=a.viewHeight+a.absoluteTop-this.HEIGHT_-this.verticalSpacing_,this.zoomInGroup_.setAttribute("transform","translate(0, 43)"),this.zoomOutGroup_.setAttribute("transform","translate(0, 77)")),this.svgGroup_.setAttribute("transform","translate("+this.left_+","+this.top_+")"))}}; Blockly.ZoomControls.prototype.createZoomOutSvg_=function(a){var b=this.workspace_;this.zoomOutGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyZoom"},this.svgGroup_);var c=Blockly.utils.createSvgElement("clipPath",{id:"blocklyZoomoutClipPath"+a},this.zoomOutGroup_);Blockly.utils.createSvgElement("rect",{width:32,height:32},c);a=Blockly.utils.createSvgElement("image",{width:Blockly.SPRITE.width,height:Blockly.SPRITE.height,x:-64,y:-92,"clip-path":"url(#blocklyZoomoutClipPath"+a+")"},this.zoomOutGroup_); @@ -1308,12 +1307,12 @@ Blockly.Procedures.flyoutCategory)};goog.inherits(Blockly.WorkspaceSvg,Blockly.W Blockly.WorkspaceSvg.prototype.startScrollY=0;Blockly.WorkspaceSvg.prototype.dragDeltaXY_=null;Blockly.WorkspaceSvg.prototype.scale=1;Blockly.WorkspaceSvg.prototype.trashcan=null;Blockly.WorkspaceSvg.prototype.scrollbar=null;Blockly.WorkspaceSvg.prototype.flyout_=null;Blockly.WorkspaceSvg.prototype.toolbox_=null;Blockly.WorkspaceSvg.prototype.currentGesture_=null;Blockly.WorkspaceSvg.prototype.blockDragSurface_=null;Blockly.WorkspaceSvg.prototype.workspaceDragSurface_=null; Blockly.WorkspaceSvg.prototype.useWorkspaceDragSurface_=!1;Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_=!1;Blockly.WorkspaceSvg.prototype.injectionDiv_=null;Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_=null;Blockly.WorkspaceSvg.prototype.flyoutButtonCallbacks_={};Blockly.WorkspaceSvg.prototype.toolboxCategoryCallbacks_={};Blockly.WorkspaceSvg.prototype.configureContextMenu=null;Blockly.WorkspaceSvg.prototype.targetWorkspace=null;Blockly.WorkspaceSvg.prototype.inverseScreenCTM_=null; Blockly.WorkspaceSvg.prototype.inverseScreenCTMDirty_=!0;Blockly.WorkspaceSvg.prototype.getInverseScreenCTM=function(){if(this.inverseScreenCTMDirty_){var a=this.getParentSvg().getScreenCTM();a&&(this.inverseScreenCTM_=a.inverse(),this.inverseScreenCTMDirty_=!1)}return this.inverseScreenCTM_};Blockly.WorkspaceSvg.prototype.updateInverseScreenCTM=function(){this.inverseScreenCTMDirty_=!0};Blockly.WorkspaceSvg.prototype.isVisible=function(){return this.isVisible_}; -Blockly.WorkspaceSvg.prototype.getSvgXY=function(a){var b=0,c=0,d=1;if(Blockly.utils.containsNode(this.getCanvas(),a)||Blockly.utils.containsNode(this.getBubbleCanvas(),a))d=this.scale;do{var e=Blockly.utils.getRelativeXY(a);if(a==this.getCanvas()||a==this.getBubbleCanvas())d=1;b+=e.x*d;c+=e.y*d;a=a.parentNode}while(a&&a!=this.getParentSvg());return new Blockly.utils.Coordinate(b,c)};Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels=function(){return Blockly.utils.getInjectionDivXY_(this.svgBlockCanvas_)}; +Blockly.WorkspaceSvg.prototype.getSvgXY=function(a){var b=0,c=0,d=1;if(Blockly.utils.dom.containsNode(this.getCanvas(),a)||Blockly.utils.dom.containsNode(this.getBubbleCanvas(),a))d=this.scale;do{var e=Blockly.utils.getRelativeXY(a);if(a==this.getCanvas()||a==this.getBubbleCanvas())d=1;b+=e.x*d;c+=e.y*d;a=a.parentNode}while(a&&a!=this.getParentSvg());return new Blockly.utils.Coordinate(b,c)};Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels=function(){return Blockly.utils.getInjectionDivXY_(this.svgBlockCanvas_)}; Blockly.WorkspaceSvg.prototype.getInjectionDiv=function(){if(!this.injectionDiv_)for(var a=this.svgGroup_;a;){if(-1!=(" "+(a.getAttribute("class")||"")+" ").indexOf(" injectionDiv ")){this.injectionDiv_=a;break}a=a.parentNode}return this.injectionDiv_};Blockly.WorkspaceSvg.prototype.setResizeHandlerWrapper=function(a){this.resizeHandlerWrapper_=a}; Blockly.WorkspaceSvg.prototype.createDom=function(a){this.svgGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyWorkspace"},null);a&&(this.svgBackground_=Blockly.utils.createSvgElement("rect",{height:"100%",width:"100%","class":a},this.svgGroup_),"blocklyMainBackground"==a&&this.grid_&&(this.svgBackground_.style.fill="url(#"+this.grid_.getPatternId()+")"));this.svgBlockCanvas_=Blockly.utils.createSvgElement("g",{"class":"blocklyBlockCanvas"},this.svgGroup_);this.svgBubbleCanvas_=Blockly.utils.createSvgElement("g", {"class":"blocklyBubbleCanvas"},this.svgGroup_);this.isFlyout||(Blockly.bindEventWithChecks_(this.svgGroup_,"mousedown",this,this.onMouseDown_,!1,!0),Blockly.bindEventWithChecks_(this.svgGroup_,"wheel",this,this.onMouseWheel_));this.options.hasCategories&&(this.toolbox_=new Blockly.Toolbox(this));this.grid_&&this.grid_.update(this.scale);this.recordDeleteAreas();return this.svgGroup_}; -Blockly.WorkspaceSvg.prototype.dispose=function(){this.rendered=!1;this.currentGesture_&&this.currentGesture_.cancel();Blockly.WorkspaceSvg.superClass_.dispose.call(this);this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.svgBubbleCanvas_=this.svgBlockCanvas_=null;this.toolbox_&&(this.toolbox_.dispose(),this.toolbox_=null);this.flyout_&&(this.flyout_.dispose(),this.flyout_=null);this.trashcan&&(this.trashcan.dispose(),this.trashcan=null);this.scrollbar&&(this.scrollbar.dispose(), -this.scrollbar=null);this.zoomControls_&&(this.zoomControls_.dispose(),this.zoomControls_=null);this.audioManager_&&(this.audioManager_.dispose(),this.audioManager_=null);this.grid_&&(this.grid_.dispose(),this.grid_=null);this.flyoutButtonCallbacks_=this.toolboxCategoryCallbacks_=null;if(!this.options.parentWorkspace){var a=this.getParentSvg().parentNode;a&&Blockly.utils.removeNode(a)}this.resizeHandlerWrapper_&&(Blockly.unbindEvent_(this.resizeHandlerWrapper_),this.resizeHandlerWrapper_=null)}; +Blockly.WorkspaceSvg.prototype.dispose=function(){this.rendered=!1;this.currentGesture_&&this.currentGesture_.cancel();Blockly.WorkspaceSvg.superClass_.dispose.call(this);this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.svgBubbleCanvas_=this.svgBlockCanvas_=null;this.toolbox_&&(this.toolbox_.dispose(),this.toolbox_=null);this.flyout_&&(this.flyout_.dispose(),this.flyout_=null);this.trashcan&&(this.trashcan.dispose(),this.trashcan=null);this.scrollbar&&(this.scrollbar.dispose(), +this.scrollbar=null);this.zoomControls_&&(this.zoomControls_.dispose(),this.zoomControls_=null);this.audioManager_&&(this.audioManager_.dispose(),this.audioManager_=null);this.grid_&&(this.grid_.dispose(),this.grid_=null);this.flyoutButtonCallbacks_=this.toolboxCategoryCallbacks_=null;if(!this.options.parentWorkspace){var a=this.getParentSvg().parentNode;a&&Blockly.utils.dom.removeNode(a)}this.resizeHandlerWrapper_&&(Blockly.unbindEvent_(this.resizeHandlerWrapper_),this.resizeHandlerWrapper_=null)}; Blockly.WorkspaceSvg.prototype.newBlock=function(a,b){return new Blockly.BlockSvg(this,a,b)};Blockly.WorkspaceSvg.prototype.addTrashcan=function(){this.trashcan=new Blockly.Trashcan(this);var a=this.trashcan.createDom();this.svgGroup_.insertBefore(a,this.svgBlockCanvas_)};Blockly.WorkspaceSvg.prototype.addZoomControls=function(){this.zoomControls_=new Blockly.ZoomControls(this);var a=this.zoomControls_.createDom();this.svgGroup_.appendChild(a)}; Blockly.WorkspaceSvg.prototype.addFlyout_=function(a){var b={disabledPatternId:this.options.disabledPatternId,parentWorkspace:this,RTL:this.RTL,oneBasedIndex:this.options.oneBasedIndex,horizontalLayout:this.horizontalLayout,toolboxPosition:this.options.toolboxPosition};this.flyout_=this.horizontalLayout?new Blockly.HorizontalFlyout(b):new Blockly.VerticalFlyout(b);this.flyout_.autoClose=!1;return this.flyout_.createDom(a)}; Blockly.WorkspaceSvg.prototype.getFlyout=function(){return this.flyout_?this.flyout_:this.toolbox_?this.toolbox_.flyout_:null};Blockly.WorkspaceSvg.prototype.getToolbox=function(){return this.toolbox_};Blockly.WorkspaceSvg.prototype.updateScreenCalculations_=function(){this.updateInverseScreenCTM();this.recordDeleteAreas()}; @@ -1352,7 +1351,7 @@ this.options.languageTree=a;this.flyout_.show(a.childNodes)}}else if(this.option Blockly.WorkspaceSvg.prototype.zoom=function(a,b,c){c=Math.pow(this.options.zoomOptions.scaleSpeed,c);var d=this.scale*c;if(this.scale!=d){d>this.options.zoomOptions.maxScale?c=this.options.zoomOptions.maxScale/this.scale:dthis.options.zoomOptions.maxScale?a=this.options.zoomOptions.maxScale:this.options.zoomOptions.minScale&&aa||Math.abs(this.workspaceHeight_-b)>a)this.workspaceWidth_=c,this.workspaceHeight_=b,this.bubble_.setBubbleSize(c+a,b+a),this.svgDialog_.setAttribute("width",this.workspaceWidth_), this.svgDialog_.setAttribute("height",this.workspaceHeight_);this.block_.RTL&&(a="translate("+this.workspaceWidth_+",0)",this.workspace_.getCanvas().setAttribute("transform",a));this.workspace_.resize()}; Blockly.Mutator.prototype.setVisible=function(a){if(a!=this.isVisible())if(Blockly.Events.fire(new Blockly.Events.Ui(this.block_,"mutatorOpen",!a,a)),a){this.bubble_=new Blockly.Bubble(this.block_.workspace,this.createEditor_(),this.block_.svgPath_,this.iconXY_,null,null);this.bubble_.setSvgId(this.block_.id);if(a=this.workspace_.options.languageTree)this.workspace_.flyout_.init(this.workspace_),this.workspace_.flyout_.show(a.childNodes);this.rootBlock_=this.block_.decompose(this.workspace_);a=this.rootBlock_.getDescendants(!1); @@ -1401,8 +1400,8 @@ Blockly.Field.prototype.SERIALIZABLE=!1;Blockly.Field.prototype.setSourceBlock=f Blockly.Field.prototype.init=function(){this.fieldGroup_||(this.fieldGroup_=Blockly.utils.createSvgElement("g",{},null),this.isVisible()||(this.fieldGroup_.style.display="none"),this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_),this.initView(),this.updateEditable(),this.setTooltip(),this.bindEvents_(),this.initModel())};Blockly.Field.prototype.initView=function(){this.createBorderRect_();this.createTextElement_()}; Blockly.Field.prototype.createBorderRect_=function(){this.borderRect_=Blockly.utils.createSvgElement("rect",{rx:4,ry:4,x:-Blockly.BlockSvg.SEP_SPACE_X/2,y:0,height:16,width:this.size_.width+Blockly.BlockSvg.SEP_SPACE_X},this.fieldGroup_)};Blockly.Field.prototype.createTextElement_=function(){this.textElement_=Blockly.utils.createSvgElement("text",{"class":"blocklyText",y:this.size_.height-12.5},this.fieldGroup_);this.textContent_=document.createTextNode("");this.textElement_.appendChild(this.textContent_)}; Blockly.Field.prototype.bindEvents_=function(){Blockly.Tooltip.bindMouseEvents(this.getClickTarget_());this.mouseDownWrapper_=Blockly.bindEventWithChecks_(this.getClickTarget_(),"mousedown",this,this.onMouseDown_)};Blockly.Field.prototype.initModel=function(){};Blockly.Field.prototype.fromXml=function(a){this.setValue(a.textContent)};Blockly.Field.prototype.toXml=function(a){a.textContent=this.getValue();return a}; -Blockly.Field.prototype.dispose=function(){this.mouseDownWrapper_&&(Blockly.unbindEvent_(this.mouseDownWrapper_),this.mouseDownWrapper_=null);this.sourceBlock_=null;this.fieldGroup_&&(Blockly.utils.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.validator_=this.borderRect_=this.textElement_=null}; -Blockly.Field.prototype.updateEditable=function(){var a=this.getClickTarget_();this.EDITABLE&&a&&(this.sourceBlock_.isEditable()?(Blockly.utils.addClass(a,"blocklyEditableText"),Blockly.utils.removeClass(a,"blocklyNonEditableText"),a.style.cursor=this.CURSOR):(Blockly.utils.addClass(a,"blocklyNonEditableText"),Blockly.utils.removeClass(a,"blocklyEditableText"),a.style.cursor=""))};Blockly.Field.prototype.isClickable=function(){return!!this.showEditor_&&"function"===typeof this.showEditor_}; +Blockly.Field.prototype.dispose=function(){this.mouseDownWrapper_&&(Blockly.unbindEvent_(this.mouseDownWrapper_),this.mouseDownWrapper_=null);this.sourceBlock_=null;this.fieldGroup_&&(Blockly.utils.dom.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.validator_=this.borderRect_=this.textElement_=null}; +Blockly.Field.prototype.updateEditable=function(){var a=this.getClickTarget_();this.EDITABLE&&a&&(this.sourceBlock_.isEditable()?(Blockly.utils.dom.addClass(a,"blocklyEditableText"),Blockly.utils.dom.removeClass(a,"blocklyNonEditableText"),a.style.cursor=this.CURSOR):(Blockly.utils.dom.addClass(a,"blocklyNonEditableText"),Blockly.utils.dom.removeClass(a,"blocklyEditableText"),a.style.cursor=""))};Blockly.Field.prototype.isClickable=function(){return!!this.showEditor_&&"function"===typeof this.showEditor_}; Blockly.Field.prototype.isCurrentlyEditable=function(){return this.EDITABLE&&!!this.sourceBlock_&&this.sourceBlock_.isEditable()};Blockly.Field.prototype.isSerializable=function(){var a=!1;this.name&&(this.SERIALIZABLE?a=!0:this.EDITABLE&&(console.warn("Detected an editable field that was not serializable. Please define SERIALIZABLE property as true on all editable custom fields. Proceeding with serialization."),a=!0));return a};Blockly.Field.prototype.isVisible=function(){return this.visible_}; Blockly.Field.prototype.setVisible=function(a){if(this.visible_!=a){this.visible_=a;var b=this.getSvgRoot();b&&(b.style.display=a?"block":"none")}};Blockly.Field.prototype.setValidator=function(a){this.validator_=a};Blockly.Field.prototype.getValidator=function(){return this.validator_};Blockly.Field.prototype.classValidator=function(a){return a}; Blockly.Field.prototype.callValidator=function(a){var b=this.classValidator(a);if(null===b)return null;void 0!==b&&(a=b);if(b=this.getValidator()){b=b.call(this,a);if(null===b)return null;void 0!==b&&(a=b)}return a};Blockly.Field.prototype.getSvgRoot=function(){return this.fieldGroup_};Blockly.Field.prototype.updateColour=function(){};Blockly.Field.prototype.render_=function(){this.textContent_.nodeValue=this.getDisplayText_();this.updateSize_()}; @@ -1415,7 +1414,7 @@ Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlo Blockly.Field.prototype.setValue=function(a){if(null!==a){var b=this.doClassValidation_(a);void 0!==b&&(a=b);if(null===a)this.doValueInvalid_(),this.isDirty_&&this.forceRerender();else{if(b=this.getValidator())if(b=b.call(this,a),void 0!==b&&(a=b),null===a){this.doValueInvalid_();this.isDirty_&&this.forceRerender();return}b=this.getValue();b!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockChange(this.sourceBlock_,"field",this.name,b,a)),this.doValueUpdate_(a), this.isDirty_&&this.forceRerender())}}};Blockly.Field.prototype.value_=null;Blockly.Field.prototype.doClassValidation_=function(a){return a=this.classValidator(a)};Blockly.Field.prototype.doValueUpdate_=function(a){this.value_=a;this.isDirty_=!0;this.text_=String(a)};Blockly.Field.prototype.doValueInvalid_=function(){};Blockly.Field.prototype.onMouseDown_=function(a){this.sourceBlock_&&this.sourceBlock_.workspace&&(a=this.sourceBlock_.workspace.getGesture(a))&&a.setStartField(this)}; Blockly.Field.prototype.setTooltip=function(a){a||""===a?this.getClickTarget_().tooltip=a:this.getClickTarget_().tooltip=this.sourceBlock_};Blockly.Field.prototype.getClickTarget_=function(){return this.clickTarget_||this.getSvgRoot()};Blockly.Field.prototype.getAbsoluteXY_=function(){return goog.style.getPageOffset(this.borderRect_)};Blockly.Field.prototype.referencesVariables=function(){return!1};Blockly.FieldLabel=function(a,b){this.size_=new goog.math.Size(0,17.5);this.class_=b;a=this.doClassValidation_(a);null===a&&(a="");this.setValue(a)};goog.inherits(Blockly.FieldLabel,Blockly.Field);Blockly.FieldLabel.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.text);return new Blockly.FieldLabel(b,a["class"])};Blockly.FieldLabel.prototype.EDITABLE=!1; -Blockly.FieldLabel.prototype.initView=function(){this.createTextElement_();this.textElement_.setAttribute("y",this.size_.height-5);this.class_&&Blockly.utils.addClass(this.textElement_,this.class_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.doClassValidation_=function(a){return null===a||void 0===a?null:String(a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; +Blockly.FieldLabel.prototype.initView=function(){this.createTextElement_();this.textElement_.setAttribute("y",this.size_.height-5);this.class_&&Blockly.utils.dom.addClass(this.textElement_,this.class_)};Blockly.FieldLabel.prototype.dispose=function(){this.textElement_&&(Blockly.utils.dom.removeNode(this.textElement_),this.textElement_=null)};Blockly.FieldLabel.prototype.doClassValidation_=function(a){return null===a||void 0===a?null:String(a)};Blockly.Field.register("field_label",Blockly.FieldLabel);Blockly.Input=function(a,b,c,d){if(a!=Blockly.DUMMY_INPUT&&!b)throw Error("Value inputs and statement inputs must have non-empty name.");this.type=a;this.name=b;this.sourceBlock_=c;this.connection=d;this.fieldRow=[]};Blockly.Input.prototype.align=Blockly.ALIGN_LEFT;Blockly.Input.prototype.visible_=!0;Blockly.Input.prototype.appendField=function(a,b){this.insertFieldAt(this.fieldRow.length,a,b);return this}; Blockly.Input.prototype.insertFieldAt=function(a,b,c){if(0>a||a>this.fieldRow.length)throw Error("index "+a+" out of bounds.");if(!b&&!c)return a;"string"==typeof b&&(b=new Blockly.FieldLabel(b));b.setSourceBlock(this.sourceBlock_);this.sourceBlock_.rendered&&b.init();b.name=c;b.prefixField&&(a=this.insertFieldAt(a,b.prefixField));this.fieldRow.splice(a,0,b);++a;b.suffixField&&(a=this.insertFieldAt(a,b.suffixField));this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_()); return a};Blockly.Input.prototype.removeField=function(a){for(var b=0,c;c=this.fieldRow[b];b++)if(c.name===a){c.dispose();this.fieldRow.splice(b,1);this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_());return}throw Error('Field "%s" not found.',a);};Blockly.Input.prototype.isVisible=function(){return this.visible_}; Blockly.Input.prototype.setVisible=function(a){var b=[];if(this.visible_==a)return b;for(var c=(this.visible_=a)?"block":"none",d=0,e;e=this.fieldRow[d];d++)e.setVisible(a);this.connection&&(a?b=this.connection.unhideAll():this.connection.hideAll(),d=this.connection.targetBlock())&&(d.getSvgRoot().style.display=c,a||(d.rendered=!1));return b};Blockly.Input.prototype.setCheck=function(a){if(!this.connection)throw Error("This input does not have a connection.");this.connection.setCheck(a);return this}; @@ -1445,7 +1444,7 @@ Blockly.Block.prototype.setConnectionsHidden=function(a){if(!a&&this.isCollapsed Blockly.Block.prototype.getMatchingConnection=function(a,b){var c=this.getConnections_(!0),d=a.getConnections_(!0);if(c.length!=d.length)throw Error("Connection lists did not match in length.");for(var e=0;e=c)this.hue_=c,this.colour_=Blockly.utils.colour.hueToHex(c);else if(c=Blockly.utils.colour.parse(b))this.colour_=c,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; +Blockly.Block.prototype.setColour=function(a){var b="string"==typeof a?Blockly.utils.replaceMessageReferences(a):a,c=Number(b);if(!isNaN(c)&&0<=c&&360>=c)this.hue_=c,this.colour_=Blockly.hueToHex(c);else if(c=Blockly.utils.colour.parse(b))this.colour_=c,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),Error(c);}; Blockly.Block.prototype.setStyle=function(a){var b=Blockly.getTheme();if(!b)throw Error("Trying to set block style to "+a+" before theme was defined via Blockly.setTheme().");b=b.getBlockStyle(a);this.styleName_=a;if(b)this.colourSecondary_=b.colourSecondary,this.colourTertiary_=b.colourTertiary,this.hat=b.hat,this.setColour(b.colourPrimary);else throw Error("Invalid style name: "+a);}; Blockly.Block.prototype.setOnChange=function(a){if(a&&"function"!=typeof a)throw Error("onchange must be a function.");this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);if(this.onchange=a)this.onchangeWrapper_=a.bind(this),this.workspace.addChangeListener(this.onchangeWrapper_)};Blockly.Block.prototype.getField=function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(e.name===a)return e;return null}; Blockly.Block.prototype.getVars=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&a.push(e.getValue());return a};Blockly.Block.prototype.getVarModels=function(){for(var a=[],b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)e.referencesVariables()&&(e=this.workspace.getVariableById(e.getValue()))&&a.push(e);return a}; @@ -1466,7 +1465,7 @@ a.inputsInline&&this.setInputsInline(a.inputsInline);void 0!==a.output&&this.set Blockly.Block.prototype.jsonInitColour_=function(a,b){if("colour"in a)if(void 0===a.colour)console.warn(b+"Undefined colour value.");else{var c=a.colour;try{this.setColour(c)}catch(d){console.warn(b+"Illegal colour value: ",c)}}};Blockly.Block.prototype.jsonInitStyle_=function(a,b){var c=a.style;try{this.setStyle(c)}catch(d){console.warn(b+"Style does not exist: ",c)}}; Blockly.Block.prototype.mixin=function(a,b){if(void 0!==b&&"boolean"!=typeof b)throw Error("opt_disableCheck must be a boolean if provided");if(!b){var c=[],d;for(d in a)void 0!==this[d]&&c.push(d);if(c.length)throw Error("Mixin will overwrite block members: "+JSON.stringify(c));}goog.mixin(this,a)}; Blockly.Block.prototype.interpolate_=function(a,b,c){var d=Blockly.utils.tokenizeInterpolation(a),e=[],f=0;a=[];for(var g=0;g=h||h>b.length)throw Error('Block "'+this.type+'": Message index %'+h+" out of range.");if(e[h])throw Error('Block "'+this.type+'": Message index %'+h+" duplicated.");e[h]=!0;f++;a.push(b[h-1])}else(h=h.trim())&&a.push(h)}if(f!=b.length)throw Error('Block "'+this.type+'": Message does not reference all '+b.length+" arg(s)."); -a.length&&("string"==typeof a[a.length-1]||Blockly.utils.startsWith(a[a.length-1].type,"field_"))&&(g={type:"input_dummy"},c&&(g.align=c),a.push(g));c={LEFT:Blockly.ALIGN_LEFT,RIGHT:Blockly.ALIGN_RIGHT,CENTRE:Blockly.ALIGN_CENTRE};b=[];for(g=0;ge.bottom)if(d-f.heighte.bottom)if(d-f.heightc;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+ Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove", this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; -Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& +Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.math.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& (a-=360),c=String(a),c!=this.text_&&(Blockly.FieldTextInput.htmlInput_.value=a,this.setValue(a),this.text_=c,this.forceRerender()))}; -Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; +Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.math.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.math.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; d-=Math.sin(b)*Blockly.FieldAngle.RADIUS;b=Math.abs(Math.floor((b-e)/Math.PI)%2);Blockly.FieldAngle.CLOCKWISE&&(b=1-b);a.push(" l ",f,",",g," A ",Blockly.FieldAngle.RADIUS,",",Blockly.FieldAngle.RADIUS," 0 ",b," ",Number(Blockly.FieldAngle.CLOCKWISE)," ",c,",",d," z")}this.gauge_.setAttribute("d",a.join(""));this.line_.setAttribute("x2",c);this.line_.setAttribute("y2",d)}}; Blockly.FieldAngle.prototype.doClassValidation_=function(a){if(isNaN(a))return null;a=parseFloat(a||0);a%=360;0>a&&(a+=360);a>Blockly.FieldAngle.WRAP&&(a-=360);return a};Blockly.Field.register("field_angle",Blockly.FieldAngle);Blockly.FieldCheckbox=function(a,b){a=this.doClassValidation_(a);null===a&&(a="FALSE");Blockly.FieldCheckbox.superClass_.constructor.call(this,a,b);this.size_.width=Blockly.FieldCheckbox.WIDTH};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.fromJson=function(a){return new Blockly.FieldCheckbox(a.checked)};Blockly.FieldCheckbox.WIDTH=5;Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.CHECK_X_OFFSET=-3;Blockly.FieldCheckbox.CHECK_Y_OFFSET=14; Blockly.FieldCheckbox.prototype.SERIALIZABLE=!0;Blockly.FieldCheckbox.prototype.CURSOR="default";Blockly.FieldCheckbox.prototype.isDirty_=!1; -Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.textElement_.setAttribute("x",Blockly.FieldCheckbox.CHECK_X_OFFSET);this.textElement_.setAttribute("y",Blockly.FieldCheckbox.CHECK_Y_OFFSET);Blockly.utils.addClass(this.textElement_,"blocklyCheckbox");var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.textElement_.appendChild(a);this.textElement_.style.display=this.value_?"block":"none"}; +Blockly.FieldCheckbox.prototype.initView=function(){Blockly.FieldCheckbox.superClass_.initView.call(this);this.textElement_.setAttribute("x",Blockly.FieldCheckbox.CHECK_X_OFFSET);this.textElement_.setAttribute("y",Blockly.FieldCheckbox.CHECK_Y_OFFSET);Blockly.utils.dom.addClass(this.textElement_,"blocklyCheckbox");var a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);this.textElement_.appendChild(a);this.textElement_.style.display=this.value_?"block":"none"}; Blockly.FieldCheckbox.prototype.showEditor_=function(){this.setValue(!this.value_)};Blockly.FieldCheckbox.prototype.doClassValidation_=function(a){return!0===a||"TRUE"===a?"TRUE":!1===a||"FALSE"===a?"FALSE":null};Blockly.FieldCheckbox.prototype.doValueUpdate_=function(a){this.value_=this.convertValueToBool_(a);this.textElement_&&(this.textElement_.style.display=this.value_?"block":"none")};Blockly.FieldCheckbox.prototype.getValue=function(){return this.value_?"TRUE":"FALSE"}; Blockly.FieldCheckbox.prototype.getValueBoolean=function(){return this.value_};Blockly.FieldCheckbox.prototype.getText=function(){return String(this.convertValueToBool_(this.value_))};Blockly.FieldCheckbox.prototype.convertValueToBool_=function(a){return"string"==typeof a?"TRUE"==a:!!a};Blockly.Field.register("field_checkbox",Blockly.FieldCheckbox);Blockly.utils.colour={};Blockly.utils.colour.parse=function(a){a=String(a).toLowerCase().trim();var b=Blockly.utils.colour.names[a];if(b)return b;b="#"==a[0]?a:"#"+a;if(/^#[0-9a-f]{6}$/.test(b))return b;if(/^#[0-9a-f]{3}$/.test(b))return["#",b[1],b[1],b[2],b[2],b[3],b[3]].join("");var c=a.match(/^(?:rgb)?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);return c&&(a=Number(c[1]),b=Number(c[2]),c=Number(c[3]),0<=a&&256>a&&0<=b&&256>b&&0<=c&&256>c)?Blockly.utils.colour.rgbToHex(a,b,c):null}; -Blockly.utils.colour.rgbToHex=function(a,b,c){b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};Blockly.utils.colour.hexToRgb=function(a){a=parseInt(a.substr(1),16);return[a>>16,a>>8&255,a&255]};Blockly.utils.colour.hueToHex=function(a){return Blockly.utils.colour.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)}; +Blockly.utils.colour.rgbToHex=function(a,b,c){b=a<<16|b<<8|c;return 16>a?"#"+(16777216|b).toString(16).substr(1):"#"+b.toString(16)};Blockly.utils.colour.hexToRgb=function(a){a=parseInt(a.substr(1),16);return[a>>16,a>>8&255,a&255]}; Blockly.utils.colour.hsvToHex=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return Blockly.utils.colour.rgbToHex(Math.floor(d),Math.floor(e),Math.floor(f))}; Blockly.utils.colour.blend=function(a,b,c){a=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(a));b=Blockly.utils.colour.hexToRgb(Blockly.utils.colour.parse(b));return Blockly.utils.colour.rgbToHex(Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2])))}; Blockly.utils.colour.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00"};Blockly.FieldColour=function(a,b){a=this.doClassValidation_(a);null===a&&(a=Blockly.FieldColour.COLOURS[0]);Blockly.FieldColour.superClass_.constructor.call(this,a,b)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.fromJson=function(a){return new Blockly.FieldColour(a.colour)};Blockly.FieldColour.DEFAULT_WIDTH=16;Blockly.FieldColour.DEFAULT_HEIGHT=12;Blockly.FieldColour.prototype.SERIALIZABLE=!0;Blockly.FieldColour.prototype.CURSOR="default"; @@ -1629,9 +1628,9 @@ Blockly.FieldDropdown.prototype.initView=function(){Blockly.FieldDropdown.superC this.textContent_):this.textElement_.appendChild(this.arrow_)};Blockly.FieldDropdown.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,null);var a=this.createMenu_();this.addActionListener_(a);this.positionMenu_(a)};Blockly.FieldDropdown.prototype.addActionListener_=function(a){var b=this;goog.events.listen(a,goog.ui.Component.EventType.ACTION,function(a){if(a=a.target)b.onItemSelected(this,a);Blockly.WidgetDiv.hideIfOwner(b);Blockly.Events.setGroup(!1)})}; Blockly.FieldDropdown.prototype.createMenu_=function(){var a=new goog.ui.Menu;a.setRightToLeft(this.sourceBlock_.RTL);for(var b=this.getOptions(),c=0;ce&&(d.height=e);this.sourceBlock_.RTL&&Blockly.utils.uiMenu.adjustBBoxesForRTL(b,c,d);Blockly.WidgetDiv.positionWithAnchor(b,c,d,this.sourceBlock_.RTL);a.getElement().focus()}; -Blockly.FieldDropdown.prototype.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);Blockly.utils.addClass(a.getElement(),"blocklyDropdownMenu");a.setAllowAutoFocus(!0)};Blockly.FieldDropdown.prototype.getAnchorDimensions_=function(){var a=this.getScaledBBox_();this.sourceBlock_.RTL?a.right+=Blockly.FieldDropdown.CHECKMARK_OVERHANG:a.left-=Blockly.FieldDropdown.CHECKMARK_OVERHANG;return a};Blockly.FieldDropdown.prototype.onItemSelected=function(a,b){this.setValue(b.getValue())}; -Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(Array.isArray(a)){for(var b=!1,c=0;ca.length)){b=[];for(c=0;ca.length)){b=[];for(c=0;c=this.height_||0>=this.width_)throw Error("Height and width values of an image field must be greater than 0.");this.size_=new goog.math.Size(this.width_,this.height_+2*Blockly.BlockSvg.INLINE_PADDING_Y);this.flipRtl_=f;this.text_=d||"";this.setValue(a||"");"function"==typeof e&&(this.clickHandler_= e)};goog.inherits(Blockly.FieldImage,Blockly.Field);Blockly.FieldImage.fromJson=function(a){var b=Blockly.utils.replaceMessageReferences(a.src),c=Number(Blockly.utils.replaceMessageReferences(a.width)),d=Number(Blockly.utils.replaceMessageReferences(a.height)),e=Blockly.utils.replaceMessageReferences(a.alt);return new Blockly.FieldImage(b,c,d,e,null,!!a.flipRtl)};Blockly.FieldImage.prototype.EDITABLE=!1;Blockly.FieldImage.prototype.isDirty_=!1; -Blockly.FieldImage.prototype.initView=function(){this.imageElement_=Blockly.utils.createSvgElement("image",{height:this.height_+"px",width:this.width_+"px",alt:this.text_},this.fieldGroup_);this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_)};Blockly.FieldImage.prototype.dispose=function(){this.fieldGroup_&&(Blockly.utils.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.imageElement_=null}; +Blockly.FieldImage.prototype.initView=function(){this.imageElement_=Blockly.utils.createSvgElement("image",{height:this.height_+"px",width:this.width_+"px",alt:this.text_},this.fieldGroup_);this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_)};Blockly.FieldImage.prototype.dispose=function(){this.fieldGroup_&&(Blockly.utils.dom.removeNode(this.fieldGroup_),this.fieldGroup_=null);this.imageElement_=null}; Blockly.FieldImage.prototype.doClassValidation_=function(a){return"string"!=typeof a?null:a};Blockly.FieldImage.prototype.doValueUpdate_=function(a){this.value_=a;this.imageElement_&&this.imageElement_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.value_||"")};Blockly.FieldImage.prototype.getFlipRtl=function(){return this.flipRtl_};Blockly.FieldImage.prototype.setText=function(a){null!==a&&(this.text_=a,this.imageElement_&&this.imageElement_.setAttribute("alt",a||""))}; Blockly.FieldImage.prototype.showEditor_=function(){this.clickHandler_&&this.clickHandler_(this)};Blockly.Field.register("field_image",Blockly.FieldImage);Blockly.FieldNumber=function(a,b,c,d,e){this.setConstraints(b,c,d);a=this.doClassValidation_(a);null===a&&(a=0);Blockly.FieldNumber.superClass_.constructor.call(this,a,e)};goog.inherits(Blockly.FieldNumber,Blockly.FieldTextInput);Blockly.FieldNumber.fromJson=function(a){return new Blockly.FieldNumber(a.value,a.min,a.max,a.precision)};Blockly.FieldNumber.prototype.SERIALIZABLE=!0; Blockly.FieldNumber.prototype.setConstraints=function(a,b,c){c=parseFloat(c);this.precision_=isNaN(c)?0:c;c=this.precision_.toString();var d=c.indexOf(".");this.fractionalDigits_=-1==d?-1:c.length-(d+1);a=parseFloat(a);this.min_=isNaN(a)?-Infinity:a;b=parseFloat(b);this.max_=isNaN(b)?Infinity:b;this.setValue(this.getValue())}; @@ -1685,21 +1684,21 @@ Blockly.FlyoutButton.prototype.createDom=function(){var a=this.isLabel_?"blockly rx:4,ry:4},this.svgGroup_);var c=Blockly.utils.createSvgElement("text",{"class":this.isLabel_?"blocklyFlyoutLabelText":"blocklyText",x:0,y:0,"text-anchor":"middle"},this.svgGroup_);c.textContent=Blockly.utils.replaceMessageReferences(this.text_);this.width=Blockly.Field.getCachedWidth(c);this.height=20;this.isLabel_||(this.width+=2*Blockly.FlyoutButton.MARGIN,b.setAttribute("width",this.width),b.setAttribute("height",this.height));a.setAttribute("width",this.width);a.setAttribute("height",this.height); c.setAttribute("x",this.width/2);c.setAttribute("y",this.height-Blockly.FlyoutButton.MARGIN);this.updateTransform_();this.onMouseUpWrapper_=Blockly.bindEventWithChecks_(this.svgGroup_,"mouseup",this,this.onMouseUp_);return this.svgGroup_};Blockly.FlyoutButton.prototype.show=function(){this.updateTransform_();this.svgGroup_.setAttribute("display","block")}; Blockly.FlyoutButton.prototype.updateTransform_=function(){this.svgGroup_.setAttribute("transform","translate("+this.position_.x+","+this.position_.y+")")};Blockly.FlyoutButton.prototype.moveTo=function(a,b){this.position_.x=a;this.position_.y=b;this.updateTransform_()};Blockly.FlyoutButton.prototype.getPosition=function(){return this.position_};Blockly.FlyoutButton.prototype.getTargetWorkspace=function(){return this.targetWorkspace_}; -Blockly.FlyoutButton.prototype.dispose=function(){this.onMouseUpWrapper_&&Blockly.unbindEvent_(this.onMouseUpWrapper_);this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.workspace_=null}; +Blockly.FlyoutButton.prototype.dispose=function(){this.onMouseUpWrapper_&&Blockly.unbindEvent_(this.onMouseUpWrapper_);this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.workspace_=null}; Blockly.FlyoutButton.prototype.onMouseUp_=function(a){(a=this.targetWorkspace_.getGesture(a))&&a.cancel();this.isLabel_&&this.callbackKey_?console.warn("Labels should not have callbacks. Label text: "+this.text_):this.isLabel_||this.callbackKey_&&this.targetWorkspace_.getButtonCallback(this.callbackKey_)?this.isLabel_||this.targetWorkspace_.getButtonCallback(this.callbackKey_)(this):console.warn("Buttons should have callbacks. Button text: "+this.text_)};Blockly.Flyout=function(a){a.getMetrics=this.getMetrics_.bind(this);a.setMetrics=this.setMetrics_.bind(this);this.workspace_=new Blockly.WorkspaceSvg(a);this.workspace_.isFlyout=!0;this.RTL=!!a.RTL;this.toolboxPosition_=a.toolboxPosition;this.eventWrappers_=[];this.mats_=[];this.buttons_=[];this.listeners_=[];this.permanentlyDisabled_=[]};Blockly.Flyout.prototype.autoClose=!0;Blockly.Flyout.prototype.isVisible_=!1;Blockly.Flyout.prototype.containerVisible_=!0; Blockly.Flyout.prototype.CORNER_RADIUS=8;Blockly.Flyout.prototype.MARGIN=Blockly.Flyout.prototype.CORNER_RADIUS;Blockly.Flyout.prototype.GAP_X=3*Blockly.Flyout.prototype.MARGIN;Blockly.Flyout.prototype.GAP_Y=3*Blockly.Flyout.prototype.MARGIN;Blockly.Flyout.prototype.SCROLLBAR_PADDING=2;Blockly.Flyout.prototype.width_=0;Blockly.Flyout.prototype.height_=0;Blockly.Flyout.prototype.dragAngleRange_=70; Blockly.Flyout.prototype.createDom=function(a){this.svgGroup_=Blockly.utils.createSvgElement(a,{"class":"blocklyFlyout",style:"display: none"},null);this.svgBackground_=Blockly.utils.createSvgElement("path",{"class":"blocklyFlyoutBackground"},this.svgGroup_);this.svgGroup_.appendChild(this.workspace_.createDom());return this.svgGroup_}; Blockly.Flyout.prototype.init=function(a){this.targetWorkspace_=a;this.workspace_.targetWorkspace=a;this.scrollbar_=new Blockly.Scrollbar(this.workspace_,this.horizontalLayout_,!1,"blocklyFlyoutScrollbar");this.hide();Array.prototype.push.apply(this.eventWrappers_,Blockly.bindEventWithChecks_(this.svgGroup_,"wheel",this,this.wheel_));this.autoClose||(this.filterWrapper_=this.filterForCapacity_.bind(this),this.targetWorkspace_.addChangeListener(this.filterWrapper_));Array.prototype.push.apply(this.eventWrappers_, Blockly.bindEventWithChecks_(this.svgBackground_,"mousedown",this,this.onMouseDown_));this.workspace_.getGesture=this.targetWorkspace_.getGesture.bind(this.targetWorkspace_);this.workspace_.variableMap_=this.targetWorkspace_.getVariableMap();this.workspace_.createPotentialVariableMap()}; -Blockly.Flyout.prototype.dispose=function(){this.hide();Blockly.unbindEvent_(this.eventWrappers_);this.filterWrapper_&&(this.targetWorkspace_.removeChangeListener(this.filterWrapper_),this.filterWrapper_=null);this.scrollbar_&&(this.scrollbar_.dispose(),this.scrollbar_=null);this.workspace_&&(this.workspace_.targetWorkspace=null,this.workspace_.dispose(),this.workspace_=null);this.svgGroup_&&(Blockly.utils.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.svgBackground_=null}; -Blockly.Flyout.prototype.getWidth=function(){return this.width_};Blockly.Flyout.prototype.getHeight=function(){return this.height_};Blockly.Flyout.prototype.getWorkspace=function(){return this.workspace_};Blockly.Flyout.prototype.isVisible=function(){return this.isVisible_};Blockly.Flyout.prototype.setVisible=function(a){var b=a!=this.isVisible();this.isVisible_=a;b&&this.updateDisplay_()}; +Blockly.Flyout.prototype.dispose=function(){this.hide();Blockly.unbindEvent_(this.eventWrappers_);this.filterWrapper_&&(this.targetWorkspace_.removeChangeListener(this.filterWrapper_),this.filterWrapper_=null);this.scrollbar_&&(this.scrollbar_.dispose(),this.scrollbar_=null);this.workspace_&&(this.workspace_.targetWorkspace=null,this.workspace_.dispose(),this.workspace_=null);this.svgGroup_&&(Blockly.utils.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.targetWorkspace_=this.svgBackground_= +null};Blockly.Flyout.prototype.getWidth=function(){return this.width_};Blockly.Flyout.prototype.getHeight=function(){return this.height_};Blockly.Flyout.prototype.getWorkspace=function(){return this.workspace_};Blockly.Flyout.prototype.isVisible=function(){return this.isVisible_};Blockly.Flyout.prototype.setVisible=function(a){var b=a!=this.isVisible();this.isVisible_=a;b&&this.updateDisplay_()}; Blockly.Flyout.prototype.setContainerVisible=function(a){var b=a!=this.containerVisible_;this.containerVisible_=a;b&&this.updateDisplay_()};Blockly.Flyout.prototype.updateDisplay_=function(){var a=this.containerVisible_?this.isVisible():!1;this.svgGroup_.style.display=a?"block":"none";this.scrollbar_.setContainerVisible(a)}; Blockly.Flyout.prototype.positionAt_=function(a,b,c,d){this.svgGroup_.setAttribute("width",a);this.svgGroup_.setAttribute("height",b);"svg"==this.svgGroup_.tagName?Blockly.utils.setCssTransform(this.svgGroup_,"translate("+c+"px,"+d+"px)"):this.svgGroup_.setAttribute("transform","translate("+c+","+d+")");this.scrollbar_&&(this.scrollbar_.setOrigin(c,d),this.scrollbar_.resize(),this.scrollbar_.setPosition_(this.scrollbar_.position_.x,this.scrollbar_.position_.y))}; Blockly.Flyout.prototype.hide=function(){if(this.isVisible()){this.setVisible(!1);for(var a=0,b;b=this.listeners_[a];a++)Blockly.unbindEvent_(b);this.listeners_.length=0;this.reflowWrapper_&&(this.workspace_.removeChangeListener(this.reflowWrapper_),this.reflowWrapper_=null)}}; Blockly.Flyout.prototype.show=function(a){this.workspace_.setResizesEnabled(!1);this.hide();this.clearOldBlocks_();if("string"==typeof a){a=this.workspace_.targetWorkspace.getToolboxCategoryCallback(a);if("function"!=typeof a)throw TypeError("Couldn't find a callback function when opening a toolbox category.");a=a(this.workspace_.targetWorkspace);if(!Array.isArray(a))throw TypeError("Result of toolbox category callback must be an array.");}this.setVisible(!0);var b=[],c=[];this.permanentlyDisabled_.length= 0;for(var d=this.horizontalLayout_?this.GAP_X:this.GAP_Y,e=0,f;f=a[e];e++)if(f.tagName)switch(f.tagName.toUpperCase()){case "BLOCK":var g=Blockly.Xml.domToBlock(f,this.workspace_);g.isEnabled()||this.permanentlyDisabled_.push(g);b.push({type:"block",block:g});f=parseInt(f.getAttribute("gap"),10);c.push(isNaN(f)?d:f);break;case "SEP":f=parseInt(f.getAttribute("gap"),10);!isNaN(f)&&0e?Blockly.WidgetDiv.positionInternal_(a,0,c.height+e):Blockly.WidgetDiv.positionInternal_(a,e,c.height)}; -Blockly.WidgetDiv.calculateX_=function(a,b,c,d){if(d)return b=Math.max(b.right-c.width,a.left),Math.min(b,a.right-c.width);b=Math.min(b.left,a.right-c.width);return Math.max(b,a.left)};Blockly.WidgetDiv.calculateY_=function(a,b,c){return b.bottom+c.height>=a.bottom?b.top-c.height:b.bottom};Blockly.inject=function(a,b){Blockly.checkBlockColourConstants();"string"==typeof a&&(a=document.getElementById(a)||document.querySelector(a));if(!Blockly.utils.containsNode(document,a))throw Error("Error: container is not in current document.");var c=new Blockly.Options(b||{}),d=document.createElement("div");d.className="injectionDiv";a.appendChild(d);var e=Blockly.createDom_(d,c),f=new Blockly.BlockDragSurfaceSvg(d);d=new Blockly.WorkspaceDragSurfaceSvg(d);e=Blockly.createMainWorkspace_(e,c,f,d); -Blockly.setTheme(c.theme);Blockly.init_(e);Blockly.mainWorkspace=e;Blockly.svgResize(e);return e}; +Blockly.WidgetDiv.calculateX_=function(a,b,c,d){if(d)return b=Math.max(b.right-c.width,a.left),Math.min(b,a.right-c.width);b=Math.min(b.left,a.right-c.width);return Math.max(b,a.left)};Blockly.WidgetDiv.calculateY_=function(a,b,c){return b.bottom+c.height>=a.bottom?b.top-c.height:b.bottom};Blockly.inject=function(a,b){Blockly.checkBlockColourConstants();"string"==typeof a&&(a=document.getElementById(a)||document.querySelector(a));if(!Blockly.utils.dom.containsNode(document,a))throw Error("Error: container is not in current document.");var c=new Blockly.Options(b||{}),d=document.createElement("div");d.className="injectionDiv";a.appendChild(d);var e=Blockly.createDom_(d,c),f=new Blockly.BlockDragSurfaceSvg(d);d=new Blockly.WorkspaceDragSurfaceSvg(d);e=Blockly.createMainWorkspace_(e,c, +f,d);Blockly.setTheme(c.theme);Blockly.init_(e);Blockly.mainWorkspace=e;Blockly.svgResize(e);return e}; Blockly.createDom_=function(a,b){a.setAttribute("dir","LTR");goog.ui.Component.setDefaultRightToLeft(b.RTL);Blockly.Css.inject(b.hasCss,b.pathToMedia);var c=Blockly.utils.createSvgElement("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:html":"http://www.w3.org/1999/xhtml","xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklySvg"},a),d=Blockly.utils.createSvgElement("defs",{},c),e=String(Math.random()).substring(2),f=Blockly.utils.createSvgElement("filter",{id:"blocklyEmbossFilter"+ e},d);Blockly.utils.createSvgElement("feGaussianBlur",{"in":"SourceAlpha",stdDeviation:1,result:"blur"},f);var g=Blockly.utils.createSvgElement("feSpecularLighting",{"in":"blur",surfaceScale:1,specularConstant:.5,specularExponent:10,"lighting-color":"white",result:"specOut"},f);Blockly.utils.createSvgElement("fePointLight",{x:-5E3,y:-1E4,z:2E4},g);Blockly.utils.createSvgElement("feComposite",{"in":"specOut",in2:"SourceAlpha",operator:"in",result:"specOut"},f);Blockly.utils.createSvgElement("feComposite", {"in":"SourceGraphic",in2:"specOut",operator:"arithmetic",k1:0,k2:1,k3:1,k4:0},f);b.embossFilterId=f.id;f=Blockly.utils.createSvgElement("pattern",{id:"blocklyDisabledPattern"+e,patternUnits:"userSpaceOnUse",width:10,height:10},d);Blockly.utils.createSvgElement("rect",{width:10,height:10,fill:"#aaa"},f);Blockly.utils.createSvgElement("path",{d:"M 0 0 L 10 10 M 10 0 L 0 10",stroke:"#cc0"},f);b.disabledPatternId=f.id;b.gridPattern=Blockly.Grid.createDom(e,b.gridOptions,d);return c}; -Blockly.createMainWorkspace_=function(a,b,c,d){b.parentWorkspace=null;var e=new Blockly.WorkspaceSvg(b,c,d);e.scale=b.zoomOptions.startScale;a.appendChild(e.createDom("blocklyMainBackground"));!b.hasCategories&&b.languageTree&&(c=e.addFlyout_("svg"),Blockly.utils.insertAfter(c,a));b.hasTrashcan&&e.addTrashcan();b.zoomOptions&&b.zoomOptions.controls&&e.addZoomControls();e.translate(0,0);Blockly.mainWorkspace=e;b.readOnly||e.isMovable()||e.addChangeListener(function(a){if(!e.isDragging()&&!e.isMovable()&& +Blockly.createMainWorkspace_=function(a,b,c,d){b.parentWorkspace=null;var e=new Blockly.WorkspaceSvg(b,c,d);e.scale=b.zoomOptions.startScale;a.appendChild(e.createDom("blocklyMainBackground"));!b.hasCategories&&b.languageTree&&(c=e.addFlyout_("svg"),Blockly.utils.dom.insertAfter(c,a));b.hasTrashcan&&e.addTrashcan();b.zoomOptions&&b.zoomOptions.controls&&e.addZoomControls();e.translate(0,0);Blockly.mainWorkspace=e;b.readOnly||e.isMovable()||e.addChangeListener(function(a){if(!e.isDragging()&&!e.isMovable()&& -1!=Blockly.Events.BUMP_EVENTS.indexOf(a.type)){var b=Object.create(null),c=e.getMetrics(),d=e.scale;b.viewLeft=c.viewLeft/d;b.viewTop=c.viewTop/d;b.viewRight=(c.viewLeft+c.viewWidth)/d;b.viewBottom=(c.viewTop+c.viewHeight)/d;e.isContentBounded()?(c=e.getBlocksBoundingBox(),b.contentLeft=c.x,b.contentTop=c.y,b.contentRight=c.x+c.width,b.contentBottom=c.y+c.height):(b.contentLeft=c.contentLeft/d,b.contentTop=c.contentTop/d,b.contentRight=(c.contentLeft+c.contentWidth)/d,b.contentBottom=(c.contentTop+ c.contentHeight)/d);if(b.contentTopb.viewBottom||b.contentLeftb.viewRight){c=null;a&&(c=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));switch(a.type){case Blockly.Events.BLOCK_CREATE:case Blockly.Events.BLOCK_MOVE:var f=e.getBlockById(a.blockId);f=f.getRootBlock();break;case Blockly.Events.COMMENT_CREATE:case Blockly.Events.COMMENT_MOVE:f=e.getCommentById(a.commentId)}if(f){d=f.getBoundingRectangle();var n=b.viewTop-d.topLeft.y; 0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; @@ -1816,7 +1815,7 @@ Blockly.defineBlocksWithJsonArray=function(a){for(var b=0;b 1) { - Blockly.utils.removeNode(clone); + Blockly.utils.dom.removeNode(clone); } else { var x = clone.translateX_ + (rtl ? -1 : 1) * clone.bBox_.width * workspaceScale / 2 * percent; @@ -141,7 +142,7 @@ Blockly.BlockAnimations.connectionUiStep_ = function(ripple, start, scale) { var ms = new Date - start; var percent = ms / 150; if (percent > 1) { - Blockly.utils.removeNode(ripple); + Blockly.utils.dom.removeNode(ripple); } else { ripple.setAttribute('r', percent * 25 * scale); ripple.style.opacity = 1 - percent; diff --git a/core/block_render_svg.js b/core/block_render_svg.js index 6c905293471..ebe6012bd4e 100644 --- a/core/block_render_svg.js +++ b/core/block_render_svg.js @@ -28,7 +28,7 @@ goog.provide('Blockly.BlockSvg.render'); goog.require('Blockly.BlockSvg'); -goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -1199,10 +1199,10 @@ Blockly.BlockSvg.prototype.positionNewBlock = function(newBlock, newConnection, */ Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { if (add) { - Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } else { - Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } }; diff --git a/core/block_svg.js b/core/block_svg.js index 529e67dacad..76d46e53fa8 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -29,7 +29,6 @@ goog.provide('Blockly.BlockSvg'); goog.require('Blockly.Block'); goog.require('Blockly.BlockAnimations'); goog.require('Blockly.ContextMenu'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Events.BlockMove'); @@ -39,6 +38,8 @@ goog.require('Blockly.RenderedConnection'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.dom'); /** @@ -776,11 +777,11 @@ Blockly.BlockSvg.prototype.setDragging = function(adding) { group.skew_ = ''; Blockly.draggingConnections_ = Blockly.draggingConnections_.concat(this.getConnections_(true)); - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } else { Blockly.draggingConnections_ = []; - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } // Recurse through all blocks attached under this one. @@ -794,10 +795,10 @@ Blockly.BlockSvg.prototype.setDragging = function(adding) { */ Blockly.BlockSvg.prototype.updateMovable = function() { if (this.isMovable()) { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } else { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } }; @@ -845,7 +846,7 @@ Blockly.BlockSvg.prototype.setInsertionMarker = function(insertionMarker) { this.isInsertionMarker_ = insertionMarker; if (this.isInsertionMarker_) { this.setColour(Blockly.INSERTION_MARKER_COLOUR); - Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyInsertionMarker'); } }; @@ -923,7 +924,7 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { Blockly.Events.fire(deleteEvent); } - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); blockWorkspace.resizeContents(); // Sever JavaScript to DOM connections. this.svgGroup_ = null; @@ -1001,14 +1002,14 @@ Blockly.BlockSvg.prototype.setShadowColour_ = function() { */ Blockly.BlockSvg.prototype.updateDisabled = function() { if (this.disabled || this.getInheritedDisabled()) { - var added = Blockly.utils.addClass( + var added = Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (added) { this.svgPath_.setAttribute('fill', 'url(#' + this.workspace.options.disabledPatternId + ')'); } } else { - var removed = Blockly.utils.removeClass( + var removed = Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (removed) { this.updateColour(); @@ -1203,7 +1204,7 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) { * Select this block. Highlight it visually. */ Blockly.BlockSvg.prototype.addSelect = function() { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); }; @@ -1211,7 +1212,7 @@ Blockly.BlockSvg.prototype.addSelect = function() { * Unselect this block. Remove its highlighting. */ Blockly.BlockSvg.prototype.removeSelect = function() { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); }; @@ -1223,10 +1224,10 @@ Blockly.BlockSvg.prototype.removeSelect = function() { */ Blockly.BlockSvg.prototype.setDeleteStyle = function(enable) { if (enable) { - Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.dom.addClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete'); } else { - Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete'); } }; diff --git a/core/blockly.js b/core/blockly.js index eea9c7902e6..832a6af42c0 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -600,6 +600,16 @@ Blockly.isNumber = function(str) { return /^\s*-?\d+(\.\d+)?\s*$/.test(str); }; +/** + * Convert a hue (HSV model) into an RGB hex triplet. + * @param {number} hue Hue on a colour wheel (0-360). + * @return {string} RGB code, e.g. '#5ba65b'. + */ +Blockly.hueToHex = function(hue) { + return Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION, + Blockly.HSV_VALUE * 255); +}; + /** * Checks old colour constants are not overwritten by the host application. * If a constant is overwritten, it prints a console warning directing the diff --git a/core/bubble.js b/core/bubble.js index 28c1f59f601..7937a7aceb9 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -30,6 +30,8 @@ goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.math'); goog.require('Blockly.Workspace'); @@ -55,7 +57,7 @@ Blockly.Bubble = function(workspace, content, shape, anchorXY, if (this.workspace_.RTL) { angle = -angle; } - this.arrow_radians_ = Blockly.utils.toRadians(angle); + this.arrow_radians_ = Blockly.utils.math.toRadians(angle); var canvas = workspace.getBubbleCanvas(); canvas.appendChild(this.createDom_(content, !!(bubbleWidth && bubbleHeight))); @@ -758,7 +760,7 @@ Blockly.Bubble.prototype.setColour = function(hexColour) { Blockly.Bubble.prototype.dispose = function() { Blockly.Bubble.unbindDragEvents_(); // Dispose of and unlink the bubble. - Blockly.utils.removeNode(this.bubbleGroup_); + Blockly.utils.dom.removeNode(this.bubbleGroup_); this.bubbleGroup_ = null; this.bubbleArrow_ = null; this.bubbleBack_ = null; diff --git a/core/contextmenu.js b/core/contextmenu.js index 017b11808da..3074f1f8999 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -36,6 +36,7 @@ goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.uiMenu'); goog.require('Blockly.Xml'); @@ -156,7 +157,7 @@ Blockly.ContextMenu.createWidget_ = function(menu) { var div = Blockly.WidgetDiv.DIV; menu.render(div); var menuDom = menu.getElement(); - Blockly.utils.addClass(menuDom, 'blocklyContextMenu'); + Blockly.utils.dom.addClass(menuDom, 'blocklyContextMenu'); // Prevent system context menu when right-clicking a Blockly context menu. Blockly.bindEventWithChecks_( menuDom, 'contextmenu', null, Blockly.utils.noEvent); diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index f5eefa06b07..b624b34485b 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -28,7 +28,7 @@ goog.provide('Blockly.DropDownDiv'); -goog.require('Blockly.utils'); +goog.require('Blockly.utils.math'); goog.require('goog.style'); @@ -228,10 +228,10 @@ Blockly.DropDownDiv.showPositionedByBlock = function(field, block, * by a particular field. The primary position will be below the field, * and the secondary position above the field. Drop-down will be * constrained to the block's workspace. - * @param {Object} owner The object showing the drop-down. + * @param {!Object} owner The object showing the drop-down. * @param {Function=} opt_onHide Optional callback for when the drop-down is * hidden. - * @param {number} opt_secondaryYOffset Optional Y offset for above-block + * @param {number=} opt_secondaryYOffset Optional Y offset for above-block * positioning. * @return {boolean} True if the menu rendered below block; false if above. */ @@ -272,17 +272,18 @@ Blockly.DropDownDiv.showPositionedByField = function(owner, * @param {Function=} opt_onHide Optional callback for when the drop-down is hidden * @return {boolean} True if the menu rendered at the primary origin point. */ -Blockly.DropDownDiv.show = function(owner, primaryX, primaryY, secondaryX, secondaryY, opt_onHide) { +Blockly.DropDownDiv.show = function(owner, primaryX, primaryY, + secondaryX, secondaryY, opt_onHide) { Blockly.DropDownDiv.owner_ = owner; Blockly.DropDownDiv.onHide_ = opt_onHide; - var metrics = Blockly.DropDownDiv.getPositionMetrics(primaryX, primaryY, secondaryX, secondaryY); - // Update arrow CSS + var metrics = Blockly.DropDownDiv.getPositionMetrics(primaryX, primaryY, + secondaryX, secondaryY); + // Update arrow CSS. Blockly.DropDownDiv.arrow_.style.transform = 'translate(' + - metrics.arrowX + 'px,' + metrics.arrowY + 'px) rotate(45deg)'; - Blockly.DropDownDiv.arrow_.setAttribute('class', - metrics.arrowAtTop ? 'blocklyDropDownArrow arrowTop' : 'blocklyDropDownArrow arrowBottom'); - Blockly.DropDownDiv.arrow_.style.display = - metrics.arrowVisible ? '' : 'none'; + metrics.arrowX + 'px,' + metrics.arrowY + 'px) rotate(45deg)'; + Blockly.DropDownDiv.arrow_.setAttribute('class', metrics.arrowAtTop ? + 'blocklyDropDownArrow arrowTop' : 'blocklyDropDownArrow arrowBottom'); + Blockly.DropDownDiv.arrow_.style.display = metrics.arrowVisible ? '' : 'none'; // When we change `translate` multiple times in close succession, // Chrome may choose to wait and apply them all at once. @@ -328,7 +329,8 @@ Blockly.DropDownDiv.getBoundsInfo_ = function() { * @param {number} secondaryY Secondary/alternative origin point y, in absolute px * @return {Object} Various final metrics, including rendered positions for drop-down and arrow. */ -Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, secondaryX, secondaryY) { +Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, + secondaryX, secondaryY) { var boundsInfo = Blockly.DropDownDiv.getBoundsInfo_(); var div = Blockly.DropDownDiv.DIV_; var divSize = goog.style.getSize(div); @@ -364,14 +366,14 @@ Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, secondaryX // dropdown should appear centered relative to the desired origin point. renderX -= divSize.width / 2; // Fit horizontally in the bounds. - renderX = Blockly.utils.clampNumber( + renderX = Blockly.utils.math.clamp( boundsInfo.left, renderX, boundsInfo.right - divSize.width); // Calculate the absolute arrow X. The arrow wants to be as close to the // origin point as possible. The arrow may not be centered in the dropdown div. var absoluteArrowX = centerX - Blockly.DropDownDiv.ARROW_SIZE / 2; // Keep in overall bounds - absoluteArrowX = Blockly.utils.clampNumber( + absoluteArrowX = Blockly.utils.math.clamp( boundsInfo.left, absoluteArrowX, boundsInfo.right); // Convert the arrow position to be relative to the top left corner of the div. @@ -379,7 +381,7 @@ Blockly.DropDownDiv.getPositionMetrics = function(primaryX, primaryY, secondaryX // Pad the arrow by some pixels, primarily so that it doesn't render on top // of a rounded border. - relativeArrowX = Blockly.utils.clampNumber( + relativeArrowX = Blockly.utils.math.clamp( Blockly.DropDownDiv.ARROW_HORIZONTAL_PADDING, relativeArrowX, divSize.width - Blockly.DropDownDiv.ARROW_HORIZONTAL_PADDING - diff --git a/core/field.js b/core/field.js index 8d9d54b0188..1945ef7bf07 100644 --- a/core/field.js +++ b/core/field.js @@ -33,6 +33,7 @@ goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('goog.math.Size'); goog.require('goog.style'); @@ -337,7 +338,7 @@ Blockly.Field.prototype.dispose = function() { } this.sourceBlock_ = null; if (this.fieldGroup_) { - Blockly.utils.removeNode(this.fieldGroup_); + Blockly.utils.dom.removeNode(this.fieldGroup_); this.fieldGroup_ = null; } this.textElement_ = null; @@ -354,12 +355,12 @@ Blockly.Field.prototype.updateEditable = function() { return; } if (this.sourceBlock_.isEditable()) { - Blockly.utils.addClass(group, 'blocklyEditableText'); - Blockly.utils.removeClass(group, 'blocklyNonEditableText'); + Blockly.utils.dom.addClass(group, 'blocklyEditableText'); + Blockly.utils.dom.removeClass(group, 'blocklyNonEditableText'); group.style.cursor = this.CURSOR; } else { - Blockly.utils.addClass(group, 'blocklyNonEditableText'); - Blockly.utils.removeClass(group, 'blocklyEditableText'); + Blockly.utils.dom.addClass(group, 'blocklyNonEditableText'); + Blockly.utils.dom.removeClass(group, 'blocklyEditableText'); group.style.cursor = ''; } }; diff --git a/core/field_angle.js b/core/field_angle.js index 0b1e4d865e8..d648f548d0c 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -30,6 +30,7 @@ goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.math'); /** @@ -253,7 +254,7 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) { // This shouldn't happen, but let's not let this error propagate further. return; } - angle = Blockly.utils.toDegrees(angle); + angle = Blockly.utils.math.toDegrees(angle); // 0: East, 90: North, 180: West, 270: South. if (dx < 0) { angle += 180; @@ -304,12 +305,12 @@ Blockly.FieldAngle.prototype.updateGraph_ = function() { // Always display the input (i.e. getText) even if it is invalid. var angleDegrees = Number(this.getText()) + Blockly.FieldAngle.OFFSET; angleDegrees %= 360; - var angleRadians = Blockly.utils.toRadians(angleDegrees); + var angleRadians = Blockly.utils.math.toRadians(angleDegrees); var path = ['M ', Blockly.FieldAngle.HALF, ',', Blockly.FieldAngle.HALF]; var x2 = Blockly.FieldAngle.HALF; var y2 = Blockly.FieldAngle.HALF; if (!isNaN(angleRadians)) { - var angle1 = Blockly.utils.toRadians(Blockly.FieldAngle.OFFSET); + var angle1 = Blockly.utils.math.toRadians(Blockly.FieldAngle.OFFSET); var x1 = Math.cos(angle1) * Blockly.FieldAngle.RADIUS; var y1 = Math.sin(angle1) * -Blockly.FieldAngle.RADIUS; if (Blockly.FieldAngle.CLOCKWISE) { diff --git a/core/field_checkbox.js b/core/field_checkbox.js index cbb73933c24..82f281cadd3 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -29,7 +29,7 @@ goog.provide('Blockly.FieldCheckbox'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); -goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -123,7 +123,7 @@ Blockly.FieldCheckbox.prototype.initView = function() { this.textElement_.setAttribute('x', Blockly.FieldCheckbox.CHECK_X_OFFSET); this.textElement_.setAttribute('y', Blockly.FieldCheckbox.CHECK_Y_OFFSET); - Blockly.utils.addClass(this.textElement_, 'blocklyCheckbox'); + Blockly.utils.dom.addClass(this.textElement_, 'blocklyCheckbox'); var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR); this.textElement_.appendChild(textNode); diff --git a/core/field_date.js b/core/field_date.js index 7603524035a..5d80a665c6d 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -28,7 +28,7 @@ goog.provide('Blockly.FieldDate'); goog.require('Blockly.Events'); goog.require('Blockly.Field'); -goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('goog.date'); goog.require('goog.date.DateTime'); @@ -200,7 +200,7 @@ Blockly.FieldDate.prototype.updateEditor_ = function() { Blockly.FieldDate.prototype.showEditor_ = function() { this.picker_ = this.createWidget_(); this.picker_.render(Blockly.DropDownDiv.getContentDiv()); - Blockly.utils.addClass(this.picker_.getElement(), 'blocklyDatePicker'); + Blockly.utils.dom.addClass(this.picker_.getElement(), 'blocklyDatePicker'); Blockly.DropDownDiv.showPositionedByField(this); Blockly.DropDownDiv.setColour( this.DROPDOWN_BACKGROUND_COLOUR, this.DROPDOWN_BORDER_COLOUR); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 71f587fcfb4..13f7fc3f521 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -33,6 +33,8 @@ goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.string'); goog.require('Blockly.utils.uiMenu'); goog.require('goog.events'); @@ -255,7 +257,7 @@ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) { Blockly.FieldDropdown.prototype.createWidget_ = function(menu) { var div = Blockly.WidgetDiv.DIV; menu.render(div); - Blockly.utils.addClass(menu.getElement(), 'blocklyDropdownMenu'); + Blockly.utils.dom.addClass(menu.getElement(), 'blocklyDropdownMenu'); // Enable autofocus after the initial render to avoid issue #1329. menu.setAllowAutoFocus(true); }; @@ -323,9 +325,9 @@ Blockly.FieldDropdown.prototype.trimOptions_ = function() { for (var i = 0; i < options.length; i++) { strings.push(options[i][0]); } - var shortest = Blockly.utils.shortestStringLength(strings); - var prefixLength = Blockly.utils.commonWordPrefix(strings, shortest); - var suffixLength = Blockly.utils.commonWordSuffix(strings, shortest); + var shortest = Blockly.utils.string.shortestStringLength(strings); + var prefixLength = Blockly.utils.string.commonWordPrefix(strings, shortest); + var suffixLength = Blockly.utils.string.commonWordSuffix(strings, shortest); if (!prefixLength && !suffixLength) { return; } diff --git a/core/field_image.js b/core/field_image.js index 9188935d640..e7d8a96c346 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -29,6 +29,7 @@ goog.provide('Blockly.FieldImage'); goog.require('Blockly.Field'); goog.require('Blockly.Tooltip'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('goog.math.Size'); @@ -133,7 +134,7 @@ Blockly.FieldImage.prototype.initView = function() { */ Blockly.FieldImage.prototype.dispose = function() { if (this.fieldGroup_) { - Blockly.utils.removeNode(this.fieldGroup_); + Blockly.utils.dom.removeNode(this.fieldGroup_); this.fieldGroup_ = null; } this.imageElement_ = null; diff --git a/core/field_label.js b/core/field_label.js index b752f74bbe9..00cb8a35d24 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -30,6 +30,7 @@ goog.provide('Blockly.FieldLabel'); goog.require('Blockly.Field'); goog.require('Blockly.Tooltip'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('goog.math.Size'); @@ -82,7 +83,7 @@ Blockly.FieldLabel.prototype.initView = function() { this.createTextElement_(); this.textElement_.setAttribute('y', this.size_.height - 5); if (this.class_) { - Blockly.utils.addClass(this.textElement_, this.class_); + Blockly.utils.dom.addClass(this.textElement_, this.class_); } }; @@ -91,7 +92,7 @@ Blockly.FieldLabel.prototype.initView = function() { */ Blockly.FieldLabel.prototype.dispose = function() { if (this.textElement_) { - Blockly.utils.removeNode(this.textElement_); + Blockly.utils.dom.removeNode(this.textElement_); this.textElement_ = null; } }; diff --git a/core/field_textinput.js b/core/field_textinput.js index b791bcc2085..606108e1f53 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -34,6 +34,7 @@ goog.require('Blockly.Field'); goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -179,9 +180,9 @@ Blockly.FieldTextInput.prototype.render_ = function() { var htmlInput = Blockly.FieldTextInput.htmlInput_; this.resizeEditor_(); if (!this.isTextValid_) { - Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); } else { - Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); } } }; diff --git a/core/flyout_base.js b/core/flyout_base.js index e3f08137658..8375600d941 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -36,6 +36,7 @@ goog.require('Blockly.Gesture'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.Xml'); @@ -278,7 +279,7 @@ Blockly.Flyout.prototype.dispose = function() { this.workspace_ = null; } if (this.svgGroup_) { - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgBackground_ = null; @@ -537,7 +538,7 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() { for (var j = 0; j < this.mats_.length; j++) { var rect = this.mats_[j]; if (rect) { - Blockly.utils.removeNode(rect); + Blockly.utils.dom.removeNode(rect); } } this.mats_.length = 0; diff --git a/core/flyout_button.js b/core/flyout_button.js index 17f8d60460e..34dd9455e70 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -28,6 +28,7 @@ goog.provide('Blockly.FlyoutButton'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -228,7 +229,7 @@ Blockly.FlyoutButton.prototype.dispose = function() { Blockly.unbindEvent_(this.onMouseUpWrapper_); } if (this.svgGroup_) { - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.workspace_ = null; diff --git a/core/icon.js b/core/icon.js index 119f3ae9c7d..27af9f032ec 100644 --- a/core/icon.js +++ b/core/icon.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Icon'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -79,7 +80,7 @@ Blockly.Icon.prototype.createIcon = function() { this.iconGroup_ = Blockly.utils.createSvgElement('g', {'class': 'blocklyIconGroup'}, null); if (this.block_.isInFlyout) { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly'); } this.drawIcon_(this.iconGroup_); @@ -95,7 +96,7 @@ Blockly.Icon.prototype.createIcon = function() { */ Blockly.Icon.prototype.dispose = function() { // Dispose of and unlink the icon. - Blockly.utils.removeNode(this.iconGroup_); + Blockly.utils.dom.removeNode(this.iconGroup_); this.iconGroup_ = null; // Dispose of and unlink the bubble. this.setVisible(false); diff --git a/core/inject.js b/core/inject.js index 4582ee43d63..78f40d9cf8c 100644 --- a/core/inject.js +++ b/core/inject.js @@ -35,6 +35,7 @@ goog.require('Blockly.Options'); goog.require('Blockly.Tooltip'); goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.WorkspaceDragSurfaceSvg'); @@ -56,7 +57,7 @@ Blockly.inject = function(container, opt_options) { document.querySelector(container); } // Verify that the container is in document. - if (!Blockly.utils.containsNode(document, container)) { + if (!Blockly.utils.dom.containsNode(document, container)) { throw Error('Error: container is not in current document.'); } var options = new Blockly.Options(opt_options || {}); @@ -222,7 +223,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, if (!options.hasCategories && options.languageTree) { // Add flyout as an that is a sibling of the workspace svg. var flyout = mainWorkspace.addFlyout_('svg'); - Blockly.utils.insertAfter(flyout, svg); + Blockly.utils.dom.insertAfter(flyout, svg); } if (options.hasTrashcan) { mainWorkspace.addTrashcan(); diff --git a/core/mutator.js b/core/mutator.js index 2e57df43d1d..5247706c0e0 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -33,6 +33,7 @@ goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.Xml'); goog.require('Blockly.Xml.utils'); @@ -183,7 +184,7 @@ Blockly.Mutator.prototype.updateEditable = function() { if (!this.block_.isInFlyout) { if (this.block_.isEditable()) { if (this.iconGroup_) { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly'); } @@ -191,7 +192,7 @@ Blockly.Mutator.prototype.updateEditable = function() { // Close any mutator bubble. Icon is not clickable. this.setVisible(false); if (this.iconGroup_) { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroupReadonly'); } diff --git a/core/rendered_connection.js b/core/rendered_connection.js index b9ab8f2418a..f180cfdead6 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -27,9 +27,10 @@ goog.provide('Blockly.RenderedConnection'); goog.require('Blockly.Connection'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.dom'); /** @@ -266,7 +267,7 @@ Blockly.RenderedConnection.prototype.unhideAll = function() { * Remove the highlighting around this connection. */ Blockly.RenderedConnection.prototype.unhighlight = function() { - Blockly.utils.removeNode(Blockly.Connection.highlightedPath_); + Blockly.utils.dom.removeNode(Blockly.Connection.highlightedPath_); delete Blockly.Connection.highlightedPath_; }; diff --git a/core/scrollbar.js b/core/scrollbar.js index afec9fdc98c..9d1cc1c8447 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -30,6 +30,7 @@ goog.provide('Blockly.ScrollbarPair'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -56,7 +57,7 @@ Blockly.ScrollbarPair = function(workspace) { 'class': 'blocklyScrollbarBackground' }, null); - Blockly.utils.insertAfter(this.corner_, workspace.getBubbleCanvas()); + Blockly.utils.dom.insertAfter(this.corner_, workspace.getBubbleCanvas()); }; /** @@ -71,7 +72,7 @@ Blockly.ScrollbarPair.prototype.oldHostMetrics_ = null; * Unlink from all DOM elements to prevent memory leaks. */ Blockly.ScrollbarPair.prototype.dispose = function() { - Blockly.utils.removeNode(this.corner_); + Blockly.utils.dom.removeNode(this.corner_); this.corner_ = null; this.workspace_ = null; this.oldHostMetrics_ = null; @@ -346,7 +347,7 @@ Blockly.Scrollbar.prototype.dispose = function() { Blockly.unbindEvent_(this.onMouseDownHandleWrapper_); this.onMouseDownHandleWrapper_ = null; - Blockly.utils.removeNode(this.outerSvg_); + Blockly.utils.dom.removeNode(this.outerSvg_); this.outerSvg_ = null; this.svgGroup_ = null; this.svgBackground_ = null; @@ -624,7 +625,7 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { 'ry': radius }, this.svgGroup_); - Blockly.utils.insertAfter(this.outerSvg_, this.workspace_.getParentSvg()); + Blockly.utils.dom.insertAfter(this.outerSvg_, this.workspace_.getParentSvg()); }; /** diff --git a/core/theme/classic.js b/core/theme/classic.js index d3bb2cfbcaf..ad46626ce7a 100644 --- a/core/theme/classic.js +++ b/core/theme/classic.js @@ -22,7 +22,6 @@ * @fileoverview Classic theme. * Contains multi-coloured border to create shadow effect. */ - 'use strict'; goog.provide('Blockly.Themes.Classic'); @@ -30,6 +29,9 @@ goog.provide('Blockly.Themes.Classic'); goog.require('Blockly.Theme'); +// Temporary holding object. +Blockly.Themes.Classic = {}; + Blockly.Themes.Classic.defaultBlockStyles = { "colour_blocks": { "colourPrimary": "20" diff --git a/core/theme/highcontrast.js b/core/theme/highcontrast.js index 5dfc1bb8004..f2737e19cd6 100644 --- a/core/theme/highcontrast.js +++ b/core/theme/highcontrast.js @@ -29,6 +29,9 @@ goog.provide('Blockly.Themes.HighContrast'); goog.require('Blockly.Theme'); +// Temporary holding object. +Blockly.Themes.HighContrast = {}; + Blockly.Themes.HighContrast.defaultBlockStyles = { "colour_blocks": { "colourPrimary": "#a52714", diff --git a/core/theme/modern.js b/core/theme/modern.js index 0dc0181e459..b6fbd49df54 100644 --- a/core/theme/modern.js +++ b/core/theme/modern.js @@ -29,6 +29,9 @@ goog.provide('Blockly.Themes.Modern'); goog.require('Blockly.Theme'); +// Temporary holding object. +Blockly.Themes.Modern = {}; + Blockly.Themes.Modern.defaultBlockStyles = { "colour_blocks": { "colourPrimary": "#a5745b", diff --git a/core/toolbox.js b/core/toolbox.js index 758b184c84a..92ad7a91c67 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -32,6 +32,7 @@ goog.require('Blockly.Flyout'); goog.require('Blockly.HorizontalFlyout'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.Rect'); goog.require('Blockly.VerticalFlyout'); @@ -191,7 +192,7 @@ Blockly.Toolbox.prototype.init = function() { this.flyout_ = new Blockly.VerticalFlyout(workspaceOptions); } // Insert the flyout after the workspace. - Blockly.utils.insertAfter(this.flyout_.createDom('svg'), + Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), this.workspace_.getParentSvg()); this.flyout_.init(workspace); @@ -219,7 +220,7 @@ Blockly.Toolbox.prototype.init = function() { Blockly.Toolbox.prototype.dispose = function() { this.flyout_.dispose(); this.tree_.dispose(); - Blockly.utils.removeNode(this.HtmlDiv); + Blockly.utils.dom.removeNode(this.HtmlDiv); this.workspace_ = null; this.lastCategory_ = null; }; @@ -387,7 +388,8 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) { * @param {string} categoryName Name of the toolbox category. * @private */ -Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryName) { +Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, + categoryName) { // Decode the colour for any potential message references // (eg. `%{BKY_MATH_HUE}`). var colour = Blockly.utils.replaceMessageReferences(colourValue); @@ -399,7 +401,7 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, categoryN this.hasColours_ = true; } else if (typeof colour === 'number' || (typeof colour === 'string' && !isNaN(Number(colour)))) { - childOut.hexColour = Blockly.utils.colour.hueToHex(Number(colour)); + childOut.hexColour = Blockly.hueToHex(Number(colour)); this.hasColours_ = true; } else { childOut.hexColour = ''; @@ -516,7 +518,7 @@ Blockly.Toolbox.prototype.clearSelection = function() { * @package */ Blockly.Toolbox.prototype.addStyle = function(style) { - Blockly.utils.addClass(/** @type {!Element} */ (this.HtmlDiv), style); + Blockly.utils.dom.addClass(/** @type {!Element} */ (this.HtmlDiv), style); }; /** @@ -525,7 +527,7 @@ Blockly.Toolbox.prototype.addStyle = function(style) { * @package */ Blockly.Toolbox.prototype.removeStyle = function(style) { - Blockly.utils.removeClass(/** @type {!Element} */ (this.HtmlDiv), style); + Blockly.utils.dom.removeClass(/** @type {!Element} */ (this.HtmlDiv), style); }; /** diff --git a/core/tooltip.js b/core/tooltip.js index 06d22f85f8f..eded96dd4ee 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -35,7 +35,7 @@ */ goog.provide('Blockly.Tooltip'); -goog.require('Blockly.utils'); +goog.require('Blockly.utils.string'); /** @@ -292,7 +292,7 @@ Blockly.Tooltip.show_ = function() { while (typeof tip == 'function') { tip = tip(); } - tip = Blockly.utils.wrap(tip, Blockly.Tooltip.LIMIT); + tip = Blockly.utils.string.wrap(tip, Blockly.Tooltip.LIMIT); // Create new text, line by line. var lines = tip.split('\n'); for (var i = 0; i < lines.length; i++) { diff --git a/core/touch.js b/core/touch.js index 052128cde9a..c06433a1c86 100644 --- a/core/touch.js +++ b/core/touch.js @@ -31,6 +31,7 @@ goog.provide('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.string'); /** @@ -210,7 +211,7 @@ Blockly.Touch.checkTouchIdentifier = function(e) { * @param {!Event} e A touch event. */ Blockly.Touch.setClientFromTouch = function(e) { - if (Blockly.utils.startsWith(e.type, 'touch')) { + if (Blockly.utils.string.startsWith(e.type, 'touch')) { // Map the touch event's properties to the event. var touchPoint = e.changedTouches[0]; e.clientX = touchPoint.clientX; @@ -224,9 +225,9 @@ Blockly.Touch.setClientFromTouch = function(e) { * @return {boolean} True if it is a mouse or touch event; false otherwise. */ Blockly.Touch.isMouseOrTouchEvent = function(e) { - return Blockly.utils.startsWith(e.type, 'touch') || - Blockly.utils.startsWith(e.type, 'mouse') || - Blockly.utils.startsWith(e.type, 'pointer'); + return Blockly.utils.string.startsWith(e.type, 'touch') || + Blockly.utils.string.startsWith(e.type, 'mouse') || + Blockly.utils.string.startsWith(e.type, 'pointer'); }; /** @@ -235,8 +236,8 @@ Blockly.Touch.isMouseOrTouchEvent = function(e) { * @return {boolean} True if it is a touch event; false otherwise. */ Blockly.Touch.isTouchEvent = function(e) { - return Blockly.utils.startsWith(e.type, 'touch') || - Blockly.utils.startsWith(e.type, 'pointer'); + return Blockly.utils.string.startsWith(e.type, 'touch') || + Blockly.utils.string.startsWith(e.type, 'pointer'); }; /** diff --git a/core/trashcan.js b/core/trashcan.js index 2059ff42a49..b5c13c0a199 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Trashcan'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.Rect'); goog.require('Blockly.Xml'); @@ -286,7 +287,7 @@ Blockly.Trashcan.prototype.createDom = function() { */ Blockly.Trashcan.prototype.init = function(verticalSpacing) { if (this.workspace_.options.maxTrashcanContents > 0) { - Blockly.utils.insertAfter(this.flyout_.createDom('svg'), + Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), this.workspace_.getParentSvg()); this.flyout_.init(this.workspace_); this.flyout_.isBlockCreatable_ = function() { @@ -307,7 +308,7 @@ Blockly.Trashcan.prototype.init = function(verticalSpacing) { */ Blockly.Trashcan.prototype.dispose = function() { if (this.svgGroup_) { - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgLid_ = null; diff --git a/core/ui_menu_utils.js b/core/ui_menu_utils.js index a621827fb47..6e1dbaec2c2 100644 --- a/core/ui_menu_utils.js +++ b/core/ui_menu_utils.js @@ -19,7 +19,7 @@ */ /** - * @fileoverview Utility methods for working with the closure menu + * @fileoverview Utility methods for working with the Closure menu * (goog.ui.menu). * @author fenichel@google.com (Rachel Fenichel) */ diff --git a/core/utils.js b/core/utils.js index 6a4bf79f433..54b33c011e6 100644 --- a/core/utils.js +++ b/core/utils.js @@ -35,79 +35,11 @@ goog.provide('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Msg'); goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.string'); goog.require('goog.style'); -/** - * Add a CSS class to a element. - * Similar to Closure's goog.dom.classes.add, except it handles SVG elements. - * @param {!Element} element DOM element to add class to. - * @param {string} className Name of class to add. - * @return {boolean} True if class was added, false if already present. - */ -Blockly.utils.addClass = function(element, className) { - var classes = element.getAttribute('class') || ''; - if ((' ' + classes + ' ').indexOf(' ' + className + ' ') != -1) { - return false; - } - if (classes) { - classes += ' '; - } - element.setAttribute('class', classes + className); - return true; -}; - -/** - * Remove a CSS class from a element. - * Similar to Closure's goog.dom.classes.remove, except it handles SVG elements. - * @param {!Element} element DOM element to remove class from. - * @param {string} className Name of class to remove. - * @return {boolean} True if class was removed, false if never present. - */ -Blockly.utils.removeClass = function(element, className) { - var classes = element.getAttribute('class'); - if ((' ' + classes + ' ').indexOf(' ' + className + ' ') == -1) { - return false; - } - var classList = classes.split(/\s+/); - for (var i = 0; i < classList.length; i++) { - if (!classList[i] || classList[i] == className) { - classList.splice(i, 1); - i--; - } - } - if (classList.length) { - element.setAttribute('class', classList.join(' ')); - } else { - element.removeAttribute('class'); - } - return true; -}; - -/** - * Checks if an element has the specified CSS class. - * Similar to Closure's goog.dom.classes.has, except it handles SVG elements. - * @param {!Element} element DOM element to check. - * @param {string} className Name of class to check. - * @return {boolean} True if class exists, false otherwise. - * @package - */ -Blockly.utils.hasClass = function(element, className) { - var classes = element.getAttribute('class'); - return (' ' + classes + ' ').indexOf(' ' + className + ' ') != -1; -}; - -/** - * Removes a node from its parent. No-op if not attached to a parent. - * @param {Node} node The node to remove. - * @return {Node} The node removed if removed; else, null. - */ -// Copied from Closure goog.dom.removeNode -Blockly.utils.removeNode = function(node) { - return node && node.parentNode ? node.parentNode.removeChild(node) : null; -}; - /** * Don't do anything for this event, just halt propagation. * @param {!Event} e An event. @@ -303,90 +235,6 @@ Blockly.utils.getScrollDeltaPixels = function(e) { } }; -/** - * Given an array of strings, return the length of the shortest one. - * @param {!Array.} array Array of strings. - * @return {number} Length of shortest string. - */ -Blockly.utils.shortestStringLength = function(array) { - if (!array.length) { - return 0; - } - return array.reduce(function(a, b) { - return a.length < b.length ? a : b; - }).length; -}; - -/** - * Given an array of strings, return the length of the common prefix. - * Words may not be split. Any space after a word is included in the length. - * @param {!Array.} array Array of strings. - * @param {number=} opt_shortest Length of shortest string. - * @return {number} Length of common prefix. - */ -Blockly.utils.commonWordPrefix = function(array, opt_shortest) { - if (!array.length) { - return 0; - } else if (array.length == 1) { - return array[0].length; - } - var wordPrefix = 0; - var max = opt_shortest || Blockly.utils.shortestStringLength(array); - for (var len = 0; len < max; len++) { - var letter = array[0][len]; - for (var i = 1; i < array.length; i++) { - if (letter != array[i][len]) { - return wordPrefix; - } - } - if (letter == ' ') { - wordPrefix = len + 1; - } - } - for (var i = 1; i < array.length; i++) { - var letter = array[i][len]; - if (letter && letter != ' ') { - return wordPrefix; - } - } - return max; -}; - -/** - * Given an array of strings, return the length of the common suffix. - * Words may not be split. Any space after a word is included in the length. - * @param {!Array.} array Array of strings. - * @param {number=} opt_shortest Length of shortest string. - * @return {number} Length of common suffix. - */ -Blockly.utils.commonWordSuffix = function(array, opt_shortest) { - if (!array.length) { - return 0; - } else if (array.length == 1) { - return array[0].length; - } - var wordPrefix = 0; - var max = opt_shortest || Blockly.utils.shortestStringLength(array); - for (var len = 0; len < max; len++) { - var letter = array[0].substr(-len - 1, 1); - for (var i = 1; i < array.length; i++) { - if (letter != array[i].substr(-len - 1, 1)) { - return wordPrefix; - } - } - if (letter == ' ') { - wordPrefix = len + 1; - } - } - for (var i = 1; i < array.length; i++) { - var letter = array[i].charAt(array[i].length - len - 1); - if (letter && letter != ' ') { - return wordPrefix; - } - } - return max; -}; - /** * Parse a string with any number of interpolation tokens (%1, %2, ...). * It will also replace string table references (e.g., %{bky_my_msg} and @@ -534,7 +382,7 @@ Blockly.utils.tokenizeInterpolation_ = function(message, // BKY_ is the prefix used to namespace the strings used in Blockly // core files and the predefined blocks in ../blocks/. // These strings are defined in ../msgs/ files. - var bklyKey = Blockly.utils.startsWith(keyUpper, 'BKY_') ? + var bklyKey = Blockly.utils.string.startsWith(keyUpper, 'BKY_') ? keyUpper.substring(4) : null; if (bklyKey && bklyKey in Blockly.Msg) { var rawValue = Blockly.Msg[bklyKey]; @@ -619,174 +467,6 @@ Blockly.utils.genUid = function() { Blockly.utils.genUid.soup_ = '!#$%()*+,-./:;=?@[]^_`{|}~' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; -/** - * Wrap text to the specified width. - * @param {string} text Text to wrap. - * @param {number} limit Width to wrap each line. - * @return {string} Wrapped text. - */ -Blockly.utils.wrap = function(text, limit) { - var lines = text.split('\n'); - for (var i = 0; i < lines.length; i++) { - lines[i] = Blockly.utils.wrapLine_(lines[i], limit); - } - return lines.join('\n'); -}; - -/** - * Wrap single line of text to the specified width. - * @param {string} text Text to wrap. - * @param {number} limit Width to wrap each line. - * @return {string} Wrapped text. - * @private - */ -Blockly.utils.wrapLine_ = function(text, limit) { - if (text.length <= limit) { - // Short text, no need to wrap. - return text; - } - // Split the text into words. - var words = text.trim().split(/\s+/); - // Set limit to be the length of the largest word. - for (var i = 0; i < words.length; i++) { - if (words[i].length > limit) { - limit = words[i].length; - } - } - - var lastScore; - var score = -Infinity; - var lastText; - var lineCount = 1; - do { - lastScore = score; - lastText = text; - // Create a list of booleans representing if a space (false) or - // a break (true) appears after each word. - var wordBreaks = []; - // Seed the list with evenly spaced linebreaks. - var steps = words.length / lineCount; - var insertedBreaks = 1; - for (var i = 0; i < words.length - 1; i++) { - if (insertedBreaks < (i + 1.5) / steps) { - insertedBreaks++; - wordBreaks[i] = true; - } else { - wordBreaks[i] = false; - } - } - wordBreaks = Blockly.utils.wrapMutate_(words, wordBreaks, limit); - score = Blockly.utils.wrapScore_(words, wordBreaks, limit); - text = Blockly.utils.wrapToText_(words, wordBreaks); - lineCount++; - } while (score > lastScore); - return lastText; -}; - -/** - * Compute a score for how good the wrapping is. - * @param {!Array.} words Array of each word. - * @param {!Array.} wordBreaks Array of line breaks. - * @param {number} limit Width to wrap each line. - * @return {number} Larger the better. - * @private - */ -Blockly.utils.wrapScore_ = function(words, wordBreaks, limit) { - // If this function becomes a performance liability, add caching. - // Compute the length of each line. - var lineLengths = [0]; - var linePunctuation = []; - for (var i = 0; i < words.length; i++) { - lineLengths[lineLengths.length - 1] += words[i].length; - if (wordBreaks[i] === true) { - lineLengths.push(0); - linePunctuation.push(words[i].charAt(words[i].length - 1)); - } else if (wordBreaks[i] === false) { - lineLengths[lineLengths.length - 1]++; - } - } - var maxLength = Math.max.apply(Math, lineLengths); - - var score = 0; - for (var i = 0; i < lineLengths.length; i++) { - // Optimize for width. - // -2 points per char over limit (scaled to the power of 1.5). - score -= Math.pow(Math.abs(limit - lineLengths[i]), 1.5) * 2; - // Optimize for even lines. - // -1 point per char smaller than max (scaled to the power of 1.5). - score -= Math.pow(maxLength - lineLengths[i], 1.5); - // Optimize for structure. - // Add score to line endings after punctuation. - if ('.?!'.indexOf(linePunctuation[i]) != -1) { - score += limit / 3; - } else if (',;)]}'.indexOf(linePunctuation[i]) != -1) { - score += limit / 4; - } - } - // All else being equal, the last line should not be longer than the - // previous line. For example, this looks wrong: - // aaa bbb - // ccc ddd eee - if (lineLengths.length > 1 && lineLengths[lineLengths.length - 1] <= - lineLengths[lineLengths.length - 2]) { - score += 0.5; - } - return score; -}; - -/** - * Mutate the array of line break locations until an optimal solution is found. - * No line breaks are added or deleted, they are simply moved around. - * @param {!Array.} words Array of each word. - * @param {!Array.} wordBreaks Array of line breaks. - * @param {number} limit Width to wrap each line. - * @return {!Array.} New array of optimal line breaks. - * @private - */ -Blockly.utils.wrapMutate_ = function(words, wordBreaks, limit) { - var bestScore = Blockly.utils.wrapScore_(words, wordBreaks, limit); - var bestBreaks; - // Try shifting every line break forward or backward. - for (var i = 0; i < wordBreaks.length - 1; i++) { - if (wordBreaks[i] == wordBreaks[i + 1]) { - continue; - } - var mutatedWordBreaks = [].concat(wordBreaks); - mutatedWordBreaks[i] = !mutatedWordBreaks[i]; - mutatedWordBreaks[i + 1] = !mutatedWordBreaks[i + 1]; - var mutatedScore = - Blockly.utils.wrapScore_(words, mutatedWordBreaks, limit); - if (mutatedScore > bestScore) { - bestScore = mutatedScore; - bestBreaks = mutatedWordBreaks; - } - } - if (bestBreaks) { - // Found an improvement. See if it may be improved further. - return Blockly.utils.wrapMutate_(words, bestBreaks, limit); - } - // No improvements found. Done. - return wordBreaks; -}; - -/** - * Reassemble the array of words into text, with the specified line breaks. - * @param {!Array.} words Array of each word. - * @param {!Array.} wordBreaks Array of line breaks. - * @return {string} Plain text. - * @private - */ -Blockly.utils.wrapToText_ = function(words, wordBreaks) { - var text = []; - for (var i = 0; i < words.length; i++) { - text.push(words[i]); - if (wordBreaks[i] !== undefined) { - text.push(wordBreaks[i] ? '\n' : ' '); - } - } - return text.join(''); -}; - /** * Check if 3D transforms are supported by adding an element * and attempting to set the property. @@ -837,26 +517,6 @@ Blockly.utils.is3dSupported = function() { return Blockly.utils.is3dSupported.cached_; }; -/** - * Insert a node after a reference node. - * Contrast with node.insertBefore function. - * @param {!Element} newNode New element to insert. - * @param {!Element} refNode Existing element to precede new node. - * @package - */ -Blockly.utils.insertAfter = function(newNode, refNode) { - var siblingNode = refNode.nextSibling; - var parentNode = refNode.parentNode; - if (!parentNode) { - throw Error('Reference node has no parent.'); - } - if (siblingNode) { - parentNode.insertBefore(newNode, siblingNode); - } else { - parentNode.appendChild(newNode); - } -}; - /** * Calls a function after the page has loaded, possibly immediately. * @param {function()} fn Function to run. @@ -909,18 +569,6 @@ Blockly.utils.getViewportBBox = function() { }; }; -/** - * Fast prefix-checker. - * Copied from Closure's goog.string.startsWith. - * @param {string} str The string to check. - * @param {string} prefix A string to look for at the start of `str`. - * @return {boolean} True if `str` begins with `prefix`. - * @package - */ -Blockly.utils.startsWith = function(str, prefix) { - return str.lastIndexOf(prefix, 0) == 0; -}; - /** * Removes the first occurrence of a particular value from an array. * @param {!Array} arr Array from which to remove @@ -938,40 +586,6 @@ Blockly.utils.arrayRemove = function(arr, obj) { return true; }; -/** - * Converts degrees to radians. - * Copied from Closure's goog.math.toRadians. - * @param {number} angleDegrees Angle in degrees. - * @return {number} Angle in radians. - * @package - */ -Blockly.utils.toRadians = function(angleDegrees) { - return angleDegrees * Math.PI / 180; -}; - -/** - * Converts radians to degrees. - * Copied from Closure's goog.math.toDegrees. - * @param {number} angleRadians Angle in radians. - * @return {number} Angle in degrees. - * @package - */ -Blockly.utils.toDegrees = function(angleRadians) { - return angleRadians * 180 / Math.PI; -}; - -/** - * Whether a node contains another node. - * @param {!Node} parent The node that should contain the other node. - * @param {!Node} descendant The node to test presence of. - * @return {boolean} Whether the parent node contains the descendant node. - * @package - */ -Blockly.utils.containsNode = function(parent, descendant) { - return !!(parent.compareDocumentPosition(descendant) & - Node.DOCUMENT_POSITION_CONTAINED_BY); -}; - /** * Gets the document scroll distance as a coordinate object. * Copied from Closure's goog.dom.getDocumentScroll. @@ -1019,23 +633,6 @@ Blockly.utils.getBlockTypeCounts = function(block, opt_stripFollowing) { return typeCountsMap; }; -/** - * Clamp the provided number between the lower bound and the upper bound. - * @param {number} lowerBound The desired lower bound. - * @param {number} number The number to clamp. - * @param {number} upperBound The desired upper bound. - * @return {number} The clamped number. - * @package - */ -Blockly.utils.clampNumber = function(lowerBound, number, upperBound) { - if (upperBound < lowerBound) { - var temp = upperBound; - upperBound = lowerBound; - lowerBound = temp; - } - return Math.max(lowerBound, Math.min(number, upperBound)); -}; - /** * Reference to the global object. */ diff --git a/core/utils_colour.js b/core/utils/colour.js similarity index 94% rename from core/utils_colour.js rename to core/utils/colour.js index 549cd1c61b4..5a4f6ca7180 100644 --- a/core/utils_colour.js +++ b/core/utils/colour.js @@ -103,16 +103,6 @@ Blockly.utils.colour.hexToRgb = function(hexColor) { return [r, g, b]; }; -/** - * Convert a hue (HSV model) into an RGB hex triplet. - * @param {number} hue Hue on a colour wheel (0-360). - * @return {string} RGB code, e.g. '#5ba65b'. - */ -Blockly.utils.colour.hueToHex = function(hue) { - return Blockly.utils.colour.hsvToHex(hue, Blockly.HSV_SATURATION, - Blockly.HSV_VALUE * 255); -}; - /** * Converts an HSV triplet to hex representation. * @param {number} h Hue value in [0, 360]. diff --git a/core/utils_coordinate.js b/core/utils/coordinate.js similarity index 100% rename from core/utils_coordinate.js rename to core/utils/coordinate.js diff --git a/core/utils/dom.js b/core/utils/dom.js new file mode 100644 index 00000000000..9151d4499ec --- /dev/null +++ b/core/utils/dom.js @@ -0,0 +1,132 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utility methods for DOM manipulation. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.utils.dom + * @namespace + */ +goog.provide('Blockly.utils.dom'); + + +/** + * Add a CSS class to a element. + * Similar to Closure's goog.dom.classes.add, except it handles SVG elements. + * @param {!Element} element DOM element to add class to. + * @param {string} className Name of class to add. + * @return {boolean} True if class was added, false if already present. + */ +Blockly.utils.dom.addClass = function(element, className) { + var classes = element.getAttribute('class') || ''; + if ((' ' + classes + ' ').indexOf(' ' + className + ' ') != -1) { + return false; + } + if (classes) { + classes += ' '; + } + element.setAttribute('class', classes + className); + return true; +}; + +/** + * Remove a CSS class from a element. + * Similar to Closure's goog.dom.classes.remove, except it handles SVG elements. + * @param {!Element} element DOM element to remove class from. + * @param {string} className Name of class to remove. + * @return {boolean} True if class was removed, false if never present. + */ +Blockly.utils.dom.removeClass = function(element, className) { + var classes = element.getAttribute('class'); + if ((' ' + classes + ' ').indexOf(' ' + className + ' ') == -1) { + return false; + } + var classList = classes.split(/\s+/); + for (var i = 0; i < classList.length; i++) { + if (!classList[i] || classList[i] == className) { + classList.splice(i, 1); + i--; + } + } + if (classList.length) { + element.setAttribute('class', classList.join(' ')); + } else { + element.removeAttribute('class'); + } + return true; +}; + +/** + * Checks if an element has the specified CSS class. + * Similar to Closure's goog.dom.classes.has, except it handles SVG elements. + * @param {!Element} element DOM element to check. + * @param {string} className Name of class to check. + * @return {boolean} True if class exists, false otherwise. + */ +Blockly.utils.dom.hasClass = function(element, className) { + var classes = element.getAttribute('class'); + return (' ' + classes + ' ').indexOf(' ' + className + ' ') != -1; +}; + +/** + * Removes a node from its parent. No-op if not attached to a parent. + * @param {Node} node The node to remove. + * @return {Node} The node removed if removed; else, null. + */ +// Copied from Closure goog.dom.removeNode +Blockly.utils.dom.removeNode = function(node) { + return node && node.parentNode ? node.parentNode.removeChild(node) : null; +}; + +/** + * Insert a node after a reference node. + * Contrast with node.insertBefore function. + * @param {!Element} newNode New element to insert. + * @param {!Element} refNode Existing element to precede new node. + */ +Blockly.utils.dom.insertAfter = function(newNode, refNode) { + var siblingNode = refNode.nextSibling; + var parentNode = refNode.parentNode; + if (!parentNode) { + throw Error('Reference node has no parent.'); + } + if (siblingNode) { + parentNode.insertBefore(newNode, siblingNode); + } else { + parentNode.appendChild(newNode); + } +}; + +/** + * Whether a node contains another node. + * @param {!Node} parent The node that should contain the other node. + * @param {!Node} descendant The node to test presence of. + * @return {boolean} Whether the parent node contains the descendant node. + */ +Blockly.utils.dom.containsNode = function(parent, descendant) { + return !!(parent.compareDocumentPosition(descendant) & + Node.DOCUMENT_POSITION_CONTAINED_BY); +}; diff --git a/core/utils/math.js b/core/utils/math.js new file mode 100644 index 00000000000..7a8cc3ff00d --- /dev/null +++ b/core/utils/math.js @@ -0,0 +1,70 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utility methods for math. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.utils.math + * @namespace + */ +goog.provide('Blockly.utils.math'); + + +/** + * Converts degrees to radians. + * Copied from Closure's goog.math.toRadians. + * @param {number} angleDegrees Angle in degrees. + * @return {number} Angle in radians. + */ +Blockly.utils.math.toRadians = function(angleDegrees) { + return angleDegrees * Math.PI / 180; +}; + +/** + * Converts radians to degrees. + * Copied from Closure's goog.math.toDegrees. + * @param {number} angleRadians Angle in radians. + * @return {number} Angle in degrees. + */ +Blockly.utils.math.toDegrees = function(angleRadians) { + return angleRadians * 180 / Math.PI; +}; + +/** + * Clamp the provided number between the lower bound and the upper bound. + * @param {number} lowerBound The desired lower bound. + * @param {number} number The number to clamp. + * @param {number} upperBound The desired upper bound. + * @return {number} The clamped number. + */ +Blockly.utils.math.clamp = function(lowerBound, number, upperBound) { + if (upperBound < lowerBound) { + var temp = upperBound; + upperBound = lowerBound; + lowerBound = temp; + } + return Math.max(lowerBound, Math.min(number, upperBound)); +}; diff --git a/core/utils_rect.js b/core/utils/rect.js similarity index 100% rename from core/utils_rect.js rename to core/utils/rect.js diff --git a/core/utils/string.js b/core/utils/string.js new file mode 100644 index 00000000000..75425f7071c --- /dev/null +++ b/core/utils/string.js @@ -0,0 +1,298 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Utility methods for string manipulation. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +/** + * @name Blockly.utils.string + * @namespace + */ +goog.provide('Blockly.utils.string'); + + +/** + * Fast prefix-checker. + * Copied from Closure's goog.string.startsWith. + * @param {string} str The string to check. + * @param {string} prefix A string to look for at the start of `str`. + * @return {boolean} True if `str` begins with `prefix`. + */ +Blockly.utils.string.startsWith = function(str, prefix) { + return str.lastIndexOf(prefix, 0) == 0; +}; + +/** + * Given an array of strings, return the length of the shortest one. + * @param {!Array.} array Array of strings. + * @return {number} Length of shortest string. + */ +Blockly.utils.string.shortestStringLength = function(array) { + if (!array.length) { + return 0; + } + return array.reduce(function(a, b) { + return a.length < b.length ? a : b; + }).length; +}; + +/** + * Given an array of strings, return the length of the common prefix. + * Words may not be split. Any space after a word is included in the length. + * @param {!Array.} array Array of strings. + * @param {number=} opt_shortest Length of shortest string. + * @return {number} Length of common prefix. + */ +Blockly.utils.string.commonWordPrefix = function(array, opt_shortest) { + if (!array.length) { + return 0; + } else if (array.length == 1) { + return array[0].length; + } + var wordPrefix = 0; + var max = opt_shortest || Blockly.utils.string.shortestStringLength(array); + for (var len = 0; len < max; len++) { + var letter = array[0][len]; + for (var i = 1; i < array.length; i++) { + if (letter != array[i][len]) { + return wordPrefix; + } + } + if (letter == ' ') { + wordPrefix = len + 1; + } + } + for (var i = 1; i < array.length; i++) { + var letter = array[i][len]; + if (letter && letter != ' ') { + return wordPrefix; + } + } + return max; +}; + +/** + * Given an array of strings, return the length of the common suffix. + * Words may not be split. Any space after a word is included in the length. + * @param {!Array.} array Array of strings. + * @param {number=} opt_shortest Length of shortest string. + * @return {number} Length of common suffix. + */ +Blockly.utils.string.commonWordSuffix = function(array, opt_shortest) { + if (!array.length) { + return 0; + } else if (array.length == 1) { + return array[0].length; + } + var wordPrefix = 0; + var max = opt_shortest || Blockly.utils.string.shortestStringLength(array); + for (var len = 0; len < max; len++) { + var letter = array[0].substr(-len - 1, 1); + for (var i = 1; i < array.length; i++) { + if (letter != array[i].substr(-len - 1, 1)) { + return wordPrefix; + } + } + if (letter == ' ') { + wordPrefix = len + 1; + } + } + for (var i = 1; i < array.length; i++) { + var letter = array[i].charAt(array[i].length - len - 1); + if (letter && letter != ' ') { + return wordPrefix; + } + } + return max; +}; + +/** + * Wrap text to the specified width. + * @param {string} text Text to wrap. + * @param {number} limit Width to wrap each line. + * @return {string} Wrapped text. + */ +Blockly.utils.string.wrap = function(text, limit) { + var lines = text.split('\n'); + for (var i = 0; i < lines.length; i++) { + lines[i] = Blockly.utils.string.wrapLine_(lines[i], limit); + } + return lines.join('\n'); +}; + +/** + * Wrap single line of text to the specified width. + * @param {string} text Text to wrap. + * @param {number} limit Width to wrap each line. + * @return {string} Wrapped text. + * @private + */ +Blockly.utils.string.wrapLine_ = function(text, limit) { + if (text.length <= limit) { + // Short text, no need to wrap. + return text; + } + // Split the text into words. + var words = text.trim().split(/\s+/); + // Set limit to be the length of the largest word. + for (var i = 0; i < words.length; i++) { + if (words[i].length > limit) { + limit = words[i].length; + } + } + + var lastScore; + var score = -Infinity; + var lastText; + var lineCount = 1; + do { + lastScore = score; + lastText = text; + // Create a list of booleans representing if a space (false) or + // a break (true) appears after each word. + var wordBreaks = []; + // Seed the list with evenly spaced linebreaks. + var steps = words.length / lineCount; + var insertedBreaks = 1; + for (var i = 0; i < words.length - 1; i++) { + if (insertedBreaks < (i + 1.5) / steps) { + insertedBreaks++; + wordBreaks[i] = true; + } else { + wordBreaks[i] = false; + } + } + wordBreaks = Blockly.utils.string.wrapMutate_(words, wordBreaks, limit); + score = Blockly.utils.string.wrapScore_(words, wordBreaks, limit); + text = Blockly.utils.string.wrapToText_(words, wordBreaks); + lineCount++; + } while (score > lastScore); + return lastText; +}; + +/** + * Compute a score for how good the wrapping is. + * @param {!Array.} words Array of each word. + * @param {!Array.} wordBreaks Array of line breaks. + * @param {number} limit Width to wrap each line. + * @return {number} Larger the better. + * @private + */ +Blockly.utils.string.wrapScore_ = function(words, wordBreaks, limit) { + // If this function becomes a performance liability, add caching. + // Compute the length of each line. + var lineLengths = [0]; + var linePunctuation = []; + for (var i = 0; i < words.length; i++) { + lineLengths[lineLengths.length - 1] += words[i].length; + if (wordBreaks[i] === true) { + lineLengths.push(0); + linePunctuation.push(words[i].charAt(words[i].length - 1)); + } else if (wordBreaks[i] === false) { + lineLengths[lineLengths.length - 1]++; + } + } + var maxLength = Math.max.apply(Math, lineLengths); + + var score = 0; + for (var i = 0; i < lineLengths.length; i++) { + // Optimize for width. + // -2 points per char over limit (scaled to the power of 1.5). + score -= Math.pow(Math.abs(limit - lineLengths[i]), 1.5) * 2; + // Optimize for even lines. + // -1 point per char smaller than max (scaled to the power of 1.5). + score -= Math.pow(maxLength - lineLengths[i], 1.5); + // Optimize for structure. + // Add score to line endings after punctuation. + if ('.?!'.indexOf(linePunctuation[i]) != -1) { + score += limit / 3; + } else if (',;)]}'.indexOf(linePunctuation[i]) != -1) { + score += limit / 4; + } + } + // All else being equal, the last line should not be longer than the + // previous line. For example, this looks wrong: + // aaa bbb + // ccc ddd eee + if (lineLengths.length > 1 && lineLengths[lineLengths.length - 1] <= + lineLengths[lineLengths.length - 2]) { + score += 0.5; + } + return score; +}; + +/** + * Mutate the array of line break locations until an optimal solution is found. + * No line breaks are added or deleted, they are simply moved around. + * @param {!Array.} words Array of each word. + * @param {!Array.} wordBreaks Array of line breaks. + * @param {number} limit Width to wrap each line. + * @return {!Array.} New array of optimal line breaks. + * @private + */ +Blockly.utils.string.wrapMutate_ = function(words, wordBreaks, limit) { + var bestScore = Blockly.utils.string.wrapScore_(words, wordBreaks, limit); + var bestBreaks; + // Try shifting every line break forward or backward. + for (var i = 0; i < wordBreaks.length - 1; i++) { + if (wordBreaks[i] == wordBreaks[i + 1]) { + continue; + } + var mutatedWordBreaks = [].concat(wordBreaks); + mutatedWordBreaks[i] = !mutatedWordBreaks[i]; + mutatedWordBreaks[i + 1] = !mutatedWordBreaks[i + 1]; + var mutatedScore = + Blockly.utils.string.wrapScore_(words, mutatedWordBreaks, limit); + if (mutatedScore > bestScore) { + bestScore = mutatedScore; + bestBreaks = mutatedWordBreaks; + } + } + if (bestBreaks) { + // Found an improvement. See if it may be improved further. + return Blockly.utils.string.wrapMutate_(words, bestBreaks, limit); + } + // No improvements found. Done. + return wordBreaks; +}; + +/** + * Reassemble the array of words into text, with the specified line breaks. + * @param {!Array.} words Array of each word. + * @param {!Array.} wordBreaks Array of line breaks. + * @return {string} Plain text. + * @private + */ +Blockly.utils.string.wrapToText_ = function(words, wordBreaks) { + var text = []; + for (var i = 0; i < words.length; i++) { + text.push(words[i]); + if (wordBreaks[i] !== undefined) { + text.push(wordBreaks[i] ? '\n' : ' '); + } + } + return text.join(''); +}; + diff --git a/core/workspace.js b/core/workspace.js index 6cf93946f1c..a630a7a0b9e 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Workspace'); goog.require('Blockly.Events'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.math'); goog.require('Blockly.VariableMap'); goog.require('Blockly.WorkspaceComment'); @@ -200,7 +201,7 @@ Blockly.Workspace.prototype.getTopBlocks = function(ordered) { var blocks = [].concat(this.topBlocks_); if (ordered && blocks.length > 1) { this.sortObjects_.offset = - Math.sin(Blockly.utils.toRadians(Blockly.Workspace.SCAN_ANGLE)); + Math.sin(Blockly.utils.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); if (this.RTL) { this.sortObjects_.offset *= -1; } @@ -246,7 +247,7 @@ Blockly.Workspace.prototype.getBlocksByType = function(type, ordered) { var blocks = this.typedBlocksDB_[type].slice(0); if (ordered && blocks.length > 1) { this.sortObjects_.offset = - Math.sign(Blockly.utils.toRadians(Blockly.Workspace.SCAN_ANGLE)); + Math.sign(Blockly.utils.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); if (this.RTL) { this.sortObjects_.offset *= -1; } @@ -299,7 +300,7 @@ Blockly.Workspace.prototype.getTopComments = function(ordered) { var comments = [].concat(this.topComments_); if (ordered && comments.length > 1) { this.sortObjects_.offset = - Math.sin(Blockly.utils.toRadians(Blockly.Workspace.SCAN_ANGLE)); + Math.sin(Blockly.utils.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); if (this.RTL) { this.sortObjects_.offset *= -1; } diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 75e02d04cc0..063a09be681 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -28,6 +28,7 @@ goog.provide('Blockly.WorkspaceAudio'); goog.require('Blockly.userAgent'); +goog.require('Blockly.utils'); /** diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index 02414037639..0742d8675e0 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -26,8 +26,9 @@ goog.provide('Blockly.WorkspaceCommentSvg.render'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceCommentSvg'); @@ -283,7 +284,7 @@ Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_ = function(e) { */ Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) { // Highlight the delete icon. - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.deleteIconBorder_), 'blocklyDeleteIconHighlighted'); // This event has been handled. No need to bubble up to the document. @@ -297,7 +298,7 @@ Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) { */ Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(_e) { // Restore highlight on the delete icon. - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.deleteIconBorder_), 'blocklyDeleteIconHighlighted'); }; @@ -441,9 +442,9 @@ Blockly.WorkspaceCommentSvg.prototype.setFocus = function() { } comment.textarea_.focus(); comment.addFocus(); - Blockly.utils.addClass( + Blockly.utils.dom.addClass( comment.svgRectTarget_, 'blocklyCommentTargetFocused'); - Blockly.utils.addClass( + Blockly.utils.dom.addClass( comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused'); }, 0); }; @@ -463,9 +464,9 @@ Blockly.WorkspaceCommentSvg.prototype.blurFocus = function() { comment.textarea_.blur(); comment.removeFocus(); - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( comment.svgRectTarget_, 'blocklyCommentTargetFocused'); - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused'); }, 0); }; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 9fb2776aa82..a8051e8120a 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -33,6 +33,7 @@ goog.require('Blockly.Events.CommentDelete'); goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceComment'); @@ -118,7 +119,7 @@ Blockly.WorkspaceCommentSvg.prototype.dispose = function() { Blockly.Events.fire(new Blockly.Events.CommentDelete(this)); } - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); // Sever JavaScript to DOM connections. this.svgGroup_ = null; this.svgRect_ = null; @@ -233,7 +234,7 @@ Blockly.WorkspaceCommentSvg.prototype.unselect = function() { * @package */ Blockly.WorkspaceCommentSvg.prototype.addSelect = function() { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); this.setFocus(); }; @@ -243,7 +244,7 @@ Blockly.WorkspaceCommentSvg.prototype.addSelect = function() { * @package */ Blockly.WorkspaceCommentSvg.prototype.removeSelect = function() { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); this.blurFocus(); }; @@ -253,7 +254,7 @@ Blockly.WorkspaceCommentSvg.prototype.removeSelect = function() { * @package */ Blockly.WorkspaceCommentSvg.prototype.addFocus = function() { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyFocused'); }; @@ -262,7 +263,7 @@ Blockly.WorkspaceCommentSvg.prototype.addFocus = function() { * @package */ Blockly.WorkspaceCommentSvg.prototype.removeFocus = function() { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyFocused'); }; @@ -450,10 +451,10 @@ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { */ Blockly.WorkspaceCommentSvg.prototype.updateMovable = function() { if (this.isMovable()) { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } else { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } }; @@ -478,10 +479,10 @@ Blockly.WorkspaceCommentSvg.prototype.setDragging = function(adding) { var group = this.getSvgRoot(); group.translate_ = ''; group.skew_ = ''; - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } else { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); } }; @@ -524,10 +525,10 @@ Blockly.WorkspaceCommentSvg.prototype.setContent = function(content) { */ Blockly.WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) { if (enable) { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete'); } else { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete'); } }; diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index 1a31a9ab709..4766a9dec0c 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -31,6 +31,7 @@ goog.provide('Blockly.WorkspaceDragSurfaceSvg'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -141,8 +142,8 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { var blockCanvas = this.SVG_.childNodes[0]; var bubbleCanvas = this.SVG_.childNodes[1]; if (!blockCanvas || !bubbleCanvas || - !Blockly.utils.hasClass(blockCanvas, 'blocklyBlockCanvas') || - !Blockly.utils.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) { + !Blockly.utils.dom.hasClass(blockCanvas, 'blocklyBlockCanvas') || + !Blockly.utils.dom.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) { throw Error('Couldn\'t clear and hide the drag surface. ' + 'A node was missing.'); } @@ -150,13 +151,13 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { // If there is a previous sibling, put the blockCanvas back right afterwards, // otherwise insert it as the first child node in newSurface. if (this.previousSibling_ != null) { - Blockly.utils.insertAfter(blockCanvas, this.previousSibling_); + Blockly.utils.dom.insertAfter(blockCanvas, this.previousSibling_); } else { newSurface.insertBefore(blockCanvas, newSurface.firstChild); } // Reattach the bubble canvas after the blockCanvas. - Blockly.utils.insertAfter(bubbleCanvas, blockCanvas); + Blockly.utils.dom.insertAfter(bubbleCanvas, blockCanvas); // Hide the drag surface. this.SVG_.style.display = 'none'; if (this.SVG_.childNodes.length) { diff --git a/core/workspace_svg.js b/core/workspace_svg.js index b92337759ce..edb7ca61cc5 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -42,6 +42,7 @@ goog.require('Blockly.Touch'); goog.require('Blockly.TouchGesture'); goog.require('Blockly.Trashcan'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.VariablesDynamic'); goog.require('Blockly.Workspace'); goog.require('Blockly.WorkspaceAudio'); @@ -435,8 +436,8 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { var x = 0; var y = 0; var scale = 1; - if (Blockly.utils.containsNode(this.getCanvas(), element) || - Blockly.utils.containsNode(this.getBubbleCanvas(), element)) { + if (Blockly.utils.dom.containsNode(this.getCanvas(), element) || + Blockly.utils.dom.containsNode(this.getBubbleCanvas(), element)) { // Before the SVG canvas, scale the coordinates. scale = this.scale; } @@ -569,7 +570,7 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { } Blockly.WorkspaceSvg.superClass_.dispose.call(this); if (this.svgGroup_) { - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgBlockCanvas_ = null; @@ -613,7 +614,7 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { // SVG is injected into (i.e. injectionDiv). var div = this.getParentSvg().parentNode; if (div) { - Blockly.utils.removeNode(div); + Blockly.utils.dom.removeNode(div); } } if (this.resizeHandlerWrapper_) { @@ -1758,10 +1759,10 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() { * @package */ Blockly.WorkspaceSvg.prototype.beginCanvasTransition = function() { - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!SVGElement} */ (this.svgBlockCanvas_), 'blocklyCanvasTransitioning'); - Blockly.utils.addClass( + Blockly.utils.dom.addClass( /** @type {!SVGElement} */ (this.svgBubbleCanvas_), 'blocklyCanvasTransitioning'); }; @@ -1771,10 +1772,10 @@ Blockly.WorkspaceSvg.prototype.beginCanvasTransition = function() { * @package */ Blockly.WorkspaceSvg.prototype.endCanvasTransition = function() { - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!SVGElement} */ (this.svgBlockCanvas_), 'blocklyCanvasTransitioning'); - Blockly.utils.removeClass( + Blockly.utils.dom.removeClass( /** @type {!SVGElement} */ (this.svgBubbleCanvas_), 'blocklyCanvasTransitioning'); }; diff --git a/core/xml.js b/core/xml.js index 812e46b1b82..a0fe66b739e 100644 --- a/core/xml.js +++ b/core/xml.js @@ -35,6 +35,7 @@ goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.FinishedLoading'); goog.require('Blockly.Events.VarCreate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.Xml.utils'); @@ -257,7 +258,7 @@ Blockly.Xml.cloneShadow_ = function(shadow) { if (textNode.nodeType == Node.TEXT_NODE && textNode.data.trim() == '' && node.firstChild != textNode) { // Prune whitespace after a tag. - Blockly.utils.removeNode(textNode); + Blockly.utils.dom.removeNode(textNode); } } if (node) { @@ -266,7 +267,7 @@ Blockly.Xml.cloneShadow_ = function(shadow) { if (textNode.nodeType == Node.TEXT_NODE && textNode.data.trim() == '') { // Prune whitespace before a tag. - Blockly.utils.removeNode(textNode); + Blockly.utils.dom.removeNode(textNode); } } } diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 7a4fccb94b2..c9a68e70280 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -28,6 +28,7 @@ goog.provide('Blockly.ZoomControls'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.dom'); /** @@ -128,7 +129,7 @@ Blockly.ZoomControls.prototype.init = function(verticalSpacing) { */ Blockly.ZoomControls.prototype.dispose = function() { if (this.svgGroup_) { - Blockly.utils.removeNode(this.svgGroup_); + Blockly.utils.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.workspace_ = null; diff --git a/dart_compressed.js b/dart_compressed.js index 7663ee9bb01..8dd5a2ba5c8 100644 --- a/dart_compressed.js +++ b/dart_compressed.js @@ -9,8 +9,8 @@ Blockly.Dart.init=function(a){Blockly.Dart.definitions_=Object.create(null);Bloc for(d=0;dc&&(a=a+" - "+-c,g=Blockly.Dart.ORDER_ADDITIVE); d&&(a=c?"-("+a+")":"-"+a,g=Blockly.Dart.ORDER_UNARY_PREFIX);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.Dart.colour={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.Dart.ORDER_ATOMIC]}; Blockly.Dart.colour_random=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return[Blockly.Dart.provideFunction_("colour_random",["String "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"() {"," String hex = '0123456789abcdef';"," var rnd = new Math.Random();"," return '#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'"," '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'"," '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}';","}"])+"()",Blockly.Dart.ORDER_UNARY_POSTFIX]}; diff --git a/generators/dart.js b/generators/dart.js index cc24151d8b6..77dd620dd25 100644 --- a/generators/dart.js +++ b/generators/dart.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Dart'); goog.require('Blockly.Generator'); +goog.require('Blockly.utils.string'); /** @@ -198,7 +199,7 @@ Blockly.Dart.scrub_ = function(block, code, opt_thisOnly) { if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); - comment = Blockly.utils.wrap(comment, Blockly.Dart.COMMENT_WRAP - 3); + comment = Blockly.utils.string.wrap(comment, Blockly.Dart.COMMENT_WRAP - 3); if (comment) { if (block.getProcedureDef) { // Use documentation comment for function comments. diff --git a/generators/javascript.js b/generators/javascript.js index ce38b726a7d..9d20ca97458 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -27,6 +27,7 @@ goog.provide('Blockly.JavaScript'); goog.require('Blockly.Generator'); +goog.require('Blockly.utils.string'); /** @@ -239,7 +240,8 @@ Blockly.JavaScript.scrub_ = function(block, code, opt_thisOnly) { if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); - comment = Blockly.utils.wrap(comment, Blockly.JavaScript.COMMENT_WRAP - 3); + comment = Blockly.utils.string.wrap(comment, + Blockly.JavaScript.COMMENT_WRAP - 3); if (comment) { if (block.getProcedureDef) { // Use a comment block for function comments. diff --git a/generators/lua.js b/generators/lua.js index 0e05c24dc6c..70a83b2ede2 100644 --- a/generators/lua.js +++ b/generators/lua.js @@ -28,6 +28,7 @@ goog.provide('Blockly.Lua'); goog.require('Blockly.Generator'); +goog.require('Blockly.utils.string'); /** @@ -172,7 +173,7 @@ Blockly.Lua.scrub_ = function(block, code, opt_thisOnly) { if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); - comment = Blockly.utils.wrap(comment, Blockly.Lua.COMMENT_WRAP - 3); + comment = Blockly.utils.string.wrap(comment, Blockly.Lua.COMMENT_WRAP - 3); if (comment) { commentCode += Blockly.Lua.prefixLines(comment, '-- ') + '\n'; } diff --git a/generators/php.js b/generators/php.js index cd717abe3e9..0c926e90bb2 100644 --- a/generators/php.js +++ b/generators/php.js @@ -27,6 +27,7 @@ goog.provide('Blockly.PHP'); goog.require('Blockly.Generator'); +goog.require('Blockly.utils.string'); /** @@ -228,7 +229,7 @@ Blockly.PHP.scrub_ = function(block, code, opt_thisOnly) { if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); - comment = Blockly.utils.wrap(comment, Blockly.PHP.COMMENT_WRAP - 3); + comment = Blockly.utils.string.wrap(comment, Blockly.PHP.COMMENT_WRAP - 3); if (comment) { commentCode += Blockly.PHP.prefixLines(comment, '// ') + '\n'; } diff --git a/generators/python.js b/generators/python.js index c3d45b8c1fc..9a328d98a8b 100644 --- a/generators/python.js +++ b/generators/python.js @@ -27,6 +27,7 @@ goog.provide('Blockly.Python'); goog.require('Blockly.Generator'); +goog.require('Blockly.utils.string'); /** @@ -254,7 +255,8 @@ Blockly.Python.scrub_ = function(block, code, opt_thisOnly) { if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); - comment = Blockly.utils.wrap(comment, Blockly.Python.COMMENT_WRAP - 3); + comment = Blockly.utils.string.wrap(comment, + Blockly.Python.COMMENT_WRAP - 3); if (comment) { if (block.getProcedureDef) { // Use a comment block for function comments. diff --git a/javascript_compressed.js b/javascript_compressed.js index 3f035b567ae..4160479be05 100644 --- a/javascript_compressed.js +++ b/javascript_compressed.js @@ -11,7 +11,7 @@ Blockly.JavaScript.ORDER_ADDITION],[Blockly.JavaScript.ORDER_LOGICAL_AND,Blockly Blockly.JavaScript.init=function(a){Blockly.JavaScript.definitions_=Object.create(null);Blockly.JavaScript.functionNames_=Object.create(null);Blockly.JavaScript.variableDB_?Blockly.JavaScript.variableDB_.reset():Blockly.JavaScript.variableDB_=new Blockly.Names(Blockly.JavaScript.RESERVED_WORDS_);Blockly.JavaScript.variableDB_.setVariableMap(a.getVariableMap());for(var b=[],c=Blockly.Variables.allDeveloperVariables(a),d=0;dc?Blockly.JavaScript.valueToCode(a,b,Blockly.JavaScript.ORDER_SUBTRACTION)||f:d?Blockly.JavaScript.valueToCode(a,b,Blockly.JavaScript.ORDER_UNARY_NEGATION)||f:Blockly.JavaScript.valueToCode(a,b,e)||f;if(Blockly.isNumber(a))a=parseFloat(a)+c, d&&(a=-a);else{if(0c&&(a=a+" - "+-c,g=Blockly.JavaScript.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,g=Blockly.JavaScript.ORDER_UNARY_NEGATION);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.JavaScript.colour={};Blockly.JavaScript.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.colour_random=function(a){return[Blockly.JavaScript.provideFunction_("colourRandom",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"() {"," var num = Math.floor(Math.random() * Math.pow(2, 24));"," return '#' + ('00000' + num.toString(16)).substr(-6);","}"])+"()",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; diff --git a/lua_compressed.js b/lua_compressed.js index a82523f7701..dad652a7f5e 100644 --- a/lua_compressed.js +++ b/lua_compressed.js @@ -6,7 +6,7 @@ Blockly.Lua=new Blockly.Generator("Lua");Blockly.Lua.addReservedWords("_,__inext Blockly.Lua.ORDER_ATOMIC=0;Blockly.Lua.ORDER_HIGH=1;Blockly.Lua.ORDER_EXPONENTIATION=2;Blockly.Lua.ORDER_UNARY=3;Blockly.Lua.ORDER_MULTIPLICATIVE=4;Blockly.Lua.ORDER_ADDITIVE=5;Blockly.Lua.ORDER_CONCATENATION=6;Blockly.Lua.ORDER_RELATIONAL=7;Blockly.Lua.ORDER_AND=8;Blockly.Lua.ORDER_OR=9;Blockly.Lua.ORDER_NONE=99; Blockly.Lua.init=function(a){Blockly.Lua.definitions_=Object.create(null);Blockly.Lua.functionNames_=Object.create(null);Blockly.Lua.variableDB_?Blockly.Lua.variableDB_.reset():Blockly.Lua.variableDB_=new Blockly.Names(Blockly.Lua.RESERVED_WORDS_);Blockly.Lua.variableDB_.setVariableMap(a.getVariableMap())}; Blockly.Lua.finish=function(a){var b=[],c;for(c in Blockly.Lua.definitions_)b.push(Blockly.Lua.definitions_[c]);delete Blockly.Lua.definitions_;delete Blockly.Lua.functionNames_;Blockly.Lua.variableDB_.reset();return b.join("\n\n")+"\n\n\n"+a};Blockly.Lua.scrubNakedValue=function(a){return"local _ = "+a+"\n"};Blockly.Lua.quote_=function(a){a=a.replace(/\\/g,"\\\\").replace(/\n/g,"\\\n").replace(/'/g,"\\'");return"'"+a+"'"}; -Blockly.Lua.scrub_=function(a,b,c){var d="";if(!a.outputConnection||!a.outputConnection.targetConnection){var e=a.getCommentText();(e=Blockly.utils.wrap(e,Blockly.Lua.COMMENT_WRAP-3))&&(d+=Blockly.Lua.prefixLines(e,"-- ")+"\n");for(var f=0;fc?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_SUBTRACTION)||f:d?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_UNARY_NEGATION)||f:Blockly.PHP.valueToCode(a,b,e)||f;if(Blockly.isNumber(a))a=parseFloat(a)+c,d&&(a=-a);else{if(0c&& (a=a+" - "+-c,g=Blockly.PHP.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,g=Blockly.PHP.ORDER_UNARY_NEGATION);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.PHP.colour={};Blockly.PHP.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.PHP.ORDER_ATOMIC]};Blockly.PHP.colour_random=function(a){return[Blockly.PHP.provideFunction_("colour_random",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"() {"," return '#' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), 6, '0', STR_PAD_LEFT);","}"])+"()",Blockly.PHP.ORDER_FUNCTION_CALL]}; diff --git a/python_compressed.js b/python_compressed.js index 02168a46121..e697c40a230 100644 --- a/python_compressed.js +++ b/python_compressed.js @@ -10,7 +10,7 @@ Blockly.Python.init=function(a){Blockly.Python.PASS=this.INDENT+"pass\n";Blockly " = None");a=Blockly.Variables.allUsedVarModels(a);for(d=0;dc?"int("+a+" - "+-c+")":"int("+a+")",d&&(a="-"+a));return a};Blockly.Python.colour={};Blockly.Python.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.colour_random=function(a){Blockly.Python.definitions_.import_random="import random";return["'#%06x' % random.randint(0, 2**24 - 1)",Blockly.Python.ORDER_FUNCTION_CALL]}; Blockly.Python.colour_rgb=function(a){var b=Blockly.Python.provideFunction_("colour_rgb",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(r, g, b):"," r = round(min(100, max(0, r)) * 2.55)"," g = round(min(100, max(0, g)) * 2.55)"," b = round(min(100, max(0, b)) * 2.55)"," return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"RED",Blockly.Python.ORDER_NONE)||0,d=Blockly.Python.valueToCode(a,"GREEN",Blockly.Python.ORDER_NONE)||0;a=Blockly.Python.valueToCode(a,"BLUE",Blockly.Python.ORDER_NONE)|| 0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]}; diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index ccc72d3a48c..aa61c8f3f9a 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -28,6 +28,9 @@ + + + diff --git a/tests/jsunit/utils_dom_test.js b/tests/jsunit/utils_dom_test.js new file mode 100644 index 00000000000..7f4264a7927 --- /dev/null +++ b/tests/jsunit/utils_dom_test.js @@ -0,0 +1,61 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +function test_addClass() { + var p = document.createElement('p'); + Blockly.utils.dom.addClass(p, 'one'); + assertEquals('Adding "one"', 'one', p.className); + Blockly.utils.dom.addClass(p, 'one'); + assertEquals('Adding duplicate "one"', 'one', p.className); + Blockly.utils.dom.addClass(p, 'two'); + assertEquals('Adding "two"', 'one two', p.className); + Blockly.utils.dom.addClass(p, 'two'); + assertEquals('Adding duplicate "two"', 'one two', p.className); + Blockly.utils.dom.addClass(p, 'three'); + assertEquals('Adding "three"', 'one two three', p.className); +} + +function test_hasClass() { + var p = document.createElement('p'); + p.className = ' one three two three '; + assertTrue('Has "one"', Blockly.utils.dom.hasClass(p, 'one')); + assertTrue('Has "two"', Blockly.utils.dom.hasClass(p, 'two')); + assertTrue('Has "three"', Blockly.utils.dom.hasClass(p, 'three')); + assertFalse('Has no "four"', Blockly.utils.dom.hasClass(p, 'four')); + assertFalse('Has no "t"', Blockly.utils.dom.hasClass(p, 't')); + } + +function test_removeClass() { + var p = document.createElement('p'); + p.className = ' one three two three '; + Blockly.utils.dom.removeClass(p, 'two'); + assertEquals('Removing "two"', 'one three three', p.className); + Blockly.utils.dom.removeClass(p, 'four'); + assertEquals('Removing "four"', 'one three three', p.className); + Blockly.utils.dom.removeClass(p, 'three'); + assertEquals('Removing "three"', 'one', p.className); + Blockly.utils.dom.removeClass(p, 'ne'); + assertEquals('Removing "ne"', 'one', p.className); + Blockly.utils.dom.removeClass(p, 'one'); + assertEquals('Removing "one"', '', p.className); + Blockly.utils.dom.removeClass(p, 'zero'); + assertEquals('Removing "zero"', '', p.className); +} diff --git a/tests/jsunit/utils_math_test.js b/tests/jsunit/utils_math_test.js new file mode 100644 index 00000000000..daaf928f908 --- /dev/null +++ b/tests/jsunit/utils_math_test.js @@ -0,0 +1,42 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +function test_toRadians() { + var quarter = Math.PI / 2; + assertEquals('-90', -quarter, Blockly.utils.math.toRadians(-90)); + assertEquals('0', 0, Blockly.utils.math.toRadians(0)); + assertEquals('90', quarter, Blockly.utils.math.toRadians(90)); + assertEquals('180', 2 * quarter, Blockly.utils.math.toRadians(180)); + assertEquals('270', 3 * quarter, Blockly.utils.math.toRadians(270)); + assertEquals('360', 4 * quarter, Blockly.utils.math.toRadians(360)); + assertEquals('450', 5 * quarter, Blockly.utils.math.toRadians(360 + 90)); +} + +function test_toDegrees() { + var quarter = Math.PI / 2; + assertEquals('-90', -90, Blockly.utils.math.toDegrees(-quarter)); + assertEquals('0', 0, Blockly.utils.math.toDegrees(0)); + assertEquals('90', 90, Blockly.utils.math.toDegrees(quarter)); + assertEquals('180', 180, Blockly.utils.math.toDegrees(2 * quarter)); + assertEquals('270', 270, Blockly.utils.math.toDegrees(3 * quarter)); + assertEquals('360', 360, Blockly.utils.math.toDegrees(4 * quarter)); + assertEquals('450', 360 + 90, Blockly.utils.math.toDegrees(5 * quarter)); +} diff --git a/tests/jsunit/utils_string_test.js b/tests/jsunit/utils_string_test.js new file mode 100644 index 00000000000..d37e85ea2a3 --- /dev/null +++ b/tests/jsunit/utils_string_test.js @@ -0,0 +1,81 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +function test_startsWith() { + assertEquals('Does not start with', false, Blockly.utils.string.startsWith('123', '2')); + assertEquals('Start with', true, Blockly.utils.string.startsWith('123', '12')); + assertEquals('Start with empty string 1', true, Blockly.utils.string.startsWith('123', '')); + assertEquals('Start with empty string 2', true, Blockly.utils.string.startsWith('', '')); +} + +function test_commonWordPrefix() { + var len = Blockly.utils.string.commonWordPrefix('one,two,three,four,five'.split(',')); + assertEquals('No prefix', 0, len); + len = Blockly.utils.string.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(',')); + assertEquals('No word prefix', 0, len); + len = Blockly.utils.string.commonWordPrefix('abc de,abc de,abc de,abc de'.split(',')); + assertEquals('Full equality', 6, len); + len = Blockly.utils.string.commonWordPrefix('abc deX,abc deY'.split(',')); + assertEquals('One word prefix', 4, len); + len = Blockly.utils.string.commonWordPrefix('abc de,abc deY'.split(',')); + assertEquals('Overflow no', 4, len); + len = Blockly.utils.string.commonWordPrefix('abc de,abc de Y'.split(',')); + assertEquals('Overflow yes', 6, len); + len = Blockly.utils.string.commonWordPrefix(['Hello World']); + assertEquals('List of one', 11, len); + len = Blockly.utils.string.commonWordPrefix([]); + assertEquals('Empty list', 0, len); + len = Blockly.utils.string.commonWordPrefix('turn left,turn right'.split(',')); + assertEquals('No prefix due to &nbsp;', 0, len); + len = Blockly.utils.string.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(',')); + assertEquals('No prefix due to \\u00A0', 0, len); +} + +function test_commonWordSuffix() { + var len = Blockly.utils.string.commonWordSuffix('one,two,three,four,five'.split(',')); + assertEquals('No prefix', 0, len); + len = Blockly.utils.string.commonWordSuffix('oneX,twoX,threeX,fourX,fiveX'.split(',')); + assertEquals('No word prefix', 0, len); + len = Blockly.utils.string.commonWordSuffix('abc de,abc de,abc de,abc de'.split(',')); + assertEquals('Full equality', 6, len); + len = Blockly.utils.string.commonWordSuffix('Xabc de,Yabc de'.split(',')); + assertEquals('One word prefix', 3, len); + len = Blockly.utils.string.commonWordSuffix('abc de,Yabc de'.split(',')); + assertEquals('Overflow no', 3, len); + len = Blockly.utils.string.commonWordSuffix('abc de,Y abc de'.split(',')); + assertEquals('Overflow yes', 6, len); + len = Blockly.utils.string.commonWordSuffix(['Hello World']); + assertEquals('List of one', 11, len); + len = Blockly.utils.string.commonWordSuffix([]); + assertEquals('Empty list', 0, len); +} + +function test_shortestStringLength() { + var len = Blockly.utils.string.shortestStringLength('one,two,three,four,five'.split(',')); + assertEquals('Length of "one"', 3, len); + len = Blockly.utils.string.shortestStringLength('one,two,three,four,five,'.split(',')); + assertEquals('Length of ""', 0, len); + len = Blockly.utils.string.shortestStringLength(['Hello World']); + assertEquals('List of one', 11, len); + len = Blockly.utils.string.shortestStringLength([]); + assertEquals('Empty list', 0, len); +} + diff --git a/tests/jsunit/utils_test.js b/tests/jsunit/utils_test.js index 305dee7d512..1fd66be99f9 100644 --- a/tests/jsunit/utils_test.js +++ b/tests/jsunit/utils_test.js @@ -28,100 +28,6 @@ function test_genUid() { } } -function test_addClass() { - var p = document.createElement('p'); - Blockly.utils.addClass(p, 'one'); - assertEquals('Adding "one"', 'one', p.className); - Blockly.utils.addClass(p, 'one'); - assertEquals('Adding duplicate "one"', 'one', p.className); - Blockly.utils.addClass(p, 'two'); - assertEquals('Adding "two"', 'one two', p.className); - Blockly.utils.addClass(p, 'two'); - assertEquals('Adding duplicate "two"', 'one two', p.className); - Blockly.utils.addClass(p, 'three'); - assertEquals('Adding "three"', 'one two three', p.className); -} - -function test_hasClass() { - var p = document.createElement('p'); - p.className = ' one three two three '; - assertTrue('Has "one"', Blockly.utils.hasClass(p, 'one')); - assertTrue('Has "two"', Blockly.utils.hasClass(p, 'two')); - assertTrue('Has "three"', Blockly.utils.hasClass(p, 'three')); - assertFalse('Has no "four"', Blockly.utils.hasClass(p, 'four')); - assertFalse('Has no "t"', Blockly.utils.hasClass(p, 't')); - } - -function test_removeClass() { - var p = document.createElement('p'); - p.className = ' one three two three '; - Blockly.utils.removeClass(p, 'two'); - assertEquals('Removing "two"', 'one three three', p.className); - Blockly.utils.removeClass(p, 'four'); - assertEquals('Removing "four"', 'one three three', p.className); - Blockly.utils.removeClass(p, 'three'); - assertEquals('Removing "three"', 'one', p.className); - Blockly.utils.removeClass(p, 'ne'); - assertEquals('Removing "ne"', 'one', p.className); - Blockly.utils.removeClass(p, 'one'); - assertEquals('Removing "one"', '', p.className); - Blockly.utils.removeClass(p, 'zero'); - assertEquals('Removing "zero"', '', p.className); -} - -function test_shortestStringLength() { - var len = Blockly.utils.shortestStringLength('one,two,three,four,five'.split(',')); - assertEquals('Length of "one"', 3, len); - len = Blockly.utils.shortestStringLength('one,two,three,four,five,'.split(',')); - assertEquals('Length of ""', 0, len); - len = Blockly.utils.shortestStringLength(['Hello World']); - assertEquals('List of one', 11, len); - len = Blockly.utils.shortestStringLength([]); - assertEquals('Empty list', 0, len); -} - -function test_commonWordPrefix() { - var len = Blockly.utils.commonWordPrefix('one,two,three,four,five'.split(',')); - assertEquals('No prefix', 0, len); - len = Blockly.utils.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(',')); - assertEquals('No word prefix', 0, len); - len = Blockly.utils.commonWordPrefix('abc de,abc de,abc de,abc de'.split(',')); - assertEquals('Full equality', 6, len); - len = Blockly.utils.commonWordPrefix('abc deX,abc deY'.split(',')); - assertEquals('One word prefix', 4, len); - len = Blockly.utils.commonWordPrefix('abc de,abc deY'.split(',')); - assertEquals('Overflow no', 4, len); - len = Blockly.utils.commonWordPrefix('abc de,abc de Y'.split(',')); - assertEquals('Overflow yes', 6, len); - len = Blockly.utils.commonWordPrefix(['Hello World']); - assertEquals('List of one', 11, len); - len = Blockly.utils.commonWordPrefix([]); - assertEquals('Empty list', 0, len); - len = Blockly.utils.commonWordPrefix('turn left,turn right'.split(',')); - assertEquals('No prefix due to &nbsp;', 0, len); - len = Blockly.utils.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(',')); - assertEquals('No prefix due to \\u00A0', 0, len); -} - -function test_commonWordSuffix() { - var len = Blockly.utils.commonWordSuffix('one,two,three,four,five'.split(',')); - assertEquals('No prefix', 0, len); - len = Blockly.utils.commonWordSuffix('oneX,twoX,threeX,fourX,fiveX'.split(',')); - assertEquals('No word prefix', 0, len); - len = Blockly.utils.commonWordSuffix('abc de,abc de,abc de,abc de'.split(',')); - assertEquals('Full equality', 6, len); - len = Blockly.utils.commonWordSuffix('Xabc de,Yabc de'.split(',')); - assertEquals('One word prefix', 3, len); - len = Blockly.utils.commonWordSuffix('abc de,Yabc de'.split(',')); - assertEquals('Overflow no', 3, len); - len = Blockly.utils.commonWordSuffix('abc de,Y abc de'.split(',')); - assertEquals('Overflow yes', 6, len); - len = Blockly.utils.commonWordSuffix(['Hello World']); - assertEquals('List of one', 11, len); - len = Blockly.utils.commonWordSuffix([]); - assertEquals('Empty list', 0, len); -} - function test_tokenizeInterpolation() { var tokens = Blockly.utils.tokenizeInterpolation(''); assertArrayEquals('Null interpolation', [], tokens); @@ -233,13 +139,6 @@ function test_replaceMessageReferences() { assertEquals('Message ref and subref dereferenced.', 'before test subref string after', resultString); } -function test_startsWith() { - assertEquals('Does not start with', false, Blockly.utils.startsWith('123', '2')); - assertEquals('Start with', true, Blockly.utils.startsWith('123', '12')); - assertEquals('Start with empty string 1', true, Blockly.utils.startsWith('123', '')); - assertEquals('Start with empty string 2', true, Blockly.utils.startsWith('', '')); -} - function test_arrayRemove() { var arr = [1, 2, 3, 2]; assertEquals('Remove Not found', false, Blockly.utils.arrayRemove(arr, 0)); @@ -250,28 +149,6 @@ function test_arrayRemove() { assertEquals('Remove item again result', '1,3', arr.join(',')); } -function test_toRadians() { - var quarter = Math.PI / 2; - assertEquals('-90', -quarter, Blockly.utils.toRadians(-90)); - assertEquals('0', 0, Blockly.utils.toRadians(0)); - assertEquals('90', quarter, Blockly.utils.toRadians(90)); - assertEquals('180', 2 * quarter, Blockly.utils.toRadians(180)); - assertEquals('270', 3 * quarter, Blockly.utils.toRadians(270)); - assertEquals('360', 4 * quarter, Blockly.utils.toRadians(360)); - assertEquals('450', 5 * quarter, Blockly.utils.toRadians(360 + 90)); -} - -function test_toDegrees() { - var quarter = Math.PI / 2; - assertEquals('-90', -90, Blockly.utils.toDegrees(-quarter)); - assertEquals('0', 0, Blockly.utils.toDegrees(0)); - assertEquals('90', 90, Blockly.utils.toDegrees(quarter)); - assertEquals('180', 180, Blockly.utils.toDegrees(2 * quarter)); - assertEquals('270', 270, Blockly.utils.toDegrees(3 * quarter)); - assertEquals('360', 360, Blockly.utils.toDegrees(4 * quarter)); - assertEquals('450', 360 + 90, Blockly.utils.toDegrees(5 * quarter)); -} - function test_XY_REGEX() { var regex = Blockly.utils.getRelativeXY.XY_REGEX_; var m; From 566f182fa8d0d585a17d46c678a33f6199afd8b1 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 17:43:41 -0700 Subject: [PATCH 112/233] Move Blockly.userAgent to Blockly.utils.userAgent --- blockly_accessible_compressed.js | 50 ++++++++++++++++-------------- blockly_accessible_uncompressed.js | 28 ++++++++--------- blockly_compressed.js | 50 ++++++++++++++++-------------- blockly_uncompressed.js | 28 ++++++++--------- core/bubble.js | 4 +-- core/comment.js | 4 +-- core/contextmenu.js | 6 ++-- core/field.js | 4 +-- core/field_angle.js | 8 ++--- core/field_dropdown.js | 4 +-- core/field_textinput.js | 12 +++---- core/flyout_vertical.js | 4 +-- core/grid.js | 4 +-- core/inject.js | 4 +-- core/touch.js | 2 +- core/utils.js | 6 ++-- core/{ => utils}/useragent.js | 47 +++++++++++++++------------- core/workspace_audio.js | 6 ++-- 18 files changed, 140 insertions(+), 131 deletions(-) rename core/{ => utils}/useragent.js (56%) diff --git a/blockly_accessible_compressed.js b/blockly_accessible_compressed.js index 82578834fc8..07d559357cb 100644 --- a/blockly_accessible_compressed.js +++ b/blockly_accessible_compressed.js @@ -876,9 +876,10 @@ goog.ui.tree.TreeControl.prototype.handleKeyEvent=function(a){var b;(b=this.type goog.ui.tree.TreeControl.prototype.createNode=function(a){return new goog.ui.tree.TreeNode(a||goog.html.SafeHtml.EMPTY,this.getConfig(),this.getDomHelper())};goog.ui.tree.TreeControl.prototype.setNode=function(a){this.typeAhead_.setNodeInMap(a)};goog.ui.tree.TreeControl.prototype.removeNode=function(a){this.typeAhead_.removeNodeFromMap(a)};goog.ui.tree.TreeControl.prototype.clearTypeAhead=function(){this.typeAhead_.clear()};goog.ui.tree.TreeControl.defaultConfig=goog.ui.tree.BaseNode.defaultConfig; var Blockly={};Blockly.Blocks=Object(null); Blockly.utils={};Blockly.utils.Coordinate=function(a,b){this.x=a;this.y=b};Blockly.utils.Coordinate.equals=function(a,b){return a==b?!0:a&&b?a.x==b.x&&a.y==b.y:!1};Blockly.utils.Coordinate.distance=function(a,b){var c=a.x-b.x;a=a.y-b.y;return Math.sqrt(c*c+a*a)};Blockly.utils.Coordinate.magnitude=function(a){return Math.sqrt(a.x*a.x+a.y*a.y)};Blockly.utils.Coordinate.difference=function(a,b){return new Blockly.utils.Coordinate(a.x-b.x,a.y-b.y)}; -Blockly.utils.Coordinate.sum=function(a,b){return new Blockly.utils.Coordinate(a.x+b.x,a.y+b.y)};Blockly.utils.Coordinate.prototype.scale=function(a){this.x*=a;this.y*=a;return this};Blockly.utils.Coordinate.prototype.translate=function(a,b){this.x+=a;this.y+=b;return this};Blockly.Msg={};goog.getMsgOrig=goog.getMsg;goog.getMsg=function(a,b){var c=goog.getMsg.blocklyMsgMap[a];c&&(a=Blockly.Msg[c]);return goog.getMsgOrig(a,b)};goog.getMsg.blocklyMsgMap={Today:"TODAY"};Blockly.userAgent={}; -(function(a){function b(a){return-1!=c.indexOf(a.toUpperCase())}Blockly.userAgent.raw=a;var c=Blockly.userAgent.raw.toUpperCase();Blockly.userAgent.IE=b("Trident")||b("MSIE");Blockly.userAgent.EDGE=b("Edge");Blockly.userAgent.JAVA_FX=b("JavaFX");Blockly.userAgent.WEBKIT=b("WebKit")&&!Blockly.userAgent.EDGE;Blockly.userAgent.GECKO=b("Gecko")&&!Blockly.userAgent.WEBKIT&&!Blockly.userAgent.IE&&!Blockly.userAgent.EDGE;Blockly.userAgent.ANDROID=b("Android");Blockly.userAgent.IPAD=b("iPad");Blockly.userAgent.IPOD= -b("iPod");Blockly.userAgent.IPHONE=b("iPhone")&&!Blockly.userAgent.IPAD&&!Blockly.userAgent.IPOD;Blockly.userAgent.MAC=b("Macintosh");Blockly.userAgent.TABLET=Blockly.userAgent.IPAD||Blockly.userAgent.ANDROID&&!b("Mobile")||b("Silk");Blockly.userAgent.MOBILE=!Blockly.userAgent.TABLET&&(Blockly.userAgent.IPOD||Blockly.userAgent.IPHONE||Blockly.userAgent.ANDROID||b("IEMobile"))})(this.navigator&&this.navigator.userAgent||"");Blockly.utils.string={};Blockly.utils.string.startsWith=function(a,b){return 0==a.lastIndexOf(b,0)};Blockly.utils.string.shortestStringLength=function(a){return a.length?a.reduce(function(a,c){return a.lengthb&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;a=[];var h=c.length/e,k=1;for(d=0;df);return g}; @@ -887,7 +888,7 @@ Blockly.utils.string.wrapMutate_=function(a,b,c){for(var d=Blockly.utils.string. Blockly.utils.noEvent=function(a){a.preventDefault();a.stopPropagation()};Blockly.utils.isTargetInput=function(a){return"textarea"==a.target.type||"text"==a.target.type||"number"==a.target.type||"email"==a.target.type||"password"==a.target.type||"search"==a.target.type||"tel"==a.target.type||"url"==a.target.type||a.target.isContentEditable}; Blockly.utils.getRelativeXY=function(a){var b=new Blockly.utils.Coordinate(0,0),c=a.getAttribute("x");c&&(b.x=parseInt(c,10));if(c=a.getAttribute("y"))b.y=parseInt(c,10);if(c=(c=a.getAttribute("transform"))&&c.match(Blockly.utils.getRelativeXY.XY_REGEX_))b.x+=parseFloat(c[1]),c[3]&&(b.y+=parseFloat(c[3]));(a=a.getAttribute("style"))&&-1";c=Blockly.Xml.textToDom(c).firstChild;b.push(c)}if(Blockly.Blocks.variables_get_dynamic){a.sort(Blockly.VariableModel.compareByName);for(var d=0;c=a[d];d++)c=''+Blockly.Variables.generateVariableFieldXmlString(c)+ "",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null}; -Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new Blockly.utils.global.Audio}catch(h){return}for(var d,e=0;ethis.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())}; @@ -1475,10 +1477,10 @@ Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBo Blockly.ContextMenu.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);var b=a.getElement();Blockly.utils.dom.addClass(b,"blocklyContextMenu");Blockly.bindEventWithChecks_(b,"contextmenu",null,Blockly.utils.noEvent);a.setAllowAutoFocus(!0)};Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_&&Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_)}; Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(c));c.select()}}; Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; -Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; +Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.utils.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; -Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new Blockly.utils.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=Blockly.utils.Coordinate.difference(e,f); -e.scale(1/a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= +Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.utils.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new Blockly.utils.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=Blockly.utils.Coordinate.difference(e, +f);e.scale(1/a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= Blockly.utils.is3dSupported()&&!!a.blockDragSurface_;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,a,b,c);this.svgGroup_.dataset&&(this.svgGroup_.dataset.id=this.id)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.prototype.warningTextDb_=null;Blockly.BlockSvg.INLINE=-1;Blockly.BlockSvg.COLLAPSED_WARNING_ID="TEMP_COLLAPSED_WARNING_"; Blockly.BlockSvg.prototype.initSvg=function(){if(!this.workspace.rendered)throw TypeError("Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;ac;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+ -Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove", -this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; +Blockly.FieldAngle.prototype.showEditor_=function(){Blockly.FieldAngle.superClass_.showEditor_.call(this,Blockly.utils.userAgent.MOBILE||Blockly.utils.userAgent.ANDROID||Blockly.utils.userAgent.IPAD);var a=Blockly.DropDownDiv.getContentDiv();a=Blockly.utils.createSvgElement("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:html":"http://www.w3.org/1999/xhtml","xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1",height:2*Blockly.FieldAngle.HALF+"px",width:2*Blockly.FieldAngle.HALF+"px"},a);var b= +Blockly.utils.createSvgElement("circle",{cx:Blockly.FieldAngle.HALF,cy:Blockly.FieldAngle.HALF,r:Blockly.FieldAngle.RADIUS,"class":"blocklyAngleCircle"},a);this.gauge_=Blockly.utils.createSvgElement("path",{"class":"blocklyAngleGauge"},a);this.line_=Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF,y1:Blockly.FieldAngle.HALF,"class":"blocklyAngleLine"},a);for(var c=0;360>c;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF, +x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_= +Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.math.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& (a-=360),c=String(a),c!=this.text_&&(Blockly.FieldTextInput.htmlInput_.value=a,this.setValue(a),this.text_=c,this.forceRerender()))}; Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.math.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.math.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; @@ -1614,7 +1616,7 @@ Blockly.FieldColour.prototype.showEditor_=function(){var a=this.createWidget_(); Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;g-b||a<-180+b||a>180-b?!0:!1}; -Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new Blockly.utils.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new Blockly.utils.Rect(b, +Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new Blockly.utils.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.utils.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new Blockly.utils.Rect(b, -1E9,1E9+a,2E9)}; Blockly.VerticalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);a=Math.max(a,e)}for(c=0;d=this.buttons_[c];c++)a=Math.max(a,d.width);a+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=a){for(c=0;d=b[c];c++)this.RTL&&(e=d.getRelativeToSurfaceXY().x, d.moveBy(a/this.workspace_.scale-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH-e,0)),d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);if(this.RTL)for(c=0;d=this.buttons_[c];c++)b=d.getPosition().y,d.moveTo(a/this.workspace_.scale-d.width-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH,b);this.width_=a;this.position()}};Blockly.Toolbox=function(a){this.workspace_=a;this.RTL=a.options.RTL;this.horizontalLayout_=a.options.horizontalLayout;this.toolboxPosition=a.options.toolboxPosition;this.config_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"};this.treeSeparatorConfig_={cssTreeRow:"blocklyTreeSeparator"}; @@ -1796,7 +1798,7 @@ c.contentHeight)/d);if(b.contentTopb.viewBottom||b.c 0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; -Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, +Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.utils.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, "orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[];a=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,a,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,a,!0))}; Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; diff --git a/blockly_accessible_uncompressed.js b/blockly_accessible_uncompressed.js index 2c449364453..9c96d34697c 100644 --- a/blockly_accessible_uncompressed.js +++ b/blockly_accessible_uncompressed.js @@ -69,41 +69,41 @@ goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.Bl goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []); -goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.Workspace']); +goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.Workspace']); goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg']); -goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.userAgent', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']); goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []); -goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); +goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []); goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/dropdowndiv.js", ['Blockly.DropDownDiv'], ['Blockly.utils.math', 'goog.style']); goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], ['Blockly.utils']); goog.addDependency("../../../" + dir + "/core/events_abstract.js", ['Blockly.Events.Abstract'], ['Blockly.Events']); goog.addDependency("../../../" + dir + "/core/extensions.js", ['Blockly.Extensions'], ['Blockly.Mutator', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size', 'goog.style']); -goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.math']); +goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.math']); goog.addDependency("../../../" + dir + "/core/field_checkbox.js", ['Blockly.FieldCheckbox'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/field_colour.js", ['Blockly.FieldColour'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.utils.colour', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_date.js", ['Blockly.FieldDate'], ['Blockly.Events', 'Blockly.Field', 'Blockly.utils.dom', 'goog.date', 'goog.date.DateTime', 'goog.events', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_he', 'goog.style', 'goog.ui.DatePicker']); -goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.string', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); +goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.string', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.FieldTextInput']); -goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.utils.Coordinate', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom']); +goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.utils.Coordinate', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.utils', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils.Coordinate', 'Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.FlyoutDragger'], ['Blockly.WorkspaceDragger']); goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'Blockly.utils.Rect']); -goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.Rect']); goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block']); goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger']); -goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.userAgent', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.utils.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils.Coordinate', 'Blockly.utils', 'Blockly.utils.dom']); -goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.Tooltip', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); +goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.Tooltip', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../../" + dir + "/core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.BlockAnimations', 'Blockly.Events', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []); @@ -124,14 +124,14 @@ goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.Touch goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.Rect', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], ['goog.style']); -goog.addDependency("../../../" + dir + "/core/useragent.js", ['Blockly.userAgent'], []); -goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.utils.Coordinate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils.string', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.utils.Coordinate', 'Blockly.Msg', 'Blockly.utils.userAgent', 'Blockly.utils.string', 'goog.style']); goog.addDependency("../../../" + dir + "/core/utils/colour.js", ['Blockly.utils.colour'], ['Blockly.utils']); goog.addDependency("../../../" + dir + "/core/utils/coordinate.js", ['Blockly.utils.Coordinate'], []); goog.addDependency("../../../" + dir + "/core/utils/dom.js", ['Blockly.utils.dom'], []); goog.addDependency("../../../" + dir + "/core/utils/math.js", ['Blockly.utils.math'], []); goog.addDependency("../../../" + dir + "/core/utils/rect.js", ['Blockly.utils.Rect'], []); goog.addDependency("../../../" + dir + "/core/utils/string.js", ['Blockly.utils.string'], []); +goog.addDependency("../../../" + dir + "/core/utils/useragent.js", ['Blockly.utils.userAgent'], []); goog.addDependency("../../../" + dir + "/core/variable_events.js", ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/variable_map.js", ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/variable_model.js", ['Blockly.VariableModel'], ['Blockly.Events', 'Blockly.Events.VarCreate', 'Blockly.utils']); @@ -140,7 +140,7 @@ goog.addDependency("../../../" + dir + "/core/variables_dynamic.js", ['Blockly.V goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.style']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.Events', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']); -goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.userAgent']); +goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.utils.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.WorkspaceCommentSvg']); goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceComment']); @@ -1876,7 +1876,6 @@ goog.require('Blockly.Xml.utils'); goog.require('Blockly.ZoomControls'); goog.require('Blockly.constants'); goog.require('Blockly.inject'); -goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.Rect'); @@ -1885,6 +1884,7 @@ goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); goog.require('Blockly.utils.string'); goog.require('Blockly.utils.uiMenu'); +goog.require('Blockly.utils.userAgent'); goog.require('blocklyApp.AppComponent'); goog.require('blocklyApp.AudioService'); goog.require('blocklyApp.BlockConnectionService'); diff --git a/blockly_compressed.js b/blockly_compressed.js index e76583389a1..99f42d795f4 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -880,9 +880,10 @@ goog.ui.tree.TreeControl.prototype.handleKeyEvent=function(a){var b;(b=this.type goog.ui.tree.TreeControl.prototype.createNode=function(a){return new goog.ui.tree.TreeNode(a||goog.html.SafeHtml.EMPTY,this.getConfig(),this.getDomHelper())};goog.ui.tree.TreeControl.prototype.setNode=function(a){this.typeAhead_.setNodeInMap(a)};goog.ui.tree.TreeControl.prototype.removeNode=function(a){this.typeAhead_.removeNodeFromMap(a)};goog.ui.tree.TreeControl.prototype.clearTypeAhead=function(){this.typeAhead_.clear()};goog.ui.tree.TreeControl.defaultConfig=goog.ui.tree.BaseNode.defaultConfig; var Blockly={};Blockly.Blocks=Object(null); Blockly.utils={};Blockly.utils.Coordinate=function(a,b){this.x=a;this.y=b};Blockly.utils.Coordinate.equals=function(a,b){return a==b?!0:a&&b?a.x==b.x&&a.y==b.y:!1};Blockly.utils.Coordinate.distance=function(a,b){var c=a.x-b.x,d=a.y-b.y;return Math.sqrt(c*c+d*d)};Blockly.utils.Coordinate.magnitude=function(a){return Math.sqrt(a.x*a.x+a.y*a.y)};Blockly.utils.Coordinate.difference=function(a,b){return new Blockly.utils.Coordinate(a.x-b.x,a.y-b.y)}; -Blockly.utils.Coordinate.sum=function(a,b){return new Blockly.utils.Coordinate(a.x+b.x,a.y+b.y)};Blockly.utils.Coordinate.prototype.scale=function(a){this.x*=a;this.y*=a;return this};Blockly.utils.Coordinate.prototype.translate=function(a,b){this.x+=a;this.y+=b;return this};Blockly.Msg={};goog.getMsgOrig=goog.getMsg;goog.getMsg=function(a,b){var c=goog.getMsg.blocklyMsgMap[a];c&&(a=Blockly.Msg[c]);return goog.getMsgOrig(a,b)};goog.getMsg.blocklyMsgMap={Today:"TODAY"};Blockly.userAgent={}; -(function(a){function b(a){return-1!=c.indexOf(a.toUpperCase())}Blockly.userAgent.raw=a;var c=Blockly.userAgent.raw.toUpperCase();Blockly.userAgent.IE=b("Trident")||b("MSIE");Blockly.userAgent.EDGE=b("Edge");Blockly.userAgent.JAVA_FX=b("JavaFX");Blockly.userAgent.WEBKIT=b("WebKit")&&!Blockly.userAgent.EDGE;Blockly.userAgent.GECKO=b("Gecko")&&!Blockly.userAgent.WEBKIT&&!Blockly.userAgent.IE&&!Blockly.userAgent.EDGE;Blockly.userAgent.ANDROID=b("Android");Blockly.userAgent.IPAD=b("iPad");Blockly.userAgent.IPOD= -b("iPod");Blockly.userAgent.IPHONE=b("iPhone")&&!Blockly.userAgent.IPAD&&!Blockly.userAgent.IPOD;Blockly.userAgent.MAC=b("Macintosh");Blockly.userAgent.TABLET=Blockly.userAgent.IPAD||Blockly.userAgent.ANDROID&&!b("Mobile")||b("Silk");Blockly.userAgent.MOBILE=!Blockly.userAgent.TABLET&&(Blockly.userAgent.IPOD||Blockly.userAgent.IPHONE||Blockly.userAgent.ANDROID||b("IEMobile"))})(this.navigator&&this.navigator.userAgent||"");Blockly.utils.string={};Blockly.utils.string.startsWith=function(a,b){return 0==a.lastIndexOf(b,0)};Blockly.utils.string.shortestStringLength=function(a){return a.length?a.reduce(function(a,c){return a.lengthb&&(b=c[d].length);d=-Infinity;var e=1;do{var f=d;var g=a;var h=[],k=c.length/e,l=1;for(d=0;df);return g}; @@ -891,7 +892,7 @@ Blockly.utils.string.wrapMutate_=function(a,b,c){for(var d=Blockly.utils.string. Blockly.utils.noEvent=function(a){a.preventDefault();a.stopPropagation()};Blockly.utils.isTargetInput=function(a){return"textarea"==a.target.type||"text"==a.target.type||"number"==a.target.type||"email"==a.target.type||"password"==a.target.type||"search"==a.target.type||"tel"==a.target.type||"url"==a.target.type||a.target.isContentEditable}; Blockly.utils.getRelativeXY=function(a){var b=new Blockly.utils.Coordinate(0,0),c=a.getAttribute("x");c&&(b.x=parseInt(c,10));if(c=a.getAttribute("y"))b.y=parseInt(c,10);if(c=(c=a.getAttribute("transform"))&&c.match(Blockly.utils.getRelativeXY.XY_REGEX_))b.x+=parseFloat(c[1]),c[3]&&(b.y+=parseFloat(c[3]));(a=a.getAttribute("style"))&&-1";c=Blockly.Xml.textToDom(c).firstChild;b.push(c)}if(Blockly.Blocks.variables_get_dynamic){a.sort(Blockly.VariableModel.compareByName);for(var d=0;c=a[d];d++)c=''+Blockly.Variables.generateVariableFieldXmlString(c)+ "",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null}; -Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new Blockly.utils.global.Audio}catch(h){return}for(var d,e=0;ethis.maxDisplayLength&&(a=a.substring(0,this.maxDisplayLength-2)+"\u2026");a=a.replace(/\s/g,Blockly.Field.NBSP);this.sourceBlock_.RTL&&(a+="\u200f");return a};Blockly.Field.prototype.getText=function(){return this.text_};Blockly.Field.prototype.setText=function(a){null!==a&&(a=String(a),a!==this.text_&&(this.text_=a,this.forceRerender()))}; Blockly.Field.prototype.forceRerender=function(){this.isDirty_=!0;this.sourceBlock_&&this.sourceBlock_.rendered&&(this.sourceBlock_.render(),this.sourceBlock_.bumpNeighbours_())}; @@ -1484,10 +1486,10 @@ Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBo Blockly.ContextMenu.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);var b=a.getElement();Blockly.utils.dom.addClass(b,"blocklyContextMenu");Blockly.bindEventWithChecks_(b,"contextmenu",null,Blockly.utils.noEvent);a.setAllowAutoFocus(!0)};Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_&&Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_)}; Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(c));c.select()}}; Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; -Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; +Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!Blockly.utils.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; -Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new Blockly.utils.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=Blockly.utils.Coordinate.difference(e,f); -e.scale(1/a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= +Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!Blockly.utils.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new Blockly.utils.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=Blockly.utils.Coordinate.difference(e, +f);e.scale(1/a.scale);c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= Blockly.utils.is3dSupported()&&!!a.blockDragSurface_;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this,a,b,c);this.svgGroup_.dataset&&(this.svgGroup_.dataset.id=this.id)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.prototype.warningTextDb_=null;Blockly.BlockSvg.INLINE=-1;Blockly.BlockSvg.COLLAPSED_WARNING_ID="TEMP_COLLAPSED_WARNING_"; Blockly.BlockSvg.prototype.initSvg=function(){if(!this.workspace.rendered)throw TypeError("Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;ac;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+ -Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove", -this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; +Blockly.FieldAngle.prototype.showEditor_=function(){Blockly.FieldAngle.superClass_.showEditor_.call(this,Blockly.utils.userAgent.MOBILE||Blockly.utils.userAgent.ANDROID||Blockly.utils.userAgent.IPAD);var a=Blockly.DropDownDiv.getContentDiv();a=Blockly.utils.createSvgElement("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:html":"http://www.w3.org/1999/xhtml","xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1",height:2*Blockly.FieldAngle.HALF+"px",width:2*Blockly.FieldAngle.HALF+"px"},a);var b= +Blockly.utils.createSvgElement("circle",{cx:Blockly.FieldAngle.HALF,cy:Blockly.FieldAngle.HALF,r:Blockly.FieldAngle.RADIUS,"class":"blocklyAngleCircle"},a);this.gauge_=Blockly.utils.createSvgElement("path",{"class":"blocklyAngleGauge"},a);this.line_=Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF,y1:Blockly.FieldAngle.HALF,"class":"blocklyAngleLine"},a);for(var c=0;360>c;c+=15)Blockly.utils.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF, +x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS-(0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+","+Blockly.FieldAngle.HALF+","+Blockly.FieldAngle.HALF+")"},a);c=this.sourceBlock_.getColourBorder();c=null==c.colourBorder?c.colourLight:c.colourBorder;Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),c);Blockly.DropDownDiv.showPositionedByField(this);this.clickWrapper_=Blockly.bindEvent_(a,"click",this,this.hide_.bind(this));this.moveWrapper1_= +Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()};Blockly.FieldAngle.prototype.hide_=function(){Blockly.unbindEvent_(this.moveWrapper1_);Blockly.unbindEvent_(this.moveWrapper2_);Blockly.unbindEvent_(this.clickWrapper_);Blockly.DropDownDiv.hideIfOwner(this);Blockly.WidgetDiv.hide()}; Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;b=a.clientY-b.top-Blockly.FieldAngle.HALF;a=Math.atan(-b/c);isNaN(a)||(a=Blockly.utils.math.toDegrees(a),0>c?a+=180:0Blockly.FieldAngle.WRAP&& (a-=360),c=String(a),c!=this.text_&&(Blockly.FieldTextInput.htmlInput_.value=a,this.setValue(a),this.text_=c,this.forceRerender()))}; Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=Blockly.utils.math.toRadians(a%360);a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF];var c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=Blockly.utils.math.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS; @@ -1623,7 +1625,7 @@ Blockly.FieldColour.prototype.showEditor_=function(){var a=this.createWidget_(); Blockly.FieldColour.prototype.onClick_=function(a){(a=a.target)&&!a.label&&(a=a.parentNode);a=a&&a.label;Blockly.WidgetDiv.hide();this.sourceBlock_&&(a=this.callValidator(a));null!==a&&this.setValue(a)}; Blockly.FieldColour.prototype.createWidget_=function(){var a=this.columns_||Blockly.FieldColour.COLUMNS,b=this.colours_||Blockly.FieldColour.COLOURS,c=this.titles_||Blockly.FieldColour.TITLES,d=this.getValue(),e=document.createElement("table");e.className="blocklyColourTable";for(var f,g=0;g-b||a<-180+b||a>180-b?!0:!1}; -Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new Blockly.utils.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new Blockly.utils.Rect(b, +Blockly.VerticalFlyout.prototype.getClientRect=function(){if(!this.svgGroup_)return null;var a=this.svgGroup_.getBoundingClientRect(),b=a.left;a=a.width;if(this.toolboxPosition_==Blockly.TOOLBOX_AT_LEFT)return new Blockly.utils.Rect(b-1E9,-1E9,1E9+a,2E9);if(Blockly.utils.userAgent.GECKO&&this.targetWorkspace_&&this.targetWorkspace_.isMutator){var c=this.targetWorkspace_.svgGroup_.getBoundingClientRect().x;10>Math.abs(c-b)&&(b+=this.leftEdge_*this.targetWorkspace_.options.parentWorkspace.scale)}return new Blockly.utils.Rect(b, -1E9,1E9+a,2E9)}; Blockly.VerticalFlyout.prototype.reflowInternal_=function(){this.workspace_.scale=this.targetWorkspace_.scale;for(var a=0,b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getHeightWidth().width;d.outputConnection&&(e-=Blockly.BlockSvg.TAB_WIDTH);a=Math.max(a,e)}for(c=0;d=this.buttons_[c];c++)a=Math.max(a,d.width);a+=1.5*this.MARGIN+Blockly.BlockSvg.TAB_WIDTH;a*=this.workspace_.scale;a+=Blockly.Scrollbar.scrollbarThickness;if(this.width_!=a){for(c=0;d=b[c];c++)this.RTL&&(e=d.getRelativeToSurfaceXY().x, d.moveBy(a/this.workspace_.scale-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH-e,0)),d.flyoutRect_&&this.moveRectToBlock_(d.flyoutRect_,d);if(this.RTL)for(c=0;d=this.buttons_[c];c++)b=d.getPosition().y,d.moveTo(a/this.workspace_.scale-d.width-this.MARGIN-Blockly.BlockSvg.TAB_WIDTH,b);this.width_=a;this.position()}};Blockly.Toolbox=function(a){this.workspace_=a;this.RTL=a.options.RTL;this.horizontalLayout_=a.options.horizontalLayout;this.toolboxPosition=a.options.toolboxPosition;this.config_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"};this.treeSeparatorConfig_={cssTreeRow:"blocklyTreeSeparator"}; @@ -1800,7 +1802,7 @@ c.contentHeight)/d);if(b.contentTopb.viewBottom||b.c 0n&&f.moveBy(0,n);n=b.viewLeft-d.topLeft.x;0b&&f.moveBy(b,0)}a&&(a.group||console.log("WARNING: Moved object in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(c))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.DropDownDiv.createDom();Blockly.Tooltip.createDom();return e}; Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart())); c=Blockly.Scrollbar.scrollbarThickness;b.hasTrashcan&&(c=a.trashcan.init(c));b.zoomOptions&&b.zoomOptions.controls&&a.zoomControls_.init(c);b.moveOptions&&b.moveOptions.scrollbars?(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize()):a.setMetrics({x:.5,y:.5});b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; -Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, +Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"scroll",null,function(){for(var a=Blockly.Workspace.getAll(),b=0,c;c=a[b];b++)c.updateInverseScreenCTM&&c.updateInverseScreenCTM()}),Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),Blockly.utils.userAgent.IPAD&&Blockly.bindEventWithChecks_(window, "orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[],e=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,e,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,e,!0))}; Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.theme_=null;Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index a4ddf1e299c..a10eddd6a71 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -43,41 +43,41 @@ goog.addDependency("../../../" + dir + "/core/block_render_svg.js", ['Blockly.Bl goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.BlockAnimations', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg.render', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Procedures', 'Blockly.Toolbox', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], []); -goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.Workspace']); +goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.utils.Coordinate', 'Blockly.Touch', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.Workspace']); goog.addDependency("../../../" + dir + "/core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.WorkspaceCommentSvg']); -goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.userAgent', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/connection_db.js", ['Blockly.ConnectionDB'], ['Blockly.Connection']); goog.addDependency("../../../" + dir + "/core/constants.js", ['Blockly.constants'], []); -goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); +goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Msg', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.uiMenu', 'Blockly.Xml', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], []); goog.addDependency("../../../" + dir + "/core/dragged_connection_manager.js", ['Blockly.DraggedConnectionManager'], ['Blockly.BlockAnimations', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/dropdowndiv.js", ['Blockly.DropDownDiv'], ['Blockly.utils.math', 'goog.style']); goog.addDependency("../../../" + dir + "/core/events.js", ['Blockly.Events'], ['Blockly.utils']); goog.addDependency("../../../" + dir + "/core/events_abstract.js", ['Blockly.Events.Abstract'], ['Blockly.Events']); goog.addDependency("../../../" + dir + "/core/extensions.js", ['Blockly.Extensions'], ['Blockly.Mutator', 'Blockly.utils']); -goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size', 'goog.style']); -goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.math']); +goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.math']); goog.addDependency("../../../" + dir + "/core/field_checkbox.js", ['Blockly.FieldCheckbox'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/field_colour.js", ['Blockly.FieldColour'], ['Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.utils.colour', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_date.js", ['Blockly.FieldDate'], ['Blockly.Events', 'Blockly.Field', 'Blockly.utils.dom', 'goog.date', 'goog.date.DateTime', 'goog.events', 'goog.i18n.DateTimeSymbols', 'goog.i18n.DateTimeSymbols_he', 'goog.style', 'goog.ui.DatePicker']); -goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.string', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); +goog.addDependency("../../../" + dir + "/core/field_dropdown.js", ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.string', 'Blockly.utils.uiMenu', 'goog.events', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/field_image.js", ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label.js", ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.dom', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/field_label_serializable.js", ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/field_number.js", ['Blockly.FieldNumber'], ['Blockly.FieldTextInput']); -goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.utils.Coordinate', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom']); +goog.addDependency("../../../" + dir + "/core/field_textinput.js", ['Blockly.FieldTextInput'], ['Blockly.utils.Coordinate', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/field_variable.js", ['Blockly.FieldVariable'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.utils', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'goog.math.Size']); goog.addDependency("../../../" + dir + "/core/flyout_base.js", ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutButton', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceSvg', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/flyout_button.js", ['Blockly.FlyoutButton'], ['Blockly.utils.Coordinate', 'Blockly.utils', 'Blockly.utils.dom']); goog.addDependency("../../../" + dir + "/core/flyout_dragger.js", ['Blockly.FlyoutDragger'], ['Blockly.WorkspaceDragger']); goog.addDependency("../../../" + dir + "/core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils', 'Blockly.utils.Rect']); -goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.Rect']); +goog.addDependency("../../../" + dir + "/core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.Rect']); goog.addDependency("../../../" + dir + "/core/generator.js", ['Blockly.Generator'], ['Blockly.Block']); goog.addDependency("../../../" + dir + "/core/gesture.js", ['Blockly.Gesture'], ['Blockly.BlockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.WorkspaceDragger']); -goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.userAgent', 'Blockly.utils']); +goog.addDependency("../../../" + dir + "/core/grid.js", ['Blockly.Grid'], ['Blockly.utils.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/icon.js", ['Blockly.Icon'], ['Blockly.utils.Coordinate', 'Blockly.utils', 'Blockly.utils.dom']); -goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.Tooltip', 'Blockly.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); +goog.addDependency("../../../" + dir + "/core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.Tooltip', 'Blockly.utils.userAgent', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'goog.ui.Component']); goog.addDependency("../../../" + dir + "/core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']); goog.addDependency("../../../" + dir + "/core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.BlockAnimations', 'Blockly.Events', 'Blockly.RenderedConnection']); goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []); @@ -98,14 +98,14 @@ goog.addDependency("../../../" + dir + "/core/touch_gesture.js", ['Blockly.Touch goog.addDependency("../../../" + dir + "/core/trashcan.js", ['Blockly.Trashcan'], ['Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.Rect', 'Blockly.Xml']); goog.addDependency("../../../" + dir + "/core/ui_events.js", ['Blockly.Events.Ui'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/ui_menu_utils.js", ['Blockly.utils.uiMenu'], ['goog.style']); -goog.addDependency("../../../" + dir + "/core/useragent.js", ['Blockly.userAgent'], []); -goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.utils.Coordinate', 'Blockly.Msg', 'Blockly.userAgent', 'Blockly.utils.string', 'goog.style']); +goog.addDependency("../../../" + dir + "/core/utils.js", ['Blockly.utils'], ['Blockly.utils.Coordinate', 'Blockly.Msg', 'Blockly.utils.userAgent', 'Blockly.utils.string', 'goog.style']); goog.addDependency("../../../" + dir + "/core/utils/colour.js", ['Blockly.utils.colour'], ['Blockly.utils']); goog.addDependency("../../../" + dir + "/core/utils/coordinate.js", ['Blockly.utils.Coordinate'], []); goog.addDependency("../../../" + dir + "/core/utils/dom.js", ['Blockly.utils.dom'], []); goog.addDependency("../../../" + dir + "/core/utils/math.js", ['Blockly.utils.math'], []); goog.addDependency("../../../" + dir + "/core/utils/rect.js", ['Blockly.utils.Rect'], []); goog.addDependency("../../../" + dir + "/core/utils/string.js", ['Blockly.utils.string'], []); +goog.addDependency("../../../" + dir + "/core/utils/useragent.js", ['Blockly.utils.userAgent'], []); goog.addDependency("../../../" + dir + "/core/variable_events.js", ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract']); goog.addDependency("../../../" + dir + "/core/variable_map.js", ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/variable_model.js", ['Blockly.VariableModel'], ['Blockly.Events', 'Blockly.Events.VarCreate', 'Blockly.utils']); @@ -114,7 +114,7 @@ goog.addDependency("../../../" + dir + "/core/variables_dynamic.js", ['Blockly.V goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.style']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['Blockly.Events', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap', 'Blockly.WorkspaceComment']); -goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.userAgent']); +goog.addDependency("../../../" + dir + "/core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.utils.userAgent', 'Blockly.utils']); goog.addDependency("../../../" + dir + "/core/workspace_comment.js", ['Blockly.WorkspaceComment'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.Xml.utils']); goog.addDependency("../../../" + dir + "/core/workspace_comment_render_svg.js", ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.WorkspaceCommentSvg']); goog.addDependency("../../../" + dir + "/core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.utils.Coordinate', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.WorkspaceComment']); @@ -1849,7 +1849,6 @@ goog.require('Blockly.Xml.utils'); goog.require('Blockly.ZoomControls'); goog.require('Blockly.constants'); goog.require('Blockly.inject'); -goog.require('Blockly.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.Rect'); @@ -1858,6 +1857,7 @@ goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); goog.require('Blockly.utils.string'); goog.require('Blockly.utils.uiMenu'); +goog.require('Blockly.utils.userAgent'); delete root.BLOCKLY_DIR; delete root.BLOCKLY_BOOT; diff --git a/core/bubble.js b/core/bubble.js index 7937a7aceb9..122a6dccafb 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -28,7 +28,7 @@ goog.provide('Blockly.Bubble'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); @@ -227,7 +227,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { this.bubbleGroup_ = Blockly.utils.createSvgElement('g', {}, null); var filter = {'filter': 'url(#' + this.workspace_.options.embossFilterId + ')'}; - if (Blockly.userAgent.JAVA_FX) { + if (Blockly.utils.userAgent.JAVA_FX) { // Multiple reports that JavaFX can't handle filters. // https://github.com/google/blockly/issues/99 filter = {}; diff --git a/core/comment.js b/core/comment.js index 3176b573c71..aa4eef75846 100644 --- a/core/comment.js +++ b/core/comment.js @@ -31,7 +31,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); @@ -185,7 +185,7 @@ Blockly.Comment.prototype.setVisible = function(visible) { Blockly.Events.fire( new Blockly.Events.Ui(this.block_, 'commentOpen', !visible, visible)); if ((!this.block_.isEditable() && !this.textarea_) || - Blockly.userAgent.IE) { + Blockly.utils.userAgent.IE) { // Steal the code from warnings to make an uneditable text bubble. // MSIE does not support foreignobject; textareas are impossible. // https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-svg/56e6e04c-7c8c-44dd-8100-bd745ee42034 diff --git a/core/contextmenu.js b/core/contextmenu.js index 3074f1f8999..736bd17cca8 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -34,7 +34,7 @@ goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Msg'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.uiMenu'); @@ -283,7 +283,7 @@ Blockly.ContextMenu.blockDuplicateOption = function(block) { */ Blockly.ContextMenu.blockCommentOption = function(block) { var commentOption = { - enabled: !Blockly.userAgent.IE + enabled: !Blockly.utils.userAgent.IE }; // If there's already a comment, add an option to delete it. if (block.comment) { @@ -390,7 +390,7 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { var wsCommentOption = { // Foreign objects don't work in IE. Don't let the user create comments // that they won't be able to edit. - enabled: !Blockly.userAgent.IE + enabled: !Blockly.utils.userAgent.IE }; wsCommentOption.text = Blockly.Msg.ADD_COMMENT; wsCommentOption.callback = function() { diff --git a/core/field.js b/core/field.js index 1945ef7bf07..73a80c9c194 100644 --- a/core/field.js +++ b/core/field.js @@ -31,7 +31,7 @@ goog.provide('Blockly.Field'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); @@ -570,7 +570,7 @@ Blockly.Field.getCachedWidth = function(textElement) { // Attempt to compute fetch the width of the SVG text element. try { - if (Blockly.userAgent.IE || Blockly.userAgent.EDGE) { + if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { width = textElement.getBBox().width; } else { width = textElement.getComputedTextLength(); diff --git a/core/field_angle.js b/core/field_angle.js index d648f548d0c..99bfe3d550e 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -28,7 +28,7 @@ goog.provide('Blockly.FieldAngle'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.math'); @@ -167,9 +167,9 @@ Blockly.FieldAngle.prototype.dispose_ = function() { */ Blockly.FieldAngle.prototype.showEditor_ = function() { var noFocus = - Blockly.userAgent.MOBILE || - Blockly.userAgent.ANDROID || - Blockly.userAgent.IPAD; + Blockly.utils.userAgent.MOBILE || + Blockly.utils.userAgent.ANDROID || + Blockly.utils.userAgent.IPAD; // Mobile browsers have issues with in-line textareas (focus & keyboards). Blockly.FieldAngle.superClass_.showEditor_.call(this, noFocus); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 13f7fc3f521..1092b905bae 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -31,7 +31,7 @@ goog.provide('Blockly.FieldDropdown'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.string'); @@ -108,7 +108,7 @@ Blockly.FieldDropdown.IMAGE_Y_OFFSET = 5; * Android can't (in 2014) display "▾", so use "▼" instead. */ Blockly.FieldDropdown.ARROW_CHAR = - Blockly.userAgent.ANDROID ? '\u25BC' : '\u25BE'; + Blockly.utils.userAgent.ANDROID ? '\u25BC' : '\u25BE'; /** * Mouse cursor style when over the hotspot that initiates the editor. diff --git a/core/field_textinput.js b/core/field_textinput.js index 606108e1f53..b544334829e 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -32,7 +32,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); @@ -204,9 +204,9 @@ Blockly.FieldTextInput.prototype.setSpellcheck = function(check) { Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) { this.workspace_ = this.sourceBlock_.workspace; var quietInput = opt_quietInput || false; - if (!quietInput && (Blockly.userAgent.MOBILE || - Blockly.userAgent.ANDROID || - Blockly.userAgent.IPAD)) { + if (!quietInput && (Blockly.utils.userAgent.MOBILE || + Blockly.utils.userAgent.ANDROID || + Blockly.utils.userAgent.IPAD)) { this.showPromptEditor_(); } else { this.showInlineEditor_(quietInput); @@ -368,13 +368,13 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { // Shift by a few pixels to line up exactly. xy.y += 1; - if (Blockly.userAgent.GECKO && Blockly.WidgetDiv.DIV.style.top) { + if (Blockly.utils.userAgent.GECKO && Blockly.WidgetDiv.DIV.style.top) { // Firefox mis-reports the location of the border by a pixel // once the WidgetDiv is moved into position. xy.x -= 1; xy.y -= 1; } - if (Blockly.userAgent.WEBKIT) { + if (Blockly.utils.userAgent.WEBKIT) { xy.y -= 3; } div.style.left = xy.x + 'px'; diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 51035194e70..f1dcdcda2a0 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -29,7 +29,7 @@ goog.provide('Blockly.VerticalFlyout'); goog.require('Blockly.Block'); goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Rect'); @@ -335,7 +335,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { // Firefox sometimes reports the wrong value for the client rect. // See https://github.com/google/blockly/issues/1425 and // https://bugzilla.mozilla.org/show_bug.cgi?id=1066435 - if (Blockly.userAgent.GECKO && + if (Blockly.utils.userAgent.GECKO && this.targetWorkspace_ && this.targetWorkspace_.isMutator) { // The position of the left side of the mutator workspace in pixels // relative to the window origin. diff --git a/core/grid.js b/core/grid.js index 9322dea37ad..add42b6e7cc 100644 --- a/core/grid.js +++ b/core/grid.js @@ -27,7 +27,7 @@ goog.provide('Blockly.Grid'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); @@ -186,7 +186,7 @@ Blockly.Grid.prototype.moveTo = function(x, y) { this.gridPattern_.setAttribute('x', x); this.gridPattern_.setAttribute('y', y); - if (Blockly.userAgent.IE || Blockly.userAgent.EDGE) { + if (Blockly.utils.userAgent.IE || Blockly.utils.userAgent.EDGE) { // IE/Edge doesn't notice that the x/y offsets have changed. // Force an update. this.update(this.scale_); diff --git a/core/inject.js b/core/inject.js index 78f40d9cf8c..e361173a0e9 100644 --- a/core/inject.js +++ b/core/inject.js @@ -33,7 +33,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Grid'); goog.require('Blockly.Options'); goog.require('Blockly.Tooltip'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceSvg'); @@ -438,7 +438,7 @@ Blockly.inject.bindDocumentEvents_ = function() { Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); Blockly.bindEvent_(document, 'touchcancel', null, Blockly.longStop_); // Some iPad versions don't fire resize after portrait to landscape change. - if (Blockly.userAgent.IPAD) { + if (Blockly.utils.userAgent.IPAD) { Blockly.bindEventWithChecks_(window, 'orientationchange', document, function() { // TODO (#397): Fix for multiple Blockly workspaces. diff --git a/core/touch.js b/core/touch.js index c06433a1c86..8771600b6a3 100644 --- a/core/touch.js +++ b/core/touch.js @@ -45,7 +45,7 @@ Blockly.Touch.TOUCH_ENABLED = // IE10 uses non-standard touch events, so it has a different check. !!(Blockly.utils.global['navigator'] && (Blockly.utils.global['navigator']['maxTouchPoints'] || - Blockly.utils.global['navigator']['msMaxTouchPoints']))) + Blockly.utils.global['navigator']['msMaxTouchPoints']))); /** * Which touch events are we currently paying attention to? diff --git a/core/utils.js b/core/utils.js index 54b33c011e6..b270afa9e47 100644 --- a/core/utils.js +++ b/core/utils.js @@ -34,7 +34,7 @@ goog.provide('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Msg'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils.string'); goog.require('goog.style'); @@ -182,7 +182,7 @@ Blockly.utils.createSvgElement = function(name, attrs, parent) { * @return {boolean} True if right-click. */ Blockly.utils.isRightButton = function(e) { - if (e.ctrlKey && Blockly.userAgent.MAC) { + if (e.ctrlKey && Blockly.utils.userAgent.MAC) { // Control-clicking on Mac OS X is treated as a right-click. // WebKit on Mac OS X fails to change button to 2 (but Gecko does). return true; @@ -594,7 +594,7 @@ Blockly.utils.arrayRemove = function(arr, obj) { Blockly.utils.getDocumentScroll = function() { var el = document.documentElement; var win = window; - if (Blockly.userAgent.IE && win.pageYOffset != el.scrollTop) { + if (Blockly.utils.userAgent.IE && win.pageYOffset != el.scrollTop) { // The keyboard on IE10 touch devices shifts the page using the pageYOffset // without modifying scrollTop. For this case, we want the body scroll // offsets. diff --git a/core/useragent.js b/core/utils/useragent.js similarity index 56% rename from core/useragent.js rename to core/utils/useragent.js index 1e2e8739067..56d95aa7fe0 100644 --- a/core/useragent.js +++ b/core/utils/useragent.js @@ -20,20 +20,22 @@ /** * @fileoverview Useragent detection. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. * @author fraser@google.com (Neil Fraser) */ 'use strict'; /** - * @name Blockly.userAgent + * @name Blockly.utils.userAgent * @namespace */ -goog.provide('Blockly.userAgent'); +goog.provide('Blockly.utils.userAgent'); (function(raw) { - Blockly.userAgent.raw = raw; - var rawUpper = Blockly.userAgent.raw.toUpperCase(); + Blockly.utils.userAgent.raw = raw; + var rawUpper = Blockly.utils.userAgent.raw.toUpperCase(); /** * Case-insensitive test of whether name is in the useragent string. * @param {string} name Name to test. @@ -45,33 +47,36 @@ goog.provide('Blockly.userAgent'); // Browsers. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/browser.js - Blockly.userAgent.IE = has('Trident') || has('MSIE'); - Blockly.userAgent.EDGE = has('Edge'); + Blockly.utils.userAgent.IE = has('Trident') || has('MSIE'); + Blockly.utils.userAgent.EDGE = has('Edge'); // Useragent for JavaFX: // Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.44 // (KHTML, like Gecko) JavaFX/8.0 Safari/537.44 - Blockly.userAgent.JAVA_FX = has('JavaFX'); + Blockly.utils.userAgent.JAVA_FX = has('JavaFX'); // Engines. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/engine.js - Blockly.userAgent.WEBKIT = has('WebKit') && !Blockly.userAgent.EDGE; - Blockly.userAgent.GECKO = has('Gecko') && !Blockly.userAgent.WEBKIT && - !Blockly.userAgent.IE && !Blockly.userAgent.EDGE; + Blockly.utils.userAgent.WEBKIT = has('WebKit') && + !Blockly.utils.userAgent.EDGE; + Blockly.utils.userAgent.GECKO = has('Gecko') && + !Blockly.utils.userAgent.WEBKIT && + !Blockly.utils.userAgent.IE && + !Blockly.utils.userAgent.EDGE; // Platforms. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js - Blockly.userAgent.ANDROID = has('Android'); - Blockly.userAgent.IPAD = has('iPad'); - Blockly.userAgent.IPOD = has('iPod'); - Blockly.userAgent.IPHONE = has('iPhone') && - !Blockly.userAgent.IPAD && !Blockly.userAgent.IPOD; - Blockly.userAgent.MAC = has('Macintosh'); + Blockly.utils.userAgent.ANDROID = has('Android'); + Blockly.utils.userAgent.IPAD = has('iPad'); + Blockly.utils.userAgent.IPOD = has('iPod'); + Blockly.utils.userAgent.IPHONE = has('iPhone') && + !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; + Blockly.utils.userAgent.MAC = has('Macintosh'); // Devices. Logic from: // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/device.js - Blockly.userAgent.TABLET = Blockly.userAgent.IPAD || - (Blockly.userAgent.ANDROID && !has('Mobile')) || has('Silk'); - Blockly.userAgent.MOBILE = !Blockly.userAgent.TABLET && - (Blockly.userAgent.IPOD || Blockly.userAgent.IPHONE || - Blockly.userAgent.ANDROID || has('IEMobile')); + Blockly.utils.userAgent.TABLET = Blockly.utils.userAgent.IPAD || + (Blockly.utils.userAgent.ANDROID && !has('Mobile')) || has('Silk'); + Blockly.utils.userAgent.MOBILE = !Blockly.utils.userAgent.TABLET && + (Blockly.utils.userAgent.IPOD || Blockly.utils.userAgent.IPHONE || + Blockly.utils.userAgent.ANDROID || has('IEMobile')); })((this.navigator && this.navigator.userAgent) || ''); diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 063a09be681..ca1d50b9eea 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -27,7 +27,7 @@ goog.provide('Blockly.WorkspaceAudio'); -goog.require('Blockly.userAgent'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); @@ -116,7 +116,7 @@ Blockly.WorkspaceAudio.prototype.preload = function() { sound.pause(); // iOS can only process one sound at a time. Trying to load more than one // corrupts the earlier ones. Just load one and leave the others uncached. - if (Blockly.userAgent.IPAD || Blockly.userAgent.IPHONE) { + if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.IPHONE) { break; } } @@ -139,7 +139,7 @@ Blockly.WorkspaceAudio.prototype.play = function(name, opt_volume) { } this.lastSound_ = now; var mySound; - if (Blockly.userAgent.IPAD || Blockly.userAgent.ANDROID) { + if (Blockly.utils.userAgent.IPAD || Blockly.utils.userAgent.ANDROID) { // Creating a new audio node causes lag in Android and iPad. Android // refetches the file from the server, iPad uses a singleton audio // node which must be deleted and recreated for each new audio tag. From 1905531824fe4c4896d1dbbfeb0a4918df2dc81f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 18:15:14 -0700 Subject: [PATCH 113/233] Fix Mocha tests. --- tests/mocha/utils_test.js | 141 ++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 68 deletions(-) diff --git a/tests/mocha/utils_test.js b/tests/mocha/utils_test.js index 05fce6f3ac8..3f508f9c652 100644 --- a/tests/mocha/utils_test.js +++ b/tests/mocha/utils_test.js @@ -9,78 +9,83 @@ suite('Utils', function() { uuids[uuid] = true; } }); - test('addClass', function() { - var p = document.createElement('p'); - Blockly.utils.addClass(p, 'one'); - assertEquals('Adding "one"', 'one', p.className); - Blockly.utils.addClass(p, 'one'); - assertEquals('Adding duplicate "one"', 'one', p.className); - Blockly.utils.addClass(p, 'two'); - assertEquals('Adding "two"', 'one two', p.className); - Blockly.utils.addClass(p, 'two'); - assertEquals('Adding duplicate "two"', 'one two', p.className); - Blockly.utils.addClass(p, 'three'); - assertEquals('Adding "three"', 'one two three', p.className); - }); - test('hasClass', function() { - var p = document.createElement('p'); - p.className = ' one three two three '; - assertTrue('Has "one"', Blockly.utils.hasClass(p, 'one')); - assertTrue('Has "two"', Blockly.utils.hasClass(p, 'two')); - assertTrue('Has "three"', Blockly.utils.hasClass(p, 'three')); - assertFalse('Has no "four"', Blockly.utils.hasClass(p, 'four')); - assertFalse('Has no "t"', Blockly.utils.hasClass(p, 't')); - }); + suite('DOM', function() { + test('addClass', function() { + var p = document.createElement('p'); + Blockly.utils.dom.addClass(p, 'one'); + assertEquals('Adding "one"', 'one', p.className); + Blockly.utils.dom.addClass(p, 'one'); + assertEquals('Adding duplicate "one"', 'one', p.className); + Blockly.utils.dom.addClass(p, 'two'); + assertEquals('Adding "two"', 'one two', p.className); + Blockly.utils.dom.addClass(p, 'two'); + assertEquals('Adding duplicate "two"', 'one two', p.className); + Blockly.utils.dom.addClass(p, 'three'); + assertEquals('Adding "three"', 'one two three', p.className); + }); - test('removeClass', function() { - var p = document.createElement('p'); - p.className = ' one three two three '; - Blockly.utils.removeClass(p, 'two'); - assertEquals('Removing "two"', 'one three three', p.className); - Blockly.utils.removeClass(p, 'four'); - assertEquals('Removing "four"', 'one three three', p.className); - Blockly.utils.removeClass(p, 'three'); - assertEquals('Removing "three"', 'one', p.className); - Blockly.utils.removeClass(p, 'ne'); - assertEquals('Removing "ne"', 'one', p.className); - Blockly.utils.removeClass(p, 'one'); - assertEquals('Removing "one"', '', p.className); - Blockly.utils.removeClass(p, 'zero'); - assertEquals('Removing "zero"', '', p.className); - }); + test('hasClass', function() { + var p = document.createElement('p'); + p.className = ' one three two three '; + assertTrue('Has "one"', Blockly.utils.dom.hasClass(p, 'one')); + assertTrue('Has "two"', Blockly.utils.dom.hasClass(p, 'two')); + assertTrue('Has "three"', Blockly.utils.dom.hasClass(p, 'three')); + assertFalse('Has no "four"', Blockly.utils.dom.hasClass(p, 'four')); + assertFalse('Has no "t"', Blockly.utils.dom.hasClass(p, 't')); + }); - test('shortest string length', function() { - var len = Blockly.utils.shortestStringLength('one,two,three,four,five'.split(',')); - assertEquals('Length of "one"', 3, len); - len = Blockly.utils.shortestStringLength('one,two,three,four,five,'.split(',')); - assertEquals('Length of ""', 0, len); - len = Blockly.utils.shortestStringLength(['Hello World']); - assertEquals('List of one', 11, len); - len = Blockly.utils.shortestStringLength([]); - assertEquals('Empty list', 0, len); + test('removeClass', function() { + var p = document.createElement('p'); + p.className = ' one three two three '; + Blockly.utils.dom.removeClass(p, 'two'); + assertEquals('Removing "two"', 'one three three', p.className); + Blockly.utils.dom.removeClass(p, 'four'); + assertEquals('Removing "four"', 'one three three', p.className); + Blockly.utils.dom.removeClass(p, 'three'); + assertEquals('Removing "three"', 'one', p.className); + Blockly.utils.dom.removeClass(p, 'ne'); + assertEquals('Removing "ne"', 'one', p.className); + Blockly.utils.dom.removeClass(p, 'one'); + assertEquals('Removing "one"', '', p.className); + Blockly.utils.dom.removeClass(p, 'zero'); + assertEquals('Removing "zero"', '', p.className); + }); }); - test('comment word prefix', function() { - var len = Blockly.utils.commonWordPrefix('one,two,three,four,five'.split(',')); - assertEquals('No prefix', 0, len); - len = Blockly.utils.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(',')); - assertEquals('No word prefix', 0, len); - len = Blockly.utils.commonWordPrefix('abc de,abc de,abc de,abc de'.split(',')); - assertEquals('Full equality', 6, len); - len = Blockly.utils.commonWordPrefix('abc deX,abc deY'.split(',')); - assertEquals('One word prefix', 4, len); - len = Blockly.utils.commonWordPrefix('abc de,abc deY'.split(',')); - assertEquals('Overflow no', 4, len); - len = Blockly.utils.commonWordPrefix('abc de,abc de Y'.split(',')); - assertEquals('Overflow yes', 6, len); - len = Blockly.utils.commonWordPrefix(['Hello World']); - assertEquals('List of one', 11, len); - len = Blockly.utils.commonWordPrefix([]); - assertEquals('Empty list', 0, len); - len = Blockly.utils.commonWordPrefix('turn left,turn right'.split(',')); - assertEquals('No prefix due to &nbsp;', 0, len); - len = Blockly.utils.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(',')); - assertEquals('No prefix due to \\u00A0', 0, len); + suite('String', function() { + test('shortest string length', function() { + var len = Blockly.utils.string.shortestStringLength('one,two,three,four,five'.split(',')); + assertEquals('Length of "one"', 3, len); + len = Blockly.utils.string.shortestStringLength('one,two,three,four,five,'.split(',')); + assertEquals('Length of ""', 0, len); + len = Blockly.utils.string.shortestStringLength(['Hello World']); + assertEquals('List of one', 11, len); + len = Blockly.utils.string.shortestStringLength([]); + assertEquals('Empty list', 0, len); + }); + + test('comment word prefix', function() { + var len = Blockly.utils.string.commonWordPrefix('one,two,three,four,five'.split(',')); + assertEquals('No prefix', 0, len); + len = Blockly.utils.string.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(',')); + assertEquals('No word prefix', 0, len); + len = Blockly.utils.string.commonWordPrefix('abc de,abc de,abc de,abc de'.split(',')); + assertEquals('Full equality', 6, len); + len = Blockly.utils.string.commonWordPrefix('abc deX,abc deY'.split(',')); + assertEquals('One word prefix', 4, len); + len = Blockly.utils.string.commonWordPrefix('abc de,abc deY'.split(',')); + assertEquals('Overflow no', 4, len); + len = Blockly.utils.string.commonWordPrefix('abc de,abc de Y'.split(',')); + assertEquals('Overflow yes', 6, len); + len = Blockly.utils.string.commonWordPrefix(['Hello World']); + assertEquals('List of one', 11, len); + len = Blockly.utils.string.commonWordPrefix([]); + assertEquals('Empty list', 0, len); + len = Blockly.utils.string.commonWordPrefix('turn left,turn right'.split(',')); + assertEquals('No prefix due to &nbsp;', 0, len); + len = Blockly.utils.string.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(',')); + assertEquals('No prefix due to \\u00A0', 0, len); + }); }); }); From 3dfac9a2ba67361f8fa590138d28c51cc3b46b40 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 18:31:31 -0700 Subject: [PATCH 114/233] Alphabetize require statements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Search and replace for userAgent didn’t take into account alphabetic ordering. Also some line wraping. --- core/block_svg.js | 8 ++++---- core/bubble.js | 6 +++--- core/comment.js | 2 +- core/contextmenu.js | 2 +- core/field.js | 2 +- core/field_angle.js | 5 +++-- core/field_dropdown.js | 2 +- core/field_textinput.js | 2 +- core/flyout_vertical.js | 2 +- core/grid.js | 2 +- core/inject.js | 7 ++++--- core/utils.js | 4 ++-- core/workspace_audio.js | 2 +- core/workspace_svg.js | 3 ++- 14 files changed, 26 insertions(+), 23 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 76d46e53fa8..f441486db8c 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -480,8 +480,8 @@ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { var bottomRight; if (this.RTL) { // Width has the tab built into it already so subtract it here. - topLeft = new Blockly.utils.Coordinate(blockXY.x - (blockBounds.width - tab), - blockXY.y); + topLeft = new Blockly.utils.Coordinate( + blockXY.x - (blockBounds.width - tab), blockXY.y); // Add the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. bottomRight = new Blockly.utils.Coordinate(blockXY.x + tab, @@ -491,8 +491,8 @@ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { // since X is the corner of the rectangle, not the whole puzzle piece. topLeft = new Blockly.utils.Coordinate(blockXY.x - tab, blockXY.y); // Width has the tab built into it already so subtract it here. - bottomRight = new Blockly.utils.Coordinate(blockXY.x + blockBounds.width - tab, - blockXY.y + blockBounds.height); + bottomRight = new Blockly.utils.Coordinate( + blockXY.x + blockBounds.width - tab, blockXY.y + blockBounds.height); } return {topLeft: topLeft, bottomRight: bottomRight}; }; diff --git a/core/bubble.js b/core/bubble.js index 122a6dccafb..b4e67800aef 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -28,10 +28,10 @@ goog.provide('Blockly.Bubble'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.Workspace'); @@ -41,8 +41,8 @@ goog.require('Blockly.Workspace'); * bubble. * @param {!Element} content SVG content for the bubble. * @param {Element} shape SVG element to avoid eclipsing. - * @param {!Blockly.utils.Coordinate} anchorXY Absolute position of bubble's anchor - * point. + * @param {!Blockly.utils.Coordinate} anchorXY Absolute position of bubble's + * anchor point. * @param {?number} bubbleWidth Width of bubble, or null if not resizable. * @param {?number} bubbleHeight Height of bubble, or null if not resizable. * @constructor diff --git a/core/comment.js b/core/comment.js index aa4eef75846..e60accff9be 100644 --- a/core/comment.js +++ b/core/comment.js @@ -31,8 +31,8 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.userAgent'); /** diff --git a/core/contextmenu.js b/core/contextmenu.js index 736bd17cca8..838fa03a2f0 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -34,10 +34,10 @@ goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Msg'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.uiMenu'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.Xml'); goog.require('goog.events'); diff --git a/core/field.js b/core/field.js index 73a80c9c194..fd5cb26d375 100644 --- a/core/field.js +++ b/core/field.js @@ -31,9 +31,9 @@ goog.provide('Blockly.Field'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.userAgent'); goog.require('goog.math.Size'); goog.require('goog.style'); diff --git a/core/field_angle.js b/core/field_angle.js index 99bfe3d550e..da195df42d4 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -28,9 +28,9 @@ goog.provide('Blockly.FieldAngle'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.math'); +goog.require('Blockly.utils.userAgent'); /** @@ -211,7 +211,8 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { } var border = this.sourceBlock_.getColourBorder(); - border = border.colourBorder == null ? border.colourLight : border.colourBorder; + border = (border.colourBorder == null) ? + border.colourLight : border.colourBorder; Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); Blockly.DropDownDiv.showPositionedByField(this); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 1092b905bae..c9faa1dbac9 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -31,11 +31,11 @@ goog.provide('Blockly.FieldDropdown'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.string'); goog.require('Blockly.utils.uiMenu'); +goog.require('Blockly.utils.userAgent'); goog.require('goog.events'); goog.require('goog.ui.Menu'); diff --git a/core/field_textinput.js b/core/field_textinput.js index b544334829e..cb659788d2e 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -32,9 +32,9 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.userAgent'); /** diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index f1dcdcda2a0..c892e314e8f 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -29,9 +29,9 @@ goog.provide('Blockly.VerticalFlyout'); goog.require('Blockly.Block'); goog.require('Blockly.Flyout'); goog.require('Blockly.FlyoutButton'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Rect'); +goog.require('Blockly.utils.userAgent'); /** diff --git a/core/grid.js b/core/grid.js index add42b6e7cc..2f727751dbb 100644 --- a/core/grid.js +++ b/core/grid.js @@ -27,8 +27,8 @@ goog.provide('Blockly.Grid'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.userAgent'); /** diff --git a/core/inject.js b/core/inject.js index e361173a0e9..8ad0de9d01b 100644 --- a/core/inject.js +++ b/core/inject.js @@ -33,11 +33,11 @@ goog.require('Blockly.Events'); goog.require('Blockly.Grid'); goog.require('Blockly.Options'); goog.require('Blockly.Tooltip'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); -goog.require('Blockly.WorkspaceSvg'); +goog.require('Blockly.utils.userAgent'); goog.require('Blockly.WorkspaceDragSurfaceSvg'); +goog.require('Blockly.WorkspaceSvg'); goog.require('goog.ui.Component'); @@ -314,7 +314,8 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, } // Bump any object that's below the bottom back inside. - var overflowBottom = metrics.viewBottom - objectMetrics.bottomRight.y; + var overflowBottom = + metrics.viewBottom - objectMetrics.bottomRight.y; if (overflowBottom < 0) { object.moveBy(0, overflowBottom); } diff --git a/core/utils.js b/core/utils.js index b270afa9e47..f2c3f18da76 100644 --- a/core/utils.js +++ b/core/utils.js @@ -32,10 +32,10 @@ */ goog.provide('Blockly.utils'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Msg'); -goog.require('Blockly.utils.userAgent'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.string'); +goog.require('Blockly.utils.userAgent'); goog.require('goog.style'); diff --git a/core/workspace_audio.js b/core/workspace_audio.js index ca1d50b9eea..8e7029f4bc0 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -27,8 +27,8 @@ goog.provide('Blockly.WorkspaceAudio'); -goog.require('Blockly.utils.userAgent'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.userAgent'); /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index edb7ca61cc5..6c95a623da0 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -774,7 +774,8 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculationsIfScrolled = function() { /* eslint-disable indent */ var currScroll = Blockly.utils.getDocumentScroll(); - if (!Blockly.utils.Coordinate.equals(this.lastRecordedPageScroll_, currScroll)) { + if (!Blockly.utils.Coordinate.equals( + this.lastRecordedPageScroll_, currScroll)) { this.lastRecordedPageScroll_ = currScroll; this.updateScreenCalculations_(); } From 02e9b25f033d3af65e6ae6db7cdca9100cfc57f1 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 18:54:52 -0700 Subject: [PATCH 115/233] Flaten bounding box data structure. Old: a box object with two coordinate objects, each with two numbers. New: a box object with four numbers. The old system would make sense if there was a reason to group the top-left and bottom-right coordinates. But in our code we only pulled out top/bottom/left/right numbers. New code is simpler and faster. --- core/block_svg.js | 22 ++++++++++------------ core/inject.js | 8 ++++---- core/workspace_comment_svg.js | 22 ++++++++++------------ core/workspace_svg.js | 24 ++++++++++++------------ 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index f441486db8c..f671799133e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -469,32 +469,30 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { * Returns the coordinates of a bounding box describing the dimensions of this * block and any blocks stacked below it. * Coordinate system: workspace coordinates. - * @return {!{topLeft: Blockly.utils.Coordinate, bottomRight: Blockly.utils.Coordinate}} - * Object with top left and bottom right coordinates of the bounding box. + * @return {!{top: number, bottom: number, left: number, right: number}} + * Object with top, bottom, left, and right coordinates of the bounding box. */ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { var blockXY = this.getRelativeToSurfaceXY(this); var tab = this.outputConnection ? Blockly.BlockSvg.TAB_WIDTH : 0; var blockBounds = this.getHeightWidth(); - var topLeft; - var bottomRight; + var top = blockXY.y; + var bottom = blockXY.y + blockBounds.height; + var left, right; if (this.RTL) { // Width has the tab built into it already so subtract it here. - topLeft = new Blockly.utils.Coordinate( - blockXY.x - (blockBounds.width - tab), blockXY.y); + left = blockXY.x - (blockBounds.width - tab); // Add the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - bottomRight = new Blockly.utils.Coordinate(blockXY.x + tab, - blockXY.y + blockBounds.height); + right = blockXY.x + tab; } else { // Subtract the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - topLeft = new Blockly.utils.Coordinate(blockXY.x - tab, blockXY.y); + left = blockXY.x - tab; // Width has the tab built into it already so subtract it here. - bottomRight = new Blockly.utils.Coordinate( - blockXY.x + blockBounds.width - tab, blockXY.y + blockBounds.height); + right = blockXY.x + blockBounds.width - tab; } - return {topLeft: topLeft, bottomRight: bottomRight}; + return {top: top, bottom: bottom, left: left, right: right}; }; /** diff --git a/core/inject.js b/core/inject.js index 8ad0de9d01b..93b1277fca4 100644 --- a/core/inject.js +++ b/core/inject.js @@ -308,26 +308,26 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, var objectMetrics = object.getBoundingRectangle(); // Bump any object that's above the top back inside. - var overflowTop = metrics.viewTop - objectMetrics.topLeft.y; + var overflowTop = metrics.viewTop - objectMetrics.top; if (overflowTop > 0) { object.moveBy(0, overflowTop); } // Bump any object that's below the bottom back inside. var overflowBottom = - metrics.viewBottom - objectMetrics.bottomRight.y; + metrics.viewBottom - objectMetrics.bottom; if (overflowBottom < 0) { object.moveBy(0, overflowBottom); } // Bump any object that's off the left back inside. - var overflowLeft = metrics.viewLeft - objectMetrics.topLeft.x; + var overflowLeft = metrics.viewLeft - objectMetrics.left; if (overflowLeft > 0) { object.moveBy(overflowLeft, 0); } // Bump any object that's off the right back inside. - var overflowRight = metrics.viewRight - objectMetrics.bottomRight.x; + var overflowRight = metrics.viewRight - objectMetrics.right; if (overflowRight < 0) { object.moveBy(overflowRight, 0); } diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index a8051e8120a..e8d8720da97 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -419,30 +419,28 @@ Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { * Returns the coordinates of a bounding box describing the dimensions of this * comment. * Coordinate system: workspace coordinates. - * @return {!{topLeft: Blockly.utils.Coordinate, bottomRight: Blockly.utils.Coordinate}} - * Object with top left and bottom right coordinates of the bounding box. + * @return {!{top: number, bottom: number, left: number, right: number}} + * Object with top, bottom, left, and right coordinates of the bounding box. * @package */ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { var blockXY = this.getRelativeToSurfaceXY(); var commentBounds = this.getHeightWidth(); - var topLeft; - var bottomRight; + var top = blockXY.y; + var bottom = blockXY.y + commentBounds.height; + var left, right; if (this.RTL) { - topLeft = new Blockly.utils.Coordinate(blockXY.x - (commentBounds.width), - blockXY.y); + left = blockXY.x - (commentBounds.width); // Add the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - bottomRight = new Blockly.utils.Coordinate(blockXY.x, - blockXY.y + commentBounds.height); + right = blockXY.x; } else { // Subtract the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. - topLeft = new Blockly.utils.Coordinate(blockXY.x, blockXY.y); - bottomRight = new Blockly.utils.Coordinate(blockXY.x + commentBounds.width, - blockXY.y + commentBounds.height); + left = blockXY.x; + right = blockXY.x + commentBounds.width; } - return {topLeft: topLeft, bottomRight: bottomRight}; + return {top: top, bottom: bottom, left: left, right: right}; }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 6c95a623da0..b86e6a13c69 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1370,24 +1370,24 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { // Start at 1 since the 0th block was used for initialization for (var i = 1; i < topElements.length; i++) { var blockBoundary = topElements[i].getBoundingRectangle(); - if (blockBoundary.topLeft.x < boundary.topLeft.x) { - boundary.topLeft.x = blockBoundary.topLeft.x; + if (blockBoundary.left < boundary.left) { + boundary.left = blockBoundary.left; } - if (blockBoundary.bottomRight.x > boundary.bottomRight.x) { - boundary.bottomRight.x = blockBoundary.bottomRight.x; + if (blockBoundary.right > boundary.right) { + boundary.right = blockBoundary.right; } - if (blockBoundary.topLeft.y < boundary.topLeft.y) { - boundary.topLeft.y = blockBoundary.topLeft.y; + if (blockBoundary.top < boundary.top) { + boundary.top = blockBoundary.top; } - if (blockBoundary.bottomRight.y > boundary.bottomRight.y) { - boundary.bottomRight.y = blockBoundary.bottomRight.y; + if (blockBoundary.bottom > boundary.bottom) { + boundary.bottom = blockBoundary.bottom; } } return { - x: boundary.topLeft.x, - y: boundary.topLeft.y, - width: boundary.bottomRight.x - boundary.topLeft.x, - height: boundary.bottomRight.y - boundary.topLeft.y + x: boundary.left, + y: boundary.top, + width: boundary.right - boundary.left, + height: boundary.bottom - boundary.top }; }; From a9fdf7844a2db8a800f4b400dc62d71ef56d83c4 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 21:01:32 -0700 Subject: [PATCH 116/233] Fix ordering of requires Search and replace of a name strikes again. --- core/block.js | 4 ++-- core/block_drag_surface.js | 2 +- core/block_dragger.js | 4 ++-- core/block_events.js | 2 +- core/bubble.js | 2 +- core/bubble_dragger.js | 2 +- core/contextmenu.js | 2 +- core/field_textinput.js | 2 +- core/flyout_base.js | 2 +- core/flyout_button.js | 2 +- core/gesture.js | 2 +- core/icon.js | 2 +- core/scrollbar.js | 2 +- core/touch_gesture.js | 2 +- core/workspace_comment.js | 2 +- core/workspace_comment_svg.js | 2 +- core/workspace_svg.js | 4 ++-- core/ws_comment_events.js | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/block.js b/core/block.js index cf561bbce69..35b5443def5 100644 --- a/core/block.js +++ b/core/block.js @@ -29,8 +29,6 @@ goog.provide('Blockly.Block'); goog.require('Blockly.Blocks'); goog.require('Blockly.Comment'); goog.require('Blockly.Connection'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.utils.string'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.BlockCreate'); @@ -40,6 +38,8 @@ goog.require('Blockly.Extensions'); goog.require('Blockly.Input'); goog.require('Blockly.Mutator'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.string'); goog.require('Blockly.Warning'); goog.require('Blockly.Workspace'); diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 853b176362f..18c7e70f26c 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -30,8 +30,8 @@ 'use strict'; goog.provide('Blockly.BlockDragSurfaceSvg'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); /** diff --git a/core/block_dragger.js b/core/block_dragger.js index 3b0a60398b1..a002e77a06c 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -27,10 +27,10 @@ goog.provide('Blockly.BlockDragger'); goog.require('Blockly.BlockAnimations'); -goog.require('Blockly.utils.Coordinate'); -goog.require('Blockly.InsertionMarkerManager'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockMove'); +goog.require('Blockly.InsertionMarkerManager'); +goog.require('Blockly.utils.Coordinate'); /** diff --git a/core/block_events.js b/core/block_events.js index 4d4283d0682..b40316871ce 100644 --- a/core/block_events.js +++ b/core/block_events.js @@ -34,9 +34,9 @@ goog.provide('Blockly.Events.Create'); // Deprecated. goog.provide('Blockly.Events.Delete'); // Deprecated. goog.provide('Blockly.Events.Move'); // Deprecated. -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Abstract'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Xml.utils'); diff --git a/core/bubble.js b/core/bubble.js index b4e67800aef..18f6b07a414 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -26,9 +26,9 @@ goog.provide('Blockly.Bubble'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); goog.require('Blockly.utils.userAgent'); diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index 42dfc9bd099..3fe0cd5696b 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -27,10 +27,10 @@ goog.provide('Blockly.BubbleDragger'); goog.require('Blockly.Bubble'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.WorkspaceCommentSvg'); diff --git a/core/contextmenu.js b/core/contextmenu.js index 838fa03a2f0..489a25b5829 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -30,11 +30,11 @@ */ goog.provide('Blockly.ContextMenu'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Msg'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.uiMenu'); goog.require('Blockly.utils.userAgent'); diff --git a/core/field_textinput.js b/core/field_textinput.js index cb659788d2e..027f4f683c6 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -26,13 +26,13 @@ goog.provide('Blockly.FieldTextInput'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); diff --git a/core/flyout_base.js b/core/flyout_base.js index 8375600d941..2d37598f34f 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -27,7 +27,6 @@ goog.provide('Blockly.Flyout'); goog.require('Blockly.Block'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Events.VarCreate'); @@ -36,6 +35,7 @@ goog.require('Blockly.Gesture'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceSvg'); goog.require('Blockly.Xml'); diff --git a/core/flyout_button.js b/core/flyout_button.js index 34dd9455e70..9a8a9776e58 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -26,8 +26,8 @@ goog.provide('Blockly.FlyoutButton'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); diff --git a/core/gesture.js b/core/gesture.js index a0cc3baf0ac..b2f55275212 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -31,13 +31,13 @@ goog.require('Blockly.BlockAnimations'); goog.require('Blockly.BlockDragger'); goog.require('Blockly.BubbleDragger'); goog.require('Blockly.constants'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.FlyoutDragger'); goog.require('Blockly.Tooltip'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.WorkspaceDragger'); diff --git a/core/icon.js b/core/icon.js index 27af9f032ec..85d9dc44556 100644 --- a/core/icon.js +++ b/core/icon.js @@ -26,8 +26,8 @@ goog.provide('Blockly.Icon'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); diff --git a/core/scrollbar.js b/core/scrollbar.js index 9d1cc1c8447..11e5ecf2d4a 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -27,9 +27,9 @@ goog.provide('Blockly.Scrollbar'); goog.provide('Blockly.ScrollbarPair'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); diff --git a/core/touch_gesture.js b/core/touch_gesture.js index 9dcfbddeda6..780579cf1f9 100644 --- a/core/touch_gesture.js +++ b/core/touch_gesture.js @@ -27,9 +27,9 @@ goog.provide('Blockly.TouchGesture'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Gesture'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); /* diff --git a/core/workspace_comment.js b/core/workspace_comment.js index 9b418d7cede..0d40c2d60c4 100644 --- a/core/workspace_comment.js +++ b/core/workspace_comment.js @@ -26,13 +26,13 @@ goog.provide('Blockly.WorkspaceComment'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentChange'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Xml.utils'); diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index e8d8720da97..08d2b3c2673 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -26,13 +26,13 @@ goog.provide('Blockly.WorkspaceCommentSvg'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); goog.require('Blockly.Events.CommentMove'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.WorkspaceComment'); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index b86e6a13c69..eb7ec766620 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -30,7 +30,6 @@ goog.provide('Blockly.WorkspaceSvg'); //goog.require('Blockly.BlockSvg'); goog.require('Blockly.ConnectionDB'); goog.require('Blockly.constants'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Gesture'); @@ -42,6 +41,7 @@ goog.require('Blockly.Touch'); goog.require('Blockly.TouchGesture'); goog.require('Blockly.Trashcan'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); goog.require('Blockly.VariablesDynamic'); goog.require('Blockly.Workspace'); @@ -1367,7 +1367,7 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { // Initialize boundary using the first block. var boundary = topElements[0].getBoundingRectangle(); - // Start at 1 since the 0th block was used for initialization + // Start at 1 since the 0th block was used for initialization. for (var i = 1; i < topElements.length; i++) { var blockBoundary = topElements[i].getBoundingRectangle(); if (blockBoundary.left < boundary.left) { diff --git a/core/ws_comment_events.js b/core/ws_comment_events.js index ac5e7c8d701..85552332b1c 100644 --- a/core/ws_comment_events.js +++ b/core/ws_comment_events.js @@ -30,9 +30,9 @@ goog.provide('Blockly.Events.CommentCreate'); goog.provide('Blockly.Events.CommentDelete'); goog.provide('Blockly.Events.CommentMove'); -goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Abstract'); +goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.Xml'); goog.require('Blockly.Xml.utils'); From 775ce34eaca0a753ea19a2e681d352c01f503796 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 6 Jun 2019 21:59:37 -0700 Subject: [PATCH 117/233] Simplify workspace.getBlocksBoundingBox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously it returned x,y,width,height. Returning top,bottom,left,right results in simpler code, both in this function and in downstream callers. This commit makes the minumum change to the metrics_test. I’m happy to change the test’s data if that makes more sense. --- core/inject.js | 10 ++++------ core/workspace_comment_svg.js | 2 +- core/workspace_svg.js | 31 +++++++++++++------------------ core/xml.js | 6 +++--- tests/jsunit/metrics_test.js | 8 ++++---- 5 files changed, 25 insertions(+), 32 deletions(-) diff --git a/core/inject.js b/core/inject.js index 93b1277fca4..e68ec6e7a32 100644 --- a/core/inject.js +++ b/core/inject.js @@ -257,12 +257,10 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, if (mainWorkspace.isContentBounded()) { // Already in workspace units, no need to divide by scale. var blocksBoundingBox = mainWorkspace.getBlocksBoundingBox(); - workspaceMetrics.contentLeft = blocksBoundingBox.x; - workspaceMetrics.contentTop = blocksBoundingBox.y; - workspaceMetrics.contentRight = - blocksBoundingBox.x + blocksBoundingBox.width; - workspaceMetrics.contentBottom = - blocksBoundingBox.y + blocksBoundingBox.height; + workspaceMetrics.contentLeft = blocksBoundingBox.left; + workspaceMetrics.contentTop = blocksBoundingBox.top; + workspaceMetrics.contentRight = blocksBoundingBox.right; + workspaceMetrics.contentBottom = blocksBoundingBox.bottom; } else { workspaceMetrics.contentLeft = defaultMetrics.contentLeft / scale; workspaceMetrics.contentTop = defaultMetrics.contentTop / scale; diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 08d2b3c2673..59e28d8e74c 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -430,7 +430,7 @@ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { var bottom = blockXY.y + commentBounds.height; var left, right; if (this.RTL) { - left = blockXY.x - (commentBounds.width); + left = blockXY.x - commentBounds.width; // Add the width of the tab/puzzle piece knob to the x coordinate // since X is the corner of the rectangle, not the whole puzzle piece. right = blockXY.x; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index eb7ec766620..9498a6f8508 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1361,7 +1361,7 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { var topElements = topBlocks.concat(topComments); // There are no blocks, return empty rectangle. if (!topElements.length) { - return {x: 0, y: 0, width: 0, height: 0}; + return {top: 0, bottom: 0, left: 0, right: 0}; } // Initialize boundary using the first block. @@ -1383,12 +1383,7 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { boundary.bottom = blockBoundary.bottom; } } - return { - x: boundary.left, - y: boundary.top, - width: boundary.right - boundary.left, - height: boundary.bottom - boundary.top - }; + return boundary; }; /** @@ -1726,8 +1721,8 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() { var workspaceWidth = metrics.viewWidth; var workspaceHeight = metrics.viewHeight; var blocksBox = this.getBlocksBoundingBox(); - var blocksWidth = blocksBox.width; - var blocksHeight = blocksBox.height; + var blocksWidth = blocksBox.right - blocksBox.left; + var blocksHeight = blocksBox.bottom - blocksBox.top; if (!blocksWidth) { return; // Prevents zooming to infinity. } @@ -2018,18 +2013,18 @@ Blockly.WorkspaceSvg.getContentDimensionsExact_ = function(ws) { var scale = ws.scale; // Convert to pixels. - var width = blockBox.width * scale; - var height = blockBox.height * scale; - var left = blockBox.x * scale; - var top = blockBox.y * scale; + var top = blockBox.top * scale; + var bottom = blockBox.bottom * scale; + var left = blockBox.left * scale; + var right = blockBox.right * scale; return { - left: left, top: top, - right: left + width, - bottom: top + height, - width: width, - height: height + bottom: bottom, + left: left, + right: right, + width: right - left, + height: bottom - top }; }; diff --git a/core/xml.js b/core/xml.js index a0fe66b739e..c8fb003e5d3 100644 --- a/core/xml.js +++ b/core/xml.js @@ -461,11 +461,11 @@ Blockly.Xml.appendDomToWorkspace = function(xml, workspace) { } // Load the new blocks into the workspace and get the IDs of the new blocks. var newBlockIds = Blockly.Xml.domToWorkspace(xml,workspace); - if (bbox && bbox.height) { // check if any previous block + if (bbox && bbox.top != bbox.bottom) { // check if any previous block var offsetY = 0; // offset to add to y of the new block var offsetX = 0; - var farY = bbox.y + bbox.height; // bottom position - var topX = bbox.x; // x of bounding box + var farY = bbox.bottom; // bottom position + var topX = bbox.left; // x of bounding box // Check position of the new blocks. var newX = Infinity; // x of top corner var newY = Infinity; // y of top corner diff --git a/tests/jsunit/metrics_test.js b/tests/jsunit/metrics_test.js index 30cd11af318..fb9ca4d372b 100644 --- a/tests/jsunit/metrics_test.js +++ b/tests/jsunit/metrics_test.js @@ -34,10 +34,10 @@ function makeMockWs(scale, x, y, width, height) { return { getBlocksBoundingBox: function() { return { - width: width, - height: height, - x: x, - y: y + top: y, + bottom: y + height, + left: x, + right: x + width } }, scale: scale From 848d3a35099ef008445acb8be254ccb20a6ee251 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 7 Jun 2019 00:52:40 -0700 Subject: [PATCH 118/233] Move setCssTransform & createSvgElement to dom. Also move SVG_NS and HTML_NS properties. --- core/block_animations.js | 3 +- core/block_drag_surface.js | 11 ++++--- core/block_svg.js | 8 ++--- core/bubble.js | 16 ++++----- core/comment.js | 16 ++++----- core/constants.js | 12 ------- core/field.js | 7 ++-- core/field_angle.js | 14 ++++---- core/field_dropdown.js | 4 +-- core/field_image.js | 2 +- core/flyout_base.js | 8 ++--- core/flyout_button.js | 8 ++--- core/grid.js | 10 +++--- core/icon.js | 2 +- core/inject.js | 22 ++++++------- core/mutator.js | 8 ++--- core/rendered_connection.js | 2 +- core/scrollbar.js | 12 +++---- core/trashcan.js | 15 ++++----- core/utils.js | 37 --------------------- core/utils/dom.js | 49 ++++++++++++++++++++++++++++ core/warning.js | 12 +++---- core/workspace_comment_render_svg.js | 28 ++++++++-------- core/workspace_comment_svg.js | 4 +-- core/workspace_drag_surface_svg.js | 10 +++--- core/workspace_svg.js | 8 ++--- core/zoom_controls.js | 27 ++++++++------- 27 files changed, 176 insertions(+), 179 deletions(-) diff --git a/core/block_animations.js b/core/block_animations.js index 885a61c48df..6166ae8cd62 100644 --- a/core/block_animations.js +++ b/core/block_animations.js @@ -26,7 +26,6 @@ goog.provide('Blockly.BlockAnimations'); -goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); @@ -117,7 +116,7 @@ Blockly.BlockAnimations.connectionUiEffect = function(block) { xy.x += (block.RTL ? -23 : 23) * scale; xy.y += 3 * scale; } - var ripple = Blockly.utils.createSvgElement('circle', + var ripple = Blockly.utils.dom.createSvgElement('circle', { 'cx': xy.x, 'cy': xy.y, diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 18c7e70f26c..a9c46c24431 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -32,6 +32,7 @@ goog.provide('Blockly.BlockDragSurfaceSvg'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); +goog.require('Blockly.utils.dom'); /** @@ -95,14 +96,14 @@ Blockly.BlockDragSurfaceSvg.prototype.createDom = function() { if (this.SVG_) { return; // Already created. } - this.SVG_ = Blockly.utils.createSvgElement('svg', { - 'xmlns': Blockly.SVG_NS, - 'xmlns:html': Blockly.HTML_NS, + this.SVG_ = Blockly.utils.dom.createSvgElement('svg', { + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'version': '1.1', 'class': 'blocklyBlockDragSurface' }, this.container_); - this.dragGroup_ = Blockly.utils.createSvgElement('g', {}, this.SVG_); + this.dragGroup_ = Blockly.utils.dom.createSvgElement('g', {}, this.SVG_); }; /** @@ -152,7 +153,7 @@ Blockly.BlockDragSurfaceSvg.prototype.translateSurfaceInternal_ = function() { y = y.toFixed(0); this.SVG_.style.display = 'block'; - Blockly.utils.setCssTransform(this.SVG_, + Blockly.utils.dom.setCssTransform(this.SVG_, 'translate3d(' + x + 'px, ' + y + 'px, 0px)'); }; diff --git a/core/block_svg.js b/core/block_svg.js index f671799133e..347a56be79e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -59,14 +59,14 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @type {SVGElement} * @private */ - this.svgGroup_ = Blockly.utils.createSvgElement('g', {}, null); + this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); this.svgGroup_.translate_ = ''; /** * @type {SVGElement} * @private */ - this.svgPathDark_ = Blockly.utils.createSvgElement('path', + this.svgPathDark_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, this.svgGroup_); @@ -74,14 +74,14 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @type {SVGElement} * @private */ - this.svgPath_ = Blockly.utils.createSvgElement('path', + this.svgPath_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPath'}, this.svgGroup_); /** * @type {SVGElement} * @private */ - this.svgPathLight_ = Blockly.utils.createSvgElement('path', + this.svgPathLight_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyPathLight'}, this.svgGroup_); this.svgPath_.tooltip = this; diff --git a/core/bubble.js b/core/bubble.js index 18f6b07a414..d5b9f31b124 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -224,7 +224,7 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { [...content goes here...] */ - this.bubbleGroup_ = Blockly.utils.createSvgElement('g', {}, null); + this.bubbleGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); var filter = {'filter': 'url(#' + this.workspace_.options.embossFilterId + ')'}; if (Blockly.utils.userAgent.JAVA_FX) { @@ -232,10 +232,10 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { // https://github.com/google/blockly/issues/99 filter = {}; } - var bubbleEmboss = Blockly.utils.createSvgElement('g', + var bubbleEmboss = Blockly.utils.dom.createSvgElement('g', filter, this.bubbleGroup_); - this.bubbleArrow_ = Blockly.utils.createSvgElement('path', {}, bubbleEmboss); - this.bubbleBack_ = Blockly.utils.createSvgElement('rect', + this.bubbleArrow_ = Blockly.utils.dom.createSvgElement('path', {}, bubbleEmboss); + this.bubbleBack_ = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyDraggable', 'x': 0, @@ -245,21 +245,21 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { }, bubbleEmboss); if (hasResize) { - this.resizeGroup_ = Blockly.utils.createSvgElement('g', + this.resizeGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': this.workspace_.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, this.bubbleGroup_); var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; - Blockly.utils.createSvgElement('polygon', + Blockly.utils.dom.createSvgElement('polygon', {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, this.resizeGroup_); - Blockly.utils.createSvgElement('line', + Blockly.utils.dom.createSvgElement('line', { 'class': 'blocklyResizeLine', 'x1': resizeSize / 3, 'y1': resizeSize - 1, 'x2': resizeSize - 1, 'y2': resizeSize / 3 }, this.resizeGroup_); - Blockly.utils.createSvgElement('line', + Blockly.utils.dom.createSvgElement('line', { 'class': 'blocklyResizeLine', 'x1': resizeSize * 2 / 3, diff --git a/core/comment.js b/core/comment.js index e60accff9be..f587cc78d8a 100644 --- a/core/comment.js +++ b/core/comment.js @@ -31,7 +31,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); -goog.require('Blockly.utils'); +goog.provide('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); @@ -72,13 +72,13 @@ Blockly.Comment.prototype.height_ = 80; */ Blockly.Comment.prototype.drawIcon_ = function(group) { // Circle. - Blockly.utils.createSvgElement('circle', + Blockly.utils.dom.createSvgElement('circle', {'class': 'blocklyIconShape', 'r': '8', 'cx': '8', 'cy': '8'}, group); // Can't use a real '?' text character since different browsers and operating // systems render it differently. // Body of question mark. - Blockly.utils.createSvgElement('path', + Blockly.utils.dom.createSvgElement('path', { 'class': 'blocklyIconSymbol', 'd': 'm6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.405' + @@ -86,7 +86,7 @@ Blockly.Comment.prototype.drawIcon_ = function(group) { '-1.201,0.998 -1.201,1.528 -1.204,2.19z'}, group); // Dot of question mark. - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyIconSymbol', 'x': '6.8', @@ -112,13 +112,13 @@ Blockly.Comment.prototype.createEditor_ = function() { */ - this.foreignObject_ = Blockly.utils.createSvgElement('foreignObject', + this.foreignObject_ = Blockly.utils.dom.createSvgElement('foreignObject', {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); - var body = document.createElementNS(Blockly.HTML_NS, 'body'); - body.setAttribute('xmlns', Blockly.HTML_NS); + var body = document.createElementNS(Blockly.utils.dom.HTML_NS, 'body'); + body.setAttribute('xmlns', Blockly.utils.dom.HTML_NS); body.className = 'blocklyMinimalBody'; - var textarea = document.createElementNS(Blockly.HTML_NS, 'textarea'); + var textarea = document.createElementNS(Blockly.utils.dom.HTML_NS, 'textarea'); textarea.className = 'blocklyCommentTextarea'; textarea.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR'); body.appendChild(textarea); diff --git a/core/constants.js b/core/constants.js index f310f1385ff..7d2111e690d 100644 --- a/core/constants.js +++ b/core/constants.js @@ -129,18 +129,6 @@ Blockly.SPRITE = { // Constants below this point are not intended to be changed. -/** - * Required name space for SVG elements. - * @const - */ -Blockly.SVG_NS = 'http://www.w3.org/2000/svg'; - -/** - * Required name space for HTML elements. - * @const - */ -Blockly.HTML_NS = 'http://www.w3.org/1999/xhtml'; - /** * ENUM for a right-facing value input. E.g. 'set item to' or 'return'. * @const diff --git a/core/field.js b/core/field.js index fd5cb26d375..72f9e3d1387 100644 --- a/core/field.js +++ b/core/field.js @@ -31,7 +31,6 @@ goog.provide('Blockly.Field'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Gesture'); -goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); @@ -230,7 +229,7 @@ Blockly.Field.prototype.init = function() { // Field has already been initialized once. return; } - this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null); + this.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); if (!this.isVisible()) { this.fieldGroup_.style.display = 'none'; } @@ -258,7 +257,7 @@ Blockly.Field.prototype.initView = function() { * @protected */ Blockly.Field.prototype.createBorderRect_ = function() { - this.borderRect_ = Blockly.utils.createSvgElement('rect', + this.borderRect_ = Blockly.utils.dom.createSvgElement('rect', { 'rx': 4, 'ry': 4, @@ -276,7 +275,7 @@ Blockly.Field.prototype.createBorderRect_ = function() { * @protected */ Blockly.Field.prototype.createTextElement_ = function() { - this.textElement_ = Blockly.utils.createSvgElement('text', + this.textElement_ = Blockly.utils.dom.createSvgElement('text', { 'class': 'blocklyText', 'y': this.size_.height - 12.5 diff --git a/core/field_angle.js b/core/field_angle.js index da195df42d4..6c44deb8bac 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -28,7 +28,7 @@ goog.provide('Blockly.FieldAngle'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); -goog.require('Blockly.utils'); +goog.provide('Blockly.utils.dom'); goog.require('Blockly.utils.math'); goog.require('Blockly.utils.userAgent'); @@ -125,7 +125,7 @@ Blockly.FieldAngle.RADIUS = Blockly.FieldAngle.HALF - 1; Blockly.FieldAngle.prototype.initView = function() { Blockly.FieldAngle.superClass_.initView.call(this); // Add the degree symbol to the left of the number, even in RTL (issue #2380) - this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null); + this.symbol_ = Blockly.utils.dom.createSvgElement('tspan', {}, null); this.symbol_.appendChild(document.createTextNode('\u00B0')); this.textElement_.appendChild(this.symbol_); }; @@ -176,7 +176,7 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { var div = Blockly.DropDownDiv.getContentDiv(); // Build the SVG DOM. - var svg = Blockly.utils.createSvgElement('svg', { + var svg = Blockly.utils.dom.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', @@ -184,21 +184,21 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { 'height': (Blockly.FieldAngle.HALF * 2) + 'px', 'width': (Blockly.FieldAngle.HALF * 2) + 'px' }, div); - var circle = Blockly.utils.createSvgElement('circle', { + var circle = Blockly.utils.dom.createSvgElement('circle', { 'cx': Blockly.FieldAngle.HALF, 'cy': Blockly.FieldAngle.HALF, 'r': Blockly.FieldAngle.RADIUS, 'class': 'blocklyAngleCircle' }, svg); - this.gauge_ = Blockly.utils.createSvgElement('path', + this.gauge_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyAngleGauge'}, svg); - this.line_ = Blockly.utils.createSvgElement('line', { + this.line_ = Blockly.utils.dom.createSvgElement('line', { 'x1': Blockly.FieldAngle.HALF, 'y1': Blockly.FieldAngle.HALF, 'class': 'blocklyAngleLine' }, svg); // Draw markers around the edge. for (var angle = 0; angle < 360; angle += 15) { - Blockly.utils.createSvgElement('line', { + Blockly.utils.dom.createSvgElement('line', { 'x1': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS, 'y1': Blockly.FieldAngle.HALF, 'x2': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS - diff --git a/core/field_dropdown.js b/core/field_dropdown.js index c9faa1dbac9..610fb3c8d62 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -137,12 +137,12 @@ Blockly.FieldDropdown.prototype.imageJson_ = null; Blockly.FieldDropdown.prototype.initView = function() { Blockly.FieldDropdown.superClass_.initView.call(this); - this.imageElement_ = Blockly.utils.createSvgElement( 'image', + this.imageElement_ = Blockly.utils.dom.createSvgElement( 'image', { 'y': Blockly.FieldDropdown.IMAGE_Y_OFFSET }, this.fieldGroup_); - this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, this.textElement_); + this.arrow_ = Blockly.utils.dom.createSvgElement('tspan', {}, this.textElement_); this.arrow_.appendChild(document.createTextNode( this.sourceBlock_.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : diff --git a/core/field_image.js b/core/field_image.js index e7d8a96c346..098ff1d2a7d 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -117,7 +117,7 @@ Blockly.FieldImage.prototype.isDirty_ = false; * @package */ Blockly.FieldImage.prototype.initView = function() { - this.imageElement_ = Blockly.utils.createSvgElement( + this.imageElement_ = Blockly.utils.dom.createSvgElement( 'image', { 'height': this.height_ + 'px', diff --git a/core/flyout_base.js b/core/flyout_base.js index 2d37598f34f..e427982843c 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -213,9 +213,9 @@ Blockly.Flyout.prototype.createDom = function(tagName) { */ // Setting style to display:none to start. The toolbox and flyout // hide/show code will set up proper visibility and size later. - this.svgGroup_ = Blockly.utils.createSvgElement(tagName, + this.svgGroup_ = Blockly.utils.dom.createSvgElement(tagName, {'class': 'blocklyFlyout', 'style': 'display: none'}, null); - this.svgBackground_ = Blockly.utils.createSvgElement('path', + this.svgBackground_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyFlyoutBackground'}, this.svgGroup_); this.svgGroup_.appendChild(this.workspace_.createDom()); return this.svgGroup_; @@ -376,7 +376,7 @@ Blockly.Flyout.prototype.positionAt_ = function(width, height, x, y) { this.svgGroup_.setAttribute("height", height); if (this.svgGroup_.tagName == 'svg') { var transform = 'translate(' + x + 'px,' + y + 'px)'; - Blockly.utils.setCssTransform(this.svgGroup_, transform); + Blockly.utils.dom.setCssTransform(this.svgGroup_, transform); } else { // IE and Edge don't support CSS transforms on SVG elements so // it's important to set the transform on the SVG element itself @@ -693,7 +693,7 @@ Blockly.Flyout.prototype.initFlyoutButton_ = function(button, x, y) { Blockly.Flyout.prototype.createRect_ = function(block, x, y, blockHW, index) { // Create an invisible rectangle under the block to act as a button. Just // using the block as a button is poor, since blocks have holes in them. - var rect = Blockly.utils.createSvgElement('rect', + var rect = Blockly.utils.dom.createSvgElement('rect', { 'fill-opacity': 0, 'x': x, diff --git a/core/flyout_button.js b/core/flyout_button.js index 9a8a9776e58..6f8985b3109 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -123,12 +123,12 @@ Blockly.FlyoutButton.prototype.createDom = function() { cssClass += ' ' + this.cssClass_; } - this.svgGroup_ = Blockly.utils.createSvgElement('g', {'class': cssClass}, + this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': cssClass}, this.workspace_.getCanvas()); if (!this.isLabel_) { // Shadow rectangle (light source does not mirror in RTL). - var shadow = Blockly.utils.createSvgElement('rect', + var shadow = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyFlyoutButtonShadow', 'rx': 4, 'ry': 4, 'x': 1, 'y': 1 @@ -136,7 +136,7 @@ Blockly.FlyoutButton.prototype.createDom = function() { this.svgGroup_); } // Background rectangle. - var rect = Blockly.utils.createSvgElement('rect', + var rect = Blockly.utils.dom.createSvgElement('rect', { 'class': this.isLabel_ ? 'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground', @@ -144,7 +144,7 @@ Blockly.FlyoutButton.prototype.createDom = function() { }, this.svgGroup_); - var svgText = Blockly.utils.createSvgElement('text', + var svgText = Blockly.utils.dom.createSvgElement('text', { 'class': this.isLabel_ ? 'blocklyFlyoutLabelText' : 'blocklyText', 'x': 0, diff --git a/core/grid.js b/core/grid.js index 2f727751dbb..2e78cb819dc 100644 --- a/core/grid.js +++ b/core/grid.js @@ -27,7 +27,7 @@ goog.provide('Blockly.Grid'); -goog.require('Blockly.utils'); +goog.provide('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); @@ -208,22 +208,22 @@ Blockly.Grid.createDom = function(rnd, gridOptions, defs) { */ - var gridPattern = Blockly.utils.createSvgElement('pattern', + var gridPattern = Blockly.utils.dom.createSvgElement('pattern', { 'id': 'blocklyGridPattern' + rnd, 'patternUnits': 'userSpaceOnUse' }, defs); if (gridOptions['length'] > 0 && gridOptions['spacing'] > 0) { - Blockly.utils.createSvgElement('line', + Blockly.utils.dom.createSvgElement('line', {'stroke': gridOptions['colour']}, gridPattern); if (gridOptions['length'] > 1) { - Blockly.utils.createSvgElement('line', + Blockly.utils.dom.createSvgElement('line', {'stroke': gridOptions['colour']}, gridPattern); } // x1, y1, x1, x2 properties will be set later in update. } else { // Edge 16 doesn't handle empty patterns - Blockly.utils.createSvgElement('line', {}, gridPattern); + Blockly.utils.dom.createSvgElement('line', {}, gridPattern); } return gridPattern; }; diff --git a/core/icon.js b/core/icon.js index 85d9dc44556..73f3df6095e 100644 --- a/core/icon.js +++ b/core/icon.js @@ -77,7 +77,7 @@ Blockly.Icon.prototype.createIcon = function() { ... */ - this.iconGroup_ = Blockly.utils.createSvgElement('g', + this.iconGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyIconGroup'}, null); if (this.block_.isInFlyout) { Blockly.utils.dom.addClass( diff --git a/core/inject.js b/core/inject.js index e68ec6e7a32..61df917db2c 100644 --- a/core/inject.js +++ b/core/inject.js @@ -112,7 +112,7 @@ Blockly.createDom_ = function(container, options) { ... */ - var svg = Blockly.utils.createSvgElement('svg', { + var svg = Blockly.utils.dom.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', @@ -124,7 +124,7 @@ Blockly.createDom_ = function(container, options) { ... filters go here ... */ - var defs = Blockly.utils.createSvgElement('defs', {}, svg); + var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg); // Each filter/pattern needs a unique ID for the case of multiple Blockly // instances on a page. Browser behaviour becomes undefined otherwise. // https://neil.fraser.name/news/2015/11/01/ @@ -143,11 +143,11 @@ Blockly.createDom_ = function(container, options) { k1="0" k2="1" k3="1" k4="0" /> */ - var embossFilter = Blockly.utils.createSvgElement('filter', + var embossFilter = Blockly.utils.dom.createSvgElement('filter', {'id': 'blocklyEmbossFilter' + rnd}, defs); - Blockly.utils.createSvgElement('feGaussianBlur', + Blockly.utils.dom.createSvgElement('feGaussianBlur', {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter); - var feSpecularLighting = Blockly.utils.createSvgElement('feSpecularLighting', + var feSpecularLighting = Blockly.utils.dom.createSvgElement('feSpecularLighting', { 'in': 'blur', 'surfaceScale': 1, @@ -157,16 +157,16 @@ Blockly.createDom_ = function(container, options) { 'result': 'specOut' }, embossFilter); - Blockly.utils.createSvgElement('fePointLight', + Blockly.utils.dom.createSvgElement('fePointLight', {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting); - Blockly.utils.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement('feComposite', { 'in': 'specOut', 'in2': 'SourceAlpha', 'operator': 'in', 'result': 'specOut' }, embossFilter); - Blockly.utils.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement('feComposite', { 'in': 'SourceGraphic', 'in2': 'specOut', @@ -184,16 +184,16 @@ Blockly.createDom_ = function(container, options) { */ - var disabledPattern = Blockly.utils.createSvgElement('pattern', + var disabledPattern = Blockly.utils.dom.createSvgElement('pattern', { 'id': 'blocklyDisabledPattern' + rnd, 'patternUnits': 'userSpaceOnUse', 'width': 10, 'height': 10 }, defs); - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern); - Blockly.utils.createSvgElement('path', + Blockly.utils.dom.createSvgElement('path', {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern); options.disabledPatternId = disabledPattern.id; diff --git a/core/mutator.js b/core/mutator.js index 5247706c0e0..186e9d276c7 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -70,7 +70,7 @@ Blockly.Mutator.prototype.workspaceHeight_ = 0; */ Blockly.Mutator.prototype.drawIcon_ = function(group) { // Square with rounded corners. - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyIconShape', 'rx': '4', @@ -80,7 +80,7 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) { }, group); // Gear teeth. - Blockly.utils.createSvgElement('path', + Blockly.utils.dom.createSvgElement('path', { 'class': 'blocklyIconSymbol', 'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' + @@ -93,7 +93,7 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) { }, group); // Axle hole. - Blockly.utils.createSvgElement( + Blockly.utils.dom.createSvgElement( 'circle', { 'class': 'blocklyIconShape', @@ -128,7 +128,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { [Workspace] */ - this.svgDialog_ = Blockly.utils.createSvgElement('svg', + this.svgDialog_ = Blockly.utils.dom.createSvgElement('svg', {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); // Convert the list of names into a list of XML objects for the flyout. diff --git a/core/rendered_connection.js b/core/rendered_connection.js index f180cfdead6..6dba6612313 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -210,7 +210,7 @@ Blockly.RenderedConnection.prototype.highlight = function() { var xy = this.sourceBlock_.getRelativeToSurfaceXY(); var x = this.x_ - xy.x; var y = this.y_ - xy.y; - Blockly.Connection.highlightedPath_ = Blockly.utils.createSvgElement( + Blockly.Connection.highlightedPath_ = Blockly.utils.dom.createSvgElement( 'path', { 'class': 'blocklyHighlightedConnectionPath', diff --git a/core/scrollbar.js b/core/scrollbar.js index 11e5ecf2d4a..7ea608a9bee 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -49,7 +49,7 @@ Blockly.ScrollbarPair = function(workspace) { workspace, true, true, 'blocklyMainWorkspaceScrollbar'); this.vScroll = new Blockly.Scrollbar( workspace, false, true, 'blocklyMainWorkspaceScrollbar'); - this.corner_ = Blockly.utils.createSvgElement( + this.corner_ = Blockly.utils.dom.createSvgElement( 'rect', { 'height': Blockly.Scrollbar.scrollbarThickness, @@ -410,7 +410,7 @@ Blockly.Scrollbar.prototype.setPosition_ = function(x, y) { var tempX = this.position_.x + this.origin_.x; var tempY = this.position_.y + this.origin_.y; var transform = 'translate(' + tempX + 'px,' + tempY + 'px)'; - Blockly.utils.setCssTransform(this.outerSvg_, transform); + Blockly.utils.dom.setCssTransform(this.outerSvg_, transform); }; /** @@ -611,13 +611,13 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { if (opt_class) { className += ' ' + opt_class; } - this.outerSvg_ = Blockly.utils.createSvgElement( + this.outerSvg_ = Blockly.utils.dom.createSvgElement( 'svg', {'class': className}, null); - this.svgGroup_ = Blockly.utils.createSvgElement('g', {}, this.outerSvg_); - this.svgBackground_ = Blockly.utils.createSvgElement( + this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {}, this.outerSvg_); + this.svgBackground_ = Blockly.utils.dom.createSvgElement( 'rect', {'class': 'blocklyScrollbarBackground'}, this.svgGroup_); var radius = Math.floor((Blockly.Scrollbar.scrollbarThickness - 5) / 2); - this.svgHandle_ = Blockly.utils.createSvgElement( + this.svgHandle_ = Blockly.utils.dom.createSvgElement( 'rect', { 'class': 'blocklyScrollbarHandle', diff --git a/core/trashcan.js b/core/trashcan.js index b5c13c0a199..035ff9e7779 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -26,7 +26,6 @@ goog.provide('Blockly.Trashcan'); -goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.Rect'); goog.require('Blockly.Xml'); @@ -225,21 +224,21 @@ Blockly.Trashcan.prototype.createDom = function() { clip-path="url(#blocklyTrashLidClipPath837493)"> */ - this.svgGroup_ = Blockly.utils.createSvgElement('g', + this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyTrash'}, null); var clip; var rnd = String(Math.random()).substring(2); - clip = Blockly.utils.createSvgElement('clipPath', + clip = Blockly.utils.dom.createSvgElement('clipPath', {'id': 'blocklyTrashBodyClipPath' + rnd}, this.svgGroup_); - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'width': this.WIDTH_, 'height': this.BODY_HEIGHT_, 'y': this.LID_HEIGHT_ }, clip); - var body = Blockly.utils.createSvgElement('image', + var body = Blockly.utils.dom.createSvgElement('image', { 'width': Blockly.SPRITE.width, 'x': -this.SPRITE_LEFT_, @@ -251,12 +250,12 @@ Blockly.Trashcan.prototype.createDom = function() { body.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', this.workspace_.options.pathToMedia + Blockly.SPRITE.url); - clip = Blockly.utils.createSvgElement('clipPath', + clip = Blockly.utils.dom.createSvgElement('clipPath', {'id': 'blocklyTrashLidClipPath' + rnd}, this.svgGroup_); - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', {'width': this.WIDTH_, 'height': this.LID_HEIGHT_}, clip); - this.svgLid_ = Blockly.utils.createSvgElement('image', + this.svgLid_ = Blockly.utils.dom.createSvgElement('image', { 'width': Blockly.SPRITE.width, 'x': -this.SPRITE_LEFT_, diff --git a/core/utils.js b/core/utils.js index f2c3f18da76..278121e2009 100644 --- a/core/utils.js +++ b/core/utils.js @@ -151,31 +151,6 @@ Blockly.utils.getRelativeXY.XY_REGEX_ = Blockly.utils.getRelativeXY.XY_STYLE_REGEX_ = /transform:\s*translate(?:3d)?\(\s*([-+\d.e]+)\s*px([ ,]\s*([-+\d.e]+)\s*px)?/; -/** - * Helper method for creating SVG elements. - * @param {string} name Element's tag name. - * @param {!Object} attrs Dictionary of attribute names and values. - * @param {Element} parent Optional parent on which to append the element. - * @return {!SVGElement} Newly created SVG element. - */ -Blockly.utils.createSvgElement = function(name, attrs, parent) { - var e = /** @type {!SVGElement} */ - (document.createElementNS(Blockly.SVG_NS, name)); - for (var key in attrs) { - e.setAttribute(key, attrs[key]); - } - // IE defines a unique attribute "runtimeStyle", it is NOT applied to - // elements created with createElementNS. However, Closure checks for IE - // and assumes the presence of the attribute and crashes. - if (document.body.runtimeStyle) { // Indicates presence of IE-only attr. - e.runtimeStyle = e.currentStyle = e.style; - } - if (parent) { - parent.appendChild(e); - } - return e; -}; - /** * Is this event a right-click? * @param {!Event} e Mouse event. @@ -539,18 +514,6 @@ Blockly.utils.runAfterPageLoad = function(fn) { } }; -/** - * Sets the CSS transform property on an element. This function sets the - * non-vendor-prefixed and vendor-prefixed versions for backwards compatibility - * with older browsers. See https://caniuse.com/#feat=transforms2d - * @param {!Element} node The node which the CSS transform should be applied. - * @param {string} transform The value of the CSS `transform` property. - */ -Blockly.utils.setCssTransform = function(node, transform) { - node.style['transform'] = transform; - node.style['-webkit-transform'] = transform; -}; - /** * Get the position of the current viewport in window coordinates. This takes * scroll into account. diff --git a/core/utils/dom.js b/core/utils/dom.js index 9151d4499ec..eff026f0def 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -33,6 +33,43 @@ goog.provide('Blockly.utils.dom'); +/** + * Required name space for SVG elements. + * @const + */ +Blockly.utils.dom.SVG_NS = 'http://www.w3.org/2000/svg'; + +/** + * Required name space for HTML elements. + * @const + */ +Blockly.utils.dom.HTML_NS = 'http://www.w3.org/1999/xhtml'; + +/** + * Helper method for creating SVG elements. + * @param {string} name Element's tag name. + * @param {!Object} attrs Dictionary of attribute names and values. + * @param {Element} parent Optional parent on which to append the element. + * @return {!SVGElement} Newly created SVG element. + */ +Blockly.utils.dom.createSvgElement = function(name, attrs, parent) { + var e = /** @type {!SVGElement} */ + (document.createElementNS(Blockly.utils.dom.SVG_NS, name)); + for (var key in attrs) { + e.setAttribute(key, attrs[key]); + } + // IE defines a unique attribute "runtimeStyle", it is NOT applied to + // elements created with createElementNS. However, Closure checks for IE + // and assumes the presence of the attribute and crashes. + if (document.body.runtimeStyle) { // Indicates presence of IE-only attr. + e.runtimeStyle = e.currentStyle = e.style; + } + if (parent) { + parent.appendChild(e); + } + return e; +}; + /** * Add a CSS class to a element. * Similar to Closure's goog.dom.classes.add, except it handles SVG elements. @@ -130,3 +167,15 @@ Blockly.utils.dom.containsNode = function(parent, descendant) { return !!(parent.compareDocumentPosition(descendant) & Node.DOCUMENT_POSITION_CONTAINED_BY); }; + +/** + * Sets the CSS transform property on an element. This function sets the + * non-vendor-prefixed and vendor-prefixed versions for backwards compatibility + * with older browsers. See https://caniuse.com/#feat=transforms2d + * @param {!Element} element Element to which the CSS transform will be applied. + * @param {string} transform The value of the CSS `transform` property. + */ +Blockly.utils.dom.setCssTransform = function(element, transform) { + element.style['transform'] = transform; + element.style['-webkit-transform'] = transform; +}; diff --git a/core/warning.js b/core/warning.js index f1633c06ea3..551bda5dfc3 100644 --- a/core/warning.js +++ b/core/warning.js @@ -30,7 +30,7 @@ goog.require('Blockly.Bubble'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); -goog.require('Blockly.utils'); +goog.provide('Blockly.utils.dom'); /** @@ -59,7 +59,7 @@ Blockly.Warning.prototype.collapseHidden = false; */ Blockly.Warning.prototype.drawIcon_ = function(group) { // Triangle with rounded corners. - Blockly.utils.createSvgElement('path', + Blockly.utils.dom.createSvgElement('path', { 'class': 'blocklyIconShape', 'd': 'M2,15Q-1,15 0.5,12L6.5,1.7Q8,-1 9.5,1.7L15.5,12Q17,15 14,15z' @@ -68,14 +68,14 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { // Can't use a real '!' text character since different browsers and operating // systems render it differently. // Body of exclamation point. - Blockly.utils.createSvgElement('path', + Blockly.utils.dom.createSvgElement('path', { 'class': 'blocklyIconSymbol', 'd': 'm7,4.8v3.16l0.27,2.27h1.46l0.27,-2.27v-3.16z' }, group); // Dot of exclamation point. - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyIconSymbol', 'x': '7', 'y': '11', 'height': '2', 'width': '2' @@ -91,7 +91,7 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { */ Blockly.Warning.textToDom_ = function(text) { var paragraph = /** @type {!SVGTextElement} */ - (Blockly.utils.createSvgElement( + (Blockly.utils.dom.createSvgElement( 'text', { 'class': 'blocklyText blocklyBubbleText', @@ -101,7 +101,7 @@ Blockly.Warning.textToDom_ = function(text) { ); var lines = text.split('\n'); for (var i = 0; i < lines.length; i++) { - var tspanElement = Blockly.utils.createSvgElement('tspan', + var tspanElement = Blockly.utils.dom.createSvgElement('tspan', {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); var textNode = document.createTextNode(lines[i]); tspanElement.appendChild(textNode); diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index 0742d8675e0..de5bdec3abb 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -89,14 +89,14 @@ Blockly.WorkspaceCommentSvg.prototype.render = function() { this.createEditor_(); this.svgGroup_.appendChild(this.foreignObject_); - this.svgHandleTarget_ = Blockly.utils.createSvgElement('rect', + this.svgHandleTarget_ = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyCommentHandleTarget', 'x': 0, 'y': 0 }); this.svgGroup_.appendChild(this.svgHandleTarget_); - this.svgRectTarget_ = Blockly.utils.createSvgElement('rect', + this.svgRectTarget_ = Blockly.utils.dom.createSvgElement('rect', { 'class': 'blocklyCommentTarget', 'x': 0, @@ -150,7 +150,7 @@ Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() { */ - this.foreignObject_ = Blockly.utils.createSvgElement( + this.foreignObject_ = Blockly.utils.dom.createSvgElement( 'foreignObject', { 'x': 0, @@ -158,10 +158,10 @@ Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() { 'class': 'blocklyCommentForeignObject' }, null); - var body = document.createElementNS(Blockly.HTML_NS, 'body'); - body.setAttribute('xmlns', Blockly.HTML_NS); + var body = document.createElementNS(Blockly.utils.dom.HTML_NS, 'body'); + body.setAttribute('xmlns', Blockly.utils.dom.HTML_NS); body.className = 'blocklyMinimalBody'; - var textarea = document.createElementNS(Blockly.HTML_NS, 'textarea'); + var textarea = document.createElementNS(Blockly.utils.dom.HTML_NS, 'textarea'); textarea.className = 'blocklyCommentTextarea'; textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR'); body.appendChild(textarea); @@ -184,25 +184,25 @@ Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() { * @private */ Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() { - this.resizeGroup_ = Blockly.utils.createSvgElement( + this.resizeGroup_ = Blockly.utils.dom.createSvgElement( 'g', { 'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE' }, this.svgGroup_); var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE; - Blockly.utils.createSvgElement( + Blockly.utils.dom.createSvgElement( 'polygon', {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, this.resizeGroup_); - Blockly.utils.createSvgElement( + Blockly.utils.dom.createSvgElement( 'line', { 'class': 'blocklyResizeLine', 'x1': resizeSize / 3, 'y1': resizeSize - 1, 'x2': resizeSize - 1, 'y2': resizeSize / 3 }, this.resizeGroup_); - Blockly.utils.createSvgElement( + Blockly.utils.dom.createSvgElement( 'line', { 'class': 'blocklyResizeLine', @@ -216,13 +216,13 @@ Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() { * @private */ Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { - this.deleteGroup_ = Blockly.utils.createSvgElement( + this.deleteGroup_ = Blockly.utils.dom.createSvgElement( 'g', { 'class': 'blocklyCommentDeleteIcon' }, this.svgGroup_); - this.deleteIconBorder_ = Blockly.utils.createSvgElement('circle', + this.deleteIconBorder_ = Blockly.utils.dom.createSvgElement('circle', { 'class': 'blocklyDeleteIconShape', 'r': '7', @@ -231,7 +231,7 @@ Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { }, this.deleteGroup_); // x icon. - Blockly.utils.createSvgElement( + Blockly.utils.dom.createSvgElement( 'line', { 'x1': '5', 'y1': '10', @@ -240,7 +240,7 @@ Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { 'stroke-width': '2' }, this.deleteGroup_); - Blockly.utils.createSvgElement( + Blockly.utils.dom.createSvgElement( 'line', { 'x1': '5', 'y1': '5', diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 59e28d8e74c..3469c1deb59 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -55,11 +55,11 @@ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width, * @type {SVGElement} * @private */ - this.svgGroup_ = Blockly.utils.createSvgElement( + this.svgGroup_ = Blockly.utils.dom.createSvgElement( 'g', {'class': 'blocklyComment'}, null); this.svgGroup_.translate_ = ''; - this.svgRect_ = Blockly.utils.createSvgElement( + this.svgRect_ = Blockly.utils.dom.createSvgElement( 'rect', { 'class': 'blocklyCommentRect', diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index 4766a9dec0c..fbf7c3245f3 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -86,10 +86,10 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.createDom = function() { * /g> * */ - this.SVG_ = Blockly.utils.createSvgElement('svg', + this.SVG_ = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': Blockly.SVG_NS, - 'xmlns:html': Blockly.HTML_NS, + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'version': '1.1', 'class': 'blocklyWsDragSurface blocklyOverflowVisible' @@ -113,7 +113,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) { var fixedY = y.toFixed(0); this.SVG_.style.display = 'block'; - Blockly.utils.setCssTransform( + Blockly.utils.dom.setCssTransform( this.SVG_, 'translate3d(' + fixedX + 'px, ' + fixedY + 'px, 0px)'); }; @@ -163,7 +163,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { if (this.SVG_.childNodes.length) { throw Error('Drag surface was not cleared.'); } - Blockly.utils.setCssTransform(this.SVG_, ''); + Blockly.utils.dom.setCssTransform(this.SVG_, ''); this.previousSibling_ = null; }; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 9498a6f8508..bcbe7291865 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -515,7 +515,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { * * @type {SVGElement} */ - this.svgGroup_ = Blockly.utils.createSvgElement('g', + this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyWorkspace'}, null); // Note that a alone does not receive mouse events--it must have a @@ -523,7 +523,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { // flyout, the workspace will not receive mouse events. if (opt_backgroundClass) { /** @type {SVGElement} */ - this.svgBackground_ = Blockly.utils.createSvgElement('rect', + this.svgBackground_ = Blockly.utils.dom.createSvgElement('rect', {'height': '100%', 'width': '100%', 'class': opt_backgroundClass}, this.svgGroup_); @@ -533,10 +533,10 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { } } /** @type {SVGElement} */ - this.svgBlockCanvas_ = Blockly.utils.createSvgElement('g', + this.svgBlockCanvas_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyBlockCanvas'}, this.svgGroup_); /** @type {SVGElement} */ - this.svgBubbleCanvas_ = Blockly.utils.createSvgElement('g', + this.svgBubbleCanvas_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyBubbleCanvas'}, this.svgGroup_); if (!this.isFlyout) { diff --git a/core/zoom_controls.js b/core/zoom_controls.js index c9a68e70280..3c1e85e82af 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -27,7 +27,6 @@ goog.provide('Blockly.ZoomControls'); goog.require('Blockly.Touch'); -goog.require('Blockly.utils'); goog.require('Blockly.utils.dom'); @@ -95,7 +94,7 @@ Blockly.ZoomControls.prototype.top_ = 0; */ Blockly.ZoomControls.prototype.createDom = function() { this.svgGroup_ = - Blockly.utils.createSvgElement('g', {}, null); + Blockly.utils.dom.createSvgElement('g', {}, null); // Each filter/pattern needs a unique ID for the case of multiple Blockly // instances on a page. Browser behaviour becomes undefined otherwise. @@ -195,20 +194,20 @@ Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) { */ var ws = this.workspace_; - this.zoomOutGroup_ = Blockly.utils.createSvgElement('g', + this.zoomOutGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyZoom'}, this.svgGroup_); - var clip = Blockly.utils.createSvgElement('clipPath', + var clip = Blockly.utils.dom.createSvgElement('clipPath', { 'id': 'blocklyZoomoutClipPath' + rnd }, this.zoomOutGroup_); - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'width': 32, 'height': 32, }, clip); - var zoomoutSvg = Blockly.utils.createSvgElement('image', + var zoomoutSvg = Blockly.utils.dom.createSvgElement('image', { 'width': Blockly.SPRITE.width, 'height': Blockly.SPRITE.height, @@ -248,20 +247,20 @@ Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) { */ var ws = this.workspace_; - this.zoomInGroup_ = Blockly.utils.createSvgElement('g', + this.zoomInGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyZoom'}, this.svgGroup_); - var clip = Blockly.utils.createSvgElement('clipPath', + var clip = Blockly.utils.dom.createSvgElement('clipPath', { 'id': 'blocklyZoominClipPath' + rnd }, this.zoomInGroup_); - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'width': 32, 'height': 32, }, clip); - var zoominSvg = Blockly.utils.createSvgElement('image', + var zoominSvg = Blockly.utils.dom.createSvgElement('image', { 'width': Blockly.SPRITE.width, 'height': Blockly.SPRITE.height, @@ -301,20 +300,20 @@ Blockly.ZoomControls.prototype.createZoomResetSvg_ = function(rnd) { */ var ws = this.workspace_; - this.zoomResetGroup_ = Blockly.utils.createSvgElement('g', + this.zoomResetGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': 'blocklyZoom'}, this.svgGroup_); - var clip = Blockly.utils.createSvgElement('clipPath', + var clip = Blockly.utils.dom.createSvgElement('clipPath', { 'id': 'blocklyZoomresetClipPath' + rnd }, this.zoomResetGroup_); - Blockly.utils.createSvgElement('rect', + Blockly.utils.dom.createSvgElement('rect', { 'width': 32, 'height': 32 }, clip); - var zoomresetSvg = Blockly.utils.createSvgElement('image', + var zoomresetSvg = Blockly.utils.dom.createSvgElement('image', { 'width': Blockly.SPRITE.width, 'height': Blockly.SPRITE.height, From 98a98bcce6e350bdb12b485e2ac4e9b4dd16635c Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 7 Jun 2019 01:51:53 -0700 Subject: [PATCH 119/233] Add Blockly.utils.dom.XLINK_NS And fix provide/require mixup. --- core/block_drag_surface.js | 2 +- core/comment.js | 2 +- core/field_angle.js | 8 ++++---- core/field_dropdown.js | 2 +- core/field_image.js | 4 ++-- core/grid.js | 2 +- core/inject.js | 6 +++--- core/trashcan.js | 4 ++-- core/utils/dom.js | 6 ++++++ core/warning.js | 2 +- core/workspace_drag_surface_svg.js | 2 +- core/zoom_controls.js | 6 +++--- 12 files changed, 26 insertions(+), 20 deletions(-) diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index a9c46c24431..d80924d9024 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -99,7 +99,7 @@ Blockly.BlockDragSurfaceSvg.prototype.createDom = function() { this.SVG_ = Blockly.utils.dom.createSvgElement('svg', { 'xmlns': Blockly.utils.dom.SVG_NS, 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, 'version': '1.1', 'class': 'blocklyBlockDragSurface' }, this.container_); diff --git a/core/comment.js b/core/comment.js index f587cc78d8a..80e4ed1d1af 100644 --- a/core/comment.js +++ b/core/comment.js @@ -31,7 +31,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); -goog.provide('Blockly.utils.dom'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); diff --git a/core/field_angle.js b/core/field_angle.js index 6c44deb8bac..36ca268dc6d 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -28,7 +28,7 @@ goog.provide('Blockly.FieldAngle'); goog.require('Blockly.DropDownDiv'); goog.require('Blockly.FieldTextInput'); -goog.provide('Blockly.utils.dom'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.math'); goog.require('Blockly.utils.userAgent'); @@ -177,9 +177,9 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { // Build the SVG DOM. var svg = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': 'http://www.w3.org/2000/svg', - 'xmlns:html': 'http://www.w3.org/1999/xhtml', - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, 'version': '1.1', 'height': (Blockly.FieldAngle.HALF * 2) + 'px', 'width': (Blockly.FieldAngle.HALF * 2) + 'px' diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 610fb3c8d62..be5ccfaad2f 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -476,7 +476,7 @@ Blockly.FieldDropdown.prototype.render_ = function() { */ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function() { this.imageElement_.setAttributeNS( - 'http://www.w3.org/1999/xlink', 'xlink:href', this.imageJson_.src); + Blockly.utils.dom.XLINK_NS, 'xlink:href', this.imageJson_.src); this.imageElement_.setAttribute('height', this.imageJson_.height); this.imageElement_.setAttribute('width', this.imageJson_.width); diff --git a/core/field_image.js b/core/field_image.js index 098ff1d2a7d..cc4ba061736 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -125,7 +125,7 @@ Blockly.FieldImage.prototype.initView = function() { 'alt': this.text_ }, this.fieldGroup_); - this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', + this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', this.value_); }; @@ -161,7 +161,7 @@ Blockly.FieldImage.prototype.doClassValidation_ = function(newValue) { Blockly.FieldImage.prototype.doValueUpdate_ = function(newValue) { this.value_ = newValue; if (this.imageElement_) { - this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', + this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', this.value_ || ''); } }; diff --git a/core/grid.js b/core/grid.js index 2e78cb819dc..f8d7bee7437 100644 --- a/core/grid.js +++ b/core/grid.js @@ -27,7 +27,7 @@ goog.provide('Blockly.Grid'); -goog.provide('Blockly.utils.dom'); +goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.userAgent'); diff --git a/core/inject.js b/core/inject.js index 61df917db2c..e40d110e5ed 100644 --- a/core/inject.js +++ b/core/inject.js @@ -113,9 +113,9 @@ Blockly.createDom_ = function(container, options) { */ var svg = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': 'http://www.w3.org/2000/svg', - 'xmlns:html': 'http://www.w3.org/1999/xhtml', - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, 'version': '1.1', 'class': 'blocklySvg' }, container); diff --git a/core/trashcan.js b/core/trashcan.js index 035ff9e7779..d97c1ceaeda 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -247,7 +247,7 @@ Blockly.Trashcan.prototype.createDom = function() { 'clip-path': 'url(#blocklyTrashBodyClipPath' + rnd + ')' }, this.svgGroup_); - body.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', + body.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', this.workspace_.options.pathToMedia + Blockly.SPRITE.url); clip = Blockly.utils.dom.createSvgElement('clipPath', @@ -264,7 +264,7 @@ Blockly.Trashcan.prototype.createDom = function() { 'clip-path': 'url(#blocklyTrashLidClipPath' + rnd + ')' }, this.svgGroup_); - this.svgLid_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', + this.svgLid_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', this.workspace_.options.pathToMedia + Blockly.SPRITE.url); Blockly.bindEventWithChecks_(this.svgGroup_, 'mouseup', this, this.click); diff --git a/core/utils/dom.js b/core/utils/dom.js index eff026f0def..3a9b0013ebb 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -45,6 +45,12 @@ Blockly.utils.dom.SVG_NS = 'http://www.w3.org/2000/svg'; */ Blockly.utils.dom.HTML_NS = 'http://www.w3.org/1999/xhtml'; +/** + * Required name space for XLINK elements. + * @const + */ +Blockly.utils.dom.XLINK_NS = 'http://www.w3.org/1999/xlink'; + /** * Helper method for creating SVG elements. * @param {string} name Element's tag name. diff --git a/core/warning.js b/core/warning.js index 551bda5dfc3..dae39898c54 100644 --- a/core/warning.js +++ b/core/warning.js @@ -30,7 +30,7 @@ goog.require('Blockly.Bubble'); goog.require('Blockly.Events'); goog.require('Blockly.Events.Ui'); goog.require('Blockly.Icon'); -goog.provide('Blockly.utils.dom'); +goog.require('Blockly.utils.dom'); /** diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index fbf7c3245f3..6c8f567aaf8 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -90,7 +90,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.createDom = function() { { 'xmlns': Blockly.utils.dom.SVG_NS, 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, 'version': '1.1', 'class': 'blocklyWsDragSurface blocklyOverflowVisible' }, null); diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 3c1e85e82af..46566b441a9 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -216,7 +216,7 @@ Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) { 'clip-path': 'url(#blocklyZoomoutClipPath' + rnd + ')' }, this.zoomOutGroup_); - zoomoutSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', + zoomoutSvg.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', ws.options.pathToMedia + Blockly.SPRITE.url); // Attach listener. @@ -269,7 +269,7 @@ Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) { 'clip-path': 'url(#blocklyZoominClipPath' + rnd + ')' }, this.zoomInGroup_); - zoominSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', + zoominSvg.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', ws.options.pathToMedia + Blockly.SPRITE.url); // Attach listener. @@ -321,7 +321,7 @@ Blockly.ZoomControls.prototype.createZoomResetSvg_ = function(rnd) { 'clip-path': 'url(#blocklyZoomresetClipPath' + rnd + ')' }, this.zoomResetGroup_); - zoomresetSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', + zoomresetSvg.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', ws.options.pathToMedia + Blockly.SPRITE.url); // Attach event listeners. From 6947010c49444627c2e202ead889eef15dca1f2f Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 7 Jun 2019 02:39:04 -0700 Subject: [PATCH 120/233] Change Rect to use top/bottom/left/right Instead of top/left/height/width. Given our uses of Rect, it makes the math slightly simpler. This is a setup for using Rect in other places. Currently it is only used to describe delete areas. --- core/flyout_horizontal.js | 13 +++++-------- core/flyout_vertical.js | 13 ++++++------- core/toolbox.js | 26 ++++++++++++-------------- core/trashcan.js | 9 +++++---- core/utils/rect.js | 21 ++++++++++----------- 5 files changed, 38 insertions(+), 44 deletions(-) diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index 4b10c05f2da..adb1f29b502 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -347,17 +347,14 @@ Blockly.HorizontalFlyout.prototype.getClientRect = function() { // area are still deleted. Must be larger than the largest screen size, // but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE). var BIG_NUM = 1000000000; - var y = flyoutRect.top; - var height = flyoutRect.height; + var top = flyoutRect.top; if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) { - return new Blockly.utils.Rect(-BIG_NUM, y - BIG_NUM, BIG_NUM * 2, - BIG_NUM + height); - } else if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_BOTTOM) { - return new Blockly.utils.Rect(-BIG_NUM, y, BIG_NUM * 2, - BIG_NUM + height); + var height = flyoutRect.height; + return new Blockly.utils.Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM); + } else { // Bottom. + return new Blockly.utils.Rect(top, -BIG_NUM, -BIG_NUM, BIG_NUM); } - // TODO: Else throw error (should never happen). }; /** diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index c892e314e8f..fbf2720de67 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -325,12 +325,11 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { // area are still deleted. Must be larger than the largest screen size, // but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE). var BIG_NUM = 1000000000; - var x = flyoutRect.left; - var width = flyoutRect.width; + var left = flyoutRect.left; if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) { - return new Blockly.utils.Rect(x - BIG_NUM, -BIG_NUM, BIG_NUM + width, - BIG_NUM * 2); + var width = flyoutRect.width; + return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width); } else { // Right // Firefox sometimes reports the wrong value for the client rect. // See https://github.com/google/blockly/issues/1425 and @@ -348,15 +347,15 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() { // visible area of the workspace should be more than ten pixels wide. If // the browser reports that the flyout is within ten pixels of the left // side of the workspace, ignore it and manually calculate the value. - if (Math.abs(targetWsLeftPixels - x) < 10) { + if (Math.abs(targetWsLeftPixels - left) < 10) { // If we're in a mutator, its scale is always 1, purely because of some // oddities in our rendering optimizations. The actual scale is the // same as the scale on the parent workspace. var scale = this.targetWorkspace_.options.parentWorkspace.scale; - x = x + this.leftEdge_ * scale; + left += this.leftEdge_ * scale; } } - return new Blockly.utils.Rect(x, -BIG_NUM, BIG_NUM + width, BIG_NUM * 2); + return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM); } }; diff --git a/core/toolbox.js b/core/toolbox.js index 92ad7a91c67..edb37d3bc8f 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -545,23 +545,21 @@ Blockly.Toolbox.prototype.getClientRect = function() { var BIG_NUM = 10000000; var toolboxRect = this.HtmlDiv.getBoundingClientRect(); - var x = toolboxRect.left; - var y = toolboxRect.top; - var width = toolboxRect.width; - var height = toolboxRect.height; + var top = toolboxRect.top; + var bottom = top + toolboxRect.height; + var left = toolboxRect.left; + var right = left + toolboxRect.width; // Assumes that the toolbox is on the SVG edge. If this changes // (e.g. toolboxes in mutators) then this code will need to be more complex. - if (this.toolboxPosition == Blockly.TOOLBOX_AT_LEFT) { - return new Blockly.utils.Rect(-BIG_NUM, -BIG_NUM, BIG_NUM + x + width, - 2 * BIG_NUM); - } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT) { - return new Blockly.utils.Rect(x, -BIG_NUM, BIG_NUM + width, 2 * BIG_NUM); - } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_TOP) { - return new Blockly.utils.Rect(-BIG_NUM, -BIG_NUM, 2 * BIG_NUM, - BIG_NUM + y + height); - } else { // Bottom - return new Blockly.utils.Rect(0, y, 2 * BIG_NUM, BIG_NUM + width); + if (this.toolboxPosition == Blockly.TOOLBOX_AT_TOP) { + return new Blockly.utils.Rect(-BIG_NUM, bottom, -BIG_NUM, BIG_NUM); + } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_BOTTOM) { + return new Blockly.utils.Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM); + } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_LEFT) { + return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, right); + } else { // Right + return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM); } }; diff --git a/core/trashcan.js b/core/trashcan.js index d97c1ceaeda..956c21e4364 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -361,11 +361,12 @@ Blockly.Trashcan.prototype.getClientRect = function() { } var trashRect = this.svgGroup_.getBoundingClientRect(); - var left = trashRect.left + this.SPRITE_LEFT_ - this.MARGIN_HOTSPOT_; var top = trashRect.top + this.SPRITE_TOP_ - this.MARGIN_HOTSPOT_; - var width = this.WIDTH_ + 2 * this.MARGIN_HOTSPOT_; - var height = this.LID_HEIGHT_ + this.BODY_HEIGHT_ + 2 * this.MARGIN_HOTSPOT_; - return new Blockly.utils.Rect(left, top, width, height); + var bottom = top + this.LID_HEIGHT_ + this.BODY_HEIGHT_ + + 2 * this.MARGIN_HOTSPOT_; + var left = trashRect.left + this.SPRITE_LEFT_ - this.MARGIN_HOTSPOT_; + var right = left + this.WIDTH_ + 2 * this.MARGIN_HOTSPOT_; + return new Blockly.utils.Rect(top, bottom, left, right); }; /** diff --git a/core/utils/rect.js b/core/utils/rect.js index bc87b5abc7f..ff09cd44fa8 100644 --- a/core/utils/rect.js +++ b/core/utils/rect.js @@ -35,25 +35,25 @@ goog.provide('Blockly.utils.Rect'); /** * Class for representing rectangular regions. - * @param {number} x Left. - * @param {number} y Top. - * @param {number} w Width. - * @param {number} h Height. + * @param {number} top Top. + * @param {number} bottom Bottom. + * @param {number} left Left. + * @param {number} right Right. * @struct * @constructor */ -Blockly.utils.Rect = function(x, y, w, h) { +Blockly.utils.Rect = function(top, bottom, left, right) { /** @type {number} */ - this.left = x; + this.top = top; /** @type {number} */ - this.top = y; + this.bottom = bottom; /** @type {number} */ - this.width = w; + this.left = left; /** @type {number} */ - this.height = h; + this.right = right; }; /** @@ -64,6 +64,5 @@ Blockly.utils.Rect = function(x, y, w, h) { * @return {boolean} Whether this rectangle contains given coordinate. */ Blockly.utils.Rect.prototype.contains = function(x, y) { - return x >= this.left && x <= this.left + this.width && - y >= this.top && y <= this.top + this.height; + return x >= this.left && x <= this.right && y >= this.top && y <= this.bottom; }; From 0213de11bcc22a96d2e6978c41077817cd92c438 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Fri, 7 Jun 2019 02:51:25 -0700 Subject: [PATCH 121/233] Use Rect in more places. --- core/block_svg.js | 6 +++--- core/inject.js | 3 +-- core/workspace_comment_svg.js | 6 +++--- core/workspace_svg.js | 19 ++++++++++--------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 347a56be79e..c340576be21 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -40,6 +40,7 @@ goog.require('Blockly.Touch'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.Rect'); /** @@ -469,8 +470,7 @@ Blockly.BlockSvg.prototype.snapToGrid = function() { * Returns the coordinates of a bounding box describing the dimensions of this * block and any blocks stacked below it. * Coordinate system: workspace coordinates. - * @return {!{top: number, bottom: number, left: number, right: number}} - * Object with top, bottom, left, and right coordinates of the bounding box. + * @return {!Blockly.utils.Rect} Object with coordinates of the bounding box. */ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { var blockXY = this.getRelativeToSurfaceXY(this); @@ -492,7 +492,7 @@ Blockly.BlockSvg.prototype.getBoundingRectangle = function() { // Width has the tab built into it already so subtract it here. right = blockXY.x + blockBounds.width - tab; } - return {top: top, bottom: bottom, left: left, right: right}; + return new Blockly.utils.Rect(top, bottom, left, right); }; /** diff --git a/core/inject.js b/core/inject.js index e40d110e5ed..5d4aa5545e9 100644 --- a/core/inject.js +++ b/core/inject.js @@ -312,8 +312,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, } // Bump any object that's below the bottom back inside. - var overflowBottom = - metrics.viewBottom - objectMetrics.bottom; + var overflowBottom = metrics.viewBottom - objectMetrics.bottom; if (overflowBottom < 0) { object.moveBy(0, overflowBottom); } diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 3469c1deb59..b93331c6aaa 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -34,6 +34,7 @@ goog.require('Blockly.Events.Ui'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.Rect'); goog.require('Blockly.WorkspaceComment'); @@ -419,8 +420,7 @@ Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() { * Returns the coordinates of a bounding box describing the dimensions of this * comment. * Coordinate system: workspace coordinates. - * @return {!{top: number, bottom: number, left: number, right: number}} - * Object with top, bottom, left, and right coordinates of the bounding box. + * @return {!Blockly.utils.Rect} Object with coordinates of the bounding box. * @package */ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { @@ -440,7 +440,7 @@ Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() { left = blockXY.x; right = blockXY.x + commentBounds.width; } - return {top: top, bottom: bottom, left: left, right: right}; + return new Blockly.utils.Rect(top, bottom, left, right); }; /** diff --git a/core/workspace_svg.js b/core/workspace_svg.js index bcbe7291865..7cedea7ee51 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -43,6 +43,7 @@ goog.require('Blockly.Trashcan'); goog.require('Blockly.utils'); goog.require('Blockly.utils.Coordinate'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.Rect'); goog.require('Blockly.VariablesDynamic'); goog.require('Blockly.Workspace'); goog.require('Blockly.WorkspaceAudio'); @@ -1352,8 +1353,8 @@ Blockly.WorkspaceSvg.prototype.onMouseWheel_ = function(e) { * Calculate the bounding box for the blocks on the workspace. * Coordinate system: workspace coordinates. * - * @return {Object} Contains the position and size of the bounding box - * containing the blocks on the workspace. + * @return {!Blockly.utils.Rect} Contains the position and size of the + * bounding box containing the blocks on the workspace. */ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { var topBlocks = this.getTopBlocks(false); @@ -1361,7 +1362,7 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { var topElements = topBlocks.concat(topComments); // There are no blocks, return empty rectangle. if (!topElements.length) { - return {top: 0, bottom: 0, left: 0, right: 0}; + return new Blockly.utils.Rect(0, 0, 0, 0); } // Initialize boundary using the first block. @@ -1370,18 +1371,18 @@ Blockly.WorkspaceSvg.prototype.getBlocksBoundingBox = function() { // Start at 1 since the 0th block was used for initialization. for (var i = 1; i < topElements.length; i++) { var blockBoundary = topElements[i].getBoundingRectangle(); - if (blockBoundary.left < boundary.left) { - boundary.left = blockBoundary.left; - } - if (blockBoundary.right > boundary.right) { - boundary.right = blockBoundary.right; - } if (blockBoundary.top < boundary.top) { boundary.top = blockBoundary.top; } if (blockBoundary.bottom > boundary.bottom) { boundary.bottom = blockBoundary.bottom; } + if (blockBoundary.left < boundary.left) { + boundary.left = blockBoundary.left; + } + if (blockBoundary.right > boundary.right) { + boundary.right = blockBoundary.right; + } } return boundary; }; From e0909b4ef8e72f5253a1c10921f315d3e64e2795 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 10 Jun 2019 10:42:58 -0700 Subject: [PATCH 122/233] Fixed fields still being editable on non-editable blocks. --- core/field.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/field.js b/core/field.js index 8d9d54b0188..9ea9bda6191 100644 --- a/core/field.js +++ b/core/field.js @@ -369,7 +369,8 @@ Blockly.Field.prototype.updateEditable = function() { * @return {boolean} Whether this field is clickable. */ Blockly.Field.prototype.isClickable = function() { - return !!this.showEditor_ && (typeof this.showEditor_ === 'function'); + return !!this.sourceBlock_ && this.sourceBlock_.isEditable() && + !!this.showEditor_ && (typeof this.showEditor_ === 'function'); }; /** From aca1a43ec8cb1faae3c71e0603745cb0063b6054 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 10 Jun 2019 11:03:22 -0700 Subject: [PATCH 123/233] Fix regular expressions. 1) Simplifications. 2) Enable toolbox category colours to be specified using the full range of CSS formats (not just hue or #rrggbb). 3) Fix bug where `Blockly.utils.checkMessageReferences('%{BKY_today} %{BKY_xxx}')` returns true. --- core/field_colour.js | 5 ++--- core/field_date.js | 9 +++++---- core/procedures.js | 2 +- core/toolbox.js | 26 ++++++++++++++++---------- core/utils.js | 22 ++++++---------------- core/variables.js | 2 +- 6 files changed, 31 insertions(+), 35 deletions(-) diff --git a/core/field_colour.js b/core/field_colour.js index d7cd85a3300..fb0641878e0 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -194,9 +194,8 @@ Blockly.FieldColour.prototype.doValueUpdate_ = function(newValue) { Blockly.FieldColour.prototype.getText = function() { var colour = this.value_; // Try to use #rgb format if possible, rather than #rrggbb. - var m = colour.match(/^#(.)\1(.)\2(.)\3$/); - if (m) { - colour = '#' + m[1] + m[2] + m[3]; + if (/^#(.)\1(.)\2(.)\3$/.test(colour)) { + colour = '#' + colour[1] + colour[3] + colour[5]; } return colour; }; diff --git a/core/field_date.js b/core/field_date.js index 5d80a665c6d..0878f78b1dd 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -29,6 +29,7 @@ goog.provide('Blockly.FieldDate'); goog.require('Blockly.Events'); goog.require('Blockly.Field'); goog.require('Blockly.utils.dom'); +goog.require('Blockly.utils.string'); goog.require('goog.date'); goog.require('goog.date.DateTime'); @@ -255,13 +256,13 @@ Blockly.FieldDate.widgetDispose_ = function() { * @private */ Blockly.FieldDate.loadLanguage_ = function() { - var reg = /^DateTimeSymbols_(.+)$/; for (var prop in goog.i18n) { - var m = prop.match(reg); - if (m) { - var lang = m[1].toLowerCase().replace('_', '.'); // E.g. 'pt.br' + if (Blockly.utils.string.startsWith(prop, 'DateTimeSymbols_')) { + var lang = prop.substr(16).toLowerCase().replace('_', '.'); + // E.g. 'DateTimeSymbols_pt_BR' -> 'pt.br' if (goog.getObjectByName(lang, Blockly.Msg)) { goog.i18n.DateTimeSymbols = goog.i18n[prop]; + break; } } } diff --git a/core/procedures.js b/core/procedures.js index 6923a7d3bbf..4b96c40f490 100644 --- a/core/procedures.js +++ b/core/procedures.js @@ -160,7 +160,7 @@ Blockly.Procedures.isNameUsed = function(name, workspace, opt_exclude) { */ Blockly.Procedures.rename = function(name) { // Strip leading and trailing whitespace. Beyond this, all names are legal. - name = name.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); + name = name.trim(); // Ensure two identically-named procedures don't exist. var legalName = Blockly.Procedures.findLegalName(name, this.getSourceBlock()); diff --git a/core/toolbox.js b/core/toolbox.js index edb37d3bc8f..d0619276d87 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -32,6 +32,7 @@ goog.require('Blockly.Flyout'); goog.require('Blockly.HorizontalFlyout'); goog.require('Blockly.Touch'); goog.require('Blockly.utils'); +goog.require('Blockly.utils.colour'); goog.require('Blockly.utils.dom'); goog.require('Blockly.utils.Rect'); goog.require('Blockly.VerticalFlyout'); @@ -396,17 +397,22 @@ Blockly.Toolbox.prototype.setColour_ = function(colourValue, childOut, if (colour === null || colour === '') { // No attribute. No colour. childOut.hexColour = ''; - } else if (/^#[0-9a-fA-F]{6}$/.test(colour)) { - childOut.hexColour = colour; - this.hasColours_ = true; - } else if (typeof colour === 'number' || - (typeof colour === 'string' && !isNaN(Number(colour)))) { - childOut.hexColour = Blockly.hueToHex(Number(colour)); - this.hasColours_ = true; } else { - childOut.hexColour = ''; - console.warn('Toolbox category "' + categoryName + - '" has unrecognized colour attribute: ' + colour); + var hue = Number(colour); + if (!isNaN(hue)) { + childOut.hexColour = Blockly.hueToHex(hue); + this.hasColours_ = true; + } else { + var hex = Blockly.utils.colour.parse(colour); + if (hex) { + childOut.hexColour = hex; + this.hasColours_ = true; + } else { + childOut.hexColour = ''; + console.warn('Toolbox category "' + categoryName + + '" has unrecognized colour attribute: ' + colour); + } + } } }; diff --git a/core/utils.js b/core/utils.js index 278121e2009..160696d7691 100644 --- a/core/utils.js +++ b/core/utils.js @@ -256,23 +256,13 @@ Blockly.utils.checkMessageReferences = function(message) { // TODO (#1169): Implement support for other string tables, // prefixes other than BKY_. - var regex = /%{(BKY_[A-Z][A-Z0-9_]*)}/gi; - var match = regex.exec(message); - while (match) { - var msgKey = match[1]; - msgKey = msgKey.toUpperCase(); - if (msgKey.substr(0, 4) != 'BKY_') { - console.log('WARNING: Unsupported message table prefix in %{' + - match[1] + '}.'); - validSoFar = false; // Continue to report other errors. - } else if (msgTable[msgKey.substr(4)] == undefined) { - console.log('WARNING: No message string for %{' + match[1] + '}.'); + var m = message.match(/%{BKY_[A-Z]\w*}/ig); + for (var i = 0; i < m.length; i++) { + var msgKey = m[i].toUpperCase(); + if (msgTable[msgKey.slice(6, -1)] == undefined) { + console.log('WARNING: No message string for ' + m[i] + ' in ' + message); validSoFar = false; // Continue to report other errors. } - - // Re-run on remainder of string. - message = message.substring(match.index + msgKey.length + 1); - match = regex.exec(message); } return validSoFar; @@ -350,7 +340,7 @@ Blockly.utils.tokenizeInterpolation_ = function(message, buffer.push(c); } else { var rawKey = buffer.join(''); - if (/[a-zA-Z][a-zA-Z0-9_]*/.test(rawKey)) { // Strict matching + if (/[A-Z]\w*/i.test(rawKey)) { // Strict matching // Found a valid string key. Attempt case insensitive match. var keyUpper = rawKey.toUpperCase(); diff --git a/core/variables.js b/core/variables.js index a37271702a5..f002e2ca7c0 100644 --- a/core/variables.js +++ b/core/variables.js @@ -399,7 +399,7 @@ Blockly.Variables.promptName = function(promptText, defaultText, callback) { // Merge runs of whitespace. Strip leading and trailing whitespace. // Beyond this, all names are legal. if (newVar) { - newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); + newVar = newVar.replace(/[\s\xa0]+/g, ' ').trim(); if (newVar == Blockly.Msg['RENAME_VARIABLE'] || newVar == Blockly.Msg['NEW_VARIABLE']) { // Ok, not ALL names are legal... From 61343375687ed98386f0a7dd20beaae626149372 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 10 Jun 2019 11:40:41 -0700 Subject: [PATCH 124/233] Reduce memory footprint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blockly.Css.CONTENT isn’t needed after its first use. There also is no longer a need to store a reference to the stylesheet, just a boolean. --- core/css.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/css.js b/core/css.js index da9648c4d8c..aaa7cccb98d 100644 --- a/core/css.js +++ b/core/css.js @@ -49,11 +49,11 @@ Blockly.Css.Cursor = { Blockly.Css.currentCursor_ = ''; /** - * Large stylesheet added by Blockly.Css.inject. - * @type {Element} + * Has CSS already been injected? + * @type {boolean} * @private */ -Blockly.Css.styleSheet_ = null; +Blockly.Css.injected_ = false; /** * Path to media directory, with any trailing slash removed. @@ -74,13 +74,15 @@ Blockly.Css.mediaPath_ = ''; */ Blockly.Css.inject = function(hasCss, pathToMedia) { // Only inject the CSS once. - if (Blockly.Css.styleSheet_) { + if (Blockly.Css.injected_) { return; } + Blockly.Css.injected_ = true; // Placeholder for cursor rule. Must be first rule (index 0). var text = '.blocklyDraggable {}\n'; if (hasCss) { text += Blockly.Css.CONTENT.join('\n'); + Blockly.Css.CONTENT = null; // Garbage collect 13 KB. if (Blockly.FieldDate) { text += Blockly.FieldDate.CSS.join('\n'); } @@ -88,13 +90,12 @@ Blockly.Css.inject = function(hasCss, pathToMedia) { // Strip off any trailing slash (either Unix or Windows). Blockly.Css.mediaPath_ = pathToMedia.replace(/[\\\/]$/, ''); text = text.replace(/<<>>/g, Blockly.Css.mediaPath_); + // Inject CSS tag at start of head. var cssNode = document.createElement('style'); - document.head.insertBefore(cssNode, document.head.firstChild); - var cssTextNode = document.createTextNode(text); cssNode.appendChild(cssTextNode); - Blockly.Css.styleSheet_ = cssNode.sheet; + document.head.insertBefore(cssNode, document.head.firstChild); }; /** From 1535f35ff2ff370ad8b7279d1313698ad0458ffd Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 10 Jun 2019 13:20:33 -0700 Subject: [PATCH 125/233] Remove unused CSS image fetch This default Closure image was always being overridden and was never fetched. But it takes some research to determine that this is not in effect a potential monitoring point. --- core/css.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/css.js b/core/css.js index aaa7cccb98d..1fa07501195 100644 --- a/core/css.js +++ b/core/css.js @@ -282,7 +282,7 @@ Blockly.Css.CONTENT = [ 'cursor: -webkit-grab;', '}', - '.blocklyDragging {', + '.blocklyDragging {', /* backup for browsers (e.g. IE11) that don't support grabbing */ 'cursor: url("<<>>/handclosed.cur"), auto;', 'cursor: grabbing;', @@ -647,10 +647,9 @@ Blockly.Css.CONTENT = [ 'padding: 0 !important;', '}', - /* Override the default Closure URL. */ '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,', '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {', - 'background: url(<<>>/sprites.png) no-repeat -48px -16px !important;', + 'background: url(<<>>/sprites.png) no-repeat -48px -16px;', '}', /* Category tree in Toolbox. */ @@ -964,8 +963,6 @@ Blockly.Css.CONTENT = [ '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon, ', '.blocklyDropDownDiv .goog-option-selected .goog-menuitem-checkbox, ', '.blocklyDropDownDiv .goog-option-selected .goog-menuitem-icon {', - /* Client apps may override the URL at which they serve the sprite. */ - 'background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;', 'position: static;', /* Scroll with the menu. */ 'float: left;', 'margin-left: -24px;', From 0122f36450e9692c814567804570a2dd1015c766 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 6 Jun 2019 08:39:01 -0700 Subject: [PATCH 126/233] Fixed field disposal, and reorganized editor creation. --- core/field.js | 25 +++--- core/field_angle.js | 113 +++++++++++++++------------ core/field_colour.js | 43 ++++------ core/field_date.js | 70 +++++++++-------- core/field_dropdown.js | 105 ++++++++++++------------- core/field_image.js | 7 +- core/field_label.js | 10 --- core/field_textinput.js | 168 +++++++++++++++++----------------------- 8 files changed, 255 insertions(+), 286 deletions(-) diff --git a/core/field.js b/core/field.js index a5302527f76..f4b95e3dab9 100644 --- a/core/field.js +++ b/core/field.js @@ -111,7 +111,6 @@ Blockly.Field.cacheWidths_ = null; */ Blockly.Field.cacheReference_ = 0; - /** * Name of field. Unique within each block. * Static labels are usually unnamed. @@ -126,12 +125,12 @@ Blockly.Field.prototype.name = undefined; Blockly.Field.prototype.maxDisplayLength = 50; /** - * Get the current value of the field. - * @return {*} Current value. + * A generic value possessed by the field. + * Should generally be non-null, only null when the field is created. + * @type {*} + * @protected */ -Blockly.Field.prototype.getValue = function() { - return this.value_; -}; +Blockly.Field.prototype.value_ = null; /** * Visible text to display. @@ -329,8 +328,12 @@ Blockly.Field.prototype.toXml = function(fieldElement) { /** * Dispose of all DOM objects belonging to this editable field. + * @package */ Blockly.Field.prototype.dispose = function() { + Blockly.DropDownDiv.hideIfOwner(this); + Blockly.WidgetDiv.hideIfOwner(this); + if (this.mouseDownWrapper_) { Blockly.unbindEvent_(this.mouseDownWrapper_); this.mouseDownWrapper_ = null; @@ -785,12 +788,12 @@ Blockly.Field.prototype.setValue = function(newValue) { }; /** - * A generic value possessed by the field. - * Should generally be non-null, only null when the field is created. - * @type {*} - * @protected + * Get the current value of the field. + * @return {*} Current value. */ -Blockly.Field.prototype.value_ = null; +Blockly.Field.prototype.getValue = function() { + return this.value_; +}; /** * Used to validate a value. Returns input by default. Can be overridden by diff --git a/core/field_angle.js b/core/field_angle.js index 36ca268dc6d..a3c3574d379 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -131,67 +131,73 @@ Blockly.FieldAngle.prototype.initView = function() { }; /** - * Updates the graph when the field rerenders. - * @private + * Dispose of references to DOM elements and events belonging to this field. + * @package */ -Blockly.FieldAngle.prototype.render_ = function() { - Blockly.FieldAngle.superClass_.render_.call(this); - this.updateGraph_(); +Blockly.FieldAngle.prototype.dispose = function() { + Blockly.FieldAngle.superClass_.dispose.call(this); + this.symbol_ = null; }; /** - * Clean up this FieldAngle, as well as the inherited FieldTextInput. - * @return {!Function} Closure to call on destruction of the WidgetDiv. + * Updates the graph when the field rerenders. * @private */ -Blockly.FieldAngle.prototype.dispose_ = function() { - var thisField = this; - return function() { - Blockly.FieldAngle.superClass_.dispose_.call(thisField)(); - thisField.gauge_ = null; - if (thisField.clickWrapper_) { - Blockly.unbindEvent_(thisField.clickWrapper_); - } - if (thisField.moveWrapper1_) { - Blockly.unbindEvent_(thisField.moveWrapper1_); - } - if (thisField.moveWrapper2_) { - Blockly.unbindEvent_(thisField.moveWrapper2_); - } - }; +Blockly.FieldAngle.prototype.render_ = function() { + Blockly.FieldAngle.superClass_.render_.call(this); + this.updateGraph_(); }; /** - * Show the inline free-text editor on top of the text. + * Create and show the angle field's editor. * @private */ Blockly.FieldAngle.prototype.showEditor_ = function() { - var noFocus = - Blockly.utils.userAgent.MOBILE || - Blockly.utils.userAgent.ANDROID || - Blockly.utils.userAgent.IPAD; // Mobile browsers have issues with in-line textareas (focus & keyboards). + var noFocus = + Blockly.userAgent.MOBILE || + Blockly.userAgent.ANDROID || + Blockly.userAgent.IPAD; Blockly.FieldAngle.superClass_.showEditor_.call(this, noFocus); - var div = Blockly.DropDownDiv.getContentDiv(); + var editor = this.dropdownCreate_(); + Blockly.DropDownDiv.getContentDiv().appendChild(editor); + + var border = this.sourceBlock_.getColourBorder(); + border = border.colourBorder == null ? + border.colourLight : border.colourBorder; + Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); + + Blockly.DropDownDiv.showPositionedByField( + this, this.dropdownDispose_.bind(this)); + + this.updateGraph_(); +}; - // Build the SVG DOM. - var svg = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': Blockly.utils.dom.SVG_NS, - 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, +/** + * Create the angle dropdown editor. + * @return {!Element} The newly created angle picker. + * @private + */ +Blockly.FieldAngle.prototype.dropdownCreate_ = function() { + var svg = Blockly.utils.createSvgElement('svg', { + 'xmlns': 'http://www.w3.org/2000/svg', + 'xmlns:html': 'http://www.w3.org/1999/xhtml', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'version': '1.1', 'height': (Blockly.FieldAngle.HALF * 2) + 'px', 'width': (Blockly.FieldAngle.HALF * 2) + 'px' - }, div); - var circle = Blockly.utils.dom.createSvgElement('circle', { - 'cx': Blockly.FieldAngle.HALF, 'cy': Blockly.FieldAngle.HALF, + }, null); + var circle = Blockly.utils.createSvgElement('circle', { + 'cx': Blockly.FieldAngle.HALF, + 'cy': Blockly.FieldAngle.HALF, 'r': Blockly.FieldAngle.RADIUS, 'class': 'blocklyAngleCircle' }, svg); - this.gauge_ = Blockly.utils.dom.createSvgElement('path', - {'class': 'blocklyAngleGauge'}, svg); - this.line_ = Blockly.utils.dom.createSvgElement('line', { + this.gauge_ = Blockly.utils.createSvgElement('path', { + 'class': 'blocklyAngleGauge' + }, svg); + this.line_ = Blockly.utils.createSvgElement('line', { 'x1': Blockly.FieldAngle.HALF, 'y1': Blockly.FieldAngle.HALF, 'class': 'blocklyAngleLine' @@ -210,33 +216,38 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { }, svg); } - var border = this.sourceBlock_.getColourBorder(); - border = (border.colourBorder == null) ? - border.colourLight : border.colourBorder; - - Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); - Blockly.DropDownDiv.showPositionedByField(this); // The angle picker is different from other fields in that it updates on // mousemove even if it's not in the middle of a drag. In future we may // change this behaviour. For now, using bindEvent_ instead of // bindEventWithChecks_ allows it to work without a mousedown/touchstart. this.clickWrapper_ = - Blockly.bindEvent_(svg, 'click', this, this.hide_.bind(this)); + Blockly.bindEvent_(svg, 'click', this, this.hide_); this.moveWrapper1_ = Blockly.bindEvent_(circle, 'mousemove', this, this.onMouseMove); this.moveWrapper2_ = Blockly.bindEvent_(this.gauge_, 'mousemove', this, this.onMouseMove); - this.updateGraph_(); + + return svg; }; /** - * Hide the editor and unbind event listeners. + * Dispose of references to DOM elements and events belonging + * to the angle editor. * @private */ -Blockly.FieldAngle.prototype.hide_ = function() { +Blockly.FieldAngle.prototype.dropdownDispose_ = function() { + this.gauge_ = null; + this.line_ = null; + Blockly.unbindEvent_(this.clickWrapper_); Blockly.unbindEvent_(this.moveWrapper1_); Blockly.unbindEvent_(this.moveWrapper2_); - Blockly.unbindEvent_(this.clickWrapper_); +}; + +/** + * Hide the editor. + * @private + */ +Blockly.FieldAngle.prototype.hide_ = function() { Blockly.DropDownDiv.hideIfOwner(this); Blockly.WidgetDiv.hide(); }; @@ -287,7 +298,7 @@ Blockly.FieldAngle.prototype.onMouseMove = function(e) { // Update value. var angleString = String(angle); if (angleString != this.text_) { - Blockly.FieldTextInput.htmlInput_.value = angle; + this.htmlInput_.value = angle; this.setValue(angle); // Always render the input angle. this.text_ = angleString; diff --git a/core/field_colour.js b/core/field_colour.js index fb0641878e0..894f642f941 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -154,14 +154,6 @@ Blockly.FieldColour.prototype.initView = function() { this.borderRect_.style.fill = this.value_; }; -/** - * Close the colour picker if this input is being deleted. - */ -Blockly.FieldColour.prototype.dispose = function() { - Blockly.WidgetDiv.hideIfOwner(this); - Blockly.FieldColour.superClass_.dispose.call(this); -}; - /** * Ensure that the input value is a valid colour. * @param {string=} newValue The input value. @@ -271,20 +263,18 @@ Blockly.FieldColour.prototype.setColumns = function(columns) { }; /** - * Create a palette under the colour field. + * Create and show the colour field's editor. * @private */ Blockly.FieldColour.prototype.showEditor_ = function() { - var picker = this.createWidget_(); + var picker = this.dropdownCreate_(); Blockly.DropDownDiv.getContentDiv().appendChild(picker); + Blockly.DropDownDiv.setColour( this.DROPDOWN_BACKGROUND_COLOUR, this.DROPDOWN_BORDER_COLOUR); - Blockly.DropDownDiv.showPositionedByField(this); - - // Configure event handler on the table to listen for any event in a cell. - Blockly.FieldColour.onUpWrapper_ = Blockly.bindEvent_(picker, - 'mouseup', this, this.onClick_); + Blockly.DropDownDiv.showPositionedByField( + this, this.dropdownDispose_.bind(this)); }; /** @@ -299,22 +289,17 @@ Blockly.FieldColour.prototype.onClick_ = function(e) { cell = cell.parentNode; } var colour = cell && cell.label; - Blockly.WidgetDiv.hide(); - if (this.sourceBlock_) { - // Call any validation function, and allow it to override. - colour = this.callValidator(colour); - } if (colour !== null) { this.setValue(colour); } }; /** - * Create a colour picker widget. + * Create a colour picker dropdown editor. * @return {!Element} The newly created colour picker. * @private */ -Blockly.FieldColour.prototype.createWidget_ = function() { +Blockly.FieldColour.prototype.dropdownCreate_ = function() { var columns = this.columns_ || Blockly.FieldColour.COLUMNS; var colours = this.colours_ || Blockly.FieldColour.COLOURS; var titles = this.titles_ || Blockly.FieldColour.TITLES; @@ -339,18 +324,20 @@ Blockly.FieldColour.prototype.createWidget_ = function() { div.className = 'blocklyColourSelected'; } } + + // Configure event handler on the table to listen for any event in a cell. + this.onUpWrapper_ = Blockly.bindEvent_(table, 'mouseup', this, this.onClick_); + return table; }; /** - * Hide the colour picker widget. + * Dispose of references to DOM elements and events belonging + * to the colour editor. * @private */ -Blockly.FieldColour.widgetDispose_ = function() { - if (Blockly.FieldColour.onUpWrapper_) { - Blockly.unbindEvent_(Blockly.FieldColour.onUpWrapper_); - } - Blockly.Events.setGroup(false); +Blockly.FieldColour.prototype.dropdownDispose_ = function() { + Blockly.unbindEvent_(this.onUpWrapper_); }; Blockly.Field.register('field_colour', Blockly.FieldColour); diff --git a/core/field_date.js b/core/field_date.js index 0878f78b1dd..843d5356277 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -99,14 +99,6 @@ Blockly.FieldDate.prototype.DROPDOWN_BORDER_COLOUR = 'silver'; */ Blockly.FieldDate.prototype.DROPDOWN_BACKGROUND_COLOUR = 'white'; -/** - * Close the colour picker if this input is being deleted. - */ -Blockly.FieldDate.prototype.dispose = function() { - Blockly.WidgetDiv.hideIfOwner(this); - Blockly.FieldDate.superClass_.dispose.call(this); -}; - /** * Ensure that the input value is a valid date. * @param {string=} newValue The input value. @@ -195,38 +187,28 @@ Blockly.FieldDate.prototype.updateEditor_ = function() { }; /** - * Create a date picker under the date field. + * Create and show the date field's editor. * @private */ Blockly.FieldDate.prototype.showEditor_ = function() { - this.picker_ = this.createWidget_(); + this.picker_ = this.dropdownCreate_(); this.picker_.render(Blockly.DropDownDiv.getContentDiv()); Blockly.utils.dom.addClass(this.picker_.getElement(), 'blocklyDatePicker'); - Blockly.DropDownDiv.showPositionedByField(this); Blockly.DropDownDiv.setColour( this.DROPDOWN_BACKGROUND_COLOUR, this.DROPDOWN_BORDER_COLOUR); - this.updateEditor_(); - var thisField = this; - Blockly.FieldDate.changeEventKey_ = goog.events.listen(this.picker_, - goog.ui.DatePicker.Events.CHANGE, - function(event) { - var date = event.date ? event.date.toIsoString(true) : ''; - thisField.setValue(date); - }); - Blockly.FieldDate.changeEventKey_ = goog.events.listen(this.picker_, - goog.ui.DatePicker.Events.CHANGE_ACTIVE_MONTH, - function(_e) { - thisField.updateEditor_(); - }); + Blockly.DropDownDiv.showPositionedByField( + this, this.dropdownDispose_.bind(this)); + + this.updateEditor_(); }; /** - * Create a date picker widget and render it inside the widget div. + * Create the date dropdown editor. * @return {!goog.ui.DatePicker} The newly created date picker. * @private */ -Blockly.FieldDate.prototype.createWidget_ = function() { +Blockly.FieldDate.prototype.dropdownCreate_ = function() { // Create the date picker using Closure. Blockly.FieldDate.loadLanguage_(); var picker = new goog.ui.DatePicker(); @@ -235,19 +217,43 @@ Blockly.FieldDate.prototype.createWidget_ = function() { picker.setUseNarrowWeekdayNames(true); picker.setUseSimpleNavigationMenu(true); picker.setDate(goog.date.DateTime.fromIsoString(this.getValue())); + + this.changeEventKey_ = goog.events.listen( + picker, + goog.ui.DatePicker.Events.CHANGE, + this.onDateSelected_, + null, + this); + this.activeMonthEventKey_ = goog.events.listen( + picker, + goog.ui.DatePicker.Events.CHANGE_ACTIVE_MONTH, + this.updateEditor_, + null, + this); + return picker; }; /** - * Hide the date picker. + * Dispose of references to DOM elements and events belonging + * to the date editor. * @private */ -Blockly.FieldDate.widgetDispose_ = function() { - if (Blockly.FieldDate.changeEventKey_) { - goog.events.unlistenByKey(Blockly.FieldDate.changeEventKey_); - } +Blockly.FieldDate.prototype.dropdownDispose_ = function() { this.picker_ = null; - Blockly.Events.setGroup(false); + goog.events.unlistenByKey(this.changeEventKey_); + goog.events.unlistenByKey(this.activeMonthEventKey_); +}; + +/** + * Handle a CHANGE event in the date picker. + * TODO: Not sure what the type for goog event information is. + * @param {!Event} event The CHANGE event. + * @private + */ +Blockly.FieldDate.prototype.onDateSelected_ = function(event) { + var date = event.date ? event.date.toIsoString(true) : ''; + this.setValue(date); }; /** diff --git a/core/field_dropdown.js b/core/field_dropdown.js index be5ccfaad2f..5b1272f2d22 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -155,46 +155,45 @@ Blockly.FieldDropdown.prototype.initView = function() { }; /** - * Create a dropdown menu under the text. - * @private + * Dispose of references to DOM elements and events belonging to this field. */ -Blockly.FieldDropdown.prototype.showEditor_ = function() { - Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, null); - var menu = this.createMenu_(); - this.addActionListener_(menu); - this.positionMenu_(menu); +Blockly.FieldDropdown.prototype.dispose = function() { + Blockly.FieldDropdown.superClass_.dispose.call(this); + this.imageElement_ = null; + this.arrow_ = null; }; /** - * Add a listener for mouse and keyboard events in the menu and its items. - * @param {!goog.ui.Menu} menu The menu to add listeners to. + * Create a dropdown menu under the text. * @private */ -Blockly.FieldDropdown.prototype.addActionListener_ = function(menu) { - var thisField = this; - - function callback(e) { - var menu = this; - var menuItem = e.target; - if (menuItem) { - thisField.onItemSelected(menu, menuItem); - } - Blockly.WidgetDiv.hideIfOwner(thisField); - Blockly.Events.setGroup(false); - } - // Listen for mouse/keyboard events. - goog.events.listen(menu, goog.ui.Component.EventType.ACTION, callback); +Blockly.FieldDropdown.prototype.showEditor_ = function() { + Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, + this.widgetDispose_.bind(this)); + this.menu_ = this.widgetCreate_(); + + this.menu_.render(Blockly.WidgetDiv.DIV); + // Element gets created in render. + Blockly.utils.addClass(this.menu_.getElement(), 'blocklyDropdownMenu'); + + this.positionMenu_(this.menu_); + + // Focusing needs to be handled after the menu is rendered and positioned. + // Otherwise it will cause a page scroll to get the misplaced menu in + // view. See issue #1329. + this.menu_.setAllowAutoFocus(true); + this.menu_.getElement().focus(); }; /** - * Create and populate the menu and menu items for this dropdown, based on - * the options list. - * @return {!goog.ui.Menu} The populated dropdown menu. + * Create the dropdown editor widget. + * @return {goog.ui.Menu} The newly created dropdown menu. * @private */ -Blockly.FieldDropdown.prototype.createMenu_ = function() { +Blockly.FieldDropdown.prototype.widgetCreate_ = function() { var menu = new goog.ui.Menu(); menu.setRightToLeft(this.sourceBlock_.RTL); + var options = this.getOptions(); for (var i = 0; i < options.length; i++) { var content = options[i][0]; // Human-readable text or image. @@ -213,9 +212,33 @@ Blockly.FieldDropdown.prototype.createMenu_ = function() { menu.addChild(menuItem, true); menuItem.setChecked(value == this.value_); } + + this.menuActionEventKey_ = goog.events.listen( + menu, + goog.ui.Component.EventType.ACTION, + this.handleMenuActionEvent_, + false, + this); + return menu; }; +Blockly.FieldDropdown.prototype.widgetDispose_ = function() { + this.menu_ = null; + goog.events.unlistenByKey(this.menuActionEventKey_); +}; + +/** + * Handle an ACTION event in the dropdown menu. + * TODO: Not sure what the type for goog event information is. + * @param {!Event} event The CHANGE event. + * @private + */ +Blockly.FieldDropdown.prototype.handleMenuActionEvent_ = function(event) { + Blockly.WidgetDiv.hideIfOwner(this); + this.onItemSelected(this.menu_, event.target); +}; + /** * Place the menu correctly on the screen, taking into account the dimensions * of the menu and the dimensions of the screen so that it doesn't run off any @@ -224,11 +247,9 @@ Blockly.FieldDropdown.prototype.createMenu_ = function() { * @private */ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) { - // Record viewport dimensions before adding the dropdown. var viewportBBox = Blockly.utils.getViewportBBox(); var anchorBBox = this.getAnchorDimensions_(); - this.createWidget_(menu); var menuSize = Blockly.utils.uiMenu.getSize(menu); var menuMaxHeightPx = Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH @@ -240,26 +261,8 @@ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) { if (this.sourceBlock_.RTL) { Blockly.utils.uiMenu.adjustBBoxesForRTL(viewportBBox, anchorBBox, menuSize); } - // Position the menu. Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, this.sourceBlock_.RTL); - // Calling menuDom.focus() has to wait until after the menu has been placed - // correctly. Otherwise it will cause a page scroll to get the misplaced menu - // in view. See issue #1329. - menu.getElement().focus(); -}; - -/** - * Create and render the menu widget inside Blockly's widget div. - * @param {!goog.ui.Menu} menu The menu to add to the widget div. - * @private - */ -Blockly.FieldDropdown.prototype.createWidget_ = function(menu) { - var div = Blockly.WidgetDiv.DIV; - menu.render(div); - Blockly.utils.dom.addClass(menu.getElement(), 'blocklyDropdownMenu'); - // Enable autofocus after the initial render to avoid issue #1329. - menu.setAllowAutoFocus(true); }; /** @@ -508,14 +511,6 @@ Blockly.FieldDropdown.prototype.renderSelectedText_ = function() { this.size_.width = Blockly.Field.getCachedWidth(this.textElement_); }; -/** - * Close the dropdown menu if this input is being deleted. - */ -Blockly.FieldDropdown.prototype.dispose = function() { - Blockly.WidgetDiv.hideIfOwner(this); - Blockly.FieldDropdown.superClass_.dispose.call(this); -}; - /** * Validates the data structure to be processed as an options list. * @param {?} options The proposed dropdown options. diff --git a/core/field_image.js b/core/field_image.js index cc4ba061736..7a7bb96ec67 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -133,11 +133,10 @@ Blockly.FieldImage.prototype.initView = function() { * Dispose of all DOM objects belonging to this text. */ Blockly.FieldImage.prototype.dispose = function() { - if (this.fieldGroup_) { - Blockly.utils.dom.removeNode(this.fieldGroup_); - this.fieldGroup_ = null; - } + Blockly.FieldImage.superClass_.dispose.call(this); this.imageElement_ = null; + // TODO: Do we need to dispose of this? + this.clickHandler_ = null; }; /** diff --git a/core/field_label.js b/core/field_label.js index 00cb8a35d24..efeeb1e6c46 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -87,16 +87,6 @@ Blockly.FieldLabel.prototype.initView = function() { } }; -/** - * Dispose of all DOM objects belonging to this text. - */ -Blockly.FieldLabel.prototype.dispose = function() { - if (this.textElement_) { - Blockly.utils.dom.removeNode(this.textElement_); - this.textElement_ = null; - } -}; - /** * Ensure that the input value casts to a valid string. * @param {string=} newValue The input value. diff --git a/core/field_textinput.js b/core/field_textinput.js index 027f4f683c6..87a43b75a65 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -107,14 +107,6 @@ Blockly.FieldTextInput.prototype.CURSOR = 'text'; */ Blockly.FieldTextInput.prototype.spellcheck_ = true; -/** - * Close the input widget if this input is being deleted. - */ -Blockly.FieldTextInput.prototype.dispose = function() { - Blockly.WidgetDiv.hideIfOwner(this); - Blockly.FieldTextInput.superClass_.dispose.call(this); -}; - /** * Ensure that the input value casts to a valid string. * @param {string=} newValue The input value. @@ -137,15 +129,12 @@ Blockly.FieldTextInput.prototype.doClassValidation_ = function(newValue) { Blockly.FieldTextInput.prototype.doValueInvalid_ = function() { if (this.isBeingEdited_) { this.isTextValid_ = false; - var htmlInput = Blockly.FieldTextInput.htmlInput_; - if (htmlInput) { - var oldValue = this.value_; - // Revert value when the text becomes invalid. - this.value_ = htmlInput.untypedDefaultValue_; - if (this.sourceBlock_ && Blockly.Events.isEnabled()) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - this.sourceBlock_, 'field', this.name, oldValue, this.value_)); - } + var oldValue = this.value_; + // Revert value when the text becomes invalid. + this.value_ = this.htmlInput_.untypedDefaultValue_; + if (this.sourceBlock_ && Blockly.Events.isEnabled()) { + Blockly.Events.fire(new Blockly.Events.BlockChange( + this.sourceBlock_, 'field', this.name, oldValue, this.value_)); } } }; @@ -177,12 +166,11 @@ Blockly.FieldTextInput.prototype.render_ = function() { // This logic is done in render_ rather than doValueInvalid_ or // doValueUpdate_ so that the code is more centralized. if (this.isBeingEdited_) { - var htmlInput = Blockly.FieldTextInput.htmlInput_; this.resizeEditor_(); if (!this.isTextValid_) { - Blockly.utils.dom.addClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.dom.addClass(this.htmlInput_, 'blocklyInvalidInput'); } else { - Blockly.utils.dom.removeClass(htmlInput, 'blocklyInvalidInput'); + Blockly.utils.dom.removeClass(this.htmlInput_, 'blocklyInvalidInput'); } } }; @@ -233,76 +221,74 @@ Blockly.FieldTextInput.prototype.showPromptEditor_ = function() { * @private */ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { - // Start editing. this.isBeingEdited_ = true; + Blockly.WidgetDiv.show( + this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this)); + this.htmlInput_ = this.widgetCreate_(); + + if (!quietInput) { + this.htmlInput_.focus(); + this.htmlInput_.select(); + } + + this.bindInputEvents_(); +}; - // Show the div. - Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_()); +Blockly.FieldTextInput.prototype.widgetCreate_ = function() { var div = Blockly.WidgetDiv.DIV; - // Create the input. var htmlInput = document.createElement('input'); htmlInput.className = 'blocklyHtmlInput'; htmlInput.setAttribute('spellcheck', this.spellcheck_); var fontSize = - (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt'; + (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; div.appendChild(htmlInput); - // Assign the current value to the input & resize. htmlInput.value = htmlInput.defaultValue = this.value_; htmlInput.untypedDefaultValue_ = this.value_; htmlInput.oldValue_ = null; this.resizeEditor_(); - // Give it focus. - if (!quietInput) { - htmlInput.focus(); - htmlInput.select(); - } - - // Bind events. this.bindInputEvents_(htmlInput); - // Save it. - Blockly.FieldTextInput.htmlInput_ = htmlInput; + return htmlInput; }; /** - * Bind handlers for user input on this field and size changes on the workspace. - * @param {!HTMLInputElement} htmlInput The htmlInput created in showEditor, to - * which event handlers will be bound. + * Bind handlers for user input on the text input field's editor.. * @private */ -Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { - // Bind to keydown -- trap Enter without IME and Esc to hide. - htmlInput.onKeyDownWrapper_ = +Blockly.FieldTextInput.prototype.bindInputEvents_ = function() { + // Trap Enter without IME and Esc to hide. + this.onKeyDownWrapper_ = Blockly.bindEventWithChecks_( - htmlInput, 'keydown', this, this.onHtmlInputKeyDown_); - // Bind to keyup -- resize after every keystroke. - htmlInput.onKeyUpWrapper_ = + this.htmlInput_, 'keydown', this, this.onHtmlInputKeyDown_); + // Resize after every keystroke. + this.onKeyUpWrapper_ = Blockly.bindEventWithChecks_( - htmlInput, 'keyup', this, this.onHtmlInputChange_); - // Bind to keyPress -- repeatedly resize when holding down a key. - htmlInput.onKeyPressWrapper_ = + this.htmlInput_, 'keyup', this, this.onHtmlInputChange_); + // Repeatedly resize when holding down a key. + this.onKeyPressWrapper_ = Blockly.bindEventWithChecks_( - htmlInput, 'keypress', this, this.onHtmlInputChange_); - htmlInput.onWorkspaceChangeWrapper_ = this.resizeEditor_.bind(this); - this.workspace_.addChangeListener(htmlInput.onWorkspaceChangeWrapper_); + this.htmlInput_, 'keypress', this, this.onHtmlInputChange_); + + // TODO: Figure out if this is necessary. + this.onWorkspaceChangeWrapper_ = this.resizeEditor_.bind(this); + this.workspace_.addChangeListener(this.onWorkspaceChangeWrapper_); }; /** * Unbind handlers for user input and workspace size changes. - * @param {!HTMLInputElement} htmlInput The html for this text input. * @private */ -Blockly.FieldTextInput.prototype.unbindInputEvents_ = function(htmlInput) { - Blockly.unbindEvent_(htmlInput.onKeyDownWrapper_); - Blockly.unbindEvent_(htmlInput.onKeyUpWrapper_); - Blockly.unbindEvent_(htmlInput.onKeyPressWrapper_); +Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() { + Blockly.unbindEvent_(this.onKeyDownWrapper_); + Blockly.unbindEvent_(this.onKeyUpWrapper_); + Blockly.unbindEvent_(this.onKeyPressWrapper_); this.workspace_.removeChangeListener( - htmlInput.onWorkspaceChangeWrapper_); + this.onWorkspaceChangeWrapper_); }; /** @@ -311,13 +297,12 @@ Blockly.FieldTextInput.prototype.unbindInputEvents_ = function(htmlInput) { * @private */ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) { - var htmlInput = Blockly.FieldTextInput.htmlInput_; var tabKey = 9, enterKey = 13, escKey = 27; if (e.keyCode == enterKey) { Blockly.WidgetDiv.hide(); Blockly.DropDownDiv.hideIfOwner(this); } else if (e.keyCode == escKey) { - htmlInput.value = htmlInput.defaultValue; + this.htmlInput_.value = this.htmlInput_.defaultValue; Blockly.WidgetDiv.hide(); Blockly.DropDownDiv.hideIfOwner(this); } else if (e.keyCode == tabKey) { @@ -334,10 +319,9 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) { * @private */ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { - var htmlInput = Blockly.FieldTextInput.htmlInput_; - var text = htmlInput.value; - if (text !== htmlInput.oldValue_) { - htmlInput.oldValue_ = text; + var text = this.htmlInput_.value; + if (text !== this.htmlInput_.oldValue_) { + this.htmlInput_.oldValue_ = text; // TODO(#2169): Once issue is fixed the setGroup functionality could be // moved up to the Field setValue method. This would create a @@ -345,7 +329,7 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { Blockly.Events.setGroup(true); this.setValue(text); // Always render the input text. - this.text_ = Blockly.FieldTextInput.htmlInput_.value; + this.text_ = this.htmlInput_.value; this.forceRerender(); Blockly.Events.setGroup(false); } @@ -384,44 +368,38 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { /** * Close the editor, save the results, and dispose of the editable * text field's elements. - * @return {!Function} Closure to call on destruction of the WidgetDiv. * @private */ Blockly.FieldTextInput.prototype.widgetDispose_ = function() { - var thisField = this; - return function() { - var htmlInput = Blockly.FieldTextInput.htmlInput_; - - // Finalize value. - thisField.isBeingEdited_ = false; - // No need to call setValue because if the widget is being closed the - // latest input text has already been validated. - if (thisField.value_ !== thisField.text_) { - // At the end of an edit the text should be the same as the value. It - // may not be if the input text is different than the validated text. - // We should fix that. - thisField.text_ = String(thisField.value_); - thisField.isTextValid_ = true; - thisField.forceRerender(); - } - // Otherwise don't rerender. + // Finalize value. + this.isBeingEdited_ = false; + // No need to call setValue because if the widget is being closed the + // latest input text has already been validated. + if (this.value_ !== this.text_) { + // At the end of an edit the text should be the same as the value. It + // may not be if the input text is different than the validated text. + // We should fix that. + this.text_ = String(this.value_); + this.isTextValid_ = true; + this.forceRerender(); + } + // Otherwise don't rerender. - // Call onFinishEditing - // TODO: Get rid of this or make it less of a hack. - if (thisField.onFinishEditing_) { - thisField.onFinishEditing_(thisField.value_); - } + // Call onFinishEditing + // TODO: Get rid of this or make it less of a hack. + if (this.onFinishEditing_) { + this.onFinishEditing_(this.value_); + } - // Remove htmlInput. - thisField.unbindInputEvents_(htmlInput); - Blockly.FieldTextInput.htmlInput_ = null; + // Remove htmlInput. + this.unbindInputEvents_(); + this.htmlInput_ = null; - // Delete style properties. - var style = Blockly.WidgetDiv.DIV.style; - style.width = 'auto'; - style.height = 'auto'; - style.fontSize = ''; - }; + // Delete style properties. + var style = Blockly.WidgetDiv.DIV.style; + style.width = 'auto'; + style.height = 'auto'; + style.fontSize = ''; }; /** From 217206911a92f7a0c657cd55d7cef309a271922f Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 7 Jun 2019 07:03:43 -0700 Subject: [PATCH 127/233] Fixed some formatting in text input. --- core/field_textinput.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/field_textinput.js b/core/field_textinput.js index 87a43b75a65..20636c8e8e9 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -230,8 +230,6 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { this.htmlInput_.focus(); this.htmlInput_.select(); } - - this.bindInputEvents_(); }; Blockly.FieldTextInput.prototype.widgetCreate_ = function() { @@ -257,22 +255,24 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { }; /** - * Bind handlers for user input on the text input field's editor.. + * Bind handlers for user input on the text input field's editor. + * @param {!HTMLInputElement} htmlInput The htmlInput to which event + * handlers will be bound. * @private */ -Blockly.FieldTextInput.prototype.bindInputEvents_ = function() { +Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) { // Trap Enter without IME and Esc to hide. this.onKeyDownWrapper_ = Blockly.bindEventWithChecks_( - this.htmlInput_, 'keydown', this, this.onHtmlInputKeyDown_); + htmlInput, 'keydown', this, this.onHtmlInputKeyDown_); // Resize after every keystroke. this.onKeyUpWrapper_ = Blockly.bindEventWithChecks_( - this.htmlInput_, 'keyup', this, this.onHtmlInputChange_); + htmlInput, 'keyup', this, this.onHtmlInputChange_); // Repeatedly resize when holding down a key. this.onKeyPressWrapper_ = Blockly.bindEventWithChecks_( - this.htmlInput_, 'keypress', this, this.onHtmlInputChange_); + htmlInput, 'keypress', this, this.onHtmlInputChange_); // TODO: Figure out if this is necessary. this.onWorkspaceChangeWrapper_ = this.resizeEditor_.bind(this); From 303115953e195742927efdc1262d3a46d18f3c63 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 7 Jun 2019 07:16:52 -0700 Subject: [PATCH 128/233] Moved to #2125 disposal. Cleaned up some doc. --- core/field.js | 15 +++----- core/field_angle.js | 14 +------- core/field_colour.js | 3 +- core/field_date.js | 1 - core/field_dropdown.js | 14 +++----- core/field_image.js | 10 ------ core/field_textinput.js | 78 ++++++++++++++++++++++------------------- core/field_variable.js | 10 ------ 8 files changed, 52 insertions(+), 93 deletions(-) diff --git a/core/field.js b/core/field.js index f4b95e3dab9..ecd8469cb5d 100644 --- a/core/field.js +++ b/core/field.js @@ -327,7 +327,7 @@ Blockly.Field.prototype.toXml = function(fieldElement) { }; /** - * Dispose of all DOM objects belonging to this editable field. + * Dispose of all DOM objects and events belonging to this editable field. * @package */ Blockly.Field.prototype.dispose = function() { @@ -336,16 +336,11 @@ Blockly.Field.prototype.dispose = function() { if (this.mouseDownWrapper_) { Blockly.unbindEvent_(this.mouseDownWrapper_); - this.mouseDownWrapper_ = null; } - this.sourceBlock_ = null; - if (this.fieldGroup_) { - Blockly.utils.dom.removeNode(this.fieldGroup_); - this.fieldGroup_ = null; - } - this.textElement_ = null; - this.borderRect_ = null; - this.validator_ = null; + + Blockly.utils.dom.removeNode(this.fieldGroup_); + + this.disposed = true; }; /** diff --git a/core/field_angle.js b/core/field_angle.js index a3c3574d379..13e264216db 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -130,15 +130,6 @@ Blockly.FieldAngle.prototype.initView = function() { this.textElement_.appendChild(this.symbol_); }; -/** - * Dispose of references to DOM elements and events belonging to this field. - * @package - */ -Blockly.FieldAngle.prototype.dispose = function() { - Blockly.FieldAngle.superClass_.dispose.call(this); - this.symbol_ = null; -}; - /** * Updates the graph when the field rerenders. * @private @@ -231,13 +222,10 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { }; /** - * Dispose of references to DOM elements and events belonging - * to the angle editor. + * Dispose of events belonging to the angle editor. * @private */ Blockly.FieldAngle.prototype.dropdownDispose_ = function() { - this.gauge_ = null; - this.line_ = null; Blockly.unbindEvent_(this.clickWrapper_); Blockly.unbindEvent_(this.moveWrapper1_); Blockly.unbindEvent_(this.moveWrapper2_); diff --git a/core/field_colour.js b/core/field_colour.js index 894f642f941..6fa02c696c9 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -332,8 +332,7 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() { }; /** - * Dispose of references to DOM elements and events belonging - * to the colour editor. + * Dispose of events belonging to the colour editor. * @private */ Blockly.FieldColour.prototype.dropdownDispose_ = function() { diff --git a/core/field_date.js b/core/field_date.js index 843d5356277..83f6a1c3443 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -240,7 +240,6 @@ Blockly.FieldDate.prototype.dropdownCreate_ = function() { * @private */ Blockly.FieldDate.prototype.dropdownDispose_ = function() { - this.picker_ = null; goog.events.unlistenByKey(this.changeEventKey_); goog.events.unlistenByKey(this.activeMonthEventKey_); }; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 5b1272f2d22..fd6863f7ebc 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -154,15 +154,6 @@ Blockly.FieldDropdown.prototype.initView = function() { } }; -/** - * Dispose of references to DOM elements and events belonging to this field. - */ -Blockly.FieldDropdown.prototype.dispose = function() { - Blockly.FieldDropdown.superClass_.dispose.call(this); - this.imageElement_ = null; - this.arrow_ = null; -}; - /** * Create a dropdown menu under the text. * @private @@ -223,8 +214,11 @@ Blockly.FieldDropdown.prototype.widgetCreate_ = function() { return menu; }; +/** + * Dispose of events belonging to the dropdown editor. + * @private + */ Blockly.FieldDropdown.prototype.widgetDispose_ = function() { - this.menu_ = null; goog.events.unlistenByKey(this.menuActionEventKey_); }; diff --git a/core/field_image.js b/core/field_image.js index 7a7bb96ec67..bd5a56ae176 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -129,16 +129,6 @@ Blockly.FieldImage.prototype.initView = function() { 'xlink:href', this.value_); }; -/** - * Dispose of all DOM objects belonging to this text. - */ -Blockly.FieldImage.prototype.dispose = function() { - Blockly.FieldImage.superClass_.dispose.call(this); - this.imageElement_ = null; - // TODO: Do we need to dispose of this? - this.clickHandler_ = null; -}; - /** * Ensure that the input value (the source URL) is a string. * @param {string=} newValue The input value diff --git a/core/field_textinput.js b/core/field_textinput.js index 20636c8e8e9..089d62b8ffd 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -232,6 +232,11 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { } }; +/** + * Create the text input editor widget. + * @return {HTMLInputElement} The newly created text input editor. + * @private + */ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { var div = Blockly.WidgetDiv.DIV; @@ -254,6 +259,42 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { return htmlInput; }; +/** + * Close the editor, save the results, and dispose any events bound to the + * text input's editor. + * @private + */ +Blockly.FieldTextInput.prototype.widgetDispose_ = function() { + // Finalize value. + this.isBeingEdited_ = false; + // No need to call setValue because if the widget is being closed the + // latest input text has already been validated. + if (this.value_ !== this.text_) { + // At the end of an edit the text should be the same as the value. It + // may not be if the input text is different than the validated text. + // We should fix that. + this.text_ = String(this.value_); + this.isTextValid_ = true; + this.forceRerender(); + } + // Otherwise don't rerender. + + // Call onFinishEditing + // TODO: Get rid of this or make it less of a hack. + if (this.onFinishEditing_) { + this.onFinishEditing_(this.value_); + } + + // Remove htmlInput events. + this.unbindInputEvents_(); + + // Delete style properties. + var style = Blockly.WidgetDiv.DIV.style; + style.width = 'auto'; + style.height = 'auto'; + style.fontSize = ''; +}; + /** * Bind handlers for user input on the text input field's editor. * @param {!HTMLInputElement} htmlInput The htmlInput to which event @@ -365,43 +406,6 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { div.style.top = xy.y + 'px'; }; -/** - * Close the editor, save the results, and dispose of the editable - * text field's elements. - * @private - */ -Blockly.FieldTextInput.prototype.widgetDispose_ = function() { - // Finalize value. - this.isBeingEdited_ = false; - // No need to call setValue because if the widget is being closed the - // latest input text has already been validated. - if (this.value_ !== this.text_) { - // At the end of an edit the text should be the same as the value. It - // may not be if the input text is different than the validated text. - // We should fix that. - this.text_ = String(this.value_); - this.isTextValid_ = true; - this.forceRerender(); - } - // Otherwise don't rerender. - - // Call onFinishEditing - // TODO: Get rid of this or make it less of a hack. - if (this.onFinishEditing_) { - this.onFinishEditing_(this.value_); - } - - // Remove htmlInput. - this.unbindInputEvents_(); - this.htmlInput_ = null; - - // Delete style properties. - var style = Blockly.WidgetDiv.DIV.style; - style.width = 'auto'; - style.height = 'auto'; - style.fontSize = ''; -}; - /** * Ensure that only a number may be entered. * @param {string} text The user's text. diff --git a/core/field_variable.js b/core/field_variable.js index 29aa44a0c30..278fe5c55b7 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -157,16 +157,6 @@ Blockly.FieldVariable.prototype.toXml = function(fieldElement) { return fieldElement; }; -/** - * Dispose of this field. - * @public - */ -Blockly.FieldVariable.prototype.dispose = function() { - Blockly.FieldVariable.superClass_.dispose.call(this); - this.workspace_ = null; - this.variableMap_ = null; -}; - /** * Attach this field to a block. * @param {!Blockly.Block} block The block containing this field. From 81035c3bcb5ba5e696b7122027177ea232be0eac Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 7 Jun 2019 07:22:08 -0700 Subject: [PATCH 129/233] Fixed unit tests. --- core/field_textinput.js | 8 -------- tests/mocha/field_angle_test.js | 14 +++++++------- tests/mocha/field_number_test.js | 14 +++++++------- tests/mocha/field_textinput_test.js | 12 ++++++------ 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/core/field_textinput.js b/core/field_textinput.js index 089d62b8ffd..2e6c438e594 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -88,14 +88,6 @@ Blockly.FieldTextInput.prototype.SERIALIZABLE = true; */ Blockly.FieldTextInput.FONTSIZE = 11; -/** - * The HTML input element for the user to type, or null if no FieldTextInput - * editor is currently open. - * @type {HTMLInputElement} - * @protected - */ -Blockly.FieldTextInput.htmlInput_ = null; - /** * Mouse cursor style when over the hotspot that initiates the editor. */ diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js index 7453c0a81ca..9a825283419 100644 --- a/tests/mocha/field_angle_test.js +++ b/tests/mocha/field_angle_test.js @@ -201,13 +201,13 @@ suite ('Angle Fields', function() { suite('Validators', function() { setup(function() { this.angleField = new Blockly.FieldAngle(1); - Blockly.FieldTextInput.htmlInput_ = Object.create(null); - Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; - Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; + this.angleField.htmlInput_ = Object.create(null); + this.angleField.htmlInput_.oldValue_ = '1'; + this.angleField.htmlInput_.untypedDefaultValue_ = 1; }); teardown(function() { this.angleField.setValidator(null); - Blockly.FieldTextInput.htmlInput_ = null; + this.angleField.htmlInput_ = null; }); suite('Null Validator', function() { setup(function() { @@ -217,7 +217,7 @@ suite ('Angle Fields', function() { }); test('When Editing', function() { this.angleField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = '2'; + this.angleField.htmlInput_.value = '2'; this.angleField.onHtmlInputChange_(null); assertValue(this.angleField, 1, '2'); this.angleField.isBeingEdited_ = false; @@ -235,7 +235,7 @@ suite ('Angle Fields', function() { }); test('When Editing', function() { this.angleField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = '25'; + this.angleField.htmlInput_.value = '25'; this.angleField.onHtmlInputChange_(null); assertValue(this.angleField, 30, '25'); this.angleField.isBeingEdited_ = false; @@ -251,7 +251,7 @@ suite ('Angle Fields', function() { }); test('When Editing', function() { this.angleField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = '2'; + this.angleField.htmlInput_.value = '2'; this.angleField.onHtmlInputChange_(null); assertValue(this.angleField, 2); this.angleField.isBeingEdited_ = false; diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index 5485c2d9421..4915c8b7fe3 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -298,13 +298,13 @@ suite ('Number Fields', function() { suite('Validators', function() { setup(function() { this.numberField = new Blockly.FieldNumber(1); - Blockly.FieldTextInput.htmlInput_ = Object.create(null); - Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; - Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; + this.numberField.htmlInput_ = Object.create(null); + this.numberField.htmlInput_.oldValue_ = '1'; + this.numberField.htmlInput_.untypedDefaultValue_ = 1; }); teardown(function() { this.numberField.setValidator(null); - Blockly.FieldTextInput.htmlInput_ = null; + this.numberField.htmlInput_ = null; }); suite('Null Validator', function() { setup(function() { @@ -314,7 +314,7 @@ suite ('Number Fields', function() { }); test('When Editing', function() { this.numberField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = '2'; + this.numberField.htmlInput_.value = '2'; this.numberField.onHtmlInputChange_(null); assertValue(this.numberField, 1, '2'); this.numberField.isBeingEdited_ = false; @@ -332,7 +332,7 @@ suite ('Number Fields', function() { }); test('When Editing', function() { this.numberField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = '25'; + this.numberField.htmlInput_.value = '25'; this.numberField.onHtmlInputChange_(null); assertValue(this.numberField, 26, '25'); this.numberField.isBeingEdited_ = false; @@ -348,7 +348,7 @@ suite ('Number Fields', function() { }); test('When Editing', function() { this.numberField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = '2'; + this.numberField.htmlInput_.value = '2'; this.numberField.onHtmlInputChange_(null); assertValue(this.numberField, 2); this.numberField.isBeingEdited_ = false; diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js index 30ed5b6886d..9b4e943be7f 100644 --- a/tests/mocha/field_textinput_test.js +++ b/tests/mocha/field_textinput_test.js @@ -169,9 +169,9 @@ suite ('Text Input Fields', function() { suite('Validators', function() { setup(function() { this.textInputField = new Blockly.FieldTextInput('value'); - Blockly.FieldTextInput.htmlInput_ = Object.create(null); - Blockly.FieldTextInput.htmlInput_.oldValue_ = 'value'; - Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 'value'; + this.textInputField.htmlInput_ = Object.create(null); + this.textInputField.htmlInput_.oldValue_ = 'value'; + this.textInputField.htmlInput_.untypedDefaultValue_ = 'value'; }); teardown(function() { this.textInputField.setValidator(null); @@ -185,7 +185,7 @@ suite ('Text Input Fields', function() { }); test('When Editing', function() { this.textInputField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = 'newValue'; + this.textInputField.htmlInput_.value = 'newValue'; this.textInputField.onHtmlInputChange_(null); assertValue(this.textInputField, 'value', 'newValue'); this.textInputField.isBeingEdited_ = false; @@ -203,7 +203,7 @@ suite ('Text Input Fields', function() { }); test('When Editing', function() { this.textInputField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = 'bbbaaa'; + this.textInputField.htmlInput_.value = 'bbbaaa'; this.textInputField.onHtmlInputChange_(null); assertValue(this.textInputField, 'bbb', 'bbbaaa'); this.textInputField.isBeingEdited_ = false; @@ -219,7 +219,7 @@ suite ('Text Input Fields', function() { }); test('When Editing', function() { this.textInputField.isBeingEdited_ = true; - Blockly.FieldTextInput.htmlInput_.value = 'newValue'; + this.textInputField.htmlInput_.value = 'newValue'; this.textInputField.onHtmlInputChange_(null); assertValue(this.textInputField, 'newValue'); this.textInputField.isBeingEdited_ = false; From 153817eaee1506ad83d557332a6399ca8fc26670 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 10 Jun 2019 15:26:44 -0700 Subject: [PATCH 130/233] Removed angle field WidgetDiv.hide call. --- core/field_angle.js | 1 - 1 file changed, 1 deletion(-) diff --git a/core/field_angle.js b/core/field_angle.js index 13e264216db..a4578c3eaad 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -237,7 +237,6 @@ Blockly.FieldAngle.prototype.dropdownDispose_ = function() { */ Blockly.FieldAngle.prototype.hide_ = function() { Blockly.DropDownDiv.hideIfOwner(this); - Blockly.WidgetDiv.hide(); }; /** From 7af5c5147ac349c4f8596a246a9726d509192aa8 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 10 Jun 2019 15:38:34 -0700 Subject: [PATCH 131/233] Fixed dropdown div not fading in correctly. --- core/dropdowndiv.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index b624b34485b..c7cb54ba3fa 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -139,6 +139,8 @@ Blockly.DropDownDiv.createDom = function() { div.appendChild(arrow); Blockly.DropDownDiv.arrow_ = arrow; + Blockly.DropDownDiv.DIV_.style.opacity = 0; + // Transition animation for transform: translate() and opacity. Blockly.DropDownDiv.DIV_.style.transition = 'transform ' + Blockly.DropDownDiv.ANIMATION_TIME + 's, ' + From 8ee266ea65b15057fdfd686b7c49ea8189d180a7 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 10 Jun 2019 16:14:17 -0700 Subject: [PATCH 132/233] Fixed dropdowndiv not animating correctly after hideChaff. Extracted dual functionality of positionInternal_ and moved it to hideWithoutAnimation. --- core/dropdowndiv.js | 60 +++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index c7cb54ba3fa..71ffe736871 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -463,7 +463,16 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { if (Blockly.DropDownDiv.animateOutTimer_) { clearTimeout(Blockly.DropDownDiv.animateOutTimer_); } - Blockly.DropDownDiv.positionInternal_(); + + // Reset style properties in case this gets called directly + // instead of hide() - see discussion on #2551. + var div = Blockly.DropDownDiv.DIV_; + div.style.transform = ''; + div.style.left = ''; + div.style.top = ''; + div.style.opacity = 0; + div.style.display = 'none'; + Blockly.DropDownDiv.clearContent(); Blockly.DropDownDiv.owner_ = null; if (Blockly.DropDownDiv.onHide_) { @@ -475,37 +484,36 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { /** * Set the dropdown div's position. - * @param {number} initialX Initial Horizontal location (window coordinates, not body). - * @param {number} initialY Initial Vertical location (window coordinates, not body). - * @param {number} finalX Final Horizontal location (window coordinates, not body). - * @param {number} finalY Final Vertical location (window coordinates, not body). + * @param {!number} initialX Initial Horizontal location + * (window coordinates, not body). + * @param {!number} initialY Initial Vertical location + * (window coordinates, not body). + * @param {!number} finalX Final Horizontal location + * (window coordinates, not body). + * @param {!number} finalY Final Vertical location + * (window coordinates, not body). * @private */ Blockly.DropDownDiv.positionInternal_ = function(initialX, initialY, finalX, finalY) { - initialX = initialX == null ? initialX : Math.floor(initialX); - initialY = initialY == null ? initialY : Math.floor(initialY); - finalX = finalX == null ? finalX : Math.floor(finalX); - finalY = finalY == null ? finalY : Math.floor(finalY); + initialX = Math.floor(initialX); + initialY = Math.floor(initialY); + finalX = Math.floor(finalX); + finalY = Math.floor(finalY); var div = Blockly.DropDownDiv.DIV_; // First apply initial translation. - div.style.left = initialX != null ? initialX + 'px' : ''; - div.style.top = initialY != null ? initialY + 'px' : ''; - if (finalX != null) { - // Show the div. - div.style.display = 'block'; - div.style.opacity = 1; - // Add final translate, animated through `transition`. - // Coordinates are relative to (initialX, initialY), - // where the drop-down is absolutely positioned. - var dx = (finalX - initialX); - var dy = (finalY - initialY); - div.style.transform = 'translate(' + dx + 'px,' + dy + 'px)'; - } else { - // Hide the div. - div.style.display = 'none'; - div.style.transform = ''; - } + div.style.left = initialX + 'px'; + div.style.top = initialY + 'px'; + + // Show the div. + div.style.display = 'block'; + div.style.opacity = 1; + // Add final translate, animated through `transition`. + // Coordinates are relative to (initialX, initialY), + // where the drop-down is absolutely positioned. + var dx = (finalX - initialX); + var dy = (finalY - initialY); + div.style.transform = 'translate(' + dx + 'px,' + dy + 'px)'; }; /** From 6d47853370f5f656f9b34a01277e88dae187b972 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 07:03:03 -0700 Subject: [PATCH 133/233] Fixed workspace scroll not properly hiding floating elements. --- core/workspace_svg.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 7cedea7ee51..52f7dae05d5 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1913,6 +1913,8 @@ Blockly.WorkspaceSvg.prototype.setScale = function(newScale) { * @package */ Blockly.WorkspaceSvg.prototype.scroll = function(x, y) { + Blockly.hideChaff(/* opt_allowToolbox */ true); + // Keep scrolling within the bounds of the content. var metrics = this.getMetrics(); // This is the offset of the top-left corner of the view from the @@ -1945,10 +1947,6 @@ Blockly.WorkspaceSvg.prototype.scroll = function(x, y) { this.scrollbar.vScroll.setHandlePosition(-(y + metrics.contentTop) * this.scrollbar.vScroll.ratio_); } - - // Hide the WidgetDiv without animation. This is to prevent a disposal - // animation from happening in the wrong location. - Blockly.WidgetDiv.hide(true); // We have to shift the translation so that when the canvas is at 0, 0 the // workspace origin is not underneath the toolbox. x += metrics.absoluteLeft; From 2af17fd782d9f2e22337bd57c52dab0a5e5b030d Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 07:07:14 -0700 Subject: [PATCH 134/233] Removed obsolete widgetDiv check in tooltip code. --- core/tooltip.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/tooltip.js b/core/tooltip.js index eded96dd4ee..24d661cc099 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -211,9 +211,6 @@ Blockly.Tooltip.onMouseMove_ = function(e) { if (!Blockly.Tooltip.element_ || !Blockly.Tooltip.element_.tooltip) { // No tooltip here to show. return; - } else if (Blockly.WidgetDiv.isVisible()) { - // Don't display a tooltip if a widget is open (tooltip would be under it). - return; } else if (Blockly.Tooltip.blocked_) { // Someone doesn't want us to show tooltips. We are probably handling a // user gesture, such as a click or drag. From 392119680e46b355eb15243c7ca17f18610a783f Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 07:12:57 -0700 Subject: [PATCH 135/233] Fixed misc PR comments. --- core/dropdowndiv.js | 12 ++++++------ core/field_angle.js | 3 +-- core/field_textinput.js | 11 +++-------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 71ffe736871..62e31079478 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -484,13 +484,13 @@ Blockly.DropDownDiv.hideWithoutAnimation = function() { /** * Set the dropdown div's position. - * @param {!number} initialX Initial Horizontal location + * @param {number} initialX Initial Horizontal location * (window coordinates, not body). - * @param {!number} initialY Initial Vertical location + * @param {number} initialY Initial Vertical location * (window coordinates, not body). - * @param {!number} finalX Final Horizontal location + * @param {number} finalX Final Horizontal location * (window coordinates, not body). - * @param {!number} finalY Final Vertical location + * @param {number} finalY Final Vertical location * (window coordinates, not body). * @private */ @@ -511,8 +511,8 @@ Blockly.DropDownDiv.positionInternal_ = function(initialX, initialY, finalX, fin // Add final translate, animated through `transition`. // Coordinates are relative to (initialX, initialY), // where the drop-down is absolutely positioned. - var dx = (finalX - initialX); - var dy = (finalY - initialY); + var dx = finalX - initialX; + var dy = finalY - initialY; div.style.transform = 'translate(' + dx + 'px,' + dy + 'px)'; }; diff --git a/core/field_angle.js b/core/field_angle.js index a4578c3eaad..b6bdfebbbe6 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -155,8 +155,7 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { Blockly.DropDownDiv.getContentDiv().appendChild(editor); var border = this.sourceBlock_.getColourBorder(); - border = border.colourBorder == null ? - border.colourLight : border.colourBorder; + border = border.colourBorder || border.colourLight; Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), border); Blockly.DropDownDiv.showPositionedByField( diff --git a/core/field_textinput.js b/core/field_textinput.js index 2e6c438e594..df82ee4d63b 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -26,7 +26,6 @@ goog.provide('Blockly.FieldTextInput'); -goog.require('Blockly.DropDownDiv'); goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockChange'); goog.require('Blockly.Field'); @@ -226,7 +225,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) { /** * Create the text input editor widget. - * @return {HTMLInputElement} The newly created text input editor. + * @return {!HTMLInputElement} The newly created text input editor. * @private */ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { @@ -236,7 +235,7 @@ Blockly.FieldTextInput.prototype.widgetCreate_ = function() { htmlInput.className = 'blocklyHtmlInput'; htmlInput.setAttribute('spellcheck', this.spellcheck_); var fontSize = - (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt'; + (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt'; div.style.fontSize = fontSize; htmlInput.style.fontSize = fontSize; div.appendChild(htmlInput); @@ -320,8 +319,7 @@ Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() { Blockly.unbindEvent_(this.onKeyDownWrapper_); Blockly.unbindEvent_(this.onKeyUpWrapper_); Blockly.unbindEvent_(this.onKeyPressWrapper_); - this.workspace_.removeChangeListener( - this.onWorkspaceChangeWrapper_); + this.workspace_.removeChangeListener(this.onWorkspaceChangeWrapper_); }; /** @@ -333,14 +331,11 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) { var tabKey = 9, enterKey = 13, escKey = 27; if (e.keyCode == enterKey) { Blockly.WidgetDiv.hide(); - Blockly.DropDownDiv.hideIfOwner(this); } else if (e.keyCode == escKey) { this.htmlInput_.value = this.htmlInput_.defaultValue; Blockly.WidgetDiv.hide(); - Blockly.DropDownDiv.hideIfOwner(this); } else if (e.keyCode == tabKey) { Blockly.WidgetDiv.hide(); - Blockly.DropDownDiv.hideIfOwner(this); this.sourceBlock_.tab(this, !e.shiftKey); e.preventDefault(); } From 4b0397de1731717171fd8744735a4d3fef635029 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 13:48:01 -0700 Subject: [PATCH 136/233] Cleaned up utils renamings. Readded widget div hide in field angle. --- core/field_angle.js | 15 ++++++++------- core/field_dropdown.js | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index b6bdfebbbe6..465909a6b24 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -146,9 +146,9 @@ Blockly.FieldAngle.prototype.render_ = function() { Blockly.FieldAngle.prototype.showEditor_ = function() { // Mobile browsers have issues with in-line textareas (focus & keyboards). var noFocus = - Blockly.userAgent.MOBILE || - Blockly.userAgent.ANDROID || - Blockly.userAgent.IPAD; + Blockly.utils.userAgent.MOBILE || + Blockly.utils.userAgent.ANDROID || + Blockly.utils.userAgent.IPAD; Blockly.FieldAngle.superClass_.showEditor_.call(this, noFocus); var editor = this.dropdownCreate_(); @@ -170,7 +170,7 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { * @private */ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { - var svg = Blockly.utils.createSvgElement('svg', { + var svg = Blockly.utils.dom.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', @@ -178,16 +178,16 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { 'height': (Blockly.FieldAngle.HALF * 2) + 'px', 'width': (Blockly.FieldAngle.HALF * 2) + 'px' }, null); - var circle = Blockly.utils.createSvgElement('circle', { + var circle = Blockly.utils.dom.createSvgElement('circle', { 'cx': Blockly.FieldAngle.HALF, 'cy': Blockly.FieldAngle.HALF, 'r': Blockly.FieldAngle.RADIUS, 'class': 'blocklyAngleCircle' }, svg); - this.gauge_ = Blockly.utils.createSvgElement('path', { + this.gauge_ = Blockly.utils.dom.createSvgElement('path', { 'class': 'blocklyAngleGauge' }, svg); - this.line_ = Blockly.utils.createSvgElement('line', { + this.line_ = Blockly.utils.dom.createSvgElement('line', { 'x1': Blockly.FieldAngle.HALF, 'y1': Blockly.FieldAngle.HALF, 'class': 'blocklyAngleLine' @@ -236,6 +236,7 @@ Blockly.FieldAngle.prototype.dropdownDispose_ = function() { */ Blockly.FieldAngle.prototype.hide_ = function() { Blockly.DropDownDiv.hideIfOwner(this); + Blockly.WidgetDiv.hide(); }; /** diff --git a/core/field_dropdown.js b/core/field_dropdown.js index fd6863f7ebc..6f136022442 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -165,7 +165,7 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { this.menu_.render(Blockly.WidgetDiv.DIV); // Element gets created in render. - Blockly.utils.addClass(this.menu_.getElement(), 'blocklyDropdownMenu'); + Blockly.utils.dom.addClass(this.menu_.getElement(), 'blocklyDropdownMenu'); this.positionMenu_(this.menu_); From 6f69b856395552683a8f5ce535da29c1fbd60937 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 14:24:48 -0700 Subject: [PATCH 137/233] Removed unnecessary todo's. --- core/field_date.js | 1 - core/field_dropdown.js | 1 - 2 files changed, 2 deletions(-) diff --git a/core/field_date.js b/core/field_date.js index 83f6a1c3443..f507dca2509 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -246,7 +246,6 @@ Blockly.FieldDate.prototype.dropdownDispose_ = function() { /** * Handle a CHANGE event in the date picker. - * TODO: Not sure what the type for goog event information is. * @param {!Event} event The CHANGE event. * @private */ diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 6f136022442..b2bf6bb72e8 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -224,7 +224,6 @@ Blockly.FieldDropdown.prototype.widgetDispose_ = function() { /** * Handle an ACTION event in the dropdown menu. - * TODO: Not sure what the type for goog event information is. * @param {!Event} event The CHANGE event. * @private */ From efdfec6d8a12a0bc83edd608b5f9063f247deb27 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 14:29:19 -0700 Subject: [PATCH 138/233] Fixed last rebase error. --- core/field_angle.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/field_angle.js b/core/field_angle.js index 465909a6b24..75e65fb6273 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -171,9 +171,9 @@ Blockly.FieldAngle.prototype.showEditor_ = function() { */ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { var svg = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': 'http://www.w3.org/2000/svg', - 'xmlns:html': 'http://www.w3.org/1999/xhtml', - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, 'version': '1.1', 'height': (Blockly.FieldAngle.HALF * 2) + 'px', 'width': (Blockly.FieldAngle.HALF * 2) + 'px' From d05ce11736c93e533618e9d3b9dfdee3f2d3576e Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 10 Jun 2019 15:59:27 -0700 Subject: [PATCH 139/233] Added trashcan tests. --- tests/mocha/index.html | 1 + tests/mocha/trashcan_test.js | 561 +++++++++++++++++++++++++++++++++++ 2 files changed, 562 insertions(+) create mode 100644 tests/mocha/trashcan_test.js diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 48c0c2e5183..735eaa0bcb9 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -37,6 +37,7 @@ + diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js new file mode 100644 index 00000000000..e1dc8225684 --- /dev/null +++ b/tests/mocha/trashcan_test.js @@ -0,0 +1,561 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite("Trashcan", function() { + var workspace = { + addChangeListener: function(func) { + this.listener = func; + }, + triggerListener: function(event) { + this.listener(event); + }, + options: { + maxTrashcanContents: Infinity + } + }; + function sendDeleteEvent(xmlString) { + var xml = Blockly.Xml.textToDom(xmlString); + xml = xml.children[0]; + var event = { + type: Blockly.Events.BLOCK_DELETE, + oldXml: xml + }; + workspace.triggerListener(event); + } + + setup(function() { + this.trashcan = new Blockly.Trashcan(workspace); + this.setLidStub = sinon.stub(this.trashcan, 'setLidAngle_'); + }); + teardown(function() { + this.setLidStub.restore(); + this.trashcan = null; + }); + + suite("Events", function() { + test("Delete", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + }); + test("Non-Delete", function() { + var event = { + type: 'dummy_type' + }; + workspace.triggerListener(event); + chai.assert.equal(this.trashcan.contents_.length, 0); + }); + test("Non-Delete w/ oldXml", function() { + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + '' + ); + xml = xml.children[0]; + var event = { + type: 'dummy_type', + oldXml: xml + }; + workspace.triggerListener(event); + chai.assert.equal(this.trashcan.contents_.length, 0); + }); + test("Shadow Delete", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 0); + }); + }); + suite("Unique Contents", function() { + test("Simple", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + }); + test("No Coords - Coords", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + }); + test("Different Coords", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + }); + test("No ID - ID", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + }); + test("Different IDs", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + }); + test("No Disabled - Disabled True", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Disabled - Disabled False", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + // TODO: Is this how we want this to work? To the user they appear to + // be the same. + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Disabled", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Editable - Editable True", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + // TODO: Is this how we want this to work? To the user they appear to + // be the same. + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Editable - Editable False", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Editable", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Movable - Movable True", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + // TODO: Is this how we want this to work? To the user they appear to + // be the same. + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Movable - Movable False", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Movable", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Fields - Fields", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' dummy_value' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Field Values", function() { + sendDeleteEvent( + '' + + ' ' + + ' dummy_value1' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' dummy_value2' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Values - Values", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Value Blocks", function() { + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Statements - Statements", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Statement Blocks", function() { + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Next - Next", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Next Blocks", function() { + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Comment - Comment", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' comment_text' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Comment Text", function() { + sendDeleteEvent( + '' + + ' ' + + ' comment_text1' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' comment_text2' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Comment Size", function() { + sendDeleteEvent( + '' + + ' ' + + ' comment_text' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' comment_text' + + ' ' + + '' + ); + // TODO: Is this how we want this to work? The difference is not + // related to the content. + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Comment Pinned", function() { + sendDeleteEvent( + '' + + ' ' + + ' comment_text' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' comment_text' + + ' ' + + '' + ); + // TODO: Is this how we want this to work? The difference is not + // related to the content. + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("No Mutator - Mutator", function() { + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + test("Different Mutator", function() { + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 2); + }); + }); + suite("Max Contents", function() { + test("Max 0", function() { + workspace.options.maxTrashcanContents = 0; + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 0); + workspace.options.maxTrashcanContents = Infinity; + }); + test("Last In First Out", function() { + workspace.options.maxTrashcanContents = 1; + sendDeleteEvent( + '' + + ' ' + + '' + ); + sendDeleteEvent( + '' + + ' ' + + '' + ); + chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal( + Blockly.Xml.textToDom(this.trashcan.contents_[0]) + .children[0].getAttribute('type'), + 'dummy_type2' + ); + workspace.options.maxTrashcanContents = Infinity; + }); + }); +}); From bf6d621c63ddfd80ee85fcf0bb129e037f001820 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Tue, 11 Jun 2019 15:35:18 -0700 Subject: [PATCH 140/233] Added colour and date editor auto close on selection. --- core/field_colour.js | 1 + core/field_date.js | 1 + 2 files changed, 2 insertions(+) diff --git a/core/field_colour.js b/core/field_colour.js index 6fa02c696c9..5f26899ad67 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -291,6 +291,7 @@ Blockly.FieldColour.prototype.onClick_ = function(e) { var colour = cell && cell.label; if (colour !== null) { this.setValue(colour); + Blockly.DropDownDiv.hideIfOwner(this); } }; diff --git a/core/field_date.js b/core/field_date.js index f507dca2509..730677bc288 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -252,6 +252,7 @@ Blockly.FieldDate.prototype.dropdownDispose_ = function() { Blockly.FieldDate.prototype.onDateSelected_ = function(event) { var date = event.date ? event.date.toIsoString(true) : ''; this.setValue(date); + Blockly.DropDownDiv.hideIfOwner(this); }; /** From b8cbd9e7df00120f9c75e69c2b98c3bd025d63f8 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 11 Jun 2019 21:12:29 -0700 Subject: [PATCH 141/233] Resolve 13 warnings Reduce count from 632 to 619. Eliminate copy-paste code duplication in Field.prototype.setValue --- blocks/logic.js | 2 +- blocks/procedures.js | 19 ++++++++-------- core/block_svg.js | 8 +++---- core/blockly.js | 10 ++++----- core/bubble.js | 2 +- core/field.js | 47 ++++++++++++++++++++++++---------------- core/field_date.js | 1 - core/field_textinput.js | 2 +- core/flyout_base.js | 2 +- core/options.js | 2 +- core/utils/coordinate.js | 12 +++++----- core/workspace_svg.js | 2 +- 12 files changed, 59 insertions(+), 50 deletions(-) diff --git a/blocks/logic.js b/blocks/logic.js index 8de2ae6d47b..c5f156a81f8 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -468,7 +468,7 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = { i++; } // Rebuild block. - for (var i = 1; i <= this.elseifCount_; i++) { + for (i = 1; i <= this.elseifCount_; i++) { this.appendValueInput('IF' + i) .setCheck('Boolean') .appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSEIF']); diff --git a/blocks/procedures.js b/blocks/procedures.js index 591a751a1d8..1c29e758354 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -372,17 +372,18 @@ Blockly.Blocks['procedures_defnoreturn'] = { // Add options to create getters for each parameter. if (!this.isCollapsed()) { for (var i = 0; i < this.argumentVarModels_.length; i++) { - var option = {enabled: true}; + var argOption = {enabled: true}; var argVar = this.argumentVarModels_[i]; - var name = argVar.name; - option.text = Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace('%1', name); + argOption.text = Blockly.Msg['VARIABLES_SET_CREATE_GET'] + .replace('%1', argVar.name); - var xmlField = Blockly.Variables.generateVariableFieldDom(argVar); - var xmlBlock = document.createElement('block'); - xmlBlock.setAttribute('type', 'variables_get'); - xmlBlock.appendChild(xmlField); - option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); - options.push(option); + var argXmlField = Blockly.Variables.generateVariableFieldDom(argVar); + var argXmlBlock = document.createElement('block'); + argXmlBlock.setAttribute('type', 'variables_get'); + argXmlBlock.appendChild(argXmlField); + argOption.callback = + Blockly.ContextMenu.callbackFactory(this, argXmlBlock); + options.push(argOption); } } }, diff --git a/core/block_svg.js b/core/block_svg.js index c340576be21..a1d41800f8f 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -700,8 +700,8 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) { if (this.workspace.options.disable && this.isEditable()) { // Option to disable/enable block. var disableOption = { - text: this.disabled ? - Blockly.Msg['ENABLE_BLOCK'] : Blockly.Msg['DISABLE_BLOCK'], + text: this.isEnabled() ? + Blockly.Msg['DISABLE_BLOCK'] : Blockly.Msg['ENABLE_BLOCK'], enabled: !this.getInheritedDisabled(), callback: function() { var group = Blockly.Events.getGroup(); @@ -936,7 +936,7 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { * Change the colour of a block. */ Blockly.BlockSvg.prototype.updateColour = function() { - if (this.disabled) { + if (!this.isEnabled()) { // Disabled blocks don't have colour. return; } @@ -999,7 +999,7 @@ Blockly.BlockSvg.prototype.setShadowColour_ = function() { * Enable or disable a block. */ Blockly.BlockSvg.prototype.updateDisabled = function() { - if (this.disabled || this.getInheritedDisabled()) { + if (!this.isEnabled() || this.getInheritedDisabled()) { var added = Blockly.utils.dom.addClass( /** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); if (added) { diff --git a/core/blockly.js b/core/blockly.js index 832a6af42c0..e42ad533ee1 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -107,7 +107,7 @@ Blockly.clipboardTypeCounts_ = null; /** * Cached value for whether 3D is supported. - * @type {!boolean} + * @type {?boolean} * @private */ Blockly.cache3dSupported_ = null; @@ -181,9 +181,9 @@ Blockly.svgResize = function(workspace) { // TODO (https://github.com/google/blockly/issues/1998) handle cases where there // are multiple workspaces and non-main workspaces are able to accept input. Blockly.onKeyDown_ = function(e) { - var workspace = Blockly.mainWorkspace; - if (workspace.options.readOnly || Blockly.utils.isTargetInput(e) || - (workspace.rendered && !workspace.isVisible())) { + var mainWorkspace = Blockly.mainWorkspace; + if (mainWorkspace.options.readOnly || Blockly.utils.isTargetInput(e) || + (mainWorkspace.rendered && !mainWorkspace.isVisible())) { // No key actions on readonly workspaces. // When focused on an HTML text input widget, don't trap any keys. // Ignore keypresses on rendered workspaces that have been explicitly @@ -247,7 +247,7 @@ Blockly.onKeyDown_ = function(e) { } else if (e.keyCode == 90) { // 'z' for undo 'Z' is for redo. Blockly.hideChaff(); - workspace.undo(e.shiftKey); + mainWorkspace.undo(e.shiftKey); } } // Common code for delete and cut. diff --git a/core/bubble.js b/core/bubble.js index d5b9f31b124..fe72b2c64ae 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -374,7 +374,7 @@ Blockly.Bubble.prototype.registerResizeEvent = function(callback) { /** * Move this bubble to the top of the stack. - * @return {!boolean} Whether or not the bubble has been moved. + * @return {boolean} Whether or not the bubble has been moved. * @private */ Blockly.Bubble.prototype.promote_ = function() { diff --git a/core/field.js b/core/field.js index ecd8469cb5d..86fd2981843 100644 --- a/core/field.js +++ b/core/field.js @@ -736,31 +736,19 @@ Blockly.Field.prototype.setValue = function(newValue) { var validatedValue = this.doClassValidation_(newValue); // Class validators might accidentally forget to return, we'll ignore that. - if (validatedValue !== undefined) { - newValue = validatedValue; - } - if (newValue === null) { - doLogging && console.log('invalid, return'); - this.doValueInvalid_(); - if (this.isDirty_) { - this.forceRerender(); - } + newValue = this.validate_(newValue, validatedValue); + if (newValue instanceof Error) { + doLogging && console.log('invalid class validation, return'); return; } var localValidator = this.getValidator(); if (localValidator) { - var validatedValue = localValidator.call(this, newValue); + validatedValue = localValidator.call(this, newValue); // Local validators might accidentally forget to return, we'll ignore that. - if (validatedValue !== undefined) { - newValue = validatedValue; - } - if (newValue === null) { - doLogging && console.log('invalid, return'); - this.doValueInvalid_(); - if (this.isDirty_) { - this.forceRerender(); - } + newValue = this.validate_(newValue, validatedValue); + if (newValue instanceof Error) { + doLogging && console.log('invalid local validation, return'); return; } } @@ -782,6 +770,27 @@ Blockly.Field.prototype.setValue = function(newValue) { doLogging && console.log(this.value_); }; +/** + * Process the result of validation. + * @param {*} newValue New value. + * @param {*} validatedValue Validated value. + * @return {*} New value, or an Error object. + * @private + */ +Blockly.Field.prototype.validate_ = function(newValue, validatedValue) { + if (validatedValue !== undefined) { + newValue = validatedValue; + } + if (newValue === null) { + this.doValueInvalid_(); + if (this.isDirty_) { + this.forceRerender(); + } + return Error(); + } + return newValue; +}; + /** * Get the current value of the field. * @return {*} Current value. diff --git a/core/field_date.js b/core/field_date.js index 730677bc288..20290fa683a 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -36,7 +36,6 @@ goog.require('goog.date.DateTime'); goog.require('goog.events'); goog.require('goog.i18n.DateTimeSymbols'); goog.require('goog.i18n.DateTimeSymbols_he'); -goog.require('goog.style'); goog.require('goog.ui.DatePicker'); diff --git a/core/field_textinput.js b/core/field_textinput.js index df82ee4d63b..a79d55e0393 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -134,7 +134,7 @@ Blockly.FieldTextInput.prototype.doValueInvalid_ = function() { * Called by setValue if the text input is valid. Updates the value of the * field, and updates the text of the field if it is not currently being * edited (i.e. handled by the htmlInput_). - * @param {!string} newValue The new validated value of the field. + * @param {string} newValue The new validated value of the field. * @protected */ Blockly.FieldTextInput.prototype.doValueUpdate_ = function(newValue) { diff --git a/core/flyout_base.js b/core/flyout_base.js index e427982843c..b92c6bcf832 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -608,7 +608,7 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) { * Does this flyout allow you to create a new instance of the given block? * Used for deciding if a block can be "dragged out of" the flyout. * @param {!Blockly.BlockSvg} block The block to copy from the flyout. - * @return {!boolean} True if you can create a new instance of the block, false + * @return {boolean} True if you can create a new instance of the block, false * otherwise. * @package */ diff --git a/core/options.js b/core/options.js index 9c71541f4bc..3775f2dcbc3 100644 --- a/core/options.js +++ b/core/options.js @@ -164,7 +164,7 @@ Blockly.Options.prototype.getMetrics = null; * Parse the user-specified move options, using reasonable defaults where * behaviour is unspecified. * @param {!Object} options Dictionary of options. - * @param {!boolean} hasCategories Whether the workspace has categories or not. + * @param {boolean} hasCategories Whether the workspace has categories or not. * @return {!Object} A dictionary of normalized options. * @private */ diff --git a/core/utils/coordinate.js b/core/utils/coordinate.js index 7d08362d35b..21d6ca50f77 100644 --- a/core/utils/coordinate.js +++ b/core/utils/coordinate.js @@ -94,8 +94,8 @@ Blockly.utils.Coordinate.magnitude = function(a) { /** * Returns the difference between two coordinates as a new * Blockly.utils.Coordinate. - * @param {!Blockly.utils.Coordinate} a A Coordinate. - * @param {!Blockly.utils.Coordinate} b A Coordinate. + * @param {!Blockly.utils.Coordinate|!SVGPoint} a An x/y coordinate. + * @param {!Blockly.utils.Coordinate|!SVGPoint} b An x/y coordinate. * @return {!Blockly.utils.Coordinate} A Coordinate representing the difference * between `a` and `b`. */ @@ -105,10 +105,10 @@ Blockly.utils.Coordinate.difference = function(a, b) { /** * Returns the sum of two coordinates as a new Blockly.utils.Coordinate. - * @param {!Blockly.utils.Coordinate} a A Coordinate. - * @param {!Blockly.utils.Coordinate} b A Coordinate. - * @return {!Blockly.utils.Coordinate} A Coordinate representing the sum of the two - * coordinates. + * @param {!Blockly.utils.Coordinate|!SVGPoint} a An x/y coordinate. + * @param {!Blockly.utils.Coordinate|!SVGPoint} b An x/y coordinate. + * @return {!Blockly.utils.Coordinate} A Coordinate representing the sum of + * the two coordinates. */ Blockly.utils.Coordinate.sum = function(a, b) { return new Blockly.utils.Coordinate(a.x + b.x, a.y + b.y); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 52f7dae05d5..5fd0c889965 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1676,7 +1676,7 @@ Blockly.WorkspaceSvg.prototype.zoom = function(x, y, amount) { // Find the new scrollX/scrollY so that the center remains in the same // position (relative to the center) after we zoom. // newScale and matrix.a should be identical (within a rounding error). - var matrix = matrix.translate(x * (1 - scaleChange), y * (1 - scaleChange)) + matrix = matrix.translate(x * (1 - scaleChange), y * (1 - scaleChange)) .scale(scaleChange); // scrollX and scrollY are in pixels. // The scrollX and scrollY still need to have absoluteLeft and absoluteTop From f1c73e2244fe3bece46ac554e43b8036646c431d Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 11 Jun 2019 23:28:07 -0700 Subject: [PATCH 142/233] Rename helper function --- core/field.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/field.js b/core/field.js index 86fd2981843..7c50b46a644 100644 --- a/core/field.js +++ b/core/field.js @@ -736,7 +736,7 @@ Blockly.Field.prototype.setValue = function(newValue) { var validatedValue = this.doClassValidation_(newValue); // Class validators might accidentally forget to return, we'll ignore that. - newValue = this.validate_(newValue, validatedValue); + newValue = this.processValidation_(newValue, validatedValue); if (newValue instanceof Error) { doLogging && console.log('invalid class validation, return'); return; @@ -746,7 +746,7 @@ Blockly.Field.prototype.setValue = function(newValue) { if (localValidator) { validatedValue = localValidator.call(this, newValue); // Local validators might accidentally forget to return, we'll ignore that. - newValue = this.validate_(newValue, validatedValue); + newValue = this.processValidation_(newValue, validatedValue); if (newValue instanceof Error) { doLogging && console.log('invalid local validation, return'); return; @@ -777,7 +777,8 @@ Blockly.Field.prototype.setValue = function(newValue) { * @return {*} New value, or an Error object. * @private */ -Blockly.Field.prototype.validate_ = function(newValue, validatedValue) { +Blockly.Field.prototype.processValidation_ = function(newValue, + validatedValue) { if (validatedValue !== undefined) { newValue = validatedValue; } From 74f908d77f12d664ca6687f11d051e11aa028e0c Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 12 Jun 2019 00:19:58 -0700 Subject: [PATCH 143/233] Fix escaping issue in Code demo. Resolves #1002 --- demos/code/code.js | 30 ++++++++++++++---------------- demos/code/index.html | 10 +++++----- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/demos/code/code.js b/demos/code/code.js index 7128adfc76c..373650603fd 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -304,35 +304,33 @@ Code.renderContent = function() { xmlTextarea.value = xmlText; xmlTextarea.focus(); } else if (content.id == 'content_javascript') { - Code.attemptCodeGeneration(Blockly.JavaScript, 'js'); + Code.attemptCodeGeneration(Blockly.JavaScript); } else if (content.id == 'content_python') { - Code.attemptCodeGeneration(Blockly.Python, 'py'); + Code.attemptCodeGeneration(Blockly.Python); } else if (content.id == 'content_php') { - Code.attemptCodeGeneration(Blockly.PHP, 'php'); + Code.attemptCodeGeneration(Blockly.PHP); } else if (content.id == 'content_dart') { - Code.attemptCodeGeneration(Blockly.Dart, 'dart'); + Code.attemptCodeGeneration(Blockly.Dart); } else if (content.id == 'content_lua') { - Code.attemptCodeGeneration(Blockly.Lua, 'lua'); + Code.attemptCodeGeneration(Blockly.Lua); + } + if (typeof PR == 'object') { + PR.prettyPrint(); } }; /** * Attempt to generate the code and display it in the UI, pretty printed. * @param generator {!Blockly.Generator} The generator to use. - * @param prettyPrintType {string} The file type key for the pretty printer. */ -Code.attemptCodeGeneration = function(generator, prettyPrintType) { +Code.attemptCodeGeneration = function(generator) { var content = document.getElementById('content_' + Code.selected); content.textContent = ''; if (Code.checkAllGeneratorFunctionsDefined(generator)) { var code = generator.workspaceToCode(Code.workspace); - content.textContent = code; - if (typeof PR.prettyPrintOne == 'function') { - code = content.textContent; - code = PR.prettyPrintOne(code, prettyPrintType); - content.innerHTML = code; - } + // Remove the 'prettyprinted' class, so that Prettify will recalculate. + content.className = content.className.replace('prettyprinted', ''); } }; @@ -346,7 +344,7 @@ Code.checkAllGeneratorFunctionsDefined = function(generator) { for (var i = 0; i < blocks.length; i++) { var blockType = blocks[i].type; if (!generator[blockType]) { - if (missingBlockGenerators.indexOf(blockType) === -1) { + if (missingBlockGenerators.indexOf(blockType) == -1) { missingBlockGenerators.push(blockType); } } @@ -354,8 +352,8 @@ Code.checkAllGeneratorFunctionsDefined = function(generator) { var valid = missingBlockGenerators.length == 0; if (!valid) { - var msg = 'The generator code for the following blocks not specified for ' - + generator.name_ + ':\n - ' + missingBlockGenerators.join('\n - '); + var msg = 'The generator code for the following blocks not specified for ' + + generator.name_ + ':\n - ' + missingBlockGenerators.join('\n - '); Blockly.alert(msg); // Assuming synchronous. No callback. } return valid; diff --git a/demos/code/index.html b/demos/code/index.html index e591c6a5491..c206a3fbb18 100644 --- a/demos/code/index.html +++ b/demos/code/index.html @@ -66,11 +66,11 @@

Blockly‏ >
-

-  

-  

-  

-  

+  

+  

+  

+  

+