一.什么是Blockly
(1)概述:
- Blockly是一种可视化编程工具,是众多可视化编程工具的鼻祖。
- 2012年6月,Google发布的完全可视化的编程语言Goole Blockly。
- Blockly代码块由类似于积木的图形对象构成,只需要拖拖拽拽就可以实现程序的功能。
(2)详述:
- 一种基于网页的可视化是程序:
- Google Blockly是基于网页的可视化编程库,用户可以离线或者在线进行编程操作。
- 多种开发语言环境库:
- Blockly代码块可以通过自带的语言转换工具箱转换成JavaScript、Python、PHP、Lua、Dart等多种语言。
- 开源的自定义编程环境:
- 用户可以自己定义Blockly代码块放入Blockly的工具箱中,用于以后使用。
(3)Blockly的使用流程图:
- 我们可以使用Blockly的工具箱编写Blockly代码块实现程序功能,然后使用语言转换器转换为需要的语言。
- 我们也可以自定义Blockly代码块生成工具放入工具箱和语言转换器中,用于以后使用。
二.Blockly的编程环境
(1)Blockly有在线和离线版本
- 在线版本网址: https://developers.google.cn/blockly
- 离线版本下载网址:https://github.com/google/blockly
- 下载后在demos目录下,使用浏览器打开index.html即可。
(2)Blockly在线版本
(3)Blockly离线版本
-
离线Blockly的一些demo例子:
- Fixed Blockly :固定大小的Blockly块的工作空间,不会随浏览器大小变化而变化。
- Resizable Blockly :可变大小的Blockly块的工作空间,会随浏览器大小变化而变化。
- Defining the Toolbox :Blockly自定义的工具箱
- Maximum Block Limit :限制Blockly块的个数,不能超过指定Blockly个数。
- Generate JavaScript :生成JavaScript代码
- Headless :将xml代码生成其他的语言的代码
- JS Interpreter :展示使用Blockly代码块生成JavaScript代码并可以单步执行。
- Graph :通过数学公式在坐标系中生成图形
- RTL :从右到左显示Blockly块(对于阿拉伯语和希伯来语使用)
- Custom Dialogs :自定义实现覆盖浏览器对话框
- Custom Fields :自定义字段
- Cloud Storage :云存储在App Engine
- Mirrored Blockly :展示两个同步的Blockly工作区,左侧主工作区变化,右侧从工作区也发生变化。
- Accessible Blockly : 屏幕阅读无障碍访问版本
- Plane :支持35种语言
- Code Editor :将Blocky程序导出成JavaScript,Python,PHP,Lua,Dart或XML
- Blockly Developer Tools :使用Blockly构建自定义的代码块并设置到工作箱。
三.Blockly的功能模块
工具箱中有8个主要模块: blockly-master>demos>code>index.html 中可以查看源码
运行index.html结果:(右上角可以修改语言类型为简体中文)
主要为大家讲解三个文件 blockly_compressed.js , blocks_compressed.js , javascript_compressed.js
(1) blocks_compressed.js :定义了Blockly工具箱中的所有可用Blockly块,仅仅是Blockly.Blocks的内容。
以下:讲解loops(循环)模块程序代码
- 其中 Blockly.defineBlocksWithJsonArray([{...},{...},{...},...]) :用于定义某一个工具,例如循环工具所有Blockly块。
- 每一个 {...} 都包含一个循环模块的Blockly块:6个循环模块
- controls_repeat_ext
- controls_repeat
- controls_whileUntil
- controls_for
- controls_forEach
- controls_flow_statements
1 Blockly.Blocks.loops = {}; 2 Blockly.Constants.Loops = {}; 3 Blockly.Constants.Loops.HUE = 120; 4 Blockly.defineBlocksWithJsonArray([{ 5 type: "controls_repeat_ext", 6 message0: "%{BKY_CONTROLS_REPEAT_TITLE}", 7 args0: [{ 8 type: "input_value", 9 name: "TIMES", 10 check: "Number" 11 }], 12 message1: "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1", 13 args1: [{ 14 type: "input_statement", 15 name: "DO" 16 }], 17 previousStatement: null, 18 nextStatement: null, 19 style: "loop_blocks", 20 tooltip: "%{BKY_CONTROLS_REPEAT_TOOLTIP}", 21 helpUrl: "%{BKY_CONTROLS_REPEAT_HELPURL}" 22 }, { 23 type: "controls_repeat", 24 message0: "%{BKY_CONTROLS_REPEAT_TITLE}", 25 args0: [{ 26 type: "field_number", 27 name: "TIMES", 28 value: 10, 29 min: 0, 30 precision: 1 31 }], 32 message1: "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1", 33 args1: [{ 34 type: "input_statement", 35 name: "DO" 36 }], 37 previousStatement: null, 38 nextStatement: null, 39 style: "loop_blocks", 40 tooltip: "%{BKY_CONTROLS_REPEAT_TOOLTIP}", 41 helpUrl: "%{BKY_CONTROLS_REPEAT_HELPURL}" 42 }, { 43 type: "controls_whileUntil", 44 message0: "%1 %2", 45 args0: [{ 46 type: "field_dropdown", 47 name: "MODE", 48 options: [ 49 ["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_WHILE}", "WHILE"], 50 ["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_UNTIL}", "UNTIL"] 51 ] 52 }, { 53 type: "input_value", 54 name: "BOOL", 55 check: "Boolean" 56 }], 57 message1: "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1", 58 args1: [{ 59 type: "input_statement", 60 name: "DO" 61 }], 62 previousStatement: null, 63 nextStatement: null, 64 style: "loop_blocks", 65 helpUrl: "%{BKY_CONTROLS_WHILEUNTIL_HELPURL}", 66 extensions: ["controls_whileUntil_tooltip"] 67 }, { 68 type: "controls_for", 69 message0: "%{BKY_CONTROLS_FOR_TITLE}", 70 args0: [{ 71 type: "field_variable", 72 name: "VAR", 73 variable: null 74 }, { 75 type: "input_value", 76 name: "FROM", 77 check: "Number", 78 align: "RIGHT" 79 }, { 80 type: "input_value", 81 name: "TO", 82 check: "Number", 83 align: "RIGHT" 84 }, { 85 type: "input_value", 86 name: "BY", 87 check: "Number", 88 align: "RIGHT" 89 }], 90 message1: "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1", 91 args1: [{ 92 type: "input_statement", 93 name: "DO" 94 }], 95 inputsInline: !0, 96 previousStatement: null, 97 nextStatement: null, 98 style: "loop_blocks", 99 helpUrl: "%{BKY_CONTROLS_FOR_HELPURL}", 100 extensions: ["contextMenu_newGetVariableBlock", "controls_for_tooltip"] 101 }, { 102 type: "controls_forEach", 103 message0: "%{BKY_CONTROLS_FOREACH_TITLE}", 104 args0: [{ 105 type: "field_variable", 106 name: "VAR", 107 variable: null 108 }, { 109 type: "input_value", 110 name: "LIST", 111 check: "Array" 112 }], 113 message1: "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1", 114 args1: [{ 115 type: "input_statement", 116 name: "DO" 117 }], 118 previousStatement: null, 119 nextStatement: null, 120 style: "loop_blocks", 121 helpUrl: "%{BKY_CONTROLS_FOREACH_HELPURL}", 122 extensions: ["contextMenu_newGetVariableBlock", "controls_forEach_tooltip"] 123 }, { 124 type: "controls_flow_statements", 125 message0: "%1", 126 args0: [{ 127 type: "field_dropdown", 128 name: "FLOW", 129 options: [ 130 ["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK}", "BREAK"], 131 ["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE}", "CONTINUE"] 132 ] 133 }], 134 previousStatement: null, 135 style: "loop_blocks", 136 helpUrl: "%{BKY_CONTROLS_FLOW_STATEMENTS_HELPURL}", 137 extensions: ["controls_flow_tooltip", "controls_flow_in_loop_check"] 138 }]); 139 Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS = { 140 WHILE: "%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}", 141 UNTIL: "%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}" 142 }; 143 Blockly.Extensions.register("controls_whileUntil_tooltip", Blockly.Extensions.buildTooltipForDropdown("MODE", Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS)); 144 Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS = { 145 BREAK: "%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}", 146 CONTINUE: "%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}" 147 }; 148 Blockly.Extensions.register("controls_flow_tooltip", Blockly.Extensions.buildTooltipForDropdown("FLOW", Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS)); 149 Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = { 150 customContextMenu: function (a) { 151 if (!this.isInFlyout) { 152 var b = this.getField("VAR").getVariable(), 153 c = b.name; 154 if (!this.isCollapsed() && null != c) { 155 var d = { 156 enabled: !0 157 }; 158 d.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1", c); 159 b = Blockly.Variables.generateVariableFieldDom(b); 160 c = Blockly.utils.xml.createElement("block"); 161 c.setAttribute("type", "variables_get"); 162 c.appendChild(b); 163 d.callback = Blockly.ContextMenu.callbackFactory(this, c); 164 a.push(d) 165 } 166 } 167 } 168 }; 169 Blockly.Extensions.registerMixin("contextMenu_newGetVariableBlock", Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN); 170 Blockly.Extensions.register("controls_for_tooltip", Blockly.Extensions.buildTooltipWithFieldText("%{BKY_CONTROLS_FOR_TOOLTIP}", "VAR")); 171 Blockly.Extensions.register("controls_forEach_tooltip", Blockly.Extensions.buildTooltipWithFieldText("%{BKY_CONTROLS_FOREACH_TOOLTIP}", "VAR")); 172 Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = { 173 LOOP_TYPES: ["controls_repeat", "controls_repeat_ext", "controls_forEach", "controls_for", "controls_whileUntil"], 174 suppressPrefixSuffix: !0, 175 getSurroundLoop: function (a) { 176 do { 177 if (-1 != Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.indexOf(a.type)) return a; 178 a = a.getSurroundParent() 179 } while (a); 180 return null 181 }, 182 onchange: function (a) { 183 this.workspace.isDragging && !this.workspace.isDragging() && (Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(this) ? 184 (this.setWarningText(null), this.isInFlyout || this.setEnabled(!0)) : (this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING), this.isInFlyout || this.getInheritedDisabled() || this.setEnabled(!1))) 185 } 186 }; 187 Blockly.Extensions.registerMixin("controls_flow_in_loop_check", Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);
抽取定义的一段代码: controls_for 循环功能模块
分析:一个message对应一个args,args中是一个数组里面嵌套多个对象,一个对象中主要有type表示类型,name表示名称。
1 { 2 type: "controls_for", 3 message0: "%{BKY_CONTROLS_FOR_TITLE}", 4 args0: [{ 5 type: "field_variable", 6 name: "VAR", 7 variable: null 8 }, { 9 type: "input_value", 10 name: "FROM", 11 check: "Number", 12 align: "RIGHT" 13 }, { 14 type: "input_value", 15 name: "TO", 16 check: "Number", 17 align: "RIGHT" 18 }, { 19 type: "input_value", 20 name: "BY", 21 check: "Number", 22 align: "RIGHT" 23 }], 24 message1: "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1", 25 args1: [{ 26 type: "input_statement", 27 name: "DO" 28 }], 29 inputsInline: !0, 30 previousStatement: null, 31 nextStatement: null, 32 style: "loop_blocks", 33 helpUrl: "%{BKY_CONTROLS_FOR_HELPURL}", 34 extensions: ["contextMenu_newGetVariableBlock", "controls_for_tooltip"] 35 }
在html中的代码:
我们根据值以及类型进行赋值
1 <block type="controls_for"> 2 <field name="VAR">i</field> 3 <value name="FROM"> 4 <block type="math_number"> 5 <field name="NUM">1</field> 6 </block> 7 </value> 8 <value name="TO"> 9 <block type="math_number"> 10 <field name="NUM">10</field> 11 </block> 12 </value> 13 <value name="BY"> 14 <block type="math_number"> 15 <field name="NUM">1</field> 16 </block> 17 </value> 18 </block>
显示的样式:
(2) javascript_compressed.js :主要是将定义好的Blocks的工具箱创建出来的程序解析成JavaScript代码。
以下截取一小段:主要将Blocks的list解析为JavaScript的Array。
1 Blockly.JavaScript.lists = {}; 2 Blockly.JavaScript.lists_create_empty = function (a) { 3 return ["[]", Blockly.JavaScript.ORDER_ATOMIC] 4 }; 5 Blockly.JavaScript.lists_create_with = function (a) { 6 for (var b = Array(a.itemCount_), c = 0; c < a.itemCount_; c++) b[c] = Blockly.JavaScript.valueToCode(a, "ADD" + c, Blockly.JavaScript.ORDER_COMMA) || "null"; 7 return ["[" + b.join(", ") + "]", Blockly.JavaScript.ORDER_ATOMIC] 8 }; 9 Blockly.JavaScript.lists_repeat = function (a) { 10 var b = Blockly.JavaScript.provideFunction_("listsRepeat", ["function " + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + "(value, n) {", " var array = [];", " for (var i = 0; i < n; i++) {", " array[i] = value;", " }", " return array;", "}"]), 11 c = Blockly.JavaScript.valueToCode(a, "ITEM", Blockly.JavaScript.ORDER_COMMA) || "null"; 12 a = Blockly.JavaScript.valueToCode(a, "NUM", Blockly.JavaScript.ORDER_COMMA) || "0"; 13 return [b + "(" + c + ", " + a + ")", Blockly.JavaScript.ORDER_FUNCTION_CALL] 14 }; 15 Blockly.JavaScript.lists_length = function (a) { 16 return [(Blockly.JavaScript.valueToCode(a, "VALUE", Blockly.JavaScript.ORDER_MEMBER) || "[]") + ".length", Blockly.JavaScript.ORDER_MEMBER] 17 }; 18 Blockly.JavaScript.lists_isEmpty = function (a) { 19 return ["!" + (Blockly.JavaScript.valueToCode(a, "VALUE", Blockly.JavaScript.ORDER_MEMBER) || "[]") + ".length", Blockly.JavaScript.ORDER_LOGICAL_NOT] 20 }; 21 Blockly.JavaScript.lists_indexOf = function (a) { 22 var b = "FIRST" == a.getFieldValue("END") ? "indexOf" : "lastIndexOf", 23 c = Blockly.JavaScript.valueToCode(a, "FIND", Blockly.JavaScript.ORDER_NONE) || "''"; 24 b = (Blockly.JavaScript.valueToCode(a, "VALUE", Blockly.JavaScript.ORDER_MEMBER) || "[]") + "." + b + "(" + c + ")"; 25 return a.workspace.options.oneBasedIndex ? [b + " + 1", Blockly.JavaScript.ORDER_ADDITION] : [b, Blockly.JavaScript.ORDER_FUNCTION_CALL] 26 }; 27 Blockly.JavaScript.lists_getIndex = function (a) { 28 var b = a.getFieldValue("MODE") || "GET", 29 c = a.getFieldValue("WHERE") || "FROM_START", 30 d = Blockly.JavaScript.valueToCode(a, "VALUE", "RANDOM" == c ? Blockly.JavaScript.ORDER_COMMA : Blockly.JavaScript.ORDER_MEMBER) || "[]"; 31 switch (c) { 32 case "FIRST": 33 if ("GET" == b) return [d + "[0]", Blockly.JavaScript.ORDER_MEMBER]; 34 if ("GET_REMOVE" == b) return [d + ".shift()", Blockly.JavaScript.ORDER_MEMBER]; 35 if ("REMOVE" == b) return d + ".shift(); "; 36 break; 37 case "LAST": 38 if ("GET" == b) return [d + ".slice(-1)[0]", Blockly.JavaScript.ORDER_MEMBER]; 39 if ("GET_REMOVE" == b) return [d + ".pop()", Blockly.JavaScript.ORDER_MEMBER]; 40 if ("REMOVE" == b) return d + ".pop(); "; 41 break; 42 case "FROM_START": 43 a = Blockly.JavaScript.getAdjusted(a, "AT"); 44 if ("GET" == b) return [d + "[" + a + "]", Blockly.JavaScript.ORDER_MEMBER]; 45 if ("GET_REMOVE" == b) return [d + ".splice(" + a + ", 1)[0]", Blockly.JavaScript.ORDER_FUNCTION_CALL]; 46 if ("REMOVE" == b) return d + ".splice(" + a + ", 1); "; 47 break; 48 case "FROM_END": 49 a = Blockly.JavaScript.getAdjusted(a, "AT", 1, !0); 50 if ("GET" == b) return [d + ".slice(" + a + ")[0]", Blockly.JavaScript.ORDER_FUNCTION_CALL]; 51 if ("GET_REMOVE" == b) return [d + ".splice(" + a + ", 1)[0]", Blockly.JavaScript.ORDER_FUNCTION_CALL]; 52 if ("REMOVE" == b) return d + ".splice(" + a + ", 1);"; 53 break; 54 case "RANDOM": 55 d = Blockly.JavaScript.provideFunction_("listsGetRandomItem", ["function " + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + "(list, remove) {", " var x = Math.floor(Math.random() * list.length);", " if (remove) {", " return list.splice(x, 1)[0];", " } else {", " return list[x];", " }", "}"]) + "(" + d + ", " + ("GET" != b) + ")"; 56 if ("GET" == b || "GET_REMOVE" == b) return [d, 57 Blockly.JavaScript.ORDER_FUNCTION_CALL 58 ]; 59 if ("REMOVE" == b) return d + "; " 60 } 61 throw Error("Unhandled combination (lists_getIndex)."); 62 }; 63 Blockly.JavaScript.lists_setIndex = function (a) { 64 function b() { 65 if (c.match(/^w+$/)) return ""; 66 var a = Blockly.JavaScript.variableDB_.getDistinctName("tmpList", Blockly.Variables.NAME_TYPE), 67 b = "var " + a + " = " + c + "; "; 68 c = a; 69 return b 70 } 71 var c = Blockly.JavaScript.valueToCode(a, "LIST", Blockly.JavaScript.ORDER_MEMBER) || "[]", 72 d = a.getFieldValue("MODE") || "GET", 73 e = a.getFieldValue("WHERE") || "FROM_START", 74 f = Blockly.JavaScript.valueToCode(a, "TO", Blockly.JavaScript.ORDER_ASSIGNMENT) || "null"; 75 switch (e) { 76 case "FIRST": 77 if ("SET" == d) return c + 78 "[0] = " + f + "; "; 79 if ("INSERT" == d) return c + ".unshift(" + f + "); "; 80 break; 81 case "LAST": 82 if ("SET" == d) return a = b(), a + (c + "[" + c + ".length - 1] = " + f + "; "); 83 if ("INSERT" == d) return c + ".push(" + f + "); "; 84 break; 85 case "FROM_START": 86 e = Blockly.JavaScript.getAdjusted(a, "AT"); 87 if ("SET" == d) return c + "[" + e + "] = " + f + "; "; 88 if ("INSERT" == d) return c + ".splice(" + e + ", 0, " + f + "); "; 89 break; 90 case "FROM_END": 91 e = Blockly.JavaScript.getAdjusted(a, "AT", 1, !1, Blockly.JavaScript.ORDER_SUBTRACTION); 92 a = b(); 93 if ("SET" == d) return a + (c + "[" + c + ".length - " + e + 94 "] = " + f + "; "); 95 if ("INSERT" == d) return a + (c + ".splice(" + c + ".length - " + e + ", 0, " + f + "); "); 96 break; 97 case "RANDOM": 98 a = b(); 99 e = Blockly.JavaScript.variableDB_.getDistinctName("tmpX", Blockly.Variables.NAME_TYPE); 100 a += "var " + e + " = Math.floor(Math.random() * " + c + ".length); "; 101 if ("SET" == d) return a + (c + "[" + e + "] = " + f + "; "); 102 if ("INSERT" == d) return a + (c + ".splice(" + e + ", 0, " + f + "); ") 103 } 104 throw Error("Unhandled combination (lists_setIndex)."); 105 }; 106 Blockly.JavaScript.lists.getIndex_ = function (a, b, c) { 107 return "FIRST" == b ? "0" : "FROM_END" == b ? a + ".length - 1 - " + c : "LAST" == b ? a + ".length - 1" : c 108 }; 109 Blockly.JavaScript.lists_getSublist = function (a) { 110 var b = Blockly.JavaScript.valueToCode(a, "LIST", Blockly.JavaScript.ORDER_MEMBER) || "[]", 111 c = a.getFieldValue("WHERE1"), 112 d = a.getFieldValue("WHERE2"); 113 if ("FIRST" == c && "LAST" == d) b += ".slice(0)"; 114 else if (b.match(/^w+$/) || "FROM_END" != c && "FROM_START" == d) { 115 switch (c) { 116 case "FROM_START": 117 var e = Blockly.JavaScript.getAdjusted(a, "AT1"); 118 break; 119 case "FROM_END": 120 e = Blockly.JavaScript.getAdjusted(a, "AT1", 1, !1, Blockly.JavaScript.ORDER_SUBTRACTION); 121 e = b + ".length - " + e; 122 break; 123 case "FIRST": 124 e = 125 "0"; 126 break; 127 default: 128 throw Error("Unhandled option (lists_getSublist)."); 129 } 130 switch (d) { 131 case "FROM_START": 132 a = Blockly.JavaScript.getAdjusted(a, "AT2", 1); 133 break; 134 case "FROM_END": 135 a = Blockly.JavaScript.getAdjusted(a, "AT2", 0, !1, Blockly.JavaScript.ORDER_SUBTRACTION); 136 a = b + ".length - " + a; 137 break; 138 case "LAST": 139 a = b + ".length"; 140 break; 141 default: 142 throw Error("Unhandled option (lists_getSublist)."); 143 } 144 b = b + ".slice(" + e + ", " + a + ")" 145 } else { 146 e = Blockly.JavaScript.getAdjusted(a, "AT1"); 147 a = Blockly.JavaScript.getAdjusted(a, "AT2"); 148 var f = Blockly.JavaScript.lists.getIndex_, 149 g = { 150 FIRST: "First", 151 LAST: "Last", 152 FROM_START: "FromStart", 153 FROM_END: "FromEnd" 154 }; 155 b = Blockly.JavaScript.provideFunction_("subsequence" + g[c] + g[d], ["function " + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + "(sequence" + ("FROM_END" == c || "FROM_START" == c ? ", at1" : "") + ("FROM_END" == d || "FROM_START" == d ? ", at2" : "") + ") {", " var start = " + f("sequence", c, "at1") + ";", " var end = " + f("sequence", d, "at2") + " + 1;", " return sequence.slice(start, end);", "}"]) + "(" + b + ("FROM_END" == c || "FROM_START" == c ? ", " + e : "") + ("FROM_END" == d || "FROM_START" == 156 d ? ", " + a : "") + ")" 157 } 158 return [b, Blockly.JavaScript.ORDER_FUNCTION_CALL] 159 }; 160 Blockly.JavaScript.lists_sort = function (a) { 161 var b = Blockly.JavaScript.valueToCode(a, "LIST", Blockly.JavaScript.ORDER_FUNCTION_CALL) || "[]", 162 c = "1" === a.getFieldValue("DIRECTION") ? 1 : -1; 163 a = a.getFieldValue("TYPE"); 164 var d = Blockly.JavaScript.provideFunction_("listsGetSortCompare", ["function " + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + "(type, direction) {", " var compareFuncs = {", ' "NUMERIC": function(a, b) {', " return Number(a) - Number(b); },", ' "TEXT": function(a, b) {', " return a.toString() > b.toString() ? 1 : -1; },", 165 ' "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; }", "}" 166 ]); 167 return [b + ".slice().sort(" + d + '("' + a + '", ' + c + "))", Blockly.JavaScript.ORDER_FUNCTION_CALL] 168 }; 169 Blockly.JavaScript.lists_split = function (a) { 170 var b = Blockly.JavaScript.valueToCode(a, "INPUT", Blockly.JavaScript.ORDER_MEMBER), 171 c = Blockly.JavaScript.valueToCode(a, "DELIM", Blockly.JavaScript.ORDER_NONE) || "''"; 172 a = a.getFieldValue("MODE"); 173 if ("SPLIT" == a) b || (b = "''"), a = "split"; 174 else if ("JOIN" == a) b || (b = "[]"), a = "join"; 175 else throw Error("Unknown mode: " + a); 176 return [b + "." + a + "(" + c + ")", Blockly.JavaScript.ORDER_FUNCTION_CALL] 177 }; 178 Blockly.JavaScript.lists_reverse = function (a) { 179 return [(Blockly.JavaScript.valueToCode(a, "LIST", Blockly.JavaScript.ORDER_FUNCTION_CALL) || "[]") + ".slice().reverse()", Blockly.JavaScript.ORDER_FUNCTION_CALL] 180 };