From 3ca7bcc3dfc80651c65c103740feec3de39fb1c3 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 30 Jun 2017 16:50:04 -0700 Subject: [PATCH] Develop to master (#1209) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding new minimap demo * Basic code style changes. Adding a few more comments. Return early if disableScrollChange in onScrollChange listener. * Adding horizontal scrolling. Changed scroll change callbacks from onScroll_ to setHandlePosition. onScroll_ is not challed when workspace is dragged. * Registering mousemove and mouseup listener in mousedown event. Mousemove and Mouseup events are now listening over document. * Adding the remove variable modal and functionality to accessible Blockly. (#1011) * Minimap position bug fix for browsers other than chrome. Added touch support. * Adding an add variable modal to accessible Blockly. (#1015) * Adding the remove variable modal and functionality to accessible Blockly. * Adding the add variable modal for accessible Blockly. * Block browser context menu in the toolbox and flyout * Add links to the dev registration form and contributor guidelines * Miscellaneous comment cleanup * Adding the common modal class. (#1017) Centralizes accessible modal behavior. * - Changed error message referencing 'procedure' instead of 'function' (#1019) - Added iOS specific UI messages - Fixed bug with js_to_json.py script where it didn't recognize ' character * - Allows use of Blockly's messaging format for category name, colour,… (#1028) ...in toolbox XML. - Updated code editor demo to use this message format - Re-built blockly_compressed.js * Making text_count use a text color (like text_length, which also returns a number). (#1027) * Enable google/blockly with continuous build on travis ci (#1023) (#1035) * create .travis for ci job * initial checkin for blocky-web travis ci job * rename file to .travis.yaml for typo * remove after_script * added cache * rename .travis.yaml to .travis.yml * Update .travis.yml * include build script * fix yaml file format issue * debug install part * debug build issue * Update .travis.yml * remove cache for now * Update .travis.yml * Update .travis.yml * Update .travis.yml * more debug info * Update .travis.yml * Update .travis.yml * fix typo * installing chrome browser * remove chrome setting config * run build.py as part of npm install * Update .travis.yml * update karma dependency * use karma as test runner * fix typo * remove karma test for now * Update .travis.yml * Update package.json * add npm test target * add browserstack-runner depdendency * update browser support * fix typo for test target * fix chrome typo * added closure dependency * add google-closure-library * include blockly_uncompressed.js and core.js dependency * uncomment out core/*.js files * add kama job as part of install * remove browserstack add on for now * fix karma config typo * add karma-closure * add os support * remove typo config * include more closure files * change os back to linux * use closure-library from node_modules * change log level back to INFO * change npm test target to use open browser command instead of karma * change travis test target to use open command instead of karma * list current directory * find what's in current dir * typo command * Update .travis.yml * typo again * open right index.html * use right path for index.html * xdg-open to open default browser on travis * exit browser after 5s wait * change timeout to 1 min * exit after opening up browser * use browser only * use karma * remove un-needed dependency * clean up script section * fix typo * update build status on readme * initial commit for selenium integration tests * update selenium jar path * fix test_runner.js typo * add more debug info * check java version * add && instead of 9288 * fix java path * add logic to check if selenium is running or not * add some deugging info * initial commit to get chromedriver * add chromedriver flag * add get_chromedriver.sh to package.json and .travel * change browser to chrome for now * fix path issue * update chromdriver path * fix path issue again * more debugging * add debug msg * fix typo * minor fix for getting chromedriver * install latest chrome browser * clean up pakcage.json * use npm target for test run * remove removing trailing comma * fix another trailing comma * updated travis test target * clean up scripts * not sure nmp run preinstall * redirect selenium log to tmp file * revert writing console log to file * update test summary * more clean up * minor clean up before pull request * resolved closure-library conflict 1. add closure-library to dependencies instead of devDependencies. 2. add lint back in scripts block * fix typo (adding comma) in script section * Renames Blockly.workspaceDragSurface to Blockly.WorkspaceDragSurface. Fixes #880. * Ensure useDragSurface is a boolean. Fixed #988 * use pretest instead of preinstall in package.json (#1043) * cherry pick for pretest fix * put pretest target to test_setup.sh * fix conflict * cherry pick for get_chromedriver.sh * add some sleep to wait download to finish * use node.js stable * use npm test target * field_angle renders degree symbol consistently. Fixes #973 * bumpNeighbours_ function moved to block_svg. Fixed #1009 * Update RegEx in js-to-json to match windowi eol (#1050) The current regex only works with the "\n" line endings as it expects no characters after the optional ";" at the end of the line. In windows, if it adds the "\r" it counts as a characters and is not part of the line terminator so it doesn't match. * Fix French translation of "colour with rgb" block (#1053) "colorier", which is currently used, is a verb and proposed "couleur" is a noun: the block in question does not change colour of anything, it creates new colour instead, thus noun is more applicable. Also, noun is used in French translation of "random colour" block: "couleur aléatoire". * Enforcing non-empty names on value inputs and statement inputs. (#1054) * Correcting #1054 (#1056) single quotes. better logic. * Created a variable model with name, id, and type. Created a jsunit test file for variable model. * Change how blockly handles cursors. The old way was quite slow becau… (#1057) * Change how blockly handles cursors. The old way was quite slow because it changed the stylesheet directly. See issue #981 for more details on implementation and tradeoffs. This changes makes the following high level changes: deprecate Blockly.Css.setCursor, use built in open and closed hand cursor instead of custom .cur files, add css to draggable objects to set the open and closed hand cursors. * Rebuild blockly_uncompressed to pick up a testing change to make travis happy. Fix a build warning from a multi-line string in the process. (#1059) * Merge master into develop (#1063) - pick up translation changes - clean up trailing spaces * use goog.string.startswith instead of string.startswith (#1065) * New jsinterpreter demo includes wait block. Both demos have improved UI for clarity. (#1001) Refactor of interpreter demo * Renamed demos/interpreter/index.html as demos/interpreter/step-execution.html (including redirect), and added demos/interpreter/async-execution.html. * Refactored code to automatically generate/parse the blocks, eliminating the need for a "Parse JavaScript" button. Code is still shown in alert upon stepping to the first statement. Print statements now write to output + + + + + + + + + \ No newline at end of file diff --git a/demos/interpreter/index.html b/demos/interpreter/index.html index c72f795a0..2245057c0 100644 --- a/demos/interpreter/index.html +++ b/demos/interpreter/index.html @@ -1,200 +1,11 @@ - - Blockly Demo: JS Interpreter - - - - - - + + Redirecting... + -

Blockly > - Demos > JS Interpreter

- -

This is a simple demo of executing code with a sandboxed JavaScript interpreter.

- -

→ More info on JS Interpreter

- -

- - -

- -
- - - - - - - +Redirecting to step execution jsinterpreter demo. diff --git a/demos/interpreter/step-execution.html b/demos/interpreter/step-execution.html new file mode 100644 index 000000000..8a8b95a6a --- /dev/null +++ b/demos/interpreter/step-execution.html @@ -0,0 +1,251 @@ + + + + + Blockly Demo: Step Execution with JS Interpreter + + + + + + + + +

Blockly > + Demos > Step Execution with JS Interpreter

+ +

This is a demo of executing code step-by-step with a sandboxed JavaScript interpreter.

+ +

The generator's Blockly.JavaScript.STATEMENT_PREFIX is assigned 'highlightBlock(%1);\n', + where %1 is the block id. The call to highlightBlock() will highlight the identified block + and set the variable highlightPause to true.

+ +

"Parse JavaScript" will generate the code and load it into the interpreter. Then, each press of the + "Step JavaScript" button will run the interpreter one step until the highlightPause is true. + That is, until highlightBlock() has highlighted the block that will be executed on the next step.

+ +

More info on running code with JS Interpreter

+ +

+ +

+ +
+
+ +
+ + + + + + + + diff --git a/demos/interpreter/wait_block.js b/demos/interpreter/wait_block.js new file mode 100644 index 000000000..f64d84047 --- /dev/null +++ b/demos/interpreter/wait_block.js @@ -0,0 +1,67 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Example "wait" block that will pause the interpreter for a + * number of seconds. Because wait is a blocking behavior, such blocks will + * only work in interpreted environments. + * + * See https://neil.fraser.name/software/JS-Interpreter/docs.html + */ +Blockly.defineBlocksWithJsonArray([{ + "type": "wait_seconds", + "message0": " wait %1 seconds", + "args0": [{ + "type": "field_number", + "name": "SECONDS", + "min": 0, + "max": 600, + "value": 1 + }], + "previousStatement": null, + "nextStatement": null, + "colour": "%{BKY_LOOPS_HUE}" +}]); + +/** + * Generator for wait block creates call to new method + * waitForSeconds(). + */ +Blockly.JavaScript['wait_seconds'] = function(block) { + var seconds = Number(block.getFieldValue('SECONDS')); + var code = 'waitForSeconds(' + seconds + ');\n'; + return code; +}; + +/** + * Register the interpreter asynchronous function + * waitForSeconds(). + */ +function initInterpreterWaitForSeconds(interpreter, scope) { + // Ensure function name does not conflict with variable names. + Blockly.JavaScript.addReservedWords('waitForSeconds'); + + var wrapper = interpreter.createAsyncFunction( + function(timeInSeconds, callback) { + // Delay the call to the callback. + setTimeout(callback, timeInSeconds * 1000); + }); + interpreter.setProperty(scope, 'waitForSeconds', wrapper); +} \ No newline at end of file diff --git a/demos/mirror/index.html b/demos/mirror/index.html index b14f50c35..0098e92df 100644 --- a/demos/mirror/index.html +++ b/demos/mirror/index.html @@ -56,7 +56,7 @@ {media: '../../media/', toolbox: document.getElementById('toolbox')}); // Inject secondary workspace. - var seconaryWorkspace = Blockly.inject('secondaryDiv', + var secondaryWorkspace = Blockly.inject('secondaryDiv', {media: '../../media/', readOnly: true}); // Listen to events on primary workspace. @@ -70,7 +70,7 @@ var json = primaryEvent.toJson(); console.log(json); // Convert JSON back into an event, then execute it. - var secondaryEvent = Blockly.Events.fromJson(json, seconaryWorkspace); + var secondaryEvent = Blockly.Events.fromJson(json, secondaryWorkspace); secondaryEvent.run(true); } diff --git a/demos/prettify.css b/demos/prettify.css deleted file mode 100644 index d44b3a228..000000000 --- a/demos/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.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} \ No newline at end of file diff --git a/demos/prettify.js b/demos/prettify.js deleted file mode 100644 index 7b990496d..000000000 --- a/demos/prettify.js +++ /dev/null @@ -1,30 +0,0 @@ -!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(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= -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])*(?:`|$))/, -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", -/^#[^\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"+ -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]?/, -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= -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"], -"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"], -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"], -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/, -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-", -/^]*>([\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",/^[/<->]+/], -["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}), -["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, -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"]); -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}); -return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;ic&&(a=a+" - "+-c,g=Blockly.JavaScript.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,g=Blockly.JavaScript.ORDER_UNARY_NEGATION);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.JavaScript.lists={};Blockly.JavaScript.lists_create_empty=function(a){return["[]",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c b.toString() ? 1 : -1; },", ' "IGNORE_CASE": function(a, b) {'," return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; },"," };"," var compare = compareFuncs[type];"," return function(a, b) { return compare(a, b) * direction; }","}"]);return[b+".slice().sort("+d+'("'+a+'", '+c+"))",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.lists_split=function(a){var b=Blockly.JavaScript.valueToCode(a,"INPUT",Blockly.JavaScript.ORDER_MEMBER),c=Blockly.JavaScript.valueToCode(a,"DELIM",Blockly.JavaScript.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="split";else if("JOIN"==a)b||(b="[]"),a="join";else throw"Unknown mode: "+a;return[b+"."+a+"("+c+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.lists_reverse=function(a){return[(Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_FUNCTION_CALL)||"[]")+".slice().reverse()",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math={};Blockly.JavaScript.math_number=function(a){return[parseFloat(a.getFieldValue("NUM")),Blockly.JavaScript.ORDER_ATOMIC]}; -Blockly.JavaScript.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.JavaScript.ORDER_ADDITION],MINUS:[" - ",Blockly.JavaScript.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.JavaScript.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.JavaScript.ORDER_DIVISION],POWER:[null,Blockly.JavaScript.ORDER_COMMA]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.JavaScript.valueToCode(a,"A",b)||"0";a=Blockly.JavaScript.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:["Math.pow("+d+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; +Blockly.JavaScript.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.JavaScript.ORDER_ADDITION],MINUS:[" - ",Blockly.JavaScript.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.JavaScript.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.JavaScript.ORDER_DIVISION],POWER:[null,Blockly.JavaScript.ORDER_COMMA]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.JavaScript.valueToCode(a,"A",b)||"0";a=Blockly.JavaScript.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:["Math.pow("+d+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.JavaScript.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_DIVISION)||"0":Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_NONE)||"0";switch(b){case "ABS":var c="Math.abs("+a+")";break;case "ROOT":c="Math.sqrt("+ a+")";break;case "LN":c="Math.log("+a+")";break;case "EXP":c="Math.exp("+a+")";break;case "POW10":c="Math.pow(10,"+a+")";break;case "ROUND":c="Math.round("+a+")";break;case "ROUNDUP":c="Math.ceil("+a+")";break;case "ROUNDDOWN":c="Math.floor("+a+")";break;case "SIN":c="Math.sin("+a+" / 180 * Math.PI)";break;case "COS":c="Math.cos("+a+" / 180 * Math.PI)";break;case "TAN":c="Math.tan("+a+" / 180 * Math.PI)"}if(c)return[c,Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="Math.log("+a+ ") / Math.log(10)";break;case "ASIN":c="Math.asin("+a+") / Math.PI * 180";break;case "ACOS":c="Math.acos("+a+") / Math.PI * 180";break;case "ATAN":c="Math.atan("+a+") / Math.PI * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.JavaScript.ORDER_DIVISION]}; @@ -64,30 +64,29 @@ Blockly.JavaScript.procedures_callreturn=function(a){for(var b=Blockly.JavaScrip Blockly.JavaScript.procedures_callnoreturn=function(a){for(var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=[],d=0;d= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.JavaScript.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.JavaScript.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE), a+="var "+c+" = "+d+";\n"),d=Blockly.JavaScript.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE),a+="var "+d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("Math.abs("+e+");\n"),a=a+("if ("+g+" > "+c+") {\n")+(Blockly.JavaScript.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+f+"}\n";return a}; -Blockly.JavaScript.controls_forEach=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_ASSIGNMENT)||"[]",d=Blockly.JavaScript.statementToCode(a,"DO"),d=Blockly.JavaScript.addLoopTrap(d,a.id);a="";var e=c;c.match(/^\w+$/)||(e=Blockly.JavaScript.variableDB_.getDistinctName(b+"_list",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+c+";\n");c=Blockly.JavaScript.variableDB_.getDistinctName(b+ +Blockly.JavaScript.controls_forEach=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_ASSIGNMENT)||"[]",d=Blockly.JavaScript.statementToCode(a,"DO");d=Blockly.JavaScript.addLoopTrap(d,a.id);a="";var e=c;c.match(/^\w+$/)||(e=Blockly.JavaScript.variableDB_.getDistinctName(b+"_list",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+c+";\n");c=Blockly.JavaScript.variableDB_.getDistinctName(b+ "_index",Blockly.Variables.NAME_TYPE);d=Blockly.JavaScript.INDENT+b+" = "+e+"["+c+"];\n"+d;return a+("for (var "+c+" in "+e+") {\n"+d+"}\n")};Blockly.JavaScript.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw"Unknown flow statement.";};Blockly.JavaScript.logic={};Blockly.JavaScript.controls_if=function(a){var b=0,c="";do{var d=Blockly.JavaScript.valueToCode(a,"IF"+b,Blockly.JavaScript.ORDER_NONE)||"false";var e=Blockly.JavaScript.statementToCode(a,"DO"+b);c+=(0",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.JavaScript.ORDER_EQUALITY:Blockly.JavaScript.ORDER_RELATIONAL,d=Blockly.JavaScript.valueToCode(a,"A",c)||"0";a=Blockly.JavaScript.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.JavaScript.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.JavaScript.ORDER_LOGICAL_AND:Blockly.JavaScript.ORDER_LOGICAL_OR,d=Blockly.JavaScript.valueToCode(a,"A",c);a=Blockly.JavaScript.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]}; diff --git a/lua_compressed.js b/lua_compressed.js index 395ce8777..cc9da831e 100644 --- a/lua_compressed.js +++ b/lua_compressed.js @@ -16,8 +16,8 @@ Blockly.Lua.lists_indexOf=function(a){var b=Blockly.Lua.valueToCode(a,"FIND",Blo Blockly.Lua.lists_getIndex=function(a){var b=a.getFieldValue("MODE")||"GET";var c=a.getFieldValue("WHERE")||"FROM_START";var d=Blockly.Lua.valueToCode(a,"VALUE",Blockly.Lua.ORDER_HIGH)||"{}",e=Blockly.Lua.lists.getIndex_;if("LAST"!=c&&"FROM_END"!=c&&"RANDOM"!=c||d.match(/^\w+$/)){var f="GET"==b&&"FROM_END"==c?Blockly.Lua.ORDER_ADDITIVE:Blockly.Lua.ORDER_NONE;a=Blockly.Lua.valueToCode(a,"AT",f)||"1";a=e(d,c,a);if("GET"==b)return[d+"["+a+"]",Blockly.Lua.ORDER_HIGH];c="table.remove("+d+", "+a+")";return"GET_REMOVE"== b?[c,Blockly.Lua.ORDER_HIGH]:c+"\n"}if("REMOVE"==b)return f="FROM_END"==c?Blockly.Lua.ORDER_ADDITIVE:Blockly.Lua.ORDER_NONE,a=Blockly.Lua.valueToCode(a,"AT",f)||"1",b=Blockly.Lua.variableDB_.getDistinctName("tmp_list",Blockly.Variables.NAME_TYPE),a=e(b,c,a),b+" = "+d+"\ntable.remove("+b+", "+a+")\n";a=Blockly.Lua.valueToCode(a,"AT",Blockly.Lua.ORDER_NONE)||"1";return[("GET"==b?Blockly.Lua.provideFunction_("list_get_"+c.toLowerCase(),["function "+Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_+"(t"+("FROM_END"== c||"FROM_START"==c?", at)":")")," return t["+e("t",c,"at")+"]","end"]):Blockly.Lua.provideFunction_("list_remove_"+c.toLowerCase(),["function "+Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_+"(t"+("FROM_END"==c||"FROM_START"==c?", at)":")")," return table.remove(t, "+e("t",c,"at")+")","end"]))+"("+d+("FROM_END"==c||"FROM_START"==c?", "+a:"")+")",Blockly.Lua.ORDER_HIGH]}; -Blockly.Lua.lists_setIndex=function(a){var b=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_HIGH)||"{}",c=a.getFieldValue("MODE")||"SET",d=a.getFieldValue("WHERE")||"FROM_START",e=Blockly.Lua.valueToCode(a,"AT",Blockly.Lua.ORDER_ADDITIVE)||"1";a=Blockly.Lua.valueToCode(a,"TO",Blockly.Lua.ORDER_NONE)||"None";var f=Blockly.Lua.lists.getIndex_,g="";if(("LAST"==d||"FROM_END"==d||"RANDOM"==d)&&!b.match(/^\w+$/))var h=Blockly.Lua.variableDB_.getDistinctName("tmp_list",Blockly.Variables.NAME_TYPE),g= -h+" = "+b+"\n",b=h;g="SET"==c?g+(b+"["+f(b,d,e)+"] = "+a):g+("table.insert("+b+", "+(f(b,d,e)+("LAST"==d?" + 1":""))+", "+a+")");return g+"\n"}; +Blockly.Lua.lists_setIndex=function(a){var b=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_HIGH)||"{}",c=a.getFieldValue("MODE")||"SET",d=a.getFieldValue("WHERE")||"FROM_START",e=Blockly.Lua.valueToCode(a,"AT",Blockly.Lua.ORDER_ADDITIVE)||"1";a=Blockly.Lua.valueToCode(a,"TO",Blockly.Lua.ORDER_NONE)||"None";var f=Blockly.Lua.lists.getIndex_,g="";if(("LAST"==d||"FROM_END"==d||"RANDOM"==d)&&!b.match(/^\w+$/)){var h=Blockly.Lua.variableDB_.getDistinctName("tmp_list",Blockly.Variables.NAME_TYPE); +g=h+" = "+b+"\n";b=h}g="SET"==c?g+(b+"["+f(b,d,e)+"] = "+a):g+("table.insert("+b+", "+(f(b,d,e)+("LAST"==d?" + 1":""))+", "+a+")");return g+"\n"}; Blockly.Lua.lists_getSublist=function(a){var b=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_NONE)||"{}",c=a.getFieldValue("WHERE1"),d=a.getFieldValue("WHERE2"),e=Blockly.Lua.valueToCode(a,"AT1",Blockly.Lua.ORDER_NONE)||"1";a=Blockly.Lua.valueToCode(a,"AT2",Blockly.Lua.ORDER_NONE)||"1";var f=Blockly.Lua.lists.getIndex_;return[Blockly.Lua.provideFunction_("list_sublist_"+c.toLowerCase()+"_"+d.toLowerCase(),["function "+Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_+"(source"+("FROM_END"==c||"FROM_START"== c?", at1":"")+("FROM_END"==d||"FROM_START"==d?", at2":"")+")"," local t = {}"," local start = "+f("source",c,"at1")," local finish = "+f("source",d,"at2")," for i = start, finish do"," table.insert(t, source[i])"," end"," return t","end"])+"("+b+("FROM_END"==c||"FROM_START"==c?", "+e:"")+("FROM_END"==d||"FROM_START"==d?", "+a:"")+")",Blockly.Lua.ORDER_HIGH]}; Blockly.Lua.lists_sort=function(a){var b=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_NONE)||"{}",c="1"===a.getFieldValue("DIRECTION")?1:-1;a=a.getFieldValue("TYPE");return[Blockly.Lua.provideFunction_("list_sort",["function "+Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_+"(list, typev, direction)"," local t = {}"," for n,v in pairs(list) do table.insert(t, v) end"," local compareFuncs = {"," NUMERIC = function(a, b)"," return (tonumber(tostring(a)) or 0)"," < (tonumber(tostring(b)) or 0) end,", @@ -25,7 +25,7 @@ Blockly.Lua.lists_sort=function(a){var b=Blockly.Lua.valueToCode(a,"LIST",Blockl Blockly.Lua.lists_split=function(a){var b=Blockly.Lua.valueToCode(a,"INPUT",Blockly.Lua.ORDER_NONE),c=Blockly.Lua.valueToCode(a,"DELIM",Blockly.Lua.ORDER_NONE)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a=Blockly.Lua.provideFunction_("list_string_split",["function "+Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_+"(input, delim)"," local t = {}"," local pos = 1"," while true do"," next_delim = string.find(input, delim, pos)"," if next_delim == nil then"," table.insert(t, string.sub(input, pos))", " break"," else"," table.insert(t, string.sub(input, pos, next_delim-1))"," pos = next_delim + #delim"," end"," end"," return t","end"]);else if("JOIN"==a)b||(b="{}"),a="table.concat";else throw"Unknown mode: "+a;return[a+"("+b+", "+c+")",Blockly.Lua.ORDER_HIGH]}; Blockly.Lua.lists_reverse=function(a){a=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_NONE)||"{}";Blockly.Lua.provideFunction_("list_reverse",["function "+Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_+"(input)"," local reversed = {}"," for i = #input, 1, -1 do"," table.insert(reversed, input[i])"," end"," return reversed","end"]);return["list_reverse("+a+")",Blockly.Lua.ORDER_HIGH]};Blockly.Lua.math={};Blockly.Lua.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));return[a,0>a?Blockly.Lua.ORDER_UNARY:Blockly.Lua.ORDER_ATOMIC]}; -Blockly.Lua.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Lua.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Lua.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Lua.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Lua.ORDER_MULTIPLICATIVE],POWER:[" ^ ",Blockly.Lua.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.Lua.valueToCode(a,"A",b)||"0";a=Blockly.Lua.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; +Blockly.Lua.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Lua.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Lua.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Lua.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Lua.ORDER_MULTIPLICATIVE],POWER:[" ^ ",Blockly.Lua.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.Lua.valueToCode(a,"A",b)||"0";a=Blockly.Lua.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.Lua.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_UNARY)||"0",["-"+a,Blockly.Lua.ORDER_UNARY];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_MULTIPLICATIVE)||"0":Blockly.Lua.valueToCode(a,"NUM",Blockly.Lua.ORDER_NONE)||"0";switch(b){case "ABS":b="math.abs("+a+")";break;case "ROOT":b="math.sqrt("+a+")";break;case "LN":b="math.log("+a+")";break;case "LOG10":b="math.log10("+a+")";break; case "EXP":b="math.exp("+a+")";break;case "POW10":b="math.pow(10,"+a+")";break;case "ROUND":b="math.floor("+a+" + .5)";break;case "ROUNDUP":b="math.ceil("+a+")";break;case "ROUNDDOWN":b="math.floor("+a+")";break;case "SIN":b="math.sin(math.rad("+a+"))";break;case "COS":b="math.cos(math.rad("+a+"))";break;case "TAN":b="math.tan(math.rad("+a+"))";break;case "ASIN":b="math.deg(math.asin("+a+"))";break;case "ACOS":b="math.deg(math.acos("+a+"))";break;case "ATAN":b="math.deg(math.atan("+a+"))";break;default:throw"Unknown math operator: "+ b;}return[b,Blockly.Lua.ORDER_HIGH]};Blockly.Lua.math_constant=function(a){return{PI:["math.pi",Blockly.Lua.ORDER_HIGH],E:["math.exp(1)",Blockly.Lua.ORDER_HIGH],GOLDEN_RATIO:["(1 + math.sqrt(5)) / 2",Blockly.Lua.ORDER_MULTIPLICATIVE],SQRT2:["math.sqrt(2)",Blockly.Lua.ORDER_HIGH],SQRT1_2:["math.sqrt(1 / 2)",Blockly.Lua.ORDER_HIGH],INFINITY:["math.huge",Blockly.Lua.ORDER_HIGH]}[a.getFieldValue("CONSTANT")]}; @@ -51,7 +51,7 @@ c||(c="");for(var e=[],f=0;f ("+d+") then\n")+(Blockly.Lua.INDENT+g+" = -"+g+"\n"),a+="end\n";return a+("for "+b+" = "+c+", "+d+", "+g)+(" do\n"+f+"end\n")}; Blockly.Lua.controls_forEach=function(a){var b=Blockly.Lua.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Lua.valueToCode(a,"LIST",Blockly.Lua.ORDER_NONE)||"{}";a=Blockly.Lua.statementToCode(a,"DO")||"\n";a=Blockly.Lua.addContinueLabel(a);return"for _, "+b+" in ipairs("+c+") do \n"+a+"end\n"}; Blockly.Lua.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break\n";case "CONTINUE":return Blockly.Lua.CONTINUE_STATEMENT}throw"Unknown flow statement.";};Blockly.Lua.logic={};Blockly.Lua.controls_if=function(a){var b=0,c="";do{var d=Blockly.Lua.valueToCode(a,"IF"+b,Blockly.Lua.ORDER_NONE)||"false";var e=Blockly.Lua.statementToCode(a,"DO"+b);c+=(0", - "lastupdated": "2017-05-03 12:38:29.522161", + "lastupdated": "2017-06-23 16:08:16.779777", "locale": "en", "messagedocumentation" : "qqq" }, @@ -31,6 +31,7 @@ "NEW_VARIABLE": "Create variable...", "NEW_VARIABLE_TITLE": "New variable name:", "VARIABLE_ALREADY_EXISTS": "A variable named '%1' already exists.", + "PROCEDURE_ALREADY_EXISTS": "A procedure named '%1' already exists.", "DELETE_VARIABLE_CONFIRMATION": "Delete %1 uses of the '%2' variable?", "CANNOT_DELETE_VARIABLE_PROCEDURE": "Can't delete the variable '%1' because it's part of the definition of the function '%2'", "DELETE_VARIABLE": "Delete the '%1' variable", @@ -215,8 +216,7 @@ "TEXT_CREATE_JOIN_TOOLTIP": "Add, remove, or reorder sections to reconfigure this text block.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Add an item to the text.", "TEXT_APPEND_HELPURL": "https://github.com/google/blockly/wiki/Text#text-modification", - "TEXT_APPEND_TO": "to", - "TEXT_APPEND_APPENDTEXT": "append text", + "TEXT_APPEND_TITLE": "to %1 append text %2", "TEXT_APPEND_TOOLTIP": "Append some text to variable '%1'.", "TEXT_LENGTH_HELPURL": "https://github.com/google/blockly/wiki/Text#text-modification", "TEXT_LENGTH_TITLE": "length of %1", @@ -226,12 +226,11 @@ "TEXT_ISEMPTY_TOOLTIP": "Returns true if the provided text is empty.", "TEXT_INDEXOF_HELPURL": "https://github.com/google/blockly/wiki/Text#finding-text", "TEXT_INDEXOF_TOOLTIP": "Returns the index of the first/last occurrence of the first text in the second text. Returns %1 if text is not found.", - "TEXT_INDEXOF_INPUT_INTEXT": "in text", + "TEXT_INDEXOF_TITLE": "in text %1 %2 %3", "TEXT_INDEXOF_OPERATOR_FIRST": "find first occurrence of text", "TEXT_INDEXOF_OPERATOR_LAST": "find last occurrence of text", - "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://github.com/google/blockly/wiki/Text#extracting-text", - "TEXT_CHARAT_INPUT_INTEXT": "in text", + "TEXT_CHARAT_TITLE": "in text %1 %2", "TEXT_CHARAT_FROM_START": "get letter #", "TEXT_CHARAT_FROM_END": "get letter # from end", "TEXT_CHARAT_FIRST": "get first letter", diff --git a/msg/messages.js b/msg/messages.js index 627292a38..f666fd192 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -125,6 +125,8 @@ Blockly.Msg.NEW_VARIABLE = 'Create variable...'; Blockly.Msg.NEW_VARIABLE_TITLE = 'New variable name:'; /// alert - Tells the user that the name they entered is already in use. Blockly.Msg.VARIABLE_ALREADY_EXISTS = 'A variable named "%1" already exists.' +/// alert - Tells the user that the name they entered is already in use for a procedure. +Blockly.Msg.PROCEDURE_ALREADY_EXISTS = 'A procedure named "%1" already exists.' // Variable deletion. /// confirm - Ask the user to confirm their deletion of multiple uses of a variable. @@ -256,13 +258,13 @@ Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE = Blockly.Msg.CONTROLS_IF_MSG_ELSE; /// tooltip - Describes the 'else' subblock during [https://github.com/google/blockly/wiki/IfElse#block-modification if block modification]. Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP = 'Add a final, catch-all condition to the if block.'; -/// button text - Text on a button inside a dialogue window, which will accept or acknowledge the contents of the dialogue when pressed. +/// button text - Text on a button inside a dialogue window, which will accept or acknowledge the contents of the dialogue when pressed.\n{{Identical|OK}} Blockly.Msg.IOS_OK = 'OK'; -/// button text - Text on a button inside a dialogue window, which will close or cancel the dialogue when pressed. +/// button text - Text on a button inside a dialogue window, which will close or cancel the dialogue when pressed.\n{{Identical|Cancel}} Blockly.Msg.IOS_CANCEL = 'Cancel'; -/// alert - Title text for an error dialogue. +/// alert - Title text for an error dialogue.\n{{Identical|Error}} Blockly.Msg.IOS_ERROR = 'Error'; -/// header text - Title of a section that displays a list of parameters (aka. "inputs") that have been defined for a procedure. This is used inside a dialogue window to configure a procedure. +/// header text - Title of a section that displays a list of parameters (aka. "inputs") that have been defined for a procedure. This is used inside a dialogue window to configure a procedure.\n{{Identical|Input}} Blockly.Msg.IOS_PROCEDURES_INPUTS = 'INPUTS'; /// button text - Text on a button which will add a parameter (aka. "input") to a procedure. This is used inside a dialogue window to configure a procedure. NOTE: The "+" should be preserved at the beginning of the text. Blockly.Msg.IOS_PROCEDURES_ADD_INPUT = '+ Add Input'; @@ -272,11 +274,11 @@ Blockly.Msg.IOS_PROCEDURES_ALLOW_STATEMENTS = 'Allow statements'; Blockly.Msg.IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR = 'This function has duplicate inputs.'; /// button text - Text on a button which will open a variable creation dialogue when pressed. NOTE: The "+" should be preserved at the beginning of the text. Blockly.Msg.IOS_VARIABLES_ADD_VARIABLE = '+ Add Variable'; -/// button text - Text on a button inside a variable creation dialogue, which will add a variable when pressed. +/// button text - Text on a button inside a variable creation dialogue, which will add a variable when pressed.\n{{Identical|Add}} Blockly.Msg.IOS_VARIABLES_ADD_BUTTON = 'Add'; -/// button text - Text on a button inside a variable rename dialogue, which will rename a variable when pressed. +/// button text - Text on a button inside a variable rename dialogue, which will rename a variable when pressed.\n{{Identical|Rename}} Blockly.Msg.IOS_VARIABLES_RENAME_BUTTON = 'Rename'; -/// button text - Text on a button inside a variable deletion dialogue, which will delete a variable when pressed. +/// button text - Text on a button inside a variable deletion dialogue, which will delete a variable when pressed.\n{{Identical|Delete}} Blockly.Msg.IOS_VARIABLES_DELETE_BUTTON = 'Delete'; /// placeholder text - Placeholder text used inside a text input, where a variable name should be entered. Blockly.Msg.IOS_VARIABLES_VARIABLE_NAME = 'Variable name'; @@ -566,13 +568,9 @@ Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TOOLTIP = 'Add an item to the text.'; /// url - This and the other text-related URLs are going to be hard to translate. As always, it is okay to leave untranslated or paste in the English-language URL. For these URLs, you might also consider a general URL about how computers represent text (such as the translation of [https://en.wikipedia.org/wiki/String_(computer_science) this Wikipedia page]). Blockly.Msg.TEXT_APPEND_HELPURL = 'https://github.com/google/blockly/wiki/Text#text-modification'; -/// block input text - Message preceding the name of a variable to which text should be appended. +/// block input text - Message that the variable name at %1 will have the item at %2 appended to it. /// [[File:blockly-append-text.png]] -Blockly.Msg.TEXT_APPEND_TO = 'to'; -/// block input text - Message following the variable and preceding the piece of text that should -/// be appended, as shown below. -/// [[File:blockly-append-text.png]] -Blockly.Msg.TEXT_APPEND_APPENDTEXT = 'append text'; +Blockly.Msg.TEXT_APPEND_TITLE = 'to %1 append text %2'; Blockly.Msg.TEXT_APPEND_VARIABLE = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// tooltip - See [https://github.com/google/blockly/wiki/Text#text-modification https://github.com/google/blockly/wiki/Text#text-modification] for more information.\n\nParameters:\n* %1 - the name of the variable to which text should be appended Blockly.Msg.TEXT_APPEND_TOOLTIP = 'Append some text to variable "%1".'; @@ -601,7 +599,10 @@ Blockly.Msg.TEXT_INDEXOF_TOOLTIP = 'Returns the index of the first/last occurren /// [https://github.com/google/blockly/wiki/Text#finding-text /// https://github.com/google/blockly/wiki/Text#finding-text]. /// [[File:Blockly-find-text.png]]. -Blockly.Msg.TEXT_INDEXOF_INPUT_INTEXT = 'in text'; +/// In English the expanded message is "in text %1 find (first|last) occurance of text %3" +/// where %1 and %3 are added by the user. See TEXT_INDEXOF_OPERATOR_FIRST and +/// TEXT_INDEXOF_OPERATOR_LAST for the dropdown text that replaces %2. +Blockly.Msg.TEXT_INDEXOF_TITLE = 'in text %1 %2 %3'; /// dropdown - See [https://github.com/google/blockly/wiki/Text#finding-text /// https://github.com/google/blockly/wiki/Text#finding-text]. /// [[File:Blockly-find-text.png]]. @@ -614,21 +615,17 @@ Blockly.Msg.TEXT_INDEXOF_OPERATOR_FIRST = 'find first occurrence of text'; /// https://translatewiki.net/wiki/Translating:Blockly#Drop-Down_Menus)].) /// [[File:Blockly-find-text.png]]. Blockly.Msg.TEXT_INDEXOF_OPERATOR_LAST = 'find last occurrence of text'; -/// block text - Optional text to follow the rightmost block in a -/// [https://github.com/google/blockly/wiki/Text#finding-text -/// https://github.com/google/blockly/wiki/Text#finding-text in text ... find block] -/// (after the "a" in the below picture). This will be the empty string in most languages. -/// [[File:Blockly-find-text.png]]. -Blockly.Msg.TEXT_INDEXOF_TAIL = ''; /// url - Information about extracting characters (letters, number, symbols, etc.) from text. Blockly.Msg.TEXT_CHARAT_HELPURL = 'https://github.com/google/blockly/wiki/Text#extracting-text'; -/// block text - Appears before the piece of text from which a letter (or number, -/// punctuation character, etc.) should be extracted, as shown below. See +/// block text - Text for a block to extract a letter (or number, +/// punctuation character, etc.) from a string, as shown below. %1 is added by +/// the user and %2 is replaced by a dropdown of options, possibly followed by +/// another user supplied string. TEXT_CHARAT_TAIL is then added to the end. See /// [https://github.com/google/blockly/wiki/Text#extracting-a-single-character /// https://github.com/google/blockly/wiki/Text#extracting-a-single-character]. /// [[File:Blockly-text-get.png]] -Blockly.Msg.TEXT_CHARAT_INPUT_INTEXT = 'in text'; +Blockly.Msg.TEXT_CHARAT_TITLE = 'in text %1 %2' /// dropdown - Indicates that the letter (or number, punctuation character, etc.) with the /// specified index should be obtained from the preceding piece of text. See /// [https://github.com/google/blockly/wiki/Text#extracting-a-single-character @@ -1159,7 +1156,7 @@ Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = 'Run the user-defined function "%1" /// block text - This text appears on a block in a window that appears when the user clicks /// on the plus sign or star on a function definition block. It refers to the set of parameters /// (referred to by the simpler term "inputs") to the function. See -/// [[Translating:Blockly#function_definitions]]. +/// [[Translating:Blockly#function_definitions]].\n{{Identical|Input}} Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE = 'inputs'; /// tooltip Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP = 'Add, remove, or reorder inputs to this function.'; diff --git a/php_compressed.js b/php_compressed.js index 75158b1cd..ab462f14b 100644 --- a/php_compressed.js +++ b/php_compressed.js @@ -8,12 +8,12 @@ Blockly.PHP.ORDER_ATOMIC=0;Blockly.PHP.ORDER_CLONE=1;Blockly.PHP.ORDER_NEW=1;Blo Blockly.PHP.ORDER_DIVISION=8.2;Blockly.PHP.ORDER_MODULUS=8.3;Blockly.PHP.ORDER_ADDITION=9.1;Blockly.PHP.ORDER_SUBTRACTION=9.2;Blockly.PHP.ORDER_STRING_CONCAT=9.3;Blockly.PHP.ORDER_BITWISE_SHIFT=10;Blockly.PHP.ORDER_RELATIONAL=11;Blockly.PHP.ORDER_EQUALITY=12;Blockly.PHP.ORDER_REFERENCE=13;Blockly.PHP.ORDER_BITWISE_AND=13;Blockly.PHP.ORDER_BITWISE_XOR=14;Blockly.PHP.ORDER_BITWISE_OR=15;Blockly.PHP.ORDER_LOGICAL_AND=16;Blockly.PHP.ORDER_LOGICAL_OR=17;Blockly.PHP.ORDER_IF_NULL=18; Blockly.PHP.ORDER_CONDITIONAL=19;Blockly.PHP.ORDER_ASSIGNMENT=20;Blockly.PHP.ORDER_LOGICAL_AND_WEAK=21;Blockly.PHP.ORDER_LOGICAL_XOR=22;Blockly.PHP.ORDER_LOGICAL_OR_WEAK=23;Blockly.PHP.ORDER_COMMA=24;Blockly.PHP.ORDER_NONE=99; Blockly.PHP.ORDER_OVERRIDES=[[Blockly.PHP.ORDER_MEMBER,Blockly.PHP.ORDER_FUNCTION_CALL],[Blockly.PHP.ORDER_MEMBER,Blockly.PHP.ORDER_MEMBER],[Blockly.PHP.ORDER_LOGICAL_NOT,Blockly.PHP.ORDER_LOGICAL_NOT],[Blockly.PHP.ORDER_MULTIPLICATION,Blockly.PHP.ORDER_MULTIPLICATION],[Blockly.PHP.ORDER_ADDITION,Blockly.PHP.ORDER_ADDITION],[Blockly.PHP.ORDER_LOGICAL_AND,Blockly.PHP.ORDER_LOGICAL_AND],[Blockly.PHP.ORDER_LOGICAL_OR,Blockly.PHP.ORDER_LOGICAL_OR]]; -Blockly.PHP.init=function(a){Blockly.PHP.definitions_=Object.create(null);Blockly.PHP.functionNames_=Object.create(null);Blockly.PHP.variableDB_?Blockly.PHP.variableDB_.reset():Blockly.PHP.variableDB_=new Blockly.Names(Blockly.PHP.RESERVED_WORDS_,"$");var b=[];a=Blockly.Variables.allVariables(a);for(var c=0;cc?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_SUBTRACTION)||f:d?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_UNARY_NEGATION)||f:Blockly.PHP.valueToCode(a,b,e)||f;if(Blockly.isNumber(a))a=parseFloat(a)+c,d&&(a=-a);else{if(0c&& -(a=a+" - "+-c,g=Blockly.PHP.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,g=Blockly.PHP.ORDER_UNARY_NEGATION);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.PHP.lists={};Blockly.PHP.lists_create_empty=function(a){return["array()",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;cc?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_SUBTRACTION)||g:d?Blockly.PHP.valueToCode(a,b,Blockly.PHP.ORDER_UNARY_NEGATION)||g:Blockly.PHP.valueToCode(a,b,e)||g;if(Blockly.isNumber(a))a=parseFloat(a)+c,d&&(a=-a);else{if(0c&& +(a=a+" - "+-c,f=Blockly.PHP.ORDER_SUBTRACTION);d&&(a=c?"-("+a+")":"-"+a,f=Blockly.PHP.ORDER_UNARY_NEGATION);f=Math.floor(f);e=Math.floor(e);f&&e>=f&&(a="("+a+")")}return a};Blockly.PHP.lists={};Blockly.PHP.lists_create_empty=function(a){return["array()",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c "strnatcasecmp",',' "TEXT" => "strcmp",',' "IGNORE_CASE" => "strcasecmp"'," );"," $sortCmp = $sortCmpFuncs[$type];"," $list2 = $list;"," usort($list2, $sortCmp);", " if ($direction == -1) {"," $list2 = array_reverse($list2);"," }"," return $list2;","}"])+"("+b+', "'+a+'", '+c+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.lists_split=function(a){var b=Blockly.PHP.valueToCode(a,"INPUT",Blockly.PHP.ORDER_COMMA),c=Blockly.PHP.valueToCode(a,"DELIM",Blockly.PHP.ORDER_COMMA)||"''";a=a.getFieldValue("MODE");if("SPLIT"==a)b||(b="''"),a="explode";else if("JOIN"==a)b||(b="array()"),a="implode";else throw"Unknown mode: "+a;return[a+"("+c+", "+b+")",Blockly.PHP.ORDER_FUNCTION_CALL]}; Blockly.PHP.lists_reverse=function(a){return["array_reverse("+(Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_COMMA)||"[]")+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.math={};Blockly.PHP.math_number=function(a){a=parseFloat(a.getFieldValue("NUM"));Infinity==a?a="INF":-Infinity==a&&(a="-INF");return[a,Blockly.PHP.ORDER_ATOMIC]}; -Blockly.PHP.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.PHP.ORDER_ADDITION],MINUS:[" - ",Blockly.PHP.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.PHP.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.PHP.ORDER_DIVISION],POWER:[" ** ",Blockly.PHP.ORDER_POWER]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.PHP.valueToCode(a,"A",b)||"0";a=Blockly.PHP.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; +Blockly.PHP.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.PHP.ORDER_ADDITION],MINUS:[" - ",Blockly.PHP.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.PHP.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.PHP.ORDER_DIVISION],POWER:[" ** ",Blockly.PHP.ORDER_POWER]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.PHP.valueToCode(a,"A",b)||"0";a=Blockly.PHP.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.PHP.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b)return a=Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.PHP.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_DIVISION)||"0":Blockly.PHP.valueToCode(a,"NUM",Blockly.PHP.ORDER_NONE)||"0";switch(b){case "ABS":var c="abs("+a+")";break;case "ROOT":c="sqrt("+a+")";break;case "LN":c="log("+a+")";break;case "EXP":c="exp("+ a+")";break;case "POW10":c="pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="ceil("+a+")";break;case "ROUNDDOWN":c="floor("+a+")";break;case "SIN":c="sin("+a+" / 180 * pi())";break;case "COS":c="cos("+a+" / 180 * pi())";break;case "TAN":c="tan("+a+" / 180 * pi())"}if(c)return[c,Blockly.PHP.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="log("+a+") / log(10)";break;case "ASIN":c="asin("+a+") / pi() * 180";break;case "ACOS":c="acos("+a+") / pi() * 180";break;case "ATAN":c="atan("+ a+") / pi() * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.PHP.ORDER_DIVISION]};Blockly.PHP.math_constant=function(a){return{PI:["M_PI",Blockly.PHP.ORDER_ATOMIC],E:["M_E",Blockly.PHP.ORDER_ATOMIC],GOLDEN_RATIO:["(1 + sqrt(5)) / 2",Blockly.PHP.ORDER_DIVISION],SQRT2:["M_SQRT2",Blockly.PHP.ORDER_ATOMIC],SQRT1_2:["M_SQRT1_2",Blockly.PHP.ORDER_ATOMIC],INFINITY:["INF",Blockly.PHP.ORDER_ATOMIC]}[a.getFieldValue("CONSTANT")]}; @@ -56,31 +56,31 @@ Blockly.PHP.colour_rgb=function(a){var b=Blockly.PHP.valueToCode(a,"RED",Blockly " $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT);"," $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT);"," return $hex;","}"])+"("+b+", "+c+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]}; Blockly.PHP.colour_blend=function(a){var b=Blockly.PHP.valueToCode(a,"COLOUR1",Blockly.PHP.ORDER_COMMA)||"'#000000'",c=Blockly.PHP.valueToCode(a,"COLOUR2",Blockly.PHP.ORDER_COMMA)||"'#000000'";a=Blockly.PHP.valueToCode(a,"RATIO",Blockly.PHP.ORDER_COMMA)||.5;return[Blockly.PHP.provideFunction_("colour_blend",["function "+Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_+"($c1, $c2, $ratio) {"," $ratio = max(min($ratio, 1), 0);"," $r1 = hexdec(substr($c1, 1, 2));"," $g1 = hexdec(substr($c1, 3, 2));"," $b1 = hexdec(substr($c1, 5, 2));", " $r2 = hexdec(substr($c2, 1, 2));"," $g2 = hexdec(substr($c2, 3, 2));"," $b2 = hexdec(substr($c2, 5, 2));"," $r = round($r1 * (1 - $ratio) + $r2 * $ratio);"," $g = round($g1 * (1 - $ratio) + $g2 * $ratio);"," $b = round($b1 * (1 - $ratio) + $b2 * $ratio);"," $hex = '#';"," $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT);"," $hex .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT);"," $hex .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT);"," return $hex;","}"])+"("+b+", "+c+", "+a+")",Blockly.PHP.ORDER_FUNCTION_CALL]};Blockly.PHP.procedures={}; -Blockly.PHP.procedures_defreturn=function(a){for(var b=[],c=0,d;d=a.workspace.variableList[c];c++)-1==a.arguments_.indexOf(d)&&b.push(Blockly.PHP.variableDB_.getName(d,Blockly.Variables.NAME_TYPE));b=b.length?" global "+b.join(", ")+";\n":"";d=Blockly.PHP.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE);var e=Blockly.PHP.statementToCode(a,"STACK");Blockly.PHP.STATEMENT_PREFIX&&(e=Blockly.PHP.prefixLines(Blockly.PHP.STATEMENT_PREFIX.replace(/%1/g,"'"+a.id+"'"),Blockly.PHP.INDENT)+ -e);Blockly.PHP.INFINITE_LOOP_TRAP&&(e=Blockly.PHP.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+e);var f=Blockly.PHP.valueToCode(a,"RETURN",Blockly.PHP.ORDER_NONE)||"";f&&(f=" return "+f+";\n");for(var g=[],c=0;c= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.PHP.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+=g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.PHP.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE),a+=c+" = "+d+";\n"),d=Blockly.PHP.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE), -a+=d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("abs("+e+");\n"),a=a+("if ("+g+" > "+c+") {\n")+(Blockly.PHP.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+f+"}\n";return a}; -Blockly.PHP.controls_forEach=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_ASSIGNMENT)||"[]",d=Blockly.PHP.statementToCode(a,"DO"),d=Blockly.PHP.addLoopTrap(d,a.id);return""+("foreach ("+c+" as "+b+") {\n"+d+"}\n")}; +Blockly.PHP.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(Number(a.getFieldValue("TIMES"))):Blockly.PHP.valueToCode(a,"TIMES",Blockly.PHP.ORDER_ASSIGNMENT)||"0";var c=Blockly.PHP.statementToCode(a,"DO");c=Blockly.PHP.addLoopTrap(c,a.id);var d="",e=Blockly.PHP.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE);a=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(a=Blockly.PHP.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),d+=a+" = "+b+";\n");return d+ +("for ("+e+" = 0; "+e+" < "+a+"; "+e+"++) {\n"+c+"}\n")};Blockly.PHP.controls_repeat=Blockly.PHP.controls_repeat_ext;Blockly.PHP.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.PHP.valueToCode(a,"BOOL",b?Blockly.PHP.ORDER_LOGICAL_NOT:Blockly.PHP.ORDER_NONE)||"false",d=Blockly.PHP.statementToCode(a,"DO");d=Blockly.PHP.addLoopTrap(d,a.id);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; +Blockly.PHP.controls_for=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE);var c=Blockly.PHP.valueToCode(a,"FROM",Blockly.PHP.ORDER_ASSIGNMENT)||"0";var d=Blockly.PHP.valueToCode(a,"TO",Blockly.PHP.ORDER_ASSIGNMENT)||"0",e=Blockly.PHP.valueToCode(a,"BY",Blockly.PHP.ORDER_ASSIGNMENT)||"1",g=Blockly.PHP.statementToCode(a,"DO");g=Blockly.PHP.addLoopTrap(g,a.id);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var f=parseFloat(c)<=parseFloat(d); +a="for ("+b+" = "+c+"; "+b+(f?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(f?"++":"--"):a+((f?" += ":" -= ")+b))+(") {\n"+g+"}\n")}else a="",f=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(f=Blockly.PHP.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+=f+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.PHP.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE),a+=c+" = "+d+";\n"),d=Blockly.PHP.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE), +a+=d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("abs("+e+");\n"),a=a+("if ("+f+" > "+c+") {\n")+(Blockly.PHP.INDENT+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+f+"; "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+"; "+b+" += "+d+") {\n"+g+"}\n";return a}; +Blockly.PHP.controls_forEach=function(a){var b=Blockly.PHP.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.PHP.valueToCode(a,"LIST",Blockly.PHP.ORDER_ASSIGNMENT)||"[]",d=Blockly.PHP.statementToCode(a,"DO");d=Blockly.PHP.addLoopTrap(d,a.id);return""+("foreach ("+c+" as "+b+") {\n"+d+"}\n")}; Blockly.PHP.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw"Unknown flow statement.";};Blockly.PHP.logic={};Blockly.PHP.controls_if=function(a){var b=0,c="";do{var d=Blockly.PHP.valueToCode(a,"IF"+b,Blockly.PHP.ORDER_NONE)||"false";var e=Blockly.PHP.statementToCode(a,"DO"+b);c+=(0",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.PHP.ORDER_EQUALITY:Blockly.PHP.ORDER_RELATIONAL,d=Blockly.PHP.valueToCode(a,"A",c)||"0";a=Blockly.PHP.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.PHP.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.PHP.ORDER_LOGICAL_AND:Blockly.PHP.ORDER_LOGICAL_OR,d=Blockly.PHP.valueToCode(a,"A",c);a=Blockly.PHP.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.PHP.logic_negate=function(a){var b=Blockly.PHP.ORDER_LOGICAL_NOT;return["!"+(Blockly.PHP.valueToCode(a,"BOOL",b)||"true"),b]}; diff --git a/python_compressed.js b/python_compressed.js index 5a2f7cc44..a2aceed09 100644 --- a/python_compressed.js +++ b/python_compressed.js @@ -7,7 +7,7 @@ Blockly.Python=new Blockly.Generator("Python");Blockly.Python.addReservedWords(" Blockly.Python.ORDER_ATOMIC=0;Blockly.Python.ORDER_COLLECTION=1;Blockly.Python.ORDER_STRING_CONVERSION=1;Blockly.Python.ORDER_MEMBER=2.1;Blockly.Python.ORDER_FUNCTION_CALL=2.2;Blockly.Python.ORDER_EXPONENTIATION=3;Blockly.Python.ORDER_UNARY_SIGN=4;Blockly.Python.ORDER_BITWISE_NOT=4;Blockly.Python.ORDER_MULTIPLICATIVE=5;Blockly.Python.ORDER_ADDITIVE=6;Blockly.Python.ORDER_BITWISE_SHIFT=7;Blockly.Python.ORDER_BITWISE_AND=8;Blockly.Python.ORDER_BITWISE_XOR=9;Blockly.Python.ORDER_BITWISE_OR=10; Blockly.Python.ORDER_RELATIONAL=11;Blockly.Python.ORDER_LOGICAL_NOT=12;Blockly.Python.ORDER_LOGICAL_AND=13;Blockly.Python.ORDER_LOGICAL_OR=14;Blockly.Python.ORDER_CONDITIONAL=15;Blockly.Python.ORDER_LAMBDA=16;Blockly.Python.ORDER_NONE=99; Blockly.Python.ORDER_OVERRIDES=[[Blockly.Python.ORDER_FUNCTION_CALL,Blockly.Python.ORDER_MEMBER],[Blockly.Python.ORDER_FUNCTION_CALL,Blockly.Python.ORDER_FUNCTION_CALL],[Blockly.Python.ORDER_MEMBER,Blockly.Python.ORDER_MEMBER],[Blockly.Python.ORDER_MEMBER,Blockly.Python.ORDER_FUNCTION_CALL],[Blockly.Python.ORDER_LOGICAL_NOT,Blockly.Python.ORDER_LOGICAL_NOT],[Blockly.Python.ORDER_LOGICAL_AND,Blockly.Python.ORDER_LOGICAL_AND],[Blockly.Python.ORDER_LOGICAL_OR,Blockly.Python.ORDER_LOGICAL_OR]]; -Blockly.Python.init=function(a){Blockly.Python.PASS=this.INDENT+"pass\n";Blockly.Python.definitions_=Object.create(null);Blockly.Python.functionNames_=Object.create(null);Blockly.Python.variableDB_?Blockly.Python.variableDB_.reset():Blockly.Python.variableDB_=new Blockly.Names(Blockly.Python.RESERVED_WORDS_);var b=[];a=a.variableList;for(var c=0;ca?Blockly.Python.ORDER_UNARY_SIGN:Blockly.Python.ORDER_ATOMIC;return[a,b]}; -Blockly.Python.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Python.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Python.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Python.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Python.ORDER_MULTIPLICATIVE],POWER:[" ** ",Blockly.Python.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.Python.valueToCode(a,"A",b)||"0";a=Blockly.Python.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; +Blockly.Python.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Python.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Python.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Python.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Python.ORDER_MULTIPLICATIVE],POWER:[" ** ",Blockly.Python.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.Python.valueToCode(a,"A",b)||"0";a=Blockly.Python.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.Python.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b){var c=Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_UNARY_SIGN)||"0";return["-"+c,Blockly.Python.ORDER_UNARY_SIGN]}Blockly.Python.definitions_.import_math="import math";a="SIN"==b||"COS"==b||"TAN"==b?Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_MULTIPLICATIVE)||"0":Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_NONE)||"0";switch(b){case "ABS":c="math.fabs("+a+")";break;case "ROOT":c="math.sqrt("+ a+")";break;case "LN":c="math.log("+a+")";break;case "LOG10":c="math.log10("+a+")";break;case "EXP":c="math.exp("+a+")";break;case "POW10":c="math.pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="math.ceil("+a+")";break;case "ROUNDDOWN":c="math.floor("+a+")";break;case "SIN":c="math.sin("+a+" / 180.0 * math.pi)";break;case "COS":c="math.cos("+a+" / 180.0 * math.pi)";break;case "TAN":c="math.tan("+a+" / 180.0 * math.pi)"}if(c)return[c,Blockly.Python.ORDER_FUNCTION_CALL];switch(b){case "ASIN":c= "math.asin("+a+") / math.pi * 180";break;case "ACOS":c="math.acos("+a+") / math.pi * 180";break;case "ATAN":c="math.atan("+a+") / math.pi * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.Python.ORDER_MULTIPLICATIVE]}; @@ -50,15 +50,15 @@ Blockly.Python.colour_rgb=function(a){var b=Blockly.Python.provideFunction_("col 0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]}; Blockly.Python.colour_blend=function(a){var b=Blockly.Python.provideFunction_("colour_blend",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(colour1, colour2, ratio):"," r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)"," g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)"," b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)"," ratio = min(1, max(0, ratio))"," r = round(r1 * (1 - ratio) + r2 * ratio)"," g = round(g1 * (1 - ratio) + g2 * ratio)"," b = round(b1 * (1 - ratio) + b2 * ratio)", " return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"COLOUR1",Blockly.Python.ORDER_NONE)||"'#000000'",d=Blockly.Python.valueToCode(a,"COLOUR2",Blockly.Python.ORDER_NONE)||"'#000000'";a=Blockly.Python.valueToCode(a,"RATIO",Blockly.Python.ORDER_NONE)||0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.procedures={}; -Blockly.Python.procedures_defreturn=function(a){for(var b=[],c=0,d;d=a.workspace.variableList[c];c++)-1==a.arguments_.indexOf(d)&&b.push(Blockly.Python.variableDB_.getName(d,Blockly.Variables.NAME_TYPE));b=b.length?" global "+b.join(", ")+"\n":"";d=Blockly.Python.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE);var e=Blockly.Python.statementToCode(a,"STACK");Blockly.Python.STATEMENT_PREFIX&&(e=Blockly.Python.prefixLines(Blockly.Python.STATEMENT_PREFIX.replace(/%1/g,"'"+a.id+ -"'"),Blockly.Python.INDENT)+e);Blockly.Python.INFINITE_LOOP_TRAP&&(e=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,'"'+a.id+'"')+e);var f=Blockly.Python.valueToCode(a,"RETURN",Blockly.Python.ORDER_NONE)||"";f?f=" return "+f+"\n":e||(e=Blockly.Python.PASS);for(var g=[],c=0;c= stop:"," yield start"," start -= abs(step)"])};a=function(a,b,c){return"("+a+" <= "+b+") and "+h()+"("+a+", "+b+", "+c+") or "+k()+"("+a+", "+b+", "+c+")"};if(Blockly.isNumber(c)&&Blockly.isNumber(d)&& -Blockly.isNumber(e))c=parseFloat(c),d=parseFloat(d),e=Math.abs(parseFloat(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0==c&&1==e?d:c+", "+d,1!=e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=c",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Python.ORDER_RELATIONAL,d=Blockly.Python.valueToCode(a,"A",c)||"0";a=Blockly.Python.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.Python.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"and":"or",c="and"==b?Blockly.Python.ORDER_LOGICAL_AND:Blockly.Python.ORDER_LOGICAL_OR,d=Blockly.Python.valueToCode(a,"A",c);a=Blockly.Python.valueToCode(a,"B",c);if(d||a){var e="and"==b?"True":"False";d||(d=e);a||(a=e)}else a=d="False";return[d+" "+b+" "+a,c]};Blockly.Python.logic_negate=function(a){return["not "+(Blockly.Python.valueToCode(a,"BOOL",Blockly.Python.ORDER_LOGICAL_NOT)||"True"),Blockly.Python.ORDER_LOGICAL_NOT]}; diff --git a/scripts/get_chromedriver.sh b/scripts/get_chromedriver.sh index c3e3d6453..7bff39c16 100755 --- a/scripts/get_chromedriver.sh +++ b/scripts/get_chromedriver.sh @@ -5,12 +5,13 @@ if [ ! -d $chromedriver_dir ]; then mkdir $chromedriver_dir fi -if [[ $os_name == 'Linux' ]]; then - cd chromedriver && curl -L https://chromedriver.storage.googleapis.com/2.29/chromedriver_linux64.zip > tmp.zip && unzip -o tmp.zip && rm tmp.zip +echo "downloading chromedriver" + +if [[ $os_name == 'Linux' && ! -f $chromedriver_dir/chromedriver ]]; then + cd chromedriver && curl -L https://chromedriver.storage.googleapis.com/2.29/chromedriver_linux64.zip > tmp.zip && unzip -o tmp.zip && rm tmp.zip # wait until download finish sleep 5 -elif [[ $os_name == 'Darwin' ]]; then - cd chromedriver && curl -L https://chromedriver.storage.googleapis.com/2.29/chromedriver_mac64.zip | tar xz - # wait until download finish +elif [[ $os_name == 'Darwin' && ! -f $chromedriver_dir/chromedriver ]]; then + cd chromedriver && curl -L https://chromedriver.storage.googleapis.com/2.29/chromedriver_mac64.zip | tar xz sleep 5 fi diff --git a/scripts/get_geckdriver.sh b/scripts/get_geckdriver.sh index 12002b608..77fecd4ec 100755 --- a/scripts/get_geckdriver.sh +++ b/scripts/get_geckdriver.sh @@ -1,5 +1,11 @@ #!/bin/bash os_name=`uname` + +if [ -f geckodriver ]; then + exit 0 +fi +echo "downloading gechdriver" + if [[ $os_name == 'Linux' ]]; then cd ../ && curl -L https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-linux64.tar.gz | tar xz sleep 5 diff --git a/scripts/get_selenium.sh b/scripts/get_selenium.sh index d2f9fdd7b..0dac3e9b5 100755 --- a/scripts/get_selenium.sh +++ b/scripts/get_selenium.sh @@ -6,6 +6,8 @@ if [ ! -d $DIR ]; then mkdir $DIR fi +echo "downloading selenium jar" + if [ ! -f $DIR/$FILE ]; then cd $DIR && curl -O http://selenium-release.storage.googleapis.com/3.0/selenium-server-standalone-3.0.1.jar sleep 5 diff --git a/scripts/setup_linux_env.sh b/scripts/setup_linux_env.sh new file mode 100755 index 000000000..da3d0ce6c --- /dev/null +++ b/scripts/setup_linux_env.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ "${TRAVIS_OS_NAME}" == "linux" ] + then + export CHROME_BIN="/usr/bin/google-chrome" + export DISPLAY=:99.0 + sh -e /etc/init.d/xvfb start & +fi diff --git a/scripts/setup_osx_env.sh b/scripts/setup_osx_env.sh new file mode 100755 index 000000000..92891f966 --- /dev/null +++ b/scripts/setup_osx_env.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ "${TRAVIS_OS_NAME}" == "osx" ] + then + brew cask install google-chrome + sudo Xvfb :99 -ac -screen 0 1024x768x8 & + export CHROME_BIN="/Applications/Google Chrome.app" +fi diff --git a/scripts/test_setup.sh b/scripts/test_setup.sh index feae42eeb..4220923f3 100755 --- a/scripts/test_setup.sh +++ b/scripts/test_setup.sh @@ -16,7 +16,8 @@ sleep 5 check_command scripts/get_selenium.sh sleep 5 check_command scripts/get_chromedriver.sh -sleep 5 +sleep 10 check_command scripts/selenium_connect.sh -sleep 3 +sleep 10 + exit $EXIT_STATUS diff --git a/tests/jsunit/event_test.js b/tests/jsunit/event_test.js new file mode 100644 index 000000000..c019515e9 --- /dev/null +++ b/tests/jsunit/event_test.js @@ -0,0 +1,394 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @fileoverview Tests for Blockly.Events + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +goog.require('goog.testing'); +goog.require('goog.testing.MockControl'); + +var mockControl_; +var workspace; + +function eventTest_setUp() { + workspace = new Blockly.Workspace(); + mockControl_ = new goog.testing.MockControl(); +} + +function eventTest_setUpWithMockBlocks() { + eventTest_setUp(); + Blockly.defineBlocksWithJsonArray([{ + 'type': 'field_variable_test_block', + 'message0': '%1', + 'args0': [ + { + 'type': 'field_variable', + 'name': 'VAR', + 'variable': 'item' + } + ], + }]); +} + +function eventTest_tearDown() { + mockControl_.$tearDown(); + workspace.dispose(); +} + +function eventTest_tearDownWithMockBlocks() { + eventTest_tearDown(); + delete Blockly.Blocks.field_variable_test_block; +} + +function test_abstract_constructor_block() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, '1'); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Abstract(block); + assertUndefined(event.varId); + checkExactEventValues(event, {'blockId': '1', 'workspaceId': workspace.id, + 'group': '', 'recordUndo': true}); + eventTest_tearDownWithMockBlocks(); +} + +function test_abstract_constructor_variable() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, '1'); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.Abstract(variable); + assertUndefined(event.blockId); + checkExactEventValues(event, {'varId': 'id1', + 'workspaceId': workspace.id, 'group': '', 'recordUndo': true}); + eventTest_tearDownWithMockBlocks(); +} + +function test_abstract_constructor_null() { + eventTest_setUpWithMockBlocks(); + var event = new Blockly.Events.Abstract(null); + assertUndefined(event.blockId); + assertUndefined(event.workspaceId); + checkExactEventValues(event, {'group': '', 'recordUndo': true}); + eventTest_tearDownWithMockBlocks(); +} + +function checkCreateEventValues(event, block, ids, type) { + var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block)); + var result_xml = Blockly.Xml.domToText(event.xml); + assertEquals(expected_xml, result_xml); + isEqualArrays(ids, event.ids); + assertEquals(type, event.type); +} + +function checkDeleteEventValues(event, block, ids, type) { + var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block)); + var result_xml = Blockly.Xml.domToText(event.oldXml); + assertEquals(expected_xml, result_xml); + isEqualArrays(ids, event.ids); + assertEquals(type, event.type); +} + +function checkExactEventValues(event, values) { + var keys = Object.keys(values); + for (var i = 0, field; field = keys[i]; i++) { + assertEquals(values[field], event[field]); + } +} + +function test_create_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Create(block); + checkCreateEventValues(event, block, ['1'], 'create'); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockCreate_constructor() { + // expect that blockCreate behaves the same as create. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.BlockCreate(block); + checkCreateEventValues(event, block, ['1'], 'create'); + eventTest_tearDownWithMockBlocks(); +} + +function test_delete_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Delete(block); + checkDeleteEventValues(event, block, ['1'], 'delete'); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockDelete_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.BlockDelete(block); + checkDeleteEventValues(event, block, ['1'], 'delete'); + eventTest_tearDownWithMockBlocks(); +} + +function test_change_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Change(block, 'field', 'VAR', 'item', 'item2'); + checkExactEventValues(event, {'element': 'field', 'name': 'VAR', + 'oldValue': 'item', 'newValue': 'item2', 'type': 'change'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockChange_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.BlockChange(block, 'field', 'VAR', 'item', + 'item2'); + checkExactEventValues(event, {'element': 'field', 'name': 'VAR', + 'oldValue': 'item', 'newValue': 'item2', 'type': 'change'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_move_constructorCoordinate() { + // Expect the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var coordinate = new goog.math.Coordinate(3,4); + block1.xy_ = coordinate; + + var event = new Blockly.Events.Move(block1); + checkExactEventValues(event, {'oldCoordinate': coordinate, + 'type': 'move'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_move_constructoroldParentId() { + // Expect the oldParentId to be set but not the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var block2 = new Blockly.Block(workspace, 'field_variable_test_block'); + block1.parentBlock_ = block2; + block1.xy_ = new goog.math.Coordinate(3,4); + + var event = new Blockly.Events.Move(block1); + checkExactEventValues(event, {'oldCoordinate': undefined, + 'oldParentId': '2', 'type': 'move'}); + block1.parentBlock_ = null; + eventTest_tearDownWithMockBlocks(); +} + +function test_blockMove_constructorCoordinate() { + // Expect the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var coordinate = new goog.math.Coordinate(3,4); + block1.xy_ = coordinate; + + var event = new Blockly.Events.BlockMove(block1); + checkExactEventValues(event, {'oldCoordinate': coordinate, + 'type': 'move'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockMove_constructoroldParentId() { + // Expect the oldParentId to be set but not the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var block2 = new Blockly.Block(workspace, 'field_variable_test_block'); + block1.parentBlock_ = block2; + block1.xy_ = new goog.math.Coordinate(3,4); + + var event = new Blockly.Events.BlockMove(block1); + checkExactEventValues(event, {'oldCoordinate': undefined, + 'oldParentId': '2', 'type': 'move'}); + block1.parentBlock_ = null; + eventTest_tearDownWithMockBlocks(); +} + +function test_varCreate_constructor() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarCreate(variable); + checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1', + 'type': 'var_create'}); + eventTest_tearDown(); +} + +function test_varCreate_toJson() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarCreate(variable); + var json = event.toJson(); + var expectedJson = ({type: "var_create", varId: "id1", varType: "type1", + varName: "name1"}); + + assertEquals(JSON.stringify(expectedJson), JSON.stringify(json)); + eventTest_tearDown(); +} + +function test_varCreate_fromJson() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarCreate(variable); + var event2 = new Blockly.Events.VarCreate(null); + var json = event.toJson(); + event2.fromJson(json); + + assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson())); + eventTest_tearDown(); +} + +function test_varCreate_runForward() { + eventTest_setUp(); + var json = {type: "var_create", varId: "id1", varType: "type1", + varName: "name1"}; + var event = Blockly.Events.fromJson(json, workspace); + assertNull(workspace.getVariableById('id1')); + event.run(true); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + eventTest_tearDown(); +} + +function test_varCreate_runBackwards() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarCreate(variable); + assertNotNull(workspace.getVariableById('id1')); + event.run(false); + assertNull(workspace.getVariableById('id1')); + eventTest_tearDown(); +} + +function test_varDelete_constructor() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarDelete(variable); + checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1', + 'varId':'id1', 'type': 'var_delete'}); + eventTest_tearDown(); +} + +function test_varDelete_toJson() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarDelete(variable); + var json = event.toJson(); + var expectedJson = ({type: "var_delete", varId: "id1", varType: "type1", + varName: "name1"}); + + assertEquals(JSON.stringify(expectedJson), JSON.stringify(json)); + eventTest_tearDown(); +} + +function test_varDelete_fromJson() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarDelete(variable); + var event2 = new Blockly.Events.VarDelete(null); + var json = event.toJson(); + event2.fromJson(json); + + assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson())); + eventTest_tearDown(); +} + +function test_varDelete_runForwards() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarDelete(variable); + assertNotNull(workspace.getVariableById('id1')); + event.run(true); + assertNull(workspace.getVariableById('id1')); + eventTest_tearDown(); +} + +function test_varDelete_runBackwards() { + eventTest_setUp(); + var json = {type: "var_delete", varId: "id1", varType: "type1", + varName: "name1"}; + var event = Blockly.Events.fromJson(json, workspace); + assertNull(workspace.getVariableById('id1')); + event.run(false); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + eventTest_tearDown(); +} + +function test_varRename_constructor() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarRename(variable, 'name2'); + checkExactEventValues(event, {'varId': 'id1', 'oldName': 'name1', + 'newName': 'name2', 'type': 'var_rename'}); + eventTest_tearDown(); +} + +function test_varRename_toJson() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarRename(variable, 'name2'); + var json = event.toJson(); + var expectedJson = ({type: "var_rename", varId: "id1", oldName: "name1", + newName: "name2"}); + + assertEquals(JSON.stringify(expectedJson), JSON.stringify(json)); + eventTest_tearDown(); +} + +function test_varRename_fromJson() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarRename(variable, ''); + var event2 = new Blockly.Events.VarRename(null); + var json = event.toJson(); + event2.fromJson(json); + + assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson())); + eventTest_tearDown(); +} + +function test_varRename_runForward() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarRename(variable, 'name2'); + event.run(true); + assertNull(workspace.getVariable('name1')); + checkVariableValues(workspace, 'name2', 'type1', 'id1'); + eventTest_tearDown(); +} + +function test_varBackard_runForward() { + eventTest_setUp(); + var variable = workspace.createVariable('name1', 'type1', 'id1'); + var event = new Blockly.Events.VarRename(variable, 'name2'); + event.run(false); + assertNull(workspace.getVariable('name2')); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + eventTest_tearDown(); +} diff --git a/tests/jsunit/field_variable_test.js b/tests/jsunit/field_variable_test.js new file mode 100644 index 000000000..94c5f7d41 --- /dev/null +++ b/tests/jsunit/field_variable_test.js @@ -0,0 +1,183 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @fileoverview Tests for Blockly.FieldVariable + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +goog.require('goog.testing'); +goog.require('goog.testing.MockControl'); + +var workspace; +var mockControl_; + +function fieldVariableTestWithMocks_setUp() { + workspace = new Blockly.Workspace(); + mockControl_ = new goog.testing.MockControl(); +} + +function fieldVariableTestWithMocks_tearDown() { + mockControl_.$tearDown(); + workspace.dispose(); +} + +function fieldVariable_mockBlock(workspace) { + return {'workspace': workspace, 'isShadow': function(){return false;}}; +} + +function test_fieldVariable_Constructor() { + workspace = new Blockly.Workspace(); + var fieldVariable = new Blockly.FieldVariable('name1'); + assertEquals('name1', fieldVariable.getText()); + workspace.dispose(); +} + +function test_fieldVariable_setValueMatchId() { + // Expect the fieldVariable value to be set to variable name + fieldVariableTestWithMocks_setUp(); + workspace.createVariable('name2', null, 'id2'); + var fieldVariable = new Blockly.FieldVariable('name1'); + var mockBlock = fieldVariable_mockBlock(workspace); + fieldVariable.setSourceBlock(mockBlock); + var event = new Blockly.Events.BlockChange( + mockBlock, 'field', undefined, 'name1', 'id2'); + setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null); + + fieldVariable.setValue('id2'); + assertEquals('name2', fieldVariable.getText()); + assertEquals('id2', fieldVariable.value_); + fieldVariableTestWithMocks_tearDown(); +} + +function test_fieldVariable_setValueMatchName() { + // Expect the fieldVariable value to be set to variable name + fieldVariableTestWithMocks_setUp(); + workspace.createVariable('name2', null, 'id2'); + var fieldVariable = new Blockly.FieldVariable('name1'); + var mockBlock = fieldVariable_mockBlock(workspace); + fieldVariable.setSourceBlock(mockBlock); + var event = new Blockly.Events.BlockChange( + mockBlock, 'field', undefined, 'name1', 'id2'); + setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null); + + fieldVariable.setValue('name2'); + assertEquals('name2', fieldVariable.getText()); + assertEquals('id2', fieldVariable.value_); + fieldVariableTestWithMocks_tearDown(); +} + +function test_fieldVariable_setValueNoVariable() { + // Expect the fieldVariable value to be set to the passed in string. No error + // should be thrown. + fieldVariableTestWithMocks_setUp(); + var fieldVariable = new Blockly.FieldVariable('name1'); + var mockBlock = {'workspace': workspace, + 'isShadow': function(){return false;}}; + fieldVariable.setSourceBlock(mockBlock); + var event = new Blockly.Events.BlockChange( + mockBlock, 'field', undefined, 'name1', 'id1'); + setUpMockMethod(mockControl_, Blockly.Events, 'fire', [event], null); + + fieldVariable.setValue('id1'); + assertEquals('id1', fieldVariable.getText()); + assertEquals('id1', fieldVariable.value_); + fieldVariableTestWithMocks_tearDown(); +} + +function test_fieldVariable_dropdownCreateVariablesExist() { + // Expect that the dropdown options will contain the variables that exist. + workspace = new Blockly.Workspace(); + workspace.createVariable('name1', '', 'id1'); + workspace.createVariable('name2', '', 'id2'); + var result_options = Blockly.FieldVariable.dropdownCreate.call( + { + 'sourceBlock_': {'workspace': workspace}, + 'getText': function(){return 'name1';} + }); + assertEquals(result_options.length, 3); + isEqualArrays(result_options[0], ['name1', 'id1']); + isEqualArrays(result_options[1], ['name2', 'id2']); + + workspace.dispose(); +} + +function test_fieldVariable_dropdownCreateVariablesExist() { + // Expect that the dropdown options will contain the variables that exist. + workspace = new Blockly.Workspace(); + workspace.createVariable('name1', '', 'id1'); + workspace.createVariable('name2', '', 'id2'); + var result_options = Blockly.FieldVariable.dropdownCreate.call( + { + 'sourceBlock_': {'workspace': workspace}, + 'getText': function(){return 'name1';} + }); + assertEquals(result_options.length, 3); + isEqualArrays(result_options[0], ['name1', 'id1']); + isEqualArrays(result_options[1], ['name2', 'id2']); + + workspace.dispose(); +} + +function test_fieldVariable_dropdownVariableAndTypeDoesNotExist() { + // Expect a variable will be created for the selected option. Expect the + // workspace variable map to contain the new variable once. + fieldVariableTestWithMocks_setUp(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['id1', null]); + + var result_options = Blockly.FieldVariable.dropdownCreate.call( + { + 'sourceBlock_': {'workspace': workspace}, + 'getText': function(){return 'name1';} + }); + + // Check the options. + assertEquals(2, result_options.length); + isEqualArrays(result_options[0], ['name1', 'id1']); + // Check the variable map. + assertEquals(1, workspace.getAllVariables().length); + checkVariableValues(workspace, 'name1', '', 'id1'); + + fieldVariableTestWithMocks_tearDown(); +} + +function test_fieldVariable_dropdownVariableDoesNotExistTypeDoes() { + // Expect a variable will be created for the selected option. Expect the + // workspace variable map to contain the new variable once. + fieldVariableTestWithMocks_setUp(); + workspace.createVariable('name1', '', 'id1'); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['id2', null]); + + var result_options = Blockly.FieldVariable.dropdownCreate.call( + { + 'sourceBlock_': {'workspace': workspace}, + 'getText': function(){return 'name2';} + }); + + assertEquals(3, result_options.length); + isEqualArrays(result_options[0], ['name1', 'id1']); + isEqualArrays(result_options[1], ['name2', 'id2']); + assertEquals(2, workspace.variableMap_.getAllVariables().length); + checkVariableValues(workspace, 'name1', '', 'id1'); + checkVariableValues(workspace, 'name2', '', 'id2'); + + fieldVariableTestWithMocks_tearDown(); +} diff --git a/tests/jsunit/gesture_test.js b/tests/jsunit/gesture_test.js new file mode 100644 index 000000000..19ba1864e --- /dev/null +++ b/tests/jsunit/gesture_test.js @@ -0,0 +1,90 @@ +/** + * @license + * Blockly Tests + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @fileoverview Tests for gesture. + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +var e; +var workspace; + + +function gestureTest_setUp() { + workspace = new Blockly.Workspace(); + e = {}; +} + +function gestureTest_tearDown() { + e = null; + workspace.dispose(); +} + +function test_gestureConstructor() { + var gesture = new Blockly.Gesture(e, workspace); + assertEquals(gesture.mostRecentEvent_, e); + assertEquals(gesture.creatorWorkspace_, workspace); +} + +function test_gestureIsField_ClickInWorkspace() { + gestureTest_setUp(); + var block = new Blockly.Block(workspace); + var field = new Blockly.Field(); + field.setSourceBlock(block); + var gesture = new Blockly.Gesture(e, workspace); + gesture.setStartField(field); + + var isFieldClick = gesture.isFieldClick_(); + assertEquals(isFieldClick, true); + gestureTest_tearDown(); +} + +function gestureIsFieldClick_InFlyoutHelper(flyout, expectedResult){ + // Assign workspace flyout + workspace.flyout_ = flyout; + // Create a Field inside of a Block + var block = new Blockly.Block(workspace); + var field = new Blockly.Field(); + field.setSourceBlock(block); + // Create gesture from the flyout + var gesture = new Blockly.Gesture(e, workspace.flyout_); + // Populate gesture with click start information + gesture.setStartField(field); + gesture.setStartFlyout_(workspace.flyout_); + + var isFieldClick = gesture.isFieldClick_(); + assertEquals(isFieldClick, expectedResult); +} + +function test_gestureIsFieldClick_AutoCloseFlyout() { + gestureTest_setUp(); + var flyout = new Blockly.VerticalFlyout({}); + gestureIsFieldClick_InFlyoutHelper(flyout, false); + gestureTest_tearDown(); +} + +function test_gestureIsFieldClick_AlwaysOpenFlyout() { + gestureTest_setUp(); + var flyout = new Blockly.VerticalFlyout({}); + flyout.autoClose = false; + gestureIsFieldClick_InFlyoutHelper(flyout, true); + gestureTest_tearDown(); +} diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index 2b27758ce..dd62a536a 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -7,19 +7,25 @@ + + + + + + diff --git a/tests/jsunit/test_runner.js b/tests/jsunit/test_runner.js index d3a44944a..bfd7c0bd3 100644 --- a/tests/jsunit/test_runner.js +++ b/tests/jsunit/test_runner.js @@ -10,7 +10,7 @@ var path = process.cwd(); var browser = webdriverio .remote(options) .init() - .url("file://" + path + "/tests/jsunit/index.html").pause(3000); + .url("file://" + path + "/tests/jsunit/index.html").pause(5000); browser diff --git a/tests/jsunit/test_utilities.js b/tests/jsunit/test_utilities.js new file mode 100644 index 000000000..6a80a3549 --- /dev/null +++ b/tests/jsunit/test_utilities.js @@ -0,0 +1,91 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @fileoverview Test utilities. + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +goog.require('goog.testing'); + + +/** + * Check that two arrays have the same content. + * @param {!Array.} array1 The first array. + * @param {!Array.} array2 The second array. + */ +function isEqualArrays(array1, array2) { + assertEquals(array1.length, array2.length); + for (var i = 0; i < array1.length; i++) { + assertEquals(array1[i], array2[i]); + } +} + +/** + * Creates a controlled MethodMock. Sets the expected return values and + * the parameters if any exist. Sets the method to replay. + * @param {!goog.testing.MockControl} mockControl Object that holds a set + * of mocks for this test. + * @param {!Object} scope The scope of the method to be mocked out. + * @param {!string} funcName The name of the function we're going to mock. + * @param {Array} parameters The parameters to call the mock with. + * @param {Array} return_values The values to return when called. + * @return {!goog.testing.MockInterface} The mocked method. + */ +function setUpMockMethod(mockControl, scope, funcName, parameters, + return_values) { + var mockMethod = mockControl.createMethodMock(scope, funcName); + if (return_values) { + for (var i = 0, return_value; return_value = return_values[i]; i++) { + if (parameters && i < parameters.length) { + mockMethod(parameters[i]).$returns(return_value); + } + else { + mockMethod().$returns(return_value); + } + } + } + // If there are no return values but there are parameters, we are only + // recording specific method calls. + else if (parameters) { + for (var i = 0; i < parameters.length; i++) { + mockMethod(parameters[i]); + } + } + mockMethod.$replay(); + return mockMethod; +} + +/** + * Check if a variable with the given values exists. + * @param {Blockly.Workspace|Blockly.VariableMap} container The workspace or + * variableMap the checked variable belongs to. + * @param {!string} name The expected name of the variable. + * @param {!string} type The expected type of the variable. + * @param {!string} id The expected id of the variable. + */ +function checkVariableValues(container, name, type, id) { + var variable = container.getVariableById(id); + assertNotUndefined(variable); + assertEquals(name, variable.name); + assertEquals(type, variable.type); + assertEquals(id, variable.getId()); +} diff --git a/tests/jsunit/variable_map_test.js b/tests/jsunit/variable_map_test.js new file mode 100644 index 000000000..023377b14 --- /dev/null +++ b/tests/jsunit/variable_map_test.js @@ -0,0 +1,274 @@ +/** + * @license + * Blockly Tests + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @fileoverview Tests for variable map. + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +goog.require('goog.testing'); +goog.require('goog.testing.MockControl'); + +var variable_map; +var mockControl_; +var workspace; + +function variableMapTest_setUp() { + workspace = new Blockly.Workspace(); + variable_map = new Blockly.VariableMap(workspace); + mockControl_ = new goog.testing.MockControl(); +} + +function variableMapTest_tearDown() { + workspace.dispose(); + mockControl_.$tearDown(); + variable_map = null; +} + +function test_getVariable_Trivial() { + variableMapTest_setUp(); + var var_1 = variable_map.createVariable('name1', 'type1', 'id1'); + var var_2 = variable_map.createVariable('name2', 'type1', 'id2'); + var var_3 = variable_map.createVariable('name3', 'type2', 'id3'); + var result_1 = variable_map.getVariable('name1'); + var result_2 = variable_map.getVariable('name2'); + var result_3 = variable_map.getVariable('name3'); + + assertEquals(var_1, result_1); + assertEquals(var_2, result_2); + assertEquals(var_3, result_3); + variableMapTest_tearDown(); +} + +function test_getVariable_NotFound() { + variableMapTest_setUp(); + var result = variable_map.getVariable('name1'); + assertNull(result); + variableMapTest_tearDown(); +} + +function test_getVariableById_Trivial() { + variableMapTest_setUp(); + var var_1 = variable_map.createVariable('name1', 'type1', 'id1'); + var var_2 = variable_map.createVariable('name2', 'type1', 'id2'); + var var_3 = variable_map.createVariable('name3', 'type2', 'id3'); + var result_1 = variable_map.getVariableById('id1'); + var result_2 = variable_map.getVariableById('id2'); + var result_3 = variable_map.getVariableById('id3'); + + assertEquals(var_1, result_1); + assertEquals(var_2, result_2); + assertEquals(var_3, result_3); + variableMapTest_tearDown(); +} + +function test_getVariableById_NotFound() { + variableMapTest_setUp(); + var result = variable_map.getVariableById('id1'); + assertNull(result); + variableMapTest_tearDown(); +} + +function test_createVariableTrivial() { + variableMapTest_setUp(); + variable_map.createVariable('name1', 'type1', 'id1'); + checkVariableValues(variable_map, 'name1', 'type1', 'id1'); + variableMapTest_tearDown(); +} + +function test_createVariableAlreadyExists() { + // Expect that when the variable already exists, the variableMap_ is unchanged. + variableMapTest_setUp(); + variable_map.createVariable('name1', 'type1', 'id1'); + + // Assert there is only one variable in the variable_map. + var keys = Object.keys(variable_map.variableMap_); + assertEquals(1, keys.length); + var varMapLength = variable_map.variableMap_[keys[0]].length; + assertEquals(1, varMapLength); + + variable_map.createVariable('name1'); + checkVariableValues(variable_map, 'name1', 'type1', 'id1'); + // Check that the size of the variableMap_ did not change. + keys = Object.keys(variable_map.variableMap_); + assertEquals(1, keys.length); + varMapLength = variable_map.variableMap_[keys[0]].length; + assertEquals(1, varMapLength); + variableMapTest_tearDown(); +} + +function test_createVariableNullAndUndefinedType() { + variableMapTest_setUp(); + variable_map.createVariable('name1', null, 'id1'); + variable_map.createVariable('name2', undefined, 'id2'); + + checkVariableValues(variable_map, 'name1', '', 'id1'); + checkVariableValues(variable_map, 'name2', '', 'id2'); + variableMapTest_tearDown(); +} + +function test_createVariableNullId() { + variableMapTest_setUp(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + try { + variable_map.createVariable('name1', 'type1', null); + checkVariableValues(variable_map, 'name1', 'type1', '1'); + } + finally { + variableMapTest_tearDown(); + } +} + +function test_createVariableUndefinedId() { + variableMapTest_setUp(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + try { + variable_map.createVariable('name1', 'type1', undefined); + checkVariableValues(variable_map, 'name1', 'type1', '1'); + } + finally { + variableMapTest_tearDown(); + } +} + +function test_createVariableIdAlreadyExists() { + variableMapTest_setUp(); + variable_map.createVariable('name1', 'type1', 'id1'); + try { + variable_map.createVariable('name2', 'type2', 'id1'); + fail(); + } catch (e) { + // expected + } + variableMapTest_tearDown(); +} + +function test_createVariableMismatchedIdAndType() { + variableMapTest_setUp(); + variable_map.createVariable('name1', 'type1', 'id1'); + try { + variable_map.createVariable('name1', 'type2', 'id1'); + fail(); + } catch (e) { + // expected + } + try { + variable_map.createVariable('name1', 'type1', 'id2'); + fail(); + } catch (e) { + // expected + } + variableMapTest_tearDown(); +} + +function test_createVariableTwoSameTypes() { + variableMapTest_setUp(); + variable_map.createVariable('name1', 'type1', 'id1'); + variable_map.createVariable('name2', 'type1', 'id2'); + + checkVariableValues(variable_map, 'name1', 'type1', 'id1'); + checkVariableValues(variable_map, 'name2', 'type1', 'id2'); + variableMapTest_tearDown(); +} + +function test_getVariablesOfType_Trivial() { + variableMapTest_setUp(); + var var_1 = variable_map.createVariable('name1', 'type1', 'id1'); + var var_2 = variable_map.createVariable('name2', 'type1', 'id2'); + variable_map.createVariable('name3', 'type2', 'id3'); + variable_map.createVariable('name4', 'type3', 'id4'); + var result_array_1 = variable_map.getVariablesOfType('type1'); + var result_array_2 = variable_map.getVariablesOfType('type5'); + isEqualArrays([var_1, var_2], result_array_1); + isEqualArrays([], result_array_2); + variableMapTest_tearDown(); +} + +function test_getVariablesOfType_Null() { + variableMapTest_setUp(); + var var_1 = variable_map.createVariable('name1', '', 'id1'); + var var_2 = variable_map.createVariable('name2', '', 'id2'); + var var_3 = variable_map.createVariable('name3', '', 'id3'); + variable_map.createVariable('name4', 'type1', 'id4'); + var result_array = variable_map.getVariablesOfType(null); + isEqualArrays([var_1, var_2, var_3], result_array); + variableMapTest_tearDown(); +} + +function test_getVariablesOfType_EmptyString() { + variableMapTest_setUp(); + var var_1 = variable_map.createVariable('name1', null, 'id1'); + var var_2 = variable_map.createVariable('name2', null, 'id2'); + var result_array = variable_map.getVariablesOfType(''); + isEqualArrays([var_1, var_2], result_array); + variableMapTest_tearDown(); +} + +function test_getVariablesOfType_Deleted() { + variableMapTest_setUp(); + var variable = variable_map.createVariable('name1', null, 'id1'); + variable_map.deleteVariable(variable); + var result_array = variable_map.getVariablesOfType(''); + isEqualArrays([], result_array); + variableMapTest_tearDown(); +} + +function test_getVariablesOfType_DoesNotExist() { + variableMapTest_setUp(); + var result_array = variable_map.getVariablesOfType('type1'); + isEqualArrays([], result_array); + variableMapTest_tearDown(); +} + +function test_getVariableTypes_Trivial() { + variableMapTest_setUp(); + variable_map.createVariable('name1', 'type1', 'id1'); + variable_map.createVariable('name2', 'type1', 'id2'); + variable_map.createVariable('name3', 'type2', 'id3'); + variable_map.createVariable('name4', 'type3', 'id4'); + var result_array = variable_map.getVariableTypes(); + isEqualArrays(['type1', 'type2', 'type3'], result_array); + variableMapTest_tearDown(); +} + +function test_getVariableTypes_None() { + variableMapTest_setUp(); + var result_array = variable_map.getVariableTypes(); + isEqualArrays([], result_array); + variableMapTest_tearDown(); +} + +function test_getAllVariables_Trivial() { + variableMapTest_setUp(); + var var_1 = variable_map.createVariable('name1', 'type1', 'id1'); + var var_2 = variable_map.createVariable('name2', 'type1', 'id2'); + var var_3 = variable_map.createVariable('name3', 'type2', 'id3'); + var result_array = variable_map.getAllVariables(); + isEqualArrays([var_1, var_2, var_3], result_array); + variableMapTest_tearDown(); +} + +function test_getAllVariables_None() { + variableMapTest_setUp(); + var result_array = variable_map.getAllVariables(); + isEqualArrays([], result_array); + variableMapTest_tearDown(); +} diff --git a/tests/jsunit/variable_model_test.js b/tests/jsunit/variable_model_test.js index 9a2d2ac3a..3f22f287a 100644 --- a/tests/jsunit/variable_model_test.js +++ b/tests/jsunit/variable_model_test.js @@ -25,8 +25,14 @@ 'use strict'; var variable; +var workspace; -function variableTest_tearDown() { +function variableModelTest_setUp() { + workspace = new Blockly.Workspace(); +} + +function variableModelTest_tearDown() { + workspace.dispose(); variable = null; } @@ -34,45 +40,52 @@ function variableTest_tearDown() { * These tests check the constructor of the variable model. */ function testInit_Trivial() { - variable = new Blockly.VariableModel('test', 'test_type', 'test_id'); + variableModelTest_setUp(); + variable = new Blockly.VariableModel(workspace, 'test', 'test_type', + 'test_id'); assertEquals('test', variable.name); assertEquals('test_type', variable.type); assertEquals('test_id', variable.id_); - variableTest_tearDown(); + variableModelTest_tearDown(); } function testInit_NullType() { - variable = new Blockly.VariableModel('test', null, 'test_id'); + variableModelTest_setUp(); + variable = new Blockly.VariableModel(workspace, 'test', null, 'test_id'); assertEquals('', variable.type); - variableTest_tearDown(); + variableModelTest_tearDown(); } function testInit_UndefinedType() { - variable = new Blockly.VariableModel('test', undefined, 'test_id'); + variableModelTest_setUp(); + variable = new Blockly.VariableModel(workspace, 'test', undefined, 'test_id'); assertEquals('', variable.type); - variableTest_tearDown(); + variableModelTest_tearDown(); } function testInit_NullId() { - variable = new Blockly.VariableModel('test', 'test_type', null); + variableModelTest_setUp(); + variable = new Blockly.VariableModel(workspace, 'test', 'test_type', null); assertEquals('test', variable.name); assertEquals('test_type', variable.type); assertNotNull(variable.id_); - variableTest_tearDown(); + variableModelTest_tearDown(); } function testInit_UndefinedId() { - variable = new Blockly.VariableModel('test', 'test_type', undefined); + variableModelTest_setUp(); + variable = new Blockly.VariableModel(workspace, 'test', 'test_type', undefined); assertEquals('test', variable.name); assertEquals('test_type', variable.type); assertNotNull(variable.id_); - variableTest_tearDown(); + variableModelTest_tearDown(); } function testInit_OnlyNameProvided() { - variable = new Blockly.VariableModel('test'); + variableModelTest_setUp(); + variable = new Blockly.VariableModel(workspace, 'test'); assertEquals('test', variable.name); assertEquals('', variable.type); assertNotNull(variable.id_); - variableTest_tearDown(); -} \ No newline at end of file + variableModelTest_tearDown(); +} diff --git a/tests/jsunit/workspace_test.js b/tests/jsunit/workspace_test.js index 5c4bed429..17755f158 100644 --- a/tests/jsunit/workspace_test.js +++ b/tests/jsunit/workspace_test.js @@ -19,8 +19,45 @@ */ 'use strict'; +goog.require('goog.testing'); +goog.require('goog.testing.MockControl'); + +var workspace; +var mockControl_; +Blockly.defineBlocksWithJsonArray([{ + "type": "get_var_block", + "message0": "%1", + "args0": [ + { + "type": "field_variable", + "name": "VAR", + } + ] +}]); + +function workspaceTest_setUp() { + workspace = new Blockly.Workspace(); + mockControl_ = new goog.testing.MockControl(); +} + +function workspaceTest_tearDown() { + mockControl_.$tearDown(); + workspace.dispose(); +} + +/** + * Create a test get_var_block. + * @param {?string} variable_name The string to put into the variable field. + * @return {!Blockly.Block} The created block. + */ +function createMockBlock(variable_name) { + var block = new Blockly.Block(workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue(variable_name); + return block; +} + function test_emptyWorkspace() { - var workspace = new Blockly.Workspace(); + workspaceTest_setUp(); try { assertEquals('Empty workspace (1).', 0, workspace.getTopBlocks(true).length); assertEquals('Empty workspace (2).', 0, workspace.getTopBlocks(false).length); @@ -29,20 +66,20 @@ function test_emptyWorkspace() { assertEquals('Empty workspace (4).', 0, workspace.getTopBlocks(true).length); assertEquals('Empty workspace (5).', 0, workspace.getTopBlocks(false).length); assertEquals('Empty workspace (6).', 0, workspace.getAllBlocks().length); - } finally { - workspace.dispose(); + } + finally { + workspaceTest_tearDown(); } } function test_flatWorkspace() { - var workspace = new Blockly.Workspace(); - var blockA, blockB; + workspaceTest_setUp(); try { - blockA = workspace.newBlock(''); + var blockA = workspace.newBlock(''); assertEquals('One block workspace (1).', 1, workspace.getTopBlocks(true).length); assertEquals('One block workspace (2).', 1, workspace.getTopBlocks(false).length); assertEquals('One block workspace (3).', 1, workspace.getAllBlocks().length); - blockB = workspace.newBlock(''); + var blockB = workspace.newBlock(''); assertEquals('Two block workspace (1).', 2, workspace.getTopBlocks(true).length); assertEquals('Two block workspace (2).', 2, workspace.getTopBlocks(false).length); assertEquals('Two block workspace (3).', 2, workspace.getAllBlocks().length); @@ -55,17 +92,15 @@ function test_flatWorkspace() { assertEquals('Cleared workspace (2).', 0, workspace.getTopBlocks(false).length); assertEquals('Cleared workspace (3).', 0, workspace.getAllBlocks().length); } finally { - blockB && blockB.dispose(); - blockA && blockA.dispose(); - workspace.dispose(); + workspaceTest_tearDown(); } } function test_maxBlocksWorkspace() { - var workspace = new Blockly.Workspace(); - var blockA = workspace.newBlock(''); - var blockB = workspace.newBlock(''); + workspaceTest_setUp(); try { + var blockA = workspace.newBlock(''); + var blockB = workspace.newBlock(''); assertEquals('Infinite capacity.', Infinity, workspace.remainingCapacity()); workspace.options.maxBlocks = 3; assertEquals('Three capacity.', 1, workspace.remainingCapacity()); @@ -78,9 +113,7 @@ function test_maxBlocksWorkspace() { workspace.clear(); assertEquals('Cleared capacity.', 0, workspace.remainingCapacity()); } finally { - blockB.dispose(); - blockA.dispose(); - workspace.dispose(); + workspaceTest_tearDown(); } } @@ -106,10 +139,10 @@ function test_getWorkspaceById() { } function test_getBlockById() { - var workspace = new Blockly.Workspace(); - var blockA = workspace.newBlock(''); - var blockB = workspace.newBlock(''); + workspaceTest_setUp(); try { + var blockA = workspace.newBlock(''); + var blockB = workspace.newBlock(''); assertEquals('Find blockA.', blockA, workspace.getBlockById(blockA.id)); assertEquals('Find blockB.', blockB, workspace.getBlockById(blockB.id)); assertEquals('No block found.', null, @@ -120,8 +153,338 @@ function test_getBlockById() { workspace.clear(); assertEquals('Can\'t find blockB.', null, workspace.getBlockById(blockB.id)); } finally { - blockB.dispose(); - blockA.dispose(); - workspace.dispose(); + workspaceTest_tearDown(); } } + +function test_deleteVariable_InternalTrivial() { + workspaceTest_setUp(); + var var_1 = workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + createMockBlock('name1'); + createMockBlock('name1'); + createMockBlock('name2'); + + workspace.deleteVariableInternal_(var_1); + var variable = workspace.getVariable('name1'); + var block_var_name = workspace.topBlocks_[0].getVars()[0]; + assertNull(variable); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + assertEquals('name2', block_var_name); + workspaceTest_tearDown(); +} + +// TODO(marisaleung): Test the alert for deleting a variable that is a procedure. + +function test_updateVariableStore_TrivialNoClear() { + workspaceTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', + [workspace], [['name1', 'name2']]); + + try { + workspace.updateVariableStore(); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_updateVariableStore_NameNotInvariableMap_NoClear() { + workspaceTest_setUp(); + setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', + [workspace], [['name1']]); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + + try { + workspace.updateVariableStore(); + checkVariableValues(workspace, 'name1', '', '1'); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_updateVariableStore_ClearAndAllInUse() { + workspaceTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', + [workspace], [['name1', 'name2']]); + + try { + workspace.updateVariableStore(true); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_updateVariableStore_ClearAndOneInUse() { + workspaceTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', + [workspace], [['name1']]); + + try { + workspace.updateVariableStore(true); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + var variabe = workspace.getVariable('name2'); + assertNull(variable); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_addTopBlock_TrivialFlyoutIsTrue() { + workspaceTest_setUp(); + workspace.isFlyout = true; + var block = createMockBlock(); + workspace.removeTopBlock(block); + setUpMockMethod(mockControl_, Blockly.Variables, 'allUsedVariables', [block], + [['name1']]); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + + try { + workspace.addTopBlock(block); + checkVariableValues(workspace, 'name1', '', '1'); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_clear_Trivial() { + workspaceTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false], + null); + + try { + workspace.clear(); + var topBlocks_length = workspace.topBlocks_.length; + var varMapLength = Object.keys(workspace.variableMap_.variableMap_).length; + assertEquals(0, topBlocks_length); + assertEquals(0, varMapLength); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_clear_NoVariables() { + workspaceTest_setUp(); + setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false], + null); + + try { + workspace.clear(); + var topBlocks_length = workspace.topBlocks_.length; + var varMapLength = Object.keys(workspace.variableMap_.variableMap_).length; + assertEquals(0, topBlocks_length); + assertEquals(0, varMapLength); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_renameVariable_NoBlocks() { + // Expect 'renameVariable' to create new variable with newName. + workspaceTest_setUp(); + var oldName = 'name1'; + var newName = 'name2'; + // Mocked setGroup to ensure only one call to the mocked genUid. + setUpMockMethod(mockControl_, Blockly.Events, 'setGroup', [true, false], + null); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + + try { + workspace.renameVariable(oldName, newName); + checkVariableValues(workspace, 'name2', '', '1'); + var variable = workspace.getVariable(oldName); + assertNull(variable); + } + finally { + workspaceTest_tearDown(); + } +} + +function test_renameVariable_SameNameNoBlocks() { + // Expect 'renameVariable' to create new variable with newName. + workspaceTest_setUp(); + var name = 'name1'; + workspace.createVariable(name, 'type1', 'id1'); + + workspace.renameVariable(name, name); + checkVariableValues(workspace, name, 'type1', 'id1'); + workspaceTest_tearDown(); +} + +function test_renameVariable_OnlyOldNameBlockExists() { + // Expect 'renameVariable' to change oldName variable name to newName. + workspaceTest_setUp(); + var oldName = 'name1'; + var newName = 'name2'; + workspace.createVariable(oldName, 'type1', 'id1'); + createMockBlock(oldName); + + workspace.renameVariable(oldName, newName); + checkVariableValues(workspace, newName, 'type1', 'id1'); + var variable = workspace.getVariable(oldName); + var block_var_name = workspace.topBlocks_[0].getVars()[0]; + assertNull(variable); + assertEquals(newName, block_var_name); + workspaceTest_tearDown(); +} + +function test_renameVariable_TwoVariablesSameType() { + // Expect 'renameVariable' to change oldName variable name to newName. + // Expect oldName block name to change to newName + workspaceTest_setUp(); + var oldName = 'name1'; + var newName = 'name2'; + workspace.createVariable(oldName, 'type1', 'id1'); + workspace.createVariable(newName, 'type1', 'id2'); + createMockBlock(oldName); + createMockBlock(newName); + + workspace.renameVariable(oldName, newName); + checkVariableValues(workspace, newName, 'type1', 'id2'); + var variable = workspace.getVariable(oldName); + var block_var_name_1 = workspace.topBlocks_[0].getVars()[0]; + var block_var_name_2 = workspace.topBlocks_[1].getVars()[0]; + assertNull(variable); + assertEquals(newName, block_var_name_1); + assertEquals(newName, block_var_name_2); + workspaceTest_tearDown(); +} + +function test_renameVariable_TwoVariablesDifferentType() { + // Expect triggered error because of different types + workspaceTest_setUp(); + var oldName = 'name1'; + var newName = 'name2'; + workspace.createVariable(oldName, 'type1', 'id1'); + workspace.createVariable(newName, 'type2', 'id2'); + createMockBlock(oldName); + createMockBlock(newName); + + try { + workspace.renameVariable(oldName, newName); + fail(); + } catch (e) { + // expected + } + checkVariableValues(workspace, oldName, 'type1', 'id1'); + checkVariableValues(workspace, newName, 'type2', 'id2'); + var block_var_name_1 = workspace.topBlocks_[0].getVars()[0]; + var block_var_name_2 = workspace.topBlocks_[1].getVars()[0]; + assertEquals(oldName, block_var_name_1); + assertEquals(newName, block_var_name_2); + workspaceTest_tearDown(); +} + +function test_renameVariable_OldCase() { + // Expect triggered error because of different types + workspaceTest_setUp(); + var oldCase = 'Name1'; + var newName = 'name1'; + workspace.createVariable(oldCase, 'type1', 'id1'); + createMockBlock(oldCase); + + workspace.renameVariable(oldCase, newName); + checkVariableValues(workspace, newName, 'type1', 'id1'); + var result_oldCase = workspace.getVariable(oldCase).name; + assertNotEquals(oldCase, result_oldCase); + workspaceTest_tearDown(); +} + +function test_renameVariable_TwoVariablesAndOldCase() { + // Expect triggered error because of different types + workspaceTest_setUp(); + var oldName = 'name1'; + var oldCase = 'Name2'; + var newName = 'name2'; + workspace.createVariable(oldName, 'type1', 'id1'); + workspace.createVariable(oldCase, 'type1', 'id2'); + createMockBlock(oldName); + createMockBlock(oldCase); + + workspace.renameVariable(oldName, newName); + + checkVariableValues(workspace, newName, 'type1', 'id2'); + var variable = workspace.getVariable(oldName); + var result_oldCase = workspace.getVariable(oldCase).name; + var block_var_name_1 = workspace.topBlocks_[0].getVars()[0]; + var block_var_name_2 = workspace.topBlocks_[1].getVars()[0]; + assertNull(variable); + assertNotEquals(oldCase, result_oldCase); + assertEquals(newName, block_var_name_1); + assertEquals(newName, block_var_name_2); + workspaceTest_tearDown(); +} + +// Extra testing not required for renameVariableById. It calls renameVariable +// and that has extensive testing. +function test_renameVariableById_TwoVariablesSameType() { + // Expect 'renameVariableById' to change oldName variable name to newName. + // Expect oldName block name to change to newName + workspaceTest_setUp(); + var oldName = 'name1'; + var newName = 'name2'; + workspace.createVariable(oldName, 'type1', 'id1'); + workspace.createVariable(newName, 'type1', 'id2'); + createMockBlock(oldName); + createMockBlock(newName); + + workspace.renameVariableById('id1', newName); + checkVariableValues(workspace, newName, 'type1', 'id2'); + var variable = workspace.getVariable(oldName); + var block_var_name_1 = workspace.topBlocks_[0].getVars()[0]; + var block_var_name_2 = workspace.topBlocks_[1].getVars()[0]; + assertNull(variable); + assertEquals(newName, block_var_name_1); + assertEquals(newName, block_var_name_2); + workspaceTest_tearDown(); +} + +function test_deleteVariable_Trivial() { + workspaceTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type1', 'id2'); + createMockBlock('name1'); + createMockBlock('name2'); + + workspace.deleteVariable('name1'); + checkVariableValues(workspace, 'name2', 'type1', 'id2'); + var variable = workspace.getVariable('name1'); + var block_var_name = workspace.topBlocks_[0].getVars()[0]; + assertNull(variable); + assertEquals('name2', block_var_name); + workspaceTest_tearDown(); +} + +function test_deleteVariableById_Trivial() { + workspaceTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type1', 'id2'); + createMockBlock('name1'); + createMockBlock('name2'); + + workspace.deleteVariableById('id1'); + checkVariableValues(workspace, 'name2', 'type1', 'id2'); + var variable = workspace.getVariable('name1'); + var block_var_name = workspace.topBlocks_[0].getVars()[0]; + assertNull(variable); + assertEquals('name2', block_var_name); + workspaceTest_tearDown(); +} diff --git a/tests/jsunit/workspace_undo_redo_test.js b/tests/jsunit/workspace_undo_redo_test.js new file mode 100644 index 000000000..33dc855d7 --- /dev/null +++ b/tests/jsunit/workspace_undo_redo_test.js @@ -0,0 +1,417 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** + * @fileoverview Tests for Blockly.Workspace.undo. + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +goog.require('goog.events.EventHandler'); +goog.require('goog.testing'); +goog.require('goog.testing.events'); +goog.require('goog.testing.MockControl'); + + +var workspace; +var mockControl_; +var savedFireFunc = Blockly.Events.fire; +Blockly.defineBlocksWithJsonArray([{ + "type": "get_var_block", + "message0": "%1", + "args0": [ + { + "type": "field_variable", + "name": "VAR", + } + ] +}]); + +function temporary_fireEvent(event) { + if (!Blockly.Events.isEnabled()) { + return; + } + Blockly.Events.FIRE_QUEUE_.push(event); + Blockly.Events.fireNow_(); +} + +function undoRedoTest_setUp() { + workspace = new Blockly.Workspace(); + mockControl_ = new goog.testing.MockControl(); + Blockly.Events.fire = temporary_fireEvent; +} + +function undoRedoTest_tearDown() { + mockControl_.$tearDown(); + workspace.dispose(); + Blockly.Events.fire = savedFireFunc; +} + +/** + * Create a test get_var_block. + * @param {string} variableName The string to put into the variable field. + * @return {!Blockly.Block} The created block. + */ +function createMockBlock(variableName) { + var block = new Blockly.Block(workspace, 'get_var_block'); + block.inputList[0].fieldRow[0].setValue(variableName); + return block; +} + +/** + * Check that the top block with the given index contains a variable with + * the given name. + * @param {number} blockIndex The index of the top block. + * @param {string} name The expected name of the variable in the block. + */ +function undoRedoTest_checkBlockVariableName(blockIndex, name) { + var blockVarName = workspace.topBlocks_[blockIndex].getVars()[0]; + assertEquals(name, blockVarName); +} + +function createTwoVarsEmptyType() { + workspace.createVariable('name1', '', 'id1'); + workspace.createVariable('name2', '', 'id2'); +} + +function test_undoCreateVariable_Trivial() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + + workspace.undo(); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + assertNull(workspace.getVariableById('id2')); + workspace.undo(); + assertNull(workspace.getVariableById('id1')); + assertNull(workspace.getVariableById('id2')); + undoRedoTest_tearDown(); +} + +function test_redoAndUndoCreateVariable_Trivial() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + + workspace.undo(); + workspace.undo(true); + + // Expect that variable 'id2' is recreated + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + + workspace.undo(); + workspace.undo(); + workspace.undo(true); + + // Expect that variable 'id1' is recreated + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + assertNull(workspace.getVariableById('id2')); + undoRedoTest_tearDown(); +} + +function test_undoDeleteVariable_NoBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + workspace.deleteVariableById('id1'); + workspace.deleteVariableById('id2'); + + workspace.undo(); + assertNull(workspace.getVariableById('id1')); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + + workspace.undo(); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + undoRedoTest_tearDown(); +} + +function test_undoDeleteVariable_WithBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + createMockBlock('name1'); + createMockBlock('name2'); + workspace.deleteVariableById('id1'); + workspace.deleteVariableById('id2'); + + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name2'); + assertNull(workspace.getVariableById('id1')); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name2'); + undoRedoTest_checkBlockVariableName(1, 'name1'); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + undoRedoTest_tearDown(); +} + +function test_redoAndUndoDeleteVariable_NoBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + workspace.deleteVariableById('id1'); + workspace.deleteVariableById('id2'); + + workspace.undo(); + workspace.undo(true); + // Expect that both variables are deleted + assertNull(workspace.getVariableById('id1')); + assertNull(workspace.getVariableById('id2')); + + workspace.undo(); + workspace.undo(); + workspace.undo(true); + // Expect that variable 'id2' is recreated + assertNull(workspace.getVariableById('id1')); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + undoRedoTest_tearDown(); +} + +function test_redoAndUndoDeleteVariable_WithBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + createMockBlock('name1'); + createMockBlock('name2'); + workspace.deleteVariableById('id1'); + workspace.deleteVariableById('id2'); + + workspace.undo(); + workspace.undo(true); + // Expect that both variables are deleted + assertEquals(0, workspace.topBlocks_.length); + assertNull(workspace.getVariableById('id1')); + assertNull(workspace.getVariableById('id2')); + + workspace.undo(); + workspace.undo(); + workspace.undo(true); + // Expect that variable 'id2' is recreated + undoRedoTest_checkBlockVariableName(0, 'name2'); + assertNull(workspace.getVariableById('id1')); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + undoRedoTest_tearDown(); +} + +function test_redoAndUndoDeleteVariableTwice_NoBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + workspace.deleteVariableById('id1'); + workspace.deleteVariableById('id1'); + + // Check the undoStack only recorded one delete event. + var undoStack = workspace.undoStack_; + assertEquals('var_delete', undoStack[undoStack.length-1].type); + assertNotEquals('var_delete', undoStack[undoStack.length-2].type); + + // undo delete + workspace.undo(); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + + // redo delete + workspace.undo(true); + assertNull(workspace.getVariableById('id1')); + + // redo delete, nothing should happen + workspace.undo(true); + assertNull(workspace.getVariableById('id1')); + undoRedoTest_tearDown(); +} + +function test_redoAndUndoDeleteVariableTwice_WithBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', 'type1', 'id1'); + createMockBlock('name1'); + workspace.deleteVariableById('id1'); + workspace.deleteVariableById('id1'); + + // Check the undoStack only recorded one delete event. + var undoStack = workspace.undoStack_; + assertEquals('var_delete', undoStack[undoStack.length-1].type); + assertEquals('delete', undoStack[undoStack.length-2].type); + assertNotEquals('var_delete', undoStack[undoStack.length-3].type); + + // undo delete + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name1'); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + + // redo delete + workspace.undo(true); + assertEquals(0, workspace.topBlocks_.length); + assertNull(workspace.getVariableById('id1')); + + // redo delete, nothing should happen + workspace.undo(true); + assertEquals(0, workspace.topBlocks_.length); + assertNull(workspace.getVariableById('id1')); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_NeitherVariableExists() { + // Expect that a variable with the name, 'name2', and the generated UUID, + // 'id2', to be created when rename is called. Undo removes this variable + // and redo recreates it. + undoRedoTest_setUp(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, + ['rename_group', 'id2', 'delete_group']); + workspace.renameVariable('name1', 'name2'); + + workspace.undo(); + assertNull(workspace.getVariableById('id2')); + + workspace.undo(true); + checkVariableValues(workspace, 'name2', '', 'id2'); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_OneExists_NoBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', '', 'id1'); + workspace.renameVariable('name1', 'name2'); + + workspace.undo(); + checkVariableValues(workspace, 'name1', '', 'id1'); + assertNull(workspace.getVariable('name2')); + + workspace.undo(true); + checkVariableValues(workspace, 'name2', '', 'id1'); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_OneExists_WithBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', '', 'id1'); + createMockBlock('name1'); + workspace.renameVariable('name1', 'name2'); + + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name1'); + checkVariableValues(workspace, 'name1', '', 'id1'); + assertNull(workspace.getVariable('name2')); + + workspace.undo(true); + checkVariableValues(workspace, 'name2', '', 'id1'); + undoRedoTest_checkBlockVariableName(0, 'name2'); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_BothExist_NoBlocks() { + undoRedoTest_setUp(); + createTwoVarsEmptyType(); + workspace.renameVariable('name1', 'name2'); + + workspace.undo(); + checkVariableValues(workspace, 'name1', '', 'id1'); + checkVariableValues(workspace, 'name2', '', 'id2'); + + workspace.undo(true); + checkVariableValues(workspace, 'name2', '', 'id2'); + assertNull(workspace.getVariable('name1')); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_BothExist_WithBlocks() { + undoRedoTest_setUp(); + createTwoVarsEmptyType(); + createMockBlock('name1'); + createMockBlock('name2'); + workspace.renameVariable('name1', 'name2'); + + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name1'); + undoRedoTest_checkBlockVariableName(1, 'name2'); + checkVariableValues(workspace, 'name1', '', 'id1'); + checkVariableValues(workspace, 'name2', '', 'id2'); + + workspace.undo(true); + undoRedoTest_checkBlockVariableName(0, 'name2'); + undoRedoTest_checkBlockVariableName(1, 'name2'); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_BothExistCaseChange_NoBlocks() { + undoRedoTest_setUp(); + createTwoVarsEmptyType(); + workspace.renameVariable('name1', 'Name2'); + + workspace.undo(); + checkVariableValues(workspace, 'name1', '', 'id1'); + checkVariableValues(workspace, 'name2', '', 'id2'); + + workspace.undo(true); + checkVariableValues(workspace, 'Name2', '', 'id2'); + assertNull(workspace.getVariable('name1')); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_BothExistCaseChange_WithBlocks() { + undoRedoTest_setUp(); + createTwoVarsEmptyType(); + createMockBlock('name1'); + createMockBlock('name2'); + workspace.renameVariable('name1', 'Name2'); + + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name1'); + undoRedoTest_checkBlockVariableName(1, 'name2'); + checkVariableValues(workspace, 'name1', '', 'id1'); + checkVariableValues(workspace, 'name2', '', 'id2'); + + workspace.undo(true); + checkVariableValues(workspace, 'Name2', '', 'id2'); + assertNull(workspace.getVariable('name1')); + undoRedoTest_checkBlockVariableName(0, 'Name2'); + undoRedoTest_checkBlockVariableName(1, 'Name2'); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_OnlyCaseChange_NoBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', '', 'id1'); + workspace.renameVariable('name1', 'Name1'); + + workspace.undo(); + checkVariableValues(workspace, 'name1', '', 'id1'); + + workspace.undo(true); + checkVariableValues(workspace, 'Name1', '', 'id1'); + undoRedoTest_tearDown(); +} + +function test_undoRedoRenameVariable_OnlyCaseChange_WithBlocks() { + undoRedoTest_setUp(); + workspace.createVariable('name1', '', 'id1'); + createMockBlock('name1'); + workspace.renameVariable('name1', 'Name1'); + + workspace.undo(); + undoRedoTest_checkBlockVariableName(0, 'name1'); + checkVariableValues(workspace, 'name1', '', 'id1'); + + workspace.undo(true); + checkVariableValues(workspace, 'Name1', '', 'id1'); + undoRedoTest_checkBlockVariableName(0, 'Name1'); + undoRedoTest_tearDown(); +} diff --git a/tests/jsunit/xml_test.js b/tests/jsunit/xml_test.js index d77ed9343..4651255f9 100644 --- a/tests/jsunit/xml_test.js +++ b/tests/jsunit/xml_test.js @@ -19,6 +19,11 @@ */ 'use strict'; +goog.require('goog.testing'); +goog.require('goog.testing.MockControl'); + +var mockControl_; +var workspace; var XML_TEXT = ['', ' ', ' ', @@ -46,6 +51,77 @@ var XML_TEXT = ['', ' ', ''].join('\n'); +function xmlTest_setUp() { + workspace = new Blockly.Workspace(); + mockControl_ = new goog.testing.MockControl(); +} + +function xmlTest_setUpWithMockBlocks() { + xmlTest_setUp(); + Blockly.defineBlocksWithJsonArray([{ + 'type': 'field_variable_test_block', + 'message0': '%1', + 'args0': [ + { + 'type': 'field_variable', + 'name': 'VAR', + 'variable': 'item' + } + ], + }]); +} + +function xmlTest_tearDown() { + mockControl_.$tearDown(); + workspace.dispose(); +} + +function xmlTest_tearDownWithMockBlocks() { + xmlTest_tearDown(); + delete Blockly.Blocks.field_variable_test_block; +} + +/** + * Check the values of the non variable field dom. + * @param {!Element} fieldDom The xml dom of the non variable field. + * @param {!string} name The expected name of the variable. + * @param {!string} text The expected text of the variable. + */ +function xmlTest_checkNonVariableField(fieldDom, name, text) { + assertEquals(text, fieldDom.textContent); + assertEquals(name, fieldDom.getAttribute('name')); + assertNull(fieldDom.getAttribute('id')); + assertNull(fieldDom.getAttribute('variableType')); +} + +/** + * Check the values of the variable field DOM. + * @param {!Element} fieldDom The xml dom of the variable field. + * @param {!string} name The expected name of the variable. + * @param {!string} type The expected type of the variable. + * @param {!string} id The expected id of the variable. + * @param {!string} text The expected text of the variable. + */ +function xmlTest_checkVariableFieldDomValues(fieldDom, name, type, id, text) { + assertEquals(name, fieldDom.getAttribute('name')); + assertEquals(type, fieldDom.getAttribute('variableType')); + assertEquals(id, fieldDom.getAttribute('id')); + assertEquals(text, fieldDom.textContent); +} + +/** + * Check the values of the variable DOM. + * @param {!Element} variableDom The xml dom of the variable. + * @param {!string} type The expected type of the variable. + * @param {!string} id The expected id of the variable. + * @param {!string} text The expected text of the variable. + */ +function xmlTest_checkVariableDomValues(variableDom, type, id, text) { + assertEquals(type, variableDom.getAttribute('type')); + assertEquals(id, variableDom.getAttribute('id')); + assertEquals(text, variableDom.textContent); +} + function test_textToDom() { var dom = Blockly.Xml.textToDom(XML_TEXT); assertEquals('XML tag', 'xml', dom.nodeName); @@ -59,31 +135,116 @@ function test_domToText() { text.replace(/\s+/g, '')); } -function test_domToWorkspace() { - Blockly.Blocks.test_block = { - init: function() { - this.jsonInit({ - message0: 'test', - }); - } - }; - - var workspace = new Blockly.Workspace(); +function test_domToWorkspace_BackwardCompatibility() { + // Expect that workspace still loads without serialized variables. + xmlTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '1']); try { var dom = Blockly.Xml.textToDom( - '' + - ' ' + + '' + + ' ' + + ' name1' + ' ' + ''); Blockly.Xml.domToWorkspace(dom, workspace); assertEquals('Block count', 1, workspace.getAllBlocks().length); + checkVariableValues(workspace, 'name1', '', '1'); } finally { - delete Blockly.Blocks.test_block; + xmlTest_tearDownWithMockBlocks(); + } +} +function test_domToWorkspace_VariablesAtTop() { + // Expect that unused variables are preserved. + xmlTest_setUpWithMockBlocks(); + try { + var dom = Blockly.Xml.textToDom( + '' + + ' ' + + ' name1' + + ' name2' + + ' name3' + + ' ' + + ' ' + + ' name3' + + ' ' + + ''); + Blockly.Xml.domToWorkspace(dom, workspace); + assertEquals('Block count', 1, workspace.getAllBlocks().length); + checkVariableValues(workspace, 'name1', 'type1', 'id1'); + checkVariableValues(workspace, 'name2', 'type2', 'id2'); + checkVariableValues(workspace, 'name3', '', 'id3'); + } finally { + xmlTest_tearDownWithMockBlocks(); + } +} + +function test_domToWorkspace_VariablesAtTop_DuplicateVariablesTag() { + // Expect thrown Error because of duplicate 'variables' tag + xmlTest_setUpWithMockBlocks(); + try { + var dom = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ''); + Blockly.Xml.domToWorkspace(dom, workspace); + fail(); + } + catch (e) { + // expected + } finally { + xmlTest_tearDownWithMockBlocks(); + } +} + +function test_domToWorkspace_VariablesAtTop_MissingType() { + // Expect thrown error when a variable tag is missing the type attribute. + workspace = new Blockly.Workspace(); + try { + var dom = Blockly.Xml.textToDom( + '' + + ' ' + + ' name1' + + ' ' + + ' ' + + ' name3' + + ' ' + + ''); + Blockly.Xml.domToWorkspace(dom, workspace); + fail(); + } catch (e) { + // expected + } finally { workspace.dispose(); } } +function test_domToWorkspace_VariablesAtTop_MismatchBlockType() { + // Expect thrown error when the serialized type of a variable does not match + // the type of a variable field that references it. + xmlTest_setUpWithMockBlocks(); + try { + var dom = Blockly.Xml.textToDom( + '' + + ' ' + + ' name1' + + ' ' + + ' ' + + ' name1' + + ' ' + + ''); + Blockly.Xml.domToWorkspace(dom, workspace); + fail(); + } catch (e) { + // expected + } finally { + xmlTest_tearDownWithMockBlocks(); + } +} + function test_domToPrettyText() { var dom = Blockly.Xml.textToDom(XML_TEXT); var text = Blockly.Xml.domToPrettyText(dom); @@ -110,7 +271,7 @@ function test_appendDomToWorkspace() { ' ' + ' ' + ''); - var workspace = new Blockly.Workspace(); + workspace = new Blockly.Workspace(); Blockly.Xml.appendDomToWorkspace(dom, workspace); assertEquals('Block count', 1, workspace.getAllBlocks().length); var newBlockIds = Blockly.Xml.appendDomToWorkspace(dom, workspace); @@ -121,3 +282,85 @@ function test_appendDomToWorkspace() { workspace.dispose(); } } + +function test_blockToDom_fieldToDom_trivial() { + xmlTest_setUpWithMockBlocks(); + workspace.createVariable('name1', 'type1', 'id1'); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + block.inputList[0].fieldRow[0].setValue('name1'); + var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; + xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', 'type1', 'id1', + 'name1'); + xmlTest_tearDownWithMockBlocks(); +} + +function test_blockToDom_fieldToDom_defaultCase() { + xmlTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '1']); + workspace.createVariable('name1'); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + block.inputList[0].fieldRow[0].setValue('name1'); + var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; + // Expect type is '' and id is '1' since we don't specify type and id. + xmlTest_checkVariableFieldDomValues(resultFieldDom, 'VAR', '', '1', 'name1'); + xmlTest_tearDownWithMockBlocks(); +} + +function test_blockToDom_fieldToDom_notAFieldVariable() { + Blockly.defineBlocksWithJsonArray([{ + "type": "field_angle_test_block", + "message0": "%1", + "args0": [ + { + "type": "field_angle", + "name": "VAR", + "angle": 90 + } + ], + }]); + xmlTest_setUpWithMockBlocks(); + var block = new Blockly.Block(workspace, 'field_angle_test_block'); + var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; + xmlTest_checkNonVariableField(resultFieldDom, 'VAR', '90'); + delete Blockly.Blocks.field_angle_block; + xmlTest_tearDownWithMockBlocks(); +} + +function test_variablesToDom_oneVariable() { + xmlTest_setUp(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + + workspace.createVariable('name1'); + var resultDom = Blockly.Xml.variablesToDom(workspace.getAllVariables()); + assertEquals(1, resultDom.children.length); + var resultVariableDom = resultDom.children[0]; + assertEquals('name1', resultVariableDom.textContent); + assertEquals('', resultVariableDom.getAttribute('type')); + assertEquals('1', resultVariableDom.getAttribute('id')); + xmlTest_tearDown(); +} + +function test_variablesToDom_twoVariables_oneBlock() { + xmlTest_setUpWithMockBlocks(); + + workspace.createVariable('name1', 'type1', 'id1'); + workspace.createVariable('name2', 'type2', 'id2'); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + block.inputList[0].fieldRow[0].setValue('name1'); + + var resultDom = Blockly.Xml.variablesToDom(workspace.getAllVariables()); + assertEquals(2, resultDom.children.length); + xmlTest_checkVariableDomValues(resultDom.children[0], 'type1', 'id1', + 'name1'); + xmlTest_checkVariableDomValues(resultDom.children[1], 'type2', 'id2', + 'name2'); + xmlTest_tearDownWithMockBlocks(); +} + +function test_variablesToDom_noVariables() { + xmlTest_setUp(); + workspace.createVariable('name1'); + var resultDom = Blockly.Xml.variablesToDom(workspace.getAllVariables()); + assertEquals(1, resultDom.children.length); + xmlTest_tearDown(); +} diff --git a/tests/playground.html b/tests/playground.html index a8bcb4a8f..f062bf542 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -241,8 +241,8 @@ function fakeDrag(id, dx, dy, opt_workspace) { blockToDrag.onMouseUp_(mouseUpEvent); setTimeout(fakeDragWrapper(), 100); - }, 30); - }, 30); + }, 100); + }, 100); }; function fakeDragWrapper() {