diff --git a/.gitignore b/.gitignore index 3277b7174..c546855b8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ npm-debug.log tests/compile/main_compressed.js tests/compile/*compiler*.jar local_build/*compiler*.jar -local_build/local_blockly_compressed.js +local_build/local_blockly_compressed.js \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index de6192206..82b96f3d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,12 @@ matrix: apt: packages: - google-chrome-stable - - os: osx - node_js: stable - osx_image: xcode8.3 + # TODO (#2114): reenable osx build. + # - os: osx + # node_js: stable + # osx_image: xcode8.3 + # addons: + # firefox: latest before_script: # Symlink closure library used by test/jsunit diff --git a/blockly_accessible_compressed.js b/blockly_accessible_compressed.js index 4e9e2fcc8..4ac170080 100644 --- a/blockly_accessible_compressed.js +++ b/blockly_accessible_compressed.js @@ -5,7 +5,7 @@ var $jscomp=$jscomp||{};$jscomp.scope={};var COMPILED=!0,goog=goog||{};goog.glob goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||"undefined"==typeof c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&goog.isDef(b)?c[d]=b:c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}}; goog.define=function(a,b){if(!COMPILED){var c=goog.global.CLOSURE_UNCOMPILED_DEFINES,d=goog.global.CLOSURE_DEFINES;c&&void 0===c.nodeType&&Object.prototype.hasOwnProperty.call(c,a)?b=c[a]:d&&void 0===d.nodeType&&Object.prototype.hasOwnProperty.call(d,a)&&(b=d[a])}goog.exportPath_(a,b)};goog.DEBUG=!1;goog.LOCALE="en";goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG;goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1; goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide cannot be used within a module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)};goog.constructNamespace_=function(a,b){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var c=a;(c=c.substring(0,c.lastIndexOf(".")))&&!goog.getObjectByName(c);)goog.implicitNamespaces_[c]=!0}goog.exportPath_(a,b)}; -goog.getScriptNonce=function(){null===goog.cspNonce_&&(goog.cspNonce_=goog.getScriptNonce_(goog.global.document)||"");return goog.cspNonce_};goog.NONCE_PATTERN_=/^[\w+/_-]+[=]{0,2}$/;goog.cspNonce_=null;goog.getScriptNonce_=function(a){return(a=a.querySelector&&a.querySelector("script[nonce]"))&&(a=a.nonce||a.getAttribute("nonce"))&&goog.NONCE_PATTERN_.test(a)?a:null};goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/; +goog.getScriptNonce=function(a){if(a&&a!=goog.global)return goog.getScriptNonce_(a.document);null===goog.cspNonce_&&(goog.cspNonce_=goog.getScriptNonce_(goog.global.document));return goog.cspNonce_};goog.NONCE_PATTERN_=/^[\w+/_-]+[=]{0,2}$/;goog.cspNonce_=null;goog.getScriptNonce_=function(a){return(a=a.querySelector&&a.querySelector("script[nonce]"))&&(a=a.nonce||a.getAttribute("nonce"))&&goog.NONCE_PATTERN_.test(a)?a:""};goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/; goog.module=function(a){if(!goog.isString(a)||!a||-1==a.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInGoogModuleLoader_())throw Error("Module "+a+" has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide."); if(goog.moduleLoaderState_.moduleName)throw Error("goog.module may only be called once per module.");goog.moduleLoaderState_.moduleName=a;if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a]}};goog.module.get=function(a){return goog.module.getInternal_(a)}; goog.module.getInternal_=function(a){if(!COMPILED){if(a in goog.loadedModules_)return goog.loadedModules_[a].exports;if(!goog.implicitNamespaces_[a])return a=goog.getObjectByName(a),null!=a?a:null}return null};goog.ModuleType={ES6:"es6",GOOG:"goog"};goog.moduleLoaderState_=null;goog.isInModuleLoader_=function(){return goog.isInGoogModuleLoader_()||goog.isInEs6ModuleLoader_()};goog.isInGoogModuleLoader_=function(){return!!goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.GOOG}; @@ -129,8 +129,8 @@ goog.color.prependZeroIfNecessaryHelper=function(a){return 1==a.length?"0"+a:a}; goog.color.hsvToRgb=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=c;else{var g=Math.floor(a/60),h=a/60-g;a=c*(1-b);var k=c*(1-b*h);b=c*(1-b*(1-h));switch(g){case 1:d=k;e=c;f=a;break;case 2:d=a;e=c;f=b;break;case 3:d=a;e=k;f=c;break;case 4:d=b;e=a;f=c;break;case 5:d=c;e=a;f=k;break;case 6:case 0:d=c,e=b,f=a}}return[Math.floor(d),Math.floor(e),Math.floor(f)]}; goog.color.rgbToHsv=function(a,b,c){var d=Math.max(Math.max(a,b),c),e=Math.min(Math.min(a,b),c);if(e==d)e=a=0;else{var f=d-e;e=f/d;a=60*(a==d?(b-c)/f:b==d?2+(c-a)/f:4+(a-b)/f);0>a&&(a+=360);360=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(c*a[0]+(1-c)*b[0]),Math.round(c*a[1]+(1-c)*b[1]),Math.round(c*a[2]+(1-c)*b[2])]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)};goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)}; -goog.color.highContrast=function(a,b){for(var c=[],d=0;d=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2]))]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)}; +goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)};goog.color.highContrast=function(a,b){for(var c=[],d=0;d=a.keyCode)a.keyCode=-1}catch(b){}};goog.events.BrowserEvent.prototype.getBrowserEvent=function(){return this.event_}; @@ -290,13 +290,14 @@ goog.functions.create=function(a,b){var c=function(){};c.prototype=a.prototype;c goog.functions.debounce=function(a,b,c){var d=0;return function(e){goog.global.clearTimeout(d);var f=arguments;d=goog.global.setTimeout(function(){a.apply(c,f)},b)}};goog.functions.throttle=function(a,b,c){var d=0,e=!1,f=[],g=function(){d=0;e&&(e=!1,h())},h=function(){d=goog.global.setTimeout(g,b);a.apply(c,f)};return function(a){f=arguments;d?e=!0:h()}};goog.functions.rateLimit=function(a,b,c){var d=0,e=function(){d=0};return function(f){d||(d=goog.global.setTimeout(e,b),a.apply(c,arguments))}};goog.dom.tags={};goog.dom.tags.VOID_TAGS_={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0};goog.dom.tags.isVoidTag=function(a){return!0===goog.dom.tags.VOID_TAGS_[a]};goog.string.TypedString=function(){};goog.string.Const=function(a,b){this.stringConstValueWithSecurityContract__googStringSecurityPrivate_=a===goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_&&b||"";this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_=goog.string.Const.TYPE_MARKER_};goog.string.Const.prototype.implementsGoogStringTypedString=!0;goog.string.Const.prototype.getTypedStringValue=function(){return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_}; goog.string.Const.prototype.toString=function(){return"Const{"+this.stringConstValueWithSecurityContract__googStringSecurityPrivate_+"}"};goog.string.Const.unwrap=function(a){if(a instanceof goog.string.Const&&a.constructor===goog.string.Const&&a.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_===goog.string.Const.TYPE_MARKER_)return a.stringConstValueWithSecurityContract__googStringSecurityPrivate_;goog.asserts.fail("expected object of type Const, got '"+a+"'");return"type_error:Const"}; goog.string.Const.from=function(a){return new goog.string.Const(goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_,a)};goog.string.Const.TYPE_MARKER_={};goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_={};goog.string.Const.EMPTY=goog.string.Const.from("");goog.html={};goog.html.SafeScript=function(){this.privateDoNotAccessOrElseSafeScriptWrappedValue_="";this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeScript.prototype.implementsGoogStringTypedString=!0;goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={};goog.html.SafeScript.fromConstant=function(a){a=goog.string.Const.unwrap(a);return 0===a.length?goog.html.SafeScript.EMPTY:goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(a)}; -goog.html.SafeScript.fromConstantAndArgs=function(a,b){for(var c=[],d=1;da?goog.i18n.bidi.Dir.RTL:b?null:goog.i18n.bidi.Dir.NEUTRAL:null==a?null:a?goog.i18n.bidi.Dir.RTL:goog.i18n.bidi.Dir.LTR};goog.i18n.bidi.ltrChars_="A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0900-\u1fff\u200e\u2c00-\ud801\ud804-\ud839\ud83c-\udbff\uf900-\ufb1c\ufe00-\ufe6f\ufefd-\uffff";goog.i18n.bidi.rtlChars_="\u0591-\u06ef\u06fa-\u08ff\u200f\ud802-\ud803\ud83a-\ud83b\ufb1d-\ufdff\ufe70-\ufefc"; goog.i18n.bidi.htmlSkipReg_=/<[^>]*>|&[^;]+;/g;goog.i18n.bidi.stripHtmlIfNeeded_=function(a,b){return b?a.replace(goog.i18n.bidi.htmlSkipReg_,""):a};goog.i18n.bidi.rtlCharReg_=new RegExp("["+goog.i18n.bidi.rtlChars_+"]");goog.i18n.bidi.ltrCharReg_=new RegExp("["+goog.i18n.bidi.ltrChars_+"]");goog.i18n.bidi.hasAnyRtl=function(a,b){return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.hasRtlChar=goog.i18n.bidi.hasAnyRtl; @@ -304,7 +305,7 @@ goog.i18n.bidi.hasAnyLtr=function(a,b){return goog.i18n.bidi.ltrCharReg_.test(go goog.i18n.bidi.ltrDirCheckRe_=new RegExp("^[^"+goog.i18n.bidi.rtlChars_+"]*["+goog.i18n.bidi.ltrChars_+"]");goog.i18n.bidi.rtlDirCheckRe_=new RegExp("^[^"+goog.i18n.bidi.ltrChars_+"]*["+goog.i18n.bidi.rtlChars_+"]");goog.i18n.bidi.startsWithRtl=function(a,b){return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isRtlText=goog.i18n.bidi.startsWithRtl; goog.i18n.bidi.startsWithLtr=function(a,b){return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isLtrText=goog.i18n.bidi.startsWithLtr;goog.i18n.bidi.isRequiredLtrRe_=/^http:\/\/.*/;goog.i18n.bidi.isNeutralText=function(a,b){a=goog.i18n.bidi.stripHtmlIfNeeded_(a,b);return goog.i18n.bidi.isRequiredLtrRe_.test(a)||!goog.i18n.bidi.hasAnyLtr(a)&&!goog.i18n.bidi.hasAnyRtl(a)}; goog.i18n.bidi.ltrExitDirCheckRe_=new RegExp("["+goog.i18n.bidi.ltrChars_+"][^"+goog.i18n.bidi.rtlChars_+"]*$");goog.i18n.bidi.rtlExitDirCheckRe_=new RegExp("["+goog.i18n.bidi.rtlChars_+"][^"+goog.i18n.bidi.ltrChars_+"]*$");goog.i18n.bidi.endsWithLtr=function(a,b){return goog.i18n.bidi.ltrExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isLtrExitText=goog.i18n.bidi.endsWithLtr; -goog.i18n.bidi.endsWithRtl=function(a,b){return goog.i18n.bidi.rtlExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isRtlExitText=goog.i18n.bidi.endsWithRtl;goog.i18n.bidi.rtlLocalesRe_=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;goog.i18n.bidi.isRtlLanguage=function(a){return goog.i18n.bidi.rtlLocalesRe_.test(a)};goog.i18n.bidi.bracketGuardTextRe_=/(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; +goog.i18n.bidi.endsWithRtl=function(a,b){return goog.i18n.bidi.rtlExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isRtlExitText=goog.i18n.bidi.endsWithRtl;goog.i18n.bidi.rtlLocalesRe_=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Nkoo|Rohg|Thaa))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;goog.i18n.bidi.isRtlLanguage=function(a){return goog.i18n.bidi.rtlLocalesRe_.test(a)};goog.i18n.bidi.bracketGuardTextRe_=/(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; goog.i18n.bidi.guardBracketInText=function(a,b){b=(void 0===b?goog.i18n.bidi.hasAnyRtl(a):b)?goog.i18n.bidi.Format.RLM:goog.i18n.bidi.Format.LRM;return a.replace(goog.i18n.bidi.bracketGuardTextRe_,b+"$&"+b)};goog.i18n.bidi.enforceRtlInHtml=function(a){return"<"==a.charAt(0)?a.replace(/<\w+/,"$& dir=rtl"):"\n"+a+""};goog.i18n.bidi.enforceRtlInText=function(a){return goog.i18n.bidi.Format.RLE+a+goog.i18n.bidi.Format.PDF}; goog.i18n.bidi.enforceLtrInHtml=function(a){return"<"==a.charAt(0)?a.replace(/<\w+/,"$& dir=ltr"):"\n"+a+""};goog.i18n.bidi.enforceLtrInText=function(a){return goog.i18n.bidi.Format.LRE+a+goog.i18n.bidi.Format.PDF};goog.i18n.bidi.dimensionsRe_=/:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g;goog.i18n.bidi.leftRe_=/left/gi;goog.i18n.bidi.rightRe_=/right/gi;goog.i18n.bidi.tempRe_=/%%%%/g; goog.i18n.bidi.mirrorCSS=function(a){return a.replace(goog.i18n.bidi.dimensionsRe_,":$1 $4 $3 $2").replace(goog.i18n.bidi.leftRe_,"%%%%").replace(goog.i18n.bidi.rightRe_,goog.i18n.bidi.LEFT).replace(goog.i18n.bidi.tempRe_,goog.i18n.bidi.RIGHT)};goog.i18n.bidi.doubleQuoteSubstituteRe_=/([\u0591-\u05f2])"/g;goog.i18n.bidi.singleQuoteSubstituteRe_=/([\u0591-\u05f2])'/g; @@ -317,9 +318,10 @@ goog.html.TrustedResourceUrl.prototype.cloneWithParams=function(a,b){var c=goog. goog.DEBUG&&(goog.html.TrustedResourceUrl.prototype.toString=function(){return"TrustedResourceUrl{"+this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_+"}"}); goog.html.TrustedResourceUrl.unwrap=function(a){if(a instanceof goog.html.TrustedResourceUrl&&a.constructor===goog.html.TrustedResourceUrl&&a.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;goog.asserts.fail("expected object of type TrustedResourceUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:TrustedResourceUrl"}; goog.html.TrustedResourceUrl.format=function(a,b){var c=goog.string.Const.unwrap(a);if(!goog.html.TrustedResourceUrl.BASE_URL_.test(c))throw Error("Invalid TrustedResourceUrl format: "+c);a=c.replace(goog.html.TrustedResourceUrl.FORMAT_MARKER_,function(a,e){if(!Object.prototype.hasOwnProperty.call(b,e))throw Error('Found marker, "'+e+'", in format string, "'+c+'", but no valid label mapping found in args: '+JSON.stringify(b));a=b[e];return a instanceof goog.string.Const?goog.string.Const.unwrap(a): -encodeURIComponent(String(a))});return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.TrustedResourceUrl.FORMAT_MARKER_=/%{(\w+)}/g;goog.html.TrustedResourceUrl.BASE_URL_=/^(?:https:)?\/\/[0-9a-z.:[\]-]+\/|^\/[^\/\\]|^about:blank#/i;goog.html.TrustedResourceUrl.URL_PARAM_PARSER_=/^([^?#]*)(\?[^#]*)?(#[\s\S]*)?/;goog.html.TrustedResourceUrl.formatWithParams=function(a,b,c,d){return goog.html.TrustedResourceUrl.format(a,b).cloneWithParams(c,d)}; -goog.html.TrustedResourceUrl.fromConstant=function(a){return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))};goog.html.TrustedResourceUrl.fromConstants=function(a){for(var b="",c=0;ca.length?"&":"")+encodeURIComponent(d)+"="+encodeURIComponent(String(g)))}}return b};goog.html.SafeUrl=function(){this.privateDoNotAccessOrElseSafeHtmlWrappedValue_="";this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeUrl.INNOCUOUS_STRING="about:invalid#zClosurez";goog.html.SafeUrl.prototype.implementsGoogStringTypedString=!0;goog.html.SafeUrl.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_}; goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString=!0;goog.html.SafeUrl.prototype.getDirection=function(){return goog.i18n.bidi.Dir.LTR};goog.DEBUG&&(goog.html.SafeUrl.prototype.toString=function(){return"SafeUrl{"+this.privateDoNotAccessOrElseSafeHtmlWrappedValue_+"}"}); goog.html.SafeUrl.unwrap=function(a){if(a instanceof goog.html.SafeUrl&&a.constructor===goog.html.SafeUrl&&a.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseSafeHtmlWrappedValue_;goog.asserts.fail("expected object of type SafeUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:SafeUrl"};goog.html.SafeUrl.fromConstant=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))}; goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))$/i;goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.DATA_URL_PATTERN_=/^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; @@ -329,7 +331,7 @@ goog.html.SafeUrl.fromSmsUrl=function(a){goog.string.caseInsensitiveStartsWith(a goog.html.SafeUrl.sanitizeChromeExtensionUrl=function(a,b){return goog.html.SafeUrl.sanitizeExtensionUrl_(/^chrome-extension:\/\/([^\/]+)\//,a,b)};goog.html.SafeUrl.sanitizeFirefoxExtensionUrl=function(a,b){return goog.html.SafeUrl.sanitizeExtensionUrl_(/^moz-extension:\/\/([^\/]+)\//,a,b)};goog.html.SafeUrl.sanitizeEdgeExtensionUrl=function(a,b){return goog.html.SafeUrl.sanitizeExtensionUrl_(/^ms-browser-extension:\/\/([^\/]+)\//,a,b)}; goog.html.SafeUrl.sanitizeExtensionUrl_=function(a,b,c){(a=a.exec(b))?(a=a[1],-1==(c instanceof goog.string.Const?[goog.string.Const.unwrap(c)]:c.map(function(a){return goog.string.Const.unwrap(a)})).indexOf(a)&&(b=goog.html.SafeUrl.INNOCUOUS_STRING)):b=goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b)};goog.html.SafeUrl.fromTrustedResourceUrl=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.html.TrustedResourceUrl.unwrap(a))}; goog.html.SAFE_URL_PATTERN_=/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;goog.html.SafeUrl.SAFE_URL_PATTERN=goog.html.SAFE_URL_PATTERN_;goog.html.SafeUrl.sanitize=function(a){if(a instanceof goog.html.SafeUrl)return a;a="object"==typeof a&&a.implementsGoogStringTypedString?a.getTypedStringValue():String(a);goog.html.SAFE_URL_PATTERN_.test(a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; -goog.html.SafeUrl.sanitizeAssertUnchanged=function(a){if(a instanceof goog.html.SafeUrl)return a;a="object"==typeof a&&a.implementsGoogStringTypedString?a.getTypedStringValue():String(a);goog.asserts.assert(goog.html.SAFE_URL_PATTERN_.test(a))||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={}; +goog.html.SafeUrl.sanitizeAssertUnchanged=function(a){if(a instanceof goog.html.SafeUrl)return a;a="object"==typeof a&&a.implementsGoogStringTypedString?a.getTypedStringValue():String(a);goog.asserts.assert(goog.html.SAFE_URL_PATTERN_.test(a),"%s does not match the safe URL pattern",a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={}; goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse=function(a){var b=new goog.html.SafeUrl;b.privateDoNotAccessOrElseSafeHtmlWrappedValue_=a;return b};goog.html.SafeUrl.ABOUT_BLANK=goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse("about:blank");goog.html.SafeStyle=function(){this.privateDoNotAccessOrElseSafeStyleWrappedValue_="";this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeStyle.prototype.implementsGoogStringTypedString=!0;goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={}; goog.html.SafeStyle.fromConstant=function(a){a=goog.string.Const.unwrap(a);if(0===a.length)return goog.html.SafeStyle.EMPTY;goog.html.SafeStyle.checkStyle_(a);goog.asserts.assert(goog.string.endsWith(a,";"),"Last character of style string is not ';': "+a);goog.asserts.assert(goog.string.contains(a,":"),"Style string must contain at least one ':', to specify a \"name: value\" pair: "+a);return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SafeStyle.checkStyle_=function(a){goog.asserts.assert(!/[<>]/.test(a),"Forbidden characters in style string: "+a)};goog.html.SafeStyle.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeStyleWrappedValue_};goog.DEBUG&&(goog.html.SafeStyle.prototype.toString=function(){return"SafeStyle{"+this.privateDoNotAccessOrElseSafeStyleWrappedValue_+"}"}); @@ -587,8 +589,9 @@ goog.events.KeyHandler.prototype.handleKeyDown_=function(a){(goog.userAgent.WEBK a.keyCode!=goog.events.KeyCodes.META&&(this.lastKey_=goog.events.KeyCodes.META));goog.events.KeyHandler.USES_KEYDOWN_&&!goog.events.KeyCodes.firesKeyPressEvent(a.keyCode,this.lastKey_,a.shiftKey,a.ctrlKey,a.altKey,a.metaKey)?this.handleEvent(a):(this.keyCode_=goog.events.KeyCodes.normalizeKeyCode(a.keyCode),goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_&&(this.altKey_=a.altKey))};goog.events.KeyHandler.prototype.resetState=function(){this.keyCode_=this.lastKey_=-1}; goog.events.KeyHandler.prototype.handleKeyup_=function(a){this.resetState();this.altKey_=a.altKey}; goog.events.KeyHandler.prototype.handleEvent=function(a){var b=a.getBrowserEvent(),c=b.altKey;if(goog.userAgent.IE&&a.type==goog.events.EventType.KEYPRESS){var d=this.keyCode_;var e=d!=goog.events.KeyCodes.ENTER&&d!=goog.events.KeyCodes.ESC?b.keyCode:0}else(goog.userAgent.WEBKIT||goog.userAgent.EDGE)&&a.type==goog.events.EventType.KEYPRESS?(d=this.keyCode_,e=0<=b.charCode&&63232>b.charCode&&goog.events.KeyCodes.isCharacterKey(d)?b.charCode:0):goog.userAgent.OPERA&&!goog.userAgent.WEBKIT?(d=this.keyCode_, -e=goog.events.KeyCodes.isCharacterKey(d)?b.keyCode:0):(d=b.keyCode||this.keyCode_,e=b.charCode||0,goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_&&a.type==goog.events.EventType.KEYPRESS&&(c=this.altKey_),goog.userAgent.MAC&&e==goog.events.KeyCodes.QUESTION_MARK&&d==goog.events.KeyCodes.WIN_KEY&&(d=goog.events.KeyCodes.SLASH));var f=d=goog.events.KeyCodes.normalizeKeyCode(d);d?63232<=d&&d in goog.events.KeyHandler.safariKey_?f=goog.events.KeyHandler.safariKey_[d]:25==d&&a.shiftKey&&(f=9):b.keyIdentifier&& -b.keyIdentifier in goog.events.KeyHandler.keyIdentifier_&&(f=goog.events.KeyHandler.keyIdentifier_[b.keyIdentifier]);goog.userAgent.GECKO&&goog.events.KeyHandler.USES_KEYDOWN_&&a.type==goog.events.EventType.KEYPRESS&&!goog.events.KeyCodes.firesKeyPressEvent(f,this.lastKey_,a.shiftKey,a.ctrlKey,c,a.metaKey)||(a=f==this.lastKey_,this.lastKey_=f,b=new goog.events.KeyEvent(f,e,a,b),b.altKey=c,this.dispatchEvent(b))};goog.events.KeyHandler.prototype.getElement=function(){return this.element_}; +e=goog.events.KeyCodes.isCharacterKey(d)?b.keyCode:0):(a.type==goog.events.EventType.KEYPRESS?(goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_&&(c=this.altKey_),b.keyCode==b.charCode?32>b.keyCode?(d=b.keyCode,e=0):(d=this.keyCode_,e=b.charCode):(d=b.keyCode||this.keyCode_,e=b.charCode||0)):(d=b.keyCode||this.keyCode_,e=b.charCode||0),goog.userAgent.MAC&&e==goog.events.KeyCodes.QUESTION_MARK&&d==goog.events.KeyCodes.WIN_KEY&&(d=goog.events.KeyCodes.SLASH));var f=d=goog.events.KeyCodes.normalizeKeyCode(d); +d?63232<=d&&d in goog.events.KeyHandler.safariKey_?f=goog.events.KeyHandler.safariKey_[d]:25==d&&a.shiftKey&&(f=9):b.keyIdentifier&&b.keyIdentifier in goog.events.KeyHandler.keyIdentifier_&&(f=goog.events.KeyHandler.keyIdentifier_[b.keyIdentifier]);goog.userAgent.GECKO&&goog.events.KeyHandler.USES_KEYDOWN_&&a.type==goog.events.EventType.KEYPRESS&&!goog.events.KeyCodes.firesKeyPressEvent(f,this.lastKey_,a.shiftKey,a.ctrlKey,c,a.metaKey)||(a=f==this.lastKey_,this.lastKey_=f,b=new goog.events.KeyEvent(f, +e,a,b),b.altKey=c,this.dispatchEvent(b))};goog.events.KeyHandler.prototype.getElement=function(){return this.element_}; goog.events.KeyHandler.prototype.attach=function(a,b){this.keyUpKey_&&this.detach();this.element_=a;this.keyPressKey_=goog.events.listen(this.element_,goog.events.EventType.KEYPRESS,this,b);this.keyDownKey_=goog.events.listen(this.element_,goog.events.EventType.KEYDOWN,this.handleKeyDown_,b,this);this.keyUpKey_=goog.events.listen(this.element_,goog.events.EventType.KEYUP,this.handleKeyup_,b,this)}; goog.events.KeyHandler.prototype.detach=function(){this.keyPressKey_&&(goog.events.unlistenByKey(this.keyPressKey_),goog.events.unlistenByKey(this.keyDownKey_),goog.events.unlistenByKey(this.keyUpKey_),this.keyUpKey_=this.keyDownKey_=this.keyPressKey_=null);this.element_=null;this.keyCode_=this.lastKey_=-1};goog.events.KeyHandler.prototype.disposeInternal=function(){goog.events.KeyHandler.superClass_.disposeInternal.call(this);this.detach()}; goog.events.KeyEvent=function(a,b,c,d){goog.events.BrowserEvent.call(this,d);this.type=goog.events.KeyHandler.EventType.KEY;this.keyCode=a;this.charCode=b;this.repeat=c};goog.inherits(goog.events.KeyEvent,goog.events.BrowserEvent);goog.ui.ComponentUtil={};goog.ui.ComponentUtil.getMouseEventType=function(a){return a.pointerEventsEnabled()?goog.events.PointerAsMouseEventType:goog.events.EventType};goog.dom.classlist={};goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST=!1;goog.dom.classlist.get=function(a){if(goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST||a.classList)return a.classList;a=a.className;return goog.isString(a)&&a.match(/\S+/g)||[]};goog.dom.classlist.set=function(a,b){a.className=b};goog.dom.classlist.contains=function(a,b){return goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST||a.classList?a.classList.contains(b):goog.array.contains(goog.dom.classlist.get(a),b)}; @@ -750,7 +753,7 @@ goog.debug.Logger.prototype.callPublish_=function(a){if(this.handlers_)for(var b goog.debug.LogManager.initialize=function(){goog.debug.LogManager.rootLogger_||(goog.debug.LogManager.rootLogger_=new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME),goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME]=goog.debug.LogManager.rootLogger_,goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))};goog.debug.LogManager.getLoggers=function(){return goog.debug.LogManager.loggers_}; goog.debug.LogManager.getRoot=function(){goog.debug.LogManager.initialize();return goog.debug.LogManager.rootLogger_};goog.debug.LogManager.getLogger=function(a){goog.debug.LogManager.initialize();return goog.debug.LogManager.loggers_[a]||goog.debug.LogManager.createLogger_(a)};goog.debug.LogManager.createFunctionForCatchErrors=function(a){return function(b){(a||goog.debug.LogManager.getRoot()).severe("Error: "+b.message+" ("+b.fileName+" @ Line: "+b.line+")")}}; goog.debug.LogManager.createLogger_=function(a){var b=new goog.debug.Logger(a);if(goog.debug.Logger.ENABLE_HIERARCHY){var c=a.lastIndexOf("."),d=a.substr(0,c);c=a.substr(c+1);d=goog.debug.LogManager.getLogger(d);d.addChild_(c,b);b.setParent_(d)}return goog.debug.LogManager.loggers_[a]=b};goog.log={};goog.log.ENABLED=goog.debug.LOGGING_ENABLED;goog.log.ROOT_LOGGER_NAME=goog.debug.Logger.ROOT_LOGGER_NAME;goog.log.Logger=goog.debug.Logger;goog.log.Level=goog.debug.Logger.Level;goog.log.LogRecord=goog.debug.LogRecord;goog.log.getLogger=function(a,b){return goog.log.ENABLED?(a=goog.debug.LogManager.getLogger(a),b&&a&&a.setLevel(b),a):null};goog.log.addHandler=function(a,b){goog.log.ENABLED&&a&&a.addHandler(b)}; -goog.log.removeHandler=function(a,b){return goog.log.ENABLED&&a?a.removeHandler(b):!1};goog.log.log=function(a,b,c,d){goog.log.ENABLED&&a&&a.log(b,c,d)};goog.log.error=function(a,b,c){goog.log.ENABLED&&a&&a.severe(b,c)};goog.log.warning=function(a,b,c){goog.log.ENABLED&&a&&a.warning(b,c)};goog.log.info=function(a,b,c){goog.log.ENABLED&&a&&a.info(b,c)};goog.log.fine=function(a,b,c){goog.log.ENABLED&&a&&a.fine(b,c)};goog.Thenable=function(){};goog.Thenable.prototype.then=function(a,b,c){};goog.Thenable.IMPLEMENTED_BY_PROP="$goog_Thenable";goog.Thenable.addImplementation=function(a){a.prototype.then=a.prototype.then;COMPILED?a.prototype[goog.Thenable.IMPLEMENTED_BY_PROP]=!0:a.prototype.$goog_Thenable=!0};goog.Thenable.isImplementedBy=function(a){if(!a)return!1;try{return COMPILED?!!a[goog.Thenable.IMPLEMENTED_BY_PROP]:!!a.$goog_Thenable}catch(b){return!1}};goog.async={};goog.async.FreeList=function(a,b,c){this.limit_=c;this.create_=a;this.reset_=b;this.occupants_=0;this.head_=null};goog.async.FreeList.prototype.get=function(){if(0this.remainingCapacityOfType(c))return!1;b+=a[c]}return b>this.remainingCapacity()?!1:!0};Blockly.Workspace.prototype.hasBlockLimits=function(){return Infinity!=this.options.maxBlocks||!!this.options.maxInstances}; Blockly.Workspace.prototype.undo=function(a){var b=a?this.redoStack_:this.undoStack_,c=a?this.undoStack_:this.redoStack_,d=b.pop();if(d){for(var e=[d];b.length&&d.group&&d.group==b[b.length-1].group;)e.push(b.pop());for(b=0;d=e[b];b++)c.push(d);e=Blockly.Events.filter(e,a);Blockly.Events.recordUndo=!1;try{for(b=0;d=e[b];b++)d.run(a)}finally{Blockly.Events.recordUndo=!0}}};Blockly.Workspace.prototype.clearUndo=function(){this.undoStack_.length=0;this.redoStack_.length=0;Blockly.Events.clearPendingUndo()}; Blockly.Workspace.prototype.addChangeListener=function(a){this.listeners_.push(a);return a};Blockly.Workspace.prototype.removeChangeListener=function(a){Blockly.utils.arrayRemove(this.listeners_,a)};Blockly.Workspace.prototype.fireChangeListener=function(a){if(a.recordUndo)for(this.undoStack_.push(a),this.redoStack_.length=0;this.undoStack_.length>this.MAX_UNDO&&0<=this.MAX_UNDO;)this.undoStack_.shift();for(var b=0,c;c=this.listeners_[b];b++)c(a)}; Blockly.Workspace.prototype.getBlockById=function(a){return this.blockDB_[a]||null};Blockly.Workspace.prototype.getCommentById=function(a){return this.commentDB_[a]||null};Blockly.Workspace.prototype.allInputsFilled=function(a){for(var b=this.getTopBlocks(!1),c=0,d;d=b[c];c++)if(!d.allInputsFilled(a))return!1;return!0};Blockly.Workspace.prototype.getPotentialVariableMap=function(){return this.potentialVariableMap_}; @@ -1022,7 +1029,7 @@ Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new goog.math. Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);this.blockId&&(a.blockId=this.blockId);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue;this.blockId=a.blockId};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null; Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; Blockly.Icon.prototype.dispose=function(){Blockly.utils.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; -Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; +Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed()||this.block_.isInsertionMarker())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new goog.math.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);goog.math.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; Blockly.Comment.prototype.drawIcon_=function(a){Blockly.utils.createSvgElement("circle",{"class":"blocklyIconShape",r:"8",cx:"8",cy:"8"},a);Blockly.utils.createSvgElement("path",{"class":"blocklyIconSymbol",d:"m6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.4050.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25-1.201,0.998 -1.201,1.528 -1.204,2.19z"},a);Blockly.utils.createSvgElement("rect",{"class":"blocklyIconSymbol",x:"6.8",y:"10.78",height:"2",width:"2"},a)}; @@ -1042,8 +1049,9 @@ Blockly.Connection.prototype.canConnectWithReason_=function(a){if(!a)return Bloc Blockly.Connection.CAN_CONNECT:Blockly.Connection.REASON_CHECKS_FAILED}; Blockly.Connection.prototype.checkConnection_=function(a){switch(this.canConnectWithReason_(a)){case Blockly.Connection.CAN_CONNECT:break;case Blockly.Connection.REASON_SELF_CONNECTION:throw Error("Attempted to connect a block to itself.");case Blockly.Connection.REASON_DIFFERENT_WORKSPACES:throw Error("Blocks not on same workspace.");case Blockly.Connection.REASON_WRONG_TYPE:throw Error("Attempt to connect incompatible types.");case Blockly.Connection.REASON_TARGET_NULL:throw Error("Target connection is null."); case Blockly.Connection.REASON_CHECKS_FAILED:throw Error("Connection checks failed. "+(this+" expected "+this.check_+", found "+a.check_));case Blockly.Connection.REASON_SHADOW_PARENT:throw Error("Connecting non-shadow to shadow block.");default:throw Error("Unknown connection failure: this should never happen!");}}; -Blockly.Connection.prototype.isConnectionAllowed=function(a){if(this.canConnectWithReason_(a)!=Blockly.Connection.CAN_CONNECT)return!1;switch(a.type){case Blockly.PREVIOUS_STATEMENT:if(a.isConnected()||this.isConnected())return!1;break;case Blockly.OUTPUT_VALUE:if(a.isConnected()||this.isConnected())return!1;break;case Blockly.INPUT_VALUE:if(a.targetConnection&&!a.targetBlock().isMovable()&&!a.targetBlock().isShadow())return!1;break;case Blockly.NEXT_STATEMENT:if(a.isConnected()&&!this.sourceBlock_.nextConnection&& -!a.targetBlock().isShadow()&&a.targetBlock().nextConnection)return!1;break;default:throw Error("Unknown connection type in isConnectionAllowed");}return-1!=Blockly.draggingConnections_.indexOf(a)?!1:!0};Blockly.Connection.prototype.connect=function(a){this.targetConnection!=a&&(this.checkConnection_(a),this.isSuperior()?this.connect_(a):a.connect_(this))}; +Blockly.Connection.prototype.canConnectToPrevious_=function(a){if(this.targetConnection||-1!=Blockly.draggingConnections_.indexOf(a))return!1;if(!a.targetConnection)return!0;a=a.targetBlock();return a.isInsertionMarker()?!a.getPreviousBlock():!1}; +Blockly.Connection.prototype.isConnectionAllowed=function(a){if(a.sourceBlock_.isInsertionMarker()||this.canConnectWithReason_(a)!=Blockly.Connection.CAN_CONNECT)return!1;switch(a.type){case Blockly.PREVIOUS_STATEMENT:return this.canConnectToPrevious_(a);case Blockly.OUTPUT_VALUE:if(a.isConnected()||this.isConnected())return!1;break;case Blockly.INPUT_VALUE:if(a.isConnected()&&!a.targetBlock().isMovable()&&!a.targetBlock().isShadow())return!1;break;case Blockly.NEXT_STATEMENT:if(a.isConnected()&& +!this.sourceBlock_.nextConnection&&!a.targetBlock().isShadow()&&a.targetBlock().nextConnection)return!1;break;default:throw Error("Unknown connection type in isConnectionAllowed");}return-1!=Blockly.draggingConnections_.indexOf(a)?!1:!0};Blockly.Connection.prototype.connect=function(a){this.targetConnection!=a&&(this.checkConnection_(a),this.isSuperior()?this.connect_(a):a.connect_(this))}; Blockly.Connection.connectReciprocally_=function(a,b){if(!a||!b)throw Error("Cannot connect null connections.");a.targetConnection=b;b.targetConnection=a};Blockly.Connection.singleConnection_=function(a,b){for(var c=!1,d=0;da.y_)c=d;else{b=d;break}}return b};Blockly.ConnectionDB.prototype.removeConnection_=function(a){if(!a.inDB_)throw Error("Connection not in database.");var b=this.findConnection(a);if(-1==b)throw Error("Unable to find connection in connectionDB.");a.inDB_=!1;this.splice(b,1)}; Blockly.ConnectionDB.prototype.getNeighbours=function(a,b){function c(a){var c=e-d[a].x_,g=f-d[a].y_;Math.sqrt(c*c+g*g)<=b&&k.push(d[a]);return gc)){var d=b.getSvgXY(a.getSvgRoot());a.outputConnection?(d.x+=(a.RTL?3:-3)*c,d.y+=13*c):a.previousConnection&&(d.x+=(a.RTL?-23:23)*c,d.y+=3*c);a=Blockly.utils.createSvgElement("circle",{cx:d.x,cy:d.y,r:0,fill:"none",stroke:"#888","stroke-width":10},b.getParentSvg());Blockly.BlockAnimations.connectionUiStep_(a,new Date,c)}}; Blockly.BlockAnimations.connectionUiStep_=function(a,b,c){var d=(new Date-b)/150;1a.workspace.scale)){var b=a.getHeightWidth().height;b=Math.atan(10/b)/Math.PI*180;a.RTL||(b*=-1);Blockly.BlockAnimations.disconnectUiStep_(a.getSvgRoot(),b,new Date)}}; Blockly.BlockAnimations.disconnectUiStep_=function(a,b,c){var d=(new Date-c)/200;1'+goog.string.htmlEscape(a.name)+""}; Blockly.Variables.generateVariableFieldDom=function(a){a=Blockly.Variables.generateVariableFieldXmlString(a);return Blockly.Xml.textToDom(""+a+"").firstChild};Blockly.Variables.getOrCreateVariablePackage=function(a,b,c,d){var e=Blockly.Variables.getVariable(a,b,c,d);e||(e=Blockly.Variables.createVariable_(a,b,c,d));return e}; -Blockly.Variables.getVariable=function(a,b,c,d){var e=a.getPotentialVariableMap();if(b){var f=a.getVariableById(b);!f&&e&&(f=e.getVariableById(b))}else if(c){if(void 0==d)throw Error("Tried to look up a variable by name without a type");f=a.getVariable(c,d);!f&&e&&(f=e.getVariable(c,d))}return f}; +Blockly.Variables.getVariable=function(a,b,c,d){var e=a.getPotentialVariableMap();if(b){var f=a.getVariableById(b);!f&&e&&(f=e.getVariableById(b));if(f)return f}if(c){if(void 0==d)throw Error("Tried to look up a variable by name without a type");f=a.getVariable(c,d);!f&&e&&(f=e.getVariable(c,d))}return f}; Blockly.Variables.createVariable_=function(a,b,c,d){var e=a.getPotentialVariableMap();c||(c=Blockly.Variables.generateUniqueName(a.isFlyout?a.targetWorkspace:a));return e?e.createVariable(c,d,b):a.createVariable(c,d,b)};Blockly.Variables.getAddedVariables=function(a,b){a=a.getAllVariables();var c=[];if(b.length!=a.length)for(var d=0;d";c=Blockly.Xml.textToDom(c).firstChild;b.push(c)}if(Blockly.Blocks.variables_get_dynamic)for(var d=0;c=a[d];d++)c=''+Blockly.Variables.generateVariableFieldXmlString(c)+ "",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null};Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new window.Audio}catch(h){return}for(var d,e=0;eb.bottomRight.x&&(b.bottomRight.x=d.bottomRight.x);d.topLeft.yb.bottomRight.y&&(b.bottomRight.y=d.bottomRight.y)}return{x:b.topLeft.x, -y:b.topLeft.y,width:b.bottomRight.x-b.topLeft.x,height:b.bottomRight.y-b.topLeft.y}};Blockly.WorkspaceSvg.prototype.cleanUp=function(){this.setResizesEnabled(!1);Blockly.Events.setGroup(!0);for(var a=this.getTopBlocks(!0),b=0,c=0,d;d=a[c];c++){var e=d.getRelativeToSurfaceXY();d.moveBy(-e.x,b-e.y);d.snapToGrid();b=d.getRelativeToSurfaceXY().y+d.getHeightWidth().height+Blockly.BlockSvg.MIN_BLOCK_Y}Blockly.Events.setGroup(!1);this.setResizesEnabled(!0)}; +y:b.topLeft.y,width:b.bottomRight.x-b.topLeft.x,height:b.bottomRight.y-b.topLeft.y}};Blockly.WorkspaceSvg.prototype.cleanUp=function(){this.setResizesEnabled(!1);Blockly.Events.setGroup(!0);for(var a=this.getTopBlocks(!0),b=0,c=0,d;d=a[c];c++)if(d.isMovable()){var e=d.getRelativeToSurfaceXY();d.moveBy(-e.x,b-e.y);d.snapToGrid();b=d.getRelativeToSurfaceXY().y+d.getHeightWidth().height+Blockly.BlockSvg.MIN_BLOCK_Y}Blockly.Events.setGroup(!1);this.setResizesEnabled(!0)}; Blockly.WorkspaceSvg.prototype.showContextMenu_=function(a){function b(a){if(a.isDeletable())p=p.concat(a.getDescendants(!1));else{a=a.getChildren(!1);for(var c=0;cp.length?c():Blockly.confirm(Blockly.Msg.DELETE_ALL_BLOCKS.replace("%1",p.length),function(a){a&& @@ -1362,11 +1371,11 @@ Blockly.Warning.textToDom_=function(a){var b=Blockly.utils.createSvgElement("tex Blockly.Warning.prototype.setVisible=function(a){if(a!=this.isVisible())if(Blockly.Events.fire(new Blockly.Events.Ui(this.block_,"warningOpen",!a,a)),a){a=Blockly.Warning.textToDom_(this.getText());this.bubble_=new Blockly.Bubble(this.block_.workspace,a,this.block_.svgPath_,this.iconXY_,null,null);this.bubble_.setSvgId(this.block_.id);if(this.block_.RTL)for(var b=a.getBBox().width,c=0,d;d=a.childNodes[c];c++)d.setAttribute("text-anchor","end"),d.setAttribute("x",b+Blockly.Bubble.BORDER_WIDTH);this.updateColour(); a=this.bubble_.getBubbleSize();this.bubble_.setBubbleSize(a.width,a.height)}else this.bubble_.dispose(),this.body_=this.bubble_=null};Blockly.Warning.prototype.bodyFocus_=function(a){this.bubble_.promote_()};Blockly.Warning.prototype.setText=function(a,b){this.text_[b]!=a&&(a?this.text_[b]=a:delete this.text_[b],this.isVisible()&&(this.setVisible(!1),this.setVisible(!0)))};Blockly.Warning.prototype.getText=function(){var a=[],b;for(b in this.text_)a.push(this.text_[b]);return a.join("\n")}; Blockly.Warning.prototype.dispose=function(){this.block_.warning=null;Blockly.Icon.prototype.dispose.call(this)};Blockly.Block=function(a,b,c){if("undefined"!==typeof Blockly.Generator.prototype[b])throw Error('Block prototypeName "'+b+'" conflicts with Blockly.Generator members.');this.id=c&&!a.getBlockById(c)?c:Blockly.utils.genUid();a.blockDB_[this.id]=this;this.previousConnection=this.nextConnection=this.outputConnection=null;this.inputList=[];this.inputsInline=void 0;this.disabled=!1;this.tooltip="";this.contextMenu=!0;this.parentBlock_=null;this.childBlocks_=[];this.editable_=this.movable_=this.deletable_= -!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new goog.math.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a=Blockly.Events.getGroup())|| +!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new goog.math.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);a.addTypedBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a=Blockly.Events.getGroup())|| Blockly.Events.setGroup(!0);try{Blockly.Events.fire(new Blockly.Events.BlockCreate(this))}finally{a||Blockly.Events.setGroup(!1)}}"function"==typeof this.onchange&&this.setOnChange(this.onchange)};Blockly.Block.obtain=function(a,b){console.warn("Deprecated call to Blockly.Block.obtain, use workspace.newBlock instead.");return a.newBlock(b)};Blockly.Block.prototype.data=null;Blockly.Block.prototype.colour_="#000000";Blockly.Block.prototype.hue_=null; -Blockly.Block.prototype.dispose=function(a){if(this.workspace){this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);this.unplug(a);Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockDelete(this));Blockly.Events.disable();try{this.workspace&&(this.workspace.removeTopBlock(this),delete this.workspace.blockDB_[this.id],this.workspace=null);Blockly.selected==this&&(Blockly.selected=null);for(var b=this.childBlocks_.length-1;0<=b;b--)this.childBlocks_[b].dispose(!1); -b=0;for(var c;c=this.inputList[b];b++)c.dispose();this.inputList.length=0;var d=this.getConnections_(!0);for(b=0;b=c)this.hue_=c,this.colour_=Blockly.hueToRgb(c);else if("string"==typeof b&&/^#[0-9a-fA-F]{6}$/.test(b))this.colour_=b,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),c;}; @@ -1412,7 +1421,7 @@ Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBo Blockly.ContextMenu.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);var b=a.getElement();Blockly.utils.addClass(b,"blocklyContextMenu");Blockly.bindEventWithChecks_(b,"contextmenu",null,Blockly.utils.noEvent);a.setAllowAutoFocus(!0)};Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_&&Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_)}; Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(c));c.select()}}; Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; -Blockly.ContextMenu.blockDuplicateOption=function(a){var b=!0;a.getDescendants(!1).length>a.workspace.remainingCapacity()&&(b=!1);return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!goog.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; +Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!goog.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!goog.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/a.scale); c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= @@ -1463,10 +1472,11 @@ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER=Blockly.BlockSvg.NOTCH_PATH_RIGHT+" h -"+ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL="a "+Blockly.BlockSvg.CORNER_RADIUS+","+Blockly.BlockSvg.CORNER_RADIUS+" 0 0,0 "+(-Blockly.BlockSvg.DISTANCE_45_OUTSIDE-.5)+","+(Blockly.BlockSvg.CORNER_RADIUS-Blockly.BlockSvg.DISTANCE_45_OUTSIDE);Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL="a "+(Blockly.BlockSvg.CORNER_RADIUS+.5)+","+(Blockly.BlockSvg.CORNER_RADIUS+.5)+" 0 0,0 "+(Blockly.BlockSvg.CORNER_RADIUS+.5)+","+(Blockly.BlockSvg.CORNER_RADIUS+.5); Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_LTR="a "+(Blockly.BlockSvg.CORNER_RADIUS+.5)+","+(Blockly.BlockSvg.CORNER_RADIUS+.5)+" 0 0,0 "+(Blockly.BlockSvg.CORNER_RADIUS-Blockly.BlockSvg.DISTANCE_45_OUTSIDE)+","+(Blockly.BlockSvg.DISTANCE_45_OUTSIDE+.5);Blockly.BlockSvg.prototype.getHeightWidth=function(){var a=this.height,b=this.width,c=this.getNextBlock();c?(c=c.getHeightWidth(),a+=c.height-4,b=Math.max(b,c.width)):this.nextConnection||this.outputConnection||(a+=2);return{height:a,width:b}}; Blockly.BlockSvg.prototype.render=function(a){Blockly.Field.startCache();this.rendered=!0;var b=Blockly.BlockSvg.SEP_SPACE_X;this.RTL&&(b=-b);for(var c=this.getIcons(),d=0;da)}};Blockly.Flyout.prototype.reflow=function(){this.reflowWrapper_&&this.workspace_.removeChangeListener(this.reflowWrapper_);this.reflowInternal_();this.reflowWrapper_&&this.workspace_.addChangeListener(this.reflowWrapper_)}; +Blockly.Flyout.prototype.filterForCapacity_=function(){for(var a=this.workspace_.getTopBlocks(!1),b=0,c;c=a[b];b++)-1==this.permanentlyDisabled_.indexOf(c)&&c.setDisabled(!this.targetWorkspace_.isCapacityAvailable(Blockly.utils.getBlockTypeCounts(c)))};Blockly.Flyout.prototype.reflow=function(){this.reflowWrapper_&&this.workspace_.removeChangeListener(this.reflowWrapper_);this.reflowInternal_();this.reflowWrapper_&&this.workspace_.addChangeListener(this.reflowWrapper_)}; Blockly.Flyout.prototype.isScrollable=function(){return this.scrollbar_?this.scrollbar_.isVisible():!1}; Blockly.Flyout.prototype.placeNewBlock_=function(a){var b=this.targetWorkspace_;if(!a.getSvgRoot())throw Error("oldBlock is not rendered.");var c=Blockly.Xml.blockToDom(a);b.setResizesEnabled(!1);c=Blockly.Xml.domToBlock(c,b);if(!c.getSvgRoot())throw Error("block is not rendered.");var d=b.getOriginOffsetInPixels(),e=this.workspace_.getOriginOffsetInPixels();a=a.getRelativeToSurfaceXY().scale(this.workspace_.scale);a=goog.math.Coordinate.sum(e,a);b=goog.math.Coordinate.difference(a,d).scale(1/b.scale); c.moveBy(b.x,b.y);return c};Blockly.HorizontalFlyout=function(a){a.getMetrics=this.getMetrics_.bind(this);a.setMetrics=this.setMetrics_.bind(this);Blockly.HorizontalFlyout.superClass_.constructor.call(this,a);this.horizontalLayout_=!0};goog.inherits(Blockly.HorizontalFlyout,Blockly.Flyout); @@ -1658,25 +1668,26 @@ Blockly.Css.CONTENT=[".blocklySvg {","background-color: #fff;","outline: none;", "color: #000;","display: none;","font-family: sans-serif;","font-size: 9pt;","opacity: .9;","padding: 2px;","position: absolute;","z-index: 100000;","}",".blocklyResizeSE {","cursor: se-resize;","fill: #aaa;","}",".blocklyResizeSW {","cursor: sw-resize;","fill: #aaa;","}",".blocklyResizeLine {","stroke: #515A5A;","stroke-width: 1;","}",".blocklyHighlightedConnectionPath {","fill: none;","stroke: #fc3;","stroke-width: 4px;","}",".blocklyPathLight {","fill: none;","stroke-linecap: round;","stroke-width: 1;", "}",".blocklySelected>.blocklyPath {","stroke: #fc3;","stroke-width: 3px;","}",".blocklySelected>.blocklyPathLight {","display: none;","}",".blocklyDraggable {",'cursor: url("<<>>/handopen.cur"), auto;',"cursor: grab;","cursor: -webkit-grab;","}",".blocklyDragging {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;","}",".blocklyDraggable:active {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;", "}",".blocklyBlockDragSurface .blocklyDraggable {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;","}",".blocklyDragging.blocklyDraggingDelete {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyToolboxDelete {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyToolboxGrab {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;","}",".blocklyDragging>.blocklyPath,",".blocklyDragging>.blocklyPathLight {", -"fill-opacity: .8;","stroke-opacity: .8;","}",".blocklyDragging>.blocklyPathDark {","display: none;","}",".blocklyDisabled>.blocklyPath {","fill-opacity: .5;","stroke-opacity: .5;","}",".blocklyDisabled>.blocklyPathLight,",".blocklyDisabled>.blocklyPathDark {","display: none;","}",".blocklyText {","cursor: default;","fill: #fff;","font-family: sans-serif;","font-size: 11pt;","}",".blocklyNonEditableText>text {","pointer-events: none;","}",".blocklyNonEditableText>rect,",".blocklyEditableText>rect {", -"fill: #fff;","fill-opacity: .6;","}",".blocklyNonEditableText>text,",".blocklyEditableText>text {","fill: #000;","}",".blocklyEditableText:hover>rect {","stroke: #fff;","stroke-width: 2;","}",".blocklyBubbleText {","fill: #000;","}",".blocklyFlyout {","position: absolute;","z-index: 20;","}",".blocklyFlyoutButton {","fill: #888;","cursor: default;","}",".blocklyFlyoutButtonShadow {","fill: #666;","}",".blocklyFlyoutButton:hover {","fill: #aaa;","}",".blocklyFlyoutLabel {","cursor: default;","}", -".blocklyFlyoutLabelBackground {","opacity: 0;","}",".blocklyFlyoutLabelText {","fill: #000;","}",".blocklySvg text, .blocklyBlockDragSurface text {","user-select: none;","-moz-user-select: none;","-ms-user-select: none;","-webkit-user-select: none;","cursor: inherit;","}",".blocklyHidden {","display: none;","}",".blocklyFieldDropdown:not(.blocklyHidden) {","display: block;","}",".blocklyIconGroup {","cursor: default;","}",".blocklyIconGroup:not(:hover),",".blocklyIconGroupReadonly {","opacity: .6;", -"}",".blocklyIconShape {","fill: #00f;","stroke: #fff;","stroke-width: 1px;","}",".blocklyIconSymbol {","fill: #fff;","}",".blocklyMinimalBody {","margin: 0;","padding: 0;","}",".blocklyCommentForeignObject {","position: relative;","z-index: 0;","}",".blocklyCommentRect {","fill: #E7DE8E;","stroke: #bcA903;","stroke-width: 1px","}",".blocklyCommentTarget {","fill: transparent;","stroke: #bcA903;","}",".blocklyCommentTargetFocused {","fill: none;","}",".blocklyCommentHandleTarget {","fill: none;", -"}",".blocklyCommentHandleTargetFocused {","fill: transparent;","}",".blocklyFocused>.blocklyCommentRect {","fill: #B9B272;","stroke: #B9B272;","}",".blocklySelected>.blocklyCommentTarget {","stroke: #fc3;","stroke-width: 3px;","}",".blocklyCommentTextarea {","background-color: #fef49c;","border: 0;","outline: 0;","margin: 0;","padding: 3px;","resize: none;","display: block;","overflow: hidden;","}",".blocklyCommentDeleteIcon {","cursor: pointer;","fill: #000;","display: none","}",".blocklySelected > .blocklyCommentDeleteIcon {", -"display: block","}",".blocklyDeleteIconShape {","fill: #000;","stroke: #000;","stroke-width: 1px;","}",".blocklyDeleteIconShape.blocklyDeleteIconHighlighted {","stroke: #fc3;","}",".blocklyHtmlInput {","border: none;","border-radius: 4px;","font-family: sans-serif;","height: 100%;","margin: 0;","outline: none;","padding: 0 1px;","width: 100%","}",".blocklyMainBackground {","stroke-width: 1;","stroke: #c6c6c6;","}",".blocklyMutatorBackground {","fill: #fff;","stroke: #ddd;","stroke-width: 1;","}", -".blocklyFlyoutBackground {","fill: #ddd;","fill-opacity: .8;","}",".blocklyTransparentBackground {","opacity: 0;","}",".blocklyMainWorkspaceScrollbar {","z-index: 20;","}",".blocklyFlyoutScrollbar {","z-index: 30;","}",".blocklyScrollbarHorizontal, .blocklyScrollbarVertical {","position: absolute;","outline: none;","}",".blocklyScrollbarBackground {","opacity: 0;","}",".blocklyScrollbarHandle {","fill: #ccc;","}",".blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyScrollbarHandle:hover {", -"fill: #bbb;","}",".blocklyZoom>image {","opacity: .4;","}",".blocklyZoom>image:hover {","opacity: .6;","}",".blocklyZoom>image:active {","opacity: .8;","}",".blocklyFlyout .blocklyScrollbarHandle {","fill: #bbb;","}",".blocklyFlyout .blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyFlyout .blocklyScrollbarHandle:hover {","fill: #aaa;","}",".blocklyInvalidInput {","background: #faa;","}",".blocklyAngleCircle {","stroke: #444;","stroke-width: 1;","fill: #ddd;","fill-opacity: .8;", -"}",".blocklyAngleMarks {","stroke: #444;","stroke-width: 1;","}",".blocklyAngleGauge {","fill: #f88;","fill-opacity: .8;","}",".blocklyAngleLine {","stroke: #f00;","stroke-width: 2;","stroke-linecap: round;","pointer-events: none;","}",".blocklyContextMenu {","border-radius: 4px;","}",".blocklyDropdownMenu {","padding: 0 !important;","}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(<<>>/sprites.png) no-repeat -48px -16px !important;", -"}",".blocklyToolboxDiv {","background-color: #ddd;","overflow-x: visible;","overflow-y: auto;","position: absolute;","user-select: none;","-moz-user-select: none;","-ms-user-select: none;","-webkit-user-select: none;","z-index: 70;","-webkit-tap-highlight-color: transparent;","}",".blocklyTreeRoot {","padding: 4px 0;","}",".blocklyTreeRoot:focus {","outline: none;","}",".blocklyTreeRow {","height: 22px;","line-height: 22px;","margin-bottom: 3px;","padding-right: 8px;","white-space: nowrap;","}", -".blocklyHorizontalTree {","float: left;","margin: 1px 5px 8px 0;","}",".blocklyHorizontalTreeRtl {","float: right;","margin: 1px 0 8px 5px;","}",'.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {',"margin-left: 8px;","}",".blocklyTreeRow:not(.blocklyTreeSelected):hover {","background-color: #e4e4e4;","}",".blocklyTreeSeparator {","border-bottom: solid #e5e5e5 1px;","height: 0;","margin: 5px 0;","}",".blocklyTreeSeparatorHorizontal {","border-right: solid #e5e5e5 1px;","width: 0;","padding: 5px 0;", -"margin: 0 5px;","}",".blocklyTreeIcon {","background-image: url(<<>>/sprites.png);","height: 16px;","vertical-align: middle;","width: 16px;","}",".blocklyTreeIconClosedLtr {","background-position: -32px -1px;","}",".blocklyTreeIconClosedRtl {","background-position: 0 -1px;","}",".blocklyTreeIconOpen {","background-position: -16px -1px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedLtr {","background-position: -32px -17px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedRtl {","background-position: 0 -17px;", -"}",".blocklyTreeSelected>.blocklyTreeIconOpen {","background-position: -16px -17px;","}",".blocklyTreeIconNone,",".blocklyTreeSelected>.blocklyTreeIconNone {","background-position: -48px -1px;","}",".blocklyTreeLabel {","cursor: default;","font-family: sans-serif;","font-size: 16px;","padding: 0 3px;","vertical-align: middle;","}",".blocklyToolboxDelete .blocklyTreeLabel {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyTreeSelected .blocklyTreeLabel {","color: #fff;","}",".blocklyColourTable {", -"border-collapse: collapse;","}",".blocklyColourTable>tr>td {","border: 1px solid #666;","padding: 0;","}",".blocklyColourTable>tr>td>div {","border: 1px solid #666;","height: 13px;","width: 15px;","}",".blocklyColourTable>tr>td>div:hover {","border: 1px solid #fff;","}",".blocklyColourSelected, .blocklyColourSelected:hover {","border: 1px solid #000 !important;","}",".blocklyWidgetDiv .goog-menu {","background: #fff;","border-color: #ccc #666 #666 #ccc;","border-style: solid;","border-width: 1px;", -"cursor: default;","font: normal 13px Arial, sans-serif;","margin: 0;","outline: none;","padding: 4px 0;","position: absolute;","overflow-y: auto;","overflow-x: hidden;","max-height: 100%;","z-index: 20000;","}",".blocklyWidgetDiv .goog-menuitem {","color: #000;","font: normal 13px Arial, sans-serif;","list-style: none;","margin: 0;","padding: 4px 7em 4px 28px;","white-space: nowrap;","}",".blocklyWidgetDiv .goog-menuitem.goog-menuitem-rtl {","padding-left: 7em;","padding-right: 28px;","}",".blocklyWidgetDiv .goog-menu-nocheckbox .goog-menuitem,", -".blocklyWidgetDiv .goog-menu-noicon .goog-menuitem {","padding-left: 12px;","}",".blocklyWidgetDiv .goog-menu-noaccel .goog-menuitem {","padding-right: 20px;","}",".blocklyWidgetDiv .goog-menuitem-content {","color: #000;","font: normal 13px Arial, sans-serif;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-accel,",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-content {","color: #ccc !important;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-icon {","opacity: 0.3;", -"filter: alpha(opacity=30);","}",".blocklyWidgetDiv .goog-menuitem-highlight,",".blocklyWidgetDiv .goog-menuitem-hover {","background-color: #d6e9f8;","border-color: #d6e9f8;","border-style: dotted;","border-width: 1px 0;","padding-bottom: 3px;","padding-top: 3px;","}",".blocklyWidgetDiv .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-menuitem-icon {","background-repeat: no-repeat;","height: 16px;","left: 6px;","position: absolute;","right: auto;","vertical-align: middle;","width: 16px;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-checkbox,", -".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-icon {","left: auto;","right: 6px;","}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;","}",".blocklyWidgetDiv .goog-menuitem-accel {","color: #999;","direction: ltr;","left: auto;","padding: 0 6px;","position: absolute;","right: 0;","text-align: right;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-accel {", -"left: 0;","right: auto;","text-align: left;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-hint {","text-decoration: underline;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-separator {","color: #999;","font-size: 12px;","padding-left: 4px;","}",".blocklyWidgetDiv .goog-menuseparator {","border-top: 1px solid #ccc;","margin: 4px 0;","padding: 0;","}",""];Blockly.WidgetDiv={};Blockly.WidgetDiv.DIV=null;Blockly.WidgetDiv.owner_=null;Blockly.WidgetDiv.dispose_=null;Blockly.WidgetDiv.createDom=function(){Blockly.WidgetDiv.DIV||(Blockly.WidgetDiv.DIV=document.createElement("div"),Blockly.WidgetDiv.DIV.className="blocklyWidgetDiv",document.body.appendChild(Blockly.WidgetDiv.DIV))}; +"fill-opacity: .8;","stroke-opacity: .8;","}",".blocklyDragging>.blocklyPathDark {","display: none;","}",".blocklyDisabled>.blocklyPath {","fill-opacity: .5;","stroke-opacity: .5;","}",".blocklyDisabled>.blocklyPathLight,",".blocklyDisabled>.blocklyPathDark {","display: none;","}",".blocklyInsertionMarker>.blocklyPath,",".blocklyInsertionMarker>.blocklyPathLight,",".blocklyInsertionMarker>.blocklyPathDark {","fill-opacity: .2;","stroke: none","}",".blocklyReplaceable .blocklyPath {","fill-opacity: 0.5;", +"}",".blocklyReplaceable .blocklyPathLight,",".blocklyReplaceable .blocklyPathDark {","display: none;","}",".blocklyText {","cursor: default;","fill: #fff;","font-family: sans-serif;","font-size: 11pt;","}",".blocklyNonEditableText>text {","pointer-events: none;","}",".blocklyNonEditableText>rect,",".blocklyEditableText>rect {","fill: #fff;","fill-opacity: .6;","}",".blocklyNonEditableText>text,",".blocklyEditableText>text {","fill: #000;","}",".blocklyEditableText:hover>rect {","stroke: #fff;","stroke-width: 2;", +"}",".blocklyBubbleText {","fill: #000;","}",".blocklyFlyout {","position: absolute;","z-index: 20;","}",".blocklyFlyoutButton {","fill: #888;","cursor: default;","}",".blocklyFlyoutButtonShadow {","fill: #666;","}",".blocklyFlyoutButton:hover {","fill: #aaa;","}",".blocklyFlyoutLabel {","cursor: default;","}",".blocklyFlyoutLabelBackground {","opacity: 0;","}",".blocklyFlyoutLabelText {","fill: #000;","}",".blocklySvg text, .blocklyBlockDragSurface text {","user-select: none;","-moz-user-select: none;", +"-ms-user-select: none;","-webkit-user-select: none;","cursor: inherit;","}",".blocklyHidden {","display: none;","}",".blocklyFieldDropdown:not(.blocklyHidden) {","display: block;","}",".blocklyIconGroup {","cursor: default;","}",".blocklyIconGroup:not(:hover),",".blocklyIconGroupReadonly {","opacity: .6;","}",".blocklyIconShape {","fill: #00f;","stroke: #fff;","stroke-width: 1px;","}",".blocklyIconSymbol {","fill: #fff;","}",".blocklyMinimalBody {","margin: 0;","padding: 0;","}",".blocklyCommentForeignObject {", +"position: relative;","z-index: 0;","}",".blocklyCommentRect {","fill: #E7DE8E;","stroke: #bcA903;","stroke-width: 1px","}",".blocklyCommentTarget {","fill: transparent;","stroke: #bcA903;","}",".blocklyCommentTargetFocused {","fill: none;","}",".blocklyCommentHandleTarget {","fill: none;","}",".blocklyCommentHandleTargetFocused {","fill: transparent;","}",".blocklyFocused>.blocklyCommentRect {","fill: #B9B272;","stroke: #B9B272;","}",".blocklySelected>.blocklyCommentTarget {","stroke: #fc3;","stroke-width: 3px;", +"}",".blocklyCommentTextarea {","background-color: #fef49c;","border: 0;","outline: 0;","margin: 0;","padding: 3px;","resize: none;","display: block;","overflow: hidden;","}",".blocklyCommentDeleteIcon {","cursor: pointer;","fill: #000;","display: none","}",".blocklySelected > .blocklyCommentDeleteIcon {","display: block","}",".blocklyDeleteIconShape {","fill: #000;","stroke: #000;","stroke-width: 1px;","}",".blocklyDeleteIconShape.blocklyDeleteIconHighlighted {","stroke: #fc3;","}",".blocklyHtmlInput {", +"border: none;","border-radius: 4px;","font-family: sans-serif;","height: 100%;","margin: 0;","outline: none;","padding: 0 1px;","width: 100%","}",".blocklyMainBackground {","stroke-width: 1;","stroke: #c6c6c6;","}",".blocklyMutatorBackground {","fill: #fff;","stroke: #ddd;","stroke-width: 1;","}",".blocklyFlyoutBackground {","fill: #ddd;","fill-opacity: .8;","}",".blocklyTransparentBackground {","opacity: 0;","}",".blocklyMainWorkspaceScrollbar {","z-index: 20;","}",".blocklyFlyoutScrollbar {","z-index: 30;", +"}",".blocklyScrollbarHorizontal, .blocklyScrollbarVertical {","position: absolute;","outline: none;","}",".blocklyScrollbarBackground {","opacity: 0;","}",".blocklyScrollbarHandle {","fill: #ccc;","}",".blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyScrollbarHandle:hover {","fill: #bbb;","}",".blocklyZoom>image, .blocklyZoom>svg>image {","opacity: .4;","}",".blocklyZoom>image:hover, .blocklyZoom>svg>image:hover {","opacity: .6;","}",".blocklyZoom>image:active, .blocklyZoom>svg>image:active {", +"opacity: .8;","}",".blocklyFlyout .blocklyScrollbarHandle {","fill: #bbb;","}",".blocklyFlyout .blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyFlyout .blocklyScrollbarHandle:hover {","fill: #aaa;","}",".blocklyInvalidInput {","background: #faa;","}",".blocklyAngleCircle {","stroke: #444;","stroke-width: 1;","fill: #ddd;","fill-opacity: .8;","}",".blocklyAngleMarks {","stroke: #444;","stroke-width: 1;","}",".blocklyAngleGauge {","fill: #f88;","fill-opacity: .8;","}",".blocklyAngleLine {", +"stroke: #f00;","stroke-width: 2;","stroke-linecap: round;","pointer-events: none;","}",".blocklyContextMenu {","border-radius: 4px;","}",".blocklyDropdownMenu {","padding: 0 !important;","}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(<<>>/sprites.png) no-repeat -48px -16px !important;","}",".blocklyToolboxDiv {","background-color: #ddd;","overflow-x: visible;","overflow-y: auto;","position: absolute;", +"user-select: none;","-moz-user-select: none;","-ms-user-select: none;","-webkit-user-select: none;","z-index: 70;","-webkit-tap-highlight-color: transparent;","}",".blocklyTreeRoot {","padding: 4px 0;","}",".blocklyTreeRoot:focus {","outline: none;","}",".blocklyTreeRow {","height: 22px;","line-height: 22px;","margin-bottom: 3px;","padding-right: 8px;","white-space: nowrap;","}",".blocklyHorizontalTree {","float: left;","margin: 1px 5px 8px 0;","}",".blocklyHorizontalTreeRtl {","float: right;","margin: 1px 0 8px 5px;", +"}",'.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {',"margin-left: 8px;","}",".blocklyTreeRow:not(.blocklyTreeSelected):hover {","background-color: #e4e4e4;","}",".blocklyTreeSeparator {","border-bottom: solid #e5e5e5 1px;","height: 0;","margin: 5px 0;","}",".blocklyTreeSeparatorHorizontal {","border-right: solid #e5e5e5 1px;","width: 0;","padding: 5px 0;","margin: 0 5px;","}",".blocklyTreeIcon {","background-image: url(<<>>/sprites.png);","height: 16px;","vertical-align: middle;","width: 16px;", +"}",".blocklyTreeIconClosedLtr {","background-position: -32px -1px;","}",".blocklyTreeIconClosedRtl {","background-position: 0 -1px;","}",".blocklyTreeIconOpen {","background-position: -16px -1px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedLtr {","background-position: -32px -17px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedRtl {","background-position: 0 -17px;","}",".blocklyTreeSelected>.blocklyTreeIconOpen {","background-position: -16px -17px;","}",".blocklyTreeIconNone,",".blocklyTreeSelected>.blocklyTreeIconNone {", +"background-position: -48px -1px;","}",".blocklyTreeLabel {","cursor: default;","font-family: sans-serif;","font-size: 16px;","padding: 0 3px;","vertical-align: middle;","}",".blocklyToolboxDelete .blocklyTreeLabel {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyTreeSelected .blocklyTreeLabel {","color: #fff;","}",".blocklyColourTable {","border-collapse: collapse;","}",".blocklyColourTable>tr>td {","border: 1px solid #666;","padding: 0;","}",".blocklyColourTable>tr>td>div {","border: 1px solid #666;", +"height: 13px;","width: 15px;","}",".blocklyColourTable>tr>td>div:hover {","border: 1px solid #fff;","}",".blocklyColourSelected, .blocklyColourSelected:hover {","border: 1px solid #000 !important;","}",".blocklyWidgetDiv .goog-menu {","background: #fff;","border-color: #ccc #666 #666 #ccc;","border-style: solid;","border-width: 1px;","cursor: default;","font: normal 13px Arial, sans-serif;","margin: 0;","outline: none;","padding: 4px 0;","position: absolute;","overflow-y: auto;","overflow-x: hidden;", +"max-height: 100%;","z-index: 20000;","}",".blocklyWidgetDiv .goog-menuitem {","color: #000;","font: normal 13px Arial, sans-serif;","list-style: none;","margin: 0;","padding: 4px 7em 4px 28px;","white-space: nowrap;","}",".blocklyWidgetDiv .goog-menuitem.goog-menuitem-rtl {","padding-left: 7em;","padding-right: 28px;","}",".blocklyWidgetDiv .goog-menu-nocheckbox .goog-menuitem,",".blocklyWidgetDiv .goog-menu-noicon .goog-menuitem {","padding-left: 12px;","}",".blocklyWidgetDiv .goog-menu-noaccel .goog-menuitem {", +"padding-right: 20px;","}",".blocklyWidgetDiv .goog-menuitem-content {","color: #000;","font: normal 13px Arial, sans-serif;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-accel,",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-content {","color: #ccc !important;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-icon {","opacity: 0.3;","filter: alpha(opacity=30);","}",".blocklyWidgetDiv .goog-menuitem-highlight,",".blocklyWidgetDiv .goog-menuitem-hover {","background-color: #d6e9f8;", +"border-color: #d6e9f8;","border-style: dotted;","border-width: 1px 0;","padding-bottom: 3px;","padding-top: 3px;","}",".blocklyWidgetDiv .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-menuitem-icon {","background-repeat: no-repeat;","height: 16px;","left: 6px;","position: absolute;","right: auto;","vertical-align: middle;","width: 16px;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-icon {","left: auto;","right: 6px;", +"}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;","}",".blocklyWidgetDiv .goog-menuitem-accel {","color: #999;","direction: ltr;","left: auto;","padding: 0 6px;","position: absolute;","right: 0;","text-align: right;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-accel {","left: 0;","right: auto;","text-align: left;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-hint {", +"text-decoration: underline;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-separator {","color: #999;","font-size: 12px;","padding-left: 4px;","}",".blocklyWidgetDiv .goog-menuseparator {","border-top: 1px solid #ccc;","margin: 4px 0;","padding: 0;","}",""];Blockly.WidgetDiv={};Blockly.WidgetDiv.DIV=null;Blockly.WidgetDiv.owner_=null;Blockly.WidgetDiv.dispose_=null;Blockly.WidgetDiv.createDom=function(){Blockly.WidgetDiv.DIV||(Blockly.WidgetDiv.DIV=document.createElement("div"),Blockly.WidgetDiv.DIV.className="blocklyWidgetDiv",document.body.appendChild(Blockly.WidgetDiv.DIV))}; Blockly.WidgetDiv.show=function(a,b,c){Blockly.WidgetDiv.hide();Blockly.WidgetDiv.owner_=a;Blockly.WidgetDiv.dispose_=c;a=goog.style.getViewportPageOffset(document);Blockly.WidgetDiv.DIV.style.top=a.y+"px";Blockly.WidgetDiv.DIV.style.direction=b?"rtl":"ltr";Blockly.WidgetDiv.DIV.style.display="block"}; Blockly.WidgetDiv.hide=function(){Blockly.WidgetDiv.owner_&&(Blockly.WidgetDiv.owner_=null,Blockly.WidgetDiv.DIV.style.display="none",Blockly.WidgetDiv.DIV.style.left="",Blockly.WidgetDiv.DIV.style.top="",Blockly.WidgetDiv.dispose_&&Blockly.WidgetDiv.dispose_(),Blockly.WidgetDiv.dispose_=null,Blockly.WidgetDiv.DIV.innerHTML="")};Blockly.WidgetDiv.isVisible=function(){return!!Blockly.WidgetDiv.owner_};Blockly.WidgetDiv.hideIfOwner=function(a){Blockly.WidgetDiv.owner_==a&&Blockly.WidgetDiv.hide()}; Blockly.WidgetDiv.position=function(a,b,c,d,e){bc.width+d.x&&(a=c.width+d.x):aa.viewHeight+d||a.contentLeft<(b.RTL?a.viewLeft:c)||a.contentLeft+a.contentWidth>(b.RTL?a.viewWidth:a.viewWidth+c))for(var k=e.getTopBlocks(!1),l=0,n;n=k[l];l++){var m=n.getRelativeToSurfaceXY(),p=n.getHeightWidth(),q=d+25-p.height-m.y;0q&&n.moveBy(0,q);q=25+c-m.x-(b.RTL?0:p.width);0m&&n.moveBy(m,0)}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.Tooltip.createDom(); -return e}; -Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart(),a.scrollX= -a.flyout_.width_,b.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT&&(a.scrollX*=-1),a.translate(a.scrollX,0)));b.hasScrollbars&&(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize());b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; +Blockly.createMainWorkspace_=function(a,b,c,d){b.parentWorkspace=null;var e=new Blockly.WorkspaceSvg(b,c,d);e.scale=b.zoomOptions.startScale;a.appendChild(e.createDom("blocklyMainBackground"));!b.hasCategories&&b.languageTree&&(c=e.addFlyout_("svg"),Blockly.utils.insertAfter(c,a));e.translate(0,0);Blockly.mainWorkspace=e;b.readOnly||b.hasScrollbars||e.addChangeListener(function(a){if(!e.isDragging()){var c=e.getMetrics(),d=c.viewLeft+c.absoluteLeft,f=c.viewTop+c.absoluteTop;if(c.contentTopc.viewHeight+f||c.contentLeft<(b.RTL?c.viewLeft:d)||c.contentLeft+c.contentWidth>(b.RTL?c.viewWidth:c.viewWidth+d)){var l=e.getTopBlocks(!1),n=null;a&&(n=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));for(var m=!1,p=0,q;q=l[p];p++){var r=q.getRelativeToSurfaceXY(),t=q.getHeightWidth(),u=f+25-t.height-r.y;0u&&(q.moveBy(0,u),m=!0);u=25+d-r.x-(b.RTL?0:t.width);0r&&(q.moveBy(r,0),m=!0)}a&&(!a.group&&m&&console.log("WARNING: Moved blocks in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(n))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.Tooltip.createDom();return e}; +Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart(), +a.scrollX=a.flyout_.width_,b.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT&&(a.scrollX*=-1),a.translate(a.scrollX,0)));b.hasScrollbars&&(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize());b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),goog.userAgent.IPAD&&Blockly.bindEventWithChecks_(window,"orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[];a=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,a,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,a,!0))}; -Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.cache3dSupported_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; +Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; Blockly.onKeyDown_=function(a){var b=Blockly.mainWorkspace;if(!(b.options.readOnly||Blockly.utils.isTargetInput(a)||b.rendered&&!b.isVisible())){var c=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode){a.preventDefault();if(b.isDragging())return;Blockly.selected&&Blockly.selected.isDeletable()&&(c=!0)}else if(a.altKey||a.ctrlKey||a.metaKey){if(b.isDragging())return;Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&(67==a.keyCode?(Blockly.hideChaff(), -Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(Blockly.Events.setGroup(!0),b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1)):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&&(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}}; -Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace};Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c}; -Blockly.onContextMenu_=function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()};Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();a||(a=Blockly.getMainWorkspace(),a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.flyout_.autoClose&&a.toolbox_.clearSelection())};Blockly.addChangeListener=function(a){console.warn("Deprecated call to Blockly.addChangeListener, use workspace.addChangeListener instead.");return Blockly.getMainWorkspace().addChangeListener(a)}; -Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){window.alert(a);b&&b()};Blockly.confirm=function(a,b){b(window.confirm(a))};Blockly.prompt=function(a,b,c){c(window.prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; +Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),Blockly.clipboardTypeCounts_&&b.isCapacityAvailable(Blockly.clipboardTypeCounts_)&&(Blockly.Events.setGroup(!0),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1))):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&&(Blockly.Events.setGroup(!0), +Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}};Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace;Blockly.clipboardTypeCounts_=a.isComment?null:Blockly.utils.getBlockTypeCounts(a,!0)}; +Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c};Blockly.onContextMenu_=function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()};Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();a||(a=Blockly.getMainWorkspace(),a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.flyout_.autoClose&&a.toolbox_.clearSelection())}; +Blockly.addChangeListener=function(a){console.warn("Deprecated call to Blockly.addChangeListener, use workspace.addChangeListener instead.");return Blockly.getMainWorkspace().addChangeListener(a)};Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){window.alert(a);b&&b()};Blockly.confirm=function(a,b){b(window.confirm(a))};Blockly.prompt=function(a,b,c){c(window.prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; Blockly.defineBlocksWithJsonArray=function(a){for(var b=0;ba&&(a+=360);360=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(c*a[0]+(1-c)*b[0]),Math.round(c*a[1]+(1-c)*b[1]),Math.round(c*a[2]+(1-c)*b[2])]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)};goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)}; -goog.color.highContrast=function(a,b){for(var c=[],d=0;d=a[2]?a[1]*a[2]:a[1]*(1-a[2]);var d=.5>=b[2]?b[1]*b[2]:b[1]*(1-b[2]);return(a[2]-b[2])*(a[2]-b[2])+c*c+d*d-2*c*d*Math.cos(2*(a[0]/360-b[0]/360)*Math.PI)};goog.color.blend=function(a,b,c){c=goog.math.clamp(c,0,1);return[Math.round(b[0]+c*(a[0]-b[0])),Math.round(b[1]+c*(a[1]-b[1])),Math.round(b[2]+c*(a[2]-b[2]))]};goog.color.darken=function(a,b){return goog.color.blend([0,0,0],a,b)}; +goog.color.lighten=function(a,b){return goog.color.blend([255,255,255],a,b)};goog.color.highContrast=function(a,b){for(var c=[],d=0;d=a.keyCode)a.keyCode=-1}catch(b){}};goog.events.BrowserEvent.prototype.getBrowserEvent=function(){return this.event_}; @@ -290,13 +290,14 @@ goog.functions.create=function(a,b){var c=function(){};c.prototype=a.prototype;c goog.functions.debounce=function(a,b,c){var d=0;return function(e){goog.global.clearTimeout(d);var f=arguments;d=goog.global.setTimeout(function(){a.apply(c,f)},b)}};goog.functions.throttle=function(a,b,c){var d=0,e=!1,f=[],g=function(){d=0;e&&(e=!1,h())},h=function(){d=goog.global.setTimeout(g,b);a.apply(c,f)};return function(a){f=arguments;d?e=!0:h()}};goog.functions.rateLimit=function(a,b,c){var d=0,e=function(){d=0};return function(f){d||(d=goog.global.setTimeout(e,b),a.apply(c,arguments))}};goog.dom.tags={};goog.dom.tags.VOID_TAGS_={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0};goog.dom.tags.isVoidTag=function(a){return!0===goog.dom.tags.VOID_TAGS_[a]};goog.string.TypedString=function(){};goog.string.Const=function(a,b){this.stringConstValueWithSecurityContract__googStringSecurityPrivate_=a===goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_&&b||"";this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_=goog.string.Const.TYPE_MARKER_};goog.string.Const.prototype.implementsGoogStringTypedString=!0;goog.string.Const.prototype.getTypedStringValue=function(){return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_}; goog.string.Const.prototype.toString=function(){return"Const{"+this.stringConstValueWithSecurityContract__googStringSecurityPrivate_+"}"};goog.string.Const.unwrap=function(a){if(a instanceof goog.string.Const&&a.constructor===goog.string.Const&&a.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_===goog.string.Const.TYPE_MARKER_)return a.stringConstValueWithSecurityContract__googStringSecurityPrivate_;goog.asserts.fail("expected object of type Const, got '"+a+"'");return"type_error:Const"}; goog.string.Const.from=function(a){return new goog.string.Const(goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_,a)};goog.string.Const.TYPE_MARKER_={};goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_={};goog.string.Const.EMPTY=goog.string.Const.from("");goog.html={};goog.html.SafeScript=function(){this.privateDoNotAccessOrElseSafeScriptWrappedValue_="";this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeScript.prototype.implementsGoogStringTypedString=!0;goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={};goog.html.SafeScript.fromConstant=function(a){a=goog.string.Const.unwrap(a);return 0===a.length?goog.html.SafeScript.EMPTY:goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(a)}; -goog.html.SafeScript.fromConstantAndArgs=function(a,b){for(var c=[],d=1;da?goog.i18n.bidi.Dir.RTL:b?null:goog.i18n.bidi.Dir.NEUTRAL:null==a?null:a?goog.i18n.bidi.Dir.RTL:goog.i18n.bidi.Dir.LTR};goog.i18n.bidi.ltrChars_="A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0900-\u1fff\u200e\u2c00-\ud801\ud804-\ud839\ud83c-\udbff\uf900-\ufb1c\ufe00-\ufe6f\ufefd-\uffff";goog.i18n.bidi.rtlChars_="\u0591-\u06ef\u06fa-\u08ff\u200f\ud802-\ud803\ud83a-\ud83b\ufb1d-\ufdff\ufe70-\ufefc"; goog.i18n.bidi.htmlSkipReg_=/<[^>]*>|&[^;]+;/g;goog.i18n.bidi.stripHtmlIfNeeded_=function(a,b){return b?a.replace(goog.i18n.bidi.htmlSkipReg_,""):a};goog.i18n.bidi.rtlCharReg_=new RegExp("["+goog.i18n.bidi.rtlChars_+"]");goog.i18n.bidi.ltrCharReg_=new RegExp("["+goog.i18n.bidi.ltrChars_+"]");goog.i18n.bidi.hasAnyRtl=function(a,b){return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.hasRtlChar=goog.i18n.bidi.hasAnyRtl; @@ -304,7 +305,7 @@ goog.i18n.bidi.hasAnyLtr=function(a,b){return goog.i18n.bidi.ltrCharReg_.test(go goog.i18n.bidi.ltrDirCheckRe_=new RegExp("^[^"+goog.i18n.bidi.rtlChars_+"]*["+goog.i18n.bidi.ltrChars_+"]");goog.i18n.bidi.rtlDirCheckRe_=new RegExp("^[^"+goog.i18n.bidi.ltrChars_+"]*["+goog.i18n.bidi.rtlChars_+"]");goog.i18n.bidi.startsWithRtl=function(a,b){return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isRtlText=goog.i18n.bidi.startsWithRtl; goog.i18n.bidi.startsWithLtr=function(a,b){return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isLtrText=goog.i18n.bidi.startsWithLtr;goog.i18n.bidi.isRequiredLtrRe_=/^http:\/\/.*/;goog.i18n.bidi.isNeutralText=function(a,b){a=goog.i18n.bidi.stripHtmlIfNeeded_(a,b);return goog.i18n.bidi.isRequiredLtrRe_.test(a)||!goog.i18n.bidi.hasAnyLtr(a)&&!goog.i18n.bidi.hasAnyRtl(a)}; goog.i18n.bidi.ltrExitDirCheckRe_=new RegExp("["+goog.i18n.bidi.ltrChars_+"][^"+goog.i18n.bidi.rtlChars_+"]*$");goog.i18n.bidi.rtlExitDirCheckRe_=new RegExp("["+goog.i18n.bidi.rtlChars_+"][^"+goog.i18n.bidi.ltrChars_+"]*$");goog.i18n.bidi.endsWithLtr=function(a,b){return goog.i18n.bidi.ltrExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isLtrExitText=goog.i18n.bidi.endsWithLtr; -goog.i18n.bidi.endsWithRtl=function(a,b){return goog.i18n.bidi.rtlExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isRtlExitText=goog.i18n.bidi.endsWithRtl;goog.i18n.bidi.rtlLocalesRe_=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;goog.i18n.bidi.isRtlLanguage=function(a){return goog.i18n.bidi.rtlLocalesRe_.test(a)};goog.i18n.bidi.bracketGuardTextRe_=/(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; +goog.i18n.bidi.endsWithRtl=function(a,b){return goog.i18n.bidi.rtlExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(a,b))};goog.i18n.bidi.isRtlExitText=goog.i18n.bidi.endsWithRtl;goog.i18n.bidi.rtlLocalesRe_=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Nkoo|Rohg|Thaa))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;goog.i18n.bidi.isRtlLanguage=function(a){return goog.i18n.bidi.rtlLocalesRe_.test(a)};goog.i18n.bidi.bracketGuardTextRe_=/(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g; goog.i18n.bidi.guardBracketInText=function(a,b){var c=(void 0===b?goog.i18n.bidi.hasAnyRtl(a):b)?goog.i18n.bidi.Format.RLM:goog.i18n.bidi.Format.LRM;return a.replace(goog.i18n.bidi.bracketGuardTextRe_,c+"$&"+c)};goog.i18n.bidi.enforceRtlInHtml=function(a){return"<"==a.charAt(0)?a.replace(/<\w+/,"$& dir=rtl"):"\n"+a+""};goog.i18n.bidi.enforceRtlInText=function(a){return goog.i18n.bidi.Format.RLE+a+goog.i18n.bidi.Format.PDF}; goog.i18n.bidi.enforceLtrInHtml=function(a){return"<"==a.charAt(0)?a.replace(/<\w+/,"$& dir=ltr"):"\n"+a+""};goog.i18n.bidi.enforceLtrInText=function(a){return goog.i18n.bidi.Format.LRE+a+goog.i18n.bidi.Format.PDF};goog.i18n.bidi.dimensionsRe_=/:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g;goog.i18n.bidi.leftRe_=/left/gi;goog.i18n.bidi.rightRe_=/right/gi;goog.i18n.bidi.tempRe_=/%%%%/g; goog.i18n.bidi.mirrorCSS=function(a){return a.replace(goog.i18n.bidi.dimensionsRe_,":$1 $4 $3 $2").replace(goog.i18n.bidi.leftRe_,"%%%%").replace(goog.i18n.bidi.rightRe_,goog.i18n.bidi.LEFT).replace(goog.i18n.bidi.tempRe_,goog.i18n.bidi.RIGHT)};goog.i18n.bidi.doubleQuoteSubstituteRe_=/([\u0591-\u05f2])"/g;goog.i18n.bidi.singleQuoteSubstituteRe_=/([\u0591-\u05f2])'/g; @@ -317,9 +318,10 @@ goog.html.TrustedResourceUrl.prototype.cloneWithParams=function(a,b){var c=goog. goog.DEBUG&&(goog.html.TrustedResourceUrl.prototype.toString=function(){return"TrustedResourceUrl{"+this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_+"}"}); goog.html.TrustedResourceUrl.unwrap=function(a){if(a instanceof goog.html.TrustedResourceUrl&&a.constructor===goog.html.TrustedResourceUrl&&a.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;goog.asserts.fail("expected object of type TrustedResourceUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:TrustedResourceUrl"}; goog.html.TrustedResourceUrl.format=function(a,b){var c=goog.string.Const.unwrap(a);if(!goog.html.TrustedResourceUrl.BASE_URL_.test(c))throw Error("Invalid TrustedResourceUrl format: "+c);var d=c.replace(goog.html.TrustedResourceUrl.FORMAT_MARKER_,function(a,d){if(!Object.prototype.hasOwnProperty.call(b,d))throw Error('Found marker, "'+d+'", in format string, "'+c+'", but no valid label mapping found in args: '+JSON.stringify(b));var e=b[d];return e instanceof goog.string.Const?goog.string.Const.unwrap(e): -encodeURIComponent(String(e))});return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(d)};goog.html.TrustedResourceUrl.FORMAT_MARKER_=/%{(\w+)}/g;goog.html.TrustedResourceUrl.BASE_URL_=/^(?:https:)?\/\/[0-9a-z.:[\]-]+\/|^\/[^\/\\]|^about:blank#/i;goog.html.TrustedResourceUrl.URL_PARAM_PARSER_=/^([^?#]*)(\?[^#]*)?(#[\s\S]*)?/;goog.html.TrustedResourceUrl.formatWithParams=function(a,b,c,d){return goog.html.TrustedResourceUrl.format(a,b).cloneWithParams(c,d)}; -goog.html.TrustedResourceUrl.fromConstant=function(a){return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))};goog.html.TrustedResourceUrl.fromConstants=function(a){for(var b="",c=0;ca.length?"&":"")+encodeURIComponent(d)+"="+encodeURIComponent(String(g)))}}return b};goog.html.SafeUrl=function(){this.privateDoNotAccessOrElseSafeHtmlWrappedValue_="";this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeUrl.INNOCUOUS_STRING="about:invalid#zClosurez";goog.html.SafeUrl.prototype.implementsGoogStringTypedString=!0;goog.html.SafeUrl.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_}; goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString=!0;goog.html.SafeUrl.prototype.getDirection=function(){return goog.i18n.bidi.Dir.LTR};goog.DEBUG&&(goog.html.SafeUrl.prototype.toString=function(){return"SafeUrl{"+this.privateDoNotAccessOrElseSafeHtmlWrappedValue_+"}"}); goog.html.SafeUrl.unwrap=function(a){if(a instanceof goog.html.SafeUrl&&a.constructor===goog.html.SafeUrl&&a.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_===goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_)return a.privateDoNotAccessOrElseSafeHtmlWrappedValue_;goog.asserts.fail("expected object of type SafeUrl, got '"+a+"' of type "+goog.typeOf(a));return"type_error:SafeUrl"};goog.html.SafeUrl.fromConstant=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.string.Const.unwrap(a))}; goog.html.SAFE_MIME_TYPE_PATTERN_=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime))$/i;goog.html.SafeUrl.fromBlob=function(a){a=goog.html.SAFE_MIME_TYPE_PATTERN_.test(a.type)?goog.fs.url.createObjectUrl(a):goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.DATA_URL_PATTERN_=/^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i; @@ -329,7 +331,7 @@ goog.html.SafeUrl.fromSmsUrl=function(a){goog.string.caseInsensitiveStartsWith(a goog.html.SafeUrl.sanitizeChromeExtensionUrl=function(a,b){return goog.html.SafeUrl.sanitizeExtensionUrl_(/^chrome-extension:\/\/([^\/]+)\//,a,b)};goog.html.SafeUrl.sanitizeFirefoxExtensionUrl=function(a,b){return goog.html.SafeUrl.sanitizeExtensionUrl_(/^moz-extension:\/\/([^\/]+)\//,a,b)};goog.html.SafeUrl.sanitizeEdgeExtensionUrl=function(a,b){return goog.html.SafeUrl.sanitizeExtensionUrl_(/^ms-browser-extension:\/\/([^\/]+)\//,a,b)}; goog.html.SafeUrl.sanitizeExtensionUrl_=function(a,b,c){(a=a.exec(b))?(a=a[1],-1==(c instanceof goog.string.Const?[goog.string.Const.unwrap(c)]:c.map(function(a){return goog.string.Const.unwrap(a)})).indexOf(a)&&(b=goog.html.SafeUrl.INNOCUOUS_STRING)):b=goog.html.SafeUrl.INNOCUOUS_STRING;return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(b)};goog.html.SafeUrl.fromTrustedResourceUrl=function(a){return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(goog.html.TrustedResourceUrl.unwrap(a))}; goog.html.SAFE_URL_PATTERN_=/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;goog.html.SafeUrl.SAFE_URL_PATTERN=goog.html.SAFE_URL_PATTERN_;goog.html.SafeUrl.sanitize=function(a){if(a instanceof goog.html.SafeUrl)return a;a="object"==typeof a&&a.implementsGoogStringTypedString?a.getTypedStringValue():String(a);goog.html.SAFE_URL_PATTERN_.test(a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)}; -goog.html.SafeUrl.sanitizeAssertUnchanged=function(a){if(a instanceof goog.html.SafeUrl)return a;a="object"==typeof a&&a.implementsGoogStringTypedString?a.getTypedStringValue():String(a);goog.asserts.assert(goog.html.SAFE_URL_PATTERN_.test(a))||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={}; +goog.html.SafeUrl.sanitizeAssertUnchanged=function(a){if(a instanceof goog.html.SafeUrl)return a;a="object"==typeof a&&a.implementsGoogStringTypedString?a.getTypedStringValue():String(a);goog.asserts.assert(goog.html.SAFE_URL_PATTERN_.test(a),"%s does not match the safe URL pattern",a)||(a=goog.html.SafeUrl.INNOCUOUS_STRING);return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(a)};goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={}; goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse=function(a){var b=new goog.html.SafeUrl;b.privateDoNotAccessOrElseSafeHtmlWrappedValue_=a;return b};goog.html.SafeUrl.ABOUT_BLANK=goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse("about:blank");goog.html.SafeStyle=function(){this.privateDoNotAccessOrElseSafeStyleWrappedValue_="";this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_=goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_};goog.html.SafeStyle.prototype.implementsGoogStringTypedString=!0;goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_={}; goog.html.SafeStyle.fromConstant=function(a){a=goog.string.Const.unwrap(a);if(0===a.length)return goog.html.SafeStyle.EMPTY;goog.html.SafeStyle.checkStyle_(a);goog.asserts.assert(goog.string.endsWith(a,";"),"Last character of style string is not ';': "+a);goog.asserts.assert(goog.string.contains(a,":"),"Style string must contain at least one ':', to specify a \"name: value\" pair: "+a);return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(a)}; goog.html.SafeStyle.checkStyle_=function(a){goog.asserts.assert(!/[<>]/.test(a),"Forbidden characters in style string: "+a)};goog.html.SafeStyle.prototype.getTypedStringValue=function(){return this.privateDoNotAccessOrElseSafeStyleWrappedValue_};goog.DEBUG&&(goog.html.SafeStyle.prototype.toString=function(){return"SafeStyle{"+this.privateDoNotAccessOrElseSafeStyleWrappedValue_+"}"}); @@ -590,8 +592,9 @@ goog.events.KeyHandler.prototype.handleKeyDown_=function(a){(goog.userAgent.WEBK a.keyCode!=goog.events.KeyCodes.META&&(this.lastKey_=goog.events.KeyCodes.META));goog.events.KeyHandler.USES_KEYDOWN_&&!goog.events.KeyCodes.firesKeyPressEvent(a.keyCode,this.lastKey_,a.shiftKey,a.ctrlKey,a.altKey,a.metaKey)?this.handleEvent(a):(this.keyCode_=goog.events.KeyCodes.normalizeKeyCode(a.keyCode),goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_&&(this.altKey_=a.altKey))};goog.events.KeyHandler.prototype.resetState=function(){this.keyCode_=this.lastKey_=-1}; goog.events.KeyHandler.prototype.handleKeyup_=function(a){this.resetState();this.altKey_=a.altKey}; goog.events.KeyHandler.prototype.handleEvent=function(a){var b=a.getBrowserEvent(),c=b.altKey;if(goog.userAgent.IE&&a.type==goog.events.EventType.KEYPRESS){var d=this.keyCode_;var e=d!=goog.events.KeyCodes.ENTER&&d!=goog.events.KeyCodes.ESC?b.keyCode:0}else(goog.userAgent.WEBKIT||goog.userAgent.EDGE)&&a.type==goog.events.EventType.KEYPRESS?(d=this.keyCode_,e=0<=b.charCode&&63232>b.charCode&&goog.events.KeyCodes.isCharacterKey(d)?b.charCode:0):goog.userAgent.OPERA&&!goog.userAgent.WEBKIT?(d=this.keyCode_, -e=goog.events.KeyCodes.isCharacterKey(d)?b.keyCode:0):(d=b.keyCode||this.keyCode_,e=b.charCode||0,goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_&&a.type==goog.events.EventType.KEYPRESS&&(c=this.altKey_),goog.userAgent.MAC&&e==goog.events.KeyCodes.QUESTION_MARK&&d==goog.events.KeyCodes.WIN_KEY&&(d=goog.events.KeyCodes.SLASH));var f=d=goog.events.KeyCodes.normalizeKeyCode(d);d?63232<=d&&d in goog.events.KeyHandler.safariKey_?f=goog.events.KeyHandler.safariKey_[d]:25==d&&a.shiftKey&&(f=9):b.keyIdentifier&& -b.keyIdentifier in goog.events.KeyHandler.keyIdentifier_&&(f=goog.events.KeyHandler.keyIdentifier_[b.keyIdentifier]);goog.userAgent.GECKO&&goog.events.KeyHandler.USES_KEYDOWN_&&a.type==goog.events.EventType.KEYPRESS&&!goog.events.KeyCodes.firesKeyPressEvent(f,this.lastKey_,a.shiftKey,a.ctrlKey,c,a.metaKey)||(a=f==this.lastKey_,this.lastKey_=f,b=new goog.events.KeyEvent(f,e,a,b),b.altKey=c,this.dispatchEvent(b))};goog.events.KeyHandler.prototype.getElement=function(){return this.element_}; +e=goog.events.KeyCodes.isCharacterKey(d)?b.keyCode:0):(a.type==goog.events.EventType.KEYPRESS?(goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_&&(c=this.altKey_),b.keyCode==b.charCode?32>b.keyCode?(d=b.keyCode,e=0):(d=this.keyCode_,e=b.charCode):(d=b.keyCode||this.keyCode_,e=b.charCode||0)):(d=b.keyCode||this.keyCode_,e=b.charCode||0),goog.userAgent.MAC&&e==goog.events.KeyCodes.QUESTION_MARK&&d==goog.events.KeyCodes.WIN_KEY&&(d=goog.events.KeyCodes.SLASH));var f=d=goog.events.KeyCodes.normalizeKeyCode(d); +d?63232<=d&&d in goog.events.KeyHandler.safariKey_?f=goog.events.KeyHandler.safariKey_[d]:25==d&&a.shiftKey&&(f=9):b.keyIdentifier&&b.keyIdentifier in goog.events.KeyHandler.keyIdentifier_&&(f=goog.events.KeyHandler.keyIdentifier_[b.keyIdentifier]);goog.userAgent.GECKO&&goog.events.KeyHandler.USES_KEYDOWN_&&a.type==goog.events.EventType.KEYPRESS&&!goog.events.KeyCodes.firesKeyPressEvent(f,this.lastKey_,a.shiftKey,a.ctrlKey,c,a.metaKey)||(a=f==this.lastKey_,this.lastKey_=f,b=new goog.events.KeyEvent(f, +e,a,b),b.altKey=c,this.dispatchEvent(b))};goog.events.KeyHandler.prototype.getElement=function(){return this.element_}; goog.events.KeyHandler.prototype.attach=function(a,b){this.keyUpKey_&&this.detach();this.element_=a;this.keyPressKey_=goog.events.listen(this.element_,goog.events.EventType.KEYPRESS,this,b);this.keyDownKey_=goog.events.listen(this.element_,goog.events.EventType.KEYDOWN,this.handleKeyDown_,b,this);this.keyUpKey_=goog.events.listen(this.element_,goog.events.EventType.KEYUP,this.handleKeyup_,b,this)}; goog.events.KeyHandler.prototype.detach=function(){this.keyPressKey_&&(goog.events.unlistenByKey(this.keyPressKey_),goog.events.unlistenByKey(this.keyDownKey_),goog.events.unlistenByKey(this.keyUpKey_),this.keyUpKey_=this.keyDownKey_=this.keyPressKey_=null);this.element_=null;this.keyCode_=this.lastKey_=-1};goog.events.KeyHandler.prototype.disposeInternal=function(){goog.events.KeyHandler.superClass_.disposeInternal.call(this);this.detach()}; goog.events.KeyEvent=function(a,b,c,d){goog.events.BrowserEvent.call(this,d);this.type=goog.events.KeyHandler.EventType.KEY;this.keyCode=a;this.charCode=b;this.repeat=c};goog.inherits(goog.events.KeyEvent,goog.events.BrowserEvent);goog.ui.ComponentUtil={};goog.ui.ComponentUtil.getMouseEventType=function(a){return a.pointerEventsEnabled()?goog.events.PointerAsMouseEventType:goog.events.EventType};goog.dom.classlist={};goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST=!1;goog.dom.classlist.get=function(a){if(goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST||a.classList)return a.classList;a=a.className;return goog.isString(a)&&a.match(/\S+/g)||[]};goog.dom.classlist.set=function(a,b){a.className=b};goog.dom.classlist.contains=function(a,b){return goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST||a.classList?a.classList.contains(b):goog.array.contains(goog.dom.classlist.get(a),b)}; @@ -754,7 +757,7 @@ goog.debug.Logger.prototype.callPublish_=function(a){if(this.handlers_)for(var b goog.debug.LogManager.initialize=function(){goog.debug.LogManager.rootLogger_||(goog.debug.LogManager.rootLogger_=new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME),goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME]=goog.debug.LogManager.rootLogger_,goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG))};goog.debug.LogManager.getLoggers=function(){return goog.debug.LogManager.loggers_}; goog.debug.LogManager.getRoot=function(){goog.debug.LogManager.initialize();return goog.debug.LogManager.rootLogger_};goog.debug.LogManager.getLogger=function(a){goog.debug.LogManager.initialize();return goog.debug.LogManager.loggers_[a]||goog.debug.LogManager.createLogger_(a)};goog.debug.LogManager.createFunctionForCatchErrors=function(a){return function(b){(a||goog.debug.LogManager.getRoot()).severe("Error: "+b.message+" ("+b.fileName+" @ Line: "+b.line+")")}}; goog.debug.LogManager.createLogger_=function(a){var b=new goog.debug.Logger(a);if(goog.debug.Logger.ENABLE_HIERARCHY){var c=a.lastIndexOf("."),d=a.substr(0,c);c=a.substr(c+1);d=goog.debug.LogManager.getLogger(d);d.addChild_(c,b);b.setParent_(d)}return goog.debug.LogManager.loggers_[a]=b};goog.log={};goog.log.ENABLED=goog.debug.LOGGING_ENABLED;goog.log.ROOT_LOGGER_NAME=goog.debug.Logger.ROOT_LOGGER_NAME;goog.log.Logger=goog.debug.Logger;goog.log.Level=goog.debug.Logger.Level;goog.log.LogRecord=goog.debug.LogRecord;goog.log.getLogger=function(a,b){if(goog.log.ENABLED){var c=goog.debug.LogManager.getLogger(a);b&&c&&c.setLevel(b);return c}return null};goog.log.addHandler=function(a,b){goog.log.ENABLED&&a&&a.addHandler(b)}; -goog.log.removeHandler=function(a,b){return goog.log.ENABLED&&a?a.removeHandler(b):!1};goog.log.log=function(a,b,c,d){goog.log.ENABLED&&a&&a.log(b,c,d)};goog.log.error=function(a,b,c){goog.log.ENABLED&&a&&a.severe(b,c)};goog.log.warning=function(a,b,c){goog.log.ENABLED&&a&&a.warning(b,c)};goog.log.info=function(a,b,c){goog.log.ENABLED&&a&&a.info(b,c)};goog.log.fine=function(a,b,c){goog.log.ENABLED&&a&&a.fine(b,c)};goog.Thenable=function(){};goog.Thenable.prototype.then=function(a,b,c){};goog.Thenable.IMPLEMENTED_BY_PROP="$goog_Thenable";goog.Thenable.addImplementation=function(a){a.prototype.then=a.prototype.then;COMPILED?a.prototype[goog.Thenable.IMPLEMENTED_BY_PROP]=!0:a.prototype.$goog_Thenable=!0};goog.Thenable.isImplementedBy=function(a){if(!a)return!1;try{return COMPILED?!!a[goog.Thenable.IMPLEMENTED_BY_PROP]:!!a.$goog_Thenable}catch(b){return!1}};goog.async={};goog.async.FreeList=function(a,b,c){this.limit_=c;this.create_=a;this.reset_=b;this.occupants_=0;this.head_=null};goog.async.FreeList.prototype.get=function(){if(0this.remainingCapacityOfType(c))return!1;b+=a[c]}return b>this.remainingCapacity()?!1:!0};Blockly.Workspace.prototype.hasBlockLimits=function(){return Infinity!=this.options.maxBlocks||!!this.options.maxInstances}; Blockly.Workspace.prototype.undo=function(a){var b=a?this.redoStack_:this.undoStack_,c=a?this.undoStack_:this.redoStack_,d=b.pop();if(d){for(var e=[d];b.length&&d.group&&d.group==b[b.length-1].group;)e.push(b.pop());for(b=0;d=e[b];b++)c.push(d);e=Blockly.Events.filter(e,a);Blockly.Events.recordUndo=!1;try{for(b=0;d=e[b];b++)d.run(a)}finally{Blockly.Events.recordUndo=!0}}};Blockly.Workspace.prototype.clearUndo=function(){this.undoStack_.length=0;this.redoStack_.length=0;Blockly.Events.clearPendingUndo()}; Blockly.Workspace.prototype.addChangeListener=function(a){this.listeners_.push(a);return a};Blockly.Workspace.prototype.removeChangeListener=function(a){Blockly.utils.arrayRemove(this.listeners_,a)};Blockly.Workspace.prototype.fireChangeListener=function(a){if(a.recordUndo)for(this.undoStack_.push(a),this.redoStack_.length=0;this.undoStack_.length>this.MAX_UNDO&&0<=this.MAX_UNDO;)this.undoStack_.shift();for(var b=0,c;c=this.listeners_[b];b++)c(a)}; Blockly.Workspace.prototype.getBlockById=function(a){return this.blockDB_[a]||null};Blockly.Workspace.prototype.getCommentById=function(a){return this.commentDB_[a]||null};Blockly.Workspace.prototype.allInputsFilled=function(a){for(var b=this.getTopBlocks(!1),c=0,d;d=b[c];c++)if(!d.allInputsFilled(a))return!1;return!0};Blockly.Workspace.prototype.getPotentialVariableMap=function(){return this.potentialVariableMap_}; @@ -1026,7 +1033,7 @@ Blockly.Bubble.prototype.getRelativeToSurfaceXY=function(){return new goog.math. Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);this.blockId&&(a.blockId=this.blockId);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue;this.blockId=a.blockId};Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.collapseHidden=!0;Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconXY_=null; Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.utils.createSvgElement("g",{"class":"blocklyIconGroup"},null),this.block_.isInFlyout&&Blockly.utils.addClass(this.iconGroup_,"blocklyIconGroupReadonly"),this.drawIcon_(this.iconGroup_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEventWithChecks_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; Blockly.Icon.prototype.dispose=function(){Blockly.utils.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_};Blockly.Icon.prototype.iconClick_=function(a){this.block_.workspace.isDragging()||this.block_.isInFlyout||Blockly.utils.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){this.isVisible()&&this.bubble_.setColour(this.block_.getColour())}; -Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; +Blockly.Icon.prototype.renderIcon=function(a){if(this.collapseHidden&&this.block_.isCollapsed()||this.block_.isInsertionMarker())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;this.block_.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+",5)");this.computeIconLocation();return a=this.block_.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; Blockly.Icon.prototype.setIconLocation=function(a){this.iconXY_=a;this.isVisible()&&this.bubble_.setAnchorLocation(a)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.utils.getRelativeXY(this.iconGroup_);a=new goog.math.Coordinate(a.x+b.x+this.SIZE/2,a.y+b.y+this.SIZE/2);goog.math.Coordinate.equals(this.getIconLocation(),a)||this.setIconLocation(a)};Blockly.Icon.prototype.getIconLocation=function(){return this.iconXY_}; Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; Blockly.Comment.prototype.drawIcon_=function(a){Blockly.utils.createSvgElement("circle",{"class":"blocklyIconShape",r:"8",cx:"8",cy:"8"},a);Blockly.utils.createSvgElement("path",{"class":"blocklyIconSymbol",d:"m6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.4050.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25-1.201,0.998 -1.201,1.528 -1.204,2.19z"},a);Blockly.utils.createSvgElement("rect",{"class":"blocklyIconSymbol",x:"6.8",y:"10.78",height:"2",width:"2"},a)}; @@ -1046,8 +1053,9 @@ Blockly.Connection.prototype.canConnectWithReason_=function(a){if(!a)return Bloc Blockly.Connection.CAN_CONNECT:Blockly.Connection.REASON_CHECKS_FAILED}; Blockly.Connection.prototype.checkConnection_=function(a){switch(this.canConnectWithReason_(a)){case Blockly.Connection.CAN_CONNECT:break;case Blockly.Connection.REASON_SELF_CONNECTION:throw Error("Attempted to connect a block to itself.");case Blockly.Connection.REASON_DIFFERENT_WORKSPACES:throw Error("Blocks not on same workspace.");case Blockly.Connection.REASON_WRONG_TYPE:throw Error("Attempt to connect incompatible types.");case Blockly.Connection.REASON_TARGET_NULL:throw Error("Target connection is null."); case Blockly.Connection.REASON_CHECKS_FAILED:throw Error("Connection checks failed. "+(this+" expected "+this.check_+", found "+a.check_));case Blockly.Connection.REASON_SHADOW_PARENT:throw Error("Connecting non-shadow to shadow block.");default:throw Error("Unknown connection failure: this should never happen!");}}; -Blockly.Connection.prototype.isConnectionAllowed=function(a){if(this.canConnectWithReason_(a)!=Blockly.Connection.CAN_CONNECT)return!1;switch(a.type){case Blockly.PREVIOUS_STATEMENT:if(a.isConnected()||this.isConnected())return!1;break;case Blockly.OUTPUT_VALUE:if(a.isConnected()||this.isConnected())return!1;break;case Blockly.INPUT_VALUE:if(a.targetConnection&&!a.targetBlock().isMovable()&&!a.targetBlock().isShadow())return!1;break;case Blockly.NEXT_STATEMENT:if(a.isConnected()&&!this.sourceBlock_.nextConnection&& -!a.targetBlock().isShadow()&&a.targetBlock().nextConnection)return!1;break;default:throw Error("Unknown connection type in isConnectionAllowed");}return-1!=Blockly.draggingConnections_.indexOf(a)?!1:!0};Blockly.Connection.prototype.connect=function(a){this.targetConnection!=a&&(this.checkConnection_(a),this.isSuperior()?this.connect_(a):a.connect_(this))}; +Blockly.Connection.prototype.canConnectToPrevious_=function(a){if(this.targetConnection||-1!=Blockly.draggingConnections_.indexOf(a))return!1;if(!a.targetConnection)return!0;a=a.targetBlock();return a.isInsertionMarker()?!a.getPreviousBlock():!1}; +Blockly.Connection.prototype.isConnectionAllowed=function(a){if(a.sourceBlock_.isInsertionMarker()||this.canConnectWithReason_(a)!=Blockly.Connection.CAN_CONNECT)return!1;switch(a.type){case Blockly.PREVIOUS_STATEMENT:return this.canConnectToPrevious_(a);case Blockly.OUTPUT_VALUE:if(a.isConnected()||this.isConnected())return!1;break;case Blockly.INPUT_VALUE:if(a.isConnected()&&!a.targetBlock().isMovable()&&!a.targetBlock().isShadow())return!1;break;case Blockly.NEXT_STATEMENT:if(a.isConnected()&& +!this.sourceBlock_.nextConnection&&!a.targetBlock().isShadow()&&a.targetBlock().nextConnection)return!1;break;default:throw Error("Unknown connection type in isConnectionAllowed");}return-1!=Blockly.draggingConnections_.indexOf(a)?!1:!0};Blockly.Connection.prototype.connect=function(a){this.targetConnection!=a&&(this.checkConnection_(a),this.isSuperior()?this.connect_(a):a.connect_(this))}; Blockly.Connection.connectReciprocally_=function(a,b){if(!a||!b)throw Error("Cannot connect null connections.");a.targetConnection=b;b.targetConnection=a};Blockly.Connection.singleConnection_=function(a,b){for(var c=!1,d=0;da.y_)c=d;else{b=d;break}}return b};Blockly.ConnectionDB.prototype.removeConnection_=function(a){if(!a.inDB_)throw Error("Connection not in database.");var b=this.findConnection(a);if(-1==b)throw Error("Unable to find connection in connectionDB.");a.inDB_=!1;this.splice(b,1)}; Blockly.ConnectionDB.prototype.getNeighbours=function(a,b){function c(a){var c=e-d[a].x_,g=f-d[a].y_;Math.sqrt(c*c+g*g)<=b&&l.push(d[a]);return gc)){var d=b.getSvgXY(a.getSvgRoot());a.outputConnection?(d.x+=(a.RTL?3:-3)*c,d.y+=13*c):a.previousConnection&&(d.x+=(a.RTL?-23:23)*c,d.y+=3*c);a=Blockly.utils.createSvgElement("circle",{cx:d.x,cy:d.y,r:0,fill:"none",stroke:"#888","stroke-width":10},b.getParentSvg());Blockly.BlockAnimations.connectionUiStep_(a,new Date,c)}}; Blockly.BlockAnimations.connectionUiStep_=function(a,b,c){var d=(new Date-b)/150;1a.workspace.scale)){var b=a.getHeightWidth().height;b=Math.atan(10/b)/Math.PI*180;a.RTL||(b*=-1);Blockly.BlockAnimations.disconnectUiStep_(a.getSvgRoot(),b,new Date)}}; Blockly.BlockAnimations.disconnectUiStep_=function(a,b,c){var d=(new Date-c)/200;1'+goog.string.htmlEscape(a.name)+""}; Blockly.Variables.generateVariableFieldDom=function(a){a=Blockly.Variables.generateVariableFieldXmlString(a);return Blockly.Xml.textToDom(""+a+"").firstChild};Blockly.Variables.getOrCreateVariablePackage=function(a,b,c,d){var e=Blockly.Variables.getVariable(a,b,c,d);e||(e=Blockly.Variables.createVariable_(a,b,c,d));return e}; -Blockly.Variables.getVariable=function(a,b,c,d){var e=a.getPotentialVariableMap();if(b){var f=a.getVariableById(b);!f&&e&&(f=e.getVariableById(b))}else if(c){if(void 0==d)throw Error("Tried to look up a variable by name without a type");f=a.getVariable(c,d);!f&&e&&(f=e.getVariable(c,d))}return f}; +Blockly.Variables.getVariable=function(a,b,c,d){var e=a.getPotentialVariableMap();if(b){var f=a.getVariableById(b);!f&&e&&(f=e.getVariableById(b));if(f)return f}if(c){if(void 0==d)throw Error("Tried to look up a variable by name without a type");f=a.getVariable(c,d);!f&&e&&(f=e.getVariable(c,d))}return f}; Blockly.Variables.createVariable_=function(a,b,c,d){var e=a.getPotentialVariableMap();c||(c=Blockly.Variables.generateUniqueName(a.isFlyout?a.targetWorkspace:a));return e?e.createVariable(c,d,b):a.createVariable(c,d,b)};Blockly.Variables.getAddedVariables=function(a,b){var c=a.getAllVariables(),d=[];if(b.length!=c.length)for(var e=0;e";c=Blockly.Xml.textToDom(c).firstChild;b.push(c)}if(Blockly.Blocks.variables_get_dynamic)for(var d=0;c=a[d];d++)c=''+Blockly.Variables.generateVariableFieldXmlString(c)+ "",c=Blockly.Xml.textToDom(c).firstChild,b.push(c)}return b};Blockly.WorkspaceAudio=function(a){this.parentWorkspace_=a;this.SOUNDS_=Object.create(null)};Blockly.WorkspaceAudio.prototype.lastSound_=null;Blockly.WorkspaceAudio.prototype.dispose=function(){this.SOUNDS_=this.parentWorkspace_=null};Blockly.WorkspaceAudio.prototype.load=function(a,b){if(a.length){try{var c=new window.Audio}catch(h){return}for(var d,e=0;eb.bottomRight.x&&(b.bottomRight.x=d.bottomRight.x);d.topLeft.yb.bottomRight.y&&(b.bottomRight.y=d.bottomRight.y)}return{x:b.topLeft.x, -y:b.topLeft.y,width:b.bottomRight.x-b.topLeft.x,height:b.bottomRight.y-b.topLeft.y}};Blockly.WorkspaceSvg.prototype.cleanUp=function(){this.setResizesEnabled(!1);Blockly.Events.setGroup(!0);for(var a=this.getTopBlocks(!0),b=0,c=0,d;d=a[c];c++){var e=d.getRelativeToSurfaceXY();d.moveBy(-e.x,b-e.y);d.snapToGrid();b=d.getRelativeToSurfaceXY().y+d.getHeightWidth().height+Blockly.BlockSvg.MIN_BLOCK_Y}Blockly.Events.setGroup(!1);this.setResizesEnabled(!0)}; +y:b.topLeft.y,width:b.bottomRight.x-b.topLeft.x,height:b.bottomRight.y-b.topLeft.y}};Blockly.WorkspaceSvg.prototype.cleanUp=function(){this.setResizesEnabled(!1);Blockly.Events.setGroup(!0);for(var a=this.getTopBlocks(!0),b=0,c=0,d;d=a[c];c++)if(d.isMovable()){var e=d.getRelativeToSurfaceXY();d.moveBy(-e.x,b-e.y);d.snapToGrid();b=d.getRelativeToSurfaceXY().y+d.getHeightWidth().height+Blockly.BlockSvg.MIN_BLOCK_Y}Blockly.Events.setGroup(!1);this.setResizesEnabled(!0)}; Blockly.WorkspaceSvg.prototype.showContextMenu_=function(a){function b(a){if(a.isDeletable())p=p.concat(a.getDescendants(!1));else{a=a.getChildren(!1);for(var c=0;cp.length?c():Blockly.confirm(Blockly.Msg.DELETE_ALL_BLOCKS.replace("%1",p.length),function(a){a&& @@ -1366,11 +1375,11 @@ Blockly.Warning.textToDom_=function(a){var b=Blockly.utils.createSvgElement("tex Blockly.Warning.prototype.setVisible=function(a){if(a!=this.isVisible())if(Blockly.Events.fire(new Blockly.Events.Ui(this.block_,"warningOpen",!a,a)),a){a=Blockly.Warning.textToDom_(this.getText());this.bubble_=new Blockly.Bubble(this.block_.workspace,a,this.block_.svgPath_,this.iconXY_,null,null);this.bubble_.setSvgId(this.block_.id);if(this.block_.RTL)for(var b=a.getBBox().width,c=0,d;d=a.childNodes[c];c++)d.setAttribute("text-anchor","end"),d.setAttribute("x",b+Blockly.Bubble.BORDER_WIDTH);this.updateColour(); a=this.bubble_.getBubbleSize();this.bubble_.setBubbleSize(a.width,a.height)}else this.bubble_.dispose(),this.body_=this.bubble_=null};Blockly.Warning.prototype.bodyFocus_=function(a){this.bubble_.promote_()};Blockly.Warning.prototype.setText=function(a,b){this.text_[b]!=a&&(a?this.text_[b]=a:delete this.text_[b],this.isVisible()&&(this.setVisible(!1),this.setVisible(!0)))};Blockly.Warning.prototype.getText=function(){var a=[],b;for(b in this.text_)a.push(this.text_[b]);return a.join("\n")}; Blockly.Warning.prototype.dispose=function(){this.block_.warning=null;Blockly.Icon.prototype.dispose.call(this)};Blockly.Block=function(a,b,c){if("undefined"!==typeof Blockly.Generator.prototype[b])throw Error('Block prototypeName "'+b+'" conflicts with Blockly.Generator members.');this.id=c&&!a.getBlockById(c)?c:Blockly.utils.genUid();a.blockDB_[this.id]=this;this.previousConnection=this.nextConnection=this.outputConnection=null;this.inputList=[];this.inputsInline=void 0;this.disabled=!1;this.tooltip="";this.contextMenu=!0;this.parentBlock_=null;this.childBlocks_=[];this.editable_=this.movable_=this.deletable_= -!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new goog.math.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a=Blockly.Events.getGroup())|| +!0;this.collapsed_=this.isShadow_=!1;this.comment=null;this.xy_=new goog.math.Coordinate(0,0);this.workspace=a;this.isInFlyout=a.isFlyout;this.isInMutator=a.isMutator;this.RTL=a.RTL;this.isInsertionMarker_=!1;if(b){this.type=b;c=Blockly.Blocks[b];if(!c||"object"!=typeof c)throw TypeError("Unknown block type: "+b);goog.mixin(this,c)}a.addTopBlock(this);a.addTypedBlock(this);"function"==typeof this.init&&this.init();this.inputsInlineDefault=this.inputsInline;if(Blockly.Events.isEnabled()){(a=Blockly.Events.getGroup())|| Blockly.Events.setGroup(!0);try{Blockly.Events.fire(new Blockly.Events.BlockCreate(this))}finally{a||Blockly.Events.setGroup(!1)}}"function"==typeof this.onchange&&this.setOnChange(this.onchange)};Blockly.Block.obtain=function(a,b){console.warn("Deprecated call to Blockly.Block.obtain, use workspace.newBlock instead.");return a.newBlock(b)};Blockly.Block.prototype.data=null;Blockly.Block.prototype.colour_="#000000";Blockly.Block.prototype.hue_=null; -Blockly.Block.prototype.dispose=function(a){if(this.workspace){this.onchangeWrapper_&&this.workspace.removeChangeListener(this.onchangeWrapper_);this.unplug(a);Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.BlockDelete(this));Blockly.Events.disable();try{this.workspace&&(this.workspace.removeTopBlock(this),delete this.workspace.blockDB_[this.id],this.workspace=null);Blockly.selected==this&&(Blockly.selected=null);for(var b=this.childBlocks_.length-1;0<=b;b--)this.childBlocks_[b].dispose(!1); -b=0;for(var c;c=this.inputList[b];b++)c.dispose();this.inputList.length=0;var d=this.getConnections_(!0);for(b=0;b=c)this.hue_=c,this.colour_=Blockly.hueToRgb(c);else if("string"==typeof b&&/^#[0-9a-fA-F]{6}$/.test(b))this.colour_=b,this.hue_=null;else throw c='Invalid colour: "'+b+'"',a!=b&&(c+=' (from "'+a+'")'),c;}; @@ -1421,7 +1430,7 @@ Blockly.ContextMenu.position_=function(a,b,c){var d=Blockly.utils.getViewportBBo Blockly.ContextMenu.createWidget_=function(a){a.render(Blockly.WidgetDiv.DIV);var b=a.getElement();Blockly.utils.addClass(b,"blocklyContextMenu");Blockly.bindEventWithChecks_(b,"contextmenu",null,Blockly.utils.noEvent);a.setAllowAutoFocus(!0)};Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null;Blockly.ContextMenu.eventWrapper_&&Blockly.unbindEvent_(Blockly.ContextMenu.eventWrapper_)}; Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();try{var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y)}finally{Blockly.Events.enable()}Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.BlockCreate(c));c.select()}}; Blockly.ContextMenu.blockDeleteOption=function(a){var b=a.getDescendants(!1).length,c=a.getNextBlock();c&&(b-=c.getDescendants(!1).length);return{text:1==b?Blockly.Msg.DELETE_BLOCK:Blockly.Msg.DELETE_X_BLOCKS.replace("%1",String(b)),enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.blockHelpOption=function(a){return{enabled:!("function"==typeof a.helpUrl?!a.helpUrl():!a.helpUrl),text:Blockly.Msg.HELP,callback:function(){a.showHelp_()}}}; -Blockly.ContextMenu.blockDuplicateOption=function(a){var b=!0;a.getDescendants(!1).length>a.workspace.remainingCapacity()&&(b=!1);return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!goog.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; +Blockly.ContextMenu.blockDuplicateOption=function(a){var b=a.isDuplicatable();return{text:Blockly.Msg.DUPLICATE_BLOCK,enabled:b,callback:function(){Blockly.duplicate_(a)}}};Blockly.ContextMenu.blockCommentOption=function(a){var b={enabled:!goog.userAgent.IE};a.comment?(b.text=Blockly.Msg.REMOVE_COMMENT,b.callback=function(){a.setCommentText(null)}):(b.text=Blockly.Msg.ADD_COMMENT,b.callback=function(){a.setCommentText("")});return b}; Blockly.ContextMenu.commentDeleteOption=function(a){return{text:Blockly.Msg.REMOVE_COMMENT,enabled:!0,callback:function(){Blockly.Events.setGroup(!0);a.dispose(!0,!0);Blockly.Events.setGroup(!1)}}};Blockly.ContextMenu.commentDuplicateOption=function(a){return{text:Blockly.Msg.DUPLICATE_COMMENT,enabled:!0,callback:function(){Blockly.duplicate_(a)}}}; Blockly.ContextMenu.workspaceCommentOption=function(a,b){var c={enabled:!goog.userAgent.IE};c.text=Blockly.Msg.ADD_COMMENT;c.callback=function(){var c=new Blockly.WorkspaceCommentSvg(a,Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE,Blockly.WorkspaceCommentSvg.DEFAULT_SIZE),e=a.getInjectionDiv().getBoundingClientRect();e=new goog.math.Coordinate(b.clientX-e.left,b.clientY-e.top);var f=a.getOriginOffsetInPixels();e=goog.math.Coordinate.difference(e,f).scale(1/a.scale); c.moveBy(e.x,e.y);a.rendered&&(c.initSvg(),c.render(!1),c.select())};return c};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.utils.createSvgElement("g",{},null);this.svgGroup_.translate_="";this.svgPathDark_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.utils.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.utils.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;this.useDragSurface_= @@ -1472,10 +1481,11 @@ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER=Blockly.BlockSvg.NOTCH_PATH_RIGHT+" h -"+ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL="a "+Blockly.BlockSvg.CORNER_RADIUS+","+Blockly.BlockSvg.CORNER_RADIUS+" 0 0,0 "+(-Blockly.BlockSvg.DISTANCE_45_OUTSIDE-.5)+","+(Blockly.BlockSvg.CORNER_RADIUS-Blockly.BlockSvg.DISTANCE_45_OUTSIDE);Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL="a "+(Blockly.BlockSvg.CORNER_RADIUS+.5)+","+(Blockly.BlockSvg.CORNER_RADIUS+.5)+" 0 0,0 "+(Blockly.BlockSvg.CORNER_RADIUS+.5)+","+(Blockly.BlockSvg.CORNER_RADIUS+.5); Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_LTR="a "+(Blockly.BlockSvg.CORNER_RADIUS+.5)+","+(Blockly.BlockSvg.CORNER_RADIUS+.5)+" 0 0,0 "+(Blockly.BlockSvg.CORNER_RADIUS-Blockly.BlockSvg.DISTANCE_45_OUTSIDE)+","+(Blockly.BlockSvg.DISTANCE_45_OUTSIDE+.5);Blockly.BlockSvg.prototype.getHeightWidth=function(){var a=this.height,b=this.width,c=this.getNextBlock();c?(c=c.getHeightWidth(),a+=c.height-4,b=Math.max(b,c.width)):this.nextConnection||this.outputConnection||(a+=2);return{height:a,width:b}}; Blockly.BlockSvg.prototype.render=function(a){Blockly.Field.startCache();this.rendered=!0;var b=Blockly.BlockSvg.SEP_SPACE_X;this.RTL&&(b=-b);for(var c=this.getIcons(),d=0;da)}};Blockly.Flyout.prototype.reflow=function(){this.reflowWrapper_&&this.workspace_.removeChangeListener(this.reflowWrapper_);this.reflowInternal_();this.reflowWrapper_&&this.workspace_.addChangeListener(this.reflowWrapper_)}; +Blockly.Flyout.prototype.filterForCapacity_=function(){for(var a=this.workspace_.getTopBlocks(!1),b=0,c;c=a[b];b++)-1==this.permanentlyDisabled_.indexOf(c)&&c.setDisabled(!this.targetWorkspace_.isCapacityAvailable(Blockly.utils.getBlockTypeCounts(c)))};Blockly.Flyout.prototype.reflow=function(){this.reflowWrapper_&&this.workspace_.removeChangeListener(this.reflowWrapper_);this.reflowInternal_();this.reflowWrapper_&&this.workspace_.addChangeListener(this.reflowWrapper_)}; Blockly.Flyout.prototype.isScrollable=function(){return this.scrollbar_?this.scrollbar_.isVisible():!1}; Blockly.Flyout.prototype.placeNewBlock_=function(a){var b=this.targetWorkspace_;if(!a.getSvgRoot())throw Error("oldBlock is not rendered.");var c=Blockly.Xml.blockToDom(a);b.setResizesEnabled(!1);c=Blockly.Xml.domToBlock(c,b);if(!c.getSvgRoot())throw Error("block is not rendered.");var d=b.getOriginOffsetInPixels(),e=this.workspace_.getOriginOffsetInPixels();a=a.getRelativeToSurfaceXY().scale(this.workspace_.scale);a=goog.math.Coordinate.sum(e,a);b=goog.math.Coordinate.difference(a,d).scale(1/b.scale); c.moveBy(b.x,b.y);return c};Blockly.HorizontalFlyout=function(a){a.getMetrics=this.getMetrics_.bind(this);a.setMetrics=this.setMetrics_.bind(this);Blockly.HorizontalFlyout.superClass_.constructor.call(this,a);this.horizontalLayout_=!0};goog.inherits(Blockly.HorizontalFlyout,Blockly.Flyout); @@ -1667,25 +1677,26 @@ Blockly.Css.CONTENT=[".blocklySvg {","background-color: #fff;","outline: none;", "color: #000;","display: none;","font-family: sans-serif;","font-size: 9pt;","opacity: .9;","padding: 2px;","position: absolute;","z-index: 100000;","}",".blocklyResizeSE {","cursor: se-resize;","fill: #aaa;","}",".blocklyResizeSW {","cursor: sw-resize;","fill: #aaa;","}",".blocklyResizeLine {","stroke: #515A5A;","stroke-width: 1;","}",".blocklyHighlightedConnectionPath {","fill: none;","stroke: #fc3;","stroke-width: 4px;","}",".blocklyPathLight {","fill: none;","stroke-linecap: round;","stroke-width: 1;", "}",".blocklySelected>.blocklyPath {","stroke: #fc3;","stroke-width: 3px;","}",".blocklySelected>.blocklyPathLight {","display: none;","}",".blocklyDraggable {",'cursor: url("<<>>/handopen.cur"), auto;',"cursor: grab;","cursor: -webkit-grab;","}",".blocklyDragging {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;","}",".blocklyDraggable:active {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;", "}",".blocklyBlockDragSurface .blocklyDraggable {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;","}",".blocklyDragging.blocklyDraggingDelete {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyToolboxDelete {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyToolboxGrab {",'cursor: url("<<>>/handclosed.cur"), auto;',"cursor: grabbing;","cursor: -webkit-grabbing;","}",".blocklyDragging>.blocklyPath,",".blocklyDragging>.blocklyPathLight {", -"fill-opacity: .8;","stroke-opacity: .8;","}",".blocklyDragging>.blocklyPathDark {","display: none;","}",".blocklyDisabled>.blocklyPath {","fill-opacity: .5;","stroke-opacity: .5;","}",".blocklyDisabled>.blocklyPathLight,",".blocklyDisabled>.blocklyPathDark {","display: none;","}",".blocklyText {","cursor: default;","fill: #fff;","font-family: sans-serif;","font-size: 11pt;","}",".blocklyNonEditableText>text {","pointer-events: none;","}",".blocklyNonEditableText>rect,",".blocklyEditableText>rect {", -"fill: #fff;","fill-opacity: .6;","}",".blocklyNonEditableText>text,",".blocklyEditableText>text {","fill: #000;","}",".blocklyEditableText:hover>rect {","stroke: #fff;","stroke-width: 2;","}",".blocklyBubbleText {","fill: #000;","}",".blocklyFlyout {","position: absolute;","z-index: 20;","}",".blocklyFlyoutButton {","fill: #888;","cursor: default;","}",".blocklyFlyoutButtonShadow {","fill: #666;","}",".blocklyFlyoutButton:hover {","fill: #aaa;","}",".blocklyFlyoutLabel {","cursor: default;","}", -".blocklyFlyoutLabelBackground {","opacity: 0;","}",".blocklyFlyoutLabelText {","fill: #000;","}",".blocklySvg text, .blocklyBlockDragSurface text {","user-select: none;","-moz-user-select: none;","-ms-user-select: none;","-webkit-user-select: none;","cursor: inherit;","}",".blocklyHidden {","display: none;","}",".blocklyFieldDropdown:not(.blocklyHidden) {","display: block;","}",".blocklyIconGroup {","cursor: default;","}",".blocklyIconGroup:not(:hover),",".blocklyIconGroupReadonly {","opacity: .6;", -"}",".blocklyIconShape {","fill: #00f;","stroke: #fff;","stroke-width: 1px;","}",".blocklyIconSymbol {","fill: #fff;","}",".blocklyMinimalBody {","margin: 0;","padding: 0;","}",".blocklyCommentForeignObject {","position: relative;","z-index: 0;","}",".blocklyCommentRect {","fill: #E7DE8E;","stroke: #bcA903;","stroke-width: 1px","}",".blocklyCommentTarget {","fill: transparent;","stroke: #bcA903;","}",".blocklyCommentTargetFocused {","fill: none;","}",".blocklyCommentHandleTarget {","fill: none;", -"}",".blocklyCommentHandleTargetFocused {","fill: transparent;","}",".blocklyFocused>.blocklyCommentRect {","fill: #B9B272;","stroke: #B9B272;","}",".blocklySelected>.blocklyCommentTarget {","stroke: #fc3;","stroke-width: 3px;","}",".blocklyCommentTextarea {","background-color: #fef49c;","border: 0;","outline: 0;","margin: 0;","padding: 3px;","resize: none;","display: block;","overflow: hidden;","}",".blocklyCommentDeleteIcon {","cursor: pointer;","fill: #000;","display: none","}",".blocklySelected > .blocklyCommentDeleteIcon {", -"display: block","}",".blocklyDeleteIconShape {","fill: #000;","stroke: #000;","stroke-width: 1px;","}",".blocklyDeleteIconShape.blocklyDeleteIconHighlighted {","stroke: #fc3;","}",".blocklyHtmlInput {","border: none;","border-radius: 4px;","font-family: sans-serif;","height: 100%;","margin: 0;","outline: none;","padding: 0 1px;","width: 100%","}",".blocklyMainBackground {","stroke-width: 1;","stroke: #c6c6c6;","}",".blocklyMutatorBackground {","fill: #fff;","stroke: #ddd;","stroke-width: 1;","}", -".blocklyFlyoutBackground {","fill: #ddd;","fill-opacity: .8;","}",".blocklyTransparentBackground {","opacity: 0;","}",".blocklyMainWorkspaceScrollbar {","z-index: 20;","}",".blocklyFlyoutScrollbar {","z-index: 30;","}",".blocklyScrollbarHorizontal, .blocklyScrollbarVertical {","position: absolute;","outline: none;","}",".blocklyScrollbarBackground {","opacity: 0;","}",".blocklyScrollbarHandle {","fill: #ccc;","}",".blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyScrollbarHandle:hover {", -"fill: #bbb;","}",".blocklyZoom>image {","opacity: .4;","}",".blocklyZoom>image:hover {","opacity: .6;","}",".blocklyZoom>image:active {","opacity: .8;","}",".blocklyFlyout .blocklyScrollbarHandle {","fill: #bbb;","}",".blocklyFlyout .blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyFlyout .blocklyScrollbarHandle:hover {","fill: #aaa;","}",".blocklyInvalidInput {","background: #faa;","}",".blocklyAngleCircle {","stroke: #444;","stroke-width: 1;","fill: #ddd;","fill-opacity: .8;", -"}",".blocklyAngleMarks {","stroke: #444;","stroke-width: 1;","}",".blocklyAngleGauge {","fill: #f88;","fill-opacity: .8;","}",".blocklyAngleLine {","stroke: #f00;","stroke-width: 2;","stroke-linecap: round;","pointer-events: none;","}",".blocklyContextMenu {","border-radius: 4px;","}",".blocklyDropdownMenu {","padding: 0 !important;","}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(<<>>/sprites.png) no-repeat -48px -16px !important;", -"}",".blocklyToolboxDiv {","background-color: #ddd;","overflow-x: visible;","overflow-y: auto;","position: absolute;","user-select: none;","-moz-user-select: none;","-ms-user-select: none;","-webkit-user-select: none;","z-index: 70;","-webkit-tap-highlight-color: transparent;","}",".blocklyTreeRoot {","padding: 4px 0;","}",".blocklyTreeRoot:focus {","outline: none;","}",".blocklyTreeRow {","height: 22px;","line-height: 22px;","margin-bottom: 3px;","padding-right: 8px;","white-space: nowrap;","}", -".blocklyHorizontalTree {","float: left;","margin: 1px 5px 8px 0;","}",".blocklyHorizontalTreeRtl {","float: right;","margin: 1px 0 8px 5px;","}",'.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {',"margin-left: 8px;","}",".blocklyTreeRow:not(.blocklyTreeSelected):hover {","background-color: #e4e4e4;","}",".blocklyTreeSeparator {","border-bottom: solid #e5e5e5 1px;","height: 0;","margin: 5px 0;","}",".blocklyTreeSeparatorHorizontal {","border-right: solid #e5e5e5 1px;","width: 0;","padding: 5px 0;", -"margin: 0 5px;","}",".blocklyTreeIcon {","background-image: url(<<>>/sprites.png);","height: 16px;","vertical-align: middle;","width: 16px;","}",".blocklyTreeIconClosedLtr {","background-position: -32px -1px;","}",".blocklyTreeIconClosedRtl {","background-position: 0 -1px;","}",".blocklyTreeIconOpen {","background-position: -16px -1px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedLtr {","background-position: -32px -17px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedRtl {","background-position: 0 -17px;", -"}",".blocklyTreeSelected>.blocklyTreeIconOpen {","background-position: -16px -17px;","}",".blocklyTreeIconNone,",".blocklyTreeSelected>.blocklyTreeIconNone {","background-position: -48px -1px;","}",".blocklyTreeLabel {","cursor: default;","font-family: sans-serif;","font-size: 16px;","padding: 0 3px;","vertical-align: middle;","}",".blocklyToolboxDelete .blocklyTreeLabel {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyTreeSelected .blocklyTreeLabel {","color: #fff;","}",".blocklyColourTable {", -"border-collapse: collapse;","}",".blocklyColourTable>tr>td {","border: 1px solid #666;","padding: 0;","}",".blocklyColourTable>tr>td>div {","border: 1px solid #666;","height: 13px;","width: 15px;","}",".blocklyColourTable>tr>td>div:hover {","border: 1px solid #fff;","}",".blocklyColourSelected, .blocklyColourSelected:hover {","border: 1px solid #000 !important;","}",".blocklyWidgetDiv .goog-menu {","background: #fff;","border-color: #ccc #666 #666 #ccc;","border-style: solid;","border-width: 1px;", -"cursor: default;","font: normal 13px Arial, sans-serif;","margin: 0;","outline: none;","padding: 4px 0;","position: absolute;","overflow-y: auto;","overflow-x: hidden;","max-height: 100%;","z-index: 20000;","}",".blocklyWidgetDiv .goog-menuitem {","color: #000;","font: normal 13px Arial, sans-serif;","list-style: none;","margin: 0;","padding: 4px 7em 4px 28px;","white-space: nowrap;","}",".blocklyWidgetDiv .goog-menuitem.goog-menuitem-rtl {","padding-left: 7em;","padding-right: 28px;","}",".blocklyWidgetDiv .goog-menu-nocheckbox .goog-menuitem,", -".blocklyWidgetDiv .goog-menu-noicon .goog-menuitem {","padding-left: 12px;","}",".blocklyWidgetDiv .goog-menu-noaccel .goog-menuitem {","padding-right: 20px;","}",".blocklyWidgetDiv .goog-menuitem-content {","color: #000;","font: normal 13px Arial, sans-serif;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-accel,",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-content {","color: #ccc !important;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-icon {","opacity: 0.3;", -"filter: alpha(opacity=30);","}",".blocklyWidgetDiv .goog-menuitem-highlight,",".blocklyWidgetDiv .goog-menuitem-hover {","background-color: #d6e9f8;","border-color: #d6e9f8;","border-style: dotted;","border-width: 1px 0;","padding-bottom: 3px;","padding-top: 3px;","}",".blocklyWidgetDiv .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-menuitem-icon {","background-repeat: no-repeat;","height: 16px;","left: 6px;","position: absolute;","right: auto;","vertical-align: middle;","width: 16px;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-checkbox,", -".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-icon {","left: auto;","right: 6px;","}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;","}",".blocklyWidgetDiv .goog-menuitem-accel {","color: #999;","direction: ltr;","left: auto;","padding: 0 6px;","position: absolute;","right: 0;","text-align: right;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-accel {", -"left: 0;","right: auto;","text-align: left;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-hint {","text-decoration: underline;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-separator {","color: #999;","font-size: 12px;","padding-left: 4px;","}",".blocklyWidgetDiv .goog-menuseparator {","border-top: 1px solid #ccc;","margin: 4px 0;","padding: 0;","}",""];Blockly.WidgetDiv={};Blockly.WidgetDiv.DIV=null;Blockly.WidgetDiv.owner_=null;Blockly.WidgetDiv.dispose_=null;Blockly.WidgetDiv.createDom=function(){Blockly.WidgetDiv.DIV||(Blockly.WidgetDiv.DIV=document.createElement("div"),Blockly.WidgetDiv.DIV.className="blocklyWidgetDiv",document.body.appendChild(Blockly.WidgetDiv.DIV))}; +"fill-opacity: .8;","stroke-opacity: .8;","}",".blocklyDragging>.blocklyPathDark {","display: none;","}",".blocklyDisabled>.blocklyPath {","fill-opacity: .5;","stroke-opacity: .5;","}",".blocklyDisabled>.blocklyPathLight,",".blocklyDisabled>.blocklyPathDark {","display: none;","}",".blocklyInsertionMarker>.blocklyPath,",".blocklyInsertionMarker>.blocklyPathLight,",".blocklyInsertionMarker>.blocklyPathDark {","fill-opacity: .2;","stroke: none","}",".blocklyReplaceable .blocklyPath {","fill-opacity: 0.5;", +"}",".blocklyReplaceable .blocklyPathLight,",".blocklyReplaceable .blocklyPathDark {","display: none;","}",".blocklyText {","cursor: default;","fill: #fff;","font-family: sans-serif;","font-size: 11pt;","}",".blocklyNonEditableText>text {","pointer-events: none;","}",".blocklyNonEditableText>rect,",".blocklyEditableText>rect {","fill: #fff;","fill-opacity: .6;","}",".blocklyNonEditableText>text,",".blocklyEditableText>text {","fill: #000;","}",".blocklyEditableText:hover>rect {","stroke: #fff;","stroke-width: 2;", +"}",".blocklyBubbleText {","fill: #000;","}",".blocklyFlyout {","position: absolute;","z-index: 20;","}",".blocklyFlyoutButton {","fill: #888;","cursor: default;","}",".blocklyFlyoutButtonShadow {","fill: #666;","}",".blocklyFlyoutButton:hover {","fill: #aaa;","}",".blocklyFlyoutLabel {","cursor: default;","}",".blocklyFlyoutLabelBackground {","opacity: 0;","}",".blocklyFlyoutLabelText {","fill: #000;","}",".blocklySvg text, .blocklyBlockDragSurface text {","user-select: none;","-moz-user-select: none;", +"-ms-user-select: none;","-webkit-user-select: none;","cursor: inherit;","}",".blocklyHidden {","display: none;","}",".blocklyFieldDropdown:not(.blocklyHidden) {","display: block;","}",".blocklyIconGroup {","cursor: default;","}",".blocklyIconGroup:not(:hover),",".blocklyIconGroupReadonly {","opacity: .6;","}",".blocklyIconShape {","fill: #00f;","stroke: #fff;","stroke-width: 1px;","}",".blocklyIconSymbol {","fill: #fff;","}",".blocklyMinimalBody {","margin: 0;","padding: 0;","}",".blocklyCommentForeignObject {", +"position: relative;","z-index: 0;","}",".blocklyCommentRect {","fill: #E7DE8E;","stroke: #bcA903;","stroke-width: 1px","}",".blocklyCommentTarget {","fill: transparent;","stroke: #bcA903;","}",".blocklyCommentTargetFocused {","fill: none;","}",".blocklyCommentHandleTarget {","fill: none;","}",".blocklyCommentHandleTargetFocused {","fill: transparent;","}",".blocklyFocused>.blocklyCommentRect {","fill: #B9B272;","stroke: #B9B272;","}",".blocklySelected>.blocklyCommentTarget {","stroke: #fc3;","stroke-width: 3px;", +"}",".blocklyCommentTextarea {","background-color: #fef49c;","border: 0;","outline: 0;","margin: 0;","padding: 3px;","resize: none;","display: block;","overflow: hidden;","}",".blocklyCommentDeleteIcon {","cursor: pointer;","fill: #000;","display: none","}",".blocklySelected > .blocklyCommentDeleteIcon {","display: block","}",".blocklyDeleteIconShape {","fill: #000;","stroke: #000;","stroke-width: 1px;","}",".blocklyDeleteIconShape.blocklyDeleteIconHighlighted {","stroke: #fc3;","}",".blocklyHtmlInput {", +"border: none;","border-radius: 4px;","font-family: sans-serif;","height: 100%;","margin: 0;","outline: none;","padding: 0 1px;","width: 100%","}",".blocklyMainBackground {","stroke-width: 1;","stroke: #c6c6c6;","}",".blocklyMutatorBackground {","fill: #fff;","stroke: #ddd;","stroke-width: 1;","}",".blocklyFlyoutBackground {","fill: #ddd;","fill-opacity: .8;","}",".blocklyTransparentBackground {","opacity: 0;","}",".blocklyMainWorkspaceScrollbar {","z-index: 20;","}",".blocklyFlyoutScrollbar {","z-index: 30;", +"}",".blocklyScrollbarHorizontal, .blocklyScrollbarVertical {","position: absolute;","outline: none;","}",".blocklyScrollbarBackground {","opacity: 0;","}",".blocklyScrollbarHandle {","fill: #ccc;","}",".blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyScrollbarHandle:hover {","fill: #bbb;","}",".blocklyZoom>image, .blocklyZoom>svg>image {","opacity: .4;","}",".blocklyZoom>image:hover, .blocklyZoom>svg>image:hover {","opacity: .6;","}",".blocklyZoom>image:active, .blocklyZoom>svg>image:active {", +"opacity: .8;","}",".blocklyFlyout .blocklyScrollbarHandle {","fill: #bbb;","}",".blocklyFlyout .blocklyScrollbarBackground:hover+.blocklyScrollbarHandle,",".blocklyFlyout .blocklyScrollbarHandle:hover {","fill: #aaa;","}",".blocklyInvalidInput {","background: #faa;","}",".blocklyAngleCircle {","stroke: #444;","stroke-width: 1;","fill: #ddd;","fill-opacity: .8;","}",".blocklyAngleMarks {","stroke: #444;","stroke-width: 1;","}",".blocklyAngleGauge {","fill: #f88;","fill-opacity: .8;","}",".blocklyAngleLine {", +"stroke: #f00;","stroke-width: 2;","stroke-linecap: round;","pointer-events: none;","}",".blocklyContextMenu {","border-radius: 4px;","}",".blocklyDropdownMenu {","padding: 0 !important;","}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(<<>>/sprites.png) no-repeat -48px -16px !important;","}",".blocklyToolboxDiv {","background-color: #ddd;","overflow-x: visible;","overflow-y: auto;","position: absolute;", +"user-select: none;","-moz-user-select: none;","-ms-user-select: none;","-webkit-user-select: none;","z-index: 70;","-webkit-tap-highlight-color: transparent;","}",".blocklyTreeRoot {","padding: 4px 0;","}",".blocklyTreeRoot:focus {","outline: none;","}",".blocklyTreeRow {","height: 22px;","line-height: 22px;","margin-bottom: 3px;","padding-right: 8px;","white-space: nowrap;","}",".blocklyHorizontalTree {","float: left;","margin: 1px 5px 8px 0;","}",".blocklyHorizontalTreeRtl {","float: right;","margin: 1px 0 8px 5px;", +"}",'.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {',"margin-left: 8px;","}",".blocklyTreeRow:not(.blocklyTreeSelected):hover {","background-color: #e4e4e4;","}",".blocklyTreeSeparator {","border-bottom: solid #e5e5e5 1px;","height: 0;","margin: 5px 0;","}",".blocklyTreeSeparatorHorizontal {","border-right: solid #e5e5e5 1px;","width: 0;","padding: 5px 0;","margin: 0 5px;","}",".blocklyTreeIcon {","background-image: url(<<>>/sprites.png);","height: 16px;","vertical-align: middle;","width: 16px;", +"}",".blocklyTreeIconClosedLtr {","background-position: -32px -1px;","}",".blocklyTreeIconClosedRtl {","background-position: 0 -1px;","}",".blocklyTreeIconOpen {","background-position: -16px -1px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedLtr {","background-position: -32px -17px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedRtl {","background-position: 0 -17px;","}",".blocklyTreeSelected>.blocklyTreeIconOpen {","background-position: -16px -17px;","}",".blocklyTreeIconNone,",".blocklyTreeSelected>.blocklyTreeIconNone {", +"background-position: -48px -1px;","}",".blocklyTreeLabel {","cursor: default;","font-family: sans-serif;","font-size: 16px;","padding: 0 3px;","vertical-align: middle;","}",".blocklyToolboxDelete .blocklyTreeLabel {",'cursor: url("<<>>/handdelete.cur"), auto;',"}",".blocklyTreeSelected .blocklyTreeLabel {","color: #fff;","}",".blocklyColourTable {","border-collapse: collapse;","}",".blocklyColourTable>tr>td {","border: 1px solid #666;","padding: 0;","}",".blocklyColourTable>tr>td>div {","border: 1px solid #666;", +"height: 13px;","width: 15px;","}",".blocklyColourTable>tr>td>div:hover {","border: 1px solid #fff;","}",".blocklyColourSelected, .blocklyColourSelected:hover {","border: 1px solid #000 !important;","}",".blocklyWidgetDiv .goog-menu {","background: #fff;","border-color: #ccc #666 #666 #ccc;","border-style: solid;","border-width: 1px;","cursor: default;","font: normal 13px Arial, sans-serif;","margin: 0;","outline: none;","padding: 4px 0;","position: absolute;","overflow-y: auto;","overflow-x: hidden;", +"max-height: 100%;","z-index: 20000;","}",".blocklyWidgetDiv .goog-menuitem {","color: #000;","font: normal 13px Arial, sans-serif;","list-style: none;","margin: 0;","padding: 4px 7em 4px 28px;","white-space: nowrap;","}",".blocklyWidgetDiv .goog-menuitem.goog-menuitem-rtl {","padding-left: 7em;","padding-right: 28px;","}",".blocklyWidgetDiv .goog-menu-nocheckbox .goog-menuitem,",".blocklyWidgetDiv .goog-menu-noicon .goog-menuitem {","padding-left: 12px;","}",".blocklyWidgetDiv .goog-menu-noaccel .goog-menuitem {", +"padding-right: 20px;","}",".blocklyWidgetDiv .goog-menuitem-content {","color: #000;","font: normal 13px Arial, sans-serif;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-accel,",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-content {","color: #ccc !important;","}",".blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-icon {","opacity: 0.3;","filter: alpha(opacity=30);","}",".blocklyWidgetDiv .goog-menuitem-highlight,",".blocklyWidgetDiv .goog-menuitem-hover {","background-color: #d6e9f8;", +"border-color: #d6e9f8;","border-style: dotted;","border-width: 1px 0;","padding-bottom: 3px;","padding-top: 3px;","}",".blocklyWidgetDiv .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-menuitem-icon {","background-repeat: no-repeat;","height: 16px;","left: 6px;","position: absolute;","right: auto;","vertical-align: middle;","width: 16px;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-icon {","left: auto;","right: 6px;", +"}",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,",".blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {","background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;","}",".blocklyWidgetDiv .goog-menuitem-accel {","color: #999;","direction: ltr;","left: auto;","padding: 0 6px;","position: absolute;","right: 0;","text-align: right;","}",".blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-accel {","left: 0;","right: auto;","text-align: left;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-hint {", +"text-decoration: underline;","}",".blocklyWidgetDiv .goog-menuitem-mnemonic-separator {","color: #999;","font-size: 12px;","padding-left: 4px;","}",".blocklyWidgetDiv .goog-menuseparator {","border-top: 1px solid #ccc;","margin: 4px 0;","padding: 0;","}",""];Blockly.WidgetDiv={};Blockly.WidgetDiv.DIV=null;Blockly.WidgetDiv.owner_=null;Blockly.WidgetDiv.dispose_=null;Blockly.WidgetDiv.createDom=function(){Blockly.WidgetDiv.DIV||(Blockly.WidgetDiv.DIV=document.createElement("div"),Blockly.WidgetDiv.DIV.className="blocklyWidgetDiv",document.body.appendChild(Blockly.WidgetDiv.DIV))}; Blockly.WidgetDiv.show=function(a,b,c){Blockly.WidgetDiv.hide();Blockly.WidgetDiv.owner_=a;Blockly.WidgetDiv.dispose_=c;a=goog.style.getViewportPageOffset(document);Blockly.WidgetDiv.DIV.style.top=a.y+"px";Blockly.WidgetDiv.DIV.style.direction=b?"rtl":"ltr";Blockly.WidgetDiv.DIV.style.display="block"}; Blockly.WidgetDiv.hide=function(){Blockly.WidgetDiv.owner_&&(Blockly.WidgetDiv.owner_=null,Blockly.WidgetDiv.DIV.style.display="none",Blockly.WidgetDiv.DIV.style.left="",Blockly.WidgetDiv.DIV.style.top="",Blockly.WidgetDiv.dispose_&&Blockly.WidgetDiv.dispose_(),Blockly.WidgetDiv.dispose_=null,Blockly.WidgetDiv.DIV.innerHTML="")};Blockly.WidgetDiv.isVisible=function(){return!!Blockly.WidgetDiv.owner_};Blockly.WidgetDiv.hideIfOwner=function(a){Blockly.WidgetDiv.owner_==a&&Blockly.WidgetDiv.hide()}; Blockly.WidgetDiv.position=function(a,b,c,d,e){bc.width+d.x&&(a=c.width+d.x):aa.viewHeight+d||a.contentLeft<(b.RTL?a.viewLeft:c)||a.contentLeft+a.contentWidth>(b.RTL?a.viewWidth:a.viewWidth+c))for(var k=e.getTopBlocks(!1),l=0,n;n=k[l];l++){var m=n.getRelativeToSurfaceXY(),p=n.getHeightWidth(),q=d+25-p.height-m.y;0q&&n.moveBy(0,q);q=25+c-m.x-(b.RTL?0:p.width);0m&&n.moveBy(m,0)}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.Tooltip.createDom(); -return e}; -Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart(),a.scrollX= -a.flyout_.width_,b.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT&&(a.scrollX*=-1),a.translate(a.scrollX,0)));b.hasScrollbars&&(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize());b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; +Blockly.createMainWorkspace_=function(a,b,c,d){b.parentWorkspace=null;var e=new Blockly.WorkspaceSvg(b,c,d);e.scale=b.zoomOptions.startScale;a.appendChild(e.createDom("blocklyMainBackground"));!b.hasCategories&&b.languageTree&&(c=e.addFlyout_("svg"),Blockly.utils.insertAfter(c,a));e.translate(0,0);Blockly.mainWorkspace=e;b.readOnly||b.hasScrollbars||e.addChangeListener(function(a){if(!e.isDragging()){var c=e.getMetrics(),d=c.viewLeft+c.absoluteLeft,f=c.viewTop+c.absoluteTop;if(c.contentTopc.viewHeight+f||c.contentLeft<(b.RTL?c.viewLeft:d)||c.contentLeft+c.contentWidth>(b.RTL?c.viewWidth:c.viewWidth+d)){var l=e.getTopBlocks(!1),n=null;a&&(n=Blockly.Events.getGroup(),Blockly.Events.setGroup(a.group));for(var m=!1,p=0,q;q=l[p];p++){var r=q.getRelativeToSurfaceXY(),t=q.getHeightWidth(),u=f+25-t.height-r.y;0u&&(q.moveBy(0,u),m=!0);u=25+d-r.x-(b.RTL?0:t.width);0r&&(q.moveBy(r,0),m=!0)}a&&(!a.group&&m&&console.log("WARNING: Moved blocks in bounds but there was no event group. This may break undo."),Blockly.Events.setGroup(n))}}});Blockly.svgResize(e);Blockly.WidgetDiv.createDom();Blockly.Tooltip.createDom();return e}; +Blockly.init_=function(a){var b=a.options,c=a.getParentSvg();Blockly.bindEventWithChecks_(c.parentNode,"contextmenu",null,function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()});c=Blockly.bindEventWithChecks_(window,"resize",null,function(){Blockly.hideChaff(!0);Blockly.svgResize(a)});a.setResizeHandlerWrapper(c);Blockly.inject.bindDocumentEvents_();b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.flyout_.scrollToStart(), +a.scrollX=a.flyout_.width_,b.toolboxPosition==Blockly.TOOLBOX_AT_RIGHT&&(a.scrollX*=-1),a.translate(a.scrollX,0)));b.hasScrollbars&&(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize());b.hasSounds&&Blockly.inject.loadSounds_(b.pathToMedia,a)}; Blockly.inject.bindDocumentEvents_=function(){Blockly.documentEventsBound_||(Blockly.bindEventWithChecks_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),goog.userAgent.IPAD&&Blockly.bindEventWithChecks_(window,"orientationchange",document,function(){Blockly.svgResize(Blockly.getMainWorkspace())}));Blockly.documentEventsBound_=!0}; Blockly.inject.loadSounds_=function(a,b){var c=b.getAudioManager();c.load([a+"click.mp3",a+"click.wav",a+"click.ogg"],"click");c.load([a+"disconnect.wav",a+"disconnect.mp3",a+"disconnect.ogg"],"disconnect");c.load([a+"delete.mp3",a+"delete.ogg",a+"delete.wav"],"delete");var d=[],e=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());c.preload()};d.push(Blockly.bindEventWithChecks_(document,"mousemove",null,e,!0));d.push(Blockly.bindEventWithChecks_(document,"touchstart",null,e,!0))}; -Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.cache3dSupported_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; +Blockly.updateToolbox=function(a){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)};var CLOSURE_DEFINES={"goog.DEBUG":!1};Blockly.mainWorkspace=null;Blockly.selected=null;Blockly.draggingConnections_=[];Blockly.clipboardXml_=null;Blockly.clipboardSource_=null;Blockly.clipboardTypeCounts_=null;Blockly.cache3dSupported_=null;Blockly.hueToRgb=function(a){return goog.color.hsvToHex(a,Blockly.HSV_SATURATION,255*Blockly.HSV_VALUE)};Blockly.svgSize=function(a){return{width:a.cachedWidth_,height:a.cachedHeight_}};Blockly.resizeSvgContents=function(a){a.resizeContents()}; Blockly.svgResize=function(a){for(;a.options.parentWorkspace;)a=a.options.parentWorkspace;var b=a.getParentSvg(),c=b.parentNode;if(c){var d=c.offsetWidth;c=c.offsetHeight;b.cachedWidth_!=d&&(b.setAttribute("width",d+"px"),b.cachedWidth_=d);b.cachedHeight_!=c&&(b.setAttribute("height",c+"px"),b.cachedHeight_=c);a.resize()}}; Blockly.onKeyDown_=function(a){var b=Blockly.mainWorkspace;if(!(b.options.readOnly||Blockly.utils.isTargetInput(a)||b.rendered&&!b.isVisible())){var c=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode){a.preventDefault();if(b.isDragging())return;Blockly.selected&&Blockly.selected.isDeletable()&&(c=!0)}else if(a.altKey||a.ctrlKey||a.metaKey){if(b.isDragging())return;Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&(67==a.keyCode?(Blockly.hideChaff(), -Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(Blockly.Events.setGroup(!0),b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1)):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&&(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}}; -Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace};Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c}; -Blockly.onContextMenu_=function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()};Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();a||(a=Blockly.getMainWorkspace(),a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.flyout_.autoClose&&a.toolbox_.clearSelection())};Blockly.addChangeListener=function(a){console.warn("Deprecated call to Blockly.addChangeListener, use workspace.addChangeListener instead.");return Blockly.getMainWorkspace().addChangeListener(a)}; -Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){window.alert(a);b&&b()};Blockly.confirm=function(a,b){b(window.confirm(a))};Blockly.prompt=function(a,b,c){c(window.prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; +Blockly.copy_(Blockly.selected)):88!=a.keyCode||Blockly.selected.workspace.isFlyout||(Blockly.copy_(Blockly.selected),c=!0));86==a.keyCode?Blockly.clipboardXml_&&(b=Blockly.clipboardSource_,b.isFlyout&&(b=b.targetWorkspace),Blockly.clipboardTypeCounts_&&b.isCapacityAvailable(Blockly.clipboardTypeCounts_)&&(Blockly.Events.setGroup(!0),b.paste(Blockly.clipboardXml_),Blockly.Events.setGroup(!1))):90==a.keyCode&&(Blockly.hideChaff(),b.undo(a.shiftKey))}c&&!Blockly.selected.workspace.isFlyout&&(Blockly.Events.setGroup(!0), +Blockly.hideChaff(),Blockly.selected.dispose(!0,!0),Blockly.Events.setGroup(!1))}};Blockly.copy_=function(a){if(a.isComment)var b=a.toXmlWithXY();else{b=Blockly.Xml.blockToDom(a);Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y)}Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace;Blockly.clipboardTypeCounts_=a.isComment?null:Blockly.utils.getBlockTypeCounts(a,!0)}; +Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c};Blockly.onContextMenu_=function(a){Blockly.utils.isTargetInput(a)||a.preventDefault()};Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();a||(a=Blockly.getMainWorkspace(),a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.flyout_.autoClose&&a.toolbox_.clearSelection())}; +Blockly.addChangeListener=function(a){console.warn("Deprecated call to Blockly.addChangeListener, use workspace.addChangeListener instead.");return Blockly.getMainWorkspace().addChangeListener(a)};Blockly.getMainWorkspace=function(){return Blockly.mainWorkspace};Blockly.alert=function(a,b){window.alert(a);b&&b()};Blockly.confirm=function(a,b){b(window.confirm(a))};Blockly.prompt=function(a,b,c){c(window.prompt(a,b))};Blockly.jsonInitFactory_=function(a){return function(){this.jsonInit(a)}}; Blockly.defineBlocksWithJsonArray=function(a){for(var b=0;b} valueConnections List of value + * connectsions for if input. + * @param {!Array} statementConnections List of + * statement connections for do input. + * @param {?Blockly.RenderedConnection} elseStatementConnection Statement + * connection for else input. + */ + reconnectChildBlocks_: function(valueConnections, statementConnections, + elseStatementConnection) { + for (var i = 1; i <= this.elseifCount_; i++) { + Blockly.Mutator.reconnect(valueConnections[i], this, 'IF' + i); + Blockly.Mutator.reconnect(statementConnections[i], this, 'DO' + i); + } + Blockly.Mutator.reconnect(elseStatementConnection, this, 'ELSE'); } }; diff --git a/blocks/procedures.js b/blocks/procedures.js index 0511ed232..7f6e0965f 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -159,7 +159,11 @@ Blockly.Blocks['procedures_defnoreturn'] = { this.arguments_.push(varName); var variable = Blockly.Variables.getOrCreateVariablePackage( this.workspace, varId, varName, ''); - this.argumentVarModels_.push(variable); + if (variable != null) { + this.argumentVarModels_.push(variable); + } else { + console.log('Failed to create a variable with name ' + varName + ', ignoring.'); + } } } this.updateParams_(); @@ -216,7 +220,12 @@ Blockly.Blocks['procedures_defnoreturn'] = { var varName = paramBlock.getFieldValue('NAME'); this.arguments_.push(varName); var variable = this.workspace.getVariable(varName, ''); - this.argumentVarModels_.push(variable); + if (variable != null) { + this.argumentVarModels_.push(variable); + } else { + console.log('Failed to get variable named ' + varName + ', ignoring.'); + } + this.paramIds_.push(paramBlock.id); paramBlock = paramBlock.nextConnection && paramBlock.nextConnection.targetBlock(); diff --git a/blocks/variables.js b/blocks/variables.js index 7d0c8d36f..0d8e0d950 100644 --- a/blocks/variables.js +++ b/blocks/variables.js @@ -100,31 +100,76 @@ Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = { * @this Blockly.Block */ customContextMenu: function(options) { - if (this.isInFlyout){ - return; - } - // Getter blocks have the option to create a setter block, and vice versa. - if (this.type == 'variables_get') { - var opposite_type = 'variables_set'; - var contextMenuMsg = Blockly.Msg['VARIABLES_GET_CREATE_SET']; - } else { - var opposite_type = 'variables_get'; - var contextMenuMsg = Blockly.Msg['VARIABLES_SET_CREATE_GET']; - } + if (!this.isInFlyout){ + // Getter blocks have the option to create a setter block, and vice versa. + if (this.type == 'variables_get') { + var opposite_type = 'variables_set'; + var contextMenuMsg = Blockly.Msg['VARIABLES_GET_CREATE_SET']; + } else { + var opposite_type = 'variables_get'; + var contextMenuMsg = Blockly.Msg['VARIABLES_SET_CREATE_GET']; + } - var option = {enabled: this.workspace.remainingCapacity() > 0}; - var name = this.getField('VAR').getText(); - option.text = contextMenuMsg.replace('%1', name); - var xmlField = document.createElement('field'); - xmlField.setAttribute('name', 'VAR'); - xmlField.appendChild(document.createTextNode(name)); - var xmlBlock = document.createElement('block'); - xmlBlock.setAttribute('type', opposite_type); - xmlBlock.appendChild(xmlField); - option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); - options.push(option); + var option = {enabled: this.workspace.remainingCapacity() > 0}; + var name = this.getField('VAR').getText(); + option.text = contextMenuMsg.replace('%1', name); + var xmlField = document.createElement('field'); + xmlField.setAttribute('name', 'VAR'); + xmlField.appendChild(document.createTextNode(name)); + var xmlBlock = document.createElement('block'); + xmlBlock.setAttribute('type', opposite_type); + xmlBlock.appendChild(xmlField); + option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); + options.push(option); + // Getter blocks have the option to rename or delete that variable. + } else { + if (this.type == 'variables_get' || this.type == 'variables_get_reporter'){ + var renameOption = { + text: Blockly.Msg.RENAME_VARIABLE, + enabled: true, + callback: Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY(this) + }; + var name = this.getField('VAR').getText(); + var deleteOption = { + text: Blockly.Msg.DELETE_VARIABLE.replace('%1', name), + enabled: true, + callback: Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY(this) + }; + options.unshift(renameOption); + options.unshift(deleteOption); + } + } } }; +/** + * Callback for rename variable dropdown menu option associated with a + * variable getter block. + * @param {!Blockly.Block} block The block with the variable to rename. + * @return {!function()} A function that renames the variable. + */ +Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY = function(block) { + return function() { + var workspace = block.workspace; + var variable = block.getField('VAR').getVariable(); + Blockly.Variables.renameVariable(workspace, variable); + }; +}; + +/** + * Callback for delete variable dropdown menu option associated with a + * variable getter block. + * @param {!Blockly.Block} block The block with the variable to delete. + * @return {!function()} A function that deletes the variable. + */ +Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY = function(block) { + return function() { + var workspace = block.workspace; + var variable = block.getField('VAR').getVariable(); + workspace.deleteVariableById(variable.getId()); + workspace.refreshToolboxSelection(); + }; +}; + Blockly.Extensions.registerMixin('contextMenu_variableSetterGetter', Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN); diff --git a/blocks/variables_dynamic.js b/blocks/variables_dynamic.js index 5aaa0aab0..fe30b8f22 100644 --- a/blocks/variables_dynamic.js +++ b/blocks/variables_dynamic.js @@ -97,34 +97,50 @@ Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MI */ customContextMenu: function(options) { // Getter blocks have the option to create a setter block, and vice versa. - if (this.isInFlyout) { - return; - } - var opposite_type; - var contextMenuMsg; - var id = this.getFieldValue('VAR'); - var variableModel = this.workspace.getVariableById(id); - var varType = variableModel.type; - if (this.type == 'variables_get_dynamic') { - opposite_type = 'variables_set_dynamic'; - contextMenuMsg = Blockly.Msg['VARIABLES_GET_CREATE_SET']; - } else { - opposite_type = 'variables_get_dynamic'; - contextMenuMsg = Blockly.Msg['VARIABLES_SET_CREATE_GET']; - } + if (!this.isInFlyout) { + var opposite_type; + var contextMenuMsg; + var id = this.getFieldValue('VAR'); + var variableModel = this.workspace.getVariableById(id); + var varType = variableModel.type; + if (this.type == 'variables_get_dynamic') { + opposite_type = 'variables_set_dynamic'; + contextMenuMsg = Blockly.Msg['VARIABLES_GET_CREATE_SET']; + } else { + opposite_type = 'variables_get_dynamic'; + contextMenuMsg = Blockly.Msg['VARIABLES_SET_CREATE_GET']; + } - var option = {enabled: this.workspace.remainingCapacity() > 0}; - var name = this.getField('VAR').getText(); - option.text = contextMenuMsg.replace('%1', name); - var xmlField = document.createElement('field'); - xmlField.setAttribute('name', 'VAR'); - xmlField.setAttribute('variabletype', varType); - xmlField.appendChild(document.createTextNode(name)); - var xmlBlock = document.createElement('block'); - xmlBlock.setAttribute('type', opposite_type); - xmlBlock.appendChild(xmlField); - option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); - options.push(option); + var option = {enabled: this.workspace.remainingCapacity() > 0}; + var name = this.getField('VAR').getText(); + option.text = contextMenuMsg.replace('%1', name); + var xmlField = document.createElement('field'); + xmlField.setAttribute('name', 'VAR'); + xmlField.setAttribute('variabletype', varType); + xmlField.appendChild(document.createTextNode(name)); + var xmlBlock = document.createElement('block'); + xmlBlock.setAttribute('type', opposite_type); + xmlBlock.appendChild(xmlField); + option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); + options.push(option); + } else { + if (this.type == 'variables_get_dynamic' || + this.type == 'variables_get_reporter_dynamic') { + var renameOption = { + text: Blockly.Msg.RENAME_VARIABLE, + enabled: true, + callback: Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY(this) + }; + var name = this.getField('VAR').getText(); + var deleteOption = { + text: Blockly.Msg.DELETE_VARIABLE.replace('%1', name), + enabled: true, + callback: Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY(this) + }; + options.unshift(renameOption); + options.unshift(deleteOption); + } + } }, onchange: function() { var id = this.getFieldValue('VAR'); @@ -137,5 +153,34 @@ Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MI } }; +/** + * Callback for rename variable dropdown menu option associated with a + * variable getter block. + * @param {!Blockly.Block} block The block with the variable to rename. + * @return {!function()} A function that renames the variable. + */ +Blockly.Constants.VariablesDynamic.RENAME_OPTION_CALLBACK_FACTORY = function(block) { + return function() { + var workspace = block.workspace; + var variable = block.getField('VAR').getVariable(); + Blockly.Variables.renameVariable(workspace, variable); + }; +}; + +/** + * Callback for delete variable dropdown menu option associated with a + * variable getter block. + * @param {!Blockly.Block} block The block with the variable to delete. + * @return {!function()} A function that deletes the variable. + */ +Blockly.Constants.VariablesDynamic.DELETE_OPTION_CALLBACK_FACTORY = function(block) { + return function() { + var workspace = block.workspace; + var variable = block.getField('VAR').getVariable(); + workspace.deleteVariableById(variable.getId()); + workspace.refreshToolboxSelection(); + }; +}; + Blockly.Extensions.registerMixin('contextMenu_variableDynamicSetterGetter', Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN); diff --git a/blocks_compressed.js b/blocks_compressed.js index 3d8c32e15..b05fd9508 100644 --- a/blocks_compressed.js +++ b/blocks_compressed.js @@ -33,7 +33,7 @@ this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number") Blockly.Blocks.lists_getSublist={init:function(){this.WHERE_OPTIONS_1=[[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST,"FIRST"]];this.WHERE_OPTIONS_2=[[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);this.setColour(Blockly.Msg.LISTS_HUE); this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);this.appendDummyInput("AT1");this.appendDummyInput("AT2");Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);this.setInputsInline(!0);this.setOutput(!0,"Array");this.updateAt_(1,!0);this.updateAt_(2,!0);this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation"),b=this.getInput("AT1").type== Blockly.INPUT_VALUE;a.setAttribute("at1",b);b=this.getInput("AT2").type==Blockly.INPUT_VALUE;a.setAttribute("at2",b);return a},domToMutation:function(a){var b="true"==a.getAttribute("at1");a="true"==a.getAttribute("at2");this.updateAt_(1,b);this.updateAt_(2,a)},updateAt_:function(a,b){this.removeInput("AT"+a);this.removeInput("ORDINAL"+a,!0);b?(this.appendValueInput("AT"+a).setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL"+a).appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)): -this.appendDummyInput("AT"+a);var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var e="FROM_START"==c||"FROM_END"==c;if(e!=b){var d=this.sourceBlock_;d.updateAt_(a,e);d.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&this.moveInputBefore("ORDINAL1","AT2"));Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.moveInputBefore("TAIL",null)}}; +this.appendDummyInput("AT"+a);var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var d="FROM_START"==c||"FROM_END"==c;if(d!=b){var f=this.sourceBlock_;f.updateAt_(a,d);f.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&this.moveInputBefore("ORDINAL1","AT2"));Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.moveInputBefore("TAIL",null)}}; Blockly.Blocks.lists_sort={init:function(){this.jsonInit({message0:Blockly.Msg.LISTS_SORT_TITLE,args0:[{type:"field_dropdown",name:"TYPE",options:[[Blockly.Msg.LISTS_SORT_TYPE_NUMERIC,"NUMERIC"],[Blockly.Msg.LISTS_SORT_TYPE_TEXT,"TEXT"],[Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE,"IGNORE_CASE"]]},{type:"field_dropdown",name:"DIRECTION",options:[[Blockly.Msg.LISTS_SORT_ORDER_ASCENDING,"1"],[Blockly.Msg.LISTS_SORT_ORDER_DESCENDING,"-1"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Array",colour:Blockly.Msg.LISTS_HUE, tooltip:Blockly.Msg.LISTS_SORT_TOOLTIP,helpUrl:Blockly.Msg.LISTS_SORT_HELPURL})}}; Blockly.Blocks.lists_split={init:function(){var a=this,b=new Blockly.FieldDropdown([[Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT,"SPLIT"],[Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST,"JOIN"]],function(b){a.updateType_(b)});this.setHelpUrl(Blockly.Msg.LISTS_SPLIT_HELPURL);this.setColour(Blockly.Msg.LISTS_HUE);this.appendValueInput("INPUT").setCheck("String").appendField(b,"MODE");this.appendValueInput("DELIM").setCheck("String").appendField(Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER);this.setInputsInline(!0);this.setOutput(!0, @@ -48,11 +48,12 @@ message2:"%{BKY_LOGIC_TERNARY_IF_FALSE} %1",args2:[{type:"input_value",name:"ELS Blockly.defineBlocksWithJsonArray([{type:"controls_if_if",message0:"%{BKY_CONTROLS_IF_IF_TITLE_IF}",nextStatement:null,enableContextMenu:!1,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_CONTROLS_IF_IF_TOOLTIP}"},{type:"controls_if_elseif",message0:"%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",previousStatement:null,nextStatement:null,enableContextMenu:!1,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"},{type:"controls_if_else",message0:"%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",previousStatement:null, enableContextMenu:!1,colour:"%{BKY_LOGIC_HUE}",tooltip:"%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"}]);Blockly.Constants.Logic.TOOLTIPS_BY_OP={EQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_EQ}",NEQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_NEQ}",LT:"%{BKY_LOGIC_COMPARE_TOOLTIP_LT}",LTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_LTE}",GT:"%{BKY_LOGIC_COMPARE_TOOLTIP_GT}",GTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_GTE}",AND:"%{BKY_LOGIC_OPERATION_TOOLTIP_AND}",OR:"%{BKY_LOGIC_OPERATION_TOOLTIP_OR}"}; Blockly.Extensions.register("logic_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Logic.TOOLTIPS_BY_OP)); -Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN={elseifCount_:0,elseCount_:0,mutationToDom:function(){if(!this.elseifCount_&&!this.elseCount_)return null;var a=document.createElement("mutation");this.elseifCount_&&a.setAttribute("elseif",this.elseifCount_);this.elseCount_&&a.setAttribute("else",1);return a},domToMutation:function(a){this.elseifCount_=parseInt(a.getAttribute("elseif"),10)||0;this.elseCount_=parseInt(a.getAttribute("else"),10)||0;this.updateShape_()},decompose:function(a){var b=a.newBlock("controls_if_if"); -b.initSvg();for(var c=b.nextConnection,d=1;d<=this.elseifCount_;d++){var e=a.newBlock("controls_if_elseif");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}this.elseCount_&&(a=a.newBlock("controls_if_else"),a.initSvg(),c.connect(a.previousConnection));return b},compose:function(a){var b=a.nextConnection.targetBlock();this.elseCount_=this.elseifCount_=0;a=[null];for(var c=[null],d=null;b;){switch(b.type){case "controls_if_elseif":this.elseifCount_++;a.push(b.valueConnection_);c.push(b.statementConnection_); -break;case "controls_if_else":this.elseCount_++;d=b.statementConnection_;break;default:throw TypeError("Unknown block type: "+b.type);}b=b.nextConnection&&b.nextConnection.targetBlock()}this.updateShape_();for(b=1;b<=this.elseifCount_;b++)Blockly.Mutator.reconnect(a[b],this,"IF"+b),Blockly.Mutator.reconnect(c[b],this,"DO"+b);Blockly.Mutator.reconnect(d,this,"ELSE")},saveConnections:function(a){a=a.nextConnection.targetBlock();for(var b=1;a;){switch(a.type){case "controls_if_elseif":var c=this.getInput("IF"+ -b),d=this.getInput("DO"+b);a.valueConnection_=c&&c.connection.targetConnection;a.statementConnection_=d&&d.connection.targetConnection;b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw TypeError("Unknown block type: "+a.type);}a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.getInput("ELSE")&&this.removeInput("ELSE");for(var a=1;this.getInput("IF"+a);)this.removeInput("IF"+a),this.removeInput("DO"+ -a),a++;for(a=1;a<=this.elseifCount_;a++)this.appendValueInput("IF"+a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);this.elseCount_&&this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)}};Blockly.Extensions.registerMutator("controls_if_mutator",Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN,null,["controls_if_elseif","controls_if_else"]); +Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN={elseifCount_:0,elseCount_:0,mutationToDom:function(){if(!this.elseifCount_&&!this.elseCount_)return null;var a=document.createElement("mutation");this.elseifCount_&&a.setAttribute("elseif",this.elseifCount_);this.elseCount_&&a.setAttribute("else",1);return a},domToMutation:function(a){this.elseifCount_=parseInt(a.getAttribute("elseif"),10)||0;this.elseCount_=parseInt(a.getAttribute("else"),10)||0;this.rebuildShape_()},decompose:function(a){var b= +a.newBlock("controls_if_if");b.initSvg();for(var c=b.nextConnection,d=1;d<=this.elseifCount_;d++){var e=a.newBlock("controls_if_elseif");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}this.elseCount_&&(a=a.newBlock("controls_if_else"),a.initSvg(),c.connect(a.previousConnection));return b},compose:function(a){a=a.nextConnection.targetBlock();this.elseCount_=this.elseifCount_=0;for(var b=[null],c=[null],d=null;a;){switch(a.type){case "controls_if_elseif":this.elseifCount_++;b.push(a.valueConnection_); +c.push(a.statementConnection_);break;case "controls_if_else":this.elseCount_++;d=a.statementConnection_;break;default:throw TypeError("Unknown block type: "+a.type);}a=a.nextConnection&&a.nextConnection.targetBlock()}this.updateShape_();this.reconnectChildBlocks_(b,c,d)},saveConnections:function(a){a=a.nextConnection.targetBlock();for(var b=1;a;){switch(a.type){case "controls_if_elseif":var c=this.getInput("IF"+b),d=this.getInput("DO"+b);a.valueConnection_=c&&c.connection.targetConnection;a.statementConnection_= +d&&d.connection.targetConnection;b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw TypeError("Unknown block type: "+a.type);}a=a.nextConnection&&a.nextConnection.targetBlock()}},rebuildShape_:function(){var a=[null],b=[null],c=null;this.getInput("ELSE")&&(c=this.getInput("ELSE").connection.targetConnection);for(var d=1;this.getInput("IF"+d);){var e=this.getInput("IF"+d),f=this.getInput("DO"+d);a.push(e.connection.targetConnection); +b.push(f.connection.targetConnection);d++}this.updateShape_();this.reconnectChildBlocks_(a,b,c)},updateShape_:function(){this.getInput("ELSE")&&this.removeInput("ELSE");for(var a=1;this.getInput("IF"+a);)this.removeInput("IF"+a),this.removeInput("DO"+a),a++;for(a=1;a<=this.elseifCount_;a++)this.appendValueInput("IF"+a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);this.elseCount_&&this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)}, +reconnectChildBlocks_:function(a,b,c){for(var d=1;d<=this.elseifCount_;d++)Blockly.Mutator.reconnect(a[d],this,"IF"+d),Blockly.Mutator.reconnect(b[d],this,"DO"+d);Blockly.Mutator.reconnect(c,this,"ELSE")}};Blockly.Extensions.registerMutator("controls_if_mutator",Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN,null,["controls_if_elseif","controls_if_else"]); Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION=function(){this.setTooltip(function(){if(this.elseifCount_||this.elseCount_){if(!this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;if(this.elseifCount_&&!this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;if(this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_4}else return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;return""}.bind(this))};Blockly.Extensions.register("controls_if_tooltip",Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION); Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN={onchange:function(a){this.prevBlocks_||(this.prevBlocks_=[null,null]);var b=this.getInputTargetBlock("A"),c=this.getInputTargetBlock("B");b&&c&&!b.outputConnection.checkType_(c.outputConnection)&&(Blockly.Events.setGroup(a.group),a=this.prevBlocks_[0],a!==b&&(b.unplug(),a&&!a.isShadow()&&this.getInput("A").connection.connect(a.outputConnection)),b=this.prevBlocks_[1],b!==c&&(c.unplug(),b&&!b.isShadow()&&this.getInput("B").connection.connect(b.outputConnection)), this.bumpNeighbours_(),Blockly.Events.setGroup(!1));this.prevBlocks_[0]=this.getInputTargetBlock("A");this.prevBlocks_[1]=this.getInputTargetBlock("B")}};Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION=function(){this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN)};Blockly.Extensions.register("logic_compare",Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION); @@ -91,13 +92,14 @@ Blockly.Blocks.procedures_defnoreturn={init:function(){var a=new Blockly.FieldTe this.setColour(Blockly.Msg.PROCEDURES_HUE);this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.arguments_=[];this.argumentVarModels_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:function(a){this.hasStatements_!==a&&(a?(this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO),this.getInput("RETURN")&&this.moveInputBefore("STACK","RETURN")):this.removeInput("STACK",!0), this.hasStatements_=a)},updateParams_:function(){for(var a=!1,b={},c=0;c.js for every language defined in msg/js/.json. import sys -if sys.version_info[0] != 2: - raise Exception("Blockly build only compatible with Python 2.x.\n" - "You are using: " + sys.version) for arg in sys.argv[1:len(sys.argv)]: if (arg != 'core' and @@ -65,8 +62,15 @@ for arg in sys.argv[1:len(sys.argv)]: raise Exception("Invalid argument: \"" + arg + "\". Usage: build.py " "<0 or more of accessible, core, generators, langfiles>") -import errno, glob, httplib, json, os, re, subprocess, threading, urllib +import errno, glob, json, os, re, subprocess, threading, codecs +if sys.version_info[0] == 2: + import httplib + from urllib import urlencode +else: + import http.client as httplib + from urllib.parse import urlencode + from importlib import reload def import_path(fullpath): """Import a file with full path specification. @@ -234,8 +238,8 @@ class Gen_compressed(threading.Thread): # Filter out the Closure files (the compiler will add them). if filename.startswith(os.pardir + os.sep): # '../' continue - f = open(filename) - params.append(("js_code", "".join(f.readlines()))) + f = codecs.open(filename, encoding="utf-8") + params.append(("js_code", "".join(f.readlines()).encode("utf-8"))) f.close() self.do_compile(params, target_filename, filenames, "") @@ -263,8 +267,8 @@ class Gen_compressed(threading.Thread): # Filter out the Closure files (the compiler will add them). if filename.startswith(os.pardir + os.sep): # '../' continue - f = open(filename) - params.append(("js_code", "".join(f.readlines()))) + f = codecs.open(filename, encoding="utf-8") + params.append(("js_code", "".join(f.readlines()).encode("utf-8"))) f.close() self.do_compile(params, target_filename, filenames, "") @@ -288,8 +292,8 @@ class Gen_compressed(threading.Thread): filenames = glob.glob(os.path.join("blocks", "*.js")) filenames.sort() # Deterministic build. for filename in filenames: - f = open(filename) - params.append(("js_code", "".join(f.readlines()))) + f = codecs.open(filename, encoding="utf-8") + params.append(("js_code", "".join(f.readlines()).encode("utf-8"))) f.close() # Remove Blockly.Blocks to be compatible with Blockly. @@ -317,8 +321,8 @@ class Gen_compressed(threading.Thread): filenames.sort() # Deterministic build. filenames.insert(0, os.path.join("generators", language + ".js")) for filename in filenames: - f = open(filename) - params.append(("js_code", "".join(f.readlines()))) + f = codecs.open(filename, encoding="utf-8") + params.append(("js_code", "".join(f.readlines()).encode("utf-8"))) f.close() filenames.insert(0, "[goog.provide]") @@ -330,9 +334,11 @@ class Gen_compressed(threading.Thread): # Send the request to Google. headers = {"Content-type": "application/x-www-form-urlencoded"} conn = httplib.HTTPSConnection("closure-compiler.appspot.com") - conn.request("POST", "/compile", urllib.urlencode(params), headers) + conn.request("POST", "/compile", urlencode(params), headers) response = conn.getresponse() - json_str = response.read() + + # Decode is necessary for Python 3.4 compatibility + json_str = response.read().decode("utf-8") conn.close() # Parse the JSON response. @@ -349,12 +355,12 @@ class Gen_compressed(threading.Thread): n = int(name[6:]) - 1 return filenames[n] - if json_data.has_key("serverErrors"): + if "serverErrors" in json_data: errors = json_data["serverErrors"] for error in errors: print("SERVER ERROR: %s" % target_filename) print(error["error"]) - elif json_data.has_key("errors"): + elif "errors" in json_data: errors = json_data["errors"] for error in errors: print("FATAL ERROR") @@ -366,7 +372,7 @@ class Gen_compressed(threading.Thread): print((" " * error["charno"]) + "^") sys.exit(1) else: - if json_data.has_key("warnings"): + if "warnings" in json_data: warnings = json_data["warnings"] for warning in warnings: print("WARNING") @@ -378,7 +384,7 @@ class Gen_compressed(threading.Thread): print((" " * warning["charno"]) + "^") print() - if not json_data.has_key("compiledCode"): + if not "compiledCode" in json_data: print("FATAL ERROR: Compiler did not return compiledCode.") sys.exit(1) @@ -452,7 +458,7 @@ class Gen_langfiles(threading.Thread): # If a destination file was missing, rebuild. return True else: - print("Error checking file creation times: " + e) + print("Error checking file creation times: " + str(e)) def run(self): # The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js. @@ -530,10 +536,10 @@ developers.google.com/blockly/guides/modify/web/closure""") core_search_paths = calcdeps.ExpandDirectories( ["core", os.path.join(os.path.pardir, "closure-library")]) - core_search_paths.sort() # Deterministic build. + core_search_paths = sorted(core_search_paths) # Deterministic build. full_search_paths = calcdeps.ExpandDirectories( ["accessible", "core", os.path.join(os.path.pardir, "closure-library")]) - full_search_paths.sort() # Deterministic build. + full_search_paths = sorted(full_search_paths) # Deterministic build. if (len(sys.argv) == 1): args = ['core', 'accessible', 'generators', 'defaultlangfiles'] diff --git a/core/block.js b/core/block.js index eef55c47a..c5cea853b 100644 --- a/core/block.js +++ b/core/block.js @@ -164,6 +164,7 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { } workspace.addTopBlock(this); + workspace.addTypedBlock(this); // Call an initialization function, if it exists. if (typeof this.init == 'function') { @@ -255,6 +256,7 @@ Blockly.Block.prototype.dispose = function(healStack) { // Remove this block from the workspace's list of top-most blocks. if (this.workspace) { this.workspace.removeTopBlock(this); + this.workspace.removeTypedBlock(this); // Remove from block database. delete this.workspace.blockDB_[this.id]; this.workspace = null; @@ -668,6 +670,21 @@ Blockly.Block.prototype.setMovable = function(movable) { this.movable_ = movable; }; +/** + * Get whether is block is duplicatable or not. If duplicating this block and + * descendants will put this block over the workspace's capacity this block is + * not duplicatable. If duplicating this block and descendants will put any + * type over their maxInstances this block is not duplicatable. + * @return {boolean} True if duplicatable. + */ +Blockly.Block.prototype.isDuplicatable = function() { + if (!this.workspace.hasBlockLimits()) { + return true; + } + return this.workspace.isCapacityAvailable( + Blockly.utils.getBlockTypeCounts(this, true)); +}; + /** * Get whether this block is a shadow block or not. * @return {boolean} True if a shadow. diff --git a/core/block_dragger.js b/core/block_dragger.js index 7de40fbf5..ffd8f8754 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -162,6 +162,9 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY, this.draggingBlock_.bringToFront(); } + // During a drag there may be a lot of rerenders, but not field changes. + // Turn the cache on so we don't do spurious remeasures during the drag. + Blockly.Field.startCache(); this.workspace_.setResizesEnabled(false); Blockly.BlockAnimations.disconnectUiStop(); @@ -222,6 +225,8 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) { this.dragBlock(e, currentDragDeltaXY); this.dragIconData_ = []; + Blockly.Field.stopCache(); + Blockly.BlockAnimations.disconnectUiStop(); var delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY); diff --git a/core/block_render_svg.js b/core/block_render_svg.js index f9a36d66f..a1d4af37e 100644 --- a/core/block_render_svg.js +++ b/core/block_render_svg.js @@ -385,6 +385,11 @@ Blockly.BlockSvg.prototype.renderFields_ = function(fieldList, Blockly.BlockSvg.SEP_SPACE_X; } } + // Fields are invisible on insertion marker. They still have to be rendered + // so that the block can be sized correctly. + if (this.isInsertionMarker()) { + root.setAttribute('display', 'none'); + } } return this.RTL ? -cursorX : cursorX; }; @@ -1144,3 +1149,43 @@ Blockly.BlockSvg.prototype.renderStatementInput_ = function(pathObject, row, cursor.y += Blockly.BlockSvg.SEP_SPACE_Y; } }; + +/** + * Position an new block correctly, so that it doesn't move the existing block + * when connected to it. + * @param {!Blockly.Block} newBlock The block to position - either the first + * block in a dragged stack or an insertion marker. + * @param {!Blockly.Connection} newConnection The connection on the new block's + * stack - either a connection on newBlock, or the last NEXT_STATEMENT + * connection on the stack if the stack's being dropped before another + * block. + * @param {!Blockly.Connection} existingConnection The connection on the + * existing block, which newBlock should line up with. + */ +Blockly.BlockSvg.prototype.positionNewBlock = function(newBlock, newConnection, + existingConnection) { + // We only need to position the new block if it's before the existing one, + // otherwise its position is set by the previous block. + if (newConnection.type == Blockly.NEXT_STATEMENT || + newConnection.type == Blockly.INPUT_VALUE) { + var dx = existingConnection.x_ - newConnection.x_; + var dy = existingConnection.y_ - newConnection.y_; + + newBlock.moveBy(dx, dy); + } +}; + +/** + * Visual effect to show that if the dragging block is dropped, this block will + * be replaced. If a shadow block, it will disappear. Otherwise it will bump. + * @param {boolean} add True if highlighting should be added. + */ +Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { + if (add) { + Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), + 'blocklyReplaceable'); + } else { + Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_), + 'blocklyReplaceable'); + } +}; diff --git a/core/blockly.js b/core/blockly.js index bfd58cdff..366e55fdf 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -98,6 +98,13 @@ Blockly.clipboardXml_ = null; */ Blockly.clipboardSource_ = null; +/** + * Map of types to type counts for the clipboard object and descendants. + * @type {Object} + * @private + */ +Blockly.clipboardTypeCounts_ = null; + /** * Cached value for whether 3D is supported. * @type {!boolean} @@ -227,15 +234,18 @@ Blockly.onKeyDown_ = function(e) { if (e.keyCode == 86) { // 'v' for paste. if (Blockly.clipboardXml_) { - Blockly.Events.setGroup(true); // Pasting always pastes to the main workspace, even if the copy // started in a flyout workspace. var workspace = Blockly.clipboardSource_; if (workspace.isFlyout) { workspace = workspace.targetWorkspace; } - workspace.paste(Blockly.clipboardXml_); - Blockly.Events.setGroup(false); + if (Blockly.clipboardTypeCounts_ && + workspace.isCapacityAvailable(Blockly.clipboardTypeCounts_)) { + Blockly.Events.setGroup(true); + workspace.paste(Blockly.clipboardXml_); + Blockly.Events.setGroup(false); + } } } else if (e.keyCode == 90) { // 'z' for undo 'Z' is for redo. @@ -273,6 +283,8 @@ Blockly.copy_ = function(toCopy) { } Blockly.clipboardXml_ = xml; Blockly.clipboardSource_ = toCopy.workspace; + Blockly.clipboardTypeCounts_ = toCopy.isComment ? null : + Blockly.utils.getBlockTypeCounts(toCopy, true); }; /** diff --git a/core/connection.js b/core/connection.js index b94d07fec..6e978dedc 100644 --- a/core/connection.js +++ b/core/connection.js @@ -334,12 +334,52 @@ Blockly.Connection.prototype.checkConnection_ = function(target) { } }; +/** + * Check if the two connections can be dragged to connect to each other. + * This is used by the connection database when searching for the closest + * connection. + * @param {!Blockly.Connection} candidate A nearby connection to check, which + * must be a previous connection. + * @return {boolean} True if the connection is allowed, false otherwise. + * @private + */ +Blockly.Connection.prototype.canConnectToPrevious_ = function(candidate) { + if (this.targetConnection) { + // This connection is already occupied. + // A next connection will never disconnect itself mid-drag. + return false; + } + + // Don't let blocks try to connect to themselves or ones they nest. + if (Blockly.draggingConnections_.indexOf(candidate) != -1) { + return false; + } + + if (!candidate.targetConnection) { + return true; + } + + var targetBlock = candidate.targetBlock(); + // If it is connected to a real block, game over. + if (!targetBlock.isInsertionMarker()) { + return false; + } + // If it's connected to an insertion marker but that insertion marker + // is the first block in a stack, it's still fine. If that insertion + // marker is in the middle of a stack, it won't work. + return !targetBlock.getPreviousBlock(); +}; + /** * Check if the two connections can be dragged to connect to each other. * @param {!Blockly.Connection} candidate A nearby connection to check. * @return {boolean} True if the connection is allowed, false otherwise. */ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) { + // Don't consider insertion markers. + if (candidate.sourceBlock_.isInsertionMarker()) { + return false; + } // Type checking. var canConnect = this.canConnectWithReason_(candidate); if (canConnect != Blockly.Connection.CAN_CONNECT) { @@ -348,30 +388,27 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) { switch (candidate.type) { case Blockly.PREVIOUS_STATEMENT: - // Don't offer to connect the bottom of a statement block to one that's - // already connected. - if (candidate.isConnected() || this.isConnected()) { - return false; - } - break; - case Blockly.OUTPUT_VALUE: + return this.canConnectToPrevious_(candidate); + case Blockly.OUTPUT_VALUE: { // Don't offer to connect an already connected left (male) value plug to // an available right (female) value plug. if (candidate.isConnected() || this.isConnected()) { return false; } break; - case Blockly.INPUT_VALUE: + } + case Blockly.INPUT_VALUE: { // Offering to connect the left (male) of a value block to an already // connected value pair is ok, we'll splice it in. - // However, don't offer to splice into an unmovable block. - if (candidate.targetConnection && + // However, don't offer to splice into an immovable block. + if (candidate.isConnected() && !candidate.targetBlock().isMovable() && !candidate.targetBlock().isShadow()) { return false; } break; - case Blockly.NEXT_STATEMENT: + } + case Blockly.NEXT_STATEMENT: { // Don't let a block with no next connection bump other blocks out of the // stack. But covering up a shadow block or stack of shadow blocks is // fine. Similarly, replacing a terminal statement with another terminal @@ -383,6 +420,7 @@ Blockly.Connection.prototype.isConnectionAllowed = function(candidate) { return false; } break; + } default: throw Error('Unknown connection type in isConnectionAllowed'); } diff --git a/core/constants.js b/core/constants.js index 54ed1fb49..229ca0d4d 100644 --- a/core/constants.js +++ b/core/constants.js @@ -42,13 +42,37 @@ Blockly.FLYOUT_DRAG_RADIUS = 10; /** * Maximum misalignment between connections for them to snap together. */ -Blockly.SNAP_RADIUS = 20; +Blockly.SNAP_RADIUS = 28; + +/** + * Maximum misalignment between connections for them to snap together, + * when a connection is already highlighted. + */ +Blockly.CONNECTING_SNAP_RADIUS = Blockly.SNAP_RADIUS; + +/** + * How much to prefer staying connected to the current connection over moving to + * a new connection. The current previewed connection is considered to be this + * much closer to the matching connection on the block than it actually is. + */ +Blockly.CURRENT_CONNECTION_PREFERENCE = 8; + +/** + * The main colour of insertion markers, in hex. The block is rendered a + * transparent grey by changing the fill opacity in CSS. + */ +Blockly.INSERTION_MARKER_COLOUR = '#000000'; /** * Delay in ms between trigger and bumping unconnected block out of alignment. */ Blockly.BUMP_DELAY = 250; +/** + * Maximum randomness in workspace units for bumping a block. + */ +Blockly.BUMP_RANDOMNESS = 10; + /** * Number of characters to truncate a collapsed block to. */ diff --git a/core/contextmenu.js b/core/contextmenu.js index b23e8e11e..bd8b38f8e 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -260,11 +260,7 @@ Blockly.ContextMenu.blockHelpOption = function(block) { * @package */ Blockly.ContextMenu.blockDuplicateOption = function(block) { - var enabled = true; - if (block.getDescendants(false).length > - block.workspace.remainingCapacity()) { - enabled = false; - } + var enabled = block.isDuplicatable(); var duplicateOption = { text: Blockly.Msg['DUPLICATE_BLOCK'], enabled: enabled, diff --git a/core/css.js b/core/css.js index e19e2dfe0..94a75f723 100644 --- a/core/css.js +++ b/core/css.js @@ -284,6 +284,22 @@ Blockly.Css.CONTENT = [ 'display: none;', '}', + '.blocklyInsertionMarker>.blocklyPath,', + '.blocklyInsertionMarker>.blocklyPathLight,', + '.blocklyInsertionMarker>.blocklyPathDark {', + 'fill-opacity: .2;', + 'stroke: none', + '}', + + '.blocklyReplaceable .blocklyPath {', + 'fill-opacity: 0.5;', + '}', + + '.blocklyReplaceable .blocklyPathLight,', + '.blocklyReplaceable .blocklyPathDark {', + 'display: none;', + '}', + '.blocklyText {', 'cursor: default;', 'fill: #fff;', @@ -515,15 +531,15 @@ Blockly.Css.CONTENT = [ 'fill: #bbb;', '}', - '.blocklyZoom>image {', + '.blocklyZoom>image, .blocklyZoom>svg>image {', 'opacity: .4;', '}', - '.blocklyZoom>image:hover {', + '.blocklyZoom>image:hover, .blocklyZoom>svg>image:hover {', 'opacity: .6;', '}', - '.blocklyZoom>image:active {', + '.blocklyZoom>image:active, .blocklyZoom>svg>image:active {', 'opacity: .8;', '}', diff --git a/core/dragged_connection_manager.js b/core/dragged_connection_manager.js index 1b2642280..211ec8bf4 100644 --- a/core/dragged_connection_manager.js +++ b/core/dragged_connection_manager.js @@ -36,6 +36,7 @@ goog.require('goog.math.Coordinate'); * Class that controls updates to connections during drags. It is primarily * responsible for finding the closest eligible connection and highlighting or * unhiglighting it as needed during a drag. + * @deprecated July 2018. Use InsertionMarkerManager. * @param {!Blockly.BlockSvg} block The top block in the stack being dragged. * @constructor */ diff --git a/core/field_dropdown.js b/core/field_dropdown.js index f5c1fe9dd..1de845765 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -548,7 +548,7 @@ Blockly.FieldDropdown.validateOptions_ = function(options) { var foundError = false; for (var i = 0; i < options.length; ++i) { var tuple = options[i]; - if (!Array.isArray(options)) { + if (!Array.isArray(tuple)) { foundError = true; console.error( 'Invalid option[' + i + ']: Each FieldDropdown option must be an ' + diff --git a/core/field_textinput.js b/core/field_textinput.js index 1f6daf975..d727603fe 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -281,7 +281,13 @@ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) { var text = htmlInput.value; if (text !== htmlInput.oldValue_) { htmlInput.oldValue_ = text; + + // TODO(#2169): Once issue is fixed the setGroup functionality could be + // moved up to the Field setValue method. This would create a + // broader fix for all field types. + Blockly.Events.setGroup(true); this.setValue(text); + Blockly.Events.setGroup(false); this.validate_(); } else if (goog.userAgent.WEBKIT) { // Cursor key. Render the source block to show the caret moving. diff --git a/core/flyout_base.js b/core/flyout_base.js index 235a03bb9..5be9802b7 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -228,6 +228,7 @@ Blockly.Flyout.prototype.createDom = function(tagName) { Blockly.Flyout.prototype.init = function(targetWorkspace) { this.targetWorkspace_ = targetWorkspace; this.workspace_.targetWorkspace = targetWorkspace; + // Add scrollbar. this.scrollbar_ = new Blockly.Scrollbar(this.workspace_, this.horizontalLayout_, false, 'blocklyFlyoutScrollbar'); @@ -724,12 +725,11 @@ Blockly.Flyout.prototype.moveRectToBlock_ = function(rect, block) { * @private */ Blockly.Flyout.prototype.filterForCapacity_ = function() { - var remainingCapacity = this.targetWorkspace_.remainingCapacity(); var blocks = this.workspace_.getTopBlocks(false); for (var i = 0, block; block = blocks[i]; i++) { if (this.permanentlyDisabled_.indexOf(block) == -1) { - var allBlocks = block.getDescendants(false); - block.setDisabled(allBlocks.length > remainingCapacity); + block.setDisabled(!this.targetWorkspace_ + .isCapacityAvailable(Blockly.utils.getBlockTypeCounts(block))); } } }; diff --git a/core/generator.js b/core/generator.js index f6f5e7a75..b5a794959 100644 --- a/core/generator.js +++ b/core/generator.js @@ -158,17 +158,18 @@ Blockly.Generator.prototype.allNestedComments = function(block) { /** * Generate code for the specified block (and attached blocks). * @param {Blockly.Block} block The block to generate code for. + * @param {boolean=} opt_thisOnly True to generate code for only this statement. * @return {string|!Array} For statement blocks, the generated code. * For value blocks, an array containing the generated code and an * operator order value. Returns '' if block is null. */ -Blockly.Generator.prototype.blockToCode = function(block) { +Blockly.Generator.prototype.blockToCode = function(block, opt_thisOnly) { if (!block) { return ''; } if (block.disabled) { // Skip past this block if it is disabled. - return this.blockToCode(block.getNextBlock()); + return opt_thisOnly ? '' : this.blockToCode(block.getNextBlock()); } var func = this[block.type]; @@ -186,13 +187,13 @@ Blockly.Generator.prototype.blockToCode = function(block) { if (!block.outputConnection) { throw TypeError('Expecting string from statement block: ' + block.type); } - return [this.scrub_(block, code[0]), code[1]]; + return [this.scrub_(block, code[0], opt_thisOnly), code[1]]; } else if (typeof code == 'string') { var id = block.id.replace(/\$/g, '$$$$'); // Issue 251. if (this.STATEMENT_PREFIX) { code = this.STATEMENT_PREFIX.replace(/%1/g, '\'' + id + '\'') + code; } - return this.scrub_(block, code); + return this.scrub_(block, code, opt_thisOnly); } else if (code === null) { // Block has handled code generation itself. return ''; diff --git a/core/icon.js b/core/icon.js index 6c259245d..0d3f2ddd3 100644 --- a/core/icon.js +++ b/core/icon.js @@ -147,7 +147,8 @@ Blockly.Icon.prototype.updateColour = function() { * @return {number} Horizontal offset for next item to draw. */ Blockly.Icon.prototype.renderIcon = function(cursorX) { - if (this.collapseHidden && this.block_.isCollapsed()) { + if ((this.collapseHidden && this.block_.isCollapsed()) || + this.block_.isInsertionMarker()) { this.iconGroup_.setAttribute('display', 'none'); return cursorX; } diff --git a/core/inject.js b/core/inject.js index 5ee706d15..df7b48179 100644 --- a/core/inject.js +++ b/core/inject.js @@ -224,7 +224,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, Blockly.mainWorkspace = mainWorkspace; if (!options.readOnly && !options.hasScrollbars) { - var workspaceChanged = function() { + var workspaceChanged = function(e) { if (!mainWorkspace.isDragging()) { var metrics = mainWorkspace.getMetrics(); var edgeLeft = metrics.viewLeft + metrics.absoluteLeft; @@ -239,6 +239,12 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, // One or more blocks may be out of bounds. Bump them back in. var MARGIN = 25; var blocks = mainWorkspace.getTopBlocks(false); + var oldGroup = null; + if (e) { + oldGroup = Blockly.Events.getGroup(); + Blockly.Events.setGroup(e.group); + } + var movedBlocks = false; for (var b = 0, block; block = blocks[b]; b++) { var blockXY = block.getRelativeToSurfaceXY(); var blockHW = block.getHeightWidth(); @@ -246,26 +252,37 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, var overflowTop = edgeTop + MARGIN - blockHW.height - blockXY.y; if (overflowTop > 0) { block.moveBy(0, overflowTop); + movedBlocks = true; } // Bump any block that's below the bottom back inside. var overflowBottom = edgeTop + metrics.viewHeight - MARGIN - blockXY.y; if (overflowBottom < 0) { block.moveBy(0, overflowBottom); + movedBlocks = true; } // Bump any block that's off the left back inside. var overflowLeft = MARGIN + edgeLeft - blockXY.x - (options.RTL ? 0 : blockHW.width); if (overflowLeft > 0) { block.moveBy(overflowLeft, 0); + movedBlocks = true; } // Bump any block that's off the right back inside. var overflowRight = edgeLeft + metrics.viewWidth - MARGIN - blockXY.x + (options.RTL ? blockHW.width : 0); if (overflowRight < 0) { block.moveBy(overflowRight, 0); + movedBlocks = true; } } + if (e) { + if (!e.group && movedBlocks) { + console.log('WARNING: Moved blocks in bounds but there was no event group.' + + ' This may break undo.'); + } + Blockly.Events.setGroup(oldGroup); + } } } }; diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js new file mode 100644 index 000000000..f94677c8d --- /dev/null +++ b/core/insertion_marker_manager.js @@ -0,0 +1,698 @@ +/** + * @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 Class that controls updates to connections during drags. + * @author fenichel@google.com (Rachel Fenichel) + */ +'use strict'; + +goog.provide('Blockly.InsertionMarkerManager'); + +goog.require('Blockly.BlockAnimations'); +goog.require('Blockly.Events.BlockMove'); +goog.require('Blockly.RenderedConnection'); + +goog.require('goog.math.Coordinate'); + + +/** + * Class that controls updates to connections during drags. It is primarily + * responsible for finding the closest eligible connection and highlighting or + * unhiglighting it as needed during a drag. + * @param {!Blockly.BlockSvg} block The top block in the stack being dragged. + * @constructor + */ +Blockly.InsertionMarkerManager = function(block) { + Blockly.selected = block; + + /** + * The top block in the stack being dragged. + * Does not change during a drag. + * @type {!Blockly.Block} + * @private + */ + this.topBlock_ = block; + + /** + * The workspace on which these connections are being dragged. + * Does not change during a drag. + * @type {!Blockly.WorkspaceSvg} + * @private + */ + this.workspace_ = block.workspace; + + /** + * The last connection on the stack, if it's not the last connection on the + * first block. + * Set in initAvailableConnections, if at all. + * @type {Blockly.RenderedConnection} + * @private + */ + this.lastOnStack_ = null; + + /** + * The insertion marker corresponding to the last block in the stack, if + * that's not the same as the first block in the stack. + * Set in initAvailableConnections, if at all + * @type {Blockly.BlockSvg} + * @private + */ + this.lastMarker_ = null; + + /** + * The insertion marker that shows up between blocks to show where a block + * would go if dropped immediately. + * @type {Blockly.BlockSvg} + * @private + */ + this.firstMarker_ = this.createMarkerBlock_(this.topBlock_); + + /** + * The connection that this block would connect to if released immediately. + * Updated on every mouse move. + * This is not on any of the blocks that are being dragged. + * @type {Blockly.RenderedConnection} + * @private + */ + this.closestConnection_ = null; + + /** + * The connection that would connect to this.closestConnection_ if this block + * were released immediately. + * Updated on every mouse move. + * This is on the top block that is being dragged or the last block in the + * dragging stack. + * @type {Blockly.RenderedConnection} + * @private + */ + this.localConnection_ = null; + + /** + * Whether the block would be deleted if it were dropped immediately. + * Updated on every mouse move. + * @type {boolean} + * @private + */ + this.wouldDeleteBlock_ = false; + + /** + * Connection on the insertion marker block that corresponds to + * this.localConnection_ on the currently dragged block. + * @type {Blockly.RenderedConnection} + * @private + */ + this.markerConnection_ = null; + + /** + * Whether we are currently highlighting the block (shadow or real) that would + * be replaced if the drag were released immediately. + * @type {boolean} + * @private + */ + this.highlightingBlock_ = false; + + /** + * The block that is being highlighted for replacement, or null. + * @type {Blockly.BlockSvg} + * @private + */ + this.highlightedBlock_ = null; + + /** + * The connections on the dragging blocks that are available to connect to + * other blocks. This includes all open connections on the top block, as well + * as the last connection on the block stack. + * Does not change during a drag. + * @type {!Array.} + * @private + */ + this.availableConnections_ = this.initAvailableConnections_(); +}; + +/** + * Sever all links from this object. + * @package + */ +Blockly.InsertionMarkerManager.prototype.dispose = function() { + this.topBlock_ = null; + this.workspace_ = null; + this.availableConnections_.length = 0; + this.closestConnection_ = null; + this.localConnection_ = null; + + Blockly.Events.disable(); + try { + if (this.firstMarker_) { + this.firstMarker_.dispose(); + this.firstMarker_ = null; + } + if (this.lastMarker_) { + this.lastMarker_.dispose(); + this.lastMarker_ = null; + } + } finally { + Blockly.Events.enable(); + } + + this.highlightedBlock_ = null; +}; + +/** + * Return whether the block would be deleted if dropped immediately, based on + * information from the most recent move event. + * @return {boolean} true if the block would be deleted if dropped immediately. + * @package + */ +Blockly.InsertionMarkerManager.prototype.wouldDeleteBlock = function() { + return this.wouldDeleteBlock_; +}; + +/** + * Return whether the block would be connected if dropped immediately, based on + * information from the most recent move event. + * @return {boolean} true if the block would be connected if dropped immediately. + * @package + */ +Blockly.InsertionMarkerManager.prototype.wouldConnectBlock = function() { + return !!this.closestConnection_; +}; + +/** + * Connect to the closest connection and render the results. + * This should be called at the end of a drag. + * @package + */ +Blockly.InsertionMarkerManager.prototype.applyConnections = function() { + if (this.closestConnection_) { + // Don't fire events for insertion markers. + Blockly.Events.disable(); + this.hidePreview_(); + Blockly.Events.enable(); + // Connect two blocks together. + this.localConnection_.connect(this.closestConnection_); + if (this.topBlock_.rendered) { + // Trigger a connection animation. + // Determine which connection is inferior (lower in the source stack). + var inferiorConnection = this.localConnection_.isSuperior() ? + this.closestConnection_ : this.localConnection_; + Blockly.BlockAnimations.connectionUiEffect( + inferiorConnection.getSourceBlock()); + // Bring the just-edited stack to the front. + var rootBlock = this.topBlock_.getRootBlock(); + rootBlock.bringToFront(); + } + } +}; + +/** + * Update highlighted connections based on the most recent move location. + * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * in workspace units. + * @param {?number} deleteArea One of {@link Blockly.DELETE_AREA_TRASH}, + * {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}. + * @package + */ +Blockly.InsertionMarkerManager.prototype.update = function(dxy, deleteArea) { + var candidate = this.getCandidate_(dxy); + + this.wouldDeleteBlock_ = this.shouldDelete_(candidate, deleteArea); + var shouldUpdate = this.wouldDeleteBlock_ || + this.shouldUpdatePreviews_(candidate, dxy); + + if (shouldUpdate) { + // Don't fire events for insertion marker creation or movement. + Blockly.Events.disable(); + this.maybeHidePreview_(candidate); + this.maybeShowPreview_(candidate); + Blockly.Events.enable(); + } +}; + +/**** Begin initialization functions ****/ + +/** + * Create an insertion marker that represents the given block. + * @param {!Blockly.BlockSvg} sourceBlock The block that the insertion marker + * will represent. + * @return {!Blockly.BlockSvg} The insertion marker that represents the given + * block. + * @private + */ +Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlock) { + var imType = sourceBlock.type; + + Blockly.Events.disable(); + try { + var result = this.workspace_.newBlock(imType); + result.setInsertionMarker(true, sourceBlock.width); + if (sourceBlock.mutationToDom) { + var oldMutationDom = sourceBlock.mutationToDom(); + if (oldMutationDom) { + result.domToMutation(oldMutationDom); + } + } + // Copy field values from the other block. These values may impact the + // rendered size of the insertion marker. Note that we do not care about + // child blocks here. + for (var i = 0; i < sourceBlock.inputList.length; i++) { + var input = sourceBlock.inputList[i]; + for (var j = 0; j < input.fieldRow.length; j++) { + var field = input.fieldRow[j]; + result.setFieldValue(field.getValue(), field.name); + } + } + + result.initSvg(); + result.getSvgRoot().setAttribute('visibility', 'hidden'); + } finally { + Blockly.Events.enable(); + } + + return result; +}; + +/** + * Populate the list of available connections on this block stack. This should + * only be called once, at the beginning of a drag. + * If the stack has more than one block, this function will populate + * lastOnStack_ and create the corresponding insertion marker. + * @return {!Array.} a list of available + * connections. + * @private + */ +Blockly.InsertionMarkerManager.prototype.initAvailableConnections_ = function() { + var available = this.topBlock_.getConnections_(false); + // Also check the last connection on this stack + var lastOnStack = this.topBlock_.lastConnectionInStack(); + if (lastOnStack && lastOnStack != this.topBlock_.nextConnection) { + available.push(lastOnStack); + this.lastOnStack_ = lastOnStack; + this.lastMarker_ = this.createMarkerBlock_(lastOnStack.sourceBlock_); + } + return available; +}; + +/**** End initialization functions ****/ + + +/** + * Whether the previews (insertion marker and replacement marker) should be + * updated based on the closest candidate and the current drag distance. + * @param {!Object} candidate An object containing a local connection, a closest + * connection, and a radius. Returned by getCandidate_. + * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * in workspace units. + * @return {boolean} whether the preview should be updated. + * @private + */ +Blockly.InsertionMarkerManager.prototype.shouldUpdatePreviews_ = function( + candidate, dxy) { + var candidateLocal = candidate.local; + var candidateClosest = candidate.closest; + var radius = candidate.radius; + + // Found a connection! + if (candidateLocal && candidateClosest) { + // We're already showing an insertion marker. + // Decide whether the new connection has higher priority. + if (this.localConnection_ && this.closestConnection_) { + // The connection was the same as the current connection. + if (this.closestConnection_ == candidateClosest && + this.localConnection_ == candidateLocal) { + return false; + } + var xDiff = this.localConnection_.x_ + dxy.x - this.closestConnection_.x_; + var yDiff = this.localConnection_.y_ + dxy.y - this.closestConnection_.y_; + var curDistance = Math.sqrt(xDiff * xDiff + yDiff * yDiff); + // Slightly prefer the existing preview over a new preview. + return !(candidateClosest && radius > curDistance - + Blockly.CURRENT_CONNECTION_PREFERENCE); + } else if (!this.localConnection_ && !this.closestConnection_) { + // We weren't showing a preview before, but we should now. + return true; + } else { + console.error('Only one of localConnection_ and closestConnection_ was set.'); + } + } else { // No connection found. + // Only need to update if we were showing a preview before. + return !!(this.localConnection_ && this.closestConnection_); + } + + console.error('Returning true from shouldUpdatePreviews, but it\'s not clear why.'); + return true; +}; + +/** + * Find the nearest valid connection, which may be the same as the current + * closest connection. + * @param {!goog.math.Coordinate} dxy Position relative to drag start, + * in workspace units. + * @return {!Object} candidate An object containing a local connection, a closest + * connection, and a radius. + */ +Blockly.InsertionMarkerManager.prototype.getCandidate_ = function(dxy) { + var radius = this.getStartRadius_(); + var candidateClosest = null; + var candidateLocal = null; + + for (var i = 0; i < this.availableConnections_.length; i++) { + var myConnection = this.availableConnections_[i]; + var neighbour = myConnection.closest(radius, dxy); + if (neighbour.connection) { + candidateClosest = neighbour.connection; + candidateLocal = myConnection; + radius = neighbour.radius; + } + } + return { + closest: candidateClosest, + local: candidateLocal, + radius: radius + }; +}; + +/** + * Decide the radius at which to start searching for the closest connection. + * @return {number} The radius at which to start the search for the closest + * connection. + * @private + */ +Blockly.InsertionMarkerManager.prototype.getStartRadius_ = function() { + // If there is already a connection highlighted, + // increase the radius we check for making new connections. + // Why? When a connection is highlighted, blocks move around when the insertion + // marker is created, which could cause the connection became out of range. + // By increasing radiusConnection when a connection already exists, + // we never "lose" the connection from the offset. + if (this.closestConnection_ && this.localConnection_) { + return Blockly.CONNECTING_SNAP_RADIUS; + } + return Blockly.SNAP_RADIUS; +}; + +/** + * Whether ending the drag would replace a block or insert a block. + * @return {boolean} True if dropping the block immediately would replace + * another block. False if dropping the block immediately would result in + * the block being inserted in a block stack. + * @private + */ +Blockly.InsertionMarkerManager.prototype.shouldReplace_ = function() { + var closest = this.closestConnection_; + var local = this.localConnection_; + + // Dragging a block over an existing block in an input. + if (local.type == Blockly.OUTPUT_VALUE) { + // Insert the dragged block into the stack if possible. + if (!closest.isConnected() || + Blockly.Connection.lastConnectionInRow_(this.topBlock_, + closest.targetConnection.getSourceBlock())) { + return false; // Insert. + } + // Otherwise replace the existing block and bump it out. + return true; // Replace. + } + + // Connecting to a statement input of c-block is an insertion, even if that + // c-block is terminal (e.g. forever). + if (local == local.sourceBlock_.getFirstStatementConnection()) { + return false; // Insert. + } + + // Dragging a terminal block over another (connected) terminal block will + // replace, not insert. + var isTerminalBlock = !this.topBlock_.nextConnection; + var isConnectedTerminal = isTerminalBlock && + local.type == Blockly.PREVIOUS_STATEMENT && closest.isConnected(); + if (isConnectedTerminal) { + return true; // Replace. + } + + // Otherwise it's an insertion. + return false; +}; + +/** + * Whether ending the drag would delete the block. + * @param {!Object} candidate An object containing a local connection, a closest + * connection, and a radius. + * @param {?number} deleteArea One of {@link Blockly.DELETE_AREA_TRASH}, + * {@link Blockly.DELETE_AREA_TOOLBOX}, or {@link Blockly.DELETE_AREA_NONE}. + * @return {boolean} True if dropping the block immediately would replace + * delete the block. False otherwise. + * @private + */ +Blockly.InsertionMarkerManager.prototype.shouldDelete_ = function(candidate, + deleteArea) { + // Prefer connecting over dropping into the trash can, but prefer dragging to + // the toolbox over connecting to other blocks. + var wouldConnect = candidate && !!candidate.closest && + deleteArea != Blockly.DELETE_AREA_TOOLBOX; + var wouldDelete = !!deleteArea && !this.topBlock_.getParent() && + this.topBlock_.isDeletable(); + + return wouldDelete && !wouldConnect; +}; + +/**** Begin preview visibility functions ****/ + +/** + * Show an insertion marker or replacement highlighting during a drag, if + * needed. + * At the beginning of this function, this.localConnection_ and + * this.closestConnection_ should both be null. + * @param {!Object} candidate An object containing a local connection, a closest + * connection, and a radius. + * @private + */ +Blockly.InsertionMarkerManager.prototype.maybeShowPreview_ = function(candidate) { + // Nope, don't add a marker. + if (this.wouldDeleteBlock_) { + return; + } + var closest = candidate.closest; + var local = candidate.local; + + // Nothing to connect to. + if (!closest) { + return; + } + + // Something went wrong and we're trying to connect to an invalid connection. + if (closest == this.closestConnection_ || + closest.sourceBlock_.isInsertionMarker()) { + console.log("trying to connect to an insertion marker"); + return; + } + // Add an insertion marker or replacement marker. + this.closestConnection_ = closest; + this.localConnection_ = local; + this.showPreview_(); +}; + +/** + * A preview should be shown. This function figures out if it should be a block + * highlight or an insertion marker, and shows the appropriate one. + * @private + */ +Blockly.InsertionMarkerManager.prototype.showPreview_ = function() { + if (this.shouldReplace_()) { + this.highlightBlock_(); + } else { // Should insert + this.connectMarker_(); + } + // Also highlight the actual connection, as a nod to previous behaviour. + if (this.closestConnection_) { + this.closestConnection_.highlight(); + } +}; + +/** + * Show an insertion marker or replacement highlighting during a drag, if + * needed. + * At the end of this function, this.localConnection_ and + * this.closestConnection_ should both be null. + * @param {!Object} candidate An object containing a local connection, a closest + * connection, and a radius. + * @private + */ +Blockly.InsertionMarkerManager.prototype.maybeHidePreview_ = function(candidate) { + // If there's no new preview, remove the old one but don't bother deleting it. + // We might need it later, and this saves disposing of it and recreating it. + if (!candidate.closest) { + this.hidePreview_(); + } else { + // If there's a new preview and there was an preview before, and either + // connection has changed, remove the old preview. + var hadPreview = this.closestConnection_ && this.localConnection_; + var closestChanged = this.closestConnection_ != candidate.closest; + var localChanged = this.localConnection_ != candidate.local; + + // Also hide if we had a preview before but now we're going to delete instead. + if (hadPreview && (closestChanged || localChanged || this.wouldDeleteBlock_)) { + this.hidePreview_(); + } + } + + // Either way, clear out old state. + this.markerConnection_ = null; + this.closestConnection_ = null; + this.localConnection_ = null; +}; + +/** + * A preview should be hidden. This function figures out if it is a block + * highlight or an insertion marker, and hides the appropriate one. + * @private + */ +Blockly.InsertionMarkerManager.prototype.hidePreview_ = function() { + if (this.closestConnection_) { + this.closestConnection_.unhighlight(); + } + if (this.highlightingBlock_) { + this.unhighlightBlock_(); + } else if (this.markerConnection_) { + this.disconnectMarker_(); + } +}; + +/**** End preview visibility functions ****/ + +/**** Begin block highlighting functions ****/ + +/** + * Add highlighting showing which block will be replaced. + */ +Blockly.InsertionMarkerManager.prototype.highlightBlock_ = function() { + var closest = this.closestConnection_; + var local = this.localConnection_; + if (closest.targetBlock()) { + this.highlightedBlock_ = closest.targetBlock(); + closest.targetBlock().highlightForReplacement(true); + } else if (local.type == Blockly.OUTPUT_VALUE) { + this.highlightedBlock_ = closest.sourceBlock_; + // TODO: remove? + closest.sourceBlock_.highlightShapeForInput(closest, true); + } + this.highlightingBlock_ = true; +}; + +/** + * Get rid of the highlighting marking the block that will be replaced. + */ +Blockly.InsertionMarkerManager.prototype.unhighlightBlock_ = function() { + var closest = this.closestConnection_; + // If there's no block in place, but we're still connecting to a value input, + // then we must have been highlighting an input shape. + if (closest.type == Blockly.INPUT_VALUE && !closest.isConnected()) { + this.highlightedBlock_.highlightShapeForInput(closest, false); + } else { + this.highlightedBlock_.highlightForReplacement(false); + } + this.highlightedBlock_ = null; + this.highlightingBlock_ = false; +}; + +/**** End block highlighting functions ****/ + +/**** Begin insertion marker display functions ****/ + +/** + * Disconnect the insertion marker block in a manner that returns the stack to + * original state. + * @private + */ +Blockly.InsertionMarkerManager.prototype.disconnectMarker_ = function() { + if (!this.markerConnection_) { + console.log('No insertion marker connection to disconnect'); + return; + } + + var imConn = this.markerConnection_; + var imBlock = imConn.sourceBlock_; + var markerNext = imBlock.nextConnection; + var markerPrev = imBlock.previousConnection; + var markerOutput = imBlock.outputConnection; + + var isFirstInStatementStack = + (imConn == markerNext && !(markerPrev && markerPrev.targetConnection)); + + var isFirstInOutputStack = imConn.type == Blockly.INPUT_VALUE && + !(markerOutput && markerOutput.targetConnection); + // The insertion marker is the first block in a stack. Unplug won't do + // anything in that case. Instead, unplug the following block. + if (isFirstInStatementStack || isFirstInOutputStack) { + imConn.targetBlock().unplug(false); + } + // Inside of a C-block, first statement connection. + else if (imConn.type == Blockly.NEXT_STATEMENT && imConn != markerNext) { + var innerConnection = imConn.targetConnection; + innerConnection.sourceBlock_.unplug(false); + + var previousBlockNextConnection = + markerPrev ? markerPrev.targetConnection : null; + + imBlock.unplug(true); + if (previousBlockNextConnection) { + previousBlockNextConnection.connect(innerConnection); + } + } else { + imBlock.unplug(true /* healStack */); + } + + if (imConn.targetConnection) { + throw 'markerConnection_ still connected at the end of disconnectInsertionMarker'; + } + + this.markerConnection_ = null; + imBlock.getSvgRoot().setAttribute('visibility', 'hidden'); +}; + +/** + * Add an insertion marker connected to the appropriate blocks. + * @private + */ +Blockly.InsertionMarkerManager.prototype.connectMarker_ = function() { + var local = this.localConnection_; + var closest = this.closestConnection_; + + var isLastInStack = this.lastOnStack_ && local == this.lastOnStack_; + var imBlock = isLastInStack ? this.lastMarker_ : this.firstMarker_; + var imConn = imBlock.getMatchingConnection(local.sourceBlock_, local); + + goog.asserts.assert(imConn != this.markerConnection_, + 'Made it to connectMarker_ even though the marker isn\'t changing'); + + // Render disconnected from everything else so that we have a valid + // connection location. + imBlock.render(); + imBlock.rendered = true; + imBlock.getSvgRoot().setAttribute('visibility', 'visible'); + + // Position based on the calculated connection locations. + imBlock.positionNewBlock(imBlock, imConn, closest); + + // Connect() also renders the insertion marker. + imConn.connect(closest); + this.markerConnection_ = imConn; +}; + +/**** End insertion marker display functions ****/ diff --git a/core/options.js b/core/options.js index 51a47a1ce..0b91d9d64 100644 --- a/core/options.js +++ b/core/options.js @@ -119,6 +119,7 @@ Blockly.Options = function(options) { this.disable = hasDisable; this.readOnly = readOnly; this.maxBlocks = options['maxBlocks'] || Infinity; + this.maxInstances = options['maxInstances']; this.pathToMedia = pathToMedia; this.hasCategories = hasCategories; this.hasScrollbars = hasScrollbars; diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 8b786b26d..d972c60c2 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -97,8 +97,10 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) // Raise it to the top for extra visibility. var selected = Blockly.selected == rootBlock; selected || rootBlock.addSelect(); - var dx = (staticConnection.x_ + Blockly.SNAP_RADIUS) - this.x_; - var dy = (staticConnection.y_ + Blockly.SNAP_RADIUS) - this.y_; + var dx = (staticConnection.x_ + Blockly.SNAP_RADIUS + + Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.x_; + var dy = (staticConnection.y_ + Blockly.SNAP_RADIUS + + Math.floor(Math.random() * Blockly.BUMP_RANDOMNESS)) - this.y_; if (reverse) { // When reversing a bump due to an uneditable block, bump up. dy = -dy; diff --git a/core/utils.js b/core/utils.js index 8d5ccac83..2ec39feee 100644 --- a/core/utils.js +++ b/core/utils.js @@ -974,3 +974,32 @@ Blockly.utils.containsNode = function(parent, descendant) { return !!(parent.compareDocumentPosition(descendant) & Node.DOCUMENT_POSITION_CONTAINED_BY); }; + +/** + * Get a map of all the block's descendants mapping their type to the number of + * children with that type. + * @param {!Blockly.Block} block The block to map. + * @param {boolean=} opt_stripFollowing Optionally ignore all following + * statements (blocks that are not inside a value or statement input + * of the block). + * @returns {!Object} Map of types to type counts for descendants of the bock. + */ +Blockly.utils.getBlockTypeCounts = function(block, opt_stripFollowing) { + var typeCountsMap = Object.create(null); + var descendants = block.getDescendants(true); + if (opt_stripFollowing) { + var nextBlock = block.getNextBlock(); + if (nextBlock) { + var index = descendants.indexOf(nextBlock); + descendants.splice(index, descendants.length - index); + } + } + for (var i = 0, checkBlock; checkBlock = descendants[i]; i++) { + if (typeCountsMap[checkBlock.type]) { + typeCountsMap[checkBlock.type]++; + } else { + typeCountsMap[checkBlock.type] = 1; + } + } + return typeCountsMap; +}; diff --git a/core/variables.js b/core/variables.js index fbd627f48..36cb36358 100644 --- a/core/variables.js +++ b/core/variables.js @@ -539,7 +539,13 @@ Blockly.Variables.getVariable = function(workspace, id, opt_name, opt_type) { if (!variable && potentialVariableMap) { variable = potentialVariableMap.getVariableById(id); } - } else if (opt_name) { + if (variable) { + return variable; + } + } + // If there was no ID, or there was an ID but it didn't match any variables, + // look up by name and type. + if (opt_name) { if (opt_type == undefined) { throw Error('Tried to look up a variable by name without a type'); } diff --git a/core/workspace.js b/core/workspace.js index 6040f7da4..8d58ff87a 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -85,6 +85,11 @@ Blockly.Workspace = function(opt_options) { * @private */ this.blockDB_ = Object.create(null); + /** + * @type {!Object} + * @private + */ + this.typedBlocksDB_ = Object.create(null); /** * A map from variable type to list of variable names. The lists contain all @@ -147,6 +152,24 @@ Blockly.Workspace.prototype.dispose = function() { */ Blockly.Workspace.SCAN_ANGLE = 3; +/** + * Compare function for sorting objects (blocks, comments, etc) by position; + * top to bottom (with slight LTR or RTL bias). + * @param {!Blockly.Block | !Blockly.WorkspaceComment} a The first object to + * compare. + * @param {!Blockly.Block | !Blockly.WorkspaceComment} b The second object to + * compare. + * @returns {number} The comparison value. This tells Array.sort() how to change + * object a's index. + * @private + */ +Blockly.Workspace.prototype.sortObjects_ = function(a, b) { + var aXY = a.getRelativeToSurfaceXY(); + var bXY = b.getRelativeToSurfaceXY(); + return (aXY.y + Blockly.Workspace.prototype.sortObjects_.offset * aXY.x) - + (bXY.y + Blockly.Workspace.prototype.sortObjects_.offset * bXY.x); +}; + /** * Add a block to the list of top blocks. * @param {!Blockly.Block} block Block to add. @@ -175,16 +198,58 @@ Blockly.Workspace.prototype.getTopBlocks = function(ordered) { // Copy the topBlocks_ list. var blocks = [].concat(this.topBlocks_); if (ordered && blocks.length > 1) { - var offset = + this.sortObjects_.offset = Math.sin(Blockly.utils.toRadians(Blockly.Workspace.SCAN_ANGLE)); if (this.RTL) { - offset *= -1; + this.sortObjects_.offset *= -1; } - blocks.sort(function(a, b) { - var aXY = a.getRelativeToSurfaceXY(); - var bXY = b.getRelativeToSurfaceXY(); - return (aXY.y + offset * aXY.x) - (bXY.y + offset * bXY.x); - }); + blocks.sort(this.sortObjects_); + } + return blocks; +}; + +/** + * Add a block to the list of blocks keyed by type. + * @param {!Blockly.Block} block Block to add. + */ +Blockly.Workspace.prototype.addTypedBlock = function(block) { + if (!this.typedBlocksDB_[block.type]) { + this.typedBlocksDB_[block.type] = []; + } + this.typedBlocksDB_[block.type].push(block); +}; + +/** + * Remove a block from the list of blocks keyed by type. + * @param {!Blockly.Block} block Block to remove. + */ +Blockly.Workspace.prototype.removeTypedBlock = function(block) { + this.typedBlocksDB_[block.type].splice(this.typedBlocksDB_[block.type] + .indexOf(block), 1); + if (!this.typedBlocksDB_[block.type].length) { + delete this.typedBlocksDB_[block.type]; + } +}; + +/** + * Finds the blocks with the associated type and returns them. Blocks are + * optionally sorted by position; top to bottom (with slight LTR or RTL bias). + * @param {string} type The type of block to search for. + * @param {boolean} ordered Sort the list if true. + * @return {!Array.} The blocks of the given type. + */ +Blockly.Workspace.prototype.getBlocksByType = function(type, ordered) { + if (!this.typedBlocksDB_[type]) { + return []; + } + var blocks = this.typedBlocksDB_[type].slice(0); + if (ordered && blocks.length > 1) { + this.sortObjects_.offset = + Math.sign(Blockly.utils.toRadians(Blockly.Workspace.SCAN_ANGLE)); + if (this.RTL) { + this.sortObjects_.offset *= -1; + } + blocks.sort(this.sortObjects_); } return blocks; }; @@ -232,16 +297,12 @@ Blockly.Workspace.prototype.getTopComments = function(ordered) { // Copy the topComments_ list. var comments = [].concat(this.topComments_); if (ordered && comments.length > 1) { - var offset = + this.sortObjects_.offset = Math.sin(Blockly.utils.toRadians(Blockly.Workspace.SCAN_ANGLE)); if (this.RTL) { - offset *= -1; + this.sortObjects_.offset *= -1; } - comments.sort(function(a, b) { - var aXY = a.getRelativeToSurfaceXY(); - var bXY = b.getRelativeToSurfaceXY(); - return (aXY.y + offset * aXY.x) - (bXY.y + offset * bXY.x); - }); + comments.sort(this.sortObjects_); } return comments; }; @@ -455,6 +516,56 @@ Blockly.Workspace.prototype.remainingCapacity = function() { return this.options.maxBlocks - this.getAllBlocks().length; }; +/** + * The number of blocks of the given type that may be added to the workspace + * before reaching the maxInstances allowed for that type. + * @param {string} type Type of block to return capacity for. + * @return {number} Number of blocks of type left. + */ +Blockly.Workspace.prototype.remainingCapacityOfType = function(type) { + if (!this.options.maxInstances) { + return Infinity; + } + return (this.options.maxInstances[type] || Infinity) - + this.getBlocksByType(type).length; +}; + +/** + * Check if there is remaining capacity for blocks of the given counts to be + * created. If the total number of blocks represented by the map is more than + * the total remaining capacity, it returns false. If a type count is more + * than the remaining capacity for that type, it returns false. + * @param {!Object} typeCountsMap A map of types to counts (usually representing + * blocks to be created). + * @returns {boolean} True if there is capacity for the given map, + * false otherwise. + */ +Blockly.Workspace.prototype.isCapacityAvailable = function(typeCountsMap) { + if (!this.hasBlockLimits()) { + return true; + } + var copyableBlocksCount = 0; + for (var type in typeCountsMap) { + if (typeCountsMap[type] > this.remainingCapacityOfType(type)) { + return false; + } + copyableBlocksCount += typeCountsMap[type]; + } + if (copyableBlocksCount > this.remainingCapacity()) { + return false; + } + return true; +}; + +/** + * Checks if the workspace has any limits on the maximum number of blocks, + * or the maximum number of blocks of specific types. + * @returns {boolean} True if it has block limits, false otherwise. + */ +Blockly.Workspace.prototype.hasBlockLimits = function() { + return this.options.maxBlocks != Infinity || !!this.options.maxInstances; +}; + /** * Undo or redo the previous action. * @param {boolean} redo False if undo, true if redo. diff --git a/core/workspace_audio.js b/core/workspace_audio.js index fff9b3482..8b7089f91 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -111,7 +111,7 @@ Blockly.WorkspaceAudio.prototype.preload = function() { for (var name in this.SOUNDS_) { var sound = this.SOUNDS_[name]; sound.volume = 0.01; - sound.play(); + sound.play().catch(function() {}); sound.pause(); // iOS can only process one sound at a time. Trying to load more than one // corrupts the earlier ones. Just load one and leave the others uncached. diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index 8c41ff2be..51fb738bb 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -425,6 +425,7 @@ Blockly.WorkspaceCommentSvg.prototype.disposeInternal_ = function() { this.foreignObject_ = null; this.svgRectTarget_ = null; this.svgHandleTarget_ = null; + this.disposed_ = true; }; /** @@ -436,6 +437,9 @@ Blockly.WorkspaceCommentSvg.prototype.setFocus = function() { this.focused_ = true; // Defer CSS changes. setTimeout(function() { + if (comment.disposed_) { + return; + } comment.textarea_.focus(); comment.addFocus(); Blockly.utils.addClass( @@ -454,6 +458,10 @@ Blockly.WorkspaceCommentSvg.prototype.blurFocus = function() { this.focused_ = false; // Defer CSS changes. setTimeout(function() { + if (comment.disposed_) { + return; + } + comment.textarea_.blur(); comment.removeFocus(); Blockly.utils.removeClass( diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 5f5a462d9..7484650e8 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1285,6 +1285,9 @@ Blockly.WorkspaceSvg.prototype.cleanUp = function() { var topBlocks = this.getTopBlocks(true); var cursorY = 0; for (var i = 0, block; block = topBlocks[i]; i++) { + if (!block.isMovable()) { + continue; + } var xy = block.getRelativeToSurfaceXY(); block.moveBy(-xy.x, cursorY - xy.y); block.snapToGrid(); diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 09ffe934c..3c8dd8a52 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -171,18 +171,27 @@ Blockly.ZoomControls.prototype.position = function() { */ Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) { /* This markup will be generated and added to the "blocklyZoom" group: - - - - + + + + + + */ var ws = this.workspace_; + + var svgHolder = Blockly.utils.createSvgElement('svg', + { + "id": "svg" + rnd + }, + this.svgGroup_); + var clip = Blockly.utils.createSvgElement('clipPath', { 'id': 'blocklyZoomoutClipPath' + rnd }, - this.svgGroup_); + svgHolder); Blockly.utils.createSvgElement('rect', { 'width': 32, @@ -197,7 +206,7 @@ Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) { 'y': -15, 'clip-path': 'url(#blocklyZoomoutClipPath' + rnd + ')' }, - this.svgGroup_); + svgHolder); zoomoutSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', ws.options.pathToMedia + Blockly.SPRITE.url); @@ -220,18 +229,26 @@ Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) { */ Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) { /* This markup will be generated and added to the "blocklyZoom" group: - - - - + + + + + + */ + var ws = this.workspace_; + var svgHolder = Blockly.utils.createSvgElement('svg', + { + "id": "svg" + rnd + }, + this.svgGroup_); var clip = Blockly.utils.createSvgElement('clipPath', { 'id': 'blocklyZoominClipPath' + rnd }, - this.svgGroup_); + svgHolder); Blockly.utils.createSvgElement('rect', { 'width': 32, @@ -247,7 +264,7 @@ Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) { 'y': -49, 'clip-path': 'url(#blocklyZoominClipPath' + rnd + ')' }, - this.svgGroup_); + svgHolder); zoominSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', ws.options.pathToMedia + Blockly.SPRITE.url); @@ -270,18 +287,25 @@ Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) { */ Blockly.ZoomControls.prototype.createZoomResetSvg_ = function(rnd) { /* This markup will be generated and added to the "blocklyZoom" group: - - - - + + + + + + */ var ws = this.workspace_; + var svgHolder = Blockly.utils.createSvgElement('svg', + { + "id": "svg" + rnd + }, + this.svgGroup_); var clip = Blockly.utils.createSvgElement('clipPath', { 'id': 'blocklyZoomresetClipPath' + rnd }, - this.svgGroup_); + svgHolder); Blockly.utils.createSvgElement('rect', { 'width': 32, @@ -294,7 +318,7 @@ Blockly.ZoomControls.prototype.createZoomResetSvg_ = function(rnd) { 'height': Blockly.SPRITE.height, 'y': -92, 'clip-path': 'url(#blocklyZoomresetClipPath' + rnd + ')' }, - this.svgGroup_); + svgHolder); zoomresetSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', ws.options.pathToMedia + Blockly.SPRITE.url); diff --git a/dart_compressed.js b/dart_compressed.js index 2d74acbfd..a9e84da5c 100644 --- a/dart_compressed.js +++ b/dart_compressed.js @@ -9,8 +9,8 @@ Blockly.Dart.init=function(a){Blockly.Dart.definitions_=Object.create(null);Bloc for(d=0;dc&&(a=a+" - "+-c,g=Blockly.Dart.ORDER_ADDITIVE); d&&(a=c?"-("+a+")":"-"+a,g=Blockly.Dart.ORDER_UNARY_PREFIX);g=Math.floor(g);e=Math.floor(e);g&&e>=g&&(a="("+a+")")}return a};Blockly.Dart.colour={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.colour_picker=function(a){return["'"+a.getFieldValue("COLOUR")+"'",Blockly.Dart.ORDER_ATOMIC]}; Blockly.Dart.colour_random=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return[Blockly.Dart.provideFunction_("colour_random",["String "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"() {"," String hex = '0123456789abcdef';"," var rnd = new Math.Random();"," return '#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'"," '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}'"," '${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}';","}"])+"()",Blockly.Dart.ORDER_UNARY_POSTFIX]}; diff --git a/demos/mobile/html/index.html b/demos/mobile/html/index.html index e527aa3b9..55906503d 100644 --- a/demos/mobile/html/index.html +++ b/demos/mobile/html/index.html @@ -2,7 +2,7 @@ - +