diff --git a/appengine/storage.js b/appengine/storage.js index c8390b5c8..59cbd6a3a 100644 --- a/appengine/storage.js +++ b/appengine/storage.js @@ -140,17 +140,18 @@ BlocklyStorage.handleRequest_ = function() { * @private */ BlocklyStorage.monitorChanges_ = function() { - var startXmlDom = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); + var workspace = Blockly.getMainWorkspace(); + var startXmlDom = Blockly.Xml.workspaceToDom(workspace); var startXmlText = Blockly.Xml.domToText(startXmlDom); function change() { - var xmlDom = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); + var xmlDom = Blockly.Xml.workspaceToDom(workspace); var xmlText = Blockly.Xml.domToText(xmlDom); if (startXmlText != xmlText) { window.location.hash = ''; Blockly.removeChangeListener(bindData); } } - var bindData = Blockly.addChangeListener(change); + var bindData = workspace.addChangeListener(change); }; /** diff --git a/blockly_compressed.js b/blockly_compressed.js index efffd993b..e3205ed72 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -58,8 +58,8 @@ goog.string.escapeChar=function(a){if(a in goog.string.jsEscapeCache_)return goo goog.string.caseInsensitiveContains=function(a,b){return goog.string.contains(a.toLowerCase(),b.toLowerCase())};goog.string.countOf=function(a,b){return a&&b?a.split(b).length-1:0};goog.string.removeAt=function(a,b,c){var d=a;0<=b&&bb?1:0};goog.string.HASHCODE_MAX_=4294967296;goog.string.hashCode=function(a){for(var b=0,c=0;cb?1:0};goog.string.HASHCODE_MAX_=4294967296;goog.string.hashCode=function(a){for(var b=0,c=0;c=a.left&&b.right<=a.right&&b.top>=a.top&&b.bottom<=a.bottom:b.x>=a.left&&b.x<=a.right&&b.y>=a.top&&b.y<=a.bottom:!1};goog.math.Box.relativePositionX=function(a,b){return b.xa.right?b.x-a.right:0}; +goog.math.Box.relativePositionY=function(a,b){return b.ya.bottom?b.y-a.bottom:0};goog.math.Box.distance=function(a,b){var c=goog.math.Box.relativePositionX(a,b),d=goog.math.Box.relativePositionY(a,b);return Math.sqrt(c*c+d*d)};goog.math.Box.intersects=function(a,b){return a.left<=b.right&&b.left<=a.right&&a.top<=b.bottom&&b.top<=a.bottom};goog.math.Box.intersectsWithPadding=function(a,b,c){return a.left<=b.right+c&&b.left<=a.right+c&&a.top<=b.bottom+c&&b.top<=a.bottom+c}; +goog.math.Box.prototype.ceil=function(){this.top=Math.ceil(this.top);this.right=Math.ceil(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.ceil(this.left);return this};goog.math.Box.prototype.floor=function(){this.top=Math.floor(this.top);this.right=Math.floor(this.right);this.bottom=Math.floor(this.bottom);this.left=Math.floor(this.left);return this}; +goog.math.Box.prototype.round=function(){this.top=Math.round(this.top);this.right=Math.round(this.right);this.bottom=Math.round(this.bottom);this.left=Math.round(this.left);return this};goog.math.Box.prototype.translate=function(a,b){a instanceof goog.math.Coordinate?(this.left+=a.x,this.right+=a.x,this.top+=a.y,this.bottom+=a.y):(this.left+=a,this.right+=a,goog.isNumber(b)&&(this.top+=b,this.bottom+=b));return this}; +goog.math.Box.prototype.scale=function(a,b){var c=goog.isNumber(b)?b:a;this.left*=a;this.right*=a;this.top*=c;this.bottom*=c;return this};goog.math.Rect=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};goog.math.Rect.prototype.clone=function(){return new goog.math.Rect(this.left,this.top,this.width,this.height)};goog.math.Rect.prototype.toBox=function(){return new goog.math.Box(this.top,this.left+this.width,this.top+this.height,this.left)};goog.math.Rect.createFromBox=function(a){return new goog.math.Rect(a.left,a.top,a.right-a.left,a.bottom-a.top)}; +goog.DEBUG&&(goog.math.Rect.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"});goog.math.Rect.equals=function(a,b){return a==b?!0:a&&b?a.left==b.left&&a.width==b.width&&a.top==b.top&&a.height==b.height:!1}; +goog.math.Rect.prototype.intersection=function(a){var b=Math.max(this.left,a.left),c=Math.min(this.left+this.width,a.left+a.width);if(b<=c){var d=Math.max(this.top,a.top);a=Math.min(this.top+this.height,a.top+a.height);if(d<=a)return this.left=b,this.top=d,this.width=c-b,this.height=a-d,!0}return!1}; +goog.math.Rect.intersection=function(a,b){var c=Math.max(a.left,b.left),d=Math.min(a.left+a.width,b.left+b.width);if(c<=d){var e=Math.max(a.top,b.top),f=Math.min(a.top+a.height,b.top+b.height);if(e<=f)return new goog.math.Rect(c,e,d-c,f-e)}return null};goog.math.Rect.intersects=function(a,b){return a.left<=b.left+b.width&&b.left<=a.left+a.width&&a.top<=b.top+b.height&&b.top<=a.top+a.height};goog.math.Rect.prototype.intersects=function(a){return goog.math.Rect.intersects(this,a)}; +goog.math.Rect.difference=function(a,b){var c=goog.math.Rect.intersection(a,b);if(!c||!c.height||!c.width)return[a.clone()];var c=[],d=a.top,e=a.height,f=a.left+a.width,g=a.top+a.height,h=b.left+b.width,k=b.top+b.height;b.top>a.top&&(c.push(new goog.math.Rect(a.left,a.top,a.width,b.top-a.top)),d=b.top,e-=b.top-a.top);ka.left&&c.push(new goog.math.Rect(a.left,d,b.left-a.left,e));h=a.left+a.width&&this.top<=a.top&&this.top+this.height>=a.top+a.height:a.x>=this.left&&a.x<=this.left+this.width&&a.y>=this.top&&a.y<=this.top+this.height};goog.math.Rect.prototype.squaredDistance=function(a){var b=a.xa.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c|| +"absolute"==c||"relative"==c))return a;return null}; +goog.style.getVisibleRectForElement=function(a){for(var b=new goog.math.Box(0,Infinity,Infinity,0),c=goog.dom.getDomHelper(a),d=c.getDocument().body,e=c.getDocument().documentElement,f=c.getDocumentScrollElement();a=goog.style.getOffsetParent(a);)if(!(goog.userAgent.IE&&0==a.clientWidth||goog.userAgent.WEBKIT&&0==a.clientHeight&&a==d)&&a!=d&&a!=e&&"visible"!=goog.style.getStyle_(a,"overflow")){var g=goog.style.getPageOffset(a),h=goog.style.getClientLeftTop(a);g.x+=h.x;g.y+=h.y;b.top=Math.max(b.top, +g.y);b.right=Math.min(b.right,g.x+a.clientWidth);b.bottom=Math.min(b.bottom,g.y+a.clientHeight);b.left=Math.max(b.left,g.x)}d=f.scrollLeft;f=f.scrollTop;b.left=Math.max(b.left,d);b.top=Math.max(b.top,f);c=c.getViewportSize();b.right=Math.min(b.right,d+c.width);b.bottom=Math.min(b.bottom,f+c.height);return 0<=b.top&&0<=b.left&&b.bottom>b.top&&b.right>b.left?b:null}; +goog.style.getContainerOffsetToScrollInto=function(a,b,c){var d=goog.style.getPageOffset(a),e=goog.style.getPageOffset(b),f=goog.style.getBorderBox(b),g=d.x-e.x-f.left,d=d.y-e.y-f.top,h=b.clientWidth-a.offsetWidth;a=b.clientHeight-a.offsetHeight;var k=b.scrollLeft,l=b.scrollTop;if(b==goog.dom.getDocument().body||b==goog.dom.getDocument().documentElement)k=e.x+f.left,l=e.y+f.top,goog.userAgent.IE&&!goog.userAgent.isDocumentModeOrHigher(10)&&(k+=f.left,l+=f.top);c?(k+=g-h/2,l+=d-a/2):(k+=Math.min(g, +Math.max(g-h,0)),l+=Math.min(d,Math.max(d-a,0)));return new goog.math.Coordinate(k,l)};goog.style.scrollIntoContainerView=function(a,b,c){a=goog.style.getContainerOffsetToScrollInto(a,b,c);b.scrollLeft=a.x;b.scrollTop=a.y};goog.style.getClientLeftTop=function(a){return new goog.math.Coordinate(a.clientLeft,a.clientTop)}; +goog.style.getPageOffset=function(a){var b=goog.dom.getOwnerDocument(a);goog.asserts.assertObject(a,"Parameter is required");var c=new goog.math.Coordinate(0,0),d=goog.style.getClientViewportElement(b);if(a==d)return c;a=goog.style.getBoundingClientRect_(a);b=goog.dom.getDomHelper(b).getDocumentScroll();c.x=a.left+b.x;c.y=a.top+b.y;return c};goog.style.getPageOffsetLeft=function(a){return goog.style.getPageOffset(a).x};goog.style.getPageOffsetTop=function(a){return goog.style.getPageOffset(a).y}; +goog.style.getFramedPageOffset=function(a,b){var c=new goog.math.Coordinate(0,0),d=goog.dom.getWindow(goog.dom.getOwnerDocument(a)),e=a;do{var f=d==b?goog.style.getPageOffset(e):goog.style.getClientPositionForElement_(goog.asserts.assert(e));c.x+=f.x;c.y+=f.y}while(d&&d!=b&&d!=d.parent&&(e=d.frameElement)&&(d=d.parent));return c}; +goog.style.translateRectForAnotherFrame=function(a,b,c){if(b.getDocument()!=c.getDocument()){var d=b.getDocument().body;c=goog.style.getFramedPageOffset(d,c.getWindow());c=goog.math.Coordinate.difference(c,goog.style.getPageOffset(d));!goog.userAgent.IE||goog.userAgent.isDocumentModeOrHigher(9)||b.isCss1CompatMode()||(c=goog.math.Coordinate.difference(c,b.getDocumentScroll()));a.left+=c.x;a.top+=c.y}}; +goog.style.getRelativePosition=function(a,b){var c=goog.style.getClientPosition(a),d=goog.style.getClientPosition(b);return new goog.math.Coordinate(c.x-d.x,c.y-d.y)};goog.style.getClientPositionForElement_=function(a){a=goog.style.getBoundingClientRect_(a);return new goog.math.Coordinate(a.left,a.top)}; +goog.style.getClientPosition=function(a){goog.asserts.assert(a);if(a.nodeType==goog.dom.NodeType.ELEMENT)return goog.style.getClientPositionForElement_(a);var b=goog.isFunction(a.getBrowserEvent),c=a;a.targetTouches&&a.targetTouches.length?c=a.targetTouches[0]:b&&a.getBrowserEvent().targetTouches&&a.getBrowserEvent().targetTouches.length&&(c=a.getBrowserEvent().targetTouches[0]);return new goog.math.Coordinate(c.clientX,c.clientY)}; +goog.style.setPageOffset=function(a,b,c){var d=goog.style.getPageOffset(a);b instanceof goog.math.Coordinate&&(c=b.y,b=b.x);goog.style.setPosition(a,a.offsetLeft+(b-d.x),a.offsetTop+(c-d.y))};goog.style.setSize=function(a,b,c){if(b instanceof goog.math.Size)c=b.height,b=b.width;else if(void 0==c)throw Error("missing height argument");goog.style.setWidth(a,b);goog.style.setHeight(a,c)};goog.style.getPixelStyleValue_=function(a,b){"number"==typeof a&&(a=(b?Math.round(a):a)+"px");return a}; +goog.style.setHeight=function(a,b){a.style.height=goog.style.getPixelStyleValue_(b,!0)};goog.style.setWidth=function(a,b){a.style.width=goog.style.getPixelStyleValue_(b,!0)};goog.style.getSize=function(a){return goog.style.evaluateWithTemporaryDisplay_(goog.style.getSizeWithDisplay_,a)}; +goog.style.evaluateWithTemporaryDisplay_=function(a,b){if("none"!=goog.style.getStyle_(b,"display"))return a(b);var c=b.style,d=c.display,e=c.visibility,f=c.position;c.visibility="hidden";c.position="absolute";c.display="inline";var g=a(b);c.display=d;c.position=f;c.visibility=e;return g}; +goog.style.getSizeWithDisplay_=function(a){var b=a.offsetWidth,c=a.offsetHeight,d=goog.userAgent.WEBKIT&&!b&&!c;return goog.isDef(b)&&!d||!a.getBoundingClientRect?new goog.math.Size(b,c):(a=goog.style.getBoundingClientRect_(a),new goog.math.Size(a.right-a.left,a.bottom-a.top))};goog.style.getTransformedSize=function(a){if(!a.getBoundingClientRect)return null;a=goog.style.evaluateWithTemporaryDisplay_(goog.style.getBoundingClientRect_,a);return new goog.math.Size(a.right-a.left,a.bottom-a.top)}; +goog.style.getBounds=function(a){var b=goog.style.getPageOffset(a);a=goog.style.getSize(a);return new goog.math.Rect(b.x,b.y,a.width,a.height)};goog.style.toCamelCase=function(a){return goog.string.toCamelCase(String(a))};goog.style.toSelectorCase=function(a){return goog.string.toSelectorCase(a)}; +goog.style.getOpacity=function(a){var b=a.style;a="";"opacity"in b?a=b.opacity:"MozOpacity"in b?a=b.MozOpacity:"filter"in b&&(b=b.filter.match(/alpha\(opacity=([\d.]+)\)/))&&(a=String(b[1]/100));return""==a?a:Number(a)};goog.style.setOpacity=function(a,b){var c=a.style;"opacity"in c?c.opacity=b:"MozOpacity"in c?c.MozOpacity=b:"filter"in c&&(c.filter=""===b?"":"alpha(opacity="+100*b+")")}; +goog.style.setTransparentBackgroundImage=function(a,b){var c=a.style;goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("8")?c.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+b+'", sizingMethod="crop")':(c.backgroundImage="url("+b+")",c.backgroundPosition="top left",c.backgroundRepeat="no-repeat")};goog.style.clearTransparentBackgroundImage=function(a){a=a.style;"filter"in a?a.filter="":a.backgroundImage="none"}; +goog.style.showElement=function(a,b){goog.style.setElementShown(a,b)};goog.style.setElementShown=function(a,b){a.style.display=b?"":"none"};goog.style.isElementShown=function(a){return"none"!=a.style.display}; +goog.style.installStyles=function(a,b){var c=goog.dom.getDomHelper(b),d=null,e=c.getDocument();goog.userAgent.IE&&e.createStyleSheet?(d=e.createStyleSheet(),goog.style.setStyles(d,a)):(e=c.getElementsByTagNameAndClass("head")[0],e||(d=c.getElementsByTagNameAndClass("body")[0],e=c.createDom("head"),d.parentNode.insertBefore(e,d)),d=c.createDom("style"),goog.style.setStyles(d,a),c.appendChild(e,d));return d};goog.style.uninstallStyles=function(a){goog.dom.removeNode(a.ownerNode||a.owningElement||a)}; +goog.style.setStyles=function(a,b){goog.userAgent.IE&&goog.isDef(a.cssText)?a.cssText=b:a.innerHTML=b};goog.style.setPreWrap=function(a){a=a.style;goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("8")?(a.whiteSpace="pre",a.wordWrap="break-word"):a.whiteSpace=goog.userAgent.GECKO?"-moz-pre-wrap":"pre-wrap"};goog.style.setInlineBlock=function(a){a=a.style;a.position="relative";goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("8")?(a.zoom="1",a.display="inline"):a.display="inline-block"}; +goog.style.isRightToLeft=function(a){return"rtl"==goog.style.getStyle_(a,"direction")};goog.style.unselectableStyle_=goog.userAgent.GECKO?"MozUserSelect":goog.userAgent.WEBKIT?"WebkitUserSelect":null;goog.style.isUnselectable=function(a){return goog.style.unselectableStyle_?"none"==a.style[goog.style.unselectableStyle_].toLowerCase():goog.userAgent.IE||goog.userAgent.OPERA?"on"==a.getAttribute("unselectable"):!1}; +goog.style.setUnselectable=function(a,b,c){c=c?null:a.getElementsByTagName("*");var d=goog.style.unselectableStyle_;if(d){if(b=b?"none":"",a.style[d]=b,c){a=0;for(var e;e=c[a];a++)e.style[d]=b}}else if(goog.userAgent.IE||goog.userAgent.OPERA)if(b=b?"on":"",a.setAttribute("unselectable",b),c)for(a=0;e=c[a];a++)e.setAttribute("unselectable",b)};goog.style.getBorderBoxSize=function(a){return new goog.math.Size(a.offsetWidth,a.offsetHeight)}; +goog.style.setBorderBoxSize=function(a,b){var c=goog.dom.getOwnerDocument(a),d=goog.dom.getDomHelper(c).isCss1CompatMode();if(!goog.userAgent.IE||goog.userAgent.isVersionOrHigher("10")||d&&goog.userAgent.isVersionOrHigher("8"))goog.style.setBoxSizingSize_(a,b,"border-box");else if(c=a.style,d){var d=goog.style.getPaddingBox(a),e=goog.style.getBorderBox(a);c.pixelWidth=b.width-e.left-d.left-d.right-e.right;c.pixelHeight=b.height-e.top-d.top-d.bottom-e.bottom}else c.pixelWidth=b.width,c.pixelHeight= +b.height}; +goog.style.getContentBoxSize=function(a){var b=goog.dom.getOwnerDocument(a),c=goog.userAgent.IE&&a.currentStyle;if(c&&goog.dom.getDomHelper(b).isCss1CompatMode()&&"auto"!=c.width&&"auto"!=c.height&&!c.boxSizing)return b=goog.style.getIePixelValue_(a,c.width,"width","pixelWidth"),a=goog.style.getIePixelValue_(a,c.height,"height","pixelHeight"),new goog.math.Size(b,a);c=goog.style.getBorderBoxSize(a);b=goog.style.getPaddingBox(a);a=goog.style.getBorderBox(a);return new goog.math.Size(c.width-a.left- +b.left-b.right-a.right,c.height-a.top-b.top-b.bottom-a.bottom)}; +goog.style.setContentBoxSize=function(a,b){var c=goog.dom.getOwnerDocument(a),d=goog.dom.getDomHelper(c).isCss1CompatMode();if(!goog.userAgent.IE||goog.userAgent.isVersionOrHigher("10")||d&&goog.userAgent.isVersionOrHigher("8"))goog.style.setBoxSizingSize_(a,b,"content-box");else if(c=a.style,d)c.pixelWidth=b.width,c.pixelHeight=b.height;else{var d=goog.style.getPaddingBox(a),e=goog.style.getBorderBox(a);c.pixelWidth=b.width+e.left+d.left+d.right+e.right;c.pixelHeight=b.height+e.top+d.top+d.bottom+ +e.bottom}};goog.style.setBoxSizingSize_=function(a,b,c){a=a.style;goog.userAgent.GECKO?a.MozBoxSizing=c:goog.userAgent.WEBKIT?a.WebkitBoxSizing=c:a.boxSizing=c;a.width=Math.max(b.width,0)+"px";a.height=Math.max(b.height,0)+"px"};goog.style.getIePixelValue_=function(a,b,c,d){if(/^\d+px?$/.test(b))return parseInt(b,10);var e=a.style[c],f=a.runtimeStyle[c];a.runtimeStyle[c]=a.currentStyle[c];a.style[c]=b;b=a.style[d];a.style[c]=e;a.runtimeStyle[c]=f;return b}; +goog.style.getIePixelDistance_=function(a,b){var c=goog.style.getCascadedStyle(a,b);return c?goog.style.getIePixelValue_(a,c,"left","pixelLeft"):0}; +goog.style.getBox_=function(a,b){if(goog.userAgent.IE){var c=goog.style.getIePixelDistance_(a,b+"Left"),d=goog.style.getIePixelDistance_(a,b+"Right"),e=goog.style.getIePixelDistance_(a,b+"Top"),f=goog.style.getIePixelDistance_(a,b+"Bottom");return new goog.math.Box(e,d,f,c)}c=goog.style.getComputedStyle(a,b+"Left");d=goog.style.getComputedStyle(a,b+"Right");e=goog.style.getComputedStyle(a,b+"Top");f=goog.style.getComputedStyle(a,b+"Bottom");return new goog.math.Box(parseFloat(e),parseFloat(d),parseFloat(f), +parseFloat(c))};goog.style.getPaddingBox=function(a){return goog.style.getBox_(a,"padding")};goog.style.getMarginBox=function(a){return goog.style.getBox_(a,"margin")};goog.style.ieBorderWidthKeywords_={thin:2,medium:4,thick:6}; +goog.style.getIePixelBorder_=function(a,b){if("none"==goog.style.getCascadedStyle(a,b+"Style"))return 0;var c=goog.style.getCascadedStyle(a,b+"Width");return c in goog.style.ieBorderWidthKeywords_?goog.style.ieBorderWidthKeywords_[c]:goog.style.getIePixelValue_(a,c,"left","pixelLeft")}; +goog.style.getBorderBox=function(a){if(goog.userAgent.IE&&!goog.userAgent.isDocumentModeOrHigher(9)){var b=goog.style.getIePixelBorder_(a,"borderLeft"),c=goog.style.getIePixelBorder_(a,"borderRight"),d=goog.style.getIePixelBorder_(a,"borderTop");a=goog.style.getIePixelBorder_(a,"borderBottom");return new goog.math.Box(d,c,a,b)}b=goog.style.getComputedStyle(a,"borderLeftWidth");c=goog.style.getComputedStyle(a,"borderRightWidth");d=goog.style.getComputedStyle(a,"borderTopWidth");a=goog.style.getComputedStyle(a, +"borderBottomWidth");return new goog.math.Box(parseFloat(d),parseFloat(c),parseFloat(a),parseFloat(b))};goog.style.getFontFamily=function(a){var b=goog.dom.getOwnerDocument(a),c="";if(b.body.createTextRange&&goog.dom.contains(b,a)){b=b.body.createTextRange();b.moveToElementText(a);try{c=b.queryCommandValue("FontName")}catch(d){c=""}}c||(c=goog.style.getStyle_(a,"fontFamily"));a=c.split(",");1goog.Timer.MAX_TIMEOUT_?goog.Timer.INVALID_TIMEOUT_ID_:goog.Timer.defaultTimerObject.setTimeout(a,b||0)};goog.Timer.clear=function(a){goog.Timer.defaultTimerObject.clearTimeout(a)}; -goog.Timer.promise=function(a,b){var c=null;return(new goog.Promise(function(d,e){c=goog.Timer.callOnce(function(){d(b)},a);c==goog.Timer.INVALID_TIMEOUT_ID_&&e(Error("Failed to schedule timer."))})).thenCatch(function(a){goog.Timer.clear(c);throw a;})};goog.math.Box=function(a,b,c,d){this.top=a;this.right=b;this.bottom=c;this.left=d};goog.math.Box.boundingBox=function(a){for(var b=new goog.math.Box(arguments[0].y,arguments[0].x,arguments[0].y,arguments[0].x),c=1;c=a.left&&b.right<=a.right&&b.top>=a.top&&b.bottom<=a.bottom:b.x>=a.left&&b.x<=a.right&&b.y>=a.top&&b.y<=a.bottom:!1};goog.math.Box.relativePositionX=function(a,b){return b.xa.right?b.x-a.right:0}; -goog.math.Box.relativePositionY=function(a,b){return b.ya.bottom?b.y-a.bottom:0};goog.math.Box.distance=function(a,b){var c=goog.math.Box.relativePositionX(a,b),d=goog.math.Box.relativePositionY(a,b);return Math.sqrt(c*c+d*d)};goog.math.Box.intersects=function(a,b){return a.left<=b.right&&b.left<=a.right&&a.top<=b.bottom&&b.top<=a.bottom};goog.math.Box.intersectsWithPadding=function(a,b,c){return a.left<=b.right+c&&b.left<=a.right+c&&a.top<=b.bottom+c&&b.top<=a.bottom+c}; -goog.math.Box.prototype.ceil=function(){this.top=Math.ceil(this.top);this.right=Math.ceil(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.ceil(this.left);return this};goog.math.Box.prototype.floor=function(){this.top=Math.floor(this.top);this.right=Math.floor(this.right);this.bottom=Math.floor(this.bottom);this.left=Math.floor(this.left);return this}; -goog.math.Box.prototype.round=function(){this.top=Math.round(this.top);this.right=Math.round(this.right);this.bottom=Math.round(this.bottom);this.left=Math.round(this.left);return this};goog.math.Box.prototype.translate=function(a,b){a instanceof goog.math.Coordinate?(this.left+=a.x,this.right+=a.x,this.top+=a.y,this.bottom+=a.y):(this.left+=a,this.right+=a,goog.isNumber(b)&&(this.top+=b,this.bottom+=b));return this}; -goog.math.Box.prototype.scale=function(a,b){var c=goog.isNumber(b)?b:a;this.left*=a;this.right*=a;this.top*=c;this.bottom*=c;return this};goog.math.Rect=function(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d};goog.math.Rect.prototype.clone=function(){return new goog.math.Rect(this.left,this.top,this.width,this.height)};goog.math.Rect.prototype.toBox=function(){return new goog.math.Box(this.top,this.left+this.width,this.top+this.height,this.left)};goog.math.Rect.createFromBox=function(a){return new goog.math.Rect(a.left,a.top,a.right-a.left,a.bottom-a.top)}; -goog.DEBUG&&(goog.math.Rect.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"});goog.math.Rect.equals=function(a,b){return a==b?!0:a&&b?a.left==b.left&&a.width==b.width&&a.top==b.top&&a.height==b.height:!1}; -goog.math.Rect.prototype.intersection=function(a){var b=Math.max(this.left,a.left),c=Math.min(this.left+this.width,a.left+a.width);if(b<=c){var d=Math.max(this.top,a.top);a=Math.min(this.top+this.height,a.top+a.height);if(d<=a)return this.left=b,this.top=d,this.width=c-b,this.height=a-d,!0}return!1}; -goog.math.Rect.intersection=function(a,b){var c=Math.max(a.left,b.left),d=Math.min(a.left+a.width,b.left+b.width);if(c<=d){var e=Math.max(a.top,b.top),f=Math.min(a.top+a.height,b.top+b.height);if(e<=f)return new goog.math.Rect(c,e,d-c,f-e)}return null};goog.math.Rect.intersects=function(a,b){return a.left<=b.left+b.width&&b.left<=a.left+a.width&&a.top<=b.top+b.height&&b.top<=a.top+a.height};goog.math.Rect.prototype.intersects=function(a){return goog.math.Rect.intersects(this,a)}; -goog.math.Rect.difference=function(a,b){var c=goog.math.Rect.intersection(a,b);if(!c||!c.height||!c.width)return[a.clone()];var c=[],d=a.top,e=a.height,f=a.left+a.width,g=a.top+a.height,h=b.left+b.width,k=b.top+b.height;b.top>a.top&&(c.push(new goog.math.Rect(a.left,a.top,a.width,b.top-a.top)),d=b.top,e-=b.top-a.top);ka.left&&c.push(new goog.math.Rect(a.left,d,b.left-a.left,e));h=a.left+a.width&&this.top<=a.top&&this.top+this.height>=a.top+a.height:a.x>=this.left&&a.x<=this.left+this.width&&a.y>=this.top&&a.y<=this.top+this.height};goog.math.Rect.prototype.squaredDistance=function(a){var b=a.xa.clientWidth||a.scrollHeight>a.clientHeight||"fixed"==c|| -"absolute"==c||"relative"==c))return a;return null}; -goog.style.getVisibleRectForElement=function(a){for(var b=new goog.math.Box(0,Infinity,Infinity,0),c=goog.dom.getDomHelper(a),d=c.getDocument().body,e=c.getDocument().documentElement,f=c.getDocumentScrollElement();a=goog.style.getOffsetParent(a);)if(!(goog.userAgent.IE&&0==a.clientWidth||goog.userAgent.WEBKIT&&0==a.clientHeight&&a==d)&&a!=d&&a!=e&&"visible"!=goog.style.getStyle_(a,"overflow")){var g=goog.style.getPageOffset(a),h=goog.style.getClientLeftTop(a);g.x+=h.x;g.y+=h.y;b.top=Math.max(b.top, -g.y);b.right=Math.min(b.right,g.x+a.clientWidth);b.bottom=Math.min(b.bottom,g.y+a.clientHeight);b.left=Math.max(b.left,g.x)}d=f.scrollLeft;f=f.scrollTop;b.left=Math.max(b.left,d);b.top=Math.max(b.top,f);c=c.getViewportSize();b.right=Math.min(b.right,d+c.width);b.bottom=Math.min(b.bottom,f+c.height);return 0<=b.top&&0<=b.left&&b.bottom>b.top&&b.right>b.left?b:null}; -goog.style.getContainerOffsetToScrollInto=function(a,b,c){var d=goog.style.getPageOffset(a),e=goog.style.getPageOffset(b),f=goog.style.getBorderBox(b),g=d.x-e.x-f.left,d=d.y-e.y-f.top,h=b.clientWidth-a.offsetWidth;a=b.clientHeight-a.offsetHeight;var k=b.scrollLeft,l=b.scrollTop;if(b==goog.dom.getDocument().body||b==goog.dom.getDocument().documentElement)k=e.x+f.left,l=e.y+f.top,goog.userAgent.IE&&!goog.userAgent.isDocumentModeOrHigher(10)&&(k+=f.left,l+=f.top);c?(k+=g-h/2,l+=d-a/2):(k+=Math.min(g, -Math.max(g-h,0)),l+=Math.min(d,Math.max(d-a,0)));return new goog.math.Coordinate(k,l)};goog.style.scrollIntoContainerView=function(a,b,c){a=goog.style.getContainerOffsetToScrollInto(a,b,c);b.scrollLeft=a.x;b.scrollTop=a.y};goog.style.getClientLeftTop=function(a){return new goog.math.Coordinate(a.clientLeft,a.clientTop)}; -goog.style.getPageOffset=function(a){var b=goog.dom.getOwnerDocument(a);goog.asserts.assertObject(a,"Parameter is required");var c=new goog.math.Coordinate(0,0),d=goog.style.getClientViewportElement(b);if(a==d)return c;a=goog.style.getBoundingClientRect_(a);b=goog.dom.getDomHelper(b).getDocumentScroll();c.x=a.left+b.x;c.y=a.top+b.y;return c};goog.style.getPageOffsetLeft=function(a){return goog.style.getPageOffset(a).x};goog.style.getPageOffsetTop=function(a){return goog.style.getPageOffset(a).y}; -goog.style.getFramedPageOffset=function(a,b){var c=new goog.math.Coordinate(0,0),d=goog.dom.getWindow(goog.dom.getOwnerDocument(a)),e=a;do{var f=d==b?goog.style.getPageOffset(e):goog.style.getClientPositionForElement_(goog.asserts.assert(e));c.x+=f.x;c.y+=f.y}while(d&&d!=b&&d!=d.parent&&(e=d.frameElement)&&(d=d.parent));return c}; -goog.style.translateRectForAnotherFrame=function(a,b,c){if(b.getDocument()!=c.getDocument()){var d=b.getDocument().body;c=goog.style.getFramedPageOffset(d,c.getWindow());c=goog.math.Coordinate.difference(c,goog.style.getPageOffset(d));!goog.userAgent.IE||goog.userAgent.isDocumentModeOrHigher(9)||b.isCss1CompatMode()||(c=goog.math.Coordinate.difference(c,b.getDocumentScroll()));a.left+=c.x;a.top+=c.y}}; -goog.style.getRelativePosition=function(a,b){var c=goog.style.getClientPosition(a),d=goog.style.getClientPosition(b);return new goog.math.Coordinate(c.x-d.x,c.y-d.y)};goog.style.getClientPositionForElement_=function(a){a=goog.style.getBoundingClientRect_(a);return new goog.math.Coordinate(a.left,a.top)}; -goog.style.getClientPosition=function(a){goog.asserts.assert(a);if(a.nodeType==goog.dom.NodeType.ELEMENT)return goog.style.getClientPositionForElement_(a);var b=goog.isFunction(a.getBrowserEvent),c=a;a.targetTouches&&a.targetTouches.length?c=a.targetTouches[0]:b&&a.getBrowserEvent().targetTouches&&a.getBrowserEvent().targetTouches.length&&(c=a.getBrowserEvent().targetTouches[0]);return new goog.math.Coordinate(c.clientX,c.clientY)}; -goog.style.setPageOffset=function(a,b,c){var d=goog.style.getPageOffset(a);b instanceof goog.math.Coordinate&&(c=b.y,b=b.x);goog.style.setPosition(a,a.offsetLeft+(b-d.x),a.offsetTop+(c-d.y))};goog.style.setSize=function(a,b,c){if(b instanceof goog.math.Size)c=b.height,b=b.width;else if(void 0==c)throw Error("missing height argument");goog.style.setWidth(a,b);goog.style.setHeight(a,c)};goog.style.getPixelStyleValue_=function(a,b){"number"==typeof a&&(a=(b?Math.round(a):a)+"px");return a}; -goog.style.setHeight=function(a,b){a.style.height=goog.style.getPixelStyleValue_(b,!0)};goog.style.setWidth=function(a,b){a.style.width=goog.style.getPixelStyleValue_(b,!0)};goog.style.getSize=function(a){return goog.style.evaluateWithTemporaryDisplay_(goog.style.getSizeWithDisplay_,a)}; -goog.style.evaluateWithTemporaryDisplay_=function(a,b){if("none"!=goog.style.getStyle_(b,"display"))return a(b);var c=b.style,d=c.display,e=c.visibility,f=c.position;c.visibility="hidden";c.position="absolute";c.display="inline";var g=a(b);c.display=d;c.position=f;c.visibility=e;return g}; -goog.style.getSizeWithDisplay_=function(a){var b=a.offsetWidth,c=a.offsetHeight,d=goog.userAgent.WEBKIT&&!b&&!c;return goog.isDef(b)&&!d||!a.getBoundingClientRect?new goog.math.Size(b,c):(a=goog.style.getBoundingClientRect_(a),new goog.math.Size(a.right-a.left,a.bottom-a.top))};goog.style.getTransformedSize=function(a){if(!a.getBoundingClientRect)return null;a=goog.style.evaluateWithTemporaryDisplay_(goog.style.getBoundingClientRect_,a);return new goog.math.Size(a.right-a.left,a.bottom-a.top)}; -goog.style.getBounds=function(a){var b=goog.style.getPageOffset(a);a=goog.style.getSize(a);return new goog.math.Rect(b.x,b.y,a.width,a.height)};goog.style.toCamelCase=function(a){return goog.string.toCamelCase(String(a))};goog.style.toSelectorCase=function(a){return goog.string.toSelectorCase(a)}; -goog.style.getOpacity=function(a){var b=a.style;a="";"opacity"in b?a=b.opacity:"MozOpacity"in b?a=b.MozOpacity:"filter"in b&&(b=b.filter.match(/alpha\(opacity=([\d.]+)\)/))&&(a=String(b[1]/100));return""==a?a:Number(a)};goog.style.setOpacity=function(a,b){var c=a.style;"opacity"in c?c.opacity=b:"MozOpacity"in c?c.MozOpacity=b:"filter"in c&&(c.filter=""===b?"":"alpha(opacity="+100*b+")")}; -goog.style.setTransparentBackgroundImage=function(a,b){var c=a.style;goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("8")?c.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+b+'", sizingMethod="crop")':(c.backgroundImage="url("+b+")",c.backgroundPosition="top left",c.backgroundRepeat="no-repeat")};goog.style.clearTransparentBackgroundImage=function(a){a=a.style;"filter"in a?a.filter="":a.backgroundImage="none"}; -goog.style.showElement=function(a,b){goog.style.setElementShown(a,b)};goog.style.setElementShown=function(a,b){a.style.display=b?"":"none"};goog.style.isElementShown=function(a){return"none"!=a.style.display}; -goog.style.installStyles=function(a,b){var c=goog.dom.getDomHelper(b),d=null,e=c.getDocument();goog.userAgent.IE&&e.createStyleSheet?(d=e.createStyleSheet(),goog.style.setStyles(d,a)):(e=c.getElementsByTagNameAndClass("head")[0],e||(d=c.getElementsByTagNameAndClass("body")[0],e=c.createDom("head"),d.parentNode.insertBefore(e,d)),d=c.createDom("style"),goog.style.setStyles(d,a),c.appendChild(e,d));return d};goog.style.uninstallStyles=function(a){goog.dom.removeNode(a.ownerNode||a.owningElement||a)}; -goog.style.setStyles=function(a,b){goog.userAgent.IE&&goog.isDef(a.cssText)?a.cssText=b:a.innerHTML=b};goog.style.setPreWrap=function(a){a=a.style;goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("8")?(a.whiteSpace="pre",a.wordWrap="break-word"):a.whiteSpace=goog.userAgent.GECKO?"-moz-pre-wrap":"pre-wrap"};goog.style.setInlineBlock=function(a){a=a.style;a.position="relative";goog.userAgent.IE&&!goog.userAgent.isVersionOrHigher("8")?(a.zoom="1",a.display="inline"):a.display="inline-block"}; -goog.style.isRightToLeft=function(a){return"rtl"==goog.style.getStyle_(a,"direction")};goog.style.unselectableStyle_=goog.userAgent.GECKO?"MozUserSelect":goog.userAgent.WEBKIT?"WebkitUserSelect":null;goog.style.isUnselectable=function(a){return goog.style.unselectableStyle_?"none"==a.style[goog.style.unselectableStyle_].toLowerCase():goog.userAgent.IE||goog.userAgent.OPERA?"on"==a.getAttribute("unselectable"):!1}; -goog.style.setUnselectable=function(a,b,c){c=c?null:a.getElementsByTagName("*");var d=goog.style.unselectableStyle_;if(d){if(b=b?"none":"",a.style[d]=b,c){a=0;for(var e;e=c[a];a++)e.style[d]=b}}else if(goog.userAgent.IE||goog.userAgent.OPERA)if(b=b?"on":"",a.setAttribute("unselectable",b),c)for(a=0;e=c[a];a++)e.setAttribute("unselectable",b)};goog.style.getBorderBoxSize=function(a){return new goog.math.Size(a.offsetWidth,a.offsetHeight)}; -goog.style.setBorderBoxSize=function(a,b){var c=goog.dom.getOwnerDocument(a),d=goog.dom.getDomHelper(c).isCss1CompatMode();if(!goog.userAgent.IE||goog.userAgent.isVersionOrHigher("10")||d&&goog.userAgent.isVersionOrHigher("8"))goog.style.setBoxSizingSize_(a,b,"border-box");else if(c=a.style,d){var d=goog.style.getPaddingBox(a),e=goog.style.getBorderBox(a);c.pixelWidth=b.width-e.left-d.left-d.right-e.right;c.pixelHeight=b.height-e.top-d.top-d.bottom-e.bottom}else c.pixelWidth=b.width,c.pixelHeight= -b.height}; -goog.style.getContentBoxSize=function(a){var b=goog.dom.getOwnerDocument(a),c=goog.userAgent.IE&&a.currentStyle;if(c&&goog.dom.getDomHelper(b).isCss1CompatMode()&&"auto"!=c.width&&"auto"!=c.height&&!c.boxSizing)return b=goog.style.getIePixelValue_(a,c.width,"width","pixelWidth"),a=goog.style.getIePixelValue_(a,c.height,"height","pixelHeight"),new goog.math.Size(b,a);c=goog.style.getBorderBoxSize(a);b=goog.style.getPaddingBox(a);a=goog.style.getBorderBox(a);return new goog.math.Size(c.width-a.left- -b.left-b.right-a.right,c.height-a.top-b.top-b.bottom-a.bottom)}; -goog.style.setContentBoxSize=function(a,b){var c=goog.dom.getOwnerDocument(a),d=goog.dom.getDomHelper(c).isCss1CompatMode();if(!goog.userAgent.IE||goog.userAgent.isVersionOrHigher("10")||d&&goog.userAgent.isVersionOrHigher("8"))goog.style.setBoxSizingSize_(a,b,"content-box");else if(c=a.style,d)c.pixelWidth=b.width,c.pixelHeight=b.height;else{var d=goog.style.getPaddingBox(a),e=goog.style.getBorderBox(a);c.pixelWidth=b.width+e.left+d.left+d.right+e.right;c.pixelHeight=b.height+e.top+d.top+d.bottom+ -e.bottom}};goog.style.setBoxSizingSize_=function(a,b,c){a=a.style;goog.userAgent.GECKO?a.MozBoxSizing=c:goog.userAgent.WEBKIT?a.WebkitBoxSizing=c:a.boxSizing=c;a.width=Math.max(b.width,0)+"px";a.height=Math.max(b.height,0)+"px"};goog.style.getIePixelValue_=function(a,b,c,d){if(/^\d+px?$/.test(b))return parseInt(b,10);var e=a.style[c],f=a.runtimeStyle[c];a.runtimeStyle[c]=a.currentStyle[c];a.style[c]=b;b=a.style[d];a.style[c]=e;a.runtimeStyle[c]=f;return b}; -goog.style.getIePixelDistance_=function(a,b){var c=goog.style.getCascadedStyle(a,b);return c?goog.style.getIePixelValue_(a,c,"left","pixelLeft"):0}; -goog.style.getBox_=function(a,b){if(goog.userAgent.IE){var c=goog.style.getIePixelDistance_(a,b+"Left"),d=goog.style.getIePixelDistance_(a,b+"Right"),e=goog.style.getIePixelDistance_(a,b+"Top"),f=goog.style.getIePixelDistance_(a,b+"Bottom");return new goog.math.Box(e,d,f,c)}c=goog.style.getComputedStyle(a,b+"Left");d=goog.style.getComputedStyle(a,b+"Right");e=goog.style.getComputedStyle(a,b+"Top");f=goog.style.getComputedStyle(a,b+"Bottom");return new goog.math.Box(parseFloat(e),parseFloat(d),parseFloat(f), -parseFloat(c))};goog.style.getPaddingBox=function(a){return goog.style.getBox_(a,"padding")};goog.style.getMarginBox=function(a){return goog.style.getBox_(a,"margin")};goog.style.ieBorderWidthKeywords_={thin:2,medium:4,thick:6}; -goog.style.getIePixelBorder_=function(a,b){if("none"==goog.style.getCascadedStyle(a,b+"Style"))return 0;var c=goog.style.getCascadedStyle(a,b+"Width");return c in goog.style.ieBorderWidthKeywords_?goog.style.ieBorderWidthKeywords_[c]:goog.style.getIePixelValue_(a,c,"left","pixelLeft")}; -goog.style.getBorderBox=function(a){if(goog.userAgent.IE&&!goog.userAgent.isDocumentModeOrHigher(9)){var b=goog.style.getIePixelBorder_(a,"borderLeft"),c=goog.style.getIePixelBorder_(a,"borderRight"),d=goog.style.getIePixelBorder_(a,"borderTop");a=goog.style.getIePixelBorder_(a,"borderBottom");return new goog.math.Box(d,c,a,b)}b=goog.style.getComputedStyle(a,"borderLeftWidth");c=goog.style.getComputedStyle(a,"borderRightWidth");d=goog.style.getComputedStyle(a,"borderTopWidth");a=goog.style.getComputedStyle(a, -"borderBottomWidth");return new goog.math.Box(parseFloat(d),parseFloat(c),parseFloat(a),parseFloat(b))};goog.style.getFontFamily=function(a){var b=goog.dom.getOwnerDocument(a),c="";if(b.body.createTextRange&&goog.dom.contains(b,a)){b=b.body.createTextRange();b.moveToElementText(a);try{c=b.queryCommandValue("FontName")}catch(d){c=""}}c||(c=goog.style.getStyle_(a,"fontFamily"));a=c.split(",");1c.viewWidth&&(a=this.anchorX_-c.viewLeft-c.viewWidth):this.anchorX_+ac.viewWidth&&(a=this.anchorX_-c.viewLeft-c.viewWidth):this.anchorX_+ae&&(g=2*Math.PI-g);var h=g+Math.PI/2;h>2*Math.PI&&(h-=2*Math.PI);var k=Math.sin(h),l=Math.cos(h),q=this.getBubbleSize(),h=(q.width+q.height)/Blockly.Bubble.ARROW_THICKNESS,h=Math.min(h,q.width,q.height)/2,q=1-Blockly.Bubble.ANCHOR_RADIUS/f,d=b+q*d,e=c+ -q*e,q=b+h*l,m=c+h*k,b=b-h*l,c=c-h*k,k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+q+","+m);a.push("C"+(q+f)+","+(m+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)}; +Blockly.Bubble.prototype.renderArrow_=function(){var a=[],b=this.width_/2,c=this.height_/2,d=-this.relativeLeft_,e=-this.relativeTop_;if(b==d&&c==e)a.push("M "+b+","+c);else{e-=c;d-=b;this.workspace_.RTL&&(d*=-1);var f=Math.sqrt(e*e+d*d),g=Math.acos(d/f);0>e&&(g=2*Math.PI-g);var h=g+Math.PI/2;h>2*Math.PI&&(h-=2*Math.PI);var k=Math.sin(h),l=Math.cos(h),p=this.getBubbleSize(),h=(p.width+p.height)/Blockly.Bubble.ARROW_THICKNESS,h=Math.min(h,p.width,p.height)/2,p=1-Blockly.Bubble.ANCHOR_RADIUS/f,d=b+ +p*d,e=c+p*e,p=b+h*l,m=c+h*k,b=b-h*l,c=c-h*k,k=g+this.arrow_radians_;k>2*Math.PI&&(k-=2*Math.PI);g=Math.sin(k)*f/Blockly.Bubble.ARROW_BEND;f=Math.cos(k)*f/Blockly.Bubble.ARROW_BEND;a.push("M"+p+","+m);a.push("C"+(p+f)+","+(m+g)+" "+d+","+e+" "+d+","+e);a.push("C"+d+","+e+" "+(b+f)+","+(c+g)+" "+b+","+c)}a.push("z");this.bubbleArrow_.setAttribute("d",a.join(" "))};Blockly.Bubble.prototype.setColour=function(a){this.bubbleBack_.setAttribute("fill",a);this.bubbleArrow_.setAttribute("fill",a)}; Blockly.Bubble.prototype.dispose=function(){Blockly.Bubble.unbindDragEvents_();goog.dom.removeNode(this.bubbleGroup_);this.shape_=this.content_=this.workspace_=this.bubbleGroup_=null}; // Copyright 2013 Google Inc. Apache License 2.0 Blockly.Icon=function(a){this.block_=a};Blockly.Icon.prototype.png_="";Blockly.Icon.prototype.SIZE=17;Blockly.Icon.prototype.bubble_=null;Blockly.Icon.prototype.iconX_=0;Blockly.Icon.prototype.iconY_=0; Blockly.Icon.prototype.createIcon=function(){this.iconGroup_||(this.iconGroup_=Blockly.createSvgElement("g",{"class":"blocklyIconGroup"},null),Blockly.createSvgElement("image",{width:this.SIZE,height:this.SIZE},this.iconGroup_).setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.png_),this.block_.getSvgRoot().appendChild(this.iconGroup_),Blockly.bindEvent_(this.iconGroup_,"mouseup",this,this.iconClick_),this.updateEditable())}; Blockly.Icon.prototype.dispose=function(){goog.dom.removeNode(this.iconGroup_);this.iconGroup_=null;this.setVisible(!1);this.block_=null};Blockly.Icon.prototype.updateEditable=function(){this.block_.isInFlyout||!this.block_.isEditable()?Blockly.addClass_(this.iconGroup_,"blocklyIconGroupReadonly"):Blockly.removeClass_(this.iconGroup_,"blocklyIconGroupReadonly")};Blockly.Icon.prototype.isVisible=function(){return!!this.bubble_}; -Blockly.Icon.prototype.iconClick_=function(a){this.block_.isInFlyout||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){if(this.isVisible()){var a=Blockly.makeColour(this.block_.getColour());this.bubble_.setColour(a)}}; -Blockly.Icon.prototype.renderIcon=function(a){if(this.block_.isCollapsed())return this.iconGroup_.setAttribute("display","none"),a;this.iconGroup_.setAttribute("display","block");var b=this.SIZE;Blockly.RTL&&(a-=b);this.iconGroup_.setAttribute("transform","translate("+a+", 5)");this.computeIconLocation();return a=Blockly.RTL?a-Blockly.BlockSvg.SEP_SPACE_X:a+(b+Blockly.BlockSvg.SEP_SPACE_X)}; +Blockly.Icon.prototype.iconClick_=function(a){this.block_.isInFlyout||Blockly.isRightButton(a)||this.setVisible(!this.isVisible())};Blockly.Icon.prototype.updateColour=function(){if(this.isVisible()){var a=Blockly.makeColour(this.block_.getColour());this.bubble_.setColour(a)}}; +Blockly.Icon.prototype.renderIcon=function(a){if(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.setIconLocation=function(a,b){this.iconX_=a;this.iconY_=b;this.isVisible()&&this.bubble_.setAnchorLocation(a,b)};Blockly.Icon.prototype.computeIconLocation=function(){var a=this.block_.getRelativeToSurfaceXY(),b=Blockly.getRelativeXY_(this.iconGroup_),c=a.x+b.x+this.SIZE/2,a=a.y+b.y+this.SIZE/2;c===this.iconX_&&a===this.iconY_||this.setIconLocation(c,a)};Blockly.Icon.prototype.getIconLocation=function(){return{x:this.iconX_,y:this.iconY_}}; // Copyright 2011 Google Inc. Apache License 2.0 Blockly.Comment=function(a){Blockly.Comment.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Comment,Blockly.Icon);Blockly.Comment.prototype.png_="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAANyAAADcgBffIlqAAAAAd0SU1FB98DGgAnBf0Xj5sAAAIBSURBVDjLjZO9SxxRFMXPrFkWl2UFYSOIRtF210YtAiH/gGATRNZFgo19IBaB9Ipgk3SiEoKQgI19JIVgGaOIgpWJEAV1kZk3b1ad0V+KRYIzk5ALh1ecc88978tRSgHPg0Bjvq/BbFalMNR5oaBv+bzWHMfZjOudWPOg6+pDva6elRXlt7fVcnYmPX4sDQ3pdmpKQXu7frS16aXjON8T06OIMWOwtRp3jgNSEpkMTE5y5/v4UcSLePxnroutVNKb4xgYANfFAk/vDbLG8Gtk5P8M7jE6CsZwDDwSMLm5iYmLlpbg4ABOTmBjA4aHk0ZbWxigposLvlarScH5OSwvw9oaABwdJTW1GtTrfJHnUe/uTgqKxeZaKEAUgTEQP/CeHvA8LhRFhLlc+r6zWVhfbyaZn0/yuRxEEaGCAK9USjdZWGgarK5CS0uS7+gAa3EzjYaOy2WlludJi4vSzIx0e5vky2Xp6ko/M4WCPleruk4zsVa6vJSur9OHTEzoqljUJwEdQYDf25uMe3jY3E5fX5Lr7wdr8YGSJCkIeL23h9/a+lA4Pg7T039u6h75POzv4wcBrx5Ec11Wd3bwOzv//VK7umB3F991+Zj2/R1reWstdnaWm3L5YXOlAnNz3FiLbTR4Azj6WwFPjOG953EahoT1On4YEnoep8bwDuiO9/wG1sM4kG8A4fUAAAAASUVORK5CYII="; Blockly.Comment.prototype.text_="";Blockly.Comment.prototype.width_=160;Blockly.Comment.prototype.height_=80; -Blockly.Comment.prototype.createEditor_=function(){this.foreignObject_=Blockly.createSvgElement("foreignObject",{x:Blockly.Bubble.BORDER_WIDTH,y:Blockly.Bubble.BORDER_WIDTH},null);var a=document.createElementNS(Blockly.HTML_NS,"body");a.setAttribute("xmlns",Blockly.HTML_NS);a.className="blocklyMinimalBody";this.textarea_=document.createElementNS(Blockly.HTML_NS,"textarea");this.textarea_.className="blocklyCommentTextarea";this.textarea_.setAttribute("dir",Blockly.RTL?"RTL":"LTR");a.appendChild(this.textarea_); +Blockly.Comment.prototype.createEditor_=function(){this.foreignObject_=Blockly.createSvgElement("foreignObject",{x:Blockly.Bubble.BORDER_WIDTH,y:Blockly.Bubble.BORDER_WIDTH},null);var a=document.createElementNS(Blockly.HTML_NS,"body");a.setAttribute("xmlns",Blockly.HTML_NS);a.className="blocklyMinimalBody";this.textarea_=document.createElementNS(Blockly.HTML_NS,"textarea");this.textarea_.className="blocklyCommentTextarea";this.textarea_.setAttribute("dir",this.block_.RTL?"RTL":"LTR");a.appendChild(this.textarea_); this.foreignObject_.appendChild(a);Blockly.bindEvent_(this.textarea_,"mouseup",this,this.textareaFocus_);return this.foreignObject_};Blockly.Comment.prototype.updateEditable=function(){this.isVisible()&&(this.setVisible(!1),this.setVisible(!0));Blockly.Icon.prototype.updateEditable.call(this)}; Blockly.Comment.prototype.resizeBubble_=function(){var a=this.bubble_.getBubbleSize(),b=2*Blockly.Bubble.BORDER_WIDTH;this.foreignObject_.setAttribute("width",a.width-b);this.foreignObject_.setAttribute("height",a.height-b);this.textarea_.style.width=a.width-b-4+"px";this.textarea_.style.height=a.height-b-4+"px"}; Blockly.Comment.prototype.setVisible=function(a){if(a!=this.isVisible())if(!this.block_.isEditable()&&!this.textarea_||goog.userAgent.IE)Blockly.Warning.prototype.setVisible.call(this,a);else{var b=this.getText(),c=this.getBubbleSize();a?(this.bubble_=new Blockly.Bubble(this.block_.workspace,this.createEditor_(),this.block_.svgPath_,this.iconX_,this.iconY_,this.width_,this.height_),this.bubble_.registerResizeEvent(this,this.resizeBubble_),this.updateColour(),this.text_=null):(this.bubble_.dispose(), @@ -892,13 +894,13 @@ b=a.targetBlock();b.setParent(null);if(!b.previousConnection)throw"Orphan block this.sourceBlock_);this.targetConnection=a;a.targetConnection=this;d.setParent(c);c.rendered&&c.updateDisabled();d.rendered&&d.updateDisabled();c.rendered&&d.rendered&&(this.type==Blockly.NEXT_STATEMENT||this.type==Blockly.PREVIOUS_STATEMENT?d.render():c.render())};Blockly.Connection.singleConnection_=function(a,b){for(var c=!1,d=0;dBlockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastXY_=Blockly.mouseToSvg(a), -Blockly.Tooltip.showPid_=setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.svgGroup_&&(Blockly.Tooltip.svgGroup_.style.display="none"));clearTimeout(Blockly.Tooltip.showPid_)}; -Blockly.Tooltip.show_=function(){Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_;if(Blockly.Tooltip.svgGroup_){goog.dom.removeChildren(Blockly.Tooltip.svgText_);var a=Blockly.Tooltip.element_.tooltip;goog.isFunction(a)&&(a=a());for(var a=Blockly.Tooltip.wrap_(a,Blockly.Tooltip.LIMIT),a=a.split("\n"),b=0;bd.height&&(b-=a.height+2*Blockly.Tooltip.OFFSET_Y);Blockly.RTL?c=Math.max(Blockly.Tooltip.MARGINS,c):c+a.width>d.width-2*Blockly.Tooltip.MARGINS&&(c=d.width-a.width-2*Blockly.Tooltip.MARGINS);Blockly.Tooltip.svgGroup_.setAttribute("transform","translate("+c+","+b+")")}}; -Blockly.Tooltip.wrap_=function(a,b){if(a.length<=b)return a;for(var c=a.trim().split(/\s+/),d=0;db&&(b=c[d].length);var e,d=-Infinity,f,g=1;do{e=d;f=a;for(var h=[],k=c.length/g,l=1,d=0;de);return f}; +Blockly.Tooltip={};Blockly.Tooltip.visible=!1;Blockly.Tooltip.LIMIT=50;Blockly.Tooltip.mouseOutPid_=0;Blockly.Tooltip.showPid_=0;Blockly.Tooltip.lastX_=0;Blockly.Tooltip.lastY_=0;Blockly.Tooltip.element_=null;Blockly.Tooltip.poisonedElement_=null;Blockly.Tooltip.OFFSET_X=0;Blockly.Tooltip.OFFSET_Y=10;Blockly.Tooltip.RADIUS_OK=10;Blockly.Tooltip.HOVER_MS=1E3;Blockly.Tooltip.MARGINS=5;Blockly.Tooltip.DIV=null; +Blockly.Tooltip.createDom=function(){Blockly.Tooltip.DIV||(Blockly.Tooltip.DIV=goog.dom.createDom("div","blocklyTooltipDiv"),document.body.appendChild(Blockly.Tooltip.DIV))};Blockly.Tooltip.bindMouseEvents=function(a){Blockly.bindEvent_(a,"mouseover",null,Blockly.Tooltip.onMouseOver_);Blockly.bindEvent_(a,"mouseout",null,Blockly.Tooltip.onMouseOut_);Blockly.bindEvent_(a,"mousemove",null,Blockly.Tooltip.onMouseMove_)}; +Blockly.Tooltip.onMouseOver_=function(a){for(a=a.target;!goog.isString(a.tooltip)&&!goog.isFunction(a.tooltip);)a=a.tooltip;Blockly.Tooltip.element_!=a&&(Blockly.Tooltip.hide(),Blockly.Tooltip.poisonedElement_=null,Blockly.Tooltip.element_=a);clearTimeout(Blockly.Tooltip.mouseOutPid_)};Blockly.Tooltip.onMouseOut_=function(a){Blockly.Tooltip.mouseOutPid_=setTimeout(function(){Blockly.Tooltip.element_=null;Blockly.Tooltip.poisonedElement_=null;Blockly.Tooltip.hide()},1);clearTimeout(Blockly.Tooltip.showPid_)}; +Blockly.Tooltip.onMouseMove_=function(a){if(Blockly.Tooltip.element_&&Blockly.Tooltip.element_.tooltip&&0==Blockly.dragMode_&&!Blockly.WidgetDiv.isVisible())if(Blockly.Tooltip.visible){var b=Blockly.Tooltip.lastY_-a.clientY;Math.sqrt(Math.pow(Blockly.Tooltip.lastX_-a.clientX,2)+Math.pow(b,2))>Blockly.Tooltip.RADIUS_OK&&Blockly.Tooltip.hide()}else Blockly.Tooltip.poisonedElement_!=Blockly.Tooltip.element_&&(clearTimeout(Blockly.Tooltip.showPid_),Blockly.Tooltip.lastX_=a.clientX,Blockly.Tooltip.lastY_= +a.clientY,Blockly.Tooltip.showPid_=setTimeout(Blockly.Tooltip.show_,Blockly.Tooltip.HOVER_MS))};Blockly.Tooltip.hide=function(){Blockly.Tooltip.visible&&(Blockly.Tooltip.visible=!1,Blockly.Tooltip.DIV&&(Blockly.Tooltip.DIV.style.display="none"));clearTimeout(Blockly.Tooltip.showPid_)}; +Blockly.Tooltip.show_=function(){Blockly.Tooltip.poisonedElement_=Blockly.Tooltip.element_;if(Blockly.Tooltip.DIV){goog.dom.removeChildren(Blockly.Tooltip.DIV);var a=Blockly.Tooltip.element_.tooltip;goog.isFunction(a)&&(a=a());for(var a=Blockly.Tooltip.wrap_(a,Blockly.Tooltip.LIMIT),a=a.split("\n"),b=0;bb.height&&(d-=Blockly.Tooltip.DIV.offsetHeight+2*Blockly.Tooltip.OFFSET_Y);a?c=Math.max(Blockly.Tooltip.MARGINS,c):c+Blockly.Tooltip.DIV.offsetWidth>b.width-2*Blockly.Tooltip.MARGINS&&(c=b.width-Blockly.Tooltip.DIV.offsetWidth-2*Blockly.Tooltip.MARGINS); +Blockly.Tooltip.DIV.style.top=d+"px";Blockly.Tooltip.DIV.style.left=c+"px"}};Blockly.Tooltip.wrap_=function(a,b){if(a.length<=b)return a;for(var c=a.trim().split(/\s+/),d=0;db&&(b=c[d].length);var e,d=-Infinity,f,g=1;do{e=d;f=a;for(var h=[],k=c.length/g,l=1,d=0;de);return f}; Blockly.Tooltip.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.Tooltip.wrapMutate_(a,e,c):b};Blockly.Tooltip.wrapToText_=function(a,b){for(var c=[],d=0;d=c+d&&(e+=f);this.svgKnob_.setAttribute(this.horizontal_?"x":"y",this.constrainKnob_(e));this.onScroll_()}a.stopPropagation()}; -Blockly.Scrollbar.prototype.onMouseDownKnob_=function(a){this.onMouseUpKnob_();Blockly.isRightButton(a)||(this.startDragKnob=parseFloat(this.svgKnob_.getAttribute(this.horizontal_?"x":"y")),this.startDragMouse=this.horizontal_?a.clientX:a.clientY,Blockly.Scrollbar.onMouseUpWrapper_=Blockly.bindEvent_(document,"mouseup",this,this.onMouseUpKnob_),Blockly.Scrollbar.onMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",this,this.onMouseMoveKnob_));a.stopPropagation()}; +Blockly.Scrollbar.prototype.onMouseDownBar_=function(a){this.onMouseUpKnob_();if(!Blockly.isRightButton(a)){var b=Blockly.mouseToSvg(a,this.workspace_.options.svg),b=this.horizontal_?b.x:b.y,c=Blockly.getSvgXY_(this.svgKnob_),c=this.horizontal_?c.x:c.y,d=parseFloat(this.svgKnob_.getAttribute(this.horizontal_?"width":"height")),e=parseFloat(this.svgKnob_.getAttribute(this.horizontal_?"x":"y")),f=.95*d;b<=c?e-=f:b>=c+d&&(e+=f);this.svgKnob_.setAttribute(this.horizontal_?"x":"y",this.constrainKnob_(e)); +this.onScroll_()}a.stopPropagation()};Blockly.Scrollbar.prototype.onMouseDownKnob_=function(a){this.onMouseUpKnob_();Blockly.isRightButton(a)||(this.startDragKnob=parseFloat(this.svgKnob_.getAttribute(this.horizontal_?"x":"y")),this.startDragMouse=this.horizontal_?a.clientX:a.clientY,Blockly.Scrollbar.onMouseUpWrapper_=Blockly.bindEvent_(document,"mouseup",this,this.onMouseUpKnob_),Blockly.Scrollbar.onMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",this,this.onMouseMoveKnob_));a.stopPropagation()}; Blockly.Scrollbar.prototype.onMouseMoveKnob_=function(a){this.svgKnob_.setAttribute(this.horizontal_?"x":"y",this.constrainKnob_(this.startDragKnob+((this.horizontal_?a.clientX:a.clientY)-this.startDragMouse)));this.onScroll_()}; Blockly.Scrollbar.prototype.onMouseUpKnob_=function(){Blockly.removeAllRanges();Blockly.hideChaff(!0);Blockly.Scrollbar.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Scrollbar.onMouseUpWrapper_),Blockly.Scrollbar.onMouseUpWrapper_=null);Blockly.Scrollbar.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Scrollbar.onMouseMoveWrapper_),Blockly.Scrollbar.onMouseMoveWrapper_=null)}; Blockly.Scrollbar.prototype.constrainKnob_=function(a){if(0>=a||isNaN(a))a=0;else{var b=this.horizontal_?"width":"height",c=parseFloat(this.svgBackground_.getAttribute(b)),b=parseFloat(this.svgKnob_.getAttribute(b));a=Math.min(a,c-b)}return a}; @@ -965,74 +966,83 @@ Blockly.Scrollbar.insertAfter_=function(a,b){var c=b.nextSibling,d=b.parentNode; Blockly.Trashcan=function(a){this.workspace_=a};Blockly.Trashcan.prototype.SPRITE_URL_="media/sprites.png";Blockly.Trashcan.prototype.LID_URL_="media/trashlid.png";Blockly.Trashcan.prototype.WIDTH_=47;Blockly.Trashcan.prototype.BODY_HEIGHT_=45;Blockly.Trashcan.prototype.LID_HEIGHT_=15;Blockly.Trashcan.prototype.MARGIN_BOTTOM_=35;Blockly.Trashcan.prototype.MARGIN_SIDE_=35;Blockly.Trashcan.prototype.MARGIN_HOTSPOT_=25;Blockly.Trashcan.prototype.isOpen=!1;Blockly.Trashcan.prototype.svgGroup_=null; Blockly.Trashcan.prototype.svgLid_=null;Blockly.Trashcan.prototype.lidTask_=0;Blockly.Trashcan.prototype.lidOpen_=0;Blockly.Trashcan.prototype.left_=0;Blockly.Trashcan.prototype.top_=0; Blockly.Trashcan.prototype.createDom=function(){this.svgGroup_=Blockly.createSvgElement("g",{},null);var a=Blockly.createSvgElement("clipPath",{id:"blocklyTrashBodyClipPath"},this.svgGroup_);Blockly.createSvgElement("rect",{width:this.WIDTH_,height:this.BODY_HEIGHT_,y:this.LID_HEIGHT_},a);Blockly.createSvgElement("image",{width:Blockly.SPRITE.width,height:Blockly.SPRITE.height,y:-32,"clip-path":"url(#blocklyTrashBodyClipPath)"},this.svgGroup_).setAttributeNS("http://www.w3.org/1999/xlink","xlink:href", -Blockly.pathToMedia+Blockly.SPRITE.url);a=Blockly.createSvgElement("clipPath",{id:"blocklyTrashLidClipPath"},this.svgGroup_);Blockly.createSvgElement("rect",{width:this.WIDTH_,height:this.LID_HEIGHT_},a);this.svgLid_=Blockly.createSvgElement("image",{width:Blockly.SPRITE.width,height:Blockly.SPRITE.height,y:-32,"clip-path":"url(#blocklyTrashLidClipPath)"},this.svgGroup_);this.svgLid_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",Blockly.pathToMedia+Blockly.SPRITE.url);this.animateLid_(); -return this.svgGroup_};Blockly.Trashcan.prototype.init=function(){this.setOpen_(!1);this.position_();Blockly.bindEvent_(window,"resize",this,this.position_)};Blockly.Trashcan.prototype.dispose=function(){this.svgGroup_&&(goog.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.workspace_=this.svgLid_=null;goog.Timer.clear(this.lidTask_)}; -Blockly.Trashcan.prototype.position_=function(){var a=this.workspace_.getMetrics();a&&(this.left_=Blockly.RTL?this.MARGIN_SIDE_:a.viewWidth+a.absoluteLeft-this.WIDTH_-this.MARGIN_SIDE_,this.top_=a.viewHeight+a.absoluteTop-(this.BODY_HEIGHT_+this.LID_HEIGHT_)-this.MARGIN_BOTTOM_,this.svgGroup_.setAttribute("transform","translate("+this.left_+","+this.top_+")"))}; +this.workspace_.options.pathToMedia+Blockly.SPRITE.url);a=Blockly.createSvgElement("clipPath",{id:"blocklyTrashLidClipPath"},this.svgGroup_);Blockly.createSvgElement("rect",{width:this.WIDTH_,height:this.LID_HEIGHT_},a);this.svgLid_=Blockly.createSvgElement("image",{width:Blockly.SPRITE.width,height:Blockly.SPRITE.height,y:-32,"clip-path":"url(#blocklyTrashLidClipPath)"},this.svgGroup_);this.svgLid_.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",this.workspace_.options.pathToMedia+Blockly.SPRITE.url); +this.animateLid_();return this.svgGroup_};Blockly.Trashcan.prototype.init=function(){this.setOpen_(!1);Blockly.bindEvent_(window,"resize",this,this.position_)};Blockly.Trashcan.prototype.dispose=function(){this.svgGroup_&&(goog.dom.removeNode(this.svgGroup_),this.svgGroup_=null);this.workspace_=this.svgLid_=null;goog.Timer.clear(this.lidTask_)}; +Blockly.Trashcan.prototype.position_=function(){var a=this.workspace_.getMetrics();a&&(this.left_=this.workspace_.RTL?this.MARGIN_SIDE_:a.viewWidth+a.absoluteLeft-this.WIDTH_-this.MARGIN_SIDE_,this.top_=a.viewHeight+a.absoluteTop-(this.BODY_HEIGHT_+this.LID_HEIGHT_)-this.MARGIN_BOTTOM_,this.svgGroup_.setAttribute("transform","translate("+this.left_+","+this.top_+")"))}; Blockly.Trashcan.prototype.getRect=function(){var a=Blockly.getSvgXY_(this.svgGroup_);return new goog.math.Rect(a.x-this.MARGIN_HOTSPOT_,a.y-this.MARGIN_HOTSPOT_,this.WIDTH_+2*this.MARGIN_HOTSPOT_,this.BODY_HEIGHT_+this.LID_HEIGHT_+2*this.MARGIN_HOTSPOT_)};Blockly.Trashcan.prototype.setOpen_=function(a){this.isOpen!=a&&(goog.Timer.clear(this.lidTask_),this.isOpen=a,this.animateLid_())}; -Blockly.Trashcan.prototype.animateLid_=function(){this.lidOpen_+=this.isOpen?.2:-.2;this.lidOpen_=goog.math.clamp(this.lidOpen_,0,1);var a=45*this.lidOpen_;this.svgLid_.setAttribute("transform","rotate("+(Blockly.RTL?-a:a)+", "+(Blockly.RTL?4:this.WIDTH_-4)+", "+(this.LID_HEIGHT_-2)+")");a=goog.math.lerp(.4,.8,this.lidOpen_);this.svgGroup_.style.opacity=a;0this.lidOpen_&&(this.lidTask_=goog.Timer.callOnce(this.animateLid_,20,this))};Blockly.Trashcan.prototype.close=function(){this.setOpen_(!1)}; +Blockly.Trashcan.prototype.animateLid_=function(){this.lidOpen_+=this.isOpen?.2:-.2;this.lidOpen_=goog.math.clamp(this.lidOpen_,0,1);var a=45*this.lidOpen_;this.svgLid_.setAttribute("transform","rotate("+(this.workspace_.RTL?-a:a)+", "+(this.workspace_.RTL?4:this.WIDTH_-4)+", "+(this.LID_HEIGHT_-2)+")");a=goog.math.lerp(.4,.8,this.lidOpen_);this.svgGroup_.style.opacity=a;0this.lidOpen_&&(this.lidTask_=goog.Timer.callOnce(this.animateLid_,20,this))}; +Blockly.Trashcan.prototype.close=function(){this.setOpen_(!1)}; // Copyright 2012 Google Inc. Apache License 2.0 -Blockly.Xml={};Blockly.Xml.workspaceToDom=function(a){var b;Blockly.RTL&&(b=a.getWidth());var c=goog.dom.createDom("xml");a=a.getTopBlocks(!0);for(var d=0,e;e=a[d];d++){var f=Blockly.Xml.blockToDom_(e);e=e.getRelativeToSurfaceXY();f.setAttribute("x",Blockly.RTL?b-e.x:e.x);f.setAttribute("y",e.y);c.appendChild(f)}return c}; +Blockly.Xml={};Blockly.Xml.workspaceToDom=function(a){var b;a.RTL&&(b=a.getWidth());for(var c=goog.dom.createDom("xml"),d=a.getTopBlocks(!0),e=0,f;f=d[e];e++){var g=Blockly.Xml.blockToDom_(f);f=f.getRelativeToSurfaceXY();g.setAttribute("x",a.RTL?b-f.x:f.x);g.setAttribute("y",f.y);c.appendChild(g)}return c}; Blockly.Xml.blockToDom_=function(a){var b=goog.dom.createDom("block");b.setAttribute("type",a.type);b.setAttribute("id",a.id);if(a.mutationToDom){var c=a.mutationToDom();c&&b.appendChild(c)}for(var c=0,d;d=a.inputList[c];c++)for(var e=0,f;f=d.fieldRow[e];e++)if(f.name&&f.EDITABLE){var g=goog.dom.createDom("field",null,f.getValue());g.setAttribute("name",f.name);b.appendChild(g)}if(c=a.getCommentText())c=goog.dom.createDom("comment",null,c),"object"==typeof a.comment&&(c.setAttribute("pinned",a.comment.isVisible()), d=a.comment.getBubbleSize(),c.setAttribute("h",d.height),c.setAttribute("w",d.width)),b.appendChild(c);a.data&&(c=goog.dom.createDom("data",null,a.data),b.appendChild(c));e=!1;for(c=0;d=a.inputList[c];c++){var h;f=!0;d.type!=Blockly.DUMMY_INPUT&&(g=d.connection.targetBlock(),d.type==Blockly.INPUT_VALUE?(h=goog.dom.createDom("value"),e=!0):d.type==Blockly.NEXT_STATEMENT&&(h=goog.dom.createDom("statement")),g&&(h.appendChild(Blockly.Xml.blockToDom_(g)),f=!1),h.setAttribute("name",d.name),f||b.appendChild(h))}e&& b.setAttribute("inline",a.inputsInline);a.isCollapsed()&&b.setAttribute("collapsed",!0);a.disabled&&b.setAttribute("disabled",!0);a.isDeletable()||b.setAttribute("deletable",!1);a.isMovable()||b.setAttribute("movable",!1);a.isEditable()||b.setAttribute("editable",!1);if(a=a.getNextBlock())h=goog.dom.createDom("next",null,Blockly.Xml.blockToDom_(a)),b.appendChild(h);return b};Blockly.Xml.domToText=function(a){return(new XMLSerializer).serializeToString(a)}; Blockly.Xml.domToPrettyText=function(a){a=Blockly.Xml.domToText(a).split("<");for(var b="",c=1;c"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=(new DOMParser).parseFromString(a,"text/xml");if(!a||!a.firstChild||"xml"!=a.firstChild.nodeName.toLowerCase()||a.firstChild!==a.lastChild)throw"Blockly.Xml.textToDom did not obtain a valid XML tree.";return a.firstChild}; -Blockly.Xml.domToWorkspace=function(a,b){var c;Blockly.RTL&&(c=a.getWidth());for(var d=b.childNodes.length,e=0;e=this.remainingCapacity())){var b=Blockly.Xml.domToBlock(this,a),c=parseInt(a.getAttribute("x"),10);a=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(a)){Blockly.RTL&&(c=-c);do for(var d=!1,e=this.getAllBlocks(),f=0,g;g=e[f];f++)g=g.getRelativeToSurfaceXY(),1>=Math.abs(c-g.x)&&1>=Math.abs(a-g.y)&&(c=Blockly.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,a+=2*Blockly.SNAP_RADIUS,d=!0);while(d);b.moveBy(c, -a)}b.select()}};Blockly.WorkspaceSvg.prototype.recordDeleteAreas=function(){this.deleteAreaTrash_=this.trashcan?this.trashcan.getRect():null;this.deleteAreaToolbox_=this.flyout_?this.flyout_.getRect():this.toolbox_?this.toolbox_.getRect():null}; -Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){a=Blockly.mouseToSvg(a);a=new goog.math.Coordinate(a.x,a.y);if(this.deleteAreaTrash_){if(this.deleteAreaTrash_.contains(a))return this.trashcan.setOpen_(!0),Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;this.trashcan.setOpen_(!1)}if(this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a))return Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);return!1}; -Blockly.WorkspaceSvg.prototype.clear=Blockly.WorkspaceSvg.prototype.clear; +Blockly.WorkspaceSvg.prototype.paste=function(a){if(this.rendered&&!(a.getElementsByTagName("block").length>=this.remainingCapacity())){Blockly.terminateDrag_();var b=Blockly.Xml.domToBlock(this,a),c=parseInt(a.getAttribute("x"),10);a=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(a)){this.RTL&&(c=-c);do for(var d=!1,e=this.getAllBlocks(),f=0,g;g=e[f];f++)g=g.getRelativeToSurfaceXY(),1>=Math.abs(c-g.x)&&1>=Math.abs(a-g.y)&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,a+=2*Blockly.SNAP_RADIUS, +d=!0);while(d);b.moveBy(c,a)}b.select()}};Blockly.WorkspaceSvg.prototype.recordDeleteAreas=function(){this.deleteAreaTrash_=this.trashcan?this.trashcan.getRect():null;this.deleteAreaToolbox_=this.flyout_?this.flyout_.getRect():this.toolbox_?this.toolbox_.getRect():null}; +Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){a=Blockly.mouseToSvg(a,this.options.svg);a=new goog.math.Coordinate(a.x,a.y);if(this.deleteAreaTrash_){if(this.deleteAreaTrash_.contains(a))return this.trashcan.setOpen_(!0),Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;this.trashcan.setOpen_(!1)}if(this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a))return Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);return!1}; +Blockly.WorkspaceSvg.prototype.onMouseDown_=function(a){this.markFocused();Blockly.isTargetInput_(a)||(Blockly.svgResize(this),Blockly.terminateDrag_(),Blockly.hideChaff(),a.target&&a.target.nodeName&&("svg"==a.target.nodeName.toLowerCase()||a.target==this.svgBackground_)&&Blockly.selected&&!this.options.readOnly&&Blockly.selected.unselect(),Blockly.isRightButton(a)?this.showContextMenu_(a):this.scrollbar&&(Blockly.removeAllRanges(),this.isScrolling=!0,this.startDragMouseX=a.clientX,this.startDragMouseY= +a.clientY,this.startDragMetrics=this.getMetrics(),this.startScrollX=this.scrollX,this.startScrollY=this.scrollY,"mouseup"in Blockly.bindEvent_.TOUCH_MAP&&(Blockly.onTouchUpWrapper_=Blockly.bindEvent_(document,"mouseup",null,Blockly.onMouseUp_)),Blockly.onMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",null,Blockly.onMouseMove_)),a.stopPropagation())}; +Blockly.WorkspaceSvg.prototype.showContextMenu_=function(a){if(!this.options.readOnly){var b=[];if(this.options.collapse){for(var c=!1,d=!1,e=this.getTopBlocks(!1),f=0;fa||Math.abs(this.workspaceHeight_-b)>a)this.workspaceWidth_=d,this.workspaceHeight_=b,this.bubble_.setBubbleSize(d+a,b+a),this.svgDialog_.setAttribute("width",this.workspaceWidth_),this.svgDialog_.setAttribute("height", -this.workspaceHeight_);Blockly.RTL&&(a="translate("+this.workspaceWidth_+",0)",this.workspace_.getCanvas().setAttribute("transform",a))}; -Blockly.Mutator.prototype.setVisible=function(a){if(a!=this.isVisible())if(a){this.bubble_=new Blockly.Bubble(this.block_.workspace,this.createEditor_(),this.block_.svgPath_,this.iconX_,this.iconY_,null,null);var b=this;this.workspace_.flyout_.init(this.workspace_);var c=[];a=0;for(var d;d=this.quarkNames_[a];a++)c[a]=goog.dom.createDom("block",{type:d});this.workspace_.flyout_.show(c);this.rootBlock_=this.block_.decompose(this.workspace_);c=this.rootBlock_.getDescendants();for(a=0;d=c[a];a++)d.render(); -this.rootBlock_.setMovable(!1);this.rootBlock_.setDeletable(!1);a=2*this.workspace_.flyout_.CORNER_RADIUS;c=this.workspace_.flyout_.width_+a;Blockly.RTL&&(c=-c);this.rootBlock_.moveBy(c,a);this.block_.saveConnections&&(this.block_.saveConnections(this.rootBlock_),this.sourceListener_=Blockly.bindEvent_(this.block_.workspace.getCanvas(),"blocklyWorkspaceChange",this.block_,function(){b.block_.saveConnections(b.rootBlock_)}));this.resizeBubble_();Blockly.bindEvent_(this.workspace_.getCanvas(),"blocklyWorkspaceChange", -this.block_,function(){b.workspaceChanged_()});this.updateColour()}else this.svgDialog_=null,this.workspace_.dispose(),this.rootBlock_=this.workspace_=null,this.bubble_.dispose(),this.bubble_=null,this.workspaceHeight_=this.workspaceWidth_=0,this.sourceListener_&&(Blockly.unbindEvent_(this.sourceListener_),this.sourceListener_=null)}; +Blockly.Mutator.prototype.createEditor_=function(){this.svgDialog_=Blockly.createSvgElement("svg",{x:Blockly.Bubble.BORDER_WIDTH,y:Blockly.Bubble.BORDER_WIDTH},null);for(var a=goog.dom.createDom("xml"),b=0,c;c=this.quarkNames_[b];b++)a.appendChild(goog.dom.createDom("block",{type:c}));var d=this;this.workspace_=new Blockly.WorkspaceSvg({languageTree:a,parentWorkspace:this.block_.workspace,RTL:this.block_.RTL,getMetrics:function(){return d.getFlyoutMetrics_()},setMetrics:null,svg:this.svgDialog_}); +this.svgDialog_.appendChild(this.workspace_.createDom("blocklyMutatorBackground"));return this.svgDialog_};Blockly.Mutator.prototype.updateEditable=function(){this.block_.isEditable()?Blockly.Icon.prototype.updateEditable.call(this):(this.setVisible(!1),this.iconGroup_&&Blockly.addClass_(this.iconGroup_,"blocklyIconGroupReadonly"))}; +Blockly.Mutator.prototype.resizeBubble_=function(){var a=2*Blockly.Bubble.BORDER_WIDTH,b=this.workspace_.getCanvas().getBBox(),c=this.workspace_.flyout_.getMetrics_(),d;d=this.block_.RTL?-b.x:b.width+b.x;b=Math.max(b.height+3*a,c.contentHeight+20);d+=3*a;if(Math.abs(this.workspaceWidth_-d)>a||Math.abs(this.workspaceHeight_-b)>a)this.workspaceWidth_=d,this.workspaceHeight_=b,this.bubble_.setBubbleSize(d+a,b+a),this.svgDialog_.setAttribute("width",this.workspaceWidth_),this.svgDialog_.setAttribute("height", +this.workspaceHeight_);this.block_.RTL&&(a="translate("+this.workspaceWidth_+",0)",this.workspace_.getCanvas().setAttribute("transform",a))}; +Blockly.Mutator.prototype.setVisible=function(a){if(a!=this.isVisible())if(a){this.bubble_=new Blockly.Bubble(this.block_.workspace,this.createEditor_(),this.block_.svgPath_,this.iconX_,this.iconY_,null,null);var b=this;this.workspace_.flyout_.init(this.workspace_);this.workspace_.flyout_.show(this.workspace_.options.languageTree.childNodes);this.rootBlock_=this.block_.decompose(this.workspace_);a=this.rootBlock_.getDescendants();for(var c=0,d;d=a[c];c++)d.render();this.rootBlock_.setMovable(!1); +this.rootBlock_.setDeletable(!1);a=2*this.workspace_.flyout_.CORNER_RADIUS;c=this.workspace_.flyout_.width_+a;this.block_.RTL&&(c=-c);this.rootBlock_.moveBy(c,a);this.block_.saveConnections&&(this.block_.saveConnections(this.rootBlock_),this.sourceListener_=Blockly.bindEvent_(this.block_.workspace.getCanvas(),"blocklyWorkspaceChange",this.block_,function(){b.block_.saveConnections(b.rootBlock_)}));this.resizeBubble_();Blockly.bindEvent_(this.workspace_.getCanvas(),"blocklyWorkspaceChange",this.block_, +function(){b.workspaceChanged_()});this.updateColour()}else this.svgDialog_=null,this.workspace_.dispose(),this.rootBlock_=this.workspace_=null,this.bubble_.dispose(),this.bubble_=null,this.workspaceHeight_=this.workspaceWidth_=0,this.sourceListener_&&(Blockly.unbindEvent_(this.sourceListener_),this.sourceListener_=null)}; Blockly.Mutator.prototype.workspaceChanged_=function(){if(0==Blockly.dragMode_)for(var a=this.workspace_.getTopBlocks(!1),b=0,c;c=a[b];b++){var d=c.getRelativeToSurfaceXY(),e=c.getHeightWidth();20>d.y+e.height&&c.moveBy(0,20-e.height-d.y)}this.rootBlock_.workspace==this.workspace_&&(a=this.block_.rendered,this.block_.rendered=!1,this.block_.compose(this.rootBlock_),this.block_.rendered=a,this.block_.initSvg(),this.block_.rendered&&this.block_.render(),this.resizeBubble_(),this.block_.workspace.fireChangeEvent(), -goog.Timer.callOnce(this.block_.bumpNeighbours_,Blockly.BUMP_DELAY,this.block_))};Blockly.Mutator.prototype.getFlyoutMetrics_=function(){var a=0;Blockly.RTL&&(a+=this.workspaceWidth_);return{viewHeight:this.workspaceHeight_,viewWidth:0,absoluteTop:0,absoluteLeft:a}};Blockly.Mutator.prototype.dispose=function(){this.block_.mutator=null;Blockly.Icon.prototype.dispose.call(this)}; +goog.Timer.callOnce(this.block_.bumpNeighbours_,Blockly.BUMP_DELAY,this.block_))};Blockly.Mutator.prototype.getFlyoutMetrics_=function(){var a=0;this.block_.RTL&&(a+=this.workspaceWidth_);return{viewHeight:this.workspaceHeight_,viewWidth:0,absoluteTop:0,absoluteLeft:a}};Blockly.Mutator.prototype.dispose=function(){this.block_.mutator=null;Blockly.Icon.prototype.dispose.call(this)}; // Copyright 2012 Google Inc. Apache License 2.0 Blockly.Warning=function(a){Blockly.Warning.superClass_.constructor.call(this,a);this.createIcon()};goog.inherits(Blockly.Warning,Blockly.Icon);Blockly.Warning.prototype.png_="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAANyAAADcgBffIlqAAAAAd0SU1FB98DGgApDBpIGrEAAAGfSURBVDjLnZM9S2NREIbfc2P8AF27BXshpIzK5g9ssUj8C2tnYyUoiBGSyk4sbCLs1vkRgoW1jYWFICwsMV2Se3JPboLe+FhcNCZcjXFgOMzHeec9M2ekDwTIAEUgo68IsOQczdNTIudoAksTg/g+5+UyDxKUyzz4PueTsvhZr+NmZkCC6Wmo1QiAX58FmLKWf4VCDPCiGxtgLf+B9FiQXo+9y0ucBIUCnJ3B+noMdHGBC0P2xrH4HoYEmUx8qVQCgMPD2F5ehjDEjTbZe2s4p5NKRenb2+Qid3dSpaK0tTp+j8VKq0VncXHQh2IxZrK/P/AtLECjQQf4McQEMNbq786O5qwdANfr8Xl/P/AFgbS7qzlr9Qcwr4EoYvPmBud5wxPJ5+HqCtbWhv3GwPU1Lor4/fKMeedo5vPDiRKsrsLWFuRyybFOhxbwTd0upWqVcDQpaTqjWq0SdruU5PvUkiol/ZNRzeXA96mp3aaRzSYnjdNsFtptGiYI2PY8HaVSmu33xWf3K5WS6ffVe3rSgXnzT+YlpSfY00djjJOkZ/wpr41bQMIsAAAAAElFTkSuQmCC"; Blockly.Warning.textToDom_=function(a){var b=Blockly.createSvgElement("text",{"class":"blocklyText blocklyBubbleText",y:Blockly.Bubble.BORDER_WIDTH},null);a=a.split("\n");for(var c=0;c=e.height&&(k-=h.height);Blockly.RTL?h.width>=a.clientX&&(d+=h.width):a.clientX+h.width>=e.width&&(d-=h.width);Blockly.WidgetDiv.position(d,k,e,f);c.setAllowAutoFocus(!0);setTimeout(function(){g.focus()},1);Blockly.ContextMenu.currentBlock=null}else Blockly.ContextMenu.hide()}; -Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null};Blockly.ContextMenu.callbackFactory=function(a,b){return function(){var c=Blockly.Xml.domToBlock(a.workspace,b),d=a.getRelativeToSurfaceXY();d.x=Blockly.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y);c.select()}}; +Blockly.ContextMenu.show=function(a,b,c){Blockly.WidgetDiv.show(Blockly.ContextMenu,c,null);if(b.length){var d=new goog.ui.Menu;d.setRightToLeft(c);for(var e=0,f;f=b[e];e++){var g=new goog.ui.MenuItem(f.text);g.setRightToLeft(c);d.addChild(g,!0);g.setEnabled(f.enabled);f.enabled&&goog.events.listen(g,goog.ui.Component.EventType.ACTION,function(a){return function(){Blockly.doCommand(a)}}(f.callback))}goog.events.listen(d,goog.ui.Component.EventType.ACTION,Blockly.ContextMenu.hide);b=goog.dom.getViewportSize(); +f=goog.style.getViewportPageOffset(document);d.render(Blockly.WidgetDiv.DIV);var h=d.getElement();Blockly.addClass_(h,"blocklyContextMenu");var g=goog.style.getSize(h),e=a.clientX+f.x,k=a.clientY+f.y;a.clientY+g.height>=b.height&&(k-=g.height);c?g.width>=a.clientX&&(e+=g.width):a.clientX+g.width>=b.width&&(e-=g.width);Blockly.WidgetDiv.position(e,k,b,f,c);d.setAllowAutoFocus(!0);setTimeout(function(){h.focus()},1);Blockly.ContextMenu.currentBlock=null}else Blockly.ContextMenu.hide()}; +Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null};Blockly.ContextMenu.callbackFactory=function(a,b){return function(){var c=Blockly.Xml.domToBlock(a.workspace,b),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);c.select()}}; // Copyright 2012 Google Inc. Apache License 2.0 -Blockly.BlockSvg=function(){this.svgGroup_=Blockly.createSvgElement("g",{},null);this.svgPathDark_=Blockly.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1, 1)"},this.svgGroup_);this.svgPath_=Blockly.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;Blockly.Tooltip.bindMouseEvents(this.svgPath_);this.updateMovable()}; -goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.INLINE=-1; -Blockly.BlockSvg.prototype.initSvg=function(){goog.asserts.assert(this.workspace.rendered,"Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();this.mutator&&this.mutator.createIcon();this.updateColour();if(!Blockly.readOnly&&!this.eventsInit_){Blockly.bindEvent_(this.getSvgRoot(),"mousedown",this,this.onMouseDown_);var c=this;Blockly.bindEvent_(this.getSvgRoot(),"touchstart",null,function(a){Blockly.longStart_(a,c)})}goog.isFunction(this.onchange)&&!this.eventsInit_&&Blockly.bindEvent_(this.workspace.getCanvas(), -"blocklyWorkspaceChange",this,this.onchange);this.eventsInit_=!0;this.getSvgRoot().parentNode||this.workspace.getCanvas().appendChild(this.getSvgRoot())};Blockly.BlockSvg.prototype.select=function(){Blockly.selected&&Blockly.selected.unselect();Blockly.selected=this;this.addSelect();Blockly.fireUiEvent(this.workspace.getCanvas(),"blocklySelectChange")};Blockly.BlockSvg.prototype.unselect=function(){Blockly.selected=null;this.removeSelect();Blockly.fireUiEvent(this.workspace.getCanvas(),"blocklySelectChange")}; -Blockly.BlockSvg.prototype.mutator=null;Blockly.BlockSvg.prototype.comment=null;Blockly.BlockSvg.prototype.warning=null;Blockly.BlockSvg.prototype.getIcons=function(){var a=[];this.mutator&&a.push(this.mutator);this.comment&&a.push(this.comment);this.warning&&a.push(this.warning);return a};Blockly.BlockSvg.onMouseUpWrapper_=null;Blockly.BlockSvg.onMouseMoveWrapper_=null; +Blockly.BlockSvg=function(){this.svgGroup_=Blockly.createSvgElement("g",{},null);this.svgPathDark_=Blockly.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1, 1)"},this.svgGroup_);this.svgPath_=Blockly.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;Blockly.Tooltip.bindMouseEvents(this.svgPath_)};goog.inherits(Blockly.BlockSvg,Blockly.Block); +Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.INLINE=-1; +Blockly.BlockSvg.prototype.initSvg=function(){goog.asserts.assert(this.workspace.rendered,"Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();this.mutator&&this.mutator.createIcon();this.updateColour();this.updateMovable();if(!this.workspace.options.readOnly&&!this.eventsInit_){Blockly.bindEvent_(this.getSvgRoot(),"mousedown",this,this.onMouseDown_);var c=this;Blockly.bindEvent_(this.getSvgRoot(),"touchstart",null,function(a){Blockly.longStart_(a,c)})}goog.isFunction(this.onchange)&& +!this.eventsInit_&&Blockly.bindEvent_(this.workspace.getCanvas(),"blocklyWorkspaceChange",this,this.onchange);this.eventsInit_=!0;this.getSvgRoot().parentNode||this.workspace.getCanvas().appendChild(this.getSvgRoot())};Blockly.BlockSvg.prototype.select=function(){Blockly.selected&&Blockly.selected.unselect();Blockly.selected=this;this.addSelect();Blockly.fireUiEvent(this.workspace.getCanvas(),"blocklySelectChange")}; +Blockly.BlockSvg.prototype.unselect=function(){Blockly.selected=null;this.removeSelect();Blockly.fireUiEvent(this.workspace.getCanvas(),"blocklySelectChange")};Blockly.BlockSvg.prototype.mutator=null;Blockly.BlockSvg.prototype.comment=null;Blockly.BlockSvg.prototype.warning=null;Blockly.BlockSvg.prototype.getIcons=function(){var a=[];this.mutator&&a.push(this.mutator);this.comment&&a.push(this.comment);this.warning&&a.push(this.warning);return a};Blockly.BlockSvg.onMouseUpWrapper_=null; +Blockly.BlockSvg.onMouseMoveWrapper_=null; Blockly.BlockSvg.terminateDrag_=function(){Blockly.BlockSvg.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.BlockSvg.onMouseUpWrapper_),Blockly.BlockSvg.onMouseUpWrapper_=null);Blockly.BlockSvg.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.BlockSvg.onMouseMoveWrapper_),Blockly.BlockSvg.onMouseMoveWrapper_=null);var a=Blockly.selected;if(2==Blockly.dragMode_&&a){var b=a.getRelativeToSurfaceXY();a.moveConnections_(b.x-a.startDragX,b.y-a.startDragY);delete a.draggedBubbles_;a.setDragging_(!1); -a.render();Blockly.gridOptions.snap&&a.workspace==Blockly.mainWorkspace&&goog.Timer.callOnce(a.snapToGrid_,Blockly.BUMP_DELAY/2,a);goog.Timer.callOnce(a.bumpNeighbours_,Blockly.BUMP_DELAY,a);Blockly.fireUiEvent(window,"resize");a.workspace.fireChangeEvent()}Blockly.dragMode_=0;Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN)}; +a.render();a.workspace&&a.workspace.options.gridOptions&&a.workspace.options.gridOptions.snap&&goog.Timer.callOnce(a.snapToGrid_,Blockly.BUMP_DELAY/2,a);goog.Timer.callOnce(a.bumpNeighbours_,Blockly.BUMP_DELAY,a);Blockly.fireUiEvent(window,"resize");a.workspace.fireChangeEvent()}Blockly.dragMode_=0;Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN)}; Blockly.BlockSvg.prototype.setParent=function(a){var b=this.getSvgRoot();if(this.parentBlock_&&b){var c=this.getRelativeToSurfaceXY();this.workspace.getCanvas().appendChild(b);b.setAttribute("transform","translate("+c.x+", "+c.y+")")}Blockly.BlockSvg.superClass_.setParent.call(this,a);a&&(c=this.getRelativeToSurfaceXY(),a.getSvgRoot().appendChild(b),a=this.getRelativeToSurfaceXY(),this.moveConnections_(a.x-c.x,a.y-c.y))}; Blockly.BlockSvg.prototype.getRelativeToSurfaceXY=function(){var a=0,b=0,c=this.getSvgRoot();if(c){do var d=Blockly.getRelativeXY_(c),a=a+d.x,b=b+d.y,c=c.parentNode;while(c&&c!=this.workspace.getCanvas())}return new goog.math.Coordinate(a,b)};Blockly.BlockSvg.prototype.moveBy=function(a,b){var c=this.getRelativeToSurfaceXY();this.getSvgRoot().setAttribute("transform","translate("+(c.x+a)+", "+(c.y+b)+")");this.moveConnections_(a,b);Blockly.Realtime.blockChanged(this)}; -Blockly.BlockSvg.prototype.snapToGrid_=function(){if(this.workspace&&0==Blockly.dragMode_&&!this.getParent()&&!this.isInFlyout){var a=Blockly.gridOptions.spacing,b=a/2,c=this.getRelativeToSurfaceXY(),d=Math.round((c.x-b)/a)*a+b-c.x,a=Math.round((c.y-b)/a)*a+b-c.y,d=Math.round(d),a=Math.round(a);0==d&&0==a||this.moveBy(d,a)}}; +Blockly.BlockSvg.prototype.snapToGrid_=function(){if(this.workspace&&0==Blockly.dragMode_&&!this.getParent()&&!this.isInFlyout){var a=this.workspace.options.gridOptions.spacing,b=a/2,c=this.getRelativeToSurfaceXY(),d=Math.round((c.x-b)/a)*a+b-c.x,a=Math.round((c.y-b)/a)*a+b-c.y,d=Math.round(d),a=Math.round(a);0==d&&0==a||this.moveBy(d,a)}}; 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));return{height:a,width:b}}; Blockly.BlockSvg.prototype.setCollapsed=function(a){if(this.collapsed_!=a){for(var b=[],c=0,d;d=this.inputList[c];c++)b.push.apply(b,d.setVisible(!a));if(a){d=this.getIcons();for(c=0;cthis.workspace.remainingCapacity()&&(d.enabled=!1);c.push(d);this.isEditable()&&!this.collapsed_&&Blockly.comments&&(d={enabled:!0},this.comment?(d.text=Blockly.Msg.REMOVE_COMMENT,d.callback=function(){b.setCommentText(null)}): -(d.text=Blockly.Msg.ADD_COMMENT,d.callback=function(){b.setCommentText("")}),c.push(d));if(!this.collapsed_)for(d=0;dthis.workspace.remainingCapacity()&&(d.enabled=!1);c.push(d);this.isEditable()&&!this.collapsed_&&this.workspace.options.comments&&(d={enabled:!0},this.comment?(d.text=Blockly.Msg.REMOVE_COMMENT,d.callback= +function(){b.setCommentText(null)}):(d.text=Blockly.Msg.ADD_COMMENT,d.callback=function(){b.setCommentText("")}),c.push(d));if(!this.collapsed_)for(d=0;d=a.clientX&&0==a.clientY&&0==a.button)){Blockly.removeAllRanges();var c=a.clientX-b.startDragMouseX,d=a.clientY-b.startDragMouseY;1==Blockly.dragMode_&&Math.sqrt(Math.pow(c,2)+Math.pow(d,2))>Blockly.DRAG_RADIUS&&(Blockly.dragMode_=2,Blockly.longStop_(),b.setParent(null),b.setDragging_(!0),b.workspace.recordDeleteAreas());if(2==Blockly.dragMode_){var e=b.startDragX+c,f=b.startDragY+ -d;b.getSvgRoot().setAttribute("transform","translate("+e+", "+f+")");for(e=0;ec;c+=15)Blockly.createSvgElement("line",{x1:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS,y1:Blockly.FieldAngle.HALF,x2:Blockly.FieldAngle.HALF+Blockly.FieldAngle.RADIUS- (0==c%45?10:5),y2:Blockly.FieldAngle.HALF,"class":"blocklyAngleMarks",transform:"rotate("+c+", "+Blockly.FieldAngle.HALF+", "+Blockly.FieldAngle.HALF+")"},a);a.style.marginLeft="-35px";this.clickWrapper_=Blockly.bindEvent_(a,"click",this,Blockly.WidgetDiv.hide);this.moveWrapper1_=Blockly.bindEvent_(b,"mousemove",this,this.onMouseMove);this.moveWrapper2_=Blockly.bindEvent_(this.gauge_,"mousemove",this,this.onMouseMove);this.updateGraph_()}}; Blockly.FieldAngle.prototype.onMouseMove=function(a){var b=this.gauge_.ownerSVGElement.getBoundingClientRect(),c=a.clientX-b.left-Blockly.FieldAngle.HALF;a=a.clientY-b.top-Blockly.FieldAngle.HALF;b=Math.atan(-a/c);isNaN(b)||(b=goog.math.toDegrees(b),0>c?b+=180:0Math.PI?1:0)+" 0 "+b+","+c+" z");this.line_.setAttribute("x2",b);this.line_.setAttribute("y2",c)}}};Blockly.FieldAngle.angleValidator=function(a){a=Blockly.FieldTextInput.numberValidator(a);null!==a&&(a%=360,0>a&&(a+=360),a=String(a));return a}; // Copyright 2012 Google Inc. Apache License 2.0 @@ -1153,18 +1164,18 @@ Blockly.FieldCheckbox.prototype.setValue=function(a){a="TRUE"==a;this.state_!==a Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,"\u00a0\u00a0\u00a0");this.changeHandler_=b;this.setValue(a);this.colours_=null;this.columns_=0};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.prototype.init=function(a){Blockly.FieldColour.superClass_.init.call(this,a);this.borderRect_.style.fillOpacity=1;this.setValue(this.getValue())};Blockly.FieldColour.prototype.clone=function(){return new Blockly.FieldColour(this.getValue(),this.changeHandler_)}; Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.getValue=function(){return this.colour_};Blockly.FieldColour.prototype.setValue=function(a){this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a);this.sourceBlock_&&this.sourceBlock_.rendered&&(Blockly.Realtime.blockChanged(this.sourceBlock_),this.sourceBlock_.workspace.fireChangeEvent())}; Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS=goog.ui.ColorPicker.SIMPLE_GRID_COLORS;Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function(a){this.colours_=a;return this};Blockly.FieldColour.prototype.setColumns=function(a){this.columns_=a;return this}; -Blockly.FieldColour.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,Blockly.FieldColour.widgetDispose_);var a=new goog.ui.ColorPicker;a.setSize(this.columns_||Blockly.FieldColour.COLUMNS);a.setColors(this.colours_||Blockly.FieldColour.COLOURS);var b=goog.dom.getViewportSize(),c=goog.style.getViewportPageOffset(document),d=Blockly.getAbsoluteXY_(this.borderRect_),e=this.borderRect_.getBBox();a.render(Blockly.WidgetDiv.DIV);a.setSelectedColor(this.getValue());var f=goog.style.getSize(a.getElement()); -d.y=d.y+f.height+e.height>=b.height+c.y?d.y-(f.height-1):d.y+(e.height-1);Blockly.RTL?(d.x+=e.width,d.x-=f.width,d.xb.width+c.x-f.width&&(d.x=b.width+c.x-f.width);Blockly.WidgetDiv.position(d.x,d.y,b,c);var g=this;Blockly.FieldColour.changeEventKey_=goog.events.listen(a,goog.ui.ColorPicker.EventType.CHANGE,function(a){a=a.target.getSelectedColor()||"#000000";Blockly.WidgetDiv.hide();if(g.sourceBlock_&&g.changeHandler_){var b=g.changeHandler_(a);void 0!==b&&(a=b)}null!==a&&g.setValue(a)})}; -Blockly.FieldColour.widgetDispose_=function(){Blockly.FieldColour.changeEventKey_&&goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_)}; +Blockly.FieldColour.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,Blockly.FieldColour.widgetDispose_);var a=new goog.ui.ColorPicker;a.setSize(this.columns_||Blockly.FieldColour.COLUMNS);a.setColors(this.colours_||Blockly.FieldColour.COLOURS);var b=goog.dom.getViewportSize(),c=goog.style.getViewportPageOffset(document),d=this.getAbsoluteXY_(),e=this.borderRect_.getBBox();a.render(Blockly.WidgetDiv.DIV);a.setSelectedColor(this.getValue());var f=goog.style.getSize(a.getElement()); +d.y=d.y+f.height+e.height>=b.height+c.y?d.y-(f.height-1):d.y+(e.height-1);this.sourceBlock_.RTL?(d.x+=e.width,d.x-=f.width,d.xb.width+c.x-f.width&&(d.x=b.width+c.x-f.width);Blockly.WidgetDiv.position(d.x,d.y,b,c,this.sourceBlock_.RTL);var g=this;Blockly.FieldColour.changeEventKey_=goog.events.listen(a,goog.ui.ColorPicker.EventType.CHANGE,function(a){a=a.target.getSelectedColor()||"#000000";Blockly.WidgetDiv.hide();if(g.sourceBlock_&&g.changeHandler_){var b=g.changeHandler_(a); +void 0!==b&&(a=b)}null!==a&&g.setValue(a)})};Blockly.FieldColour.widgetDispose_=function(){Blockly.FieldColour.changeEventKey_&&goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_)}; // Copyright 2012 Google Inc. Apache License 2.0 Blockly.FieldDropdown=function(a,b){this.menuGenerator_=a;this.changeHandler_=b;this.trimOptions_();var c=this.getOptions_()[0];this.value_=c[1];Blockly.FieldDropdown.superClass_.constructor.call(this,c[0])};goog.inherits(Blockly.FieldDropdown,Blockly.Field);Blockly.FieldDropdown.CHECKMARK_OVERHANG=25;Blockly.FieldDropdown.ARROW_CHAR=goog.userAgent.ANDROID?"\u25bc":"\u25be";Blockly.FieldDropdown.prototype.clone=function(){return new Blockly.FieldDropdown(this.menuGenerator_,this.changeHandler_)}; -Blockly.FieldDropdown.prototype.CURSOR="default";Blockly.FieldDropdown.prototype.init=function(a){this.sourceBlock_||(this.arrow_=Blockly.createSvgElement("tspan",{},null),this.arrow_.appendChild(document.createTextNode(Blockly.RTL?Blockly.FieldDropdown.ARROW_CHAR+" ":" "+Blockly.FieldDropdown.ARROW_CHAR)),Blockly.FieldDropdown.superClass_.init.call(this,a),a=this.text_,this.text_=null,this.setText(a))}; -Blockly.FieldDropdown.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,null);for(var a=this,b=new goog.ui.Menu,c=this.getOptions_(),d=0;d=c.height+d.y?e.y-h.height:e.y+f.height;Blockly.RTL?(e.x+=f.width,e.x+=Blockly.FieldDropdown.CHECKMARK_OVERHANG,e.xc.width+d.x-h.width&&(e.x=c.width+d.x-h.width));Blockly.WidgetDiv.position(e.x,e.y,c,d);b.setAllowAutoFocus(!0);g.focus()}; +Blockly.FieldDropdown.prototype.CURSOR="default";Blockly.FieldDropdown.prototype.init=function(a){this.sourceBlock_||(this.arrow_=Blockly.createSvgElement("tspan",{},null),this.arrow_.appendChild(document.createTextNode(a.RTL?Blockly.FieldDropdown.ARROW_CHAR+" ":" "+Blockly.FieldDropdown.ARROW_CHAR)),Blockly.FieldDropdown.superClass_.init.call(this,a),a=this.text_,this.text_=null,this.setText(a))}; +Blockly.FieldDropdown.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,null);for(var a=this,b=new goog.ui.Menu,c=this.getOptions_(),d=0;d=c.height+d.y?e.y-h.height:e.y+f.height;this.sourceBlock_.RTL?(e.x+=f.width,e.x+=Blockly.FieldDropdown.CHECKMARK_OVERHANG,e.xc.width+d.x-h.width&&(e.x=c.width+d.x-h.width));Blockly.WidgetDiv.position(e.x,e.y,c,d,this.sourceBlock_.RTL);b.setAllowAutoFocus(!0);g.focus()}; Blockly.FieldDropdown.prototype.trimOptions_=function(){this.suffixField=this.prefixField=null;var a=this.menuGenerator_;if(goog.isArray(a)&&!(2>a.length)){var b=a.map(function(a){return a[0]}),c=Blockly.shortestStringLength(b),d=Blockly.commonWordPrefix(b,c),e=Blockly.commonWordSuffix(b,c);if((d||e)&&!(c<=d+e)){d&&(this.prefixField=b[0].substring(0,d-1));e&&(this.suffixField=b[0].substr(1-e));b=[];for(c=0;cd?1:c=a.clientX&&0==a.clientY&&0==a.button)a.stopPropagation();else{Blockly.removeAllRanges();var b=a.clientY-Blockly.Flyout.startDownEvent_.clientY;Math.sqrt(Math.pow(a.clientX-Blockly.Flyout.startDownEvent_.clientX,2)+Math.pow(b,2))>Blockly.DRAG_RADIUS&&Blockly.Flyout.startFlyout_.createBlockFunc_(Blockly.Flyout.startBlock_)(Blockly.Flyout.startDownEvent_)}}; Blockly.Flyout.prototype.createBlockFunc_=function(a){var b=this;return function(c){if(!Blockly.isRightButton(c)&&!a.disabled){var d=Blockly.Xml.blockToDom_(a),d=Blockly.Xml.domToBlock(b.targetWorkspace_,d),e=a.getSvgRoot();if(!e)throw"originBlock is not rendered.";var e=Blockly.getSvgXY_(e),f=d.getSvgRoot();if(!f)throw"block is not rendered.";f=Blockly.getSvgXY_(f);d.moveBy(e.x-f.x,e.y-f.y);b.autoClose?b.hide():b.filterForCapacity_();d.onMouseDown_(c)}}}; -Blockly.Flyout.prototype.filterForCapacity_=function(){for(var a=this.targetWorkspace_.remainingCapacity(),b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getDescendants().length>a;d.setDisabled(e)}}; +Blockly.Flyout.prototype.filterForCapacity_=function(){for(var a=this.targetWorkspace_.remainingCapacity(),b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++){var e=d.getDescendants().length>a;d.setDisabled(e)}};Blockly.Flyout.prototype.getRect=function(){var a=Blockly.getSvgXY_(this.svgGroup_).x;this.RTL||(a-=1E7);return new goog.math.Rect(a,-1E7,1E7+this.width_,this.height_+2E7)}; Blockly.Flyout.terminateDrag_=function(){Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_),Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.onMouseMoveBlockWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveBlockWrapper_),Blockly.Flyout.onMouseMoveBlockWrapper_=null);Blockly.Flyout.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveWrapper_),Blockly.Flyout.onMouseMoveWrapper_=null);Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_), -Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.startDownEvent_=null;Blockly.Flyout.startBlock_=null;Blockly.Flyout.startFlyout_=null};Blockly.Flyout.prototype.getRect=function(){var a=Blockly.getSvgXY_(this.svgGroup_).x;Blockly.RTL||(a-=1E7);return new goog.math.Rect(a,-1E7,1E7+this.width_,this.height_+2E7)}; +Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.startDownEvent_=null;Blockly.Flyout.startBlock_=null;Blockly.Flyout.startFlyout_=null}; // Copyright 2011 Google Inc. Apache License 2.0 -Blockly.Toolbox=function(a,b){this.HtmlDiv=goog.dom.createDom("div","blocklyToolboxDiv");this.HtmlDiv.setAttribute("dir",Blockly.RTL?"RTL":"LTR");b.appendChild(this.HtmlDiv);this.flyout_=new Blockly.Flyout;a.appendChild(this.flyout_.createDom());Blockly.bindEvent_(this.HtmlDiv,"mousedown",this,function(a){Blockly.isRightButton(a)||a.target==this.HtmlDiv?Blockly.hideChaff(!1):Blockly.hideChaff(!0)})};Blockly.Toolbox.prototype.width=0;Blockly.Toolbox.prototype.selectedOption_=null; -Blockly.Toolbox.prototype.lastCategory_=null;Blockly.Toolbox.prototype.CONFIG_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"}; -Blockly.Toolbox.prototype.init=function(a){this.CONFIG_.cleardotPath=Blockly.pathToMedia+"1x1.gif";this.CONFIG_.cssCollapsedFolderIcon="blocklyTreeIconClosed"+(Blockly.RTL?"Rtl":"Ltr");var b=new Blockly.Toolbox.TreeControl(this,this.CONFIG_);this.tree_=b;b.setShowRootNode(!1);b.setShowLines(!1);b.setShowExpandIcons(!1);b.setSelectedItem(null);this.HtmlDiv.style.display="block";this.flyout_.init(a);this.populate_();b.render(this.HtmlDiv);var c=this;goog.events.listen(window,goog.events.EventType.RESIZE, -function(){c.position_()});this.position_()};Blockly.Toolbox.prototype.position_=function(){var a=this.HtmlDiv,b=goog.style.getBorderBox(Blockly.svg),c=Blockly.svgSize();Blockly.RTL?(b=Blockly.convertCoordinates(0,0,!1),a.style.left=b.x+c.width-a.offsetWidth+"px"):a.style.marginLeft=b.left;a.style.height=c.height+"px";this.width=a.offsetWidth;Blockly.RTL||--this.width}; -Blockly.Toolbox.prototype.populate_=function(){function a(c,d){for(var e=0,f;f=c.childNodes[e];e++)if(f.tagName){var g=f.tagName.toUpperCase();if("CATEGORY"==g){g=b.createNode(f.getAttribute("name"));g.blocks=[];d.add(g);var h=f.getAttribute("custom");h?g.blocks=h:a(f,g)}else"HR"==g?console.warn("The
separator tag in the toolbox XML needs to be changed to (due to a bug in IE)."):"SEP"==g?d.add(new Blockly.Toolbox.TreeSeparator):"BLOCK"==g&&d.blocks.push(f)}}var b=this.tree_;b.removeChildren(); -b.blocks=[];a(Blockly.languageTree,this.tree_);if(b.blocks.length)throw"Toolbox cannot have both blocks and categories in the root level.";Blockly.fireUiEvent(window,"resize")};Blockly.Toolbox.prototype.clearSelection=function(){this.tree_.setSelectedItem(null)};Blockly.Toolbox.prototype.getRect=function(){var a=Blockly.RTL?Blockly.svgSize().width-this.width:-1E7;return new goog.math.Rect(a,-1E7,1E7+this.width,2E7)}; +Blockly.Toolbox=function(a){this.workspace_=a};Blockly.Toolbox.prototype.width=0;Blockly.Toolbox.prototype.selectedOption_=null;Blockly.Toolbox.prototype.lastCategory_=null;Blockly.Toolbox.prototype.CONFIG_={indentWidth:19,cssRoot:"blocklyTreeRoot",cssHideRoot:"blocklyHidden",cssItem:"",cssTreeRow:"blocklyTreeRow",cssItemLabel:"blocklyTreeLabel",cssTreeIcon:"blocklyTreeIcon",cssExpandedFolderIcon:"blocklyTreeIconOpen",cssFileIcon:"blocklyTreeIconNone",cssSelectedRow:"blocklyTreeSelected"}; +Blockly.Toolbox.prototype.init=function(){var a=this.workspace_,b=a.options.svg;this.HtmlDiv=goog.dom.createDom("div","blocklyToolboxDiv");this.HtmlDiv.setAttribute("dir",this.workspace_.RTL?"RTL":"LTR");b.parentNode.insertBefore(this.HtmlDiv,b);Blockly.bindEvent_(this.HtmlDiv,"mousedown",this,function(a){Blockly.isRightButton(a)||a.target==this.HtmlDiv?Blockly.hideChaff(!1):Blockly.hideChaff(!0)});this.flyout_=new Blockly.Flyout({parentWorkspace:a,RTL:a.RTL});goog.dom.insertSiblingAfter(this.flyout_.createDom(), +a.svgGroup_);this.flyout_.init(a);this.CONFIG_.cleardotPath=a.options.pathToMedia+"1x1.gif";this.CONFIG_.cssCollapsedFolderIcon="blocklyTreeIconClosed"+(this.workspace_.RTL?"Rtl":"Ltr");this.tree_=b=new Blockly.Toolbox.TreeControl(this,this.CONFIG_);b.setShowRootNode(!1);b.setShowLines(!1);b.setShowExpandIcons(!1);b.setSelectedItem(null);this.HtmlDiv.style.display="block";this.populate_(a.options.languageTree);b.render(this.HtmlDiv);var c=this;goog.events.listen(window,goog.events.EventType.RESIZE, +function(){c.position_()});this.position_()};Blockly.Toolbox.prototype.position_=function(){var a=this.workspace_.options.svg,b=this.HtmlDiv,c=goog.style.getBorderBox(a),d=Blockly.svgSize(a);this.workspace_.RTL?(a=Blockly.convertCoordinates(0,0,!1,a),b.style.left=a.x+d.width-b.offsetWidth+"px"):b.style.marginLeft=c.left;b.style.height=d.height+"px";this.width=b.offsetWidth;this.workspace_.RTL||--this.width}; +Blockly.Toolbox.prototype.populate_=function(a){function b(a,e){for(var f=0,g;g=a.childNodes[f];f++)if(g.tagName){var h=g.tagName.toUpperCase();if("CATEGORY"==h){h=c.createNode(g.getAttribute("name"));h.blocks=[];e.add(h);var k=g.getAttribute("custom");k?h.blocks=k:b(g,h)}else"HR"==h?console.warn("The
separator tag in the toolbox XML needs to be changed to (due to a bug in IE)."):"SEP"==h?e.add(new Blockly.Toolbox.TreeSeparator):"BLOCK"==h&&e.blocks.push(g)}}var c=this.tree_;c.removeChildren(); +c.blocks=[];b(a,this.tree_);if(c.blocks.length)throw"Toolbox cannot have both blocks and categories in the root level.";Blockly.fireUiEvent(window,"resize")};Blockly.Toolbox.prototype.clearSelection=function(){this.tree_.setSelectedItem(null)};Blockly.Toolbox.prototype.getRect=function(){var a=this.workspace_.RTL?Blockly.svgSize(this.workspace_.options.svg).width-this.width:-1E7;return new goog.math.Rect(a,-1E7,1E7+this.width,2E7)}; Blockly.Toolbox.TreeControl=function(a,b){this.toolbox_=a;goog.ui.tree.TreeControl.call(this,goog.html.SafeHtml.EMPTY,b)};goog.inherits(Blockly.Toolbox.TreeControl,goog.ui.tree.TreeControl);Blockly.Toolbox.TreeControl.prototype.enterDocument=function(){Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this);if(goog.events.BrowserFeature.TOUCH_ENABLED){var a=this.getElement();Blockly.bindEvent_(a,goog.events.EventType.TOUCHSTART,this,this.handleTouchEvent_)}}; Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_=function(a){a.preventDefault();var b=this.getNodeFromEvent_(a);b&&a.type===goog.events.EventType.TOUCHSTART&&setTimeout(function(){b.onMouseDown(a)},1)};Blockly.Toolbox.TreeControl.prototype.createNode=function(a){return new Blockly.Toolbox.TreeNode(this.toolbox_,a?goog.html.SafeHtml.htmlEscape(a):goog.html.SafeHtml.EMPTY,this.getConfig(),this.getDomHelper())}; Blockly.Toolbox.TreeControl.prototype.setSelectedItem=function(a){Blockly.removeAllRanges();if(this.selectedItem_!=a){goog.ui.tree.TreeControl.prototype.setSelectedItem.call(this,a);var b=this.toolbox_;a&&a.blocks&&a.blocks.length?(b.flyout_.show(a.blocks),b.lastCategory_!=a.blocks&&(b.flyout_.scrollToTop(),b.lastCategory_=a.blocks)):b.flyout_.hide()}}; @@ -1279,86 +1289,76 @@ Blockly.Toolbox.TreeNode=function(a,b,c,d){goog.ui.tree.TreeNode.call(this,b,c,d Blockly.Toolbox.TreeNode.prototype.onMouseDown=function(a){this.hasChildren()&&this.isUserCollapsible_?(this.toggle(),this.select()):this.isSelected()?this.getTree().setSelectedItem(null):this.select();this.updateRow()};Blockly.Toolbox.TreeNode.prototype.onDoubleClick_=function(a){};Blockly.Toolbox.TreeSeparator=function(){Blockly.Toolbox.TreeNode.call(this,null,"",Blockly.Toolbox.TreeSeparator.CONFIG_)};goog.inherits(Blockly.Toolbox.TreeSeparator,Blockly.Toolbox.TreeNode); Blockly.Toolbox.TreeSeparator.CONFIG_={cssTreeRow:"blocklyTreeSeparator"}; // Copyright 2013 Google Inc. Apache License 2.0 -Blockly.Css={};Blockly.Css.Cursor={OPEN:"handopen",CLOSED:"handclosed",DELETE:"handdelete"};Blockly.Css.currentCursor_="";Blockly.Css.styleSheet_=null;Blockly.Css.mediaPath_="";Blockly.Css.inject=function(){var a=".blocklyDraggable {}\n";Blockly.hasCss&&(a+=Blockly.Css.CONTENT.join("\n"));Blockly.Css.mediaPath_=Blockly.pathToMedia.replace(/[\\\/]$/,"");a=a.replace(/<<>>/g,Blockly.Css.mediaPath_);Blockly.Css.styleSheet_=goog.cssom.addCssText(a).sheet;Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN)}; -Blockly.Css.setCursor=function(a){if(!Blockly.readOnly&&Blockly.Css.currentCursor_!=a){Blockly.Css.currentCursor_=a;var b="url("+Blockly.Css.mediaPath_+"/"+a+".cur) "+(a==Blockly.Css.Cursor.OPEN?"8 5":"7 3")+", auto";goog.cssom.replaceCssRule("",".blocklyDraggable {\n cursor: "+b+";\n}\n",Blockly.Css.styleSheet_,0);for(var c=document.getElementsByClassName("blocklyToolboxDiv"),d=0,e;e=c[d];d++)e.style.cursor=a==Blockly.Css.Cursor.OPEN?"":b;Blockly.svg&&(Blockly.svg.style.cursor=a==Blockly.Css.Cursor.OPEN? -"":b)}}; -Blockly.Css.CONTENT=[".blocklySvg {"," background-color: #fff;"," overflow: hidden;","}",".blocklyWidgetDiv {"," display: none;"," position: absolute;"," z-index: 999;","}",".blocklyResizeSE {"," cursor: se-resize;"," fill: #aaa;","}",".blocklyResizeSW {"," cursor: sw-resize;"," fill: #aaa;","}",".blocklyResizeLine {"," stroke: #888;"," stroke-width: 1;","}",".blocklyHighlightedConnectionPath {"," fill: none;"," stroke: #fc3;"," stroke-width: 4px;","}",".blocklyPathLight {"," fill: none;", -" stroke-linecap: round;"," stroke-width: 2;","}",".blocklySelected>.blocklyPath {"," stroke: #fc3;"," stroke-width: 3px;","}",".blocklySelected>.blocklyPathLight {"," display: none;","}",".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;","}", -".blocklySvg text {"," user-select: none;"," -moz-user-select: none;"," -webkit-user-select: none;"," cursor: inherit;","}",".blocklyHidden {"," display: none;","}",".blocklyFieldDropdown:not(.blocklyHidden) {"," display: block;","}",".blocklyTooltipBackground {"," fill: #ffffc7;"," stroke: #d8d8d8;"," stroke-width: 1px;","}",".blocklyTooltipShadow,",".blocklyDropdownMenuShadow {"," fill: #bbb;"," filter: url(#blocklyShadowFilter);","}",".blocklyTooltipText {"," fill: #000;"," font-family: sans-serif;", -" font-size: 9pt;","}",".blocklyIconShield {"," cursor: default;"," fill: #00c;"," stroke: #ccc;"," stroke-width: 1px;","}",".blocklyIconGroup:not(:hover),",".blocklyIconGroupReadonly {"," opacity: .6;","}",".blocklyIconMark {"," cursor: default !important;"," fill: #ccc;"," font-family: sans-serif;"," font-size: 9pt;"," font-weight: bold;"," text-anchor: middle;","}",".blocklyWarningBody {","}",".blocklyMinimalBody {"," margin: 0;"," padding: 0;","}",".blocklyCommentTextarea {"," background-color: #ffc;", -" border: 0;"," margin: 0;"," padding: 2px;"," resize: none;","}",".blocklyHtmlInput {"," border: none;"," font-family: sans-serif;"," font-size: 11pt;"," outline: none;"," width: 100%","}",".blocklyMainBackground {"," fill: url(#blocklyGridPattern);"," stroke-width: 1;"," stroke: #c6c6c6;","}",".blocklyMutatorBackground {"," fill: #fff;"," stroke: #ddd;"," stroke-width: 1;","}",".blocklyFlyoutBackground {"," fill: #ddd;"," fill-opacity: .8;","}",".blocklyColourBackground {"," fill: #666;", -"}",".blocklyScrollbarBackground {"," fill: #fff;"," stroke: #e4e4e4;"," stroke-width: 1;","}",".blocklyScrollbarKnob {"," fill: #ccc;","}",".blocklyScrollbarBackground:hover+.blocklyScrollbarKnob,",".blocklyScrollbarKnob:hover {"," fill: #bbb;","}",".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;","}",".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;"," display: none;", -" overflow-x: visible;"," overflow-y: auto;"," position: absolute;","}",".blocklyTreeRoot {"," padding: 4px 0;","}",".blocklyTreeRoot:focus {"," outline: none;","}",".blocklyTreeRow {"," line-height: 22px;"," height: 22px;"," padding-right: 1em;"," white-space: nowrap;","}",'.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {'," padding-right: 0;"," padding-left: 1em !important;","}",".blocklyTreeRow:hover {"," background-color: #e4e4e4;","}",".blocklyTreeSeparator {"," border-bottom: solid #e5e5e5 1px;", -" height: 0px;"," margin: 5px 0;","}",".blocklyTreeIcon {"," background-image: url(<<>>/sprites.png);"," height: 16px;"," vertical-align: middle;"," width: 16px;","}",".blocklyTreeIconClosedLtr {"," background-position: -32px -1px;","}",".blocklyTreeIconClosedRtl {"," background-position: 0px -1px;","}",".blocklyTreeIconOpen {"," background-position: -16px -1px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedLtr {"," background-position: -32px -17px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedRtl {", -" background-position: 0px -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;","}",".blocklyTreeSelected {"," background-color: #57e !important;","}",".blocklyTreeSelected .blocklyTreeLabel {"," color: #fff;", -"}",".blocklyWidgetDiv .goog-palette {"," outline: none;"," cursor: default;","}",".blocklyWidgetDiv .goog-palette-table {"," border: 1px solid #666;"," border-collapse: collapse;","}",".blocklyWidgetDiv .goog-palette-cell {"," height: 13px;"," width: 15px;"," margin: 0;"," border: 0;"," text-align: center;"," vertical-align: middle;"," border-right: 1px solid #666;"," font-size: 1px;","}",".blocklyWidgetDiv .goog-palette-colorswatch {"," position: relative;"," height: 13px;"," width: 15px;", -" border: 1px solid #666;","}",".blocklyWidgetDiv .goog-palette-cell-hover .goog-palette-colorswatch {"," border: 1px solid #FFF;","}",".blocklyWidgetDiv .goog-palette-cell-selected .goog-palette-colorswatch {"," border: 1px solid #000;"," color: #fff;","}",".blocklyWidgetDiv .goog-date-picker,",".blocklyWidgetDiv .goog-date-picker th,",".blocklyWidgetDiv .goog-date-picker td {"," font: 13px Arial, sans-serif;","}",".blocklyWidgetDiv .goog-date-picker {"," -moz-user-focus: normal;"," -moz-user-select: none;", -" position: relative;"," border: 1px solid #000;"," float: left;"," padding: 2px;"," color: #000;"," background: #c3d9ff;"," cursor: default;","}",".blocklyWidgetDiv .goog-date-picker th {"," text-align: center;","}",".blocklyWidgetDiv .goog-date-picker td {"," text-align: center;"," vertical-align: middle;"," padding: 1px 3px;","}",".blocklyWidgetDiv .goog-date-picker-menu {"," position: absolute;"," background: threedface;"," border: 1px solid gray;"," -moz-user-focus: normal;"," z-index: 1;", -" outline: none;","}",".blocklyWidgetDiv .goog-date-picker-menu ul {"," list-style: none;"," margin: 0px;"," padding: 0px;","}",".blocklyWidgetDiv .goog-date-picker-menu ul li {"," cursor: default;","}",".blocklyWidgetDiv .goog-date-picker-menu-selected {"," background: #ccf;","}",".blocklyWidgetDiv .goog-date-picker th {"," font-size: .9em;","}",".blocklyWidgetDiv .goog-date-picker td div {"," float: left;","}",".blocklyWidgetDiv .goog-date-picker button {"," padding: 0px;"," margin: 1px 0;", -" border: 0;"," color: #20c;"," font-weight: bold;"," background: transparent;","}",".blocklyWidgetDiv .goog-date-picker-date {"," background: #fff;","}",".blocklyWidgetDiv .goog-date-picker-week,",".blocklyWidgetDiv .goog-date-picker-wday {"," padding: 1px 3px;"," border: 0;"," border-color: #a2bbdd;"," border-style: solid;","}",".blocklyWidgetDiv .goog-date-picker-week {"," border-right-width: 1px;","}",".blocklyWidgetDiv .goog-date-picker-wday {"," border-bottom-width: 1px;","}",".blocklyWidgetDiv .goog-date-picker-head td {", -" text-align: center;","}",".blocklyWidgetDiv td.goog-date-picker-today-cont {"," text-align: center;","}",".blocklyWidgetDiv td.goog-date-picker-none-cont {"," text-align: center;","}",".blocklyWidgetDiv .goog-date-picker-month {"," min-width: 11ex;"," white-space: nowrap;","}",".blocklyWidgetDiv .goog-date-picker-year {"," min-width: 6ex;"," white-space: nowrap;","}",".blocklyWidgetDiv .goog-date-picker-monthyear {"," white-space: nowrap;","}",".blocklyWidgetDiv .goog-date-picker table {", -" border-collapse: collapse;","}",".blocklyWidgetDiv .goog-date-picker-other-month {"," color: #888;","}",".blocklyWidgetDiv .goog-date-picker-wkend-start,",".blocklyWidgetDiv .goog-date-picker-wkend-end {"," background: #eee;","}",".blocklyWidgetDiv td.goog-date-picker-selected {"," background: #c3d9ff;","}",".blocklyWidgetDiv .goog-date-picker-today {"," background: #9ab;"," font-weight: bold !important;"," border-color: #246 #9bd #9bd #246;"," color: #fff;","}",".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;"," 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;"," -moz-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.Css={};Blockly.Css.Cursor={OPEN:"handopen",CLOSED:"handclosed",DELETE:"handdelete"};Blockly.Css.currentCursor_="";Blockly.Css.styleSheet_=null;Blockly.Css.mediaPath_="";Blockly.Css.inject=function(a,b){if(!Blockly.Css.styleSheet_){var c=".blocklyDraggable {}\n";a&&(c+=Blockly.Css.CONTENT.join("\n"));Blockly.Css.mediaPath_=b.replace(/[\\\/]$/,"");c=c.replace(/<<>>/g,Blockly.Css.mediaPath_);Blockly.Css.styleSheet_=goog.cssom.addCssText(c).sheet;Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN)}}; +Blockly.Css.setCursor=function(a){if(Blockly.Css.currentCursor_!=a){Blockly.Css.currentCursor_=a;var b="url("+Blockly.Css.mediaPath_+"/"+a+".cur) "+(a==Blockly.Css.Cursor.OPEN?"8 5":"7 3")+", auto";goog.cssom.replaceCssRule("",".blocklyDraggable {\n cursor: "+b+";\n}\n",Blockly.Css.styleSheet_,0);for(var c=document.getElementsByClassName("blocklyToolboxDiv"),d=0,e;e=c[d];d++)e.style.cursor=a==Blockly.Css.Cursor.OPEN?"":b;document.body.parentNode.style.cursor=a==Blockly.Css.Cursor.OPEN?"":b}}; +Blockly.Css.CONTENT=[".blocklySvg {"," background-color: #fff;"," outline: none;"," overflow: hidden;","}",".blocklyWidgetDiv {"," display: none;"," position: absolute;"," z-index: 999;","}",".blocklyTooltipDiv {"," background-color: #ffffc7;"," border: 1px solid #ddc;"," box-shadow: 4px 4px 20px 1px rgba(0,0,0,.15);"," colour: #000;"," display: none;"," font-family: sans-serif;"," font-size: 9pt;"," opacity: 0.9;"," padding: 2px;"," position: absolute;"," z-index: 1000;","}",".blocklyResizeSE {", +" cursor: se-resize;"," fill: #aaa;","}",".blocklyResizeSW {"," cursor: sw-resize;"," fill: #aaa;","}",".blocklyResizeLine {"," stroke: #888;"," stroke-width: 1;","}",".blocklyHighlightedConnectionPath {"," fill: none;"," stroke: #fc3;"," stroke-width: 4px;","}",".blocklyPathLight {"," fill: none;"," stroke-linecap: round;"," stroke-width: 2;","}",".blocklySelected>.blocklyPath {"," stroke: #fc3;"," stroke-width: 3px;","}",".blocklySelected>.blocklyPathLight {"," display: none;","}", +".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;","}",".blocklySvg text {"," user-select: none;"," -moz-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;","}",".blocklyMinimalBody {"," margin: 0;"," padding: 0;","}",".blocklyCommentTextarea {"," background-color: #ffc;"," border: 0;"," margin: 0;"," padding: 2px;"," resize: none;","}",".blocklyHtmlInput {"," border: none;"," font-family: sans-serif;"," font-size: 11pt;"," outline: none;"," width: 100%", +"}",".blocklyMainBackground {"," stroke-width: 1;"," stroke: #c6c6c6;","}",".blocklyMutatorBackground {"," fill: #fff;"," stroke: #ddd;"," stroke-width: 1;","}",".blocklyFlyoutBackground {"," fill: #ddd;"," fill-opacity: .8;","}",".blocklyColourBackground {"," fill: #666;","}",".blocklyScrollbarBackground {"," fill: #fff;"," stroke: #e4e4e4;"," stroke-width: 1;","}",".blocklyScrollbarKnob {"," fill: #ccc;","}",".blocklyScrollbarBackground:hover+.blocklyScrollbarKnob,",".blocklyScrollbarKnob:hover {", +" fill: #bbb;","}",".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;","}",".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;"," display: none;"," overflow-x: visible;"," overflow-y: auto;"," position: absolute;","}",".blocklyTreeRoot {"," padding: 4px 0;","}",".blocklyTreeRoot:focus {"," outline: none;","}",".blocklyTreeRow {"," line-height: 22px;"," height: 22px;", +" padding-right: 1em;"," white-space: nowrap;","}",'.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {'," padding-right: 0;"," padding-left: 1em !important;","}",".blocklyTreeRow:hover {"," background-color: #e4e4e4;","}",".blocklyTreeSeparator {"," border-bottom: solid #e5e5e5 1px;"," height: 0px;"," margin: 5px 0;","}",".blocklyTreeIcon {"," background-image: url(<<>>/sprites.png);"," height: 16px;"," vertical-align: middle;"," width: 16px;","}",".blocklyTreeIconClosedLtr {"," background-position: -32px -1px;", +"}",".blocklyTreeIconClosedRtl {"," background-position: 0px -1px;","}",".blocklyTreeIconOpen {"," background-position: -16px -1px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedLtr {"," background-position: -32px -17px;","}",".blocklyTreeSelected>.blocklyTreeIconClosedRtl {"," background-position: 0px -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;","}",".blocklyTreeSelected {"," background-color: #57e !important;","}",".blocklyTreeSelected .blocklyTreeLabel {"," color: #fff;","}",".blocklyWidgetDiv .goog-palette {"," outline: none;"," cursor: default;","}",".blocklyWidgetDiv .goog-palette-table {"," border: 1px solid #666;"," border-collapse: collapse;","}",".blocklyWidgetDiv .goog-palette-cell {", +" height: 13px;"," width: 15px;"," margin: 0;"," border: 0;"," text-align: center;"," vertical-align: middle;"," border-right: 1px solid #666;"," font-size: 1px;","}",".blocklyWidgetDiv .goog-palette-colorswatch {"," position: relative;"," height: 13px;"," width: 15px;"," border: 1px solid #666;","}",".blocklyWidgetDiv .goog-palette-cell-hover .goog-palette-colorswatch {"," border: 1px solid #FFF;","}",".blocklyWidgetDiv .goog-palette-cell-selected .goog-palette-colorswatch {"," border: 1px solid #000;", +" color: #fff;","}",".blocklyWidgetDiv .goog-date-picker,",".blocklyWidgetDiv .goog-date-picker th,",".blocklyWidgetDiv .goog-date-picker td {"," font: 13px Arial, sans-serif;","}",".blocklyWidgetDiv .goog-date-picker {"," -moz-user-focus: normal;"," -moz-user-select: none;"," position: relative;"," border: 1px solid #000;"," float: left;"," padding: 2px;"," color: #000;"," background: #c3d9ff;"," cursor: default;","}",".blocklyWidgetDiv .goog-date-picker th {"," text-align: center;", +"}",".blocklyWidgetDiv .goog-date-picker td {"," text-align: center;"," vertical-align: middle;"," padding: 1px 3px;","}",".blocklyWidgetDiv .goog-date-picker-menu {"," position: absolute;"," background: threedface;"," border: 1px solid gray;"," -moz-user-focus: normal;"," z-index: 1;"," outline: none;","}",".blocklyWidgetDiv .goog-date-picker-menu ul {"," list-style: none;"," margin: 0px;"," padding: 0px;","}",".blocklyWidgetDiv .goog-date-picker-menu ul li {"," cursor: default;","}", +".blocklyWidgetDiv .goog-date-picker-menu-selected {"," background: #ccf;","}",".blocklyWidgetDiv .goog-date-picker th {"," font-size: .9em;","}",".blocklyWidgetDiv .goog-date-picker td div {"," float: left;","}",".blocklyWidgetDiv .goog-date-picker button {"," padding: 0px;"," margin: 1px 0;"," border: 0;"," color: #20c;"," font-weight: bold;"," background: transparent;","}",".blocklyWidgetDiv .goog-date-picker-date {"," background: #fff;","}",".blocklyWidgetDiv .goog-date-picker-week,", +".blocklyWidgetDiv .goog-date-picker-wday {"," padding: 1px 3px;"," border: 0;"," border-color: #a2bbdd;"," border-style: solid;","}",".blocklyWidgetDiv .goog-date-picker-week {"," border-right-width: 1px;","}",".blocklyWidgetDiv .goog-date-picker-wday {"," border-bottom-width: 1px;","}",".blocklyWidgetDiv .goog-date-picker-head td {"," text-align: center;","}",".blocklyWidgetDiv td.goog-date-picker-today-cont {"," text-align: center;","}",".blocklyWidgetDiv td.goog-date-picker-none-cont {", +" text-align: center;","}",".blocklyWidgetDiv .goog-date-picker-month {"," min-width: 11ex;"," white-space: nowrap;","}",".blocklyWidgetDiv .goog-date-picker-year {"," min-width: 6ex;"," white-space: nowrap;","}",".blocklyWidgetDiv .goog-date-picker-monthyear {"," white-space: nowrap;","}",".blocklyWidgetDiv .goog-date-picker table {"," border-collapse: collapse;","}",".blocklyWidgetDiv .goog-date-picker-other-month {"," color: #888;","}",".blocklyWidgetDiv .goog-date-picker-wkend-start,", +".blocklyWidgetDiv .goog-date-picker-wkend-end {"," background: #eee;","}",".blocklyWidgetDiv td.goog-date-picker-selected {"," background: #c3d9ff;","}",".blocklyWidgetDiv .goog-date-picker-today {"," background: #9ab;"," font-weight: bold !important;"," border-color: #246 #9bd #9bd #246;"," color: #fff;","}",".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;"," 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;"," -moz-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;","}",""]; // Copyright 2013 Google Inc. Apache License 2.0 -Blockly.WidgetDiv={};Blockly.WidgetDiv.DIV=null;Blockly.WidgetDiv.owner_=null;Blockly.WidgetDiv.dispose_=null;Blockly.WidgetDiv.show=function(a,b){Blockly.WidgetDiv.hide();Blockly.WidgetDiv.owner_=a;Blockly.WidgetDiv.dispose_=b;Blockly.WidgetDiv.DIV.style.display="block"};Blockly.WidgetDiv.hide=function(){Blockly.WidgetDiv.owner_&&(Blockly.WidgetDiv.DIV.style.display="none",Blockly.WidgetDiv.dispose_&&Blockly.WidgetDiv.dispose_(),Blockly.WidgetDiv.owner_=null,Blockly.WidgetDiv.dispose_=null,goog.dom.removeChildren(Blockly.WidgetDiv.DIV))}; -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){bc.width+d.x&&(a=c.width+d.x):ac.width+d.x&&(a=c.width+d.x):a -a.viewHeight+c||a.contentLeft<(Blockly.RTL?a.viewLeft:b)||a.contentLeft+a.contentWidth>(Blockly.RTL?a.viewWidth:a.viewWidth+b))for(var d=Blockly.mainWorkspace.getTopBlocks(!1),e=0,f;f=d[e];e++){var p=f.getRelativeToSurfaceXY(),n=f.getHeightWidth(),r=c+25-n.height-p.y;0r&&f.moveBy(0,r);r=25+b-p.x-(Blockly.RTL?0:n.width);0r&&f.moveBy(r,0)}}}));b.appendChild(Blockly.Tooltip.createDom());a.appendChild(b); -Blockly.svg=b;Blockly.svgResize();Blockly.WidgetDiv.DIV=goog.dom.createDom("div","blocklyWidgetDiv");Blockly.WidgetDiv.DIV.style.direction=Blockly.RTL?"rtl":"ltr";document.body.appendChild(Blockly.WidgetDiv.DIV)}; -Blockly.init_=function(){Blockly.bindEvent_(Blockly.svg,"mousedown",null,Blockly.onMouseDown_);Blockly.bindEvent_(Blockly.svg,"contextmenu",null,Blockly.onContextMenu_);Blockly.bindEvent_(Blockly.WidgetDiv.DIV,"contextmenu",null,Blockly.onContextMenu_);Blockly.bindEvent_(Blockly.svg,"touchstart",null,function(a){Blockly.longStart_(a,null)});Blockly.documentEventsBound_||(Blockly.bindEvent_(window,"resize",document,Blockly.svgResize),Blockly.bindEvent_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document, -"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel",null,Blockly.longStop_),document.addEventListener("mouseup",Blockly.onMouseUp_,!1),goog.userAgent.IPAD&&Blockly.bindEvent_(window,"orientationchange",document,function(){Blockly.fireUiEvent(window,"resize")}),Blockly.documentEventsBound_=!0);if(Blockly.languageTree)if(Blockly.mainWorkspace.toolbox_)Blockly.mainWorkspace.toolbox_.init(Blockly.mainWorkspace);else if(Blockly.mainWorkspace.flyout_){Blockly.mainWorkspace.flyout_.init(Blockly.mainWorkspace); -Blockly.mainWorkspace.flyout_.show(Blockly.languageTree.childNodes);Blockly.mainWorkspace.scrollX=Blockly.mainWorkspace.flyout_.width_;Blockly.RTL&&(Blockly.mainWorkspace.scrollX*=-1);var a="translate("+Blockly.mainWorkspace.scrollX+", 0)";Blockly.mainWorkspace.getCanvas().setAttribute("transform",a);Blockly.mainWorkspace.getBubbleCanvas().setAttribute("transform",a)}Blockly.hasScrollbars&&(Blockly.mainWorkspace.scrollbar=new Blockly.ScrollbarPair(Blockly.mainWorkspace),Blockly.mainWorkspace.scrollbar.resize()); -Blockly.mainWorkspace.addTrashcan();if(Blockly.hasSounds){Blockly.loadAudio_([Blockly.pathToMedia+"click.mp3",Blockly.pathToMedia+"click.wav",Blockly.pathToMedia+"click.ogg"],"click");Blockly.loadAudio_([Blockly.pathToMedia+"delete.mp3",Blockly.pathToMedia+"delete.ogg",Blockly.pathToMedia+"delete.wav"],"delete");var b=[],a=function(){for(;b.length;)Blockly.unbindEvent_(b.pop());Blockly.preloadAudio_()};b.push(Blockly.bindEvent_(document,"mousemove",null,a));b.push(Blockly.bindEvent_(document,"touchstart", -null,a))}}; -Blockly.updateToolbox=function(a){if(a=Blockly.parseToolboxTree_(a)){if(!Blockly.languageTree)throw"Existing toolbox is null. Can't create new toolbox.";if(a.getElementsByTagName("category").length){if(!Blockly.hasCategories)throw"Existing toolbox has no categories. Can't change mode.";Blockly.languageTree=a;Blockly.mainWorkspace.toolbox_.populate_()}else{if(Blockly.hasCategories)throw"Existing toolbox has categories. Can't change mode.";Blockly.languageTree=a;Blockly.mainWorkspace.flyout_.show(Blockly.languageTree.childNodes)}}else if(Blockly.languageTree)throw"Can't nullify an existing toolbox.";}; +Blockly.parseOptions_=function(a){var b=!!a.readOnly;if(b)var c=null,d=!1,e=!1,f=!1,g=!1,h=!1,k=!1;else c=Blockly.parseToolboxTree_(a.toolbox),d=Boolean(c&&c.getElementsByTagName("category").length),e=a.trashcan,void 0===e&&(e=d),f=a.collapse,void 0===f&&(f=d),g=a.comments,void 0===g&&(g=d),h=a.disable,void 0===h&&(h=d),k=a.sounds,void 0===k&&(k=!0);var l=a.scrollbars;void 0===l&&(l=d);var p=a.css;void 0===p&&(p=!0);var m=a.grid||{};m.spacing=m.spacing?parseFloat(m.spacing):0;m.colour||(m.colour= +"#888");m.length=m.length?parseFloat(m.length):1;m.snap=!!m.snap;var q="https://blockly-demo.appspot.com/static/media/";a.media?q=a.media:a.path&&(q=a.path+"media/");var n=!!a.realtime;return{RTL:!!a.rtl,collapse:f,comments:g,disable:h,readOnly:b,maxBlocks:a.maxBlocks||Infinity,pathToMedia:q,hasCategories:d,hasScrollbars:l,hasTrashcan:e,hasSounds:k,hasCss:p,languageTree:c,gridOptions:m,enableRealtime:n,realtimeOptions:n?a.realtimeOptions:void 0}}; +Blockly.createDom_=function(a,b){a.setAttribute("dir","LTR");goog.ui.Component.setDefaultRightToLeft(b.RTL);Blockly.Css.inject(b.hasCss,b.pathToMedia);var c=Blockly.createSvgElement("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:html":"http://www.w3.org/1999/xhtml","xmlns:xlink":"http://www.w3.org/1999/xlink",version:"1.1","class":"blocklySvg"},a),d=Blockly.createSvgElement("defs",{},c),e,f;e=Blockly.createSvgElement("filter",{id:"blocklyEmboss"},d);Blockly.createSvgElement("feGaussianBlur",{"in":"SourceAlpha", +stdDeviation:1,result:"blur"},e);f=Blockly.createSvgElement("feSpecularLighting",{"in":"blur",surfaceScale:1,specularConstant:.5,specularExponent:10,"lighting-color":"white",result:"specOut"},e);Blockly.createSvgElement("fePointLight",{x:-5E3,y:-1E4,z:2E4},f);Blockly.createSvgElement("feComposite",{"in":"specOut",in2:"SourceAlpha",operator:"in",result:"specOut"},e);Blockly.createSvgElement("feComposite",{"in":"SourceGraphic",in2:"specOut",operator:"arithmetic",k1:0,k2:1,k3:1,k4:0},e);e=Blockly.createSvgElement("filter", +{id:"blocklyShadowFilter"},d);Blockly.createSvgElement("feGaussianBlur",{stdDeviation:2},e);e=Blockly.createSvgElement("pattern",{id:"blocklyDisabledPattern",patternUnits:"userSpaceOnUse",width:10,height:10},d);Blockly.createSvgElement("rect",{width:10,height:10,fill:"#aaa"},e);Blockly.createSvgElement("path",{d:"M 0 0 L 10 10 M 10 0 L 0 10",stroke:"#cc0"},e);d=Blockly.createSvgElement("pattern",{id:"blocklyGridPattern"+String(Math.random()).substring(2),patternUnits:"userSpaceOnUse",width:b.gridOptions.spacing, +height:b.gridOptions.spacing},d);if(0a.viewHeight+f||a.contentLeft<(b.RTL? +a.viewLeft:e)||a.contentLeft+a.contentWidth>(b.RTL?a.viewWidth:a.viewWidth+e))for(var g=c.getTopBlocks(!1),h=0,k;k=g[h];h++){var l=k.getRelativeToSurfaceXY(),p=k.getHeightWidth(),m=f+25-p.height-l.y;0m&&k.moveBy(0,m);m=25+e-l.x-(b.RTL?0:p.width);0m&&k.moveBy(m,0)}}});Blockly.svgResize(c);Blockly.WidgetDiv.createDom();Blockly.Tooltip.createDom();return c}; +Blockly.init_=function(a){var b=a.options,c=a.options.svg;Blockly.bindEvent_(c,"contextmenu",null,function(a){Blockly.isTargetInput_(a)||a.preventDefault()});Blockly.bindEvent_(c,"touchstart",null,function(a){Blockly.longStart_(a,null)});Blockly.bindEvent_(window,"resize",null,function(){Blockly.svgResize(a)});Blockly.documentEventsBound_||(Blockly.bindEvent_(document,"keydown",null,Blockly.onKeyDown_),Blockly.bindEvent_(document,"touchend",null,Blockly.longStop_),Blockly.bindEvent_(document,"touchcancel", +null,Blockly.longStop_),document.addEventListener("mouseup",Blockly.onMouseUp_,!1),goog.userAgent.IPAD&&Blockly.bindEvent_(window,"orientationchange",document,function(){Blockly.fireUiEvent(window,"resize")}),Blockly.documentEventsBound_=!0);b.languageTree&&(a.toolbox_?a.toolbox_.init(a):a.flyout_&&(a.flyout_.init(a),a.flyout_.show(b.languageTree.childNodes),a.scrollX=a.flyout_.width_,b.RTL&&(a.scrollX*=-1),c="translate("+a.scrollX+", 0)",a.getCanvas().setAttribute("transform",c),a.getBubbleCanvas().setAttribute("transform", +c)));b.hasScrollbars&&(a.scrollbar=new Blockly.ScrollbarPair(a),a.scrollbar.resize());if(b.hasSounds){a.loadAudio_([b.pathToMedia+"click.mp3",b.pathToMedia+"click.wav",b.pathToMedia+"click.ogg"],"click");a.loadAudio_([b.pathToMedia+"delete.mp3",b.pathToMedia+"delete.ogg",b.pathToMedia+"delete.wav"],"delete");var d=[],b=function(){for(;d.length;)Blockly.unbindEvent_(d.pop());a.preloadAudio_()};d.push(Blockly.bindEvent_(document,"mousemove",null,b));d.push(Blockly.bindEvent_(document,"touchstart",null, +b))}};Blockly.updateToolbox=function(a,b){console.warn("Deprecated call to Blockly.updateToolbox, use workspace.updateToolbox instead.");Blockly.getMainWorkspace().updateToolbox(a)}; // Copyright 2012 Google Inc. Apache License 2.0 Blockly.utils={};Blockly.addClass_=function(a,b){var c=a.getAttribute("class")||"";-1==(" "+c+" ").indexOf(" "+b+" ")&&(c&&(c+=" "),a.setAttribute("class",c+b))};Blockly.removeClass_=function(a,b){var c=a.getAttribute("class");if(-1!=(" "+c+" ").indexOf(" "+b+" ")){for(var c=c.split(/\s+/),d=0;dBlockly.DRAG_RADIUS&&Blockly.longStop_();a.stopPropagation()}}; -Blockly.onKeyDown_=function(a){if(!Blockly.isTargetInput_(a))if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode)try{Blockly.selected&&Blockly.selected.isDeletable()&&(Blockly.hideChaff(),Blockly.selected.dispose(!0,!0))}finally{a.preventDefault()}else if(a.altKey||a.ctrlKey||a.metaKey)Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&Blockly.selected.workspace==Blockly.mainWorkspace&&(Blockly.hideChaff(),67==a.keyCode?Blockly.copy_(Blockly.selected): -88==a.keyCode&&(Blockly.copy_(Blockly.selected),Blockly.selected.dispose(!0,!0))),86==a.keyCode&&Blockly.clipboard_&&Blockly.mainWorkspace.paste(Blockly.clipboard_)};Blockly.terminateDrag_=function(){Blockly.BlockSvg.terminateDrag_();Blockly.Flyout.terminateDrag_()};Blockly.longPid_=0;Blockly.longStart_=function(a,b){Blockly.longStop_();Blockly.longPid_=setTimeout(function(){a.button=2;if(b)b.onMouseDown_(a);else Blockly.onMouseDown_(a)},Blockly.LONGPRESS)}; -Blockly.longStop_=function(){Blockly.longPid_&&(clearTimeout(Blockly.longPid_),Blockly.longPid_=0)};Blockly.copy_=function(a){var b=Blockly.Xml.blockToDom_(a);Blockly.Xml.deleteNext(b);a=a.getRelativeToSurfaceXY();b.setAttribute("x",Blockly.RTL?-a.x:a.x);b.setAttribute("y",a.y);Blockly.clipboard_=b}; -Blockly.showContextMenu_=function(a){if(!Blockly.readOnly){var b=[];if(Blockly.collapse){for(var c=!1,d=!1,e=Blockly.mainWorkspace.getTopBlocks(!1),f=0;fBlockly.DRAG_RADIUS&& +Blockly.longStop_();a.stopPropagation()}}; +Blockly.onKeyDown_=function(a){if(!Blockly.isTargetInput_(a))if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode)try{Blockly.selected&&Blockly.selected.isDeletable()&&(Blockly.hideChaff(),Blockly.selected.dispose(!0,!0))}finally{a.preventDefault()}else if(a.altKey||a.ctrlKey||a.metaKey)Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&(Blockly.hideChaff(),67==a.keyCode?Blockly.copy_(Blockly.selected):88==a.keyCode&&(Blockly.copy_(Blockly.selected), +Blockly.selected.dispose(!0,!0))),86==a.keyCode&&Blockly.clipboardXml_&&Blockly.clipboardSource_.paste(Blockly.clipboardXml_)};Blockly.terminateDrag_=function(){Blockly.BlockSvg.terminateDrag_();Blockly.Flyout.terminateDrag_()};Blockly.longPid_=0;Blockly.longStart_=function(a,b){Blockly.longStop_();Blockly.longPid_=setTimeout(function(){a.button=2;if(b)b.onMouseDown_(a);else Blockly.onMouseDown_(a)},Blockly.LONGPRESS)}; +Blockly.longStop_=function(){Blockly.longPid_&&(clearTimeout(Blockly.longPid_),Blockly.longPid_=0)};Blockly.copy_=function(a){var 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.onContextMenu_=function(a){Blockly.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.removeAllRanges=function(){getSelection()&&setTimeout(function(){try{var a=getSelection();a.isCollapsed||a.removeAllRanges()}catch(b){}},0)}; +Blockly.getMainWorkspaceMetrics_=function(){var a=Blockly.svgSize(this.options.svg);this.toolbox_&&(a.width-=this.toolbox_.width);var b=a.width-Blockly.Scrollbar.scrollbarThickness,c=a.height-Blockly.Scrollbar.scrollbarThickness;try{var d=this.getCanvas().getBBox()}catch(e){return null}if(this.scrollbar)var f=this.RTL?0:Blockly.Scrollbar.scrollbarThickness,g=Math.min(d.x-b/2,d.x+d.width-b-(this.RTL?Blockly.Scrollbar.scrollbarThickness:0)+5),b=Math.max(d.x+d.width+b/2,d.x+b+f-5),f=Math.min(d.y-c/2, +d.y+d.height-c+5),c=Math.max(d.y+d.height+c/2,d.y+c+Blockly.Scrollbar.scrollbarThickness-5);else g=d.x,b=g+d.width,f=d.y,c=f+d.height;d=0;!this.RTL&&this.toolbox_&&(d=this.toolbox_.width);return{viewHeight:a.height,viewWidth:a.width,contentHeight:c-f,contentWidth:b-g,viewTop:-this.scrollY,viewLeft:-this.scrollX,contentTop:f,contentLeft:g,absoluteTop:0,absoluteLeft:d}}; +Blockly.setMainWorkspaceMetrics_=function(a){if(!this.scrollbar)throw"Attempt to set main workspace scroll without scrollbars.";var b=this.getMetrics();goog.isNumber(a.x)&&(this.scrollX=-b.contentWidth*a.x-b.contentLeft);goog.isNumber(a.y)&&(this.scrollY=-b.contentHeight*a.y-b.contentTop);a=this.scrollX+b.absoluteLeft;b=this.scrollY+b.absoluteTop;this.translate(a,b);this.options.gridPattern&&(this.options.gridPattern.setAttribute("x",a),this.options.gridPattern.setAttribute("y",b))}; +Blockly.doCommand=function(a){Blockly.Realtime.isEnabled?Blockly.Realtime.doCommand(a):a()};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};goog.global.Blockly||(goog.global.Blockly={});goog.global.Blockly.getMainWorkspace=Blockly.getMainWorkspace; goog.global.Blockly.addChangeListener=Blockly.addChangeListener;goog.global.Blockly.removeChangeListener=Blockly.removeChangeListener; \ No newline at end of file diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 4168888a0..8248aa8ca 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -26,14 +26,14 @@ if (!window.goog) { var dir = window.BLOCKLY_DIR.match(/[^\/]+$/)[0]; goog.addDependency("../../../" + dir + "/core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Comment', 'Blockly.Connection', 'Blockly.Input', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.Workspace', 'Blockly.Xml', 'goog.array', 'goog.asserts', 'goog.math.Coordinate', 'goog.string']); goog.addDependency("../../../" + dir + "/core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.ContextMenu', 'goog.asserts', 'goog.dom', 'goog.math.Coordinate', 'goog.Timer']); -goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Realtime', 'Blockly.Toolbox', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.inject', 'Blockly.utils', 'goog.color', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/blockly.js", ['Blockly'], ['Blockly.BlockSvg', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Generator', 'Blockly.Msg', 'Blockly.Procedures', 'Blockly.Realtime', 'Blockly.Toolbox', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.inject', 'Blockly.utils', 'goog.color']); goog.addDependency("../../../" + dir + "/core/blocks.js", ['Blockly.Blocks'], ['goog.asserts']); goog.addDependency("../../../" + dir + "/core/bubble.js", ['Blockly.Bubble'], ['Blockly.Workspace', 'goog.dom', 'goog.math']); goog.addDependency("../../../" + dir + "/core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Icon', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/connection.js", ['Blockly.Connection', 'Blockly.ConnectionDB'], ['goog.dom']); goog.addDependency("../../../" + dir + "/core/contextmenu.js", ['Blockly.ContextMenu'], ['goog.dom', 'goog.events', 'goog.style', 'goog.ui.Menu', 'goog.ui.MenuItem']); goog.addDependency("../../../" + dir + "/core/css.js", ['Blockly.Css'], ['goog.cssom']); -goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['goog.asserts', 'goog.dom', 'goog.math.Size', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/field.js", ['Blockly.Field'], ['goog.asserts', 'goog.dom', 'goog.math.Size', 'goog.style', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/field_angle.js", ['Blockly.FieldAngle'], ['Blockly.FieldTextInput', 'goog.math', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/field_checkbox.js", ['Blockly.FieldCheckbox'], ['Blockly.Field']); goog.addDependency("../../../" + dir + "/core/field_colour.js", ['Blockly.FieldColour'], ['Blockly.Field', 'goog.dom', 'goog.events', 'goog.ui.ColorPicker', 'goog.style']); @@ -63,7 +63,7 @@ goog.addDependency("../../../" + dir + "/core/variables.js", ['Blockly.Variables goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Icon']); goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.dom']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['goog.math']); -goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ScrollbarPair', 'Blockly.Trashcan', 'Blockly.Workspace', 'Blockly.Xml', 'goog.dom', 'goog.math.Coordinate']); +goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ScrollbarPair', 'Blockly.Trashcan', 'Blockly.Workspace', 'Blockly.Xml', 'goog.dom', 'goog.math.Coordinate', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['goog.dom']); goog.addDependency("../../alltests.js", [], []); goog.addDependency("base.js", [], []); diff --git a/blocks/logic.js b/blocks/logic.js index 245589513..37243d330 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -263,7 +263,7 @@ Blockly.Blocks['logic_compare'] = { * @this Blockly.Block */ init: function() { - var OPERATORS = Blockly.RTL ? [ + var OPERATORS = this.RTL ? [ ['=', 'EQ'], ['\u2260', 'NEQ'], ['>', 'LT'], diff --git a/blocks/text.js b/blocks/text.js index 9fe2919f8..b885cfc46 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -50,15 +50,16 @@ Blockly.Blocks['text'] = { * Create an image of an open or closed quote. * @param {boolean} open True if open quote, false if closed. * @return {!Blockly.FieldImage} The field image of the quote. + * @this Blockly.Block * @private */ newQuote_: function(open) { - if (open == Blockly.RTL) { - var file = 'quote1.png'; + if (open == this.RTL) { + var file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAYAAACALL/6AAAA0UlEQVQY023QP0oDURSF8e8MImhlUIiCjWKhrUUK3YCIVkq6bMAF2LkCa8ENWLoNS1sLEQKprMQ/GBDks3kDM+Oc8nfPfTxuANQTYBeYAvdJLL4FnAFfwF2ST9Rz27kp5YH/kwrYp50LdaXHAU4rYNYzWAdeenx7AbgF5sAhcARsAkkyVQ+ACbAKjIGqta4+l78udXxc/LiJG+qvet0pV+q7+tHE+iJzdbGz8FhmOzVcqj/qq7rcKI7Ut1Leq70C1oCrJMMk343HB8ADMEzyVOMff72l48gwfqkAAAAASUVORK5CYII='; } else { - var file = 'quote0.png'; + var file = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAYAAACALL/6AAAAvklEQVQY022PoapCQRRF97lBVDRYhBcEQcP1BwS/QLAqr7xitZn0HzRr8Rts+htmQdCqSbQIwmMZPMIw3lVmZu0zG44UAFSBLdBVBDAFZqFo8eYKtANfBC7AE5h8ZNOHd1FrDnh4VgmDO3ADkujDHPgHfkLZ84bfaLjg/hD6RFLq9z6wBDr+rvuZB1bAEDABY76pA2mGHyWSjvqmIemc4WsCLKOp4nssIj8wD8qS/iSVJK3N7OTeJPV9n72ZbV7iDuSc2BaQBQAAAABJRU5ErkJggg=='; } - return new Blockly.FieldImage(Blockly.pathToMedia + file, 12, 12, '"'); + return new Blockly.FieldImage(file, 12, 12, '"'); } }; @@ -174,10 +175,8 @@ Blockly.Blocks['text_join'] = { // Rebuild block. if (this.itemCount_ == 0) { this.appendDummyInput('EMPTY') - .appendField(new Blockly.FieldImage(Blockly.pathToMedia + - 'quote0.png', 12, 12, '"')) - .appendField(new Blockly.FieldImage(Blockly.pathToMedia + - 'quote1.png', 12, 12, '"')); + .appendField(this.newQuote_(true)) + .appendField(this.newQuote_(false)); } else { for (var i = 0; i < this.itemCount_; i++) { var input = this.appendValueInput('ADD' + i); @@ -186,7 +185,8 @@ Blockly.Blocks['text_join'] = { } } } - } + }, + newQuote_: Blockly.Blocks['text'].newQuote_ }; Blockly.Blocks['text_create_join_container'] = { diff --git a/blocks_compressed.js b/blocks_compressed.js index 6ddcca4d4..fce61ea76 100644 --- a/blocks_compressed.js +++ b/blocks_compressed.js @@ -46,7 +46,7 @@ b=this.appendStatementInput("ELSE");b.appendField(Blockly.Msg.CONTROLS_IF_MSG_EL b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw"Unknown block type.";}a=a.nextConnection&&a.nextConnection.targetBlock()}}};Blockly.Blocks.controls_if_if={init:function(){this.setColour(Blockly.Blocks.logic.HUE);this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF);this.appendStatementInput("STACK");this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP);this.contextMenu=!1}}; Blockly.Blocks.controls_if_elseif={init:function(){this.setColour(Blockly.Blocks.logic.HUE);this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP);this.contextMenu=!1}}; Blockly.Blocks.controls_if_else={init:function(){this.setColour(Blockly.Blocks.logic.HUE);this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE);this.setPreviousStatement(!0);this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP);this.contextMenu=!1}}; -Blockly.Blocks.logic_compare={init:function(){var a=Blockly.RTL?[["=","EQ"],["\u2260","NEQ"],[">","LT"],["\u2265","LTE"],["<","GT"],["\u2264","GTE"]]:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]];this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);this.setColour(Blockly.Blocks.logic.HUE);this.setOutput(!0,"Boolean");this.appendValueInput("A");this.appendValueInput("B").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a= +Blockly.Blocks.logic_compare={init:function(){var a=this.RTL?[["=","EQ"],["\u2260","NEQ"],[">","LT"],["\u2265","LTE"],["<","GT"],["\u2264","GTE"]]:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]];this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);this.setColour(Blockly.Blocks.logic.HUE);this.setOutput(!0,"Boolean");this.appendValueInput("A");this.appendValueInput("B").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a= b.getFieldValue("OP");return{EQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,NEQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,LT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,LTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,GT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,GTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE}[a]});this.prevBlocks_=[null,null]},onchange:function(){if(this.workspace){var a=this.getInputTargetBlock("A"),b=this.getInputTargetBlock("B");if(a&&b&&!a.outputConnection.checkType_(b.outputConnection))for(var c=0;c 1) { goog.dom.removeNode(clone); } else { var x = clone.translateX_ + - (Blockly.RTL ? -1 : 1) * clone.bBox_.width / 2 * percent; + (rtl ? -1 : 1) * clone.bBox_.width / 2 * percent; var y = clone.translateY_ + clone.bBox_.height * percent; var translate = x + ', ' + y; var scale = 1 - percent; clone.setAttribute('transform', 'translate(' + translate + ')' + ' scale(' + scale + ')'); var closure = function() { - Blockly.BlockSvg.disposeUiStep_(clone); + Blockly.BlockSvg.disposeUiStep_(clone, rtl); }; setTimeout(closure, 10); } @@ -1051,22 +1065,22 @@ Blockly.BlockSvg.disposeUiStep_ = function(clone) { * Play some UI effects (sound, ripple) after a connection has been established. */ Blockly.BlockSvg.prototype.connectionUiEffect = function() { - Blockly.playAudio('click'); + this.workspace.playAudio('click'); // Determine the absolute coordinates of the inferior block. var xy = Blockly.getSvgXY_(/** @type {!Element} */ (this.svgGroup_)); // Offset the coordinates based on the two connection types. if (this.outputConnection) { - xy.x += Blockly.RTL ? 3 : -3; + xy.x += this.RTL ? 3 : -3; xy.y += 13; } else if (this.previousConnection) { - xy.x += Blockly.RTL ? -23 : 23; + xy.x += this.RTL ? -23 : 23; xy.y += 3; } var ripple = Blockly.createSvgElement('circle', {'cx': xy.x, 'cy': xy.y, 'r': 0, 'fill': 'none', 'stroke': '#888', 'stroke-width': 10}, - Blockly.svg); + this.workspace.options.svg); // Start the animation. ripple.startDate_ = new Date(); Blockly.BlockSvg.connectionUiStep_(ripple); @@ -1304,7 +1318,7 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { this.rendered = true; var cursorX = Blockly.BlockSvg.SEP_SPACE_X; - if (Blockly.RTL) { + if (this.RTL) { cursorX = -cursorX; } // Move the icons into position. @@ -1312,7 +1326,7 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { for (var x = 0; x < icons.length; x++) { cursorX = icons[x].renderIcon(cursorX); } - cursorX += Blockly.RTL ? + cursorX += this.RTL ? Blockly.BlockSvg.SEP_SPACE_X : -Blockly.BlockSvg.SEP_SPACE_X; // If there are no icons, cursorX will be 0, otherwise it will be the // width that the first label needs to move over by. @@ -1343,7 +1357,7 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) { */ Blockly.BlockSvg.prototype.renderFields_ = function(fieldList, cursorX, cursorY) { - if (Blockly.RTL) { + if (this.RTL) { cursorX = -cursorX; } for (var t = 0, field; field = fieldList[t]; t++) { @@ -1351,7 +1365,7 @@ Blockly.BlockSvg.prototype.renderFields_ = if (!root) { continue; } - if (Blockly.RTL) { + if (this.RTL) { cursorX -= field.renderSep + field.renderWidth; root.setAttribute('transform', 'translate(' + cursorX + ', ' + cursorY + ')'); @@ -1367,7 +1381,7 @@ Blockly.BlockSvg.prototype.renderFields_ = } } } - return Blockly.RTL ? -cursorX : cursorX; + return this.RTL ? -cursorX : cursorX; }; /** @@ -1440,7 +1454,7 @@ Blockly.BlockSvg.prototype.renderCompute_ = function(iconWidth) { input.fieldWidth = 0; if (inputRows.length == 1) { // The first row gets shifted to accommodate any icons. - input.fieldWidth += Blockly.RTL ? -iconWidth : iconWidth; + input.fieldWidth += this.RTL ? -iconWidth : iconWidth; } var previousFieldEditable = false; for (var j = 0, field; field = input.fieldRow[j]; j++) { @@ -1565,7 +1579,7 @@ Blockly.BlockSvg.prototype.renderDraw_ = function(iconWidth, inputRows) { this.svgPathDark_.setAttribute('d', pathString); pathString = highlightSteps.join(' ') + '\n' + highlightInlineSteps.join(' '); this.svgPathLight_.setAttribute('d', pathString); - if (Blockly.RTL) { + if (this.RTL) { // Mirror the block's path. this.svgPath_.setAttribute('transform', 'scale(-1 1)'); this.svgPathLight_.setAttribute('transform', 'scale(-1 1)'); @@ -1589,7 +1603,7 @@ Blockly.BlockSvg.prototype.renderDrawTop_ = highlightSteps.push('m 1,1'); } else { steps.push(Blockly.BlockSvg.TOP_LEFT_CORNER_START); - highlightSteps.push(Blockly.RTL ? + highlightSteps.push(this.RTL ? Blockly.BlockSvg.TOP_LEFT_CORNER_START_HIGHLIGHT_RTL : Blockly.BlockSvg.TOP_LEFT_CORNER_START_HIGHLIGHT_LTR); // Top-left rounded corner. @@ -1604,14 +1618,14 @@ Blockly.BlockSvg.prototype.renderDrawTop_ = steps.push(Blockly.BlockSvg.NOTCH_PATH_LEFT); highlightSteps.push(Blockly.BlockSvg.NOTCH_PATH_LEFT_HIGHLIGHT); // Create previous block connection. - var connectionX = connectionsXY.x + (Blockly.RTL ? + var connectionX = connectionsXY.x + (this.RTL ? -Blockly.BlockSvg.NOTCH_WIDTH : Blockly.BlockSvg.NOTCH_WIDTH); var connectionY = connectionsXY.y; this.previousConnection.moveTo(connectionX, connectionY); // This connection will be tightened when the parent renders. } steps.push('H', rightEdge); - highlightSteps.push('H', rightEdge + (Blockly.RTL ? -1 : 0)); + highlightSteps.push('H', rightEdge + (this.RTL ? -1 : 0)); this.width = rightEdge; }; @@ -1636,7 +1650,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, for (var y = 0, row; row = inputRows[y]; y++) { cursorX = Blockly.BlockSvg.SEP_SPACE_X; if (y == 0) { - cursorX += Blockly.RTL ? -iconWidth : iconWidth; + cursorX += this.RTL ? -iconWidth : iconWidth; } highlightSteps.push('M', (inputRows.rightEdge - 1) + ',' + (cursorY + 1)); if (this.isCollapsed()) { @@ -1646,14 +1660,14 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, var fieldY = cursorY + Blockly.BlockSvg.FIELD_HEIGHT; this.renderFields_(input.fieldRow, fieldX, fieldY); steps.push(Blockly.BlockSvg.JAGGED_TEETH); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('l 8,0 0,3.8 7,3.2 m -14.5,9 l 8,4'); } else { highlightSteps.push('h 8'); } var remainder = row.height - Blockly.BlockSvg.JAGGED_TEETH_HEIGHT; steps.push('v', remainder); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('v', remainder - 2); } this.width += Blockly.BlockSvg.JAGGED_TEETH_WIDTH; @@ -1682,7 +1696,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, inlineSteps.push('h', input.renderWidth + 2 - Blockly.BlockSvg.TAB_WIDTH); inlineSteps.push('z'); - if (Blockly.RTL) { + if (this.RTL) { // Highlight right edge, around back of tab, and bottom. highlightInlineSteps.push('M', (cursorX - Blockly.BlockSvg.SEP_SPACE_X - 3 + @@ -1711,7 +1725,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, (Blockly.BlockSvg.TAB_WIDTH * 0.38) + ',-1.8'); } // Create inline input connection. - if (Blockly.RTL) { + if (this.RTL) { connectionX = connectionsXY.x - cursorX - Blockly.BlockSvg.TAB_WIDTH + Blockly.BlockSvg.SEP_SPACE_X + input.renderWidth + 1; @@ -1732,9 +1746,9 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, cursorX = Math.max(cursorX, inputRows.rightEdge); this.width = Math.max(this.width, cursorX); steps.push('H', cursorX); - highlightSteps.push('H', cursorX + (Blockly.RTL ? -1 : 0)); + highlightSteps.push('H', cursorX + (this.RTL ? -1 : 0)); steps.push('v', row.height); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('v', row.height - 2); } } else if (row.type == Blockly.INPUT_VALUE) { @@ -1755,7 +1769,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, steps.push(Blockly.BlockSvg.TAB_PATH_DOWN); var v = row.height - Blockly.BlockSvg.TAB_HEIGHT; steps.push('v', v); - if (Blockly.RTL) { + if (this.RTL) { // Highlight around back of tab. highlightSteps.push(Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL); highlightSteps.push('v', v); @@ -1768,7 +1782,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, } // Create external input connection. connectionX = connectionsXY.x + - (Blockly.RTL ? -inputRows.rightEdge - 1 : inputRows.rightEdge + 1); + (this.RTL ? -inputRows.rightEdge - 1 : inputRows.rightEdge + 1); connectionY = connectionsXY.y + cursorY; input.connection.moveTo(connectionX, connectionY); if (input.connection.targetConnection) { @@ -1796,7 +1810,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, } this.renderFields_(input.fieldRow, fieldX, fieldY); steps.push('v', row.height); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('v', row.height - 2); } } else if (row.type == Blockly.NEXT_STATEMENT) { @@ -1805,7 +1819,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, if (y == 0) { // If the first input is a statement stack, add a small row on top. steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('v', Blockly.BlockSvg.SEP_SPACE_Y - 1); } cursorY += Blockly.BlockSvg.SEP_SPACE_Y; @@ -1828,7 +1842,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, steps.push('v', row.height - 2 * Blockly.BlockSvg.CORNER_RADIUS); steps.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER); steps.push('H', inputRows.rightEdge); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('M', (cursorX - Blockly.BlockSvg.NOTCH_WIDTH + Blockly.BlockSvg.DISTANCE_45_OUTSIDE) + @@ -1850,7 +1864,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, highlightSteps.push('H', inputRows.rightEdge); } // Create statement connection. - connectionX = connectionsXY.x + (Blockly.RTL ? -cursorX : cursorX); + connectionX = connectionsXY.x + (this.RTL ? -cursorX : cursorX); connectionY = connectionsXY.y + cursorY + 1; input.connection.moveTo(connectionX, connectionY); if (input.connection.targetConnection) { @@ -1863,7 +1877,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, // If the final input is a statement stack, add a small row underneath. // Consecutive statement stacks are also separated by a small divider. steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('v', Blockly.BlockSvg.SEP_SPACE_Y - 1); } cursorY += Blockly.BlockSvg.SEP_SPACE_Y; @@ -1874,7 +1888,7 @@ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, highlightSteps, if (!inputRows.length) { cursorY = Blockly.BlockSvg.MIN_BLOCK_Y; steps.push('V', cursorY); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('V', cursorY - 1); } } @@ -1897,7 +1911,7 @@ Blockly.BlockSvg.prototype.renderDrawBottom_ = Blockly.BlockSvg.NOTCH_PATH_RIGHT); // Create next block connection. var connectionX; - if (Blockly.RTL) { + if (this.RTL) { connectionX = connectionsXY.x - Blockly.BlockSvg.NOTCH_WIDTH; } else { connectionX = connectionsXY.x + Blockly.BlockSvg.NOTCH_WIDTH; @@ -1913,7 +1927,7 @@ Blockly.BlockSvg.prototype.renderDrawBottom_ = // Should the bottom-left corner be rounded or square? if (this.squareBottomLeftCorner_) { steps.push('H 0'); - if (!Blockly.RTL) { + if (!this.RTL) { highlightSteps.push('M', '1,' + cursorY); } } else { @@ -1922,7 +1936,7 @@ Blockly.BlockSvg.prototype.renderDrawBottom_ = Blockly.BlockSvg.CORNER_RADIUS + ' 0 0,1 -' + Blockly.BlockSvg.CORNER_RADIUS + ',-' + Blockly.BlockSvg.CORNER_RADIUS); - if (!Blockly.RTL) { + if (!this.RTL) { highlightSteps.push('M', Blockly.BlockSvg.DISTANCE_45_INSIDE + ',' + (cursorY - Blockly.BlockSvg.DISTANCE_45_INSIDE)); highlightSteps.push('A', (Blockly.BlockSvg.CORNER_RADIUS - 1) + ',' + @@ -1950,7 +1964,7 @@ Blockly.BlockSvg.prototype.renderDrawLeft_ = steps.push('c 0,-10 -' + Blockly.BlockSvg.TAB_WIDTH + ',8 -' + Blockly.BlockSvg.TAB_WIDTH + ',-7.5 s ' + Blockly.BlockSvg.TAB_WIDTH + ',2.5 ' + Blockly.BlockSvg.TAB_WIDTH + ',-7.5'); - if (Blockly.RTL) { + if (this.RTL) { highlightSteps.push('M', (Blockly.BlockSvg.TAB_WIDTH * -0.3) + ',8.9'); highlightSteps.push('l', (Blockly.BlockSvg.TAB_WIDTH * -0.45) + ',-2.1'); } else { @@ -1962,7 +1976,7 @@ Blockly.BlockSvg.prototype.renderDrawLeft_ = ',1 V 1 H 2'); } this.width += Blockly.BlockSvg.TAB_WIDTH; - } else if (!Blockly.RTL) { + } else if (!this.RTL) { if (this.squareTopLeftCorner_) { highlightSteps.push('V', 1); } else { diff --git a/core/blockly.js b/core/blockly.js index fd81c2854..34fe911df 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -51,15 +51,8 @@ goog.require('Blockly.utils'); // Closure dependencies. goog.require('goog.color'); -goog.require('goog.userAgent'); -/** - * Path to Blockly's media directory. Can be relative, absolute, or remote. - * Used for loading sounds and sprites. Defaults to demo server. - */ -Blockly.pathToMedia = 'https://blockly-demo.appspot.com/static/media/'; - /** * Required name space for SVG elements. * @const @@ -153,26 +146,12 @@ Blockly.OPPOSITE_TYPE[Blockly.OUTPUT_VALUE] = Blockly.INPUT_VALUE; Blockly.OPPOSITE_TYPE[Blockly.NEXT_STATEMENT] = Blockly.PREVIOUS_STATEMENT; Blockly.OPPOSITE_TYPE[Blockly.PREVIOUS_STATEMENT] = Blockly.NEXT_STATEMENT; -/** - * Database of pre-loaded sounds. - * @private - * @const - */ -Blockly.SOUNDS_ = Object.create(null); - /** * Currently selected block. * @type {Blockly.Block} */ Blockly.selected = null; -/** - * Is Blockly in a read-only, non-editable mode? - * Note that this property may only be set before init is called. - * It can't be used to dynamically toggle editability on and off. - */ -Blockly.readOnly = false; - /** * Currently highlighted connection (during a drag). * @type {Blockly.Connection} @@ -213,7 +192,8 @@ Blockly.COLLAPSE_CHARS = 30; Blockly.LONGPRESS = 750; /** - * The main workspace (defined by inject.js). + * The main workspace most recently used. + * Set by Blockly.WorkspaceSvg.prototype.markFocused * @type {Blockly.Workspace} */ Blockly.mainWorkspace = null; @@ -223,7 +203,14 @@ Blockly.mainWorkspace = null; * @type {Element} * @private */ -Blockly.clipboard_ = null; +Blockly.clipboardXml_ = null; + +/** + * Source of the local clipboard. + * @type {Blockly.Workspace} + * @private + */ +Blockly.clipboardSource_ = null; /** * Is the mouse dragging a block? @@ -242,21 +229,31 @@ Blockly.dragMode_ = 0; Blockly.onTouchUpWrapper_ = null; /** - * Returns the dimensions of the current SVG image. + * Returns the dimensions of the specified SVG image. + * @param {!Element} svg SVG image. * @return {!Object} Contains width and height properties. */ -Blockly.svgSize = function() { - return {width: Blockly.svg.cachedWidth_, - height: Blockly.svg.cachedHeight_}; +Blockly.svgSize = function(svg) { + return {width: svg.cachedWidth_, + height: svg.cachedHeight_}; }; /** * Size the SVG image to completely fill its container. * Record the height/width of the SVG image. + * @param {!Blockly.WorkspaceSvg} workspace Any workspace in the SVG. */ -Blockly.svgResize = function() { - var svg = Blockly.svg; +Blockly.svgResize = function(workspace) { + var mainWorkspace = workspace; + while (mainWorkspace.options.parentWorkspace) { + mainWorkspace = mainWorkspace.options.parentWorkspace; + } + var svg = mainWorkspace.options.svg; var div = svg.parentNode; + if (!div) { + // Workspace deteted, or something. + return; + } var width = div.offsetWidth; var height = div.offsetHeight; if (svg.cachedWidth_ != width) { @@ -268,56 +265,8 @@ Blockly.svgResize = function() { svg.cachedHeight_ = height; } // Update the scrollbars (if they exist). - if (Blockly.mainWorkspace.scrollbar) { - Blockly.mainWorkspace.scrollbar.resize(); - } -}; - -/** - * Handle a mouse-down on SVG drawing surface. - * @param {!Event} e Mouse down event. - * @private - */ -Blockly.onMouseDown_ = function(e) { - Blockly.svgResize(); - Blockly.terminateDrag_(); // In case mouse-up event was lost. - Blockly.hideChaff(); - var isTargetSvg = e.target && e.target.nodeName && - (e.target.nodeName.toLowerCase() == 'svg' || - e.target == Blockly.mainWorkspace.svgBackground_); - if (!Blockly.readOnly && Blockly.selected && isTargetSvg) { - // Clicking on the document clears the selection. - Blockly.selected.unselect(); - } - if ((e.target == Blockly.svg || - e.target == Blockly.mainWorkspace.svgBackground_) && - Blockly.isRightButton(e)) { - // Right-click on main workspace (not in a mutator). - Blockly.showContextMenu_(e); - } else if ((Blockly.readOnly || isTargetSvg) && - Blockly.mainWorkspace.scrollbar) { - Blockly.removeAllRanges(); - // If the workspace is editable, only allow dragging when gripping empty - // space. Otherwise, allow dragging when gripping anywhere. - Blockly.mainWorkspace.dragMode = true; - // Record the current mouse position. - Blockly.mainWorkspace.startDragMouseX = e.clientX; - Blockly.mainWorkspace.startDragMouseY = e.clientY; - Blockly.mainWorkspace.startDragMetrics = - Blockly.mainWorkspace.getMetrics(); - Blockly.mainWorkspace.startScrollX = Blockly.mainWorkspace.scrollX; - Blockly.mainWorkspace.startScrollY = Blockly.mainWorkspace.scrollY; - - // If this is a touch event then bind to the mouseup so workspace drag mode - // is turned off and double move events are not performed on a block. - // See comment in inject.js Blockly.init_ as to why mouseup events are - // bound to the document instead of the SVG's surface. - if ('mouseup' in Blockly.bindEvent_.TOUCH_MAP) { - Blockly.onTouchUpWrapper_ = - Blockly.bindEvent_(document, 'mouseup', null, Blockly.onMouseUp_); - } - Blockly.onMouseMoveWrapper_ = - Blockly.bindEvent_(document, 'mousemove', null, Blockly.onMouseMove_); + if (mainWorkspace.scrollbar) { + mainWorkspace.scrollbar.resize(); } }; @@ -327,8 +276,9 @@ Blockly.onMouseDown_ = function(e) { * @private */ Blockly.onMouseUp_ = function(e) { + var workspace = Blockly.getMainWorkspace(); Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN); - Blockly.mainWorkspace.dragMode = false; + workspace.isScrolling = false; // Unbind the touch event if it exists. if (Blockly.onTouchUpWrapper_) { @@ -347,13 +297,14 @@ Blockly.onMouseUp_ = function(e) { * @private */ Blockly.onMouseMove_ = function(e) { - if (Blockly.mainWorkspace.dragMode) { + var workspace = Blockly.getMainWorkspace(); + if (workspace.isScrolling) { Blockly.removeAllRanges(); - var dx = e.clientX - Blockly.mainWorkspace.startDragMouseX; - var dy = e.clientY - Blockly.mainWorkspace.startDragMouseY; - var metrics = Blockly.mainWorkspace.startDragMetrics; - var x = Blockly.mainWorkspace.startScrollX + dx; - var y = Blockly.mainWorkspace.startScrollY + dy; + var dx = e.clientX - workspace.startDragMouseX; + var dy = e.clientY - workspace.startDragMouseY; + var metrics = workspace.startDragMetrics; + var x = workspace.startScrollX + dx; + var y = workspace.startScrollY + dy; x = Math.min(x, -metrics.contentLeft); y = Math.min(y, -metrics.contentTop); x = Math.max(x, metrics.viewWidth - metrics.contentLeft - @@ -362,7 +313,7 @@ Blockly.onMouseMove_ = function(e) { metrics.contentHeight); // Move the scrollbars and the page will scroll automatically. - Blockly.mainWorkspace.scrollbar.set(-x - metrics.contentLeft, + workspace.scrollbar.set(-x - metrics.contentLeft, -y - metrics.contentTop); // Cancel the long-press if the drag has moved too far. var dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); @@ -383,7 +334,6 @@ Blockly.onKeyDown_ = function(e) { // When focused on an HTML text input widget, don't trap any keys. return; } - // TODO: Add keyboard support for cursoring around the context menu. if (e.keyCode == 27) { // Pressing esc closes the context menu. Blockly.hideChaff(); @@ -402,8 +352,7 @@ Blockly.onKeyDown_ = function(e) { } } else if (e.altKey || e.ctrlKey || e.metaKey) { if (Blockly.selected && - Blockly.selected.isDeletable() && Blockly.selected.isMovable() && - Blockly.selected.workspace == Blockly.mainWorkspace) { + Blockly.selected.isDeletable() && Blockly.selected.isMovable()) { Blockly.hideChaff(); if (e.keyCode == 67) { // 'c' for copy. @@ -416,8 +365,8 @@ Blockly.onKeyDown_ = function(e) { } if (e.keyCode == 86) { // 'v' for paste. - if (Blockly.clipboard_) { - Blockly.mainWorkspace.paste(Blockly.clipboard_); + if (Blockly.clipboardXml_) { + Blockly.clipboardSource_.paste(Blockly.clipboardXml_); } } } @@ -483,74 +432,10 @@ Blockly.copy_ = function(block) { Blockly.Xml.deleteNext(xmlBlock); // Encode start position in XML. var xy = block.getRelativeToSurfaceXY(); - xmlBlock.setAttribute('x', Blockly.RTL ? -xy.x : xy.x); + xmlBlock.setAttribute('x', block.RTL ? -xy.x : xy.x); xmlBlock.setAttribute('y', xy.y); - Blockly.clipboard_ = xmlBlock; -}; - -/** - * Show the context menu for the workspace. - * @param {!Event} e Mouse event. - * @private - */ -Blockly.showContextMenu_ = function(e) { - if (Blockly.readOnly) { - return; - } - var options = []; - // Add a little animation to collapsing and expanding. - var COLLAPSE_DELAY = 10; - - if (Blockly.collapse) { - var hasCollapsedBlocks = false; - var hasExpandedBlocks = false; - var topBlocks = Blockly.mainWorkspace.getTopBlocks(false); - for (var i = 0; i < topBlocks.length; i++) { - var block = topBlocks[i]; - while (block) { - if (block.isCollapsed()) { - hasCollapsedBlocks = true; - } else { - hasExpandedBlocks = true; - } - block = block.getNextBlock(); - } - } - - // Option to collapse top blocks. - var collapseOption = {enabled: hasExpandedBlocks}; - collapseOption.text = Blockly.Msg.COLLAPSE_ALL; - collapseOption.callback = function() { - var ms = 0; - for (var i = 0; i < topBlocks.length; i++) { - var block = topBlocks[i]; - while (block) { - setTimeout(block.setCollapsed.bind(block, true), ms); - block = block.getNextBlock(); - ms += COLLAPSE_DELAY; - } - } - }; - options.push(collapseOption); - - // Option to expand top blocks. - var expandOption = {enabled: hasCollapsedBlocks}; - expandOption.text = Blockly.Msg.EXPAND_ALL; - expandOption.callback = function() { - var ms = 0; - for (var i = 0; i < topBlocks.length; i++) { - var block = topBlocks[i]; - while (block) { - setTimeout(block.setCollapsed.bind(block, false), ms); - block = block.getNextBlock(); - ms += COLLAPSE_DELAY; - } - } - }; - options.push(expandOption); - } - - Blockly.ContextMenu.show(e, options); + Blockly.clipboardXml_ = xmlBlock; + Blockly.clipboardSource_ = block.workspace; }; /** @@ -572,11 +457,13 @@ Blockly.onContextMenu_ = function(e) { Blockly.hideChaff = function(opt_allowToolbox) { Blockly.Tooltip.hide(); Blockly.WidgetDiv.hide(); - if (!opt_allowToolbox && - Blockly.mainWorkspace.toolbox_ && - Blockly.mainWorkspace.toolbox_.flyout_ && - Blockly.mainWorkspace.toolbox_.flyout_.autoClose) { - Blockly.mainWorkspace.toolbox_.clearSelection(); + if (!opt_allowToolbox) { + var workspace = Blockly.getMainWorkspace(); + if (workspace.toolbox_ && + workspace.toolbox_.flyout_ && + workspace.toolbox_.flyout_.autoClose) { + workspace.toolbox_.clearSelection(); + } } }; @@ -600,91 +487,6 @@ Blockly.removeAllRanges = function() { } }; -/** - * Is this event targeting a text input widget? - * @param {!Event} e An event. - * @return {boolean} True if text input. - * @private - */ -Blockly.isTargetInput_ = function(e) { - return e.target.type == 'textarea' || e.target.type == 'text' || - e.target.type == 'number' || e.target.type == 'email' || - e.target.type == 'password' || e.target.type == 'search' || - e.target.type == 'tel' || e.target.type == 'url'; -}; - -/** - * Load an audio file. Cache it, ready for instantaneous playing. - * @param {!Array.} filenames List of file types in decreasing order of - * preference (i.e. increasing size). E.g. ['media/go.mp3', 'media/go.wav'] - * Filenames include path from Blockly's root. File extensions matter. - * @param {string} name Name of sound. - * @private - */ -Blockly.loadAudio_ = function(filenames, name) { - if (!window['Audio'] || !filenames.length) { - // No browser support for Audio. - return; - } - var sound; - var audioTest = new window['Audio'](); - for (var i = 0; i < filenames.length; i++) { - var filename = filenames[i]; - var ext = filename.match(/\.(\w+)$/); - if (ext && audioTest.canPlayType('audio/' + ext[1])) { - // Found an audio format we can play. - sound = new window['Audio'](filename); - break; - } - } - if (sound && sound.play) { - Blockly.SOUNDS_[name] = sound; - } -}; - -/** - * Preload all the audio files so that they play quickly when asked for. - * @private - */ -Blockly.preloadAudio_ = function() { - for (var name in Blockly.SOUNDS_) { - var sound = Blockly.SOUNDS_[name]; - sound.volume = .01; - sound.play(); - sound.pause(); - // iOS can only process one sound at a time. Trying to load more than one - // corrupts the earlier ones. Just load one and leave the others uncached. - if (goog.userAgent.IPAD || goog.userAgent.IPHONE) { - break; - } - } -}; - -/** - * Play an audio file at specified value. If volume is not specified, - * use full volume (1). - * @param {string} name Name of sound. - * @param {?number} opt_volume Volume of sound (0-1). - */ -Blockly.playAudio = function(name, opt_volume) { - var sound = Blockly.SOUNDS_[name]; - if (sound) { - var mySound; - var ie9 = goog.userAgent.DOCUMENT_MODE && - goog.userAgent.DOCUMENT_MODE === 9; - if (ie9 || goog.userAgent.IPAD || goog.userAgent.ANDROID) { - // Creating a new audio node causes lag in IE9, Android and iPad. Android - // and IE9 refetch the file from the server, iPad uses a singleton audio - // node which must be deleted and recreated for each new audio tag. - mySound = sound; - } else { - mySound = sound.cloneNode(); - } - mySound.volume = (opt_volume === undefined ? 1 : opt_volume); - mySound.play(); - } -}; - /** * Return an object with all the metrics required to size scrollbars for the * main workspace. The following properties are computed: @@ -700,26 +502,29 @@ Blockly.playAudio = function(name, opt_volume) { * .absoluteLeft: Left-edge of view. * @return {Object} Contains size and position metrics of main workspace. * @private + * @this Blockly.WorkspaceSvg */ Blockly.getMainWorkspaceMetrics_ = function() { - var svgSize = Blockly.svgSize(); - if (Blockly.mainWorkspace.toolbox_) { - svgSize.width -= Blockly.mainWorkspace.toolbox_.width; + var svgSize = Blockly.svgSize(this.options.svg); + if (this.toolbox_) { + svgSize.width -= this.toolbox_.width; } var viewWidth = svgSize.width - Blockly.Scrollbar.scrollbarThickness; var viewHeight = svgSize.height - Blockly.Scrollbar.scrollbarThickness; try { - var blockBox = Blockly.mainWorkspace.getCanvas().getBBox(); + var blockBox = this.getCanvas().getBBox(); } catch (e) { // Firefox has trouble with hidden elements (Bug 528969). return null; } - if (Blockly.mainWorkspace.scrollbar) { + if (this.scrollbar) { // Add a border around the content that is at least half a screenful wide. // Ensure border is wide enough that blocks can scroll over entire screen. var MARGIN = 5; - var leftScroll = Blockly.RTL ? Blockly.Scrollbar.scrollbarThickness : 0; - var rightScroll = Blockly.RTL ? 0 : Blockly.Scrollbar.scrollbarThickness; + var leftScroll = this.RTL ? + Blockly.Scrollbar.scrollbarThickness : 0; + var rightScroll = this.RTL ? + 0 : Blockly.Scrollbar.scrollbarThickness; var leftEdge = Math.min(blockBox.x - viewWidth / 2, blockBox.x + blockBox.width - viewWidth - leftScroll + MARGIN); var rightEdge = Math.max(blockBox.x + blockBox.width + viewWidth / 2, @@ -736,16 +541,16 @@ Blockly.getMainWorkspaceMetrics_ = function() { var bottomEdge = topEdge + blockBox.height; } var absoluteLeft = 0; - if (!Blockly.RTL && Blockly.mainWorkspace.toolbox_) { - absoluteLeft = Blockly.mainWorkspace.toolbox_.width; + if (!this.RTL && this.toolbox_) { + absoluteLeft = this.toolbox_.width; } var metrics = { viewHeight: svgSize.height, viewWidth: svgSize.width, contentHeight: bottomEdge - topEdge, contentWidth: rightEdge - leftEdge, - viewTop: -Blockly.mainWorkspace.scrollY, - viewLeft: -Blockly.mainWorkspace.scrollX, + viewTop: -this.scrollY, + viewLeft: -this.scrollX, contentTop: topEdge, contentLeft: leftEdge, absoluteTop: 0, @@ -759,25 +564,28 @@ Blockly.getMainWorkspaceMetrics_ = function() { * @param {!Object} xyRatio Contains an x and/or y property which is a float * between 0 and 1 specifying the degree of scrolling. * @private + * @this Blockly.WorkspaceSvg */ Blockly.setMainWorkspaceMetrics_ = function(xyRatio) { - if (!Blockly.mainWorkspace.scrollbar) { + if (!this.scrollbar) { throw 'Attempt to set main workspace scroll without scrollbars.'; } - var metrics = Blockly.getMainWorkspaceMetrics_(); + var metrics = this.getMetrics(); if (goog.isNumber(xyRatio.x)) { - Blockly.mainWorkspace.scrollX = -metrics.contentWidth * xyRatio.x - + this.scrollX = -metrics.contentWidth * xyRatio.x - metrics.contentLeft; } if (goog.isNumber(xyRatio.y)) { - Blockly.mainWorkspace.scrollY = -metrics.contentHeight * xyRatio.y - + this.scrollY = -metrics.contentHeight * xyRatio.y - metrics.contentTop; } - var x = Blockly.mainWorkspace.scrollX + metrics.absoluteLeft; - var y = Blockly.mainWorkspace.scrollY + metrics.absoluteTop; - Blockly.mainWorkspace.translate(x, y); - Blockly.mainWorkspacePattern_.setAttribute('x', x); - Blockly.mainWorkspacePattern_.setAttribute('y', y); + var x = this.scrollX + metrics.absoluteLeft; + var y = this.scrollY + metrics.absoluteTop; + this.translate(x, y); + if (this.options.gridPattern) { + this.options.gridPattern.setAttribute('x', x); + this.options.gridPattern.setAttribute('y', y); + } }; /** @@ -801,22 +609,18 @@ Blockly.doCommand = function(cmdThunk) { * @param {!Function} func Function to call. * @return {!Array.} Opaque data that can be passed to * removeChangeListener. + * @deprecated April 2015 */ Blockly.addChangeListener = function(func) { - return Blockly.bindEvent_(Blockly.mainWorkspace.getCanvas(), - 'blocklyWorkspaceChange', null, func); + // Backwards compatability from before there could be multiple workspaces. + console.warn('Deprecated call to Blockly.addChangeListener, ' + + 'use workspace.addChangeListener instead.'); + return Blockly.getMainWorkspace().addChangeListener(func); }; /** - * Stop listening for Blockly's workspace changes. - * @param {!Array.} bindData Opaque data from addChangeListener. - */ -Blockly.removeChangeListener = function(bindData) { - Blockly.unbindEvent_(bindData); -}; - -/** - * Returns the main workspace. + * Returns the main workspace. Returns the last used main workspace (based on + * focus). * @return {!Blockly.Workspace} The main workspace. */ Blockly.getMainWorkspace = function() { diff --git a/core/bubble.js b/core/bubble.js index c662fcb2b..740b1e7a0 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -46,15 +46,16 @@ goog.require('goog.math'); Blockly.Bubble = function(workspace, content, shape, anchorX, anchorY, bubbleWidth, bubbleHeight) { + this.workspace_ = workspace; + this.content_ = content; + this.shape_ = shape; + var angle = Blockly.Bubble.ARROW_ANGLE; - if (Blockly.RTL) { + if (this.workspace_.RTL) { angle = -angle; } this.arrow_radians_ = goog.math.toRadians(angle); - this.workspace_ = workspace; - this.content_ = content; - this.shape_ = shape; var canvas = workspace.getBubbleCanvas(); canvas.appendChild(this.createDom_(content, !!(bubbleWidth && bubbleHeight))); @@ -71,7 +72,7 @@ Blockly.Bubble = function(workspace, content, shape, this.renderArrow_(); this.rendered_ = true; - if (!Blockly.readOnly) { + if (!workspace.options.readOnly) { Blockly.bindEvent_(this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_); if (this.resizeGroup_) { @@ -217,7 +218,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { bubbleEmboss); if (hasResize) { this.resizeGroup_ = Blockly.createSvgElement('g', - {'class': Blockly.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, + {'class': this.workspace_.RTL ? + 'blocklyResizeSW' : 'blocklyResizeSE'}, this.bubbleGroup_); var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; Blockly.createSvgElement('polygon', @@ -247,7 +249,8 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { this.promote_(); Blockly.Bubble.unbindDragEvents_(); if (Blockly.isRightButton(e)) { - // Right-click. + // No right-click. + e.stopPropagation(); return; } else if (Blockly.isTargetInput_(e)) { // When focused on an HTML text input widget, don't trap any events. @@ -256,7 +259,7 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { // Left-click (or middle click) Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED); // Record the starting offset between the current location and the mouse. - if (Blockly.RTL) { + if (this.workspace_.RTL) { this.dragDeltaX = this.relativeLeft_ + e.clientX; } else { this.dragDeltaX = this.relativeLeft_ - e.clientX; @@ -279,7 +282,7 @@ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { */ Blockly.Bubble.prototype.bubbleMouseMove_ = function(e) { this.autoLayout_ = false; - if (Blockly.RTL) { + if (this.workspace_.RTL) { this.relativeLeft_ = this.dragDeltaX - e.clientX; } else { this.relativeLeft_ = this.dragDeltaX + e.clientX; @@ -298,13 +301,14 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { this.promote_(); Blockly.Bubble.unbindDragEvents_(); if (Blockly.isRightButton(e)) { - // Right-click. + // No right-click. + e.stopPropagation(); return; } // Left-click (or middle click) Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED); // Record the starting offset between the current location and the mouse. - if (Blockly.RTL) { + if (this.workspace_.RTL) { this.resizeDeltaWidth = this.width_ + e.clientX; } else { this.resizeDeltaWidth = this.width_ - e.clientX; @@ -329,7 +333,7 @@ Blockly.Bubble.prototype.resizeMouseMove_ = function(e) { this.autoLayout_ = false; var w = this.resizeDeltaWidth; var h = this.resizeDeltaHeight + e.clientY; - if (Blockly.RTL) { + if (this.workspace_.RTL) { // RTL drags the bottom-left corner. w -= e.clientX; } else { @@ -337,7 +341,7 @@ Blockly.Bubble.prototype.resizeMouseMove_ = function(e) { w += e.clientX; } this.setBubbleSize(w, h); - if (Blockly.RTL) { + if (this.workspace_.RTL) { // RTL requires the bubble to move its left edge. this.positionBubble_(); } @@ -385,7 +389,7 @@ Blockly.Bubble.prototype.layoutBubble_ = function() { var relativeTop = -this.height_ - Blockly.BlockSvg.MIN_BLOCK_Y; // Prevent the bubble from being off-screen. var metrics = this.workspace_.getMetrics(); - if (Blockly.RTL) { + if (this.workspace_.RTL) { if (this.anchorX_ - metrics.viewLeft - relativeLeft - this.width_ < Blockly.Scrollbar.scrollbarThickness) { // Slide the bubble right until it is onscreen. @@ -424,7 +428,7 @@ Blockly.Bubble.prototype.layoutBubble_ = function() { */ Blockly.Bubble.prototype.positionBubble_ = function() { var left; - if (Blockly.RTL) { + if (this.workspace_.RTL) { left = this.anchorX_ - this.relativeLeft_ - this.width_; } else { left = this.anchorX_ + this.relativeLeft_; @@ -457,7 +461,7 @@ Blockly.Bubble.prototype.setBubbleSize = function(width, height) { this.bubbleBack_.setAttribute('width', width); this.bubbleBack_.setAttribute('height', height); if (this.resizeGroup_) { - if (Blockly.RTL) { + if (this.workspace_.RTL) { // Mirror the resize group. var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; this.resizeGroup_.setAttribute('transform', 'translate(' + @@ -500,7 +504,7 @@ Blockly.Bubble.prototype.renderArrow_ = function() { // Compute the angle of the arrow's line. var rise = relAnchorY - relBubbleY; var run = relAnchorX - relBubbleX; - if (Blockly.RTL) { + if (this.workspace_.RTL) { run *= -1; } var hypotenuse = Math.sqrt(rise * rise + run * run); diff --git a/core/comment.js b/core/comment.js index f1ca17cf8..4fc860e41 100644 --- a/core/comment.js +++ b/core/comment.js @@ -90,7 +90,7 @@ Blockly.Comment.prototype.createEditor_ = function() { body.className = 'blocklyMinimalBody'; this.textarea_ = document.createElementNS(Blockly.HTML_NS, 'textarea'); this.textarea_.className = 'blocklyCommentTextarea'; - this.textarea_.setAttribute('dir', Blockly.RTL ? 'RTL' : 'LTR'); + this.textarea_.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR'); body.appendChild(this.textarea_); this.foreignObject_.appendChild(body); Blockly.bindEvent_(this.textarea_, 'mouseup', this, this.textareaFocus_); diff --git a/core/connection.js b/core/connection.js index 500142d6d..e85ec08fa 100644 --- a/core/connection.js +++ b/core/connection.js @@ -305,7 +305,7 @@ Blockly.Connection.prototype.bumpAwayFrom_ = function(staticConnection) { // When reversing a bump due to an uneditable block, bump up. dy = -dy; } - if (Blockly.RTL) { + if (rootBlock.RTL) { dx = -dx; } rootBlock.moveBy(dx, dy); @@ -344,12 +344,12 @@ Blockly.Connection.prototype.moveBy = function(dx, dy) { Blockly.Connection.prototype.highlight = function() { var steps; if (this.type == Blockly.INPUT_VALUE || this.type == Blockly.OUTPUT_VALUE) { - var tabWidth = Blockly.RTL ? -Blockly.BlockSvg.TAB_WIDTH : - Blockly.BlockSvg.TAB_WIDTH; + var tabWidth = this.sourceBlock_.RTL ? -Blockly.BlockSvg.TAB_WIDTH : + Blockly.BlockSvg.TAB_WIDTH; steps = 'm 0,0 v 5 c 0,10 ' + -tabWidth + ',-8 ' + -tabWidth + ',7.5 s ' + tabWidth + ',-2.5 ' + tabWidth + ',7.5 v 5'; } else { - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { steps = 'm 20,0 h -5 ' + Blockly.BlockSvg.NOTCH_PATH_RIGHT + ' h -5'; } else { steps = 'm -20,0 h 5 ' + Blockly.BlockSvg.NOTCH_PATH_LEFT + ' h 5'; diff --git a/core/contextmenu.js b/core/contextmenu.js index 93731f06f..55a41be81 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -43,9 +43,10 @@ Blockly.ContextMenu.currentBlock = null; * Construct the menu based on the list of options and show the menu. * @param {!Event} e Mouse event. * @param {!Array.} options Array of menu options. + * @param {boolean} rtl True if RTL, false if LTR. */ -Blockly.ContextMenu.show = function(e, options) { - Blockly.WidgetDiv.show(Blockly.ContextMenu, null); +Blockly.ContextMenu.show = function(e, options, rtl) { + Blockly.WidgetDiv.show(Blockly.ContextMenu, rtl, null); if (!options.length) { Blockly.ContextMenu.hide(); return; @@ -56,8 +57,10 @@ Blockly.ContextMenu.show = function(e, options) { callback: Blockly.MakeItSo} */ var menu = new goog.ui.Menu(); + menu.setRightToLeft(rtl); for (var x = 0, option; option = options[x]; x++) { var menuItem = new goog.ui.MenuItem(option.text); + menuItem.setRightToLeft(rtl); menu.addChild(menuItem, true); menuItem.setEnabled(option.enabled); if (option.enabled) { @@ -88,7 +91,7 @@ Blockly.ContextMenu.show = function(e, options) { y -= menuSize.height; } // Flip menu horizontally if off the edge. - if (Blockly.RTL) { + if (rtl) { if (menuSize.width >= e.clientX) { x += menuSize.width; } @@ -97,7 +100,7 @@ Blockly.ContextMenu.show = function(e, options) { x -= menuSize.width; } } - Blockly.WidgetDiv.position(x, y, windowSize, scrollOffset); + Blockly.WidgetDiv.position(x, y, windowSize, scrollOffset, rtl); menu.setAllowAutoFocus(true); // 1ms delay is required for focusing on context menus because some other @@ -126,7 +129,7 @@ Blockly.ContextMenu.callbackFactory = function(block, xml) { var newBlock = Blockly.Xml.domToBlock(block.workspace, xml); // Move the new block next to the old block. var xy = block.getRelativeToSurfaceXY(); - if (Blockly.RTL) { + if (block.RTL) { xy.x -= Blockly.SNAP_RADIUS; } else { xy.x += Blockly.SNAP_RADIUS; diff --git a/core/css.js b/core/css.js index 451efee02..9782a1b15 100644 --- a/core/css.js +++ b/core/css.js @@ -66,15 +66,22 @@ Blockly.Css.mediaPath_ = ''; * a) It loads synchronously and doesn't force a redraw later. * b) It speeds up loading by not blocking on a separate HTTP transfer. * c) The CSS content may be made dynamic depending on init options. + * @param {boolean} hasCss If false, don't inject CSS + * (providing CSS becomes the document's responsibility). + * @param {string} pathToMedia Path from page to the Blockly media directory. */ -Blockly.Css.inject = function() { +Blockly.Css.inject = function(hasCss, pathToMedia) { + // Only inject the CSS once. + if (Blockly.Css.styleSheet_) { + return; + } // Placeholder for cursor rule. Must be first rule (index 0). var text = '.blocklyDraggable {}\n'; - if (Blockly.hasCss) { + if (hasCss) { text += Blockly.Css.CONTENT.join('\n'); } // Strip off any trailing slash (either Unix or Windows). - Blockly.Css.mediaPath_ = Blockly.pathToMedia.replace(/[\\\/]$/, ''); + Blockly.Css.mediaPath_ = pathToMedia.replace(/[\\\/]$/, ''); text = text.replace(/<<>>/g, Blockly.Css.mediaPath_); Blockly.Css.styleSheet_ = goog.cssom.addCssText(text).sheet; Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN); @@ -85,7 +92,7 @@ Blockly.Css.inject = function() { * @param {Blockly.Cursor} cursor Enum. */ Blockly.Css.setCursor = function(cursor) { - if (Blockly.readOnly || Blockly.Css.currentCursor_ == cursor) { + if (Blockly.Css.currentCursor_ == cursor) { return; } Blockly.Css.currentCursor_ = cursor; @@ -114,14 +121,13 @@ Blockly.Css.setCursor = function(cursor) { toolbox.style.cursor = url; } } - // Set cursor on the SVG surface as well, so that rapid movements + // Set cursor on the whole document, so that rapid movements // don't result in cursor changing to an arrow momentarily. - if (Blockly.svg) { - if (cursor == Blockly.Css.Cursor.OPEN) { - Blockly.svg.style.cursor = ''; - } else { - Blockly.svg.style.cursor = url; - } + var html = document.body.parentNode; + if (cursor == Blockly.Css.Cursor.OPEN) { + html.style.cursor = ''; + } else { + html.style.cursor = url; } }; @@ -131,6 +137,7 @@ Blockly.Css.setCursor = function(cursor) { Blockly.Css.CONTENT = [ '.blocklySvg {', ' background-color: #fff;', + ' outline: none;', ' overflow: hidden;', /* IE overflows by default. */ '}', @@ -140,6 +147,20 @@ Blockly.Css.CONTENT = [ ' z-index: 999;', '}', + '.blocklyTooltipDiv {', + ' background-color: #ffffc7;', + ' border: 1px solid #ddc;', + ' box-shadow: 4px 4px 20px 1px rgba(0,0,0,.15);', + ' colour: #000;', + ' display: none;', + ' font-family: sans-serif;', + ' font-size: 9pt;', + ' opacity: 0.9;', + ' padding: 2px;', + ' position: absolute;', + ' z-index: 1000;', + '}', + '.blocklyResizeSE {', ' cursor: se-resize;', ' fill: #aaa;', @@ -246,29 +267,8 @@ Blockly.Css.CONTENT = [ ' display: block;', '}', - '.blocklyTooltipBackground {', - ' fill: #ffffc7;', - ' stroke: #d8d8d8;', - ' stroke-width: 1px;', - '}', - - '.blocklyTooltipShadow,', - '.blocklyDropdownMenuShadow {', - ' fill: #bbb;', - ' filter: url(#blocklyShadowFilter);', - '}', - - '.blocklyTooltipText {', - ' fill: #000;', - ' font-family: sans-serif;', - ' font-size: 9pt;', - '}', - - '.blocklyIconShield {', + '.blocklyIconGroup {', ' cursor: default;', - ' fill: #00c;', - ' stroke: #ccc;', - ' stroke-width: 1px;', '}', '.blocklyIconGroup:not(:hover),', @@ -276,18 +276,6 @@ Blockly.Css.CONTENT = [ ' opacity: .6;', '}', - '.blocklyIconMark {', - ' cursor: default !important;', - ' fill: #ccc;', - ' font-family: sans-serif;', - ' font-size: 9pt;', - ' font-weight: bold;', - ' text-anchor: middle;', - '}', - - '.blocklyWarningBody {', - '}', - '.blocklyMinimalBody {', ' margin: 0;', ' padding: 0;', @@ -310,7 +298,6 @@ Blockly.Css.CONTENT = [ '}', '.blocklyMainBackground {', - ' fill: url(#blocklyGridPattern);', ' stroke-width: 1;', ' stroke: #c6c6c6;', /* Equates to #ddd due to border being off-pixel. */ '}', diff --git a/core/field.js b/core/field.js index 39ae22157..5e343b6a8 100644 --- a/core/field.js +++ b/core/field.js @@ -31,6 +31,7 @@ goog.provide('Blockly.Field'); goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.math.Size'); +goog.require('goog.style'); goog.require('goog.userAgent'); @@ -255,7 +256,7 @@ Blockly.Field.prototype.updateTextNode_ = function() { goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_)); // Replace whitespace with non-breaking spaces so the text doesn't collapse. text = text.replace(/\s/g, Blockly.Field.NBSP); - if (Blockly.RTL && text) { + if (this.sourceBlock_.RTL && text) { // The SVG is LTR, force text to be RTL. text += '\u200F'; } @@ -320,3 +321,13 @@ Blockly.Field.prototype.onMouseUp_ = function(e) { Blockly.Field.prototype.setTooltip = function(newTip) { // Non-abstract sub-classes may wish to implement this. See FieldLabel. }; + +/** + * Return the absolute coordinates of the top-left corner of this field. + * The origin (0,0) is the top-left corner of the page body. + * @return {{!goog.math.Coordinate}} Object with .x and .y properties. + * @private + */ +Blockly.Field.prototype.getAbsoluteXY_ = function() { + return goog.style.getPageOffset(this.borderRect_); +}; diff --git a/core/field_angle.js b/core/field_angle.js index 2e5105e8b..ef7ac492c 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -216,7 +216,7 @@ Blockly.FieldAngle.prototype.setText = function(text) { } this.updateGraph_(); // Insert degree symbol. - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { this.textElement_.insertBefore(this.symbol_, this.textElement_.firstChild); } else { this.textElement_.appendChild(this.symbol_); diff --git a/core/field_colour.js b/core/field_colour.js index acc044fe9..52495a758 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -167,7 +167,8 @@ Blockly.FieldColour.prototype.setColumns = function(columns) { * @private */ Blockly.FieldColour.prototype.showEditor_ = function() { - Blockly.WidgetDiv.show(this, Blockly.FieldColour.widgetDispose_); + Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, + Blockly.FieldColour.widgetDispose_); // Create the palette using Closure. var picker = new goog.ui.ColorPicker(); picker.setSize(this.columns_ || Blockly.FieldColour.COLUMNS); @@ -177,7 +178,7 @@ Blockly.FieldColour.prototype.showEditor_ = function() { // Record windowSize and scrollOffset before adding the palette. var windowSize = goog.dom.getViewportSize(); var scrollOffset = goog.style.getViewportPageOffset(document); - var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); + var xy = this.getAbsoluteXY_(); var borderBBox = this.borderRect_.getBBox(); var div = Blockly.WidgetDiv.DIV; picker.render(div); @@ -192,7 +193,7 @@ Blockly.FieldColour.prototype.showEditor_ = function() { } else { xy.y += borderBBox.height - 1; } - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { xy.x += borderBBox.width; xy.x -= paletteSize.width; // Don't go offscreen left. @@ -205,7 +206,8 @@ Blockly.FieldColour.prototype.showEditor_ = function() { xy.x = windowSize.width + scrollOffset.x - paletteSize.width; } } - Blockly.WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset); + Blockly.WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset, + this.sourceBlock_.RTL); // Configure event handler. var thisField = this; diff --git a/core/field_date.js b/core/field_date.js index c9c5e0c87..d536449f5 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -109,7 +109,8 @@ Blockly.FieldDate.prototype.setValue = function(date) { * @private */ Blockly.FieldDate.prototype.showEditor_ = function() { - Blockly.WidgetDiv.show(this, Blockly.FieldDate.widgetDispose_); + Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, + Blockly.FieldDate.widgetDispose_); // Create the date picker using Closure. Blockly.FieldDate.loadLanguage_(); var picker = new goog.ui.DatePicker(); @@ -120,7 +121,7 @@ Blockly.FieldDate.prototype.showEditor_ = function() { // Record windowSize and scrollOffset before adding the picker. var windowSize = goog.dom.getViewportSize(); var scrollOffset = goog.style.getViewportPageOffset(document); - var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); + var xy = this.getAbsoluteXY_(); var borderBBox = this.borderRect_.getBBox(); var div = Blockly.WidgetDiv.DIV; picker.render(div); @@ -135,7 +136,7 @@ Blockly.FieldDate.prototype.showEditor_ = function() { } else { xy.y += borderBBox.height - 1; } - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { xy.x += borderBBox.width; xy.x -= pickerSize.width; // Don't go offscreen left. @@ -148,7 +149,8 @@ Blockly.FieldDate.prototype.showEditor_ = function() { xy.x = windowSize.width + scrollOffset.x - pickerSize.width; } } - Blockly.WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset); + Blockly.WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset, + this.sourceBlock_.RTL); // Configure event handler. var thisField = this; diff --git a/core/field_dropdown.js b/core/field_dropdown.js index e90b290ea..a69290671 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -98,8 +98,8 @@ Blockly.FieldDropdown.prototype.init = function(block) { // Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL) this.arrow_ = Blockly.createSvgElement('tspan', {}, null); this.arrow_.appendChild(document.createTextNode( - Blockly.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : - ' ' + Blockly.FieldDropdown.ARROW_CHAR)); + block.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : + ' ' + Blockly.FieldDropdown.ARROW_CHAR)); Blockly.FieldDropdown.superClass_.init.call(this, block); // Force a reset of the text to add the arrow. @@ -113,7 +113,7 @@ Blockly.FieldDropdown.prototype.init = function(block) { * @private */ Blockly.FieldDropdown.prototype.showEditor_ = function() { - Blockly.WidgetDiv.show(this, null); + Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, null); var thisField = this; function callback(e) { @@ -166,7 +166,7 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { // Record windowSize and scrollOffset before adding menu. var windowSize = goog.dom.getViewportSize(); var scrollOffset = goog.style.getViewportPageOffset(document); - var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); + var xy = this.getAbsoluteXY_(); var borderBBox = this.borderRect_.getBBox(); var div = Blockly.WidgetDiv.DIV; menu.render(div); @@ -183,7 +183,7 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { } else { xy.y += borderBBox.height; } - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { xy.x += borderBBox.width; xy.x += Blockly.FieldDropdown.CHECKMARK_OVERHANG; // Don't go offscreen left. @@ -197,7 +197,8 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { xy.x = windowSize.width + scrollOffset.x - menuSize.width; } } - Blockly.WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset); + Blockly.WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset, + this.sourceBlock_.RTL); menu.setAllowAutoFocus(true); menuDom.focus(); }; @@ -301,7 +302,7 @@ Blockly.FieldDropdown.prototype.setText = function(text) { if (this.textElement_) { // Insert dropdown arrow. - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { this.textElement_.insertBefore(this.arrow_, this.textElement_.firstChild); } else { this.textElement_.appendChild(this.arrow_); diff --git a/core/field_textinput.js b/core/field_textinput.js index 97826be75..5a3846cb7 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -130,7 +130,7 @@ Blockly.FieldTextInput.prototype.showEditor_ = function(opt_quietInput) { return; } - Blockly.WidgetDiv.show(this, this.widgetDispose_()); + Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_()); var div = Blockly.WidgetDiv.DIV; // Create the input. var htmlInput = goog.dom.createDom('input', 'blocklyHtmlInput'); @@ -228,10 +228,10 @@ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { var div = Blockly.WidgetDiv.DIV; var bBox = this.fieldGroup_.getBBox(); div.style.width = bBox.width + 'px'; - var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); + var xy = this.getAbsoluteXY_(); // In RTL mode block fields and LTR input fields the left edge moves, // whereas the right edge is fixed. Reposition the editor. - if (Blockly.RTL) { + if (this.sourceBlock_.RTL) { var borderBBox = this.borderRect_.getBBox(); xy.x += borderBBox.width; xy.x -= div.offsetWidth; diff --git a/core/flyout.js b/core/flyout.js index 59c9ac225..ed0b60858 100644 --- a/core/flyout.js +++ b/core/flyout.js @@ -37,19 +37,27 @@ goog.require('goog.userAgent'); /** * Class for a flyout. + * @param {!Object} workspaceOptions Dictionary of options for the workspace. * @constructor */ -Blockly.Flyout = function() { +Blockly.Flyout = function(workspaceOptions) { var flyout = this; + workspaceOptions.getMetrics = function() {return flyout.getMetrics_();}; + workspaceOptions.setMetrics = + function(ratio) {return flyout.setMetrics_(ratio);}; /** * @type {!Blockly.Workspace} * @private */ - this.workspace_ = new Blockly.WorkspaceSvg( - function() {return flyout.getMetrics_();}, - function(ratio) {return flyout.setMetrics_(ratio);}); + this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions); this.workspace_.isFlyout = true; + /** + * Is RTL vs LTR. + * @type {boolean} + */ + this.RTL = !!workspaceOptions.RTL; + /** * Opaque data that can be passed to removeChangeListener. * @type {Array.} @@ -117,6 +125,36 @@ Blockly.Flyout.prototype.createDom = function() { return this.svgGroup_; }; +/** + * Initializes the flyout. + * @param {!Blockly.Workspace} workspace The workspace in which to create new + * blocks. + */ +Blockly.Flyout.prototype.init = function(workspace) { + this.targetWorkspace_ = workspace; + this.workspace_.targetWorkspace = workspace; + // Add scrollbar. + this.scrollbar_ = new Blockly.Scrollbar(this.workspace_, false, false); + + this.hide(); + + // If the document resizes, reposition the flyout. + this.eventWrappers_.concat(Blockly.bindEvent_(window, + goog.events.EventType.RESIZE, this, this.position_)); + this.position_(); + this.eventWrappers_.concat(Blockly.bindEvent_(this.svgGroup_, + 'wheel', this, this.wheel_)); + // Safari needs mousewheel. + this.eventWrappers_.concat(Blockly.bindEvent_(this.svgGroup_, + 'mousewheel', this, this.wheel_)); + this.eventWrappers_.concat( + Blockly.bindEvent_(this.targetWorkspace_.getCanvas(), + 'blocklyWorkspaceChange', this, this.filterForCapacity_)); + // Dragging the flyout up and down. + this.eventWrappers_.concat(Blockly.bindEvent_(this.svgGroup_, + 'mousedown', this, this.onMouseDown_)); +}; + /** * Dispose of this flyout. * Unlink from all DOM elements to prevent memory leaks. @@ -194,36 +232,6 @@ Blockly.Flyout.prototype.setMetrics_ = function(yRatio) { this.workspace_.translate(0, this.workspace_.scrollY + metrics.absoluteTop); }; -/** - * Initializes the flyout. - * @param {!Blockly.Workspace} workspace The workspace in which to create new - * blocks. - */ -Blockly.Flyout.prototype.init = function(workspace) { - this.targetWorkspace_ = workspace; - this.workspace_.targetWorkspace = workspace; - // Add scrollbar. - this.scrollbar_ = new Blockly.Scrollbar(this.workspace_, false, false); - - this.hide(); - - // If the document resizes, reposition the flyout. - this.eventWrappers_.concat(Blockly.bindEvent_(window, - goog.events.EventType.RESIZE, this, this.position_)); - this.position_(); - this.eventWrappers_.concat(Blockly.bindEvent_(this.svgGroup_, - 'wheel', this, this.wheel_)); - // Safari needs mousewheel. - this.eventWrappers_.concat(Blockly.bindEvent_(this.svgGroup_, - 'mousewheel', this, this.wheel_)); - this.eventWrappers_.concat( - Blockly.bindEvent_(this.targetWorkspace_.getCanvas(), - 'blocklyWorkspaceChange', this, this.filterForCapacity_)); - // Dragging the flyout up and down. - this.eventWrappers_.concat(Blockly.bindEvent_(this.svgGroup_, - 'mousedown', this, this.onMouseDown_)); -}; - /** * Move the toolbox to the edge of the workspace. * @private @@ -238,26 +246,26 @@ Blockly.Flyout.prototype.position_ = function() { return; } var edgeWidth = this.width_ - this.CORNER_RADIUS; - if (Blockly.RTL) { + if (this.RTL) { edgeWidth *= -1; } - var path = ['M ' + (Blockly.RTL ? this.width_ : 0) + ',0']; + var path = ['M ' + (this.RTL ? this.width_ : 0) + ',0']; path.push('h', edgeWidth); path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, - Blockly.RTL ? 0 : 1, - Blockly.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS, + this.RTL ? 0 : 1, + this.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS, this.CORNER_RADIUS); path.push('v', Math.max(0, metrics.viewHeight - this.CORNER_RADIUS * 2)); path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, - Blockly.RTL ? 0 : 1, - Blockly.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS, + this.RTL ? 0 : 1, + this.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS, this.CORNER_RADIUS); path.push('h', -edgeWidth); path.push('z'); this.svgBackground_.setAttribute('d', path.join(' ')); var x = metrics.absoluteLeft; - if (Blockly.RTL) { + if (this.RTL) { x += metrics.viewWidth; x -= this.width_; } @@ -394,7 +402,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { block.render(); var root = block.getSvgRoot(); var blockHW = block.getHeightWidth(); - var x = Blockly.RTL ? 0 : margin + Blockly.BlockSvg.TAB_WIDTH; + var x = this.RTL ? 0 : margin + Blockly.BlockSvg.TAB_WIDTH; block.moveBy(x, cursorY); cursorY += blockHW.height + gaps[i]; @@ -467,7 +475,7 @@ Blockly.Flyout.prototype.reflow = function() { for (var x = 0, block; block = blocks[x]; x++) { var blockHW = block.getHeightWidth(); var blockXY = block.getRelativeToSurfaceXY(); - if (Blockly.RTL) { + if (this.RTL) { // With the flyoutWidth known, right-align the blocks. var dx = flyoutWidth - margin - Blockly.BlockSvg.TAB_WIDTH - blockXY.x; block.moveBy(dx, 0); @@ -477,7 +485,7 @@ Blockly.Flyout.prototype.reflow = function() { block.flyoutRect_.setAttribute('width', blockHW.width); block.flyoutRect_.setAttribute('height', blockHW.height); block.flyoutRect_.setAttribute('x', - Blockly.RTL ? blockXY.x - blockHW.width : blockXY.x); + this.RTL ? blockXY.x - blockHW.width : blockXY.x); block.flyoutRect_.setAttribute('y', blockXY.y); } } @@ -643,6 +651,23 @@ Blockly.Flyout.prototype.filterForCapacity_ = function() { } }; +/** + * Return the deletion rectangle for this flyout. + * @return {goog.math.Rect} Rectangle in which to delete. + */ +Blockly.Flyout.prototype.getRect = function() { + // BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout + // area are still deleted. Must be smaller than Infinity, but larger than + // the largest screen size. + var BIG_NUM = 10000000; + var x = Blockly.getSvgXY_(this.svgGroup_).x; + if (!this.RTL) { + x -= BIG_NUM; + } + return new goog.math.Rect(x, -BIG_NUM, + BIG_NUM + this.width_, this.height_ + 2 * BIG_NUM); +}; + /** * Stop binding to the global mouseup and mousemove events. * @private @@ -668,20 +693,3 @@ Blockly.Flyout.terminateDrag_ = function() { Blockly.Flyout.startBlock_ = null; Blockly.Flyout.startFlyout_ = null; }; - -/** - * Return the deletion rectangle for this flyout. - * @return {goog.math.Rect} Rectangle in which to delete. - */ -Blockly.Flyout.prototype.getRect = function() { - // BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout - // area are still deleted. Must be smaller than Infinity, but larger than - // the largest screen size. - var BIG_NUM = 10000000; - var x = Blockly.getSvgXY_(this.svgGroup_).x; - if (!Blockly.RTL) { - x -= BIG_NUM; - } - return new goog.math.Rect(x, -BIG_NUM, - BIG_NUM + this.width_, this.height_ + 2 * BIG_NUM); -}; diff --git a/core/generator.js b/core/generator.js index 9f65ae0f8..d274e2860 100644 --- a/core/generator.js +++ b/core/generator.js @@ -65,12 +65,15 @@ Blockly.Generator.prototype.STATEMENT_PREFIX = null; /** * Generate code for all blocks in the workspace to the specified language. - * @param {Blockly.Workspace=} opt_workspace Workspace to generate code from. - * Defaults to main workspace. + * @param {Blockly.Workspace} workspace Workspace to generate code from. * @return {string} Generated code. */ -Blockly.Generator.prototype.workspaceToCode = function(opt_workspace) { - var workspace = opt_workspace || Blockly.mainWorkspace; +Blockly.Generator.prototype.workspaceToCode = function(workspace) { + if (!workspace) { + // Backwards compatability from before there could be multiple workspaces. + console.warn('No workspace specified in workspaceToCode call. Guessing.'); + workspace = Blockly.getMainWorkspace(); + } var code = []; this.init(workspace); var blocks = workspace.getTopBlocks(true); diff --git a/core/icon.js b/core/icon.js index 7788e23d8..a057defeb 100644 --- a/core/icon.js +++ b/core/icon.js @@ -133,7 +133,7 @@ Blockly.Icon.prototype.isVisible = function() { * @private */ Blockly.Icon.prototype.iconClick_ = function(e) { - if (!this.block_.isInFlyout) { + if (!this.block_.isInFlyout && !Blockly.isRightButton(e)) { this.setVisible(!this.isVisible()); } }; @@ -162,13 +162,13 @@ Blockly.Icon.prototype.renderIcon = function(cursorX) { var TOP_MARGIN = 5; var width = this.SIZE; - if (Blockly.RTL) { + if (this.block_.RTL) { cursorX -= width; } this.iconGroup_.setAttribute('transform', 'translate(' + cursorX + ', ' + TOP_MARGIN + ')'); this.computeIconLocation(); - if (Blockly.RTL) { + if (this.block_.RTL) { cursorX -= Blockly.BlockSvg.SEP_SPACE_X; } else { cursorX += width + Blockly.BlockSvg.SEP_SPACE_X; diff --git a/core/inject.js b/core/inject.js index ee3afebb8..d3018a1d0 100644 --- a/core/inject.js +++ b/core/inject.js @@ -34,31 +34,35 @@ goog.require('goog.userAgent'); /** - * Initialize the SVG document with various handlers. + * Inject a Blockly editor into the specified container DIV. * @param {!Element} container Containing element. * @param {Object} opt_options Optional dictionary of options. + * @return {!Blockly.Workspace} Newly created main workspace. */ Blockly.inject = function(container, opt_options) { // Verify that the container is in document. if (!goog.dom.contains(document, container)) { throw 'Error: container is not in current document.'; } - if (opt_options) { - Blockly.parseOptions_(opt_options); - } + var options = Blockly.parseOptions_(opt_options || {}); + var workspace; var startUi = function() { - Blockly.createDom_(container); - Blockly.init_(); + var svg = Blockly.createDom_(container, options); + workspace = Blockly.createMainWorkspace_(svg, options); + Blockly.init_(workspace); + workspace.markFocused(); + Blockly.bindEvent_(svg, 'focus', workspace, workspace.markFocused); }; - if (Blockly.enableRealtime) { + if (options.enableRealtime) { var realtimeElement = document.getElementById('realtime'); if (realtimeElement) { realtimeElement.style.display = 'block'; } - Blockly.Realtime.startRealtime(startUi, container, Blockly.realtimeOptions); + Blockly.Realtime.startRealtime(startUi, container, options.realtimeOptions); } else { startUi(); } + return workspace; }; /** @@ -87,22 +91,25 @@ Blockly.parseToolboxTree_ = function(tree) { /** * Configure Blockly to behave according to a set of options. - * @param {!Object} options Dictionary of options. + * @param {!Object} options Dictionary of options. Specification: + * https://developers.google.com/blockly/installation/overview#configuration + * @return {!Object} Dictionary of normalized options. * @private */ Blockly.parseOptions_ = function(options) { var readOnly = !!options['readOnly']; if (readOnly) { + var languageTree = null; var hasCategories = false; var hasTrashcan = false; var hasCollapse = false; var hasComments = false; var hasDisable = false; - var tree = null; + var hasSounds = false; } else { - var tree = Blockly.parseToolboxTree_(options['toolbox']); - var hasCategories = Boolean(tree && - tree.getElementsByTagName('category').length); + var languageTree = Blockly.parseToolboxTree_(options['toolbox']); + var hasCategories = Boolean(languageTree && + languageTree.getElementsByTagName('category').length); var hasTrashcan = options['trashcan']; if (hasTrashcan === undefined) { hasTrashcan = hasCategories; @@ -119,15 +126,15 @@ Blockly.parseOptions_ = function(options) { if (hasDisable === undefined) { hasDisable = hasCategories; } + var hasSounds = options['sounds']; + if (hasSounds === undefined) { + hasSounds = true; + } } var hasScrollbars = options['scrollbars']; if (hasScrollbars === undefined) { hasScrollbars = hasCategories; } - var hasSounds = options['sounds']; - if (hasSounds === undefined) { - hasSounds = true; - } var hasCss = options['css']; if (hasCss === undefined) { hasCss = true; @@ -147,47 +154,53 @@ Blockly.parseOptions_ = function(options) { grid['length'] = parseFloat(grid['length']); } grid['snap'] = !!grid['snap']; + var pathToMedia = 'https://blockly-demo.appspot.com/static/media/'; + if (options['media']) { + pathToMedia = options['media']; + } else if (options['path']) { + // 'path' is a deprecated option which has been replaced by 'media'. + pathToMedia = options['path'] + 'media/'; + } var enableRealtime = !!options['realtime']; var realtimeOptions = enableRealtime ? options['realtimeOptions'] : undefined; - Blockly.RTL = !!options['rtl']; - Blockly.collapse = hasCollapse; - Blockly.comments = hasComments; - Blockly.disable = hasDisable; - Blockly.readOnly = readOnly; - Blockly.maxBlocks = options['maxBlocks'] || Infinity; - if (options['media']) { - Blockly.pathToMedia = options['media']; - } else if (options['path']) { - // 'path' is a deprecated option which has been replaced by 'media'. - Blockly.pathToMedia = options['path'] + 'media/'; - } - Blockly.hasCategories = hasCategories; - Blockly.hasScrollbars = hasScrollbars; - Blockly.hasTrashcan = hasTrashcan; - Blockly.hasSounds = hasSounds; - Blockly.hasCss = hasCss; - Blockly.languageTree = tree; - Blockly.gridOptions = grid; - Blockly.enableRealtime = enableRealtime; - Blockly.realtimeOptions = realtimeOptions; + return { + RTL: !!options['rtl'], + collapse: hasCollapse, + comments: hasComments, + disable: hasDisable, + readOnly: readOnly, + maxBlocks: options['maxBlocks'] || Infinity, + pathToMedia: pathToMedia, + hasCategories: hasCategories, + hasScrollbars: hasScrollbars, + hasTrashcan: hasTrashcan, + hasSounds: hasSounds, + hasCss: hasCss, + languageTree: languageTree, + gridOptions: grid, + enableRealtime: enableRealtime, + realtimeOptions: realtimeOptions + }; }; /** * Create the SVG image. * @param {!Element} container Containing element. + * @param {Object} options Dictionary of options. + * @return {!Element} Newly created SVG image. * @private */ -Blockly.createDom_ = function(container) { +Blockly.createDom_ = function(container, options) { // Sadly browsers (Chrome vs Firefox) are currently inconsistent in laying // out content in RTL mode. Therefore Blockly forces the use of LTR, // then manually positions content in RTL as needed. container.setAttribute('dir', 'LTR'); // Closure can be trusted to create HTML widgets with the proper direction. - goog.ui.Component.setDefaultRightToLeft(Blockly.RTL); + goog.ui.Component.setDefaultRightToLeft(options.RTL); // Load CSS. - Blockly.Css.inject(); + Blockly.Css.inject(options.hasCss, options.pathToMedia); // Build the SVG DOM. /* @@ -206,14 +219,14 @@ Blockly.createDom_ = function(container) { 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'version': '1.1', 'class': 'blocklySvg' - }, null); + }, container); /* ... filters go here ... */ var defs = Blockly.createSvgElement('defs', {}, svg); - var filter, feSpecularLighting, feMerge, pattern; + var filter, feSpecularLighting, feMerge; /* @@ -233,16 +246,16 @@ Blockly.createDom_ = function(container) { {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, filter); feSpecularLighting = Blockly.createSvgElement('feSpecularLighting', {'in': 'blur', 'surfaceScale': 1, 'specularConstant': 0.5, - 'specularExponent': 10, 'lighting-color': 'white', 'result': 'specOut'}, + 'specularExponent': 10, 'lighting-color': 'white', 'result': 'specOut'}, filter); Blockly.createSvgElement('fePointLight', {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting); Blockly.createSvgElement('feComposite', {'in': 'specOut', 'in2': 'SourceAlpha', 'operator': 'in', - 'result': 'specOut'}, filter); + 'result': 'specOut'}, filter); Blockly.createSvgElement('feComposite', {'in': 'SourceGraphic', 'in2': 'specOut', 'operator': 'arithmetic', - 'k1': 0, 'k2': 1, 'k3': 1, 'k4': 0}, filter); + 'k1': 0, 'k2': 1, 'k3': 1, 'k4': 0}, filter); /* @@ -258,147 +271,150 @@ Blockly.createDom_ = function(container) { */ - pattern = Blockly.createSvgElement('pattern', + var disabledPattern = Blockly.createSvgElement('pattern', {'id': 'blocklyDisabledPattern', 'patternUnits': 'userSpaceOnUse', 'width': 10, 'height': 10}, defs); Blockly.createSvgElement('rect', - {'width': 10, 'height': 10, 'fill': '#aaa'}, pattern); + {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern); Blockly.createSvgElement('path', - {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, pattern); + {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern); /* - */ - pattern = Blockly.createSvgElement('pattern', - {'id': 'blocklyGridPattern', + var gridPattern = Blockly.createSvgElement('pattern', + {'id': 'blocklyGridPattern' + String(Math.random()).substring(2), 'patternUnits': 'userSpaceOnUse', - 'width': Blockly.gridOptions['spacing'], - 'height': Blockly.gridOptions['spacing']}, defs); - if (Blockly.gridOptions['length'] > 0) { - var half = Math.floor(Blockly.gridOptions['spacing'] / 2) + .5; - var start = half - Blockly.gridOptions['length'] / 2; - var end = half + Blockly.gridOptions['length'] / 2; + 'width': options.gridOptions['spacing'], + 'height': options.gridOptions['spacing']}, defs); + if (options.gridOptions['length'] > 0 && options.gridOptions['spacing'] > 0) { + var half = Math.floor(options.gridOptions['spacing'] / 2) + .5; + var start = half - options.gridOptions['length'] / 2; + var end = half + options.gridOptions['length'] / 2; Blockly.createSvgElement('line', {'x1': start, 'y1': half, 'x2': end, 'y2': half, - 'stroke': Blockly.gridOptions['colour']}, - pattern); - if (Blockly.gridOptions['length'] > 1) { + 'stroke': options.gridOptions['colour']}, + gridPattern); + if (options.gridOptions['length'] > 1) { Blockly.createSvgElement('line', {'x1': half, 'y1': start, 'x2': half, 'y2': end, - 'stroke': Blockly.gridOptions['colour']}, - pattern); + 'stroke': options.gridOptions['colour']}, + gridPattern); } - Blockly.mainWorkspacePattern_ = pattern; } + options.gridPattern = gridPattern; + options.svg = svg; + return svg; +}; - Blockly.mainWorkspace = new Blockly.WorkspaceSvg( - Blockly.getMainWorkspaceMetrics_, - Blockly.setMainWorkspaceMetrics_); - svg.appendChild(Blockly.mainWorkspace.createDom('blocklyMainBackground')); - Blockly.mainWorkspace.maxBlocks = Blockly.maxBlocks; +/** + * Create a main workspace and add it to the SVG. + * @param {!Element} svg SVG element with pattern defined. + * @param {Object} options Dictionary of options. + * @return {!Blockly.Workspace} Newly created main workspace. + * @private + */ +Blockly.createMainWorkspace_ = function(svg, options) { + options.parentWorkspace = null; + options.getMetrics = Blockly.getMainWorkspaceMetrics_; + options.setMetrics = Blockly.setMainWorkspaceMetrics_; + var mainWorkspace = new Blockly.WorkspaceSvg(options); + svg.appendChild(mainWorkspace.createDom('blocklyMainBackground')); + mainWorkspace.markFocused(); - if (!Blockly.readOnly) { - // Determine if there needs to be a category tree, or a simple list of - // blocks. This cannot be changed later, since the UI is very different. - if (Blockly.hasCategories) { - Blockly.mainWorkspace.toolbox_ = new Blockly.Toolbox(svg, container); - } else if (Blockly.languageTree) { - Blockly.mainWorkspace.addFlyout(); - } - if (!Blockly.hasScrollbars) { - var workspaceChanged = function() { - if (Blockly.dragMode_ == 0) { - var metrics = Blockly.mainWorkspace.getMetrics(); - var edgeLeft = metrics.viewLeft + metrics.absoluteLeft; - var edgeTop = metrics.viewTop + metrics.absoluteTop; - if (metrics.contentTop < edgeTop || - metrics.contentTop + metrics.contentHeight > - metrics.viewHeight + edgeTop || - metrics.contentLeft < - (Blockly.RTL ? metrics.viewLeft : edgeLeft) || - metrics.contentLeft + metrics.contentWidth > (Blockly.RTL ? - metrics.viewWidth : metrics.viewWidth + edgeLeft)) { - // One or more blocks may be out of bounds. Bump them back in. - var MARGIN = 25; - var blocks = Blockly.mainWorkspace.getTopBlocks(false); - for (var b = 0, block; block = blocks[b]; b++) { - var blockXY = block.getRelativeToSurfaceXY(); - var blockHW = block.getHeightWidth(); - // Bump any block that's above the top back inside. - var overflow = edgeTop + MARGIN - blockHW.height - blockXY.y; - if (overflow > 0) { - block.moveBy(0, overflow); - } - // Bump any block that's below the bottom back inside. - var overflow = edgeTop + metrics.viewHeight - MARGIN - blockXY.y; - if (overflow < 0) { - block.moveBy(0, overflow); - } - // Bump any block that's off the left back inside. - var overflow = MARGIN + edgeLeft - - blockXY.x - (Blockly.RTL ? 0 : blockHW.width); - if (overflow > 0) { - block.moveBy(overflow, 0); - } - // Bump any block that's off the right back inside. - var overflow = edgeLeft + metrics.viewWidth - MARGIN - - blockXY.x + (Blockly.RTL ? blockHW.width : 0); - if (overflow < 0) { - block.moveBy(overflow, 0); - } + if (!options.readOnly && !options.hasScrollbars) { + var workspaceChanged = function() { + if (Blockly.dragMode_ == 0) { + var metrics = mainWorkspace.getMetrics(); + var edgeLeft = metrics.viewLeft + metrics.absoluteLeft; + var edgeTop = metrics.viewTop + metrics.absoluteTop; + if (metrics.contentTop < edgeTop || + metrics.contentTop + metrics.contentHeight > + metrics.viewHeight + edgeTop || + metrics.contentLeft < + (options.RTL ? metrics.viewLeft : edgeLeft) || + metrics.contentLeft + metrics.contentWidth > (options.RTL ? + metrics.viewWidth : metrics.viewWidth + edgeLeft)) { + // One or more blocks may be out of bounds. Bump them back in. + var MARGIN = 25; + var blocks = mainWorkspace.getTopBlocks(false); + for (var b = 0, block; block = blocks[b]; b++) { + var blockXY = block.getRelativeToSurfaceXY(); + var blockHW = block.getHeightWidth(); + // Bump any block that's above the top back inside. + var overflow = edgeTop + MARGIN - blockHW.height - blockXY.y; + if (overflow > 0) { + block.moveBy(0, overflow); + } + // Bump any block that's below the bottom back inside. + var overflow = edgeTop + metrics.viewHeight - MARGIN - blockXY.y; + if (overflow < 0) { + block.moveBy(0, overflow); + } + // Bump any block that's off the left back inside. + var overflow = MARGIN + edgeLeft - + blockXY.x - (options.RTL ? 0 : blockHW.width); + if (overflow > 0) { + block.moveBy(overflow, 0); + } + // Bump any block that's off the right back inside. + var overflow = edgeLeft + metrics.viewWidth - MARGIN - + blockXY.x + (options.RTL ? blockHW.width : 0); + if (overflow < 0) { + block.moveBy(overflow, 0); } } } - }; - Blockly.addChangeListener(workspaceChanged); - } + } + }; + mainWorkspace.addChangeListener(workspaceChanged); } - - svg.appendChild(Blockly.Tooltip.createDom()); - - // The SVG is now fully assembled. Add it to the container. - container.appendChild(svg); - Blockly.svg = svg; - Blockly.svgResize(); - - // Create an HTML container for popup overlays (e.g. editor widgets). - Blockly.WidgetDiv.DIV = goog.dom.createDom('div', 'blocklyWidgetDiv'); - Blockly.WidgetDiv.DIV.style.direction = Blockly.RTL ? 'rtl' : 'ltr'; - document.body.appendChild(Blockly.WidgetDiv.DIV); + // The SVG is now fully assembled. + Blockly.svgResize(mainWorkspace); + Blockly.WidgetDiv.createDom(); + Blockly.Tooltip.createDom() + return mainWorkspace; }; /** * Initialize Blockly with various handlers. + * @param {!Blockly.Workspace} mainWorkspace Newly created main workspace. * @private */ -Blockly.init_ = function() { +Blockly.init_ = function(mainWorkspace) { + var options = mainWorkspace.options; + var svg = mainWorkspace.options.svg; + // Supress the browser's context menu. + Blockly.bindEvent_(svg, 'contextmenu', null, + function(e) { + if (!Blockly.isTargetInput_(e)) { + e.preventDefault(); + } + }); // Bind events for scrolling the workspace. // Most of these events should be bound to the SVG's surface. // However, 'mouseup' has to be on the whole document so that a block dragged // out of bounds and released will know that it has been released. // Also, 'keydown' has to be on the whole document since the browser doesn't // understand a concept of focus on the SVG image. - Blockly.bindEvent_(Blockly.svg, 'mousedown', null, Blockly.onMouseDown_); - Blockly.bindEvent_(Blockly.svg, 'contextmenu', null, Blockly.onContextMenu_); - Blockly.bindEvent_(Blockly.WidgetDiv.DIV, 'contextmenu', null, - Blockly.onContextMenu_); - Blockly.bindEvent_(Blockly.svg, 'touchstart', null, + Blockly.bindEvent_(svg, 'touchstart', null, function(e) {Blockly.longStart_(e, null);}); + Blockly.bindEvent_(window, 'resize', null, + function() {Blockly.svgResize(mainWorkspace);}); if (!Blockly.documentEventsBound_) { // Only bind the window/document events once. // Destroying and reinjecting Blockly should not bind again. - Blockly.bindEvent_(window, 'resize', document, Blockly.svgResize); Blockly.bindEvent_(document, 'keydown', null, Blockly.onKeyDown_); Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); Blockly.bindEvent_(document, 'touchcancel', null, Blockly.longStop_); @@ -415,42 +431,38 @@ Blockly.init_ = function() { Blockly.documentEventsBound_ = true; } - if (Blockly.languageTree) { - if (Blockly.mainWorkspace.toolbox_) { - Blockly.mainWorkspace.toolbox_.init(Blockly.mainWorkspace); - } else if (Blockly.mainWorkspace.flyout_) { + if (options.languageTree) { + if (mainWorkspace.toolbox_) { + mainWorkspace.toolbox_.init(mainWorkspace); + } else if (mainWorkspace.flyout_) { // Build a fixed flyout with the root blocks. - Blockly.mainWorkspace.flyout_.init(Blockly.mainWorkspace); - Blockly.mainWorkspace.flyout_.show(Blockly.languageTree.childNodes); + mainWorkspace.flyout_.init(mainWorkspace); + mainWorkspace.flyout_.show(options.languageTree.childNodes); // Translate the workspace sideways to avoid the fixed flyout. - Blockly.mainWorkspace.scrollX = Blockly.mainWorkspace.flyout_.width_; - if (Blockly.RTL) { - Blockly.mainWorkspace.scrollX *= -1; + mainWorkspace.scrollX = mainWorkspace.flyout_.width_; + if (options.RTL) { + mainWorkspace.scrollX *= -1; } - var translation = 'translate(' + Blockly.mainWorkspace.scrollX + ', 0)'; - Blockly.mainWorkspace.getCanvas().setAttribute('transform', translation); - Blockly.mainWorkspace.getBubbleCanvas().setAttribute('transform', - translation); + var translation = 'translate(' + mainWorkspace.scrollX + ', 0)'; + mainWorkspace.getCanvas().setAttribute('transform', translation); + mainWorkspace.getBubbleCanvas().setAttribute('transform', translation); } } - if (Blockly.hasScrollbars) { - Blockly.mainWorkspace.scrollbar = - new Blockly.ScrollbarPair(Blockly.mainWorkspace); - Blockly.mainWorkspace.scrollbar.resize(); + if (options.hasScrollbars) { + mainWorkspace.scrollbar = new Blockly.ScrollbarPair(mainWorkspace); + mainWorkspace.scrollbar.resize(); } - Blockly.mainWorkspace.addTrashcan(); - // Load the sounds. - if (Blockly.hasSounds) { - Blockly.loadAudio_( - [Blockly.pathToMedia + 'click.mp3', - Blockly.pathToMedia + 'click.wav', - Blockly.pathToMedia + 'click.ogg'], 'click'); - Blockly.loadAudio_( - [Blockly.pathToMedia + 'delete.mp3', - Blockly.pathToMedia + 'delete.ogg', - Blockly.pathToMedia + 'delete.wav'], 'delete'); + if (options.hasSounds) { + mainWorkspace.loadAudio_( + [options.pathToMedia + 'click.mp3', + options.pathToMedia + 'click.wav', + options.pathToMedia + 'click.ogg'], 'click'); + mainWorkspace.loadAudio_( + [options.pathToMedia + 'delete.mp3', + options.pathToMedia + 'delete.ogg', + options.pathToMedia + 'delete.wav'], 'delete'); // Bind temporary hooks that preload the sounds. var soundBinds = []; @@ -458,7 +470,7 @@ Blockly.init_ = function() { while (soundBinds.length) { Blockly.unbindEvent_(soundBinds.pop()); } - Blockly.preloadAudio_(); + mainWorkspace.preloadAudio_(); }; // Android ignores any sound not loaded as a result of a user action. soundBinds.push( @@ -472,30 +484,8 @@ Blockly.init_ = function() { * Modify the block tree on the existing toolbox. * @param {Node|string} tree DOM tree of blocks, or text representation of same. */ -Blockly.updateToolbox = function(tree) { - tree = Blockly.parseToolboxTree_(tree); - if (!tree) { - if (Blockly.languageTree) { - throw 'Can\'t nullify an existing toolbox.'; - } - // No change (null to null). - return; - } - if (!Blockly.languageTree) { - throw 'Existing toolbox is null. Can\'t create new toolbox.'; - } - var hasCategories = !!tree.getElementsByTagName('category').length; - if (hasCategories) { - if (!Blockly.hasCategories) { - throw 'Existing toolbox has no categories. Can\'t change mode.'; - } - Blockly.languageTree = tree; - Blockly.mainWorkspace.toolbox_.populate_(); - } else { - if (Blockly.hasCategories) { - throw 'Existing toolbox has categories. Can\'t change mode.'; - } - Blockly.languageTree = tree; - Blockly.mainWorkspace.flyout_.show(Blockly.languageTree.childNodes); - } +Blockly.updateToolbox = function(tree, workspace) { + console.warn('Deprecated call to Blockly.updateToolbox, ' + + 'use workspace.updateToolbox instead.'); + Blockly.getMainWorkspace().updateToolbox(tree); }; diff --git a/core/input.js b/core/input.js index 28610150b..5b6209ee7 100644 --- a/core/input.js +++ b/core/input.js @@ -102,7 +102,7 @@ Blockly.Input.prototype.appendField = function(field, opt_name) { * @deprecated December 2013 */ Blockly.Input.prototype.appendTitle = function(field, opt_name) { - console.log('Deprecated call to appendTitle, use appendField instead.'); + console.warn('Deprecated call to appendTitle, use appendField instead.'); return this.appendField(field, opt_name); }; diff --git a/core/mutator.js b/core/mutator.js index 15ccc7ef4..d555f5451 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -92,15 +92,23 @@ Blockly.Mutator.prototype.createEditor_ = function() { this.svgDialog_ = Blockly.createSvgElement('svg', {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); - Blockly.createSvgElement('rect', - {'class': 'blocklyMutatorBackground', - 'height': '100%', 'width': '100%'}, this.svgDialog_); + // Convert the list of names into a list of XML objects for the flyout. + var quarkXml = goog.dom.createDom('xml'); + for (var i = 0, quarkName; quarkName = this.quarkNames_[i]; i++) { + quarkXml.appendChild(goog.dom.createDom('block', {'type': quarkName})); + } var mutator = this; - this.workspace_ = new Blockly.WorkspaceSvg( - function() {return mutator.getFlyoutMetrics_();}, null); + var workspaceOptions = { + languageTree: quarkXml, + parentWorkspace: this.block_.workspace, + RTL: this.block_.RTL, + getMetrics: function() {return mutator.getFlyoutMetrics_();}, + setMetrics: null, + svg: this.svgDialog_ + }; + this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions); this.svgDialog_.appendChild( this.workspace_.createDom('blocklyMutatorBackground')); - this.workspace_.addFlyout(); return this.svgDialog_; }; @@ -131,7 +139,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { var workspaceSize = this.workspace_.getCanvas().getBBox(); var flyoutMetrics = this.workspace_.flyout_.getMetrics_(); var width; - if (Blockly.RTL) { + if (this.block_.RTL) { width = -workspaceSize.x; } else { width = workspaceSize.width + workspaceSize.x; @@ -152,7 +160,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { this.svgDialog_.setAttribute('height', this.workspaceHeight_); } - if (Blockly.RTL) { + if (this.block_.RTL) { // Scroll the workspace to always left-align. var translation = 'translate(' + this.workspaceWidth_ + ',0)'; this.workspace_.getCanvas().setAttribute('transform', translation); @@ -175,12 +183,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) { this.iconX_, this.iconY_, null, null); var thisObj = this; this.workspace_.flyout_.init(this.workspace_); - // Convert the list of names into a list of XML objects for the flyout. - var quarkXml = []; - for (var i = 0, quarkName; quarkName = this.quarkNames_[i]; i++) { - quarkXml[i] = goog.dom.createDom('block', {'type': quarkName}); - } - this.workspace_.flyout_.show(quarkXml); + this.workspace_.flyout_.show(this.workspace_.options.languageTree.childNodes); this.rootBlock_ = this.block_.decompose(this.workspace_); var blocks = this.rootBlock_.getDescendants(); @@ -192,7 +195,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) { this.rootBlock_.setDeletable(false); var margin = this.workspace_.flyout_.CORNER_RADIUS * 2; var x = this.workspace_.flyout_.width_ + margin; - if (Blockly.RTL) { + if (this.block_.RTL) { x = -x; } this.rootBlock_.moveBy(x, margin); @@ -280,7 +283,7 @@ Blockly.Mutator.prototype.workspaceChanged_ = function() { */ Blockly.Mutator.prototype.getFlyoutMetrics_ = function() { var left = 0; - if (Blockly.RTL) { + if (this.block_.RTL) { left += this.workspaceWidth_; } return { diff --git a/core/scrollbar.js b/core/scrollbar.js index 7b834a1fe..4e107bb63 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -255,7 +255,7 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { this.ratio_; this.svgKnob_.setAttribute('width', Math.max(0, innerLength)); this.xCoordinate = hostMetrics.absoluteLeft + 0.5; - if (this.pair_ && Blockly.RTL) { + if (this.pair_ && this.workspace_.RTL) { this.xCoordinate += hostMetrics.absoluteLeft + Blockly.Scrollbar.scrollbarThickness; } @@ -284,7 +284,7 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { this.ratio_; this.svgKnob_.setAttribute('height', Math.max(0, innerLength)); this.xCoordinate = hostMetrics.absoluteLeft + 0.5; - if (!Blockly.RTL) { + if (!this.workspace_.RTL) { this.xCoordinate += hostMetrics.viewWidth - Blockly.Scrollbar.scrollbarThickness - 1; } @@ -367,7 +367,7 @@ Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) { e.stopPropagation(); return; } - var mouseXY = Blockly.mouseToSvg(e); + var mouseXY = Blockly.mouseToSvg(e, this.workspace_.options.svg); var mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y; var knobXY = Blockly.getSvgXY_(this.svgKnob_); diff --git a/core/toolbox.js b/core/toolbox.js index 6dc2ba2bb..db7638475 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -39,35 +39,17 @@ goog.require('goog.ui.tree.TreeNode'); /** * Class for a Toolbox. - * Creates the toolbox's DOM. Only needs to be called once. - * @param {!Element} svg The top-level SVG element. - * @param {!Element} container The SVG's HTML parent element. + * Creates the toolbox's DOM. + * @param {!Blockly.Workspace} workspace The workspace in which to create new + * blocks. * @constructor */ -Blockly.Toolbox = function(svg, container) { - // Create an HTML container for the Toolbox menu. - this.HtmlDiv = goog.dom.createDom('div', 'blocklyToolboxDiv'); - this.HtmlDiv.setAttribute('dir', Blockly.RTL ? 'RTL' : 'LTR'); - container.appendChild(this.HtmlDiv); - +Blockly.Toolbox = function(workspace) { /** - * @type {!Blockly.Flyout} + * @type {!Blockly.Workspace} * @private */ - this.flyout_ = new Blockly.Flyout(); - svg.appendChild(this.flyout_.createDom()); - - // Clicking on toolbar closes popups. - Blockly.bindEvent_(this.HtmlDiv, 'mousedown', this, - function(e) { - if (Blockly.isRightButton(e) || e.target == this.HtmlDiv) { - // Close flyout. - Blockly.hideChaff(false); - } else { - // Just close popups. - Blockly.hideChaff(true); - } - }); + this.workspace_ = workspace; }; /** @@ -111,23 +93,50 @@ Blockly.Toolbox.prototype.CONFIG_ = { /** * Initializes the toolbox. - * @param {!Blockly.Workspace} workspace The workspace in which to create new - * blocks. */ -Blockly.Toolbox.prototype.init = function(workspace) { - this.CONFIG_['cleardotPath'] = Blockly.pathToMedia + '1x1.gif'; +Blockly.Toolbox.prototype.init = function() { + var workspace = this.workspace_; + var svg = workspace.options.svg; + + // Create an HTML container for the Toolbox menu. + this.HtmlDiv = goog.dom.createDom('div', 'blocklyToolboxDiv'); + this.HtmlDiv.setAttribute('dir', this.workspace_.RTL ? 'RTL' : 'LTR'); + svg.parentNode.insertBefore(this.HtmlDiv, svg); + + // Clicking on toolbar closes popups. + Blockly.bindEvent_(this.HtmlDiv, 'mousedown', this, + function(e) { + if (Blockly.isRightButton(e) || e.target == this.HtmlDiv) { + // Close flyout. + Blockly.hideChaff(false); + } else { + // Just close popups. + Blockly.hideChaff(true); + } + }); + var workspaceOptions = { + parentWorkspace: workspace, + RTL: workspace.RTL + }; + /** + * @type {!Blockly.Flyout} + * @private + */ + this.flyout_ = new Blockly.Flyout(workspaceOptions); + goog.dom.insertSiblingAfter(this.flyout_.createDom(), workspace.svgGroup_); + this.flyout_.init(workspace); + + this.CONFIG_['cleardotPath'] = workspace.options.pathToMedia + '1x1.gif'; this.CONFIG_['cssCollapsedFolderIcon'] = - 'blocklyTreeIconClosed' + (Blockly.RTL ? 'Rtl' : 'Ltr'); + 'blocklyTreeIconClosed' + (this.workspace_.RTL ? 'Rtl' : 'Ltr'); var tree = new Blockly.Toolbox.TreeControl(this, this.CONFIG_); this.tree_ = tree; tree.setShowRootNode(false); tree.setShowLines(false); tree.setShowExpandIcons(false); tree.setSelectedItem(null); - this.HtmlDiv.style.display = 'block'; - this.flyout_.init(workspace); - this.populate_(); + this.populate_(workspace.options.languageTree); tree.render(this.HtmlDiv); // If the document resizes, reposition the toolbox. @@ -142,18 +151,19 @@ Blockly.Toolbox.prototype.init = function(workspace) { * @private */ Blockly.Toolbox.prototype.position_ = function() { + var svg = this.workspace_.options.svg; var treeDiv = this.HtmlDiv; - var svgBox = goog.style.getBorderBox(Blockly.svg); - var svgSize = Blockly.svgSize(); - if (Blockly.RTL) { - var xy = Blockly.convertCoordinates(0, 0, false); + var svgBox = goog.style.getBorderBox(svg); + var svgSize = Blockly.svgSize(svg); + if (this.workspace_.RTL) { + var xy = Blockly.convertCoordinates(0, 0, false, svg); treeDiv.style.left = (xy.x + svgSize.width - treeDiv.offsetWidth) + 'px'; } else { treeDiv.style.marginLeft = svgBox.left; } treeDiv.style.height = svgSize.height + 'px'; this.width = treeDiv.offsetWidth; - if (!Blockly.RTL) { + if (!this.workspace_.RTL) { // For some reason the LTR toolbox now reports as 1px too wide. this.width -= 1; } @@ -163,7 +173,7 @@ Blockly.Toolbox.prototype.position_ = function() { * Fill the toolbox with categories and blocks. * @private */ -Blockly.Toolbox.prototype.populate_ = function() { +Blockly.Toolbox.prototype.populate_ = function(newTree) { var rootOut = this.tree_; rootOut.removeChildren(); // Delete any existing content. rootOut.blocks = []; @@ -197,7 +207,7 @@ Blockly.Toolbox.prototype.populate_ = function() { } } } - syncTrees(Blockly.languageTree, this.tree_); + syncTrees(newTree, this.tree_); if (rootOut.blocks.length) { throw 'Toolbox cannot have both blocks and categories in the root level.'; @@ -225,8 +235,8 @@ Blockly.Toolbox.prototype.getRect = function() { var BIG_NUM = 10000000; // Assumes that the toolbox is on the SVG edge. If this changes // (e.g. toolboxes in mutators) then this code will need to be more complex. - if (Blockly.RTL) { - var svgSize = Blockly.svgSize(); + if (this.workspace_.RTL) { + var svgSize = Blockly.svgSize(this.workspace_.options.svg); var x = svgSize.width - this.width; } else { var x = -BIG_NUM; diff --git a/core/tooltip.js b/core/tooltip.js index 606672f3a..19e9e0a70 100644 --- a/core/tooltip.js +++ b/core/tooltip.js @@ -57,10 +57,16 @@ Blockly.Tooltip.mouseOutPid_ = 0; Blockly.Tooltip.showPid_ = 0; /** - * Last observed location of the mouse pointer (freezes when tooltip appears). + * Last observed X location of the mouse pointer (freezes when tooltip appears). * @private */ -Blockly.Tooltip.lastXY_ = {x: 0, y: 0}; +Blockly.Tooltip.lastX_ = 0; + +/** + * Last observed Y location of the mouse pointer (freezes when tooltip appears). + * @private + */ +Blockly.Tooltip.lastY_ = 0; /** * Current element being pointed at. @@ -75,34 +81,6 @@ Blockly.Tooltip.element_ = null; */ Blockly.Tooltip.poisonedElement_ = null; -/** - * Tooltip's SVG group element. - * @type {Element} - * @private - */ -Blockly.Tooltip.svgGroup_ = null; - -/** - * Tooltip's SVG text element. - * @type {SVGTextElement} - * @private - */ -Blockly.Tooltip.svgText_ = null; - -/** - * Tooltip's SVG background rectangle. - * @type {Element} - * @private - */ -Blockly.Tooltip.svgBackground_ = null; - -/** - * Tooltip's SVG shadow rectangle. - * @type {Element} - * @private - */ -Blockly.Tooltip.svgShadow_ = null; - /** * Horizontal offset between mouse cursor and tooltip. */ @@ -124,35 +102,26 @@ Blockly.Tooltip.RADIUS_OK = 10; Blockly.Tooltip.HOVER_MS = 1000; /** - * Horizontal padding between text and background. + * Horizontal padding between tooltip and screen edge. */ Blockly.Tooltip.MARGINS = 5; /** - * Create the tooltip elements. Only needs to be called once. - * @return {!SVGGElement} The tooltip's SVG group. + * The HTML container. Set once by Blockly.Tooltip.createDom. + * @type Element + */ +Blockly.Tooltip.DIV = null; + +/** + * Create the tooltip div and inject it onto the page. */ Blockly.Tooltip.createDom = function() { - /* - - - - - - */ - var svgGroup = /** @type {!SVGGElement} */ ( - Blockly.createSvgElement('g', {'class': 'blocklyHidden'}, null)); - Blockly.Tooltip.svgGroup_ = svgGroup; - Blockly.Tooltip.svgShadow_ = /** @type {!SVGRectElement} */ ( - Blockly.createSvgElement( - 'rect', {'class': 'blocklyTooltipShadow', 'x': 2, 'y': 2}, svgGroup)); - Blockly.Tooltip.svgBackground_ = /** @type {!SVGRectElement} */ ( - Blockly.createSvgElement( - 'rect', {'class': 'blocklyTooltipBackground'}, svgGroup)); - Blockly.Tooltip.svgText_ = /** @type {!SVGTextElement} */ ( - Blockly.createSvgElement( - 'text', {'class': 'blocklyTooltipText'}, svgGroup)); - return svgGroup; + if (Blockly.Tooltip.DIV) { + return; // Already created. + } + // Create an HTML container for popup overlays (e.g. editor widgets). + Blockly.Tooltip.DIV = goog.dom.createDom('div', 'blocklyTooltipDiv'); + document.body.appendChild(Blockly.Tooltip.DIV); }; /** @@ -225,9 +194,8 @@ Blockly.Tooltip.onMouseMove_ = function(e) { if (Blockly.Tooltip.visible) { // Compute the distance between the mouse position when the tooltip was // shown and the current mouse position. Pythagorean theorem. - var mouseXY = Blockly.mouseToSvg(e); - var dx = Blockly.Tooltip.lastXY_.x - mouseXY.x; - var dy = Blockly.Tooltip.lastXY_.y - mouseXY.y; + var dx = Blockly.Tooltip.lastX_ - e.clientX; + var dy = Blockly.Tooltip.lastY_ - e.clientY; var dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); if (dr > Blockly.Tooltip.RADIUS_OK) { Blockly.Tooltip.hide(); @@ -236,7 +204,8 @@ Blockly.Tooltip.onMouseMove_ = function(e) { // The mouse moved, clear any previously scheduled tooltip. clearTimeout(Blockly.Tooltip.showPid_); // Maybe this time the mouse will stay put. Schedule showing of tooltip. - Blockly.Tooltip.lastXY_ = Blockly.mouseToSvg(e); + Blockly.Tooltip.lastX_ = e.clientX; + Blockly.Tooltip.lastY_ = e.clientY; Blockly.Tooltip.showPid_ = setTimeout(Blockly.Tooltip.show_, Blockly.Tooltip.HOVER_MS); } @@ -248,8 +217,8 @@ Blockly.Tooltip.onMouseMove_ = function(e) { Blockly.Tooltip.hide = function() { if (Blockly.Tooltip.visible) { Blockly.Tooltip.visible = false; - if (Blockly.Tooltip.svgGroup_) { - Blockly.Tooltip.svgGroup_.style.display = 'none'; + if (Blockly.Tooltip.DIV) { + Blockly.Tooltip.DIV.style.display = 'none'; } } clearTimeout(Blockly.Tooltip.showPid_); @@ -261,12 +230,11 @@ Blockly.Tooltip.hide = function() { */ Blockly.Tooltip.show_ = function() { Blockly.Tooltip.poisonedElement_ = Blockly.Tooltip.element_; - if (!Blockly.Tooltip.svgGroup_) { + if (!Blockly.Tooltip.DIV) { return; } // Erase all existing text. - goog.dom.removeChildren( - /** @type {!Element} */ (Blockly.Tooltip.svgText_)); + goog.dom.removeChildren(/** @type {!Element} */ (Blockly.Tooltip.DIV)); // Get the new text. var tip = Blockly.Tooltip.element_.tooltip; if (goog.isFunction(tip)) { @@ -276,58 +244,43 @@ Blockly.Tooltip.show_ = function() { // Create new text, line by line. var lines = tip.split('\n'); for (var i = 0; i < lines.length; i++) { - var tspanElement = Blockly.createSvgElement('tspan', - {'dy': '1em', 'x': Blockly.Tooltip.MARGINS}, Blockly.Tooltip.svgText_); - var textNode = document.createTextNode(lines[i]); - tspanElement.appendChild(textNode); + var div = document.createElement('div'); + div.appendChild(document.createTextNode(lines[i])); + Blockly.Tooltip.DIV.appendChild(div); } + var rtl = Blockly.Tooltip.element_.RTL; + var windowSize = goog.dom.getViewportSize(); // Display the tooltip. + Blockly.Tooltip.DIV.style.direction = rtl ? 'rtl' : 'ltr'; + Blockly.Tooltip.DIV.style.display = 'block'; Blockly.Tooltip.visible = true; - Blockly.Tooltip.svgGroup_.style.display = 'block'; - // Resize the background and shadow to fit. - var bBox = Blockly.Tooltip.svgText_.getBBox(); - var width = 2 * Blockly.Tooltip.MARGINS + bBox.width; - var height = bBox.height; - Blockly.Tooltip.svgBackground_.setAttribute('width', width); - Blockly.Tooltip.svgBackground_.setAttribute('height', height); - Blockly.Tooltip.svgShadow_.setAttribute('width', width); - Blockly.Tooltip.svgShadow_.setAttribute('height', height); - if (Blockly.RTL) { - // Right-align the paragraph. - // This cannot be done until the tooltip is rendered on screen. - var maxWidth = bBox.width; - for (var x = 0, textElement; - textElement = Blockly.Tooltip.svgText_.childNodes[x]; x++) { - textElement.setAttribute('text-anchor', 'end'); - textElement.setAttribute('x', maxWidth + Blockly.Tooltip.MARGINS); - } - } // Move the tooltip to just below the cursor. - var anchorX = Blockly.Tooltip.lastXY_.x; - if (Blockly.RTL) { + var anchorX = Blockly.Tooltip.lastX_; + if (rtl) { anchorX -= Blockly.Tooltip.OFFSET_X + width; } else { anchorX += Blockly.Tooltip.OFFSET_X; } - var anchorY = Blockly.Tooltip.lastXY_.y + Blockly.Tooltip.OFFSET_Y; + var anchorY = Blockly.Tooltip.lastY_ + Blockly.Tooltip.OFFSET_Y; - var svgSize = Blockly.svgSize(); - if (anchorY + bBox.height > svgSize.height) { + if (anchorY + Blockly.Tooltip.DIV.offsetHeight > windowSize.height) { // Falling off the bottom of the screen; shift the tooltip up. - anchorY -= bBox.height + 2 * Blockly.Tooltip.OFFSET_Y; + anchorY -= Blockly.Tooltip.DIV.offsetHeight + 2 * Blockly.Tooltip.OFFSET_Y; } - if (Blockly.RTL) { + if (rtl) { // Prevent falling off left edge in RTL mode. anchorX = Math.max(Blockly.Tooltip.MARGINS, anchorX); } else { - if (anchorX + bBox.width > svgSize.width - 2 * Blockly.Tooltip.MARGINS) { + if (anchorX + Blockly.Tooltip.DIV.offsetWidth > + windowSize.width - 2 * Blockly.Tooltip.MARGINS) { // Falling off the right edge of the screen; // clamp the tooltip on the edge. - anchorX = svgSize.width - bBox.width - 2 * Blockly.Tooltip.MARGINS; + anchorX = windowSize.width - Blockly.Tooltip.DIV.offsetWidth - + 2 * Blockly.Tooltip.MARGINS; } } - Blockly.Tooltip.svgGroup_.setAttribute('transform', - 'translate(' + anchorX + ',' + anchorY + ')'); + Blockly.Tooltip.DIV.style.top = anchorY + 'px'; + Blockly.Tooltip.DIV.style.left = anchorX + 'px'; }; /** diff --git a/core/trashcan.js b/core/trashcan.js index 4802d28cc..3a0bf7fae 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -178,7 +178,7 @@ Blockly.Trashcan.prototype.createDom = function() { 'clip-path': 'url(#blocklyTrashBodyClipPath)'}, this.svgGroup_); body.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - Blockly.pathToMedia + Blockly.SPRITE.url); + this.workspace_.options.pathToMedia + Blockly.SPRITE.url); var clip = Blockly.createSvgElement('clipPath', {'id': 'blocklyTrashLidClipPath'}, @@ -190,7 +190,7 @@ Blockly.Trashcan.prototype.createDom = function() { 'clip-path': 'url(#blocklyTrashLidClipPath)'}, this.svgGroup_); this.svgLid_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', - Blockly.pathToMedia + Blockly.SPRITE.url); + this.workspace_.options.pathToMedia + Blockly.SPRITE.url); this.animateLid_(); return this.svgGroup_; @@ -201,7 +201,6 @@ Blockly.Trashcan.prototype.createDom = function() { */ Blockly.Trashcan.prototype.init = function() { this.setOpen_(false); - this.position_(); // If the document resizes, reposition the trash can. Blockly.bindEvent_(window, 'resize', this, this.position_); }; @@ -230,7 +229,7 @@ Blockly.Trashcan.prototype.position_ = function() { // There are no metrics available (workspace is probably not visible). return; } - if (Blockly.RTL) { + if (this.workspace_.RTL) { this.left_ = this.MARGIN_SIDE_; } else { this.left_ = metrics.viewWidth + metrics.absoluteLeft - @@ -278,8 +277,8 @@ Blockly.Trashcan.prototype.animateLid_ = function() { this.lidOpen_ = goog.math.clamp(this.lidOpen_, 0, 1); var lidAngle = this.lidOpen_ * 45; this.svgLid_.setAttribute('transform', 'rotate(' + - (Blockly.RTL ? -lidAngle : lidAngle) + ', ' + - (Blockly.RTL ? 4 : this.WIDTH_ - 4) + ', ' + + (this.workspace_.RTL ? -lidAngle : lidAngle) + ', ' + + (this.workspace_.RTL ? 4 : this.WIDTH_ - 4) + ', ' + (this.LID_HEIGHT_ - 2) + ')'); var opacity = goog.math.lerp(0.4, 0.8, this.lidOpen_); this.svgGroup_.style.opacity = opacity; diff --git a/core/utils.js b/core/utils.js index dd95d9218..05243ee56 100644 --- a/core/utils.js +++ b/core/utils.js @@ -20,8 +20,8 @@ /** * @fileoverview Utility methods. - * These methods are not specific to Blockly, and could be factored out if - * a JavaScript framework such as Closure were used. + * These methods are not specific to Blockly, and could be factored out into + * a JavaScript framework such as Closure. * @author fraser@google.com (Neil Fraser) */ 'use strict'; @@ -97,9 +97,13 @@ Blockly.hasClass_ = function(element, className) { * @private */ Blockly.bindEvent_ = function(node, name, thisObject, func) { - var wrapFunc = function(e) { - func.call(thisObject, e); - }; + if (thisObject) { + var wrapFunc = function(e) { + func.call(thisObject, e); + }; + } else { + var wrapFunc = func; + } node.addEventListener(name, wrapFunc, false); var bindData = [[node, name, wrapFunc]]; // Add equivalent touch event. @@ -227,10 +231,23 @@ Blockly.noEvent = function(e) { e.stopPropagation(); }; +/** + * Is this event targeting a text input widget? + * @param {!Event} e An event. + * @return {boolean} True if text input. + * @private + */ +Blockly.isTargetInput_ = function(e) { + return e.target.type == 'textarea' || e.target.type == 'text' || + e.target.type == 'number' || e.target.type == 'email' || + e.target.type == 'password' || e.target.type == 'search' || + e.target.type == 'tel' || e.target.type == 'url'; +}; + /** * Return the coordinates of the top-left corner of this element relative to - * its parent. - * @param {!Element} element Element to find the coordinates of. + * its parent. Only for SVG elements and children (e.g. rect, g, path). + * @param {!Element} element SVG element to find the coordinates of. * @return {!Object} Object with .x and .y properties. * @private */ @@ -264,7 +281,7 @@ Blockly.getRelativeXY_ = function(element) { /** * Return the absolute coordinates of the top-left corner of this element. - * The origin (0,0) is the top-left corner of the Blockly svg. + * The origin (0,0) is the top-left corner of the nearest SVG. * @param {!Element} element Element to find the coordinates of. * @return {!Object} Object with .x and .y properties. * @private @@ -278,22 +295,10 @@ Blockly.getSvgXY_ = function(element) { x += xy.x; y += xy.y; element = element.parentNode; - } while (element && element != Blockly.svg); + } while (element && element.nodeName.toLowerCase() != 'svg'); return {x: x, y: y}; }; -/** - * Return the absolute coordinates of the top-left corner of this element. - * The origin (0,0) is the top-left corner of the page body. - * @param {!Element} element Element to find the coordinates of. - * @return {!Object} Object with .x and .y properties. - * @private - */ -Blockly.getAbsoluteXY_ = function(element) { - var xy = Blockly.getSvgXY_(element); - return Blockly.convertCoordinates(xy.x, xy.y, false); -}; - /** * Helper method for creating SVG elements. * @param {string} name Element's tag name. @@ -339,17 +344,18 @@ Blockly.isRightButton = function(e) { * @param {number} y Y input coordinate. * @param {boolean} toSvg True to convert to SVG coordinates. * False to convert to mouse/HTML coordinates. + * @param {!Element} svg SVG element. * @return {!Object} Object with x and y properties in output coordinates. */ -Blockly.convertCoordinates = function(x, y, toSvg) { +Blockly.convertCoordinates = function(x, y, toSvg, svg) { if (toSvg) { x -= window.scrollX || window.pageXOffset; y -= window.scrollY || window.pageYOffset; } - var svgPoint = Blockly.svg.createSVGPoint(); + var svgPoint = svg.createSVGPoint(); svgPoint.x = x; svgPoint.y = y; - var matrix = Blockly.svg.getScreenCTM(); + var matrix = svg.getScreenCTM(); if (toSvg) { matrix = matrix.inverse(); } @@ -365,13 +371,14 @@ Blockly.convertCoordinates = function(x, y, toSvg) { * Return the converted coordinates of the given mouse event. * The origin (0,0) is the top-left corner of the Blockly svg. * @param {!Event} e Mouse event. + * @param {!Element} svg SVG element. * @return {!Object} Object with .x and .y properties. */ -Blockly.mouseToSvg = function(e) { +Blockly.mouseToSvg = function(e, svg) { var scrollX = window.scrollX || window.pageXOffset; var scrollY = window.scrollY || window.pageYOffset; return Blockly.convertCoordinates(e.clientX + scrollX, - e.clientY + scrollY, true); + e.clientY + scrollY, true, svg); }; /** diff --git a/core/warning.js b/core/warning.js index a10ff15e9..79f176cdb 100644 --- a/core/warning.js +++ b/core/warning.js @@ -92,7 +92,7 @@ Blockly.Warning.prototype.setVisible = function(visible) { /** @type {!Blockly.Workspace} */ (this.block_.workspace), paragraph, this.block_.svgPath_, this.iconX_, this.iconY_, null, null); - if (Blockly.RTL) { + if (this.block_.RTL) { // Right-align the paragraph. // This cannot be done until the bubble is rendered on screen. var maxWidth = paragraph.getBBox().width; diff --git a/core/widgetdiv.js b/core/widgetdiv.js index fba6db4e2..75485bf75 100644 --- a/core/widgetdiv.js +++ b/core/widgetdiv.js @@ -33,7 +33,7 @@ goog.require('goog.dom'); /** - * The HTML container. Set once by inject.js's Blockly.createDom_. + * The HTML container. Set once by Blockly.WidgetDiv.createDom. * @type Element */ Blockly.WidgetDiv.DIV = null; @@ -52,16 +52,30 @@ Blockly.WidgetDiv.owner_ = null; */ Blockly.WidgetDiv.dispose_ = null; +/** + * Create the widget div and inject it onto the page. + */ +Blockly.WidgetDiv.createDom = function() { + if (Blockly.WidgetDiv.DIV) { + return; // Already created. + } + // Create an HTML container for popup overlays (e.g. editor widgets). + Blockly.WidgetDiv.DIV = goog.dom.createDom('div', 'blocklyWidgetDiv'); + document.body.appendChild(Blockly.WidgetDiv.DIV); +}; + /** * Initialize and display the widget div. Close the old one if needed. * @param {!Object} newOwner The object that will be using this container. + * @param {boolean} rtl Right-to-left (true) or left-to-right (false). * @param {Function} dispose Optional cleanup function to be run when the widget * is closed. */ -Blockly.WidgetDiv.show = function(newOwner, dispose) { +Blockly.WidgetDiv.show = function(newOwner, rtl, dispose) { Blockly.WidgetDiv.hide(); Blockly.WidgetDiv.owner_ = newOwner; Blockly.WidgetDiv.dispose_ = dispose; + Blockly.WidgetDiv.DIV.style.direction = rtl ? 'rtl' : 'ltr'; Blockly.WidgetDiv.DIV.style.display = 'block'; }; @@ -104,14 +118,15 @@ Blockly.WidgetDiv.hideIfOwner = function(oldOwner) { * @param {number} anchorY Vertical location (window coorditates, not body). * @param {!goog.math.Size} windowSize Height/width of window. * @param {!goog.math.Coordinate} scrollOffset X/y of window scrollbars. + * @param {boolean} rtl True if RTL, false if LTR. */ Blockly.WidgetDiv.position = function(anchorX, anchorY, windowSize, - scrollOffset) { + scrollOffset, rtl) { // Don't let the widget go above the top edge of the window. if (anchorY < scrollOffset.y) { anchorY = scrollOffset.y; } - if (Blockly.RTL) { + if (rtl) { // Don't let the menu go right of the right edge of the window. if (anchorX > windowSize.width + scrollOffset.x) { anchorX = windowSize.width + scrollOffset.x; diff --git a/core/workspace.js b/core/workspace.js index 6ab7e6322..520505cc4 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -32,14 +32,17 @@ goog.require('goog.math'); /** * Class for a workspace. This is a data structure that contains blocks. * There is no UI, and can be created headlessly. + * @param {Object} opt_options Dictionary of options. * @constructor */ -Blockly.Workspace = function() { +Blockly.Workspace = function(opt_options) { /** * @type {!Array.} * @private */ this.topBlocks_ = []; + this.options = opt_options || {}; + this.RTL = !!this.options.RTL; }; /** @@ -48,12 +51,6 @@ Blockly.Workspace = function() { */ Blockly.Workspace.prototype.rendered = false; -/** - * Maximum number of blocks allowed in this workspace. - * @type number - */ -Blockly.Workspace.prototype.maxBlocks = Infinity; - /** * Dispose of this workspace. * Unlink from all DOM elements to prevent memory leaks. @@ -109,7 +106,7 @@ Blockly.Workspace.prototype.getTopBlocks = function(ordered) { var blocks = [].concat(this.topBlocks_); if (ordered && blocks.length > 1) { var offset = Math.sin(goog.math.toRadians(Blockly.Workspace.SCAN_ANGLE)); - if (Blockly.RTL) { + if (this.RTL) { offset *= -1; } blocks.sort(function(a, b) { @@ -174,10 +171,10 @@ Blockly.Workspace.prototype.getBlockById = function(id) { * @return {number} Number of blocks left. */ Blockly.Workspace.prototype.remainingCapacity = function() { - if (this.maxBlocks == Infinity) { + if (isNaN(this.options.maxBlocks)) { return Infinity; } - return this.maxBlocks - this.getAllBlocks().length; + return this.options.maxBlocks - this.getAllBlocks().length; }; /** @@ -186,3 +183,34 @@ Blockly.Workspace.prototype.remainingCapacity = function() { Blockly.Workspace.prototype.fireChangeEvent = function() { // NOP. }; + +/** + * Modify the block tree on the existing toolbox. + * @param {Node|string} tree DOM tree of blocks, or text representation of same. + */ +Blockly.Workspace.prototype.updateToolbox = function(tree) { + tree = Blockly.parseToolboxTree_(tree); + if (!tree) { + if (this.options.languageTree) { + throw 'Can\'t nullify an existing toolbox.'; + } + // No change (null to null). + return; + } + if (!this.options.languageTree) { + throw 'Existing toolbox is null. Can\'t create new toolbox.'; + } + if (this.options.hasCategories) { + if (!this.toolbox_) { + throw 'Existing toolbox has no categories. Can\'t change mode.'; + } + this.options.languageTree = tree; + this.toolbox_.populate_(tree); + } else { + if (!this.flyout_) { + throw 'Existing toolbox has categories. Can\'t change mode.'; + } + this.options.languageTree = tree; + this.flyout_.show(tree.childNodes); + } +}; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index da0a6d7ed..5585fc270 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -32,24 +32,31 @@ goog.require('Blockly.ScrollbarPair'); goog.require('Blockly.Trashcan'); goog.require('Blockly.Workspace'); goog.require('Blockly.Xml'); + goog.require('goog.dom'); goog.require('goog.math.Coordinate'); +goog.require('goog.userAgent'); /** * Class for a workspace. This is an onscreen area with optional trashcan, * scrollbars, bubbles, and dragging. - * @param {Function} getMetrics A function that returns size/scrolling metrics. - * @param {Function} setMetrics A function that sets size/scrolling metrics. + * @param {!Object} options Dictionary of options. * @extends {Blockly.Workspace} * @constructor */ -Blockly.WorkspaceSvg = function(getMetrics, setMetrics) { - Blockly.WorkspaceSvg.superClass_.constructor.call(this); - this.getMetrics = getMetrics; - this.setMetrics = setMetrics; +Blockly.WorkspaceSvg = function(options) { + Blockly.WorkspaceSvg.superClass_.constructor.call(this, options); + this.getMetrics = options.getMetrics; + this.setMetrics = options.setMetrics; Blockly.ConnectionDB.init(this); + /** + * Database of pre-loaded sounds. + * @private + * @const + */ + this.SOUNDS_ = Object.create(null); }; goog.inherits(Blockly.WorkspaceSvg, Blockly.Workspace); @@ -66,10 +73,10 @@ Blockly.WorkspaceSvg.prototype.rendered = true; Blockly.WorkspaceSvg.prototype.isFlyout = false; /** - * Can this workspace be dragged around (true) or is it fixed (false)? + * Is this workspace currently being dragged around? * @type {boolean} */ -Blockly.WorkspaceSvg.prototype.dragMode = false; +Blockly.WorkspaceSvg.prototype.isScrolling = false; /** * Current horizontal scrolling offset. @@ -116,9 +123,27 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { this.svgBackground_ = Blockly.createSvgElement('rect', {'height': '100%', 'width': '100%', 'class': opt_backgroundClass}, this.svgGroup_); + if (opt_backgroundClass == 'blocklyMainBackground') { + this.svgBackground_.style.fill = + 'url(#' + this.options.gridPattern.id + ')'; + } } this.svgBlockCanvas_ = Blockly.createSvgElement('g', {}, this.svgGroup_); this.svgBubbleCanvas_ = Blockly.createSvgElement('g', {}, this.svgGroup_); + if (this.options.hasTrashcan) { + this.addTrashcan_(); + } + + Blockly.bindEvent_(this.svgGroup_, 'mousedown', this, this.onMouseDown_); + + // Determine if there needs to be a category tree, or a simple list of + // blocks. This cannot be changed later, since the UI is very different. + if (this.options.hasCategories) { + this.toolbox_ = new Blockly.Toolbox(this); + } else if (this.options.languageTree) { + this.addFlyout_(); + } + this.fireChangeEvent(); return this.svgGroup_; }; @@ -149,21 +174,25 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { /** * Add a trashcan. + * @private */ -Blockly.WorkspaceSvg.prototype.addTrashcan = function() { - if (Blockly.hasTrashcan && !Blockly.readOnly) { - this.trashcan = new Blockly.Trashcan(this); - var svgTrashcan = this.trashcan.createDom(); - this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); - this.trashcan.init(); - } +Blockly.WorkspaceSvg.prototype.addTrashcan_ = function() { + this.trashcan = new Blockly.Trashcan(this); + var svgTrashcan = this.trashcan.createDom(); + this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); + this.trashcan.init(); }; /** * Add a flyout. + * @private */ -Blockly.WorkspaceSvg.prototype.addFlyout = function() { - this.flyout_ = new Blockly.Flyout(); +Blockly.WorkspaceSvg.prototype.addFlyout_ = function() { + var workspaceOptions = { + parentWorkspace: this, + RTL: this.RTL + }; + this.flyout_ = new Blockly.Flyout(workspaceOptions); this.flyout_.autoClose = false; var svgFlyout = this.flyout_.createDom(); this.svgGroup_.insertBefore(svgFlyout, this.svgBlockCanvas_); @@ -202,7 +231,7 @@ Blockly.WorkspaceSvg.prototype.translate = function(x, y) { */ Blockly.WorkspaceSvg.prototype.addTopBlock = function(block) { Blockly.WorkspaceSvg.superClass_.addTopBlock.call(this, block); - if (Blockly.Realtime.isEnabled() && this == Blockly.mainWorkspace) { + if (Blockly.Realtime.isEnabled() && !this.options.parentWorkspace) { Blockly.Realtime.addTopBlock(block); } }; @@ -213,19 +242,11 @@ Blockly.WorkspaceSvg.prototype.addTopBlock = function(block) { */ Blockly.WorkspaceSvg.prototype.removeTopBlock = function(block) { Blockly.WorkspaceSvg.superClass_.removeTopBlock.call(this, block); - if (Blockly.Realtime.isEnabled() && this == Blockly.mainWorkspace) { + if (Blockly.Realtime.isEnabled() && !this.options.parentWorkspace) { Blockly.Realtime.removeTopBlock(block); } }; -/** - * Dispose of all blocks in workspace. - */ -Blockly.WorkspaceSvg.prototype.clear = function() { - Blockly.hideChaff(); - Blockly.WorkspaceSvg.superClass_.clear.call(this); -}; - /** * Returns the horizontal offset of the workspace. * Intended for LTR/RTL compatibility in XML. @@ -302,7 +323,7 @@ Blockly.WorkspaceSvg.prototype.highlightBlock = function(id) { * edits, mutations, connections, etc. Groups of simultaneous changes (e.g. * a tree of blocks being deleted) are merged into one event. * Applications may hook workspace changes by listening for - * 'blocklyWorkspaceChange' on Blockly.mainWorkspace.getCanvas(). + * 'blocklyWorkspaceChange' on workspace.getCanvas(). */ Blockly.WorkspaceSvg.prototype.fireChangeEvent = function() { if (this.rendered && this.svgBlockCanvas_) { @@ -315,16 +336,17 @@ Blockly.WorkspaceSvg.prototype.fireChangeEvent = function() { * @param {!Element} xmlBlock XML block element. */ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { - if (xmlBlock.getElementsByTagName('block').length >= + if (!this.rendered || xmlBlock.getElementsByTagName('block').length >= this.remainingCapacity()) { return; } + Blockly.terminateDrag_(); // Dragging while pasting? No. var block = Blockly.Xml.domToBlock(this, xmlBlock); // Move the duplicate to original position. var blockX = parseInt(xmlBlock.getAttribute('x'), 10); var blockY = parseInt(xmlBlock.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { - if (Blockly.RTL) { + if (this.RTL) { blockX = -blockX; } // Offset block until not clobbering another block. @@ -335,7 +357,7 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { var otherXY = otherBlock.getRelativeToSurfaceXY(); if (Math.abs(blockX - otherXY.x) <= 1 && Math.abs(blockY - otherXY.y) <= 1) { - if (Blockly.RTL) { + if (this.RTL) { blockX -= Blockly.SNAP_RADIUS; } else { blockX += Blockly.SNAP_RADIUS; @@ -376,7 +398,7 @@ Blockly.WorkspaceSvg.prototype.recordDeleteAreas = function() { */ Blockly.WorkspaceSvg.prototype.isDeleteArea = function(e) { var isDelete = false; - var mouseXY = Blockly.mouseToSvg(e); + var mouseXY = Blockly.mouseToSvg(e, this.options.svg); var xy = new goog.math.Coordinate(mouseXY.x, mouseXY.y); if (this.deleteAreaTrash_) { if (this.deleteAreaTrash_.contains(xy)) { @@ -396,5 +418,225 @@ Blockly.WorkspaceSvg.prototype.isDeleteArea = function(e) { return false; }; +/** + * Handle a mouse-down on SVG drawing surface. + * @param {!Event} e Mouse down event. + * @private + */ +Blockly.WorkspaceSvg.prototype.onMouseDown_ = function(e) { + this.markFocused(); + if (Blockly.isTargetInput_(e)) { + return; + } + Blockly.svgResize(this); + Blockly.terminateDrag_(); // In case mouse-up event was lost. + Blockly.hideChaff(); + var isTargetWorkspace = e.target && e.target.nodeName && + (e.target.nodeName.toLowerCase() == 'svg' || + e.target == this.svgBackground_); + if (isTargetWorkspace && Blockly.selected && !this.options.readOnly) { + // Clicking on the document clears the selection. + Blockly.selected.unselect(); + } + if (Blockly.isRightButton(e)) { + // Right-click. + this.showContextMenu_(e); + } else if (this.scrollbar) { + Blockly.removeAllRanges(); + // If the workspace is editable, only allow scrolling when gripping empty + // space. Otherwise, allow scrolling when gripping anywhere. + this.isScrolling = true; + // Record the current mouse position. + this.startDragMouseX = e.clientX; + this.startDragMouseY = e.clientY; + this.startDragMetrics = this.getMetrics(); + this.startScrollX = this.scrollX; + this.startScrollY = this.scrollY; + + // If this is a touch event then bind to the mouseup so workspace drag mode + // is turned off and double move events are not performed on a block. + // See comment in inject.js Blockly.init_ as to why mouseup events are + // bound to the document instead of the SVG's surface. + if ('mouseup' in Blockly.bindEvent_.TOUCH_MAP) { + Blockly.onTouchUpWrapper_ = + Blockly.bindEvent_(document, 'mouseup', null, Blockly.onMouseUp_); + } + Blockly.onMouseMoveWrapper_ = + Blockly.bindEvent_(document, 'mousemove', null, Blockly.onMouseMove_); + } + // This event has been handled. No need to bubble up to the document. + e.stopPropagation(); +}; + +/** + * Show the context menu for the workspace. + * @param {!Event} e Mouse event. + * @private + */ +Blockly.WorkspaceSvg.prototype.showContextMenu_ = function(e) { + if (this.options.readOnly) { + return; + } + var menuOptions = []; + // Add a little animation to collapsing and expanding. + var COLLAPSE_DELAY = 10; + + if (this.options.collapse) { + var hasCollapsedBlocks = false; + var hasExpandedBlocks = false; + var topBlocks = this.getTopBlocks(false); + for (var i = 0; i < topBlocks.length; i++) { + var block = topBlocks[i]; + while (block) { + if (block.isCollapsed()) { + hasCollapsedBlocks = true; + } else { + hasExpandedBlocks = true; + } + block = block.getNextBlock(); + } + } + + // Option to collapse top blocks. + var collapseOption = {enabled: hasExpandedBlocks}; + collapseOption.text = Blockly.Msg.COLLAPSE_ALL; + collapseOption.callback = function() { + var ms = 0; + for (var i = 0; i < topBlocks.length; i++) { + var block = topBlocks[i]; + while (block) { + setTimeout(block.setCollapsed.bind(block, true), ms); + block = block.getNextBlock(); + ms += COLLAPSE_DELAY; + } + } + }; + menuOptions.push(collapseOption); + + // Option to expand top blocks. + var expandOption = {enabled: hasCollapsedBlocks}; + expandOption.text = Blockly.Msg.EXPAND_ALL; + expandOption.callback = function() { + var ms = 0; + for (var i = 0; i < topBlocks.length; i++) { + var block = topBlocks[i]; + while (block) { + setTimeout(block.setCollapsed.bind(block, false), ms); + block = block.getNextBlock(); + ms += COLLAPSE_DELAY; + } + } + }; + menuOptions.push(expandOption); + } + + Blockly.ContextMenu.show(e, menuOptions, this.RTL); +}; + +/** + * Load an audio file. Cache it, ready for instantaneous playing. + * @param {!Array.} filenames List of file types in decreasing order of + * preference (i.e. increasing size). E.g. ['media/go.mp3', 'media/go.wav'] + * Filenames include path from Blockly's root. File extensions matter. + * @param {string} name Name of sound. + * @private + */ +Blockly.WorkspaceSvg.prototype.loadAudio_ = function(filenames, name) { + if (!window['Audio'] || !filenames.length) { + // No browser support for Audio. + return; + } + var sound; + var audioTest = new window['Audio'](); + for (var i = 0; i < filenames.length; i++) { + var filename = filenames[i]; + var ext = filename.match(/\.(\w+)$/); + if (ext && audioTest.canPlayType('audio/' + ext[1])) { + // Found an audio format we can play. + sound = new window['Audio'](filename); + break; + } + } + if (sound && sound.play) { + this.SOUNDS_[name] = sound; + } +}; + +/** + * Preload all the audio files so that they play quickly when asked for. + * @private + */ +Blockly.WorkspaceSvg.prototype.preloadAudio_ = function() { + for (var name in this.SOUNDS_) { + var sound = this.SOUNDS_[name]; + sound.volume = .01; + sound.play(); + sound.pause(); + // iOS can only process one sound at a time. Trying to load more than one + // corrupts the earlier ones. Just load one and leave the others uncached. + if (goog.userAgent.IPAD || goog.userAgent.IPHONE) { + break; + } + } +}; + +/** + * Play an audio file at specified value. If volume is not specified, + * use full volume (1). + * @param {string} name Name of sound. + * @param {?number} opt_volume Volume of sound (0-1). + */ +Blockly.WorkspaceSvg.prototype.playAudio = function(name, opt_volume) { + var sound = this.SOUNDS_[name]; + if (sound) { + var mySound; + var ie9 = goog.userAgent.DOCUMENT_MODE && + goog.userAgent.DOCUMENT_MODE === 9; + if (ie9 || goog.userAgent.IPAD || goog.userAgent.ANDROID) { + // Creating a new audio node causes lag in IE9, Android and iPad. Android + // and IE9 refetch the file from the server, iPad uses a singleton audio + // node which must be deleted and recreated for each new audio tag. + mySound = sound; + } else { + mySound = sound.cloneNode(); + } + mySound.volume = (opt_volume === undefined ? 1 : opt_volume); + mySound.play(); + } else if (this.options.parentWorkspace) { + // Maybe a workspace on a lower level knows about this sound. + this.options.parentWorkspace.playAudio(name, opt_volume); + } +}; + +/** + * When something in this workspace changes, call a function. + * @param {!Function} func Function to call. + * @return {!Array.} Opaque data that can be passed to + * removeChangeListener. + */ +Blockly.WorkspaceSvg.prototype.addChangeListener = function(func) { + return Blockly.bindEvent_(this.getCanvas(), + 'blocklyWorkspaceChange', null, func); +}; + +/** + * Stop listening for this workspace's changes. + * @param {!Array.} bindData Opaque data from addChangeListener. + */ +Blockly.WorkspaceSvg.prototype.removeChangeListener = function(bindData) { + Blockly.unbindEvent_(bindData); +}; + +/** + * Mark this workspace as the currently focused main workspace. + */ +Blockly.WorkspaceSvg.prototype.markFocused = function() { + Blockly.mainWorkspace = this; +}; + // Export symbols that would otherwise be renamed by Closure compiler. Blockly.WorkspaceSvg.prototype['clear'] = Blockly.WorkspaceSvg.prototype.clear; +Blockly.WorkspaceSvg.prototype['addChangeListener'] = + Blockly.WorkspaceSvg.prototype.addChangeListener; +Blockly.WorkspaceSvg.prototype['removeChangeListener'] = + Blockly.WorkspaceSvg.prototype.removeChangeListener; diff --git a/core/xml.js b/core/xml.js index c0bebacf3..6095464f5 100644 --- a/core/xml.js +++ b/core/xml.js @@ -38,7 +38,7 @@ goog.require('goog.dom'); */ Blockly.Xml.workspaceToDom = function(workspace) { var width; // Not used in LTR. - if (Blockly.RTL) { + if (workspace.RTL) { width = workspace.getWidth(); } var xml = goog.dom.createDom('xml'); @@ -46,7 +46,7 @@ Blockly.Xml.workspaceToDom = function(workspace) { for (var i = 0, block; block = blocks[i]; i++) { var element = Blockly.Xml.blockToDom_(block); var xy = block.getRelativeToSurfaceXY(); - element.setAttribute('x', Blockly.RTL ? width - xy.x : xy.x); + element.setAttribute('x', workspace.RTL ? width - xy.x : xy.x); element.setAttribute('y', xy.y); xml.appendChild(element); } @@ -223,7 +223,7 @@ Blockly.Xml.textToDom = function(text) { */ Blockly.Xml.domToWorkspace = function(workspace, xml) { var width; // Not used in LTR. - if (Blockly.RTL) { + if (workspace.RTL) { width = workspace.getWidth(); } // Safari 7.1.3 is known to provide node lists with extra references to @@ -237,7 +237,7 @@ Blockly.Xml.domToWorkspace = function(workspace, xml) { var blockX = parseInt(xmlChild.getAttribute('x'), 10); var blockY = parseInt(xmlChild.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { - block.moveBy(Blockly.RTL ? width - blockX : blockX, blockY); + block.moveBy(workspace.RTL ? width - blockX : blockX, blockY); } } } diff --git a/demos/blockfactory/factory.js b/demos/blockfactory/factory.js index 8cbeffdac..648fd9616 100644 --- a/demos/blockfactory/factory.js +++ b/demos/blockfactory/factory.js @@ -29,13 +29,16 @@ var blockType = ''; /** - * Initialize Blockly. Called on page load. - * @param {!Function} updateFunc Function to update the preview. + * Workspace for user to build block. + * @type Blockly.Workspace */ -function initPreview(updateFunc) { - updatePreview.updateFunc = updateFunc; - updatePreview(); -} +var mainWorkspace = null; + +/** + * Workspace for preview of block. + * @type Blockly.Workspace + */ +var previewWorkspace = null; /** * When the workspace changes, update the three other displays. @@ -382,7 +385,10 @@ function updateGenerator() { injectCode(code, 'generatorPre'); } -var oldDir = 'ltr'; +/** + * Existing direction ('ltr' vs 'rtl') of preview. + */ +var oldDir = null; /** * Update the preview display. @@ -390,12 +396,22 @@ var oldDir = 'ltr'; function updatePreview() { var newDir = document.getElementById('direction').value; if (oldDir != newDir) { - document.getElementById('previewFrame').src = 'preview.html?' + newDir; + var previewDiv = document.getElementById('preview'); + previewDiv.innerHTML = ''; + var rtl = newDir == 'rtl'; + previewWorkspace = Blockly.inject(previewDiv, {rtl: rtl}); oldDir = newDir; - } else if (updatePreview.updateFunc) { - var code = document.getElementById('languagePre').textContent; - updatePreview.updateFunc(blockType, code); } + var code = document.getElementById('languagePre').textContent; + previewWorkspace.clear(); + eval(code); + // Create the preview block. + var previewBlock = Blockly.Block.obtain(previewWorkspace, blockType); + previewBlock.initSvg(); + previewBlock.render(); + previewBlock.setMovable(false); + previewBlock.setDeletable(false); + previewBlock.moveBy(15, 10); } /** @@ -417,7 +433,7 @@ function injectCode(code, id) { * @return {Blockly.Block} */ function getRootBlock() { - var blocks = Blockly.mainWorkspace.getTopBlocks(false); + var blocks = mainWorkspace.getTopBlocks(false); for (var i = 0, block; block = blocks[i]; i++) { if (block.type == 'factory_base') { return block; @@ -451,7 +467,7 @@ function init() { var expandList = [ document.getElementById('blockly'), - document.getElementById('previewFrame'), + document.getElementById('preview'), document.getElementById('languagePre'), document.getElementById('generatorPre') ]; @@ -465,20 +481,21 @@ function init() { window.addEventListener('resize', onresize); var toolbox = document.getElementById('toolbox'); - Blockly.inject(document.getElementById('blockly'), {toolbox: toolbox}); + mainWorkspace = + Blockly.inject(document.getElementById('blockly'), {toolbox: toolbox}); // Create the root block. if ('BlocklyStorage' in window && window.location.hash.length > 1) { BlocklyStorage.retrieveXml(window.location.hash.substring(1)); } else { - var rootBlock = Blockly.Block.obtain(Blockly.mainWorkspace, 'factory_base'); + var rootBlock = Blockly.Block.obtain(mainWorkspace, 'factory_base'); rootBlock.initSvg(); rootBlock.render(); rootBlock.setMovable(false); rootBlock.setDeletable(false); } - Blockly.addChangeListener(onchange); + mainWorkspace.addChangeListener(onchange); document.getElementById('direction') .addEventListener('change', updatePreview); document.getElementById('language') diff --git a/demos/blockfactory/index.html b/demos/blockfactory/index.html index 0ffab14ed..4fb4e61ac 100644 --- a/demos/blockfactory/index.html +++ b/demos/blockfactory/index.html @@ -38,8 +38,7 @@ #blockly { position: fixed; } - #previewFrame { - border: none; + #preview { position: absolute; } pre { @@ -116,7 +115,7 @@ diff --git a/demos/blockfactory/preview.html b/demos/blockfactory/preview.html deleted file mode 100644 index 57e821d56..000000000 --- a/demos/blockfactory/preview.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - Block Factory Preview - - - - - - - - diff --git a/demos/blockfactory/preview.js b/demos/blockfactory/preview.js deleted file mode 100644 index 37cd99674..000000000 --- a/demos/blockfactory/preview.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Blockly Demos: Block Factory - * - * Copyright 2013 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview JavaScript for Blockly's Block Factory preview. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -/** - * The uneditable preview block. - * @type {Blockly.Block} - */ -var previewBlock = null; - -/** - * Create the specified block in this preview pane. - * @param {string} type Name of block. - * @param {string} code JavaScript code to create a block. - */ -function updateFunc(type, code) { - if (previewBlock) { - previewBlock.dispose(); - previewBlock = null; - } - eval(code); - // Create the preview block. - previewBlock = Blockly.Block.obtain(Blockly.mainWorkspace, type); - previewBlock.initSvg(); - previewBlock.render(); - previewBlock.setMovable(false); - previewBlock.setDeletable(false); - previewBlock.moveBy(15, 10); -} - -/** - * Initialize Blockly. Called on page load. - */ -function init() { - var rtl = (document.location.search == '?rtl'); - Blockly.inject(document.body, {rtl: rtl}); - - try { - // Let the top-level application know that Blockly is ready. - window.parent.initPreview(updateFunc); - } catch (e) { - // Attempt to diagnose the problem. - var msg = 'Error: Unable to communicate between frames.\n' + - 'The preview frame will not be functional.\n\n'; - if (window.parent == window) { - msg += 'Try loading index.html instead of preview.html'; - } else if (window.location.protocol == 'file:') { - msg += 'This may be due to a security restriction preventing\n' + - 'access when using the file:// protocol.\n\n' + - 'Try using a different browser, or use the Block Factory online at:\n' + - 'https://blockly-demo.appspot.com/static/demos/blockfactory/index.html'; - } - alert(msg); - } -} - -window.addEventListener('load', init); diff --git a/demos/code/code.js b/demos/code/code.js index 8a0b18a2c..53e15bdae 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -80,6 +80,12 @@ Code.LANGUAGE_NAME = { */ Code.LANGUAGE_RTL = ['ar', 'fa', 'he']; +/** + * Blockly's main workspace. + * @type Blockly.WorkspaceSvg + */ +Code.workspace = null; + /** * Extracts a parameter from the URL. * If the parameter is absent default_value is returned. @@ -132,11 +138,11 @@ Code.loadBlocks = function(defaultXml) { // Language switching stores the blocks during the reload. delete window.sessionStorage.loadOnceBlocks; var xml = Blockly.Xml.textToDom(loadOnce); - Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, xml); + Blockly.Xml.domToWorkspace(Code.workspace, xml); } else if (defaultXml) { // Load the editor with default starting blocks. var xml = Blockly.Xml.textToDom(defaultXml); - Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, xml); + Blockly.Xml.domToWorkspace(Code.workspace, xml); } else if ('BlocklyStorage' in window) { // Restore saved blocks in a separate thread so that subsequent // initialization is not affected from a failed load. @@ -153,7 +159,7 @@ Code.changeLanguage = function() { // not load Blockly. // MSIE 11 does not support sessionStorage on file:// URLs. if (typeof Blockly != 'undefined' && window.sessionStorage) { - var xml = Blockly.Xml.workspaceToDom(Blockly.mainWorkspace); + var xml = Blockly.Xml.workspaceToDom(Code.workspace); var text = Blockly.Xml.domToText(xml); window.sessionStorage.loadOnceBlocks = text; } @@ -262,8 +268,8 @@ Code.tabClick = function(clickedName) { } } if (xmlDom) { - Blockly.mainWorkspace.clear(); - Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, xmlDom); + Code.workspace.clear(); + Blockly.Xml.domToWorkspace(Code.workspace, xmlDom); } } @@ -292,12 +298,12 @@ Code.renderContent = function() { // Initialize the pane. if (content.id == 'content_xml') { var xmlTextarea = document.getElementById('content_xml'); - var xmlDom = Blockly.Xml.workspaceToDom(Blockly.mainWorkspace); + var xmlDom = Blockly.Xml.workspaceToDom(Code.workspace); var xmlText = Blockly.Xml.domToPrettyText(xmlDom); xmlTextarea.value = xmlText; xmlTextarea.focus(); } else if (content.id == 'content_javascript') { - var code = Blockly.JavaScript.workspaceToCode(); + var code = Blockly.JavaScript.workspaceToCode(Code.workspace); content.textContent = code; if (typeof prettyPrintOne == 'function') { code = content.innerHTML; @@ -305,7 +311,7 @@ Code.renderContent = function() { content.innerHTML = code; } } else if (content.id == 'content_python') { - code = Blockly.Python.workspaceToCode(); + code = Blockly.Python.workspaceToCode(Code.workspace); content.textContent = code; if (typeof prettyPrintOne == 'function') { code = content.innerHTML; @@ -313,7 +319,7 @@ Code.renderContent = function() { content.innerHTML = code; } } else if (content.id == 'content_dart') { - code = Blockly.Dart.workspaceToCode(); + code = Blockly.Dart.workspaceToCode(Code.workspace); content.textContent = code; if (typeof prettyPrintOne == 'function') { code = content.innerHTML; @@ -357,16 +363,16 @@ Code.init = function() { el.style.width = (2 * bBox.width - el.offsetWidth) + 'px'; } // Make the 'Blocks' tab line up with the toolbox. - if (Blockly.mainWorkspace.toolbox_.width) { + if (Code.workspace.toolbox_.width) { document.getElementById('tab_blocks').style.minWidth = - (Blockly.mainWorkspace.toolbox_.width - 38) + 'px'; + (Code.workspace.toolbox_.width - 38) + 'px'; // Account for the 19 pixel margin and on each side. } }; window.addEventListener('resize', onresize, false); var toolbox = document.getElementById('toolbox'); - Blockly.inject(document.getElementById('content_blocks'), + Code.workspace = Blockly.inject(document.getElementById('content_blocks'), {grid: {spacing: 25, length: 3, @@ -490,10 +496,10 @@ Code.runJS = function() { * Discard all blocks from the workspace. */ Code.discard = function() { - var count = Blockly.mainWorkspace.getAllBlocks().length; + var count = Code.workspace.getAllBlocks().length; if (count < 2 || window.confirm(MSG['discard'].replace('%1', count))) { - Blockly.mainWorkspace.clear(); + Code.workspace.clear(); window.location.hash = ''; } }; diff --git a/demos/generator/index.html b/demos/generator/index.html index dbdf107e4..fa3f7026e 100644 --- a/demos/generator/index.html +++ b/demos/generator/index.html @@ -113,7 +113,7 @@
- +