├── LICENSE ├── blockly ├── arduino_compressed.js ├── blockly_compressed.js ├── blocks_compressed.js ├── media │ ├── 1x1.gif │ ├── click.mp3 │ ├── click.ogg │ ├── click.wav │ ├── delete.mp3 │ ├── delete.ogg │ ├── delete.wav │ ├── handclosed.cur │ ├── handdelete.cur │ ├── handopen.cur │ ├── icon.png │ ├── icons.svg │ ├── sprites.png │ └── sprites.svg └── msg │ └── messages.js ├── blocklyduinofactory.js ├── factory.js ├── factory_blocks.js ├── filesaver ├── Blob.js └── FileSaver.min.js ├── generator.js ├── index.html ├── prettify ├── prettify.css └── prettify.js ├── preview.js └── style.css /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2011 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /blockly/arduino_compressed.js: -------------------------------------------------------------------------------- 1 | // Do not edit this file; automatically generated by build.py. 2 | 'use strict'; 3 | 4 | Blockly.Arduino=new Blockly.Generator("Arduino");Blockly.Arduino.addReservedWords("setup,loop,if,else,for,switch,case,while,do,break,continue,return,goto,define,include,HIGH,LOW,INPUT,OUTPUT,INPUT_PULLUP,true,false,interger, constants,floating,point,void,bookean,char,unsigned,byte,int,word,long,float,double,string,String,array,static, volatile,const,sizeof,pinMode,digitalWrite,digitalRead,analogReference,analogRead,analogWrite,tone,noTone,shiftOut,shitIn,pulseIn,millis,micros,delay,delayMicroseconds,min,max,abs,constrain,map,pow,sqrt,sin,cos,tan,randomSeed,random,lowByte,highByte,bitRead,bitWrite,bitSet,bitClear,bit,attachInterrupt,detachInterrupt,interrupts,noInterrupts"); 5 | Blockly.Arduino.ORDER_ATOMIC=0;Blockly.Arduino.ORDER_UNARY_POSTFIX=1;Blockly.Arduino.ORDER_UNARY_PREFIX=2;Blockly.Arduino.ORDER_MULTIPLICATIVE=3;Blockly.Arduino.ORDER_ADDITIVE=4;Blockly.Arduino.ORDER_SHIFT=5;Blockly.Arduino.ORDER_RELATIONAL=6;Blockly.Arduino.ORDER_EQUALITY=7;Blockly.Arduino.ORDER_BITWISE_AND=8;Blockly.Arduino.ORDER_BITWISE_XOR=9;Blockly.Arduino.ORDER_BITWISE_OR=10;Blockly.Arduino.ORDER_LOGICAL_AND=11;Blockly.Arduino.ORDER_LOGICAL_OR=12;Blockly.Arduino.ORDER_CONDITIONAL=13; 6 | Blockly.Arduino.ORDER_ASSIGNMENT=14;Blockly.Arduino.ORDER_NONE=99;var profile={arduino:{description:"Arduino standard-compatible board",digital:[["1","1"],["2","2"],["3","3"],["4","4"],["5","5"],["6","6"],["7","7"],["8","8"],["9","9"],["10","10"],["11","11"],["12","12"],["13","13"],["A0","A0"],["A1","A1"],["A2","A2"],["A3","A3"],["A4","A4"],["A5","A5"]],analog:[["A0","A0"],["A1","A1"],["A2","A2"],["A3","A3"],["A4","A4"],["A5","A5"]],serial:9600},arduino_mega:{description:"Arduino Mega-compatible board"}}; 7 | profile["default"]=profile.arduino; 8 | Blockly.Arduino.init=function(a){Blockly.Arduino.definitions_=Object.create(null);Blockly.Arduino.setups_=Object.create(null);Blockly.Arduino.variableDB_?Blockly.Arduino.variableDB_.reset():Blockly.Arduino.variableDB_=new Blockly.Names(Blockly.Arduino.RESERVED_WORDS_);var b=[];a=Blockly.Variables.allVariables(a);for(var c=0;c\n";Blockly.Arduino.definitions_["var_servo"+a]="Servo servo_"+a+";\n";Blockly.Arduino.setups_["setup_servo_"+a]="servo_"+a+".attach("+a+");\n";return"servo_"+a+".write("+b+");\ndelay("+c+");\n"}; 18 | Blockly.Arduino.servo_read_degrees=function(){var a=this.getFieldValue("PIN");Blockly.Arduino.definitions_.define_servo="#include <Servo.h>\n";Blockly.Arduino.definitions_["var_servo"+a]="Servo servo_"+a+";\n";Blockly.Arduino.setups_["setup_servo_"+a]="servo_"+a+".attach("+a+");\n";return"servo_"+a+".read()"}; 19 | Blockly.Arduino.serial_print=function(){var a=Blockly.Arduino.valueToCode(this,"CONTENT",Blockly.Arduino.ORDER_ATOMIC)||"0";Blockly.Arduino.setups_["setup_serial_"+profile["default"].serial]="Serial.begin("+profile["default"].serial+");\n";return"Serial.println("+a+");\n"};Blockly.Arduino.loops={}; 20 | Blockly.Arduino.controls_for=function(){var a=Blockly.Arduino.variableDB_.getName(this.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),b=Blockly.Arduino.valueToCode(this,"FROM",Blockly.Arduino.ORDER_ASSIGNMENT)||"0",c=Blockly.Arduino.valueToCode(this,"TO",Blockly.Arduino.ORDER_ASSIGNMENT)||"0",d=Blockly.Arduino.statementToCode(this,"DO");Blockly.Arduino.INFINITE_LOOP_TRAP&&(d=Blockly.Arduino.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+this.id+"'")+d);if(b.match(/^-?\d+(\.\d+)?$/)&&c.match(/^-?\d+(\.\d+)?$/))var e= 21 | parseFloat(b)<=parseFloat(c),d="for ("+a+" = "+b+"; "+a+(e?" <= ":" >= ")+c+"; "+a+(e?"++":"--")+") {\n"+d+"}\n";else d="",e=b,b.match(/^\w+$/)||b.match(/^-?\d+(\.\d+)?$/)||(e=Blockly.Arduino.variableDB_.getDistinctName(a+"_start",Blockly.Variables.NAME_TYPE),d+="int "+e+" = "+b+";\n"),b=c,c.match(/^\w+$/)||c.match(/^-?\d+(\.\d+)?$/)||(b=Blockly.Arduino.variableDB_.getDistinctName(a+"_end",Blockly.Variables.NAME_TYPE),d+="int "+b+" = "+c+";\n"),d+="for ("+a+" = "+e+";\n ("+e+" <= "+b+") ? "+a+ 22 | " <= "+b+" : "+a+" >= "+b+";\n "+a+" += ("+e+" <= "+b+") ? 1 : -1) {\n"+branch0+"}\n";return d};Blockly.Arduino.controls_whileUntil=function(){var a="UNTIL"==this.getFieldValue("MODE"),b=Blockly.Arduino.valueToCode(this,"BOOL",a?Blockly.Arduino.ORDER_LOGICAL_NOT:Blockly.Arduino.ORDER_NONE)||"false",c=Blockly.Arduino.statementToCode(this,"DO");Blockly.Arduino.INFINITE_LOOP_TRAP&&(c=Blockly.Arduino.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+this.id+"'")+c);a&&(b="!"+b);return"while ("+b+") {\n"+c+"}\n"};Blockly.Arduino.grove={};Blockly.Arduino.grove_led=function(){var a=this.getFieldValue("PIN"),b=this.getFieldValue("STAT");Blockly.Arduino.setups_["setup_green_led_"+a]="pinMode("+a+", OUTPUT);";return"digitalWrite("+a+","+b+");\n"};Blockly.Arduino.grove_button=function(){var a=this.getFieldValue("PIN");Blockly.Arduino.setups_["setup_button_"+a]="pinMode("+a+", INPUT);";return["digitalRead("+a+")",Blockly.Arduino.ORDER_ATOMIC]}; 23 | Blockly.Arduino.grove_rotary_angle=function(){return["analogRead("+this.getFieldValue("PIN")+")",Blockly.Arduino.ORDER_ATOMIC]};Blockly.Arduino.grove_tilt_switch=function(){var a=this.getFieldValue("PIN");Blockly.Arduino.setups_["setup_tilt_switch_"+a]="pinMode("+a+", INPUT);";return["digitalRead("+a+")",Blockly.Arduino.ORDER_ATOMIC]}; 24 | Blockly.Arduino.grove_piezo_buzzer=function(){var a=this.getFieldValue("PIN"),b=this.getFieldValue("STAT");Blockly.Arduino.setups_["setup_piezo_buzzer_"+a]="pinMode("+a+", OUTPUT);";return"digitalWrite("+a+","+b+");\n"};Blockly.Arduino.grove_relay=function(){var a=this.getFieldValue("PIN"),b=this.getFieldValue("STAT");Blockly.Arduino.setups_["setup_relay_"+a]="pinMode("+a+", OUTPUT);";return"digitalWrite("+a+","+b+");\n"}; 25 | Blockly.Arduino.grove_temporature_sensor=function(){var a=this.getFieldValue("PIN");return["round((1/(log((float)(1023-analogRead("+a+"))*10000/analogRead("+a+"))/10000)/3975+1/298.15)-273.15)",Blockly.Arduino.ORDER_ATOMIC]}; 26 | var _get_next_pin=function(a){var b=a,b=parseInt(b)?parseInt(a)+1:"A"+(parseInt(b.slice(1,b.length))+1);a=profile["default"].digital.length;for(var c=!0,d=0;d\n";Blockly.Arduino.definitions_.define_softwareserial="#include \n";var e= 28 | _get_next_pin(a);Blockly.Arduino.definitions_["var_lcd_"+a]="SerialLCD slcd_"+a+"("+a+","+e+");\n";Blockly.Arduino.setups_["setup_lcd_"+a]="slcd_"+a+".begin();\n";e="slcd_"+a+".backlight();\n"+("slcd_"+a+".setCursor(0,0);\n");e+="slcd_"+a+".print("+b+");\n";e+="slcd_"+a+".setCursor(0,1);\n";e+="slcd_"+a+".print("+c+");\n";return e+="delay("+d+");\n"}; 29 | Blockly.Arduino.grove_serial_lcd_power=function(){var a=this.getFieldValue("PIN"),b=this.getFieldValue("STAT");Blockly.Arduino.definitions_.define_seriallcd="#include \n";Blockly.Arduino.definitions_.define_softwareserial="#include \n";var c=_get_next_pin(a);Blockly.Arduino.definitions_["var_lcd"+a]="SerialLCD slcd_"+a+"("+a+","+c+");\n";a="slcd_"+a;return"ON"===b?a+".Power();\n":a+".noPower();\n"}; 30 | Blockly.Arduino.grove_serial_lcd_effect=function(){var a=this.getFieldValue("PIN"),b=this.getFieldValue("STAT");Blockly.Arduino.definitions_.define_seriallcd="#include \n";Blockly.Arduino.definitions_.define_softwareserial="#include \n";var c=_get_next_pin(a);Blockly.Arduino.definitions_["var_lcd"+a]="SerialLCD slcd_"+a+"("+a+","+c+");\n";a="slcd_"+a;return"LEFT"===b?a+".scrollDisplayLeft();\n":"RIGHT"===b?a+".scrollDisplayRight();\n":a+".autoscroll();\n"}; 31 | Blockly.Arduino.grove_sound_sensor=function(){return["analogRead("+this.getFieldValue("PIN")+")",Blockly.Arduino.ORDER_ATOMIC]};Blockly.Arduino.grove_pir_motion_sensor=function(){var a=this.getFieldValue("PIN");Blockly.Arduino.setups_["setup_input_"+a]="pinMode("+a+", INPUT);";return["digitalRead("+a+")",Blockly.Arduino.ORDER_ATOMIC]}; 32 | Blockly.Arduino.grove_line_finder=function(){var a=this.getFieldValue("PIN");Blockly.Arduino.setups_["setup_input_"+a]="pinMode("+a+", INPUT);";return["digitalRead("+a+")",Blockly.Arduino.ORDER_ATOMIC]}; 33 | Blockly.Arduino.grove_ultrasonic_ranger=function(){var a=this.getFieldValue("PIN"),b=this.getFieldValue("UNIT");Blockly.Arduino.definitions_.define_ultrasonic="#include \n";Blockly.Arduino.definitions_["var_ultrasonic"+a]="Ultrasonic ultrasonic_"+a+"("+a+");\n";"cm"===b?(Blockly.Arduino.setups_["setup_ultrasonic_"+a]="ultrasonic_"+a+".MeasureInCentimeters();",a="ultrasonic_"+a+".RangeInCentimeters();"):(Blockly.Arduino.setups_["setup_ultrasonic_"+a]="ultrasonic_"+a+".MeasureInInches();", 34 | a="ultrasonic_"+a+".RangeInInches();");return[a,Blockly.Arduino.ORDER_ATOMIC]}; 35 | Blockly.Arduino.grove_motor_shield=function(){var a=this.getFieldValue("DIRECTION");Blockly.Arduino.setups_.setup_motor="pinMode(8,OUTPUT);//I1\n pinMode(11,OUTPUT);//I2\n pinMode(9,OUTPUT);//speedPinA\n pinMode(12,OUTPUT);//I3\n pinMode(13,OUTPUT);//i4\n pinMode(10,OUTPUT);//speedPinB\n";var b="";"forward"===a?(Blockly.Arduino.definitions_.define_forward="void forward()\n{\n analogWrite(9,127);//input a simulation value to set the speed\n analogWrite(10,127);\n digitalWrite(13,HIGH);//turn DC Motor B move clockwise\n digitalWrite(12,LOW);\n digitalWrite(11,LOW);//turn DC Motor A move anticlockwise\n digitalWrite(8,HIGH);\n}\n",b= 36 | "forward();\n"):"right"===a?(Blockly.Arduino.definitions_.define_right="void right()\n{\n analogWrite(9,127);//input a simulation value to set the speed\n analogWrite(10,127);\n digitalWrite(13,LOW);//turn DC Motor B move anticlockwise\n digitalWrite(12,HIGH);\n digitalWrite(11,LOW);//turn DC Motor A move anticlockwise\n digitalWrite(8,HIGH);\n}\n\n",b="right();\n"):"left"===a?(Blockly.Arduino.definitions_.define_left="void left()\n{\n analogWrite(9,127);//input a simulation value to set the speed\n analogWrite(10,127);\n digitalWrite(13,HIGH);//turn DC Motor B move clockwise\n digitalWrite(12,LOW);\n digitalWrite(11,HIGH);//turn DC Motor A move clockwise\n digitalWrite(8,LOW);\n}\n\n", 37 | b="left();\n"):"backward"===a?(Blockly.Arduino.definitions_.define_backward="void backward()\n{\n analogWrite(9,127);//input a simulation value to set the speed\n analogWrite(10,127);\n digitalWrite(13,LOW);//turn DC Motor B move anticlockwise\n digitalWrite(12,HIGH);\n digitalWrite(11,HIGH);//turn DC Motor A move clockwise\n digitalWrite(8,LOW);\n}\n\n",b="backward();\n"):"stop"===a&&(Blockly.Arduino.definitions_.define_stop="void stop()\n{\ndigitalWrite(9,LOW);// Unenble the pin, to stop the motor. this should be done to avid damaging the motor.\ndigitalWrite(10,LOW);\ndelay(1000);\n}\n\n", 38 | b="stop();\n");return b};Blockly.Arduino.grove_thumb_joystick=function(){var a=this.getFieldValue("PIN"),b="0",b="y"===this.getFieldValue("AXIS")?_get_next_pin(a):a;return["analogRead("+b+")",Blockly.Arduino.ORDER_ATOMIC]};function hexToR(a){return parseInt(cutHex(a).substring(0,2),16)}function hexToG(a){return parseInt(cutHex(a).substring(2,4),16)}function hexToB(a){return parseInt(cutHex(a).substring(4,6),16)}function cutHex(a){return"#"==a.charAt(0)?a.substring(1,7):a} 39 | Blockly.Arduino.grove_rgb_led=function(){var a=this.getFieldValue("PIN"),b=_get_next_pin(a);Blockly.Arduino.setups_["setup_input_"+a]="pinMode("+a+", OUTPUT);";Blockly.Arduino.setups_["setup_input_"+b]="pinMode("+b+", OUTPUT);";Blockly.Arduino.definitions_.define_uint8="#define uint8 unsigned char";Blockly.Arduino.definitions_.define_uint16="#define uint16 unsigned int";Blockly.Arduino.definitions_.define_uint32="#define uint32 unsigned long int";Blockly.Arduino.definitions_["define_clkproduce_"+ 40 | a]="void ClkProduce_"+a+"(void)\n{\n digitalWrite("+a+", LOW);\n delayMicroseconds(20);\n digitalWrite("+a+", HIGH);\n delayMicroseconds(20);\n}\n";Blockly.Arduino.definitions_["define_send32zero_"+a]="void Send32Zero_"+a+"(void)\n{\n uint8 i;\n for (i=0; i<32; i++)\n {\n digitalWrite("+b+", LOW);\n ClkProduce_"+a+"();\n }\n}\n";Blockly.Arduino.definitions_.define_taskanticode="uint8 TakeAntiCode(uint8 dat)\n{\n uint8 tmp = 0;\n if ((dat & 0x80) == 0)\n {\n tmp |= 0x02;\n }\n \n if ((dat & 0x40) == 0)\n {\n tmp |= 0x01;\n }\n return tmp;\n}\n"; 41 | Blockly.Arduino.definitions_["define_datasend_"+a]="// gray data\nvoid DatSend_"+a+"(uint32 dx)\n{\n uint8 i;\n for (i=0; i<32; i++)\n {\n if ((dx & 0x80000000) != 0)\n {\n digitalWrite("+b+", HIGH);\n }\n else\n {\n digitalWrite("+b+", LOW);\n }\n dx <<= 1;\n ClkProduce_"+a+"();\n }\n}\n";Blockly.Arduino.definitions_["define_datadealwithsend_"+a]="// data processing\nvoid DataDealWithAndSend_"+a+"(uint8 r, uint8 g, uint8 b)\n{\n uint32 dx = 0;\n dx |= (uint32)0x03 << 30; // highest two bits 1\uff0cflag bits\n dx |= (uint32)TakeAntiCode(b) << 28;\n dx |= (uint32)TakeAntiCode(g) << 26;\n dx |= (uint32)TakeAntiCode(r) << 24;\n\n dx |= (uint32)b << 16;\n dx |= (uint32)g << 8;\n dx |= r;\n\n DatSend_"+ 42 | a+"(dx);\n}\n";b="Send32Zero_"+a+"(); // begin\n";if(0==this.itemCount_)return"";for(var c=0;c\n";Blockly.Arduino.definitions_["var_bluetooth_"+a]="SoftwareSerial blueToothSerial_"+a+"("+a+","+b+");\n";Blockly.Arduino.setups_["setup_bluetooth_"+a]="Serial.begin(9600);\n"; 44 | Blockly.Arduino.setups_["setup_bluetooth_"+a]+=" pinMode("+a+", INPUT);\n";Blockly.Arduino.setups_["setup_bluetooth_"+a]+=" pinMode("+b+", OUTPUT);\n";Blockly.Arduino.setups_["setup_bluetooth_"+a]+=" setupBlueToothConnection_"+a+"();\n";Blockly.Arduino.definitions_["define_setupBlueToothConnection_"+a]="void setupBlueToothConnection_"+a+"()\n{\n blueToothSerial_"+a+".begin(38400); //Set BluetoothBee BaudRate to default baud rate 38400\n blueToothSerial_"+a+'.print("\\r\\n+STWMOD=0\\r\\n"); //set the bluetooth work in slave mode\n blueToothSerial_'+ 45 | a+'.print("\\r\\n+STNA='+c+'\\r\\n"); //set the bluetooth name as "'+c+'"\n blueToothSerial_'+a+'.print("\\r\\n+STPIN=0000\\r\\n");//Set SLAVE pincode"0000"\n blueToothSerial_'+a+'.print("\\r\\n+STOAUT=1\\r\\n"); // Permit Paired device to connect me\n blueToothSerial_'+a+'.print("\\r\\n+STAUTO=0\\r\\n"); // Auto-connection should be forbidden here\n delay(2000); // This delay is required.\n blueToothSerial_'+a+'.print("\\r\\n+INQ=1\\r\\n"); //make the slave bluetooth inquirable \n Serial.println("The slave bluetooth is inquirable!");\n delay(2000); // This delay is required.\n blueToothSerial_'+ 46 | a+".flush();\n}\n";return"char recvChar_"+a+";\nwhile(1) {\n if(blueToothSerial_"+a+".available()) {//check if there is any data sent from the remote bluetooth shield\n recvChar_"+a+" = blueToothSerial_"+a+".read();\n Serial.print(recvChar_"+a+");\n"+d+" }\n if(Serial.available()){//check if there is any data sent from the local serial terminal, you can add the other applications here\n recvChar_"+a+" = Serial.read();\n blueToothSerial_"+a+".print(recvChar_"+a+");\n"+e+" }\n}\n"};Blockly.Arduino.logic={}; 47 | Blockly.Arduino.controls_if=function(){for(var a=0,b=Blockly.Arduino.valueToCode(this,"IF"+a,Blockly.Arduino.ORDER_NONE)||"false",c=Blockly.Arduino.statementToCode(this,"DO"+a),d="if ("+b+") {\n"+c+"\n}",a=1;a<=this.elseifCount_;a++)b=Blockly.Arduino.valueToCode(this,"IF"+a,Blockly.Arduino.ORDER_NONE)||"false",c=Blockly.Arduino.statementToCode(this,"DO"+a),d+=" else if ("+b+") {\n"+c+"}";this.elseCount_&&(c=Blockly.Arduino.statementToCode(this,"ELSE"),d+=" else {\n"+c+"\n}");return d+"\n"}; 48 | Blockly.Arduino.logic_compare=function(){var a=this.getFieldValue("OP"),a=Blockly.Arduino.logic_compare.OPERATORS[a],b="=="==a||"!="==a?Blockly.Arduino.ORDER_EQUALITY:Blockly.Arduino.ORDER_RELATIONAL,c=Blockly.Arduino.valueToCode(this,"A",b)||"0",d=Blockly.Arduino.valueToCode(this,"B",b)||"0";return[c+" "+a+" "+d,b]};Blockly.Arduino.logic_compare.OPERATORS={EQ:"==",NEQ:"!=",LT:"<",LTE:"<=",GT:">",GTE:">="}; 49 | Blockly.Arduino.logic_operation=function(){var a="AND"==this.getFieldValue("OP")?"&&":"||",b="&&"==a?Blockly.Arduino.ORDER_LOGICAL_AND:Blockly.Arduino.ORDER_LOGICAL_OR,c=Blockly.Arduino.valueToCode(this,"A",b)||"false",d=Blockly.Arduino.valueToCode(this,"B",b)||"false";return[c+" "+a+" "+d,b]};Blockly.Arduino.logic_negate=function(){var a=Blockly.Arduino.ORDER_UNARY_PREFIX;return["!"+(Blockly.Arduino.valueToCode(this,"BOOL",a)||"false"),a]}; 50 | Blockly.Arduino.logic_boolean=function(){return["TRUE"==this.getFieldValue("BOOL")?"true":"false",Blockly.Arduino.ORDER_ATOMIC]};Blockly.Arduino.logic_null=function(){return["NULL",Blockly.Arduino.ORDER_ATOMIC]};Blockly.Arduino.math={};Blockly.Arduino.math_number=function(){var a=window.parseFloat(this.getFieldValue("NUM"));return[a,0>a?Blockly.Arduino.ORDER_UNARY_PREFIX:Blockly.Arduino.ORDER_ATOMIC]};Blockly.Arduino.math_arithmetic=function(){var a=this.getFieldValue("OP"),b=Blockly.Arduino.math_arithmetic.OPERATORS[a],a=b[0],b=b[1],c=Blockly.Arduino.valueToCode(this,"A",b)||"0",d=Blockly.Arduino.valueToCode(this,"B",b)||"0";return a?[c+a+d,b]:["Math.pow("+c+", "+d+")",Blockly.Arduino.ORDER_UNARY_POSTFIX]}; 51 | Blockly.Arduino.math_arithmetic.OPERATORS={ADD:[" + ",Blockly.Arduino.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Arduino.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Arduino.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Arduino.ORDER_MULTIPLICATIVE],POWER:[null,Blockly.Arduino.ORDER_NONE]};Blockly.Arduino.procedures={}; 52 | Blockly.Arduino.procedures_defreturn=function(){var a=Blockly.Arduino.variableDB_.getName(this.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),b=Blockly.Arduino.statementToCode(this,"STACK");Blockly.Arduino.INFINITE_LOOP_TRAP&&(b=Blockly.Arduino.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+this.id+"'")+b);var c=Blockly.Arduino.valueToCode(this,"RETURN",Blockly.Arduino.ORDER_NONE)||"";c&&(c=" return "+c+";\n");for(var d=c?"int":"void",e=[],f=0;f","LT"],["\u2265","LTE"],["<","GT"],["\u2264","GTE"]]:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]];this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);this.setColour(Blockly.Blocks.logic.HUE);this.setOutput(!0,"Boolean");this.appendValueInput("A");this.appendValueInput("B").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a= 134 | b.getFieldValue("OP");return{EQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,NEQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,LT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,LTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,GT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,GTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE}[a]});this.prevBlocks_=[null,null]},onchange:function(){var a=this.getInputTargetBlock("A"),b=this.getInputTargetBlock("B");if(a&&b&&!a.outputConnection.checkType_(b.outputConnection))for(var c=0;cd;d++){var e=1==d?a:b;e&&!e.outputConnection.checkType_(c)&&(c===this.prevParentConnection_?(this.setParent(null),c.sourceBlock_.bumpNeighbours_()):(e.setParent(null),e.bumpNeighbours_()))}this.prevParentConnection_=c}}; 142 | // Copyright 2012 Google Inc. Apache License 2.0 143 | Blockly.Blocks.loops={};Blockly.Blocks.loops.HUE=120;Blockly.Blocks.controls_repeat={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_REPEAT_TITLE,args0:[{type:"field_input",name:"TIMES",text:"10"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,tooltip:Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,helpUrl:Blockly.Msg.CONTROLS_REPEAT_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);this.getField("TIMES").setChangeHandler(Blockly.FieldTextInput.nonnegativeIntegerValidator)}}; 144 | Blockly.Blocks.controls_repeat_ext={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_REPEAT_TITLE,args0:[{type:"input_value",name:"TIMES",check:"Number"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,tooltip:Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,helpUrl:Blockly.Msg.CONTROLS_REPEAT_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)}}; 145 | Blockly.Blocks.controls_whileUntil={init:function(){var a=[[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE,"WHILE"],[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL,"UNTIL"]];this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);this.setColour(Blockly.Blocks.loops.HUE);this.appendValueInput("BOOL").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a),"MODE");this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);this.setPreviousStatement(!0);this.setNextStatement(!0); 146 | var b=this;this.setTooltip(function(){var a=b.getFieldValue("MODE");return{WHILE:Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,UNTIL:Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}[a]})}}; 147 | Blockly.Blocks.controls_for={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_FOR_TITLE,args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"FROM",check:"Number",align:"RIGHT"},{type:"input_value",name:"TO",check:"Number",align:"RIGHT"},{type:"input_value",name:"BY",check:"Number",align:"RIGHT"}],inputsInline:!0,previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,helpUrl:Blockly.Msg.CONTROLS_FOR_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO); 148 | var a=this;this.setTooltip(function(){return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace("%1",a.getFieldValue("VAR"))})},getVars:function(){return[this.getFieldValue("VAR")]},renameVar:function(a,b){Blockly.Names.equals(a,this.getFieldValue("VAR"))&&this.setFieldValue(b,"VAR")},customContextMenu:function(a){if(!this.isCollapsed()){var b={enabled:!0},c=this.getFieldValue("VAR");b.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",c);c=goog.dom.createDom("field",null,c);c.setAttribute("name","VAR"); 149 | c=goog.dom.createDom("block",null,c);c.setAttribute("type","variables_get");b.callback=Blockly.ContextMenu.callbackFactory(this,c);a.push(b)}}}; 150 | Blockly.Blocks.controls_forEach={init:function(){this.jsonInit({message0:Blockly.Msg.CONTROLS_FOREACH_TITLE,args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"LIST",check:"Array"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.loops.HUE,helpUrl:Blockly.Msg.CONTROLS_FOREACH_HELPURL});this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO);var a=this;this.setTooltip(function(){return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace("%1", 151 | a.getFieldValue("VAR"))})},getVars:function(){return[this.getFieldValue("VAR")]},renameVar:function(a,b){Blockly.Names.equals(a,this.getFieldValue("VAR"))&&this.setFieldValue(b,"VAR")},customContextMenu:Blockly.Blocks.controls_for.customContextMenu}; 152 | Blockly.Blocks.controls_flow_statements={init:function(){var a=[[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK,"BREAK"],[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE,"CONTINUE"]];this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);this.setColour(Blockly.Blocks.loops.HUE);this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"FLOW");this.setPreviousStatement(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("FLOW");return{BREAK:Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK, 153 | CONTINUE:Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}[a]})},onchange:function(){var a=!1,b=this;do{if("controls_repeat"==b.type||"controls_repeat_ext"==b.type||"controls_forEach"==b.type||"controls_for"==b.type||"controls_whileUntil"==b.type){a=!0;break}b=b.getSurroundParent()}while(b);a?this.setWarningText(null):this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING)}}; 154 | // Copyright 2012 Google Inc. Apache License 2.0 155 | Blockly.Blocks.math={};Blockly.Blocks.math.HUE=230;Blockly.Blocks.math_number={init:function(){this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.appendDummyInput().appendField(new Blockly.FieldTextInput("0",Blockly.FieldTextInput.numberValidator),"NUM");this.setOutput(!0,"Number");this.setTooltip(Blockly.Msg.MATH_NUMBER_TOOLTIP)}}; 156 | Blockly.Blocks.math_arithmetic={init:function(){var a=[[Blockly.Msg.MATH_ADDITION_SYMBOL,"ADD"],[Blockly.Msg.MATH_SUBTRACTION_SYMBOL,"MINUS"],[Blockly.Msg.MATH_MULTIPLICATION_SYMBOL,"MULTIPLY"],[Blockly.Msg.MATH_DIVISION_SYMBOL,"DIVIDE"],[Blockly.Msg.MATH_POWER_SYMBOL,"POWER"]];this.setHelpUrl(Blockly.Msg.MATH_ARITHMETIC_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.setOutput(!0,"Number");this.appendValueInput("A").setCheck("Number");this.appendValueInput("B").setCheck("Number").appendField(new Blockly.FieldDropdown(a), 157 | "OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{ADD:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,MINUS:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,MULTIPLY:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,DIVIDE:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,POWER:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER}[a]})}}; 158 | Blockly.Blocks.math_single={init:function(){var a=[[Blockly.Msg.MATH_SINGLE_OP_ROOT,"ROOT"],[Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE,"ABS"],["-","NEG"],["ln","LN"],["log10","LOG10"],["e^","EXP"],["10^","POW10"]];this.setHelpUrl(Blockly.Msg.MATH_SINGLE_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.setOutput(!0,"Number");this.appendValueInput("NUM").setCheck("Number").appendField(new Blockly.FieldDropdown(a),"OP");var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{ROOT:Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT, 159 | ABS:Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,NEG:Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,LN:Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,LOG10:Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,EXP:Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,POW10:Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10}[a]})}}; 160 | Blockly.Blocks.math_trig={init:function(){var a=[[Blockly.Msg.MATH_TRIG_SIN,"SIN"],[Blockly.Msg.MATH_TRIG_COS,"COS"],[Blockly.Msg.MATH_TRIG_TAN,"TAN"],[Blockly.Msg.MATH_TRIG_ASIN,"ASIN"],[Blockly.Msg.MATH_TRIG_ACOS,"ACOS"],[Blockly.Msg.MATH_TRIG_ATAN,"ATAN"]];this.setHelpUrl(Blockly.Msg.MATH_TRIG_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.setOutput(!0,"Number");this.appendValueInput("NUM").setCheck("Number").appendField(new Blockly.FieldDropdown(a),"OP");var b=this;this.setTooltip(function(){var a= 161 | b.getFieldValue("OP");return{SIN:Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,COS:Blockly.Msg.MATH_TRIG_TOOLTIP_COS,TAN:Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,ASIN:Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,ACOS:Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,ATAN:Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN}[a]})}}; 162 | Blockly.Blocks.math_constant={init:function(){this.setHelpUrl(Blockly.Msg.MATH_CONSTANT_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.setOutput(!0,"Number");this.appendDummyInput().appendField(new Blockly.FieldDropdown([["\u03c0","PI"],["e","E"],["\u03c6","GOLDEN_RATIO"],["sqrt(2)","SQRT2"],["sqrt(\u00bd)","SQRT1_2"],["\u221e","INFINITY"]]),"CONSTANT");this.setTooltip(Blockly.Msg.MATH_CONSTANT_TOOLTIP)}}; 163 | Blockly.Blocks.math_number_property={init:function(){var a=[[Blockly.Msg.MATH_IS_EVEN,"EVEN"],[Blockly.Msg.MATH_IS_ODD,"ODD"],[Blockly.Msg.MATH_IS_PRIME,"PRIME"],[Blockly.Msg.MATH_IS_WHOLE,"WHOLE"],[Blockly.Msg.MATH_IS_POSITIVE,"POSITIVE"],[Blockly.Msg.MATH_IS_NEGATIVE,"NEGATIVE"],[Blockly.Msg.MATH_IS_DIVISIBLE_BY,"DIVISIBLE_BY"]];this.setColour(Blockly.Blocks.math.HUE);this.appendValueInput("NUMBER_TO_CHECK").setCheck("Number");a=new Blockly.FieldDropdown(a,function(a){this.sourceBlock_.updateShape_("DIVISIBLE_BY"== 164 | a)});this.appendDummyInput().appendField(a,"PROPERTY");this.setInputsInline(!0);this.setOutput(!0,"Boolean");this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP)},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"): 165 | b&&this.removeInput("DIVISOR")}}; 166 | Blockly.Blocks.math_change={init:function(){this.jsonInit({message0:Blockly.Msg.MATH_CHANGE_TITLE,args0:[{type:"field_variable",name:"VAR",variable:Blockly.Msg.MATH_CHANGE_TITLE_ITEM},{type:"input_value",name:"DELTA",check:"Number"}],previousStatement:null,nextStatement:null,colour:Blockly.Blocks.math.HUE,helpUrl:Blockly.Msg.MATH_CHANGE_HELPURL});var a=this;this.setTooltip(function(){return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace("%1",a.getFieldValue("VAR"))})},getVars:function(){return[this.getFieldValue("VAR")]},renameVar:function(a, 167 | b){Blockly.Names.equals(a,this.getFieldValue("VAR"))&&this.setFieldValue(b,"VAR")}}; 168 | Blockly.Blocks.math_round={init:function(){var a=[[Blockly.Msg.MATH_ROUND_OPERATOR_ROUND,"ROUND"],[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP,"ROUNDUP"],[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN,"ROUNDDOWN"]];this.setHelpUrl(Blockly.Msg.MATH_ROUND_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.setOutput(!0,"Number");this.appendValueInput("NUM").setCheck("Number").appendField(new Blockly.FieldDropdown(a),"OP");this.setTooltip(Blockly.Msg.MATH_ROUND_TOOLTIP)}}; 169 | Blockly.Blocks.math_on_list={init:function(){var a=[[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM,"SUM"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MIN,"MIN"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MAX,"MAX"],[Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE,"AVERAGE"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN,"MEDIAN"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MODE,"MODE"],[Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV,"STD_DEV"],[Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM,"RANDOM"]],b=this;this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL);this.setColour(Blockly.Blocks.math.HUE); 170 | this.setOutput(!0,"Number");a=new Blockly.FieldDropdown(a,function(a){"MODE"==a?b.outputConnection.setCheck("Array"):b.outputConnection.setCheck("Number")});this.appendValueInput("LIST").setCheck("Array").appendField(a,"OP");this.setTooltip(function(){var a=b.getFieldValue("OP");return{SUM:Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,MIN:Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,MAX:Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,AVERAGE:Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,MEDIAN:Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN, 171 | MODE:Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,STD_DEV:Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,RANDOM:Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM}[a]})}};Blockly.Blocks.math_modulo={init:function(){this.jsonInit({message0:Blockly.Msg.MATH_MODULO_TITLE,args0:[{type:"input_value",name:"DIVIDEND",check:"Number"},{type:"input_value",name:"DIVISOR",check:"Number"}],inputsInline:!0,output:"Number",colour:Blockly.Blocks.math.HUE,tooltip:Blockly.Msg.MATH_MODULO_TOOLTIP,helpUrl:Blockly.Msg.MATH_MODULO_HELPURL})}}; 172 | Blockly.Blocks.math_constrain={init:function(){this.jsonInit({message0:Blockly.Msg.MATH_CONSTRAIN_TITLE,args0:[{type:"input_value",name:"VALUE",check:"Number"},{type:"input_value",name:"LOW",check:"Number"},{type:"input_value",name:"HIGH",check:"Number"}],inputsInline:!0,output:"Number",colour:Blockly.Blocks.math.HUE,tooltip:Blockly.Msg.MATH_CONSTRAIN_TOOLTIP,helpUrl:Blockly.Msg.MATH_CONSTRAIN_HELPURL})}}; 173 | Blockly.Blocks.math_random_int={init:function(){this.jsonInit({message0:Blockly.Msg.MATH_RANDOM_INT_TITLE,args0:[{type:"input_value",name:"FROM",check:"Number"},{type:"input_value",name:"TO",check:"Number"}],inputsInline:!0,output:"Number",colour:Blockly.Blocks.math.HUE,tooltip:Blockly.Msg.MATH_RANDOM_INT_TOOLTIP,helpUrl:Blockly.Msg.MATH_RANDOM_INT_HELPURL})}}; 174 | Blockly.Blocks.math_random_float={init:function(){this.setHelpUrl(Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL);this.setColour(Blockly.Blocks.math.HUE);this.setOutput(!0,"Number");this.appendDummyInput().appendField(Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM);this.setTooltip(Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP)}}; 175 | // Copyright 2012 Google Inc. Apache License 2.0 176 | Blockly.Blocks.procedures={};Blockly.Blocks.procedures.HUE=290; 177 | Blockly.Blocks.procedures_defnoreturn={init:function(){this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.setColour(Blockly.Blocks.procedures.HUE);var a=Blockly.Procedures.findLegalName(Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE,this),a=new Blockly.FieldTextInput(a,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"])); 178 | this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.arguments_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:function(a){this.hasStatements_!==a&&(a?(this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO),this.getInput("RETURN")&&this.moveInputBefore("STACK","RETURN")):this.removeInput("STACK",!0),this.hasStatements_=a)},updateParams_:function(){for(var a=!1,b={},c=0;c 2 | 3 | 23 | 24 | 25 | 26 | 27 | 28 | ? 29 | 30 | 31 | 32 | 39 | 40 | 41 | 42 | ! 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /blockly/media/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlocklyDuino/BlocklyDuinoFactory/62943a0007cd435126d099f37acae09340ab50fb/blockly/media/sprites.png -------------------------------------------------------------------------------- /blockly/media/sprites.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /blocklyduinofactory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * BlocklyDuinoFactory Application 3 | * 4 | * Copyright 2015 BlocklyDuino https://github.com/BlocklyDuino 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | /** 20 | * @fileoverview JavaScript for BlocklyDuinoFactory application. 21 | */ 22 | 'use strict'; 23 | 24 | /** 25 | * Create a namespace for the BlocklyDuinoFactory application. 26 | */ 27 | var Bdf = Bdf || {}; 28 | 29 | /** 30 | * Name of block if not named. 31 | */ 32 | Bdf.UNNAMED = 'unnamed'; 33 | 34 | /** 35 | * Change the block definition code language format. 36 | */ 37 | Bdf.definitionFormatChange = function() { 38 | var maskFactory = document.getElementById('blocklyFactoryMask'); 39 | var maskGenerator = document.getElementById('blocklyGeneratorMask'); 40 | var languagePre = document.getElementById('languagePre'); 41 | var languageTA = document.getElementById('languageTA'); 42 | if (document.getElementById('format').value == 'Manual') { 43 | Blockly.hideChaff(); 44 | maskFactory.style.display = 'block'; 45 | maskGenerator.style.display = 'block'; 46 | languagePre.style.display = 'none'; 47 | languageTA.style.display = 'block'; 48 | var code = languagePre.textContent.trim(); 49 | languageTA.value = code; 50 | languageTA.focus(); 51 | Bdf.updatePreview(); 52 | } else { 53 | maskFactory.style.display = 'none'; 54 | maskGenerator.style.display = 'none'; 55 | languageTA.style.display = 'none'; 56 | languagePre.style.display = 'block'; 57 | Bdf.updateDefinitionCode(); 58 | } 59 | }; 60 | 61 | /** 62 | * Update the block definition code based on constructs made in the block 63 | * definition workspace. 64 | */ 65 | Bdf.updateDefinitionCode = function() { 66 | switch (document.getElementById('format').value) { 67 | case 'JSON': 68 | var code = Bdf.Factory.formatJson(); 69 | break; 70 | case 'JavaScript': 71 | var code = Bdf.Factory.formatJavaScript(); 72 | break; 73 | } 74 | Bdf.injectCode(code, 'languagePre'); 75 | Bdf.updatePreview(); 76 | }; 77 | 78 | /** 79 | * Update the preview workspace with the new block, which code has been 80 | * generated and injected the HTLM DOM. 81 | * @return {Blocly.Block} Block generated in the Preview workspace. 82 | */ 83 | Bdf.updatePreview = function() { 84 | // Fetch the direction 85 | var newDir = document.getElementById('direction').value; 86 | // Fetch the code and determine its format (JSON or JavaScript). 87 | var format = document.getElementById('format').value; 88 | if (format == 'Manual') { 89 | var code = document.getElementById('languageTA').value; 90 | // If the code is JSON, it will parse, otherwise treat as JS. 91 | try { 92 | JSON.parse(code); 93 | format = 'JSON'; 94 | } catch (e) { 95 | format = 'JavaScript'; 96 | } 97 | } else { 98 | var code = document.getElementById('languagePre').textContent; 99 | } 100 | if (!code.trim()) { 101 | // Nothing to render. Happens while cloud storage is loading. 102 | return; 103 | } 104 | var previewBlock = Bdf.Preview.update(newDir, format, code); 105 | return previewBlock; 106 | }; 107 | 108 | /** 109 | * Update the all block related activities: Generates the block definition code 110 | * from the definition workspace, updates the preview workspace with the code, 111 | * and generates the JavaScript code for the Blockly Arduino Generator. 112 | */ 113 | Bdf.updateBlock = function() { 114 | Bdf.updateDefinitionCode(); 115 | var previewBlock = Bdf.updatePreview(); 116 | if (previewBlock) { 117 | var generatorCode = Bdf.Generator.updateGenerator(previewBlock); 118 | Bdf.injectCode(generatorCode, 'generatorPre'); 119 | } 120 | }; 121 | 122 | /** 123 | * Creates an XML file with the blocks from the Factory workspace for the user 124 | * to download. 125 | */ 126 | Bdf.saveXmlFactory = function() { 127 | var xmlData = Bdf.Factory.getXmlString(); 128 | var blob = new Blob([xmlData], {type: 'text/xml'}); 129 | saveAs(blob, 'blockduinofactory_factory.xml'); 130 | }; 131 | 132 | /** 133 | * Loads an XML file from the user filesystem and injects the blocks into the 134 | * Factory workspace. 135 | */ 136 | Bdf.openXmlFactory = function() { 137 | function openXmlFactoryFile(xmlString) { 138 | try { 139 | var xml = Blockly.Xml.textToDom(xmlString); 140 | } catch (e) { 141 | alert('Error parsing XML:\n' + e); 142 | return; 143 | } 144 | Bdf.Factory.loadXml(xml); 145 | } 146 | // Edit the hiddent file open button listener to the XML read function 147 | Bdf.openUserFile(openXmlFactoryFile); 148 | }; 149 | 150 | /** 151 | * This function is used as a placeholder for the event listener associated to 152 | * the hidden open button, this function reference is changed based on required 153 | * functionality. 154 | */ 155 | Bdf.loadFileEventHolder = function(e) {}; 156 | 157 | /** 158 | * Triggers the open file dialog to the user and reads the selected file. It 159 | * returns the data to a callback as a string. 160 | * @param {!function} callback Callback function that takes an argument with the 161 | * text file contents in a string format. 162 | */ 163 | Bdf.openUserFile = function(callback) { 164 | var fileOpenerWithCallback = function(e) { 165 | var files = event.target.files; 166 | // Only allow uploading one file. 167 | if (files.length != 1) { 168 | alert('Can only read one file at a time.'); 169 | return; 170 | } 171 | var reader = new FileReader(); 172 | reader.onloadend = function(event) { 173 | var target = event.target; 174 | // 2 == FileReader.DONE 175 | if (target.readyState == 2) { 176 | callback(target.result); 177 | } 178 | // Reset value of input after loading because Chrome will not fire 179 | // a 'change' event if the same file is loaded again. 180 | document.getElementById('loadFileButton').value = ''; 181 | }; 182 | reader.readAsText(files[0]); 183 | }; 184 | Bdf.loadFileEventHolder = fileOpenerWithCallback; 185 | document.getElementById('loadFileButton').click(); 186 | }; 187 | 188 | /** 189 | * Inject code into a pre tag, with syntax highlighting. 190 | * Safe from HTML/script injection. 191 | * @param {string} code Lines of code. 192 | * @param {string} id ID of
 element to inject into.
193 |  */
194 | Bdf.injectCode = function(code, id) {
195 |   Blockly.removeAllRanges();
196 |   var pre = document.getElementById(id);
197 |   pre.textContent = code;
198 |   code = pre.innerHTML;
199 |   code = prettyPrintOne(code, 'js');
200 |   pre.innerHTML = code;
201 | };
202 | 
203 | /**
204 |  * Initialise Blockly and layout. Called on page load.
205 |  */
206 | Bdf.init = function() {
207 |   document.getElementById('helpButton').addEventListener('click',
208 |     function() {
209 |       open('https://developers.google.com/blockly/custom-blocks/block-factory',
210 |            'BlockFactoryHelp');
211 |     });
212 |   document.getElementById('loadFileButton').addEventListener(
213 |       'change', function(e) { Bdf.loadFileEventHolder(e); }, false);
214 |   document.getElementById('loadXmlFactoryButton').addEventListener(
215 |       'click', Bdf.openXmlFactory);
216 |   document.getElementById('saveXmlFactoryButton').addEventListener(
217 |       'click', Bdf.saveXmlFactory);
218 |   
219 |   var expandList = [
220 |     document.getElementById('blocklyFactory'),
221 |     document.getElementById('blocklyFactoryMask'),
222 |     document.getElementById('blocklyGenerator'),
223 |     document.getElementById('blocklyGeneratorMask'),
224 |     document.getElementById('preview'),
225 |     document.getElementById('languagePre'),
226 |     document.getElementById('languageTA'),
227 |     document.getElementById('generatorPre')
228 |   ];
229 |   var onresize = function(e) {
230 |     for (var i = 0, expand; expand = expandList[i]; i++) {
231 |       expand.style.width = (expand.parentNode.offsetWidth - 2) + 'px';
232 |       expand.style.height = (expand.parentNode.offsetHeight - 2) + 'px';
233 |     }
234 |   };
235 |   onresize();
236 |   window.addEventListener('resize', onresize);
237 | 
238 |   Bdf.Factory.injectBlockly('blocklyFactory',
239 |                             document.getElementById('toolboxFactory'));
240 |   Bdf.Generator.injectBlockly('blocklyGenerator',
241 |                             document.getElementById('toolboxGenerator'));
242 | 
243 |   Bdf.Factory.workspace.addChangeListener(Bdf.updateBlock);
244 |   document.getElementById('direction')
245 |       .addEventListener('change', Bdf.updatePreview);
246 |   document.getElementById('languageTA')
247 |       .addEventListener('change', Bdf.updatePreview);
248 |   document.getElementById('languageTA')
249 |       .addEventListener('keyup', Bdf.updatePreview);
250 |   document.getElementById('format')
251 |       .addEventListener('change', Bdf.definitionFormatChange);
252 | };
253 | 
254 | /**
255 |  * Bind the initialisation function to the page load event.
256 |  */
257 | window.addEventListener('load', function load(event) {
258 |   window.removeEventListener('load', load, false);
259 |   Bdf.init();
260 | });
261 | 


--------------------------------------------------------------------------------
/factory.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * BlocklyDuinoFactory Factory module
  3 |  *
  4 |  * Copyright 2015 BlocklyDuino https://github.com/BlocklyDuino
  5 |  *
  6 |  * Based on the Block Factory Blockly demo Copyright 2012 Google Inc.
  7 |  * https://developers.google.com/blockly/
  8 |  *
  9 |  * Licensed under the Apache License, Version 2.0 (the "License");
 10 |  * you may not use this file except in compliance with the License.
 11 |  * You may obtain a copy of the License at
 12 |  *
 13 |  *   http://www.apache.org/licenses/LICENSE-2.0
 14 |  *
 15 |  * Unless required by applicable law or agreed to in writing, software
 16 |  * distributed under the License is distributed on an "AS IS" BASIS,
 17 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 18 |  * See the License for the specific language governing permissions and
 19 |  * limitations under the License.
 20 |  */
 21 | 
 22 | /**
 23 |  * @fileoverview JavaScript for BlocklyDuinoFactory block factory module.
 24 |  */
 25 | 'use strict';
 26 | 
 27 | /**
 28 |  * Create a namespace nested in the BlocklyDuinoFactory application.
 29 |  */
 30 | var Bdf = Bdf || {};
 31 | Bdf.Factory = Bdf.Factory || {};
 32 | 
 33 | /**
 34 |  * Workspace for user to build block.
 35 |  * @type {Blockly.Workspace}
 36 |  */
 37 | Bdf.Factory.workspace = null;
 38 | 
 39 | /**
 40 |  * Inject Blockly into the given element and creates the Root block.
 41 |  * @param {!string|!Element} element HTML element name or Element to inject the
 42 |  *     factory Blockly workspace.
 43 |  * @param {!Element} toolbox XML element with the Blockly toolbox.
 44 |  */
 45 | Bdf.Factory.injectBlockly = function(element, toolbox) {
 46 |   Bdf.Factory.workspace = Blockly.inject(element,
 47 |       {toolbox: toolbox,
 48 |        media: 'blockly/media/' });
 49 |   Bdf.Factory.createRootBlock_();
 50 | };
 51 | 
 52 | /**
 53 |  * Update the language code as JSON.
 54 |  * @return {string} Generated language code.
 55 |  */
 56 | Bdf.Factory.formatJson = function() {
 57 |   var rootBlock = Bdf.Factory.getRootBlock_();
 58 |   var JS = {};
 59 |   // ID is not used by Blockly, but may be used by a loader.
 60 |   JS.id = Bdf.Factory.getBlockName_();
 61 |   // Generate inputs.
 62 |   var message = [];
 63 |   var args = [];
 64 |   var contentsBlock = rootBlock.getInputTargetBlock('INPUTS');
 65 |   var lastInput = null;
 66 |   while (contentsBlock) {
 67 |     if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) {
 68 |       var fields = Bdf.Factory.getFieldsJson_(
 69 |           contentsBlock.getInputTargetBlock('FIELDS'));
 70 |       for (var i = 0; i < fields.length; i++) {
 71 |         if (typeof fields[i] == 'string') {
 72 |           message.push(fields[i].replace(/%/g, '%%'));
 73 |         } else {
 74 |           args.push(fields[i]);
 75 |           message.push('%' + args.length);
 76 |         }
 77 |       }
 78 | 
 79 |       var input = {type: contentsBlock.type};
 80 |       // Dummy inputs don't have names.  Other inputs do.
 81 |       if (contentsBlock.type != 'input_dummy') {
 82 |         input.name = contentsBlock.getFieldValue('INPUTNAME');
 83 |       }
 84 |       var check = JSON.parse(Bdf.Factory.getOptTypesFrom_(
 85 |           contentsBlock, 'TYPE') || 'null');
 86 |       if (check) {
 87 |         input.check = check;
 88 |       }
 89 |       var align = contentsBlock.getFieldValue('ALIGN');
 90 |       if (align != 'LEFT') {
 91 |         input.align = align;
 92 |       }
 93 |       args.push(input);
 94 |       message.push('%' + args.length);
 95 |       lastInput = contentsBlock;
 96 |     }
 97 |     contentsBlock = contentsBlock.nextConnection &&
 98 |         contentsBlock.nextConnection.targetBlock();
 99 |   }
100 |   // Remove last input if dummy and not empty.
101 |   if (lastInput && lastInput.type == 'input_dummy') {
102 |     var fields = lastInput.getInputTargetBlock('FIELDS');
103 |     if (fields && Bdf.Factory.getFieldsJson_(fields).join('').trim() != '') {
104 |       var align = lastInput.getFieldValue('ALIGN');
105 |       if (align != 'LEFT') {
106 |         JS.lastDummyAlign0 = align;
107 |       }
108 |       args.pop();
109 |       message.pop();
110 |     }
111 |   }
112 |   JS.message0 = message.join(' ');
113 |   JS.args0 = args;
114 |   // Generate inline/external switch.
115 |   if (rootBlock.getFieldValue('INLINE') == 'EXT') {
116 |     JS.inputsInline = false;
117 |   } else if (rootBlock.getFieldValue('INLINE') == 'INT') {
118 |     JS.inputsInline = true;
119 |   }
120 |   // Generate output, or next/previous connections.
121 |   switch (rootBlock.getFieldValue('CONNECTIONS')) {
122 |     case 'LEFT':
123 |       JS.output = JSON.parse(
124 |           Bdf.Factory.getOptTypesFrom_(rootBlock, 'OUTPUTTYPE') || 'null');
125 |       break;
126 |     case 'BOTH':
127 |       JS.previousStatement =
128 |           JSON.parse(
129 |               Bdf.Factory.getOptTypesFrom_(rootBlock, 'TOPTYPE') || 'null');
130 |       JS.nextStatement =
131 |           JSON.parse(
132 |               Bdf.Factory.getOptTypesFrom_(rootBlock, 'BOTTOMTYPE') || 'null');
133 |       break;
134 |     case 'TOP':
135 |       JS.previousStatement =
136 |           JSON.parse(
137 |               Bdf.Factory.getOptTypesFrom_(rootBlock, 'TOPTYPE') || 'null');
138 |       break;
139 |     case 'BOTTOM':
140 |       JS.nextStatement =
141 |           JSON.parse(
142 |               Bdf.Factory.getOptTypesFrom_(rootBlock, 'BOTTOMTYPE') || 'null');
143 |       break;
144 |   }
145 |   // Generate colour.
146 |   var colourBlock = rootBlock.getInputTargetBlock('COLOUR');
147 |   if (colourBlock && !colourBlock.disabled) {
148 |     var hue = parseInt(colourBlock.getFieldValue('HUE'), 10);
149 |     JS.colour = hue;
150 |   }
151 |   JS.tooltip = '';
152 |   JS.helpUrl = 'http://www.example.com/';
153 |   return JSON.stringify(JS, null, '  ');
154 | };
155 | 
156 | /**
157 |  * Update the language code as JavaScript.
158 |  * @return {string} Generated language code.
159 |  */
160 | Bdf.Factory.formatJavaScript = function() {
161 |   var rootBlock = Bdf.Factory.getRootBlock_();
162 |   var code = [];
163 |   code.push("Blockly.Blocks['" + Bdf.Factory.getBlockName_() + "'] = {");
164 |   code.push('  init: function() {');
165 |   // Generate inputs.
166 |   var TYPES = {'input_value': 'appendValueInput',
167 |                'input_statement': 'appendStatementInput',
168 |                'input_dummy': 'appendDummyInput'};
169 |   var contentsBlock = rootBlock.getInputTargetBlock('INPUTS');
170 |   while (contentsBlock) {
171 |     if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) {
172 |       var name = '';
173 |       // Dummy inputs don't have names.  Other inputs do.
174 |       if (contentsBlock.type != 'input_dummy') {
175 |         name = Bdf.Factory.escapeString_(
176 |             contentsBlock.getFieldValue('INPUTNAME'));
177 |       }
178 |       code.push('    this.' + TYPES[contentsBlock.type] + '(' + name + ')');
179 |       var check = Bdf.Factory.getOptTypesFrom_(contentsBlock, 'TYPE');
180 |       if (check) {
181 |         code.push('        .setCheck(' + check + ')');
182 |       }
183 |       var align = contentsBlock.getFieldValue('ALIGN');
184 |       if (align != 'LEFT') {
185 |         code.push('        .setAlign(Blockly.ALIGN_' + align + ')');
186 |       }
187 |       var fields = Bdf.Factory.getFieldsJs_(
188 |           contentsBlock.getInputTargetBlock('FIELDS'));
189 |       for (var i = 0; i < fields.length; i++) {
190 |         code.push('        .appendField(' + fields[i] + ')');
191 |       }
192 |       // Add semicolon to last line to finish the statement.
193 |       code[code.length - 1] += ';';
194 |     }
195 |     contentsBlock = contentsBlock.nextConnection &&
196 |         contentsBlock.nextConnection.targetBlock();
197 |   }
198 |   // Generate inline/external switch.
199 |   if (rootBlock.getFieldValue('INLINE') == 'EXT') {
200 |     code.push('    this.setInputsInline(false);');
201 |   } else if (rootBlock.getFieldValue('INLINE') == 'INT') {
202 |     code.push('    this.setInputsInline(true);');
203 |   }
204 |   // Generate output, or next/previous connections.
205 |   switch (rootBlock.getFieldValue('CONNECTIONS')) {
206 |     case 'LEFT':
207 |       code.push(Bdf.Factory.connectionLineJs_('setOutput', 'OUTPUTTYPE'));
208 |       break;
209 |     case 'BOTH':
210 |       code.push(Bdf.Factory.connectionLineJs_(
211 |           'setPreviousStatement', 'TOPTYPE'));
212 |       code.push(Bdf.Factory.connectionLineJs_(
213 |           'setNextStatement', 'BOTTOMTYPE'));
214 |       break;
215 |     case 'TOP':
216 |       code.push(Bdf.Factory.connectionLineJs_(
217 |           'setPreviousStatement', 'TOPTYPE'));
218 |       break;
219 |     case 'BOTTOM':
220 |       code.push(Bdf.Factory.connectionLineJs_(
221 |           'setNextStatement', 'BOTTOMTYPE'));
222 |       break;
223 |   }
224 |   // Generate colour.
225 |   var colourBlock = rootBlock.getInputTargetBlock('COLOUR');
226 |   if (colourBlock && !colourBlock.disabled) {
227 |     var hue = parseInt(colourBlock.getFieldValue('HUE'), 10);
228 |     code.push('    this.setColour(' + hue + ');');
229 |   }
230 |   code.push("    this.setTooltip('');");
231 |   code.push("    this.setHelpUrl('http://www.example.com/');");
232 |   code.push('  }');
233 |   code.push('};');
234 |   return code.join('\n');
235 | };
236 | 
237 | /**
238 |  * Clears the workspace and loads the input XML into the Factory workspace.
239 |  * @param {Element} XML DOM to load into the workspace
240 |  */
241 | Bdf.Factory.loadXml = function(xmlDom) { 
242 |   Bdf.Factory.workspace.clear();
243 |   Blockly.Xml.domToWorkspace(Bdf.Factory.workspace, xmlDom);
244 | };
245 | 
246 | /**
247 |  * Returns the XML for the Factory workspace blocks.
248 |  * @return {Element} XML DOM from the workspace blocks.
249 |  */
250 | Bdf.Factory.getXml = function(xmlDom) {
251 |   return Blockly.Xml.workspaceToDom(Bdf.Factory.workspace);
252 | };
253 | 
254 | /**
255 |  * Returns the XML for the Factory workspace blocks.
256 |  * @return {string} XML of the workspace blocks in string format.
257 |  */
258 | Bdf.Factory.getXmlString = function() {
259 |   return Blockly.Xml.domToText(
260 |       Blockly.Xml.workspaceToDom(Bdf.Factory.workspace));
261 | };
262 | 
263 | /**
264 |  * Create JS code required to create a top, bottom, or value connection.
265 |  * @param {string} functionName JavaScript function name.
266 |  * @param {string} typeName Name of type input.
267 |  * @return {string} Line of JavaScript code to create connection.
268 |  * @private
269 |  */
270 | Bdf.Factory.connectionLineJs_ = function(functionName, typeName) {
271 |   var type = Bdf.Factory.getOptTypesFrom_(
272 |       Bdf.Factory.getRootBlock_(), typeName);
273 |   if (type) {
274 |     type = ', ' + type;
275 |   } else {
276 |     type = '';
277 |   }
278 |   return '    this.' + functionName + '(true' + type + ');';
279 | };
280 | 
281 | /**
282 |  * Returns field strings and any config.
283 |  * @param {!Blockly.Block} block Input block.
284 |  * @return {!Array.} Field strings.
285 |  * @private
286 |  */
287 | Bdf.Factory.getFieldsJs_ = function(block) {
288 |   var fields = [];
289 |   while (block) {
290 |     if (!block.disabled && !block.getInheritedDisabled()) {
291 |       switch (block.type) {
292 |         case 'field_static':
293 |           // Result: 'hello'
294 |           fields.push(Bdf.Factory.escapeString_(block.getFieldValue('TEXT')));
295 |           break;
296 |         case 'field_input':
297 |           // Result: new Blockly.FieldTextInput('Hello'), 'GREET'
298 |           fields.push('new Blockly.FieldTextInput(' +
299 |               Bdf.Factory.escapeString_(block.getFieldValue('TEXT')) + '), ' +
300 |               Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
301 |           break;
302 |         case 'field_angle':
303 |           // Result: new Blockly.FieldAngle(90), 'ANGLE'
304 |           fields.push('new Blockly.FieldAngle(' +
305 |               Bdf.Factory.escapeString_(block.getFieldValue('ANGLE')) + '), ' +
306 |               Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
307 |           break;
308 |         case 'field_checkbox':
309 |           // Result: new Blockly.FieldCheckbox('TRUE'), 'CHECK'
310 |           fields.push('new Blockly.FieldCheckbox(' +
311 |               Bdf.Factory.escapeString_(block.getFieldValue('CHECKED')) +
312 |               '), ' +
313 |               Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
314 |           break;
315 |         case 'field_colour':
316 |           // Result: new Blockly.FieldColour('#ff0000'), 'COLOUR'
317 |           fields.push('new Blockly.FieldColour(' +
318 |               Bdf.Factory.escapeString_(block.getFieldValue('COLOUR')) + '), ' +
319 |               Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
320 |           break;
321 |         case 'field_date':
322 |           // Result: new Blockly.FieldDate('2015-02-04'), 'DATE'
323 |           fields.push('new Blockly.FieldDate(' +
324 |               Bdf.Factory.escapeString_(block.getFieldValue('DATE')) + '), ' +
325 |               Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
326 |           break;
327 |         case 'field_variable':
328 |           // Result: new Blockly.FieldVariable('item'), 'VAR'
329 |           var varname = Bdf.Factory.escapeString_(
330 |               block.getFieldValue('TEXT') || null);
331 |           fields.push('new Blockly.FieldVariable(' + varname + '), ' +
332 |               Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
333 |           break;
334 |         case 'field_dropdown':
335 |           // Result:
336 |           // new Blockly.FieldDropdown([['yes', '1'], ['no', '0']]), 'TOGGLE'
337 |           var options = [];
338 |           for (var i = 0; i < block.optionCount_; i++) {
339 |             options[i] = '[' + Bdf.Factory.escapeString_(
340 |                 block.getFieldValue('USER' + i)) + ', ' +
341 |                 Bdf.Factory.escapeString_(block.getFieldValue('CPU' + i)) + ']';
342 |           }
343 |           if (options.length) {
344 |             fields.push('new Blockly.FieldDropdown([' +
345 |                 options.join(', ') + ']), ' +
346 |                 Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
347 |           }
348 |           break;
349 |         case 'field_image':
350 |           // Result: new Blockly.FieldImage('http://...', 80, 60)
351 |           var src = Bdf.Factory.escapeString_(block.getFieldValue('SRC'));
352 |           var width = Number(block.getFieldValue('WIDTH'));
353 |           var height = Number(block.getFieldValue('HEIGHT'));
354 |           var alt = Bdf.Factory.escapeString_(block.getFieldValue('ALT'));
355 |           fields.push('new Blockly.FieldImage(' +
356 |               src + ', ' + width + ', ' + height + ', ' + alt + ')');
357 |           break;
358 |         case 'field_arduino_pin':
359 |           // Result:
360 |           // new Blockly.FieldDropdown(profile.default.PIN_TYPE), 'PIN_NAME'
361 |           var pinType = block.getFieldValue('PIN_TYPE');
362 |           if (pinType === 'DIGITAL') {
363 |             fields.push('new Blockly.FieldDropdown(profile.default.digital), ' +
364 |                 Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
365 |           } else if (pinType === 'ANALOG') {
366 |             fields.push('new Blockly.FieldDropdown(profile.default.analog), ' +
367 |                 Bdf.Factory.escapeString_(block.getFieldValue('FIELDNAME')));
368 |           }
369 |           break;
370 |       }
371 |     }
372 |     block = block.nextConnection && block.nextConnection.targetBlock();
373 |   }
374 |   return fields;
375 | };
376 | 
377 | /**
378 |  * Returns field strings and any config.
379 |  * @param {!Blockly.Block} block Input block.
380 |  * @return {!Array.} Array of static text and field configs.
381 |  * @private
382 |  */
383 | Bdf.Factory.getFieldsJson_ = function(block) {
384 |   var fields = [];
385 |   while (block) {
386 |     if (!block.disabled && !block.getInheritedDisabled()) {
387 |       switch (block.type) {
388 |         case 'field_static':
389 |           // Result: 'hello'
390 |           fields.push(block.getFieldValue('TEXT'));
391 |           break;
392 |         case 'field_input':
393 |           fields.push({
394 |             type: block.type,
395 |             name: block.getFieldValue('FIELDNAME'),
396 |             text: block.getFieldValue('TEXT')
397 |           });
398 |           break;
399 |         case 'field_angle':
400 |           fields.push({
401 |             type: block.type,
402 |             name: block.getFieldValue('FIELDNAME'),
403 |             angle: Number(block.getFieldValue('ANGLE'))
404 |           });
405 |           break;
406 |         case 'field_checkbox':
407 |           fields.push({
408 |             type: block.type,
409 |             name: block.getFieldValue('FIELDNAME'),
410 |             checked: block.getFieldValue('CHECKED') == 'TRUE'
411 |           });
412 |           break;
413 |         case 'field_colour':
414 |           fields.push({
415 |             type: block.type,
416 |             name: block.getFieldValue('FIELDNAME'),
417 |             colour: block.getFieldValue('COLOUR')
418 |           });
419 |           break;
420 |         case 'field_date':
421 |           fields.push({
422 |             type: block.type,
423 |             name: block.getFieldValue('FIELDNAME'),
424 |             date: block.getFieldValue('DATE')
425 |           });
426 |           break;
427 |         case 'field_variable':
428 |           fields.push({
429 |             type: block.type,
430 |             name: block.getFieldValue('FIELDNAME'),
431 |             variable: block.getFieldValue('TEXT') || null
432 |           });
433 |           break;
434 |         case 'field_dropdown':
435 |           var options = [];
436 |           for (var i = 0; i < block.optionCount_; i++) {
437 |             options[i] = [block.getFieldValue('USER' + i),
438 |                 block.getFieldValue('CPU' + i)];
439 |           }
440 |           if (options.length) {
441 |             fields.push({
442 |               type: block.type,
443 |               name: block.getFieldValue('FIELDNAME'),
444 |               options: options
445 |             });
446 |           }
447 |           break;
448 |         case 'field_image':
449 |           fields.push({
450 |             type: block.type,
451 |             src: block.getFieldValue('SRC'),
452 |             width: Number(block.getFieldValue('WIDTH')),
453 |             height: Number(block.getFieldValue('HEIGHT')),
454 |             alt: block.getFieldValue('ALT')
455 |           });
456 |           break;
457 |         case 'field_arduino_pin':
458 |           var pinType = block.getFieldValue('PIN_TYPE');
459 |           if (pinType === 'DIGITAL') {
460 |             fields.push({
461 |               type: block.type,
462 |               name: block.getFieldValue('FIELDNAME'),
463 |               options: profile.default.digital
464 |             });
465 |           } else if (pinType === 'ANALOG') {
466 |             fields.push({
467 |               type: block.type,
468 |               name: block.getFieldValue('FIELDNAME'),
469 |               options: profile.default.analog
470 |             });
471 |           }
472 |           break;
473 |       }
474 |     }
475 |     block = block.nextConnection && block.nextConnection.targetBlock();
476 |   }
477 |   return fields;
478 | };
479 | 
480 | /**
481 |  * Fetch the type(s) defined in the given input.
482 |  * Format as a string for appending to the generated code.
483 |  * @param {!Blockly.Block} block Block with input.
484 |  * @param {string} name Name of the input.
485 |  * @return {?string} String defining the types.
486 |  * @private
487 |  */
488 | Bdf.Factory.getOptTypesFrom_ = function(block, name) {
489 |   var types = Bdf.Factory.getTypesFrom_(block, name);
490 |   if (types.length == 0) {
491 |     return undefined;
492 |   } else if (types.indexOf('null') != -1) {
493 |     return 'null';
494 |   } else if (types.length == 1) {
495 |     return types[0];
496 |   } else {
497 |     return '[' + types.join(', ') + ']';
498 |   }
499 | };
500 | 
501 | /**
502 |  * Fetch the type(s) defined in the given input.
503 |  * @param {!Blockly.Block} block Block with input.
504 |  * @param {string} name Name of the input.
505 |  * @return {!Array.} List of types.
506 |  * @private
507 |  */
508 | Bdf.Factory.getTypesFrom_ = function(block, name) {
509 |   var typeBlock = block.getInputTargetBlock(name);
510 |   var types;
511 |   if (!typeBlock || typeBlock.disabled) {
512 |     types = [];
513 |   } else if (typeBlock.type == 'type_other') {
514 |     types = [Bdf.Factory.escapeString_(typeBlock.getFieldValue('TYPE'))];
515 |   } else if (typeBlock.type == 'type_group') {
516 |     types = [];
517 |     for (var n = 0; n < typeBlock.typeCount_; n++) {
518 |       types = types.concat(Bdf.Factory.getTypesFrom_(typeBlock, 'TYPE' + n));
519 |     }
520 |     // Remove duplicates.
521 |     var hash = Object.create(null);
522 |     for (var n = types.length - 1; n >= 0; n--) {
523 |       if (hash[types[n]]) {
524 |         types.splice(n, 1);
525 |       }
526 |       hash[types[n]] = true;
527 |     }
528 |   } else {
529 |     types = [Bdf.Factory.escapeString_(typeBlock.valueType)];
530 |   }
531 |   return types;
532 | };
533 | 
534 | /**
535 |  * Create the uneditable container block that everything else attaches to.
536 |  * @private
537 |  */
538 | Bdf.Factory.createRootBlock_ = function() {
539 |   var rootBlock = Blockly.Block.obtain(Bdf.Factory.workspace, 'factory_base');
540 |   rootBlock.initSvg();
541 |   rootBlock.render();
542 |   rootBlock.setMovable(false);
543 |   rootBlock.setDeletable(false);
544 | };
545 | 
546 | /**
547 |  * Return the uneditable container block that everything else attaches to.
548 |  * @return {Blockly.Block}
549 |  * @private
550 |  */
551 | Bdf.Factory.getRootBlock_ = function() {
552 |   var blocks = Bdf.Factory.workspace.getTopBlocks(false);
553 |   for (var i = 0, block; block = blocks[i]; i++) {
554 |     if (block.type == 'factory_base') {
555 |       return block;
556 |     }
557 |   }
558 |   return null;
559 | };
560 | 
561 | /**
562 |  * Return the block name defined in the factory Root Block.
563 |  * @return {!string} Name of the generated block.
564 |  * @private
565 |  */
566 | Bdf.Factory.getBlockName_ = function() {
567 |   var rootBlock = Bdf.Factory.getRootBlock_();
568 |   if (!rootBlock) {
569 |     return;
570 |   }
571 |   var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase();
572 |   if (!blockType) {
573 |     blockType = Bdf.UNNAMED;
574 |   }
575 |   return blockType.replace(/\W/g, '_').replace(/^(\d)/, '_\\1');
576 | };
577 | 
578 | /**
579 |  * Escape a string.
580 |  * @param {string} string String to escape.
581 |  * @return {string} Escaped string surrounded by quotes.
582 |  * @private
583 |  */
584 | Bdf.Factory.escapeString_ = function(string) {
585 |   return JSON.stringify(string);
586 | };
587 | 


--------------------------------------------------------------------------------
/factory_blocks.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * Blockly Demos: Block Factory Blocks
  3 |  *
  4 |  * Copyright 2012 Google Inc.
  5 |  * https://developers.google.com/blockly/
  6 |  *
  7 |  * Licensed under the Apache License, Version 2.0 (the "License");
  8 |  * you may not use this file except in compliance with the License.
  9 |  * You may obtain a copy of the License at
 10 |  *
 11 |  *   http://www.apache.org/licenses/LICENSE-2.0
 12 |  *
 13 |  * Unless required by applicable law or agreed to in writing, software
 14 |  * distributed under the License is distributed on an "AS IS" BASIS,
 15 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16 |  * See the License for the specific language governing permissions and
 17 |  * limitations under the License.
 18 |  */
 19 | 
 20 | /**
 21 |  * @fileoverview Blocks for Blockly's Block Factory application.
 22 |  * @author fraser@google.com (Neil Fraser)
 23 |  */
 24 | 'use strict';
 25 | 
 26 | Blockly.Blocks['factory_base'] = {
 27 |   // Base of new block.
 28 |   init: function() {
 29 |     this.setColour(120);
 30 |     this.appendDummyInput()
 31 |         .appendField('name')
 32 |         .appendField(new Blockly.FieldTextInput('math_foo'), 'NAME');
 33 |     this.appendStatementInput('INPUTS')
 34 |         .setCheck('Input')
 35 |         .appendField('inputs');
 36 |     var dropdown = new Blockly.FieldDropdown([
 37 |         ['automatic inputs', 'AUTO'],
 38 |         ['external inputs', 'EXT'],
 39 |         ['inline inputs', 'INT']]);
 40 |     this.appendDummyInput()
 41 |         .appendField(dropdown, 'INLINE');
 42 |     dropdown = new Blockly.FieldDropdown([
 43 |         ['no connections', 'NONE'],
 44 |         ['← left output', 'LEFT'],
 45 |         ['↕ top+bottom connections', 'BOTH'],
 46 |         ['↑ top connection', 'TOP'],
 47 |         ['↓ bottom connection', 'BOTTOM']],
 48 |         function(option) {
 49 |           this.sourceBlock_.updateShape_(option);
 50 |         });
 51 |     this.appendDummyInput()
 52 |         .appendField(dropdown, 'CONNECTIONS');
 53 |     this.appendValueInput('COLOUR')
 54 |         .setCheck('Colour')
 55 |         .appendField('colour');
 56 |     /*
 57 |     this.appendValueInput('TOOLTIP')
 58 |         .setCheck('String')
 59 |         .appendField('tooltip');
 60 |     this.appendValueInput('HELP')
 61 |         .setCheck('String')
 62 |         .appendField('help url');
 63 |     */
 64 |     this.setTooltip('Build a custom block by plugging\n' +
 65 |         'fields, inputs and other blocks here.');
 66 |     this.setHelpUrl(
 67 |         'https://developers.google.com/blockly/custom-blocks/block-factory');
 68 |   },
 69 |   mutationToDom: function() {
 70 |     var container = document.createElement('mutation');
 71 |     container.setAttribute('connections', this.getFieldValue('CONNECTIONS'));
 72 |     return container;
 73 |   },
 74 |   domToMutation: function(xmlElement) {
 75 |     var connections = xmlElement.getAttribute('connections');
 76 |     this.updateShape_(connections);
 77 |   },
 78 |   updateShape_: function(option) {
 79 |     var outputExists = this.getInput('OUTPUTTYPE');
 80 |     var topExists = this.getInput('TOPTYPE');
 81 |     var bottomExists = this.getInput('BOTTOMTYPE');
 82 |     if (option == 'LEFT') {
 83 |       if (!outputExists) {
 84 |         this.appendValueInput('OUTPUTTYPE')
 85 |             .setCheck('Type')
 86 |             .appendField('output type');
 87 |         this.moveInputBefore('OUTPUTTYPE', 'COLOUR');
 88 |       }
 89 |     } else if (outputExists) {
 90 |       this.removeInput('OUTPUTTYPE');
 91 |     }
 92 |     if (option == 'TOP' || option == 'BOTH') {
 93 |       if (!topExists) {
 94 |         this.appendValueInput('TOPTYPE')
 95 |             .setCheck('Type')
 96 |             .appendField('top type');
 97 |         this.moveInputBefore('TOPTYPE', 'COLOUR');
 98 |       }
 99 |     } else if (topExists) {
100 |       this.removeInput('TOPTYPE');
101 |     }
102 |     if (option == 'BOTTOM' || option == 'BOTH') {
103 |       if (!bottomExists) {
104 |         this.appendValueInput('BOTTOMTYPE')
105 |             .setCheck('Type')
106 |             .appendField('bottom type');
107 |         this.moveInputBefore('BOTTOMTYPE', 'COLOUR');
108 |       }
109 |     } else if (bottomExists) {
110 |       this.removeInput('BOTTOMTYPE');
111 |     }
112 |   }
113 | };
114 | 
115 | var ALIGNMENT_OPTIONS =
116 |     [['left', 'LEFT'], ['right', 'RIGHT'], ['centre', 'CENTRE']];
117 | 
118 | Blockly.Blocks['input_value'] = {
119 |   // Value input.
120 |   init: function() {
121 |     this.setColour(210);
122 |     this.appendDummyInput()
123 |         .appendField('value input')
124 |         .appendField(new Blockly.FieldTextInput('NAME'), 'INPUTNAME');
125 |     this.appendStatementInput('FIELDS')
126 |         .setCheck('Field')
127 |         .appendField('fields')
128 |         .appendField(new Blockly.FieldDropdown(ALIGNMENT_OPTIONS), 'ALIGN');
129 |     this.appendValueInput('TYPE')
130 |         .setCheck('Type')
131 |         .setAlign(Blockly.ALIGN_RIGHT)
132 |         .appendField('type');
133 |     this.setPreviousStatement(true, 'Input');
134 |     this.setNextStatement(true, 'Input');
135 |     this.setTooltip('A value socket for horizontal connections.');
136 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=71');
137 |   },
138 |   onchange: function() {
139 |     if (!this.workspace) {
140 |       // Block has been deleted.
141 |       return;
142 |     }
143 |     inputNameCheck(this);
144 |   }
145 | };
146 | 
147 | Blockly.Blocks['input_statement'] = {
148 |   // Statement input.
149 |   init: function() {
150 |     this.setColour(210);
151 |     this.appendDummyInput()
152 |         .appendField('statement input')
153 |         .appendField(new Blockly.FieldTextInput('NAME'), 'INPUTNAME');
154 |     this.appendStatementInput('FIELDS')
155 |         .setCheck('Field')
156 |         .appendField('fields')
157 |         .appendField(new Blockly.FieldDropdown(ALIGNMENT_OPTIONS), 'ALIGN');
158 |     this.appendValueInput('TYPE')
159 |         .setCheck('Type')
160 |         .setAlign(Blockly.ALIGN_RIGHT)
161 |         .appendField('type');
162 |     this.setPreviousStatement(true, 'Input');
163 |     this.setNextStatement(true, 'Input');
164 |     this.setTooltip('A statement socket for enclosed vertical stacks.');
165 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=246');
166 |   },
167 |   onchange: function() {
168 |     if (!this.workspace) {
169 |       // Block has been deleted.
170 |       return;
171 |     }
172 |     inputNameCheck(this);
173 |   }
174 | };
175 | 
176 | Blockly.Blocks['input_dummy'] = {
177 |   // Dummy input.
178 |   init: function() {
179 |     this.setColour(210);
180 |     this.appendDummyInput()
181 |         .appendField('dummy input');
182 |     this.appendStatementInput('FIELDS')
183 |         .setCheck('Field')
184 |         .appendField('fields')
185 |         .appendField(new Blockly.FieldDropdown(ALIGNMENT_OPTIONS), 'ALIGN');
186 |     this.setPreviousStatement(true, 'Input');
187 |     this.setNextStatement(true, 'Input');
188 |     this.setTooltip('For adding fields on a separate row with no ' +
189 |                     'connections. Alignment options (left, right, centre) ' +
190 |                     'apply only to multi-line fields.');
191 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=293');
192 |   }
193 | };
194 | 
195 | Blockly.Blocks['field_static'] = {
196 |   // Text value.
197 |   init: function() {
198 |     this.setColour(160);
199 |     this.appendDummyInput()
200 |         .appendField('text')
201 |         .appendField(new Blockly.FieldTextInput(''), 'TEXT');
202 |     this.setPreviousStatement(true, 'Field');
203 |     this.setNextStatement(true, 'Field');
204 |     this.setTooltip('Static text that serves as a label.');
205 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88');
206 |   }
207 | };
208 | 
209 | Blockly.Blocks['field_input'] = {
210 |   // Text input.
211 |   init: function() {
212 |     this.setColour(160);
213 |     this.appendDummyInput()
214 |         .appendField('text input')
215 |         .appendField(new Blockly.FieldTextInput('default'), 'TEXT')
216 |         .appendField(',')
217 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
218 |     this.setPreviousStatement(true, 'Field');
219 |     this.setNextStatement(true, 'Field');
220 |     this.setTooltip('An input field for the user to enter text.');
221 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319');
222 |   },
223 |   onchange: function() {
224 |     if (!this.workspace) {
225 |       // Block has been deleted.
226 |       return;
227 |     }
228 |     fieldNameCheck(this);
229 |   }
230 | };
231 | 
232 | Blockly.Blocks['field_angle'] = {
233 |   // Angle input.
234 |   init: function() {
235 |     this.setColour(160);
236 |     this.appendDummyInput()
237 |         .appendField('angle input')
238 |         .appendField(new Blockly.FieldAngle('90'), 'ANGLE')
239 |         .appendField(',')
240 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
241 |     this.setPreviousStatement(true, 'Field');
242 |     this.setNextStatement(true, 'Field');
243 |     this.setTooltip('An input field for the user to enter an angle.');
244 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=372');
245 |   },
246 |   onchange: function() {
247 |     if (!this.workspace) {
248 |       // Block has been deleted.
249 |       return;
250 |     }
251 |     fieldNameCheck(this);
252 |   }
253 | };
254 | 
255 | Blockly.Blocks['field_dropdown'] = {
256 |   // Dropdown menu.
257 |   init: function() {
258 |     this.setColour(160);
259 |     this.appendDummyInput()
260 |         .appendField('dropdown')
261 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
262 |     this.appendDummyInput('OPTION0')
263 |         .appendField(new Blockly.FieldTextInput('option'), 'USER0')
264 |         .appendField(',')
265 |         .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU0');
266 |     this.appendDummyInput('OPTION1')
267 |         .appendField(new Blockly.FieldTextInput('option'), 'USER1')
268 |         .appendField(',')
269 |         .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU1');
270 |     this.appendDummyInput('OPTION2')
271 |         .appendField(new Blockly.FieldTextInput('option'), 'USER2')
272 |         .appendField(',')
273 |         .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU2');
274 |     this.setPreviousStatement(true, 'Field');
275 |     this.setNextStatement(true, 'Field');
276 |     this.setMutator(new Blockly.Mutator(['field_dropdown_option']));
277 |     this.setTooltip('Dropdown menu with a list of options.');
278 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
279 |     this.optionCount_ = 3;
280 |   },
281 |   mutationToDom: function(workspace) {
282 |     var container = document.createElement('mutation');
283 |     container.setAttribute('options', this.optionCount_);
284 |     return container;
285 |   },
286 |   domToMutation: function(container) {
287 |     for (var x = 0; x < this.optionCount_; x++) {
288 |       this.removeInput('OPTION' + x);
289 |     }
290 |     this.optionCount_ = parseInt(container.getAttribute('options'), 10);
291 |     for (var x = 0; x < this.optionCount_; x++) {
292 |       var input = this.appendDummyInput('OPTION' + x);
293 |       input.appendField(new Blockly.FieldTextInput('option'), 'USER' + x);
294 |       input.appendField(',');
295 |       input.appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + x);
296 |     }
297 |   },
298 |   decompose: function(workspace) {
299 |     var containerBlock =
300 |         Blockly.Block.obtain(workspace, 'field_dropdown_container');
301 |     containerBlock.initSvg();
302 |     var connection = containerBlock.getInput('STACK').connection;
303 |     for (var x = 0; x < this.optionCount_; x++) {
304 |       var optionBlock =
305 |           Blockly.Block.obtain(workspace, 'field_dropdown_option');
306 |       optionBlock.initSvg();
307 |       connection.connect(optionBlock.previousConnection);
308 |       connection = optionBlock.nextConnection;
309 |     }
310 |     return containerBlock;
311 |   },
312 |   compose: function(containerBlock) {
313 |     // Disconnect all input blocks and remove all inputs.
314 |     for (var x = this.optionCount_ - 1; x >= 0; x--) {
315 |       this.removeInput('OPTION' + x);
316 |     }
317 |     this.optionCount_ = 0;
318 |     // Rebuild the block's inputs.
319 |     var optionBlock = containerBlock.getInputTargetBlock('STACK');
320 |     while (optionBlock) {
321 |       this.appendDummyInput('OPTION' + this.optionCount_)
322 |           .appendField(new Blockly.FieldTextInput(
323 |               optionBlock.userData_ || 'option'), 'USER' + this.optionCount_)
324 |           .appendField(',')
325 |           .appendField(new Blockly.FieldTextInput(
326 |               optionBlock.cpuData_ || 'OPTIONNAME'), 'CPU' + this.optionCount_);
327 |       this.optionCount_++;
328 |       optionBlock = optionBlock.nextConnection &&
329 |           optionBlock.nextConnection.targetBlock();
330 |     }
331 |   },
332 |   saveConnections: function(containerBlock) {
333 |     // Store names and values for each option.
334 |     var optionBlock = containerBlock.getInputTargetBlock('STACK');
335 |     var x = 0;
336 |     while (optionBlock) {
337 |       optionBlock.userData_ = this.getFieldValue('USER' + x);
338 |       optionBlock.cpuData_ = this.getFieldValue('CPU' + x);
339 |       x++;
340 |       optionBlock = optionBlock.nextConnection &&
341 |           optionBlock.nextConnection.targetBlock();
342 |     }
343 |   },
344 |   onchange: function() {
345 |     if (!this.workspace) {
346 |       // Block has been deleted.
347 |       return;
348 |     }
349 |     if (this.optionCount_ < 1) {
350 |       this.setWarningText('Drop down menu must\nhave at least one option.');
351 |     } else {
352 |       fieldNameCheck(this);
353 |     }
354 |   }
355 | };
356 | 
357 | Blockly.Blocks['field_dropdown_container'] = {
358 |   // Container.
359 |   init: function() {
360 |     this.setColour(160);
361 |     this.appendDummyInput()
362 |         .appendField('add options');
363 |     this.appendStatementInput('STACK');
364 |     this.setTooltip('Add, remove, or reorder options\n' +
365 |                     'to reconfigure this dropdown menu.');
366 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
367 |     this.contextMenu = false;
368 |   }
369 | };
370 | 
371 | Blockly.Blocks['field_dropdown_option'] = {
372 |   // Add option.
373 |   init: function() {
374 |     this.setColour(160);
375 |     this.appendDummyInput()
376 |         .appendField('option');
377 |     this.setPreviousStatement(true);
378 |     this.setNextStatement(true);
379 |     this.setTooltip('Add a new option to the dropdown menu.');
380 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
381 |     this.contextMenu = false;
382 |   }
383 | };
384 | 
385 | Blockly.Blocks['field_checkbox'] = {
386 |   // Checkbox.
387 |   init: function() {
388 |     this.setColour(160);
389 |     this.appendDummyInput()
390 |         .appendField('checkbox')
391 |         .appendField(new Blockly.FieldCheckbox('TRUE'), 'CHECKED')
392 |         .appendField(',')
393 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
394 |     this.setPreviousStatement(true, 'Field');
395 |     this.setNextStatement(true, 'Field');
396 |     this.setTooltip('Checkbox field.');
397 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=485');
398 |   },
399 |   onchange: function() {
400 |     if (!this.workspace) {
401 |       // Block has been deleted.
402 |       return;
403 |     }
404 |     fieldNameCheck(this);
405 |   }
406 | };
407 | 
408 | Blockly.Blocks['field_colour'] = {
409 |   // Colour input.
410 |   init: function() {
411 |     this.setColour(160);
412 |     this.appendDummyInput()
413 |         .appendField('colour')
414 |         .appendField(new Blockly.FieldColour('#ff0000'), 'COLOUR')
415 |         .appendField(',')
416 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
417 |     this.setPreviousStatement(true, 'Field');
418 |     this.setNextStatement(true, 'Field');
419 |     this.setTooltip('Colour input field.');
420 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=495');
421 |   },
422 |   onchange: function() {
423 |     if (!this.workspace) {
424 |       // Block has been deleted.
425 |       return;
426 |     }
427 |     fieldNameCheck(this);
428 |   }
429 | };
430 | 
431 | Blockly.Blocks['field_date'] = {
432 |   // Date input.
433 |   init: function() {
434 |     this.setColour(160);
435 |     this.appendDummyInput()
436 |         .appendField('date')
437 |         .appendField(new Blockly.FieldDate(), 'DATE')
438 |         .appendField(',')
439 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
440 |     this.setPreviousStatement(true, 'Field');
441 |     this.setNextStatement(true, 'Field');
442 |     this.setTooltip('Date input field.');
443 |   },
444 |   onchange: function() {
445 |     if (!this.workspace) {
446 |       // Block has been deleted.
447 |       return;
448 |     }
449 |     fieldNameCheck(this);
450 |   }
451 | };
452 | 
453 | Blockly.Blocks['field_variable'] = {
454 |   // Dropdown for variables.
455 |   init: function() {
456 |     this.setColour(160);
457 |     this.appendDummyInput()
458 |         .appendField('variable')
459 |         .appendField(new Blockly.FieldTextInput('item'), 'TEXT')
460 |         .appendField(',')
461 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
462 |     this.setPreviousStatement(true, 'Field');
463 |     this.setNextStatement(true, 'Field');
464 |     this.setTooltip('Dropdown menu for variable names.');
465 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=510');
466 |   },
467 |   onchange: function() {
468 |     if (!this.workspace) {
469 |       // Block has been deleted.
470 |       return;
471 |     }
472 |     fieldNameCheck(this);
473 |   }
474 | };
475 | 
476 | Blockly.Blocks['field_image'] = {
477 |   // Image.
478 |   init: function() {
479 |     this.setColour(160);
480 |     var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif';
481 |     this.appendDummyInput()
482 |         .appendField('image')
483 |         .appendField(new Blockly.FieldTextInput(src), 'SRC');
484 |     this.appendDummyInput()
485 |         .appendField('width')
486 |         .appendField(new Blockly.FieldTextInput('15',
487 |             Blockly.FieldTextInput.numberValidator), 'WIDTH')
488 |         .appendField('height')
489 |         .appendField(new Blockly.FieldTextInput('15',
490 |             Blockly.FieldTextInput.numberValidator), 'HEIGHT')
491 |         .appendField('alt text')
492 |         .appendField(new Blockly.FieldTextInput('*'), 'ALT');
493 |     this.setPreviousStatement(true, 'Field');
494 |     this.setNextStatement(true, 'Field');
495 |     this.setTooltip('Static image (JPEG, PNG, GIF, SVG, BMP).\n' +
496 |                     'Retains aspect ratio regardless of height and width.\n' +
497 |                     'Alt text is for when collapsed.');
498 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=567');
499 |   }
500 | };
501 | 
502 | Blockly.Blocks['field_arduino_pin'] = {
503 |   // Set a dropdown field to selected an Arduino pin
504 |   init: function() {
505 |     this.setColour(160);
506 |     this.appendDummyInput()
507 |         .appendField('arduino')
508 |         .appendField(new Blockly.FieldDropdown(
509 |             [["digital", "DIGITAL"], ["analogue", "ANALOG"]]), "PIN_TYPE")
510 |         .appendField('pin dropdown,')
511 |         .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
512 |     this.setInputsInline(true);
513 |     this.setPreviousStatement(true, 'Field');
514 |     this.setNextStatement(true, 'Field');
515 |     this.setTooltip('Add a dropdown to select an Arduino pin.');
516 |     this.setHelpUrl('');
517 |   },
518 |   onchange: function() {
519 |     if (!this.workspace) {
520 |       // Block has been deleted.
521 |       return;
522 |     }
523 |     fieldNameCheck(this);
524 |   }
525 | };
526 | 
527 | Blockly.Blocks['type_group'] = {
528 |   // Group of types.
529 |   init: function() {
530 |     this.setColour(230);
531 |     this.appendValueInput('TYPE0')
532 |         .setCheck('Type')
533 |         .appendField('any of');
534 |     this.appendValueInput('TYPE1')
535 |         .setCheck('Type');
536 |     this.setOutput(true, 'Type');
537 |     this.setMutator(new Blockly.Mutator(['type_group_item']));
538 |     this.setTooltip('Allows more than one type to be accepted.');
539 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677');
540 |     this.typeCount_ = 2;
541 |   },
542 |   mutationToDom: function(workspace) {
543 |     var container = document.createElement('mutation');
544 |     container.setAttribute('types', this.typeCount_);
545 |     return container;
546 |   },
547 |   domToMutation: function(container) {
548 |     for (var x = 0; x < this.typeCount_; x++) {
549 |       this.removeInput('TYPE' + x);
550 |     }
551 |     this.typeCount_ = parseInt(container.getAttribute('types'), 10);
552 |     for (var x = 0; x < this.typeCount_; x++) {
553 |       var input = this.appendValueInput('TYPE' + x)
554 |                       .setCheck('Type');
555 |       if (x == 0) {
556 |         input.appendField('any of');
557 |       }
558 |     }
559 |   },
560 |   decompose: function(workspace) {
561 |     var containerBlock =
562 |         Blockly.Block.obtain(workspace, 'type_group_container');
563 |     containerBlock.initSvg();
564 |     var connection = containerBlock.getInput('STACK').connection;
565 |     for (var x = 0; x < this.typeCount_; x++) {
566 |       var typeBlock = Blockly.Block.obtain(workspace, 'type_group_item');
567 |       typeBlock.initSvg();
568 |       connection.connect(typeBlock.previousConnection);
569 |       connection = typeBlock.nextConnection;
570 |     }
571 |     return containerBlock;
572 |   },
573 |   compose: function(containerBlock) {
574 |     // Disconnect all input blocks and remove all inputs.
575 |     for (var x = this.typeCount_ - 1; x >= 0; x--) {
576 |       this.removeInput('TYPE' + x);
577 |     }
578 |     this.typeCount_ = 0;
579 |     // Rebuild the block's inputs.
580 |     var typeBlock = containerBlock.getInputTargetBlock('STACK');
581 |     while (typeBlock) {
582 |       var input = this.appendValueInput('TYPE' + this.typeCount_)
583 |                       .setCheck('Type');
584 |       if (this.typeCount_ == 0) {
585 |         input.appendField('any of');
586 |       }
587 |       // Reconnect any child blocks.
588 |       if (typeBlock.valueConnection_) {
589 |         input.connection.connect(typeBlock.valueConnection_);
590 |       }
591 |       this.typeCount_++;
592 |       typeBlock = typeBlock.nextConnection &&
593 |           typeBlock.nextConnection.targetBlock();
594 |     }
595 |   },
596 |   saveConnections: function(containerBlock) {
597 |     // Store a pointer to any connected child blocks.
598 |     var typeBlock = containerBlock.getInputTargetBlock('STACK');
599 |     var x = 0;
600 |     while (typeBlock) {
601 |       var input = this.getInput('TYPE' + x);
602 |       typeBlock.valueConnection_ = input && input.connection.targetConnection;
603 |       x++;
604 |       typeBlock = typeBlock.nextConnection &&
605 |           typeBlock.nextConnection.targetBlock();
606 |     }
607 |   }
608 | };
609 | 
610 | Blockly.Blocks['type_group_container'] = {
611 |   // Container.
612 |   init: function() {
613 |     this.setColour(230);
614 |     this.appendDummyInput()
615 |         .appendField('add types');
616 |     this.appendStatementInput('STACK');
617 |     this.setTooltip('Add, or remove allowed type.');
618 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677');
619 |     this.contextMenu = false;
620 |   }
621 | };
622 | 
623 | Blockly.Blocks['type_group_item'] = {
624 |   // Add type.
625 |   init: function() {
626 |     this.setColour(230);
627 |     this.appendDummyInput()
628 |         .appendField('type');
629 |     this.setPreviousStatement(true);
630 |     this.setNextStatement(true);
631 |     this.setTooltip('Add a new allowed type.');
632 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677');
633 |     this.contextMenu = false;
634 |   }
635 | };
636 | 
637 | Blockly.Blocks['type_null'] = {
638 |   // Null type.
639 |   valueType: null,
640 |   init: function() {
641 |     this.setColour(230);
642 |     this.appendDummyInput()
643 |         .appendField('any');
644 |     this.setOutput(true, 'Type');
645 |     this.setTooltip('Any type is allowed.');
646 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602');
647 |   }
648 | };
649 | 
650 | Blockly.Blocks['type_boolean'] = {
651 |   // Boolean type.
652 |   valueType: 'Boolean',
653 |   init: function() {
654 |     this.setColour(230);
655 |     this.appendDummyInput()
656 |         .appendField('boolean');
657 |     this.setOutput(true, 'Type');
658 |     this.setTooltip('Booleans (true/false) are allowed.');
659 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602');
660 |   }
661 | };
662 | 
663 | Blockly.Blocks['type_number'] = {
664 |   // Number type.
665 |   valueType: 'Number',
666 |   init: function() {
667 |     this.setColour(230);
668 |     this.appendDummyInput()
669 |         .appendField('number');
670 |     this.setOutput(true, 'Type');
671 |     this.setTooltip('Numbers (int/float) are allowed.');
672 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602');
673 |   }
674 | };
675 | 
676 | Blockly.Blocks['type_string'] = {
677 |   // String type.
678 |   valueType: 'String',
679 |   init: function() {
680 |     this.setColour(230);
681 |     this.appendDummyInput()
682 |         .appendField('string');
683 |     this.setOutput(true, 'Type');
684 |     this.setTooltip('Strings (text) are allowed.');
685 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602');
686 |   }
687 | };
688 | 
689 | Blockly.Blocks['type_list'] = {
690 |   // List type.
691 |   valueType: 'Array',
692 |   init: function() {
693 |     this.setColour(230);
694 |     this.appendDummyInput()
695 |         .appendField('list');
696 |     this.setOutput(true, 'Type');
697 |     this.setTooltip('Arrays (lists) are allowed.');
698 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602');
699 |   }
700 | };
701 | 
702 | Blockly.Blocks['type_other'] = {
703 |   // Other type.
704 |   init: function() {
705 |     this.setColour(230);
706 |     this.appendDummyInput()
707 |         .appendField('other')
708 |         .appendField(new Blockly.FieldTextInput(''), 'TYPE');
709 |     this.setOutput(true, 'Type');
710 |     this.setTooltip('Custom type to allow.');
711 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=702');
712 |   }
713 | };
714 | 
715 | Blockly.Blocks['colour_hue'] = {
716 |   // Set the colour of the block.
717 |   init: function() {
718 |     this.appendDummyInput()
719 |         .appendField('hue:')
720 |         .appendField(new Blockly.FieldAngle('0', this.validator), 'HUE');
721 |     this.setOutput(true, 'Colour');
722 |     this.setTooltip('Paint the block with this colour.');
723 |     this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=55');
724 |   },
725 |   validator: function(text) {
726 |     // Update the current block's colour to match.
727 |     this.sourceBlock_.setColour(text);
728 |   },
729 |   mutationToDom: function(workspace) {
730 |     var container = document.createElement('mutation');
731 |     container.setAttribute('colour', this.getColour());
732 |     return container;
733 |   },
734 |   domToMutation: function(container) {
735 |     this.setColour(container.getAttribute('colour'));
736 |   }
737 | };
738 | 
739 | /**
740 |  * Check to see if more than one field has this name.
741 |  * Highly inefficient (On^2), but n is small.
742 |  * @param {!Blockly.Block} referenceBlock Block to check.
743 |  */
744 | function fieldNameCheck(referenceBlock) {
745 |   var name = referenceBlock.getFieldValue('FIELDNAME').toLowerCase();
746 |   var count = 0;
747 |   var blocks = referenceBlock.workspace.getAllBlocks();
748 |   for (var x = 0, block; block = blocks[x]; x++) {
749 |     var otherName = block.getFieldValue('FIELDNAME');
750 |     if (!block.disabled && !block.getInheritedDisabled() &&
751 |         otherName && otherName.toLowerCase() == name) {
752 |       count++;
753 |     }
754 |   }
755 |   var msg = (count > 1) ?
756 |       'There are ' + count + ' field blocks\n with this name.' : null;
757 |   referenceBlock.setWarningText(msg);
758 | }
759 | 
760 | /**
761 |  * Check to see if more than one input has this name.
762 |  * Highly inefficient (On^2), but n is small.
763 |  * @param {!Blockly.Block} referenceBlock Block to check.
764 |  */
765 | function inputNameCheck(referenceBlock) {
766 |   var name = referenceBlock.getFieldValue('INPUTNAME').toLowerCase();
767 |   var count = 0;
768 |   var blocks = referenceBlock.workspace.getAllBlocks();
769 |   for (var x = 0, block; block = blocks[x]; x++) {
770 |     var otherName = block.getFieldValue('INPUTNAME');
771 |     if (!block.disabled && !block.getInheritedDisabled() &&
772 |         otherName && otherName.toLowerCase() == name) {
773 |       count++;
774 |     }
775 |   }
776 |   var msg = (count > 1) ?
777 |       'There are ' + count + ' input blocks\n with this name.' : null;
778 |   referenceBlock.setWarningText(msg);
779 | }
780 | 


--------------------------------------------------------------------------------
/filesaver/Blob.js:
--------------------------------------------------------------------------------
  1 | /* Blob.js
  2 |  * A Blob implementation.
  3 |  * 2013-01-23
  4 |  * 
  5 |  * By Eli Grey, http://eligrey.com
  6 |  * By Devin Samarin, https://github.com/eboyjr
  7 |  * License: X11/MIT
  8 |  *   See LICENSE.md
  9 |  */
 10 | 
 11 | /*global self, unescape */
 12 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
 13 |   plusplus: true */
 14 | 
 15 | /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
 16 | 
 17 | if (typeof Blob !== "function")
 18 | var Blob = (function (view) {
 19 | 	"use strict";
 20 | 
 21 | 	var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || view.MSBlobBuilder || (function(view) {
 22 | 		var
 23 | 			  get_class = function(object) {
 24 | 				return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
 25 | 			}
 26 | 			, FakeBlobBuilder = function BlobBuilder() {
 27 | 				this.data = [];
 28 | 			}
 29 | 			, FakeBlob = function Blob(data, type, encoding) {
 30 | 				this.data = data;
 31 | 				this.size = data.length;
 32 | 				this.type = type;
 33 | 				this.encoding = encoding;
 34 | 			}
 35 | 			, FBB_proto = FakeBlobBuilder.prototype
 36 | 			, FB_proto = FakeBlob.prototype
 37 | 			, FileReaderSync = view.FileReaderSync
 38 | 			, FileException = function(type) {
 39 | 				this.code = this[this.name = type];
 40 | 			}
 41 | 			, file_ex_codes = (
 42 | 				  "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
 43 | 				+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
 44 | 			).split(" ")
 45 | 			, file_ex_code = file_ex_codes.length
 46 | 			, real_URL = view.URL || view.webkitURL || view
 47 | 			, real_create_object_URL = real_URL.createObjectURL
 48 | 			, real_revoke_object_URL = real_URL.revokeObjectURL
 49 | 			, URL = real_URL
 50 | 			, btoa = view.btoa
 51 | 			, atob = view.atob
 52 | 			, can_apply_typed_arrays = false
 53 | 			, can_apply_typed_arrays_test = function(pass) {
 54 | 				can_apply_typed_arrays = !pass;
 55 | 			}
 56 | 			
 57 | 			, ArrayBuffer = view.ArrayBuffer
 58 | 			, Uint8Array = view.Uint8Array
 59 | 		;
 60 | 		FakeBlob.fake = FB_proto.fake = true;
 61 | 		while (file_ex_code--) {
 62 | 			FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
 63 | 		}
 64 | 		try {
 65 | 			if (Uint8Array) {
 66 | 				can_apply_typed_arrays_test.apply(0, new Uint8Array(1));
 67 | 			}
 68 | 		} catch (ex) {}
 69 | 		if (!real_URL.createObjectURL) {
 70 | 			URL = view.URL = {};
 71 | 		}
 72 | 		URL.createObjectURL = function(blob) {
 73 | 			var
 74 | 				  type = blob.type
 75 | 				, data_URI_header
 76 | 			;
 77 | 			if (type === null) {
 78 | 				type = "application/octet-stream";
 79 | 			}
 80 | 			if (blob instanceof FakeBlob) {
 81 | 				data_URI_header = "data:" + type;
 82 | 				if (blob.encoding === "base64") {
 83 | 					return data_URI_header + ";base64," + blob.data;
 84 | 				} else if (blob.encoding === "URI") {
 85 | 					return data_URI_header + "," + decodeURIComponent(blob.data);
 86 | 				} if (btoa) {
 87 | 					return data_URI_header + ";base64," + btoa(blob.data);
 88 | 				} else {
 89 | 					return data_URI_header + "," + encodeURIComponent(blob.data);
 90 | 				}
 91 | 			} else if (real_create_object_URL) {
 92 | 				return real_create_object_URL.call(real_URL, blob);
 93 | 			}
 94 | 		};
 95 | 		URL.revokeObjectURL = function(object_URL) {
 96 | 			if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
 97 | 				real_revoke_object_URL.call(real_URL, object_URL);
 98 | 			}
 99 | 		};
100 | 		FBB_proto.append = function(data/*, endings*/) {
101 | 			var bb = this.data;
102 | 			// decode data to a binary string
103 | 			if (Uint8Array && data instanceof ArrayBuffer) {
104 | 				if (can_apply_typed_arrays) {
105 | 					bb.push(String.fromCharCode.apply(String, new Uint8Array(data)));
106 | 				} else {
107 | 					var
108 | 						  str = ""
109 | 						, buf = new Uint8Array(data)
110 | 						, i = 0
111 | 						, buf_len = buf.length
112 | 					;
113 | 					for (; i < buf_len; i++) {
114 | 						str += String.fromCharCode(buf[i]);
115 | 					}
116 | 				}
117 | 			} else if (get_class(data) === "Blob" || get_class(data) === "File") {
118 | 				if (FileReaderSync) {
119 | 					var fr = new FileReaderSync;
120 | 					bb.push(fr.readAsBinaryString(data));
121 | 				} else {
122 | 					// async FileReader won't work as BlobBuilder is sync
123 | 					throw new FileException("NOT_READABLE_ERR");
124 | 				}
125 | 			} else if (data instanceof FakeBlob) {
126 | 				if (data.encoding === "base64" && atob) {
127 | 					bb.push(atob(data.data));
128 | 				} else if (data.encoding === "URI") {
129 | 					bb.push(decodeURIComponent(data.data));
130 | 				} else if (data.encoding === "raw") {
131 | 					bb.push(data.data);
132 | 				}
133 | 			} else {
134 | 				if (typeof data !== "string") {
135 | 					data += ""; // convert unsupported types to strings
136 | 				}
137 | 				// decode UTF-16 to binary string
138 | 				bb.push(unescape(encodeURIComponent(data)));
139 | 			}
140 | 		};
141 | 		FBB_proto.getBlob = function(type) {
142 | 			if (!arguments.length) {
143 | 				type = null;
144 | 			}
145 | 			return new FakeBlob(this.data.join(""), type, "raw");
146 | 		};
147 | 		FBB_proto.toString = function() {
148 | 			return "[object BlobBuilder]";
149 | 		};
150 | 		FB_proto.slice = function(start, end, type) {
151 | 			var args = arguments.length;
152 | 			if (args < 3) {
153 | 				type = null;
154 | 			}
155 | 			return new FakeBlob(
156 | 				  this.data.slice(start, args > 1 ? end : this.data.length)
157 | 				, type
158 | 				, this.encoding
159 | 			);
160 | 		};
161 | 		FB_proto.toString = function() {
162 | 			return "[object Blob]";
163 | 		};
164 | 		return FakeBlobBuilder;
165 | 	}(view));
166 | 
167 | 	return function Blob(blobParts, options) {
168 | 		var type = options ? (options.type || "") : "";
169 | 		var builder = new BlobBuilder();
170 | 		if (blobParts) {
171 | 			for (var i = 0, len = blobParts.length; i < len; i++) {
172 | 				builder.append(blobParts[i]);
173 | 			}
174 | 		}
175 | 		return builder.getBlob(type);
176 | 	};
177 | }(self));
178 | 


--------------------------------------------------------------------------------
/filesaver/FileSaver.min.js:
--------------------------------------------------------------------------------
1 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
2 | var saveAs=saveAs||(function(h){"use strict";var r=h.document,l=function(){return h.URL||h.webkitURL||h},e=h.URL||h.webkitURL||h,n=r.createElementNS("http://www.w3.org/1999/xhtml","a"),g="download" in n,j=function(t){var s=r.createEvent("MouseEvents");s.initMouseEvent("click",true,false,h,0,0,0,0,0,false,false,false,false,0,null);return t.dispatchEvent(s)},o=h.webkitRequestFileSystem,p=h.requestFileSystem||o||h.mozRequestFileSystem,m=function(s){(h.setImmediate||h.setTimeout)(function(){throw s},0)},c="application/octet-stream",k=0,b=[],i=function(){var t=b.length;while(t--){var s=b[t];if(typeof s==="string"){e.revokeObjectURL(s)}else{s.remove()}}b.length=0},q=function(t,s,w){s=[].concat(s);var v=s.length;while(v--){var x=t["on"+s[v]];if(typeof x==="function"){try{x.call(t,w||t)}catch(u){m(u)}}}},f=function(t,u){var v=this,B=t.type,E=false,x,w,s=function(){var F=l().createObjectURL(t);b.push(F);return F},A=function(){q(v,"writestart progress write writeend".split(" "))},D=function(){if(E||!x){x=s(t)}w.location.href=x;v.readyState=v.DONE;A()},z=function(F){return function(){if(v.readyState!==v.DONE){return F.apply(this,arguments)}}},y={create:true,exclusive:false},C;v.readyState=v.INIT;if(!u){u="download"}if(g){x=s(t);n.href=x;n.download=u;if(j(n)){v.readyState=v.DONE;A();return}}if(h.chrome&&B&&B!==c){C=t.slice||t.webkitSlice;t=C.call(t,0,t.size,c);E=true}if(o&&u!=="download"){u+=".download"}if(B===c||o){w=h}else{w=h.open()}if(!p){D();return}k+=t.size;p(h.TEMPORARY,k,z(function(F){F.root.getDirectory("saved",y,z(function(G){var H=function(){G.getFile(u,y,z(function(I){I.createWriter(z(function(J){J.onwriteend=function(K){w.location.href=I.toURL();b.push(I);v.readyState=v.DONE;q(v,"writeend",K)};J.onerror=function(){var K=J.error;if(K.code!==K.ABORT_ERR){D()}};"writestart progress write abort".split(" ").forEach(function(K){J["on"+K]=v["on"+K]});J.write(t);v.abort=function(){J.abort();v.readyState=v.DONE};v.readyState=v.WRITING}),D)}),D)};G.getFile(u,{create:false},z(function(I){I.remove();H()}),z(function(I){if(I.code===I.NOT_FOUND_ERR){H()}else{D()}}))}),D)}),D)},d=f.prototype,a=function(s,t){return new f(s,t)};d.abort=function(){var s=this;s.readyState=s.DONE;q(s,"abort")};d.readyState=d.INIT=0;d.WRITING=1;d.DONE=2;d.error=d.onwritestart=d.onprogress=d.onwrite=d.onabort=d.onerror=d.onwriteend=null;h.addEventListener("unload",i,false);return a}(self));


--------------------------------------------------------------------------------
/generator.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * BlocklyDuinoFactory Generator module
  3 |  *
  4 |  * Copyright 2015 BlocklyDuino https://github.com/BlocklyDuino
  5 |  *
  6 |  * Licensed under the Apache License, Version 2.0 (the "License");
  7 |  * you may not use this file except in compliance with the License.
  8 |  * You may obtain a copy of the License at
  9 |  *
 10 |  *   http://www.apache.org/licenses/LICENSE-2.0
 11 |  *
 12 |  * Unless required by applicable law or agreed to in writing, software
 13 |  * distributed under the License is distributed on an "AS IS" BASIS,
 14 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 |  * See the License for the specific language governing permissions and
 16 |  * limitations under the License.
 17 |  */
 18 | 
 19 | /**
 20 |  * @fileoverview JavaScript for BlocklyDuinoFactory block code generator module.
 21 |  */
 22 | 'use strict';
 23 | 
 24 | /**
 25 |  * Create a namespace nested in the BlocklyDuinoFactory application.
 26 |  */
 27 | var Bdf = Bdf || {};
 28 | Bdf.Generator = Bdf.Generator || {};
 29 | 
 30 | /**
 31 |  * Workspace for user to generate the block code.
 32 |  * @type {Blockly.Workspace}
 33 |  */
 34 | Bdf.Generator.workspace = null;
 35 | 
 36 | /**
 37 |  * Inject Blockly into the given element.
 38 |  * @param {!string|!Element} element HTML element name or Element to inject the
 39 |  *     generator Blockly workspace.
 40 |  * @param {!Element} toolbox XML element with the Blockly toolbox.
 41 |  */
 42 | Bdf.Generator.injectBlockly = function(element, toolbox) {
 43 |   Bdf.Generator.workspace = Blockly.inject(element,
 44 |       {toolbox: toolbox,
 45 |        media: 'blockly/media/' });
 46 | };
 47 | 
 48 | /**
 49 |  * Update the generator code.
 50 |  * @param {!Blockly.Block} block Rendered block in preview workspace.
 51 |  * @return {!string} Generated JavaScript code for the Arduino code Generator.
 52 |  */
 53 | Bdf.Generator.updateGenerator = function(block) {
 54 |   function makeVar(root, name) {
 55 |     name = name.toLowerCase().replace(/\W/g, '_');
 56 |     return '  var ' + root + '_' + name;
 57 |   }
 58 |   var language = 'Arduino';
 59 |   var code = [];
 60 |   code.push("Blockly." + language + "['" + block.type +
 61 |             "'] = function(block) {");
 62 | 
 63 |   // Generate getters for any fields or inputs.
 64 |   for (var i = 0, input; input = block.inputList[i]; i++) {
 65 |     for (var j = 0, field; field = input.fieldRow[j]; j++) {
 66 |       var name = field.name;
 67 |       if (!name) {
 68 |         continue;
 69 |       }
 70 |       if (field instanceof Blockly.FieldVariable) {
 71 |         // Subclass of Blockly.FieldDropdown, must test first.
 72 |         code.push(makeVar('variable', name) +
 73 |                   " = Blockly." + language +
 74 |                   ".variableDB_.getName(block.getFieldValue('" + name +
 75 |                   "'), Blockly.Variables.NAME_TYPE);");
 76 |       } else if (field instanceof Blockly.FieldAngle) {
 77 |         // Subclass of Blockly.FieldTextInput, must test first.
 78 |         code.push(makeVar('angle', name) +
 79 |                   " = block.getFieldValue('" + name + "');");
 80 |       } else if (Blockly.FieldDate && field instanceof Blockly.FieldDate) {
 81 |         // Blockly.FieldDate may not be compiled into Blockly.
 82 |         code.push(makeVar('date', name) +
 83 |                   " = block.getFieldValue('" + name + "');");
 84 |       } else if (field instanceof Blockly.FieldColour) {
 85 |         code.push(makeVar('colour', name) +
 86 |                   " = block.getFieldValue('" + name + "');");
 87 |       } else if (field instanceof Blockly.FieldCheckbox) {
 88 |         code.push(makeVar('checkbox', name) +
 89 |                   " = block.getFieldValue('" + name + "') == 'TRUE';");
 90 |       } else if (field instanceof Blockly.FieldDropdown) {
 91 |         code.push(makeVar('dropdown', name) +
 92 |                   " = block.getFieldValue('" + name + "');");
 93 |       } else if (field instanceof Blockly.FieldTextInput) {
 94 |         code.push(makeVar('text', name) +
 95 |                   " = block.getFieldValue('" + name + "');");
 96 |       }
 97 |     }
 98 |     var name = input.name;
 99 |     if (name) {
100 |       if (input.type == Blockly.INPUT_VALUE) {
101 |         code.push(makeVar('value', name) +
102 |                   " = Blockly." + language + ".valueToCode(block, '" + name +
103 |                   "', Blockly." + language + ".ORDER_ATOMIC);");
104 |       } else if (input.type == Blockly.NEXT_STATEMENT) {
105 |         code.push(makeVar('statements', name) +
106 |                   " = Blockly." + language + ".statementToCode(block, '" +
107 |                   name + "');");
108 |       }
109 |     }
110 |   }
111 |   code.push("  // TODO: Assemble " + language + " into code variable.");
112 |   code.push("  var code = \'...\';");
113 |   if (block.outputConnection) {
114 |     code.push("  // TODO: Change ORDER_NONE to the correct strength.");
115 |     code.push("  return [code, Blockly." + language + ".ORDER_NONE];");
116 |   } else {
117 |     code.push("  return code;");
118 |   }
119 |   code.push("};");
120 | 
121 |   return code.join('\n');
122 | };
123 | 


--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | 
  4 |   
  5 |   
  6 |   BlocklyDuino: Block Factory
  7 |   
  8 |   
  9 |   
 10 |   
 11 |   
 12 |   
 13 |   
 14 |   
 15 |   
 16 |   
 17 |   
 18 |   
 19 |   
 20 |   
 21 | 
 22 | 
 23 | 
 24 |   
 25 |     
 26 |     
 27 |       
 51 |     
 52 |     
 53 |     
 54 |       
 81 |       
128 |     
129 |   
28 | 29 | 30 | 33 | 48 | 49 |
31 |

BlocklyDuino: Block Factory

32 |
34 | 35 | 38 | 41 | 44 | 47 |
50 |
55 | 56 | 57 | 58 | 61 | 62 | 63 | 67 | 68 | 69 | 72 | 73 | 74 | 78 | 79 |
59 |

Block Definition:

60 |
64 |
65 |
66 |
70 |

Block Generator:

71 |
75 |
76 |
77 |
80 |
82 | 83 | 84 | 85 | 94 | 95 | 96 | 100 | 101 | 102 | 110 | 111 | 112 | 115 | 116 | 117 | 120 | 121 | 122 | 125 | 126 |
86 |

Definition code: 87 | 92 |

93 |
97 |

 98 |               
 99 |             
103 |

Preview: 104 | 108 |

109 |
113 |
114 |
118 |

Generator code for Arduino:

119 |
123 |

124 |             
127 |
130 | 131 | 169 | 170 | 303 | 304 | 305 | -------------------------------------------------------------------------------- /prettify/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /prettify/prettify.js: -------------------------------------------------------------------------------- 1 | !function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a= 3 | b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;ah[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com", 11 | /^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+ 12 | s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/, 13 | q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d= 14 | c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/, 21 | V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-", 22 | /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/], 23 | ["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}), 24 | ["cs"]);p(v({keywords:N,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:Q, 25 | hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]); 26 | p(C([],[["str",/^[\S\s]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="
"+a+"
";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1}); 27 | return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i