Automatic commit Sat Feb 8 03:00:02 PST 2014

This commit is contained in:
ellen.spertus 2014-02-08 03:00:02 -08:00
parent 1eb3a30f7e
commit 2d6a91ebcd
7 changed files with 212 additions and 74 deletions

View file

@ -1012,25 +1012,56 @@ Blockly.Procedures.findLegalName=function(a,b){if(b.isInFlyout)return a;for(;!Bl
Blockly.Procedures.rename=function(a){a=a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"");a=Blockly.Procedures.findLegalName(a,this.sourceBlock_);for(var b=this.sourceBlock_.workspace.getAllBlocks(),c=0;c<b.length;c++){var d=b[c].renameProcedure;d&&d.call(b[c],this.text_,a)}return a};
Blockly.Procedures.flyoutCategory=function(a,b,c,d){function e(e,f){for(var k=0;k<e.length;k++){var l=Blockly.Block.obtain(d,f);l.setFieldValue(e[k][0],"NAME");for(var q=[],m=0;m<e[k][1].length;m++)q[m]="ARG"+m;l.setProcedureParameters(e[k][1],q);l.initSvg();a.push(l);b.push(2*c)}}if(Blockly.Blocks.procedures_defnoreturn){var f=Blockly.Block.obtain(d,"procedures_defnoreturn");f.initSvg();a.push(f);b.push(2*c)}Blockly.Blocks.procedures_defreturn&&(f=Blockly.Block.obtain(d,"procedures_defreturn"),f.initSvg(),
a.push(f),b.push(2*c));Blockly.Blocks.procedures_ifreturn&&(f=Blockly.Block.obtain(d,"procedures_ifreturn"),f.initSvg(),a.push(f),b.push(2*c));b.length&&(b[b.length-1]=3*c);f=Blockly.Procedures.allProcedures();e(f[0],"procedures_callnoreturn");e(f[1],"procedures_callreturn")};Blockly.Procedures.getCallers=function(a,b){for(var c=[],d=b.getAllBlocks(),e=0;e<d.length;e++){var f=d[e].getProcedureCall;f&&(f=f.call(d[e]))&&Blockly.Names.equals(f,a)&&c.push(d[e])}return c};
Blockly.Procedures.disposeCallers=function(a,b){for(var c=Blockly.Procedures.getCallers(a,b),d=0;d<c.length;d++)c[d].dispose(!0,!1)};Blockly.Procedures.mutateCallers=function(a,b,c,d){a=Blockly.Procedures.getCallers(a,b);for(b=0;b<a.length;b++)a[b].setProcedureParameters(c,d)};Blockly.Procedures.getDefinition=function(a,b){for(var c=b.getAllBlocks(),d=0;d<c.length;d++){var e=c[d].getProcedureDef;if(e&&(e=e.call(c[d]))&&Blockly.Names.equals(e[0],a))return c[d]}return null};
Blockly.Procedures.disposeCallers=function(a,b){for(var c=Blockly.Procedures.getCallers(a,b),d=0;d<c.length;d++)c[d].dispose(!0,!1)};Blockly.Procedures.mutateCallers=function(a,b,c,d){a=Blockly.Procedures.getCallers(a,b);for(b=0;b<a.length;b++)a[b].setProcedureParameters(c,d)};Blockly.Procedures.getDefinition=function(a,b){for(var c=b.getAllBlocks(),d=0;d<c.length;d++){var e=c[d].getProcedureDef;if(e&&(e=e.call(c[d]))&&Blockly.Names.equals(e[0],a))return c[d]}return null};/*
Copyright 2013 Google Inc. All Rights Reserved.
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.
*/
var rtclient={INSTALL_SCOPE:"https://www.googleapis.com/auth/drive.install",FILE_SCOPE:"https://www.googleapis.com/auth/drive.file",OPENID_SCOPE:"openid",REALTIME_MIMETYPE:"application/vnd.google-apps.drive-sdk",getParams:function(){var a={},b=window.location.hash;if(b)for(var b=b.slice(1).split("&"),c=0;c<b.length;c++){var d=b[c].split("=");a[d[0]]=unescape(d[1])}if(b=window.location.search)for(b=b.slice(1).split("&"),c=0;c<b.length;c++)d=b[c].split("="),a[d[0]]=unescape(d[1]);console.log(a);return a}};
rtclient.params=rtclient.getParams();rtclient.getOption=function(a,b,c){if(a.hasOwnProperty(b))return a[b];void 0===c&&console.error(b+" should be present in the options.");return c};rtclient.Authorizer=function(a){this.clientId=rtclient.getOption(a,"clientId");this.userId=rtclient.params.userId;this.authButton=document.getElementById(rtclient.getOption(a,"authButtonElementId"));this.authDiv=document.getElementById(rtclient.getOption(a,"authDivElementId"))};
rtclient.Authorizer.prototype.start=function(a){var b=this;gapi.load("auth:client,drive-realtime,drive-share",function(){b.authorize(a)})};
rtclient.Authorizer.prototype.authorize=function(a){var b=this.clientId,c=this.userId,d=this,e=function(b){b&&!b.error?(d.authButton.disabled=!0,d.fetchUserId(a),d.authDiv.style.display="none"):(d.authButton.disabled=!1,d.authButton.onclick=f,d.authDiv.style.display="block")},f=function(){gapi.auth.authorize({client_id:b,scope:[rtclient.INSTALL_SCOPE,rtclient.FILE_SCOPE,rtclient.OPENID_SCOPE],user_id:c,immediate:!1},e)};gapi.auth.authorize({client_id:b,scope:[rtclient.INSTALL_SCOPE,rtclient.FILE_SCOPE,
rtclient.OPENID_SCOPE],user_id:c,immediate:!0},e)};rtclient.Authorizer.prototype.fetchUserId=function(a){var b=this;gapi.client.load("oauth2","v2",function(){gapi.client.oauth2.userinfo.get().execute(function(c){c.id&&(b.userId=c.id);a&&a()})})};rtclient.createRealtimeFile=function(a,b,c){gapi.client.load("drive","v2",function(){gapi.client.drive.files.insert({resource:{mimeType:b,title:a}}).execute(c)})};rtclient.getFileMetadata=function(a,b){gapi.client.load("drive","v2",function(){gapi.client.drive.files.get({fileId:a}).execute(b)})};
rtclient.parseState=function(a){try{return JSON.parse(a)}catch(b){return null}};
rtclient.RealtimeLoader=function(a){this.onFileLoaded=rtclient.getOption(a,"onFileLoaded");this.newFileMimeType=rtclient.getOption(a,"newFileMimeType",rtclient.REALTIME_MIMETYPE);this.initializeModel=rtclient.getOption(a,"initializeModel");this.registerTypes=rtclient.getOption(a,"registerTypes",function(){});this.afterAuth=rtclient.getOption(a,"afterAuth",function(){});this.autoCreate=rtclient.getOption(a,"autoCreate",!1);this.defaultTitle=rtclient.getOption(a,"defaultTitle","New Realtime File");
this.afterCreate=rtclient.getOption(a,"afterCreate",function(){});this.authorizer=new rtclient.Authorizer(a)};
rtclient.RealtimeLoader.prototype.redirectTo=function(a,b){var c=[];a&&c.push("fileIds="+a.join(","));b&&c.push("userId="+b);c=0==c.length?window.location.pathname:window.location.pathname+"#"+c.join("&");window.history&&window.history.replaceState?window.history.replaceState("Google Drive Realtime API Playground","Google Drive Realtime API Playground",c):window.location.href=c;rtclient.params=rtclient.getParams();for(var d in a)gapi.drive.realtime.load(a[d],this.onFileLoaded,this.initializeModel,
this.handleErrors)};rtclient.RealtimeLoader.prototype.start=function(){var a=this;this.authorizer.start(function(){a.registerTypes&&a.registerTypes();a.afterAuth&&a.afterAuth();a.load()})};
rtclient.RealtimeLoader.prototype.handleErrors=function(a){a.type==gapi.drive.realtime.ErrorType.TOKEN_REFRESH_REQUIRED?this.authorizer.authorize():a.type==gapi.drive.realtime.ErrorType.CLIENT_ERROR?(alert("An Error happened: "+a.message),window.location.href="/"):a.type==gapi.drive.realtime.ErrorType.NOT_FOUND&&(alert("The file was not found. It does not exist or you do not have read access to the file."),window.location.href="/")};
rtclient.RealtimeLoader.prototype.load=function(){var a=rtclient.params.fileIds;a&&(a=a.split(","));var b=this.authorizer.userId,b=rtclient.params.state;if(a)for(var c in a)gapi.drive.realtime.load(a[c],this.onFileLoaded,this.initializeModel,this.handleErrors);else{if(b&&(c=rtclient.parseState(b),"open"==c.action)){a=c.ids;b=c.userId;this.redirectTo(a,b);return}this.autoCreate&&this.createNewFileAndRedirect()}};
rtclient.RealtimeLoader.prototype.createNewFileAndRedirect=function(){var a=this;rtclient.createRealtimeFile(this.defaultTitle,this.newFileMimeType,function(b){b.id?(a.afterCreate&&a.afterCreate(b.id),a.redirectTo([b.id],a.authorizer.userId)):(console.error("Error creating file."),console.error(b))})};
// Copyright 2014 Google Inc. Apache License 2.0
Blockly.Realtime={};Blockly.Realtime.enabled_=!1;Blockly.Realtime.model_=null;Blockly.Realtime.initUi_=null;Blockly.Realtime.blocksMap_=null;Blockly.Realtime.withinSync=!1;Blockly.Realtime.realtimeLoader_=null;Blockly.Realtime.isEnabled=function(){return Blockly.Realtime.enabled_};
Blockly.Realtime.initializeModel_=function(a){Blockly.Realtime.model_=a;var b=a.createMap();a.getRoot().set("blocks",b);b=a.createList();a.getRoot().set("topBlocks",b);b=a.createString(Blockly.Msg.CHAT);a.getRoot().set("text",b)};Blockly.Realtime.removeBlock=function(a){Blockly.Realtime.blocksMap_["delete"](a.id.toString())};Blockly.Realtime.addTopBlock=function(a){-1==Blockly.Realtime.topBlocks_.indexOf(a)&&Blockly.Realtime.topBlocks_.push(a)};Blockly.Realtime.removeTopBlock=function(a){Blockly.Realtime.topBlocks_.removeValue(a)};
Blockly.Realtime.obtainBlock=function(a,b){return Blockly.Realtime.model_.create(Blockly.Block,a,b)};Blockly.Realtime.getBlockById=function(a){return Blockly.Realtime.blocksMap_.get(a)};
Blockly.Realtime={};Blockly.Realtime.enabled_=!1;Blockly.Realtime.model_=null;Blockly.Realtime.initUi_=null;Blockly.Realtime.blocksMap_=null;Blockly.Realtime.withinSync=!1;Blockly.Realtime.realtimeLoader_=null;Blockly.Realtime.chatBoxElementId_=null;Blockly.Realtime.chatBoxInitialText_=null;Blockly.Realtime.isEnabled=function(){return Blockly.Realtime.enabled_};
Blockly.Realtime.initializeModel_=function(a){Blockly.Realtime.model_=a;var b=a.createMap();a.getRoot().set("blocks",b);b=a.createList();a.getRoot().set("topBlocks",b);Blockly.Realtime.chatBoxElementId_&&a.getRoot().set(Blockly.Realtime.chatBoxElementId_,a.createString(Blockly.Realtime.chatBoxInitialText_))};Blockly.Realtime.removeBlock=function(a){Blockly.Realtime.blocksMap_["delete"](a.id.toString())};Blockly.Realtime.addTopBlock=function(a){-1==Blockly.Realtime.topBlocks_.indexOf(a)&&Blockly.Realtime.topBlocks_.push(a)};
Blockly.Realtime.removeTopBlock=function(a){Blockly.Realtime.topBlocks_.removeValue(a)};Blockly.Realtime.obtainBlock=function(a,b){return Blockly.Realtime.model_.create(Blockly.Block,a,b)};Blockly.Realtime.getBlockById=function(a){return Blockly.Realtime.blocksMap_.get(a)};
Blockly.Realtime.onObjectChange_=function(a){var b=a.events;a=a.events.length;for(var c=0;c<a;c++){var d=b[c];if(!d.isLocal&&"value_changed"==d.type)if("xmlDom"==d.property){var e=d.target;Blockly.Realtime.doWithinSync_(function(){Blockly.Realtime.placeBlockOnWorkspace_(e,!1);Blockly.Realtime.moveBlock_(e)})}else if("relativeX"==d.property||"relativeY"==d.property){var f=d.target;Blockly.Realtime.doWithinSync_(function(){f.svg_||Blockly.Realtime.placeBlockOnWorkspace_(f,!1);Blockly.Realtime.moveBlock_(f)})}}};
Blockly.Realtime.onBlocksMapChange_=function(a){console.log("Blocks Map event:");console.log(" id: "+a.property);if(!a.isLocal){var b=a.newValue;b?Blockly.Realtime.placeBlockOnWorkspace_(b,!a.oldValue):(b=a.oldValue,Blockly.Realtime.deleteBlock(b))}};Blockly.Realtime.doWithinSync_=function(a){if(Blockly.Realtime.withinSync)a();else try{Blockly.Realtime.withinSync=!0,a()}finally{Blockly.Realtime.withinSync=!1}};
Blockly.Realtime.placeBlockOnWorkspace_=function(a,b){Blockly.Realtime.doWithinSync_(function(){var c=Blockly.Xml.textToDom(a.xmlDom).firstChild;if(c=Blockly.Xml.domToBlock(Blockly.mainWorkspace,c,!0))b&&c.workspace.addTopBlock(c),(b||goog.array.contains(Blockly.Realtime.topBlocks_,c))&&Blockly.Realtime.moveBlock_(c)})};
Blockly.Realtime.moveBlock_=function(a){if(!isNaN(a.relativeX)&&!isNaN(a.relativeY)){var b=Blockly.svgSize().width,c=a.getRelativeToSurfaceXY(),d=a.relativeX-c.x;a.moveBy(Blockly.RTL?b-d:d,a.relativeY-c.y)}};Blockly.Realtime.deleteBlock=function(a){Blockly.Realtime.doWithinSync_(function(){a.dispose(!0,!0,!0)})};
Blockly.Realtime.loadBlocks_=function(){for(var a=Blockly.Realtime.blocksMap_.values(),b=0;b<a.length;b++){var c=parseInt(a[b].id,10);c>Blockly.getUidCounter()&&Blockly.setUidCounter(c+1)}a=Blockly.Realtime.topBlocks_;for(b=0;b<a.length;b++)c=a.get(b),Blockly.Realtime.placeBlockOnWorkspace_(c,!0)};
Blockly.Realtime.blockChanged=function(a){if(a.workspace==Blockly.mainWorkspace){a=a.getRootBlock();var b=a.getRelativeToSurfaceXY(),c=!1,d=Blockly.Xml.blockToDom_(a);d.setAttribute("id",a.id);var e=goog.dom.createDom("xml");e.appendChild(d);d=Blockly.Xml.domToText(e);d!=a.xmlDom&&(c=!0,a.xmlDom=d);if(a.relativeX!=b.x||a.relativeY!=b.y)a.relativeX=b.x,a.relativeY=b.y,c=!0;c&&Blockly.Realtime.blocksMap_.set(a.id.toString(),a)}};
Blockly.Realtime.onFileLoaded_=function(a){Blockly.Realtime.model_=a.getModel();Blockly.Realtime.blocksMap_=Blockly.Realtime.model_.getRoot().get("blocks");Blockly.Realtime.topBlocks_=Blockly.Realtime.model_.getRoot().get("topBlocks");Blockly.Realtime.model_.getRoot().addEventListener(gapi.drive.realtime.EventType.OBJECT_CHANGED,Blockly.Realtime.onObjectChange_);Blockly.Realtime.blocksMap_.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED,Blockly.Realtime.onBlocksMapChange_);a=Blockly.Realtime.model_.getRoot().get("text");
var b=document.getElementById("chatbox");gapi.drive.realtime.databinding.bindString(a,b);b.disabled=!1;Blockly.Realtime.initUi_();Blockly.Realtime.loadBlocks_()};
Blockly.Realtime.registerTypes_=function(){var a=gapi.drive.realtime.custom;a.registerType(Blockly.Block,"Block");Blockly.Block.prototype.id=a.collaborativeField("id");Blockly.Block.prototype.type=a.collaborativeField("type");Blockly.Block.prototype.xmlDom=a.collaborativeField("xmlDom");Blockly.Block.prototype.relativeX=a.collaborativeField("relativeX");Blockly.Block.prototype.relativeY=a.collaborativeField("relativeY");a.setInitializer(Blockly.Block,Blockly.Block.prototype.initialize)};
Blockly.Realtime.onFileLoaded_=function(a){Blockly.Realtime.model_=a.getModel();Blockly.Realtime.blocksMap_=Blockly.Realtime.model_.getRoot().get("blocks");Blockly.Realtime.topBlocks_=Blockly.Realtime.model_.getRoot().get("topBlocks");Blockly.Realtime.model_.getRoot().addEventListener(gapi.drive.realtime.EventType.OBJECT_CHANGED,Blockly.Realtime.onObjectChange_);Blockly.Realtime.blocksMap_.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED,Blockly.Realtime.onBlocksMapChange_);Blockly.Realtime.initUi_();
Blockly.Realtime.loadBlocks_()};Blockly.Realtime.registerTypes_=function(){var a=gapi.drive.realtime.custom;a.registerType(Blockly.Block,"Block");Blockly.Block.prototype.id=a.collaborativeField("id");Blockly.Block.prototype.type=a.collaborativeField("type");Blockly.Block.prototype.xmlDom=a.collaborativeField("xmlDom");Blockly.Block.prototype.relativeX=a.collaborativeField("relativeX");Blockly.Block.prototype.relativeY=a.collaborativeField("relativeY");a.setInitializer(Blockly.Block,Blockly.Block.prototype.initialize)};
Blockly.Realtime.REAUTH_INTERVAL_IN_MILLISECONDS_=18E5;Blockly.Realtime.afterAuth_=function(){window.setTimeout(function(){Blockly.Realtime.realtimeLoader_.authorizer.authorize(Blockly.Realtime.afterAuth_)},Blockly.Realtime.REAUTH_INTERVAL_IN_MILLISECONDS_)};
Blockly.Realtime.afterCreate_=function(a){var b=gapi.client.drive.permissions.insert({fileId:a,resource:{type:"anyone",role:"writer",value:"default",withLink:!0}});b.execute(function(c){c.error&&Blockly.Realtime.getUserDomain(a,function(c){b=gapi.client.drive.permissions.insert({fileId:a,resource:{type:"domain",role:"writer",value:c,withLink:!0}});b.execute(function(a){})})})};
Blockly.Realtime.getUserDomain=function(a,b){gapi.client.drive.permissions.list({fileId:a}).execute(function(a){for(var d=0;d<a.items.length;d++){var e=a.items[d];if("owner"==e.role){b(e.domain);break}}})};
Blockly.Realtime.realtimeOptions_={clientId:"922110111899.apps.googleusercontent.com",authButtonElementId:"authorizeButton",initializeModel:Blockly.Realtime.initializeModel_,autoCreate:!0,defaultTitle:"New Realtime Blockly File",newFileMimeType:null,onFileLoaded:Blockly.Realtime.onFileLoaded_,registerTypes:Blockly.Realtime.registerTypes_,afterAuth:Blockly.Realtime.afterAuth_,afterCreate:Blockly.Realtime.afterCreate_};
Blockly.Realtime.startRealtime=function(a){Blockly.Realtime.enabled_=!0;Blockly.Realtime.initUi_=a;Blockly.Realtime.realtimeLoader_=new rtclient.RealtimeLoader(Blockly.Realtime.realtimeOptions_);Blockly.Realtime.realtimeLoader_.start()};
Blockly.Realtime.realtimeOptions_={clientId:"INSERT YOUR CLIENT ID HERE",authButtonElementId:"authorizeButton",authDivElementId:"authButtonDiv",initializeModel:Blockly.Realtime.initializeModel_,autoCreate:!0,defaultTitle:"New Realtime Blockly File",newFileMimeType:null,onFileLoaded:Blockly.Realtime.onFileLoaded_,registerTypes:Blockly.Realtime.registerTypes_,afterAuth:Blockly.Realtime.afterAuth_,afterCreate:Blockly.Realtime.afterCreate_};
Blockly.Realtime.parseOptions_=function(a){if(a=rtclient.getOption(a,"chatbox"))Blockly.Realtime.chatBoxElementId_=rtclient.getOption(a,"elementId"),Blockly.Realtime.chatBoxInitialText_=rtclient.getOption(a,"initText",Blockly.Msg.CHAT)};
Blockly.Realtime.startRealtime=function(a,b,c){Blockly.Realtime.parseOptions_(c);Blockly.Realtime.enabled_=!0;Blockly.Realtime.addAuthUi_(b);Blockly.Realtime.initUi_=function(){a();if(Blockly.Realtime.chatBoxElementId_){var b=Blockly.Realtime.model_.getRoot().get(Blockly.Realtime.chatBoxElementId_),c=document.getElementById(Blockly.Realtime.chatBoxElementId_);gapi.drive.realtime.databinding.bindString(b,c);c.disabled=!1}};Blockly.Realtime.realtimeLoader_=new rtclient.RealtimeLoader(Blockly.Realtime.realtimeOptions_);
Blockly.Realtime.realtimeLoader_.start()};
Blockly.Realtime.addAuthUi_=function(a){var b=goog.style.getBounds(a),c=goog.dom.createDom("div");c.id="authButtonDiv";var d=goog.dom.createDom("p",null,Blockly.Msg.AUTH);c.appendChild(d);d=goog.dom.createDom("button",null,"Authorize");d.id=Blockly.Realtime.realtimeOptions_.authButtonElementId;c.appendChild(d);a.appendChild(c);c.style.display="none";c.style.position="relative";c.style.textAlign="center";c.style.border="1px solid";c.style.backgroundColor="#f6f9ff";c.style.borderRadius="15px";c.style.boxShadow=
"10px 10px 5px #888";c.style.width=b.width/3+"px";a=goog.style.getBounds(c);c.style.left=(b.width-a.width)/3+"px";c.style.top=(b.height-a.height)/4+"px";return c};
// Copyright 2013 Google Inc. Apache License 2.0
Blockly.Css={};Blockly.Css.inject=function(){var a=Blockly.Css.CONTENT.join("\n"),b=Blockly.pathToBlockly.replace(/[\\\/]$/,""),a=a.replace(/<<<PATH>>>/g,b);goog.cssom.addCssText(a)};
Blockly.Css.CONTENT=[".blocklySvg {"," background-color: #fff;"," border: 1px solid #ddd;","}",".blocklyWidgetDiv {"," position: absolute;"," display: none;"," z-index: 999;","}",".blocklyDraggable {"," /* Hotspot coordinates are baked into the CUR file, but they are still"," required in the CSS due to a Chrome bug."," http://code.google.com/p/chromium/issues/detail?id=1446 */"," cursor: url(<<<PATH>>>/media/handopen.cur) 8 5, auto;","}",".blocklyResizeSE {"," fill: #aaa;"," cursor: se-resize;",
@ -1052,9 +1083,9 @@ Blockly.Css.CONTENT=[".blocklySvg {"," background-color: #fff;"," border: 1px
Blockly.WidgetDiv={};Blockly.WidgetDiv.DIV=null;Blockly.WidgetDiv.field_=null;Blockly.WidgetDiv.dispose_=null;Blockly.WidgetDiv.show=function(a,b){Blockly.WidgetDiv.hide();Blockly.WidgetDiv.field_=a;Blockly.WidgetDiv.dispose_=b;Blockly.WidgetDiv.DIV.style.display="block"};Blockly.WidgetDiv.hide=function(){Blockly.WidgetDiv.field_&&(Blockly.WidgetDiv.DIV.style.display="none",Blockly.WidgetDiv.dispose_&&Blockly.WidgetDiv.dispose_(),Blockly.WidgetDiv.field_=null,Blockly.WidgetDiv.dispose_=null,goog.dom.removeChildren(Blockly.WidgetDiv.DIV))};
Blockly.WidgetDiv.hideIfField=function(a){Blockly.WidgetDiv.field_==a&&Blockly.WidgetDiv.hide()};
// Copyright 2011 Google Inc. Apache License 2.0
Blockly.inject=function(a,b){if(!goog.dom.contains(document,a))throw"Error: container is not in current document.";b&&goog.mixin(Blockly,Blockly.parseOptions_(b));Blockly.createDom_(a);Blockly.init_()};
Blockly.parseOptions_=function(a){var b=!!a.readOnly;if(b)var c=!1,d=!1,e=!1,f=null;else(f=a.toolbox)?("string"!=typeof f&&"undefined"==typeof XSLTProcessor&&(f=f.outerHTML),"string"==typeof f&&(f=Blockly.Xml.textToDom(f)),c=!!f.getElementsByTagName("category").length):(f=null,c=!1),d=a.trashcan,void 0===d&&(d=c),e=a.collapse,void 0===e&&(e=c);if(f&&!c)var g=!1;else g=a.scrollbars,void 0===g&&(g=!0);return{RTL:!!a.rtl,collapse:e,readOnly:b,maxBlocks:a.maxBlocks||Infinity,pathToBlockly:a.path||"./",
hasCategories:c,hasScrollbars:g,hasTrashcan:d,languageTree:f}};
Blockly.inject=function(a,b){if(!goog.dom.contains(document,a))throw"Error: container is not in current document.";b&&goog.mixin(Blockly,Blockly.parseOptions_(b));var c=function(){Blockly.createDom_(a);Blockly.init_()};if(Blockly.enableRealtime){var d=document.getElementById("realtime");d&&(d.style.display="block");Blockly.Realtime.startRealtime(c,a,Blockly.realtimeOptions)}else c()};
Blockly.parseOptions_=function(a){var b=!!a.readOnly;if(b)var c=!1,d=!1,e=!1,f=null;else(f=a.toolbox)?("string"!=typeof f&&"undefined"==typeof XSLTProcessor&&(f=f.outerHTML),"string"==typeof f&&(f=Blockly.Xml.textToDom(f)),c=!!f.getElementsByTagName("category").length):(f=null,c=!1),d=a.trashcan,void 0===d&&(d=c),e=a.collapse,void 0===e&&(e=c);if(f&&!c)var g=!1;else g=a.scrollbars,void 0===g&&(g=!0);var h=!!a.realtime;return{RTL:!!a.rtl,collapse:e,readOnly:b,maxBlocks:a.maxBlocks||Infinity,pathToBlockly:a.path||
"./",hasCategories:c,hasScrollbars:g,hasTrashcan:d,languageTree:f,enableRealtime:h,realtimeOptions:h?a.realtimeOptions:void 0}};
Blockly.createDom_=function(a){a.setAttribute("dir","LTR");goog.ui.Component.setDefaultRightToLeft(Blockly.RTL);Blockly.Css.inject();var b=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"},null),c=Blockly.createSvgElement("defs",{},b),d,e;d=Blockly.createSvgElement("filter",{id:"blocklyEmboss"},c);Blockly.createSvgElement("feGaussianBlur",{"in":"SourceAlpha",
stdDeviation:1,result:"blur"},d);e=Blockly.createSvgElement("feSpecularLighting",{"in":"blur",surfaceScale:1,specularConstant:0.5,specularExponent:10,"lighting-color":"white",result:"specOut"},d);Blockly.createSvgElement("fePointLight",{x:-5E3,y:-1E4,z:2E4},e);Blockly.createSvgElement("feComposite",{"in":"specOut",in2:"SourceAlpha",operator:"in",result:"specOut"},d);Blockly.createSvgElement("feComposite",{"in":"SourceGraphic",in2:"specOut",operator:"arithmetic",k1:0,k2:1,k3:1,k4:0},d);d=Blockly.createSvgElement("filter",
{id:"blocklyTrashcanShadowFilter"},c);Blockly.createSvgElement("feGaussianBlur",{"in":"SourceAlpha",stdDeviation:2,result:"blur"},d);Blockly.createSvgElement("feOffset",{"in":"blur",dx:1,dy:1,result:"offsetBlur"},d);d=Blockly.createSvgElement("feMerge",{},d);Blockly.createSvgElement("feMergeNode",{"in":"offsetBlur"},d);Blockly.createSvgElement("feMergeNode",{"in":"SourceGraphic"},d);d=Blockly.createSvgElement("filter",{id:"blocklyShadowFilter"},c);Blockly.createSvgElement("feGaussianBlur",{stdDeviation:2},

View file

@ -51,8 +51,8 @@ goog.addDependency("../../../" + dir + "/core/msg.js", ['Blockly.Msg'], []);
goog.addDependency("../../../" + dir + "/core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Icon']);
goog.addDependency("../../../" + dir + "/core/names.js", ['Blockly.Names'], []);
goog.addDependency("../../../" + dir + "/core/procedures.js", ['Blockly.Procedures'], ['Blockly.FieldVariable', 'Blockly.Names', 'Blockly.Workspace']);
goog.addDependency("../../../" + dir + "/core/realtime-client-utils.js", [], []);
goog.addDependency("../../../" + dir + "/core/realtime.js", ['Blockly.Realtime'], ['goog.array']);
goog.addDependency("../../../" + dir + "/core/realtime-client-utils.js", ['rtclient'], []);
goog.addDependency("../../../" + dir + "/core/realtime.js", ['Blockly.Realtime'], ['goog.array', 'goog.style', 'rtclient']);
goog.addDependency("../../../" + dir + "/core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['goog.userAgent']);
goog.addDependency("../../../" + dir + "/core/toolbox.js", ['Blockly.Toolbox'], ['Blockly.Flyout', 'goog.events.BrowserFeature', 'goog.style', 'goog.ui.tree.TreeControl', 'goog.ui.tree.TreeNode']);
goog.addDependency("../../../" + dir + "/core/tooltip.js", ['Blockly.Tooltip'], []);
@ -966,6 +966,7 @@ goog.require('Blockly.Workspace');
goog.require('Blockly.Xml');
goog.require('Blockly.inject');
goog.require('Blockly.utils');
goog.require('rtclient');
delete window.BLOCKLY_DIR;
delete window.BLOCKLY_BOOT;

View file

@ -44,8 +44,19 @@ Blockly.inject = function(container, opt_options) {
// TODO(scr): don't mix this in to global variables.
goog.mixin(Blockly, Blockly.parseOptions_(opt_options));
}
Blockly.createDom_(container);
Blockly.init_();
var startUi = function() {
Blockly.createDom_(container);
Blockly.init_();
};
if (Blockly.enableRealtime) {
var realtimeElement = document.getElementById('realtime');
if (realtimeElement) {
realtimeElement.style.display = 'block';
}
Blockly.Realtime.startRealtime(startUi, container, Blockly.realtimeOptions);
} else {
startUi();
}
};
/**
@ -97,6 +108,8 @@ Blockly.parseOptions_ = function(options) {
hasScrollbars = true;
}
}
var enableRealtime = !!options['realtime'];
var realtimeOptions = enableRealtime ? options['realtimeOptions'] : undefined;
return {
RTL: !!options['rtl'],
collapse: hasCollapse,
@ -106,7 +119,9 @@ Blockly.parseOptions_ = function(options) {
hasCategories: hasCategories,
hasScrollbars: hasScrollbars,
hasTrashcan: hasTrashcan,
languageTree: tree
languageTree: tree,
enableRealtime: enableRealtime,
realtimeOptions: realtimeOptions
};
};

View file

@ -30,7 +30,8 @@
/**
* Realtime client utilities namespace.
*/
var rtclient = rtclient || {};
// var rtclient = rtclient || {};
goog.provide('rtclient');
/**
* OAuth 2.0 scope for installing Drive Apps.
@ -75,9 +76,9 @@ rtclient.getParams = function() {
var searchFragment = window.location.search;
if (searchFragment) {
// split up the query string and store in an object
var paramStrs2 = searchFragment.slice(1).split("&");
var paramStrs2 = searchFragment.slice(1).split('&');
for (var j = 0; j < paramStrs2.length; j++) {
var paramStr2 = paramStrs2[j].split("=");
var paramStr2 = paramStrs2[j].split('=');
params[paramStr2[0]] = unescape(paramStr2[1]);
}
}
@ -95,15 +96,17 @@ rtclient.params = rtclient.getParams();
* neither is available.
* @param {!Object} options Containing options.
* @param {string} key Option key.
* @param {*} defaultValue Default option value (optional).
* @param {*=} opt_defaultValue Default option value (optional).
* @return {*} Option value.
*/
rtclient.getOption = function(options, key, defaultValue) {
rtclient.getOption = function(options, key, opt_defaultValue) {
if (options.hasOwnProperty(key)) {
return options[key];
}
console.error(key + ' should be present in the options.');
return defaultValue;
if (opt_defaultValue === undefined) {
console.error(key + ' should be present in the options.');
}
return opt_defaultValue;
};
/**
@ -122,6 +125,8 @@ rtclient.Authorizer = function(options) {
this.userId = rtclient.params['userId'];
this.authButton = document.getElementById(rtclient.getOption(options,
'authButtonElementId'));
this.authDiv = document.getElementById(rtclient.getOption(options,
'authDivElementId'));
};
/**
@ -147,9 +152,11 @@ rtclient.Authorizer.prototype.authorize = function(onAuthComplete) {
if (authResult && !authResult.error) {
_this.authButton.disabled = true;
_this.fetchUserId(onAuthComplete);
_this.authDiv.style.display = 'none';
} else {
_this.authButton.disabled = false;
_this.authButton.onclick = authorizeWithPopup;
_this.authDiv.style.display = 'block';
}
};
var authorizeWithPopup = function() {
@ -293,9 +300,9 @@ rtclient.RealtimeLoader.prototype.redirectTo = function(fileIds, userId) {
params.push('userId=' + userId);
}
// Naive URL construction.
var newUrl = params.length == 0
? window.location.pathname
: (window.location.pathname + '#' + params.join('&'));
var newUrl = params.length == 0 ?
window.location.pathname :
(window.location.pathname + '#' + params.join('&'));
// Using HTML URL re-write if available.
if (window.history && window.history.replaceState) {
window.history.replaceState('Google Drive Realtime API Playground',

View file

@ -42,6 +42,8 @@
goog.provide('Blockly.Realtime');
goog.require('goog.array');
goog.require('goog.style');
goog.require('rtclient');
/**
* Is realtime collaboration enabled?
@ -59,7 +61,7 @@ Blockly.Realtime.model_ = null;
/**
* The function used to initialize the UI after realtime is initialized.
* @type {Function}
* @type {function()}
* @private
*/
Blockly.Realtime.initUi_ = null;
@ -84,9 +86,23 @@ Blockly.Realtime.withinSync = false;
*/
Blockly.Realtime.realtimeLoader_ = null;
/**
* The id of a text area to be used as a realtime chat box.
* @type {string}
* @private
*/
Blockly.Realtime.chatBoxElementId_ = null;
/**
* The initial text to be placed in the realtime chat box.
* @type {string}
* @private
*/
Blockly.Realtime.chatBoxInitialText_ = null;
/**
* Returns whether realtime collaboration is enabled.
* @returns {boolean}
* @return {boolean}
*/
Blockly.Realtime.isEnabled = function() {
return Blockly.Realtime.enabled_;
@ -96,8 +112,9 @@ Blockly.Realtime.isEnabled = function() {
* This function is called the first time that the Realtime model is created
* for a file. This function should be used to initialize any values of the
* model.
* @param model {gapi.drive.realtime.Model} model The Realtime root model
* @param {gapi.drive.realtime.Model} model The Realtime root model
* object.
* @private
*/
Blockly.Realtime.initializeModel_ = function(model) {
Blockly.Realtime.model_ = model;
@ -105,8 +122,10 @@ Blockly.Realtime.initializeModel_ = function(model) {
model.getRoot().set('blocks', blocksMap);
var topBlocks = model.createList();
model.getRoot().set('topBlocks', topBlocks);
var string = model.createString(Blockly.Msg.CHAT);
model.getRoot().set('text', string);
if (Blockly.Realtime.chatBoxElementId_) {
model.getRoot().set(Blockly.Realtime.chatBoxElementId_,
model.createString(Blockly.Realtime.chatBoxInitialText_));
}
};
/**
@ -170,14 +189,14 @@ Blockly.Realtime.onObjectChange_ = function(evt) {
if (event.type == 'value_changed') {
if (event.property == 'xmlDom') {
var block = event.target;
Blockly.Realtime.doWithinSync_(function(){
Blockly.Realtime.doWithinSync_(function() {
Blockly.Realtime.placeBlockOnWorkspace_(block, false);
Blockly.Realtime.moveBlock_(block);
});
} else if (event.property == 'relativeX' ||
event.property == 'relativeY') {
var block2 = event.target;
Blockly.Realtime.doWithinSync_(function () {
Blockly.Realtime.doWithinSync_(function() {
if (!block2.svg_) {
// If this is a move of a newly disconnected (i.e newly top level)
// block it will not have any svg (because it has been disposed of
@ -214,7 +233,7 @@ Blockly.Realtime.onBlocksMapChange_ = function(evt) {
/**
* A convenient wrapper around code that synchronizes the local model being
* edited with changes from another non-local model.
* @param {!Function} thunk A thunk of code to call.
* @param {!function()} thunk A thunk of code to call.
* @private
*/
Blockly.Realtime.doWithinSync_ = function(thunk) {
@ -277,7 +296,6 @@ Blockly.Realtime.moveBlock_ = function(block) {
/**
* Delete a block.
* @param {!Blockly.Block} block The block to delete.
* @private
*/
Blockly.Realtime.deleteBlock = function(block) {
Blockly.Realtime.doWithinSync_(function() {
@ -327,7 +345,7 @@ Blockly.Realtime.blockChanged = function(block) {
changed = true;
rootBlock.xmlDom = newXml;
}
if (rootBlock.relativeX != xy.x || rootBlock.relativeY != xy.y){
if (rootBlock.relativeX != xy.x || rootBlock.relativeY != xy.y) {
rootBlock.relativeX = xy.x;
rootBlock.relativeY = xy.y;
changed = true;
@ -361,14 +379,6 @@ Blockly.Realtime.onFileLoaded_ = function(doc) {
gapi.drive.realtime.EventType.VALUE_CHANGED,
Blockly.Realtime.onBlocksMapChange_);
var string = Blockly.Realtime.model_.getRoot().get('text');
// Keeping one box updated with a String binder.
var textArea1 = document.getElementById('chatbox');
gapi.drive.realtime.databinding.bindString(string, textArea1);
// Enabling UI Elements.
textArea1.disabled = false;
Blockly.Realtime.initUi_();
Blockly.Realtime.loadBlocks_();
@ -415,6 +425,11 @@ Blockly.Realtime.registerTypes_ = function() {
custom.setInitializer(Blockly.Block, Blockly.Block.prototype.initialize);
};
/**
* Time period for realtime re-authorization
* @type {number}
* @private
*/
Blockly.Realtime.REAUTH_INTERVAL_IN_MILLISECONDS_ = 30 * 60 * 1000;
/**
@ -436,6 +451,7 @@ Blockly.Realtime.afterAuth_ = function() {
/**
* Add "Anyone with the link" permissions to the file.
* @param {string} fileId the file id
* @private
*/
Blockly.Realtime.afterCreate_ = function(fileId) {
var resource = {
@ -472,10 +488,10 @@ Blockly.Realtime.afterCreate_ = function(fileId) {
/**
* Get the domain (if it exists) associated with a realtime file. The callback
* will be called with the domain, if it exists.
* @param fileId {string} the id of the file
* @param callback {function(string)} a function to call back with the domain
* @param {string} fileId the id of the file
* @param {function(string)} callback a function to call back with the domain
*/
Blockly.Realtime.getUserDomain = function (fileId, callback) {
Blockly.Realtime.getUserDomain = function(fileId, callback) {
/**
* Note that there may be a more direct way to get the domain by, for example,
* using the Google profile API but this way we don't need any additional
@ -498,6 +514,7 @@ Blockly.Realtime.getUserDomain = function (fileId, callback) {
/**
* Options for the Realtime loader.
* @private
*/
Blockly.Realtime.realtimeOptions_ = {
/**
@ -510,6 +527,11 @@ Blockly.Realtime.realtimeOptions_ = {
*/
authButtonElementId: 'authorizeButton',
/**
* The ID of the container of the authorize button.
*/
authDivElementId: 'authButtonDiv',
/**
* Function to be called when a Realtime model is first created.
*/
@ -554,12 +576,80 @@ Blockly.Realtime.realtimeOptions_ = {
};
/**
* Start the Realtime loader with the options.
* Parse options to startRealtime().
* @param {Object} options object containing the options.
* @private
*/
Blockly.Realtime.startRealtime = function (uiInitialize) {
Blockly.Realtime.parseOptions_ = function(options) {
var chatBoxOptions = rtclient.getOption(options, 'chatbox');
if (chatBoxOptions) {
Blockly.Realtime.chatBoxElementId_ =
rtclient.getOption(chatBoxOptions, 'elementId');
Blockly.Realtime.chatBoxInitialText_ =
rtclient.getOption(chatBoxOptions, 'initText', Blockly.Msg.CHAT);
}
};
/**
* Setup the Blockly container for realtime authorization and start the
* Realtime loader.
* @param {function()} uiInitialize function to initialize the Blockly UI.
* @param {Element} uiContainer container element for the Blockly UI.
* @param {Object} options the realtime options.
*/
Blockly.Realtime.startRealtime = function(uiInitialize, uiContainer, options) {
Blockly.Realtime.parseOptions_(options);
Blockly.Realtime.enabled_ = true;
Blockly.Realtime.initUi_ = uiInitialize;
// Note that we need to setup the UI for realtime authorization before
// loading the realtime code (which, in turn, will handle initializing the
// rest of the Blockly UI.
var authDiv = Blockly.Realtime.addAuthUi_(uiContainer);
Blockly.Realtime.initUi_ = function() {
uiInitialize();
if (Blockly.Realtime.chatBoxElementId_) {
var chatText = Blockly.Realtime.model_.getRoot().get(
Blockly.Realtime.chatBoxElementId_);
var chatBox = document.getElementById(Blockly.Realtime.chatBoxElementId_);
gapi.drive.realtime.databinding.bindString(chatText, chatBox);
chatBox.disabled = false;
}
};
Blockly.Realtime.realtimeLoader_ =
new rtclient.RealtimeLoader(Blockly.Realtime.realtimeOptions_);
Blockly.Realtime.realtimeLoader_.start();
};
/**
* Setup the Blockly container for realtime authorization.
* @param {Element} uiContainer a DOM container element for the Blockly UI.
* @return {Element} the DOM element for the authorization UI.
* @private
*/
Blockly.Realtime.addAuthUi_ = function(uiContainer) {
var blocklyDivBounds = goog.style.getBounds(uiContainer);
var authButtonDiv = goog.dom.createDom('div');
authButtonDiv.id = 'authButtonDiv';
var authText = goog.dom.createDom('p', null, Blockly.Msg.AUTH);
authButtonDiv.appendChild(authText);
var authButton = goog.dom.createDom('button', null, 'Authorize');
authButton.id = Blockly.Realtime.realtimeOptions_.authButtonElementId;
authButtonDiv.appendChild(authButton);
uiContainer.appendChild(authButtonDiv);
// TODO: I would have liked to set the style for the authButtonDiv in css.js
// but that CSS doesn't get injected until after this code gets run.
authButtonDiv.style.display = 'none';
authButtonDiv.style.position = 'relative';
authButtonDiv.style.textAlign = 'center';
authButtonDiv.style.border = '1px solid';
authButtonDiv.style.backgroundColor = '#f6f9ff';
authButtonDiv.style.borderRadius = '15px';
authButtonDiv.style.boxShadow = '10px 10px 5px #888';
authButtonDiv.style.width = (blocklyDivBounds.width / 3) + 'px';
var authButtonDivBounds = goog.style.getBounds(authButtonDiv);
authButtonDiv.style.left =
(blocklyDivBounds.width - authButtonDivBounds.width) / 3 + 'px';
authButtonDiv.style.top =
(blocklyDivBounds.height - authButtonDivBounds.height) / 4 + 'px';
return authButtonDiv;
};

View file

@ -86,6 +86,8 @@ Blockly.Msg.HELP = 'Help';
// Realtime collaboration.
/// collaboration instruction - Tell the user that they can talk with other users.
Blockly.Msg.CHAT = 'Chat with your collaborator by typing in this box!';
/// authorization instruction - Ask the user to authorize this app so it can be saved and shared by them.
Blockly.Msg.AUTH = 'Please authorize this app to enable your work to be saved and to allow it to be shared by you.';
// Variable renaming.
/// prompt - This message is only seen in the Opera browser. With most browsers, users can edit numeric values in blocks by just clicking and typing. Opera does not allows this, so we have to open a new window and prompt users with this message to chanage a value.

View file

@ -48,25 +48,19 @@
var rtl = (document.location.search == '?rtl');
var block = null;
function enableRealtimeSpecificUi() {
var realtimeDiv = document.getElementById('realtime');
realtimeDiv.display = 'block';
}
function start() {
var startUi = function () {
var toolbox = document.getElementById('toolbox');
Blockly.inject(document.getElementById('blocklyDiv'),
{rtl: rtl, path: '../', toolbox: toolbox});
};
// Set up realtime collaboration.
// If you want to use the realtime collaboration features then uncomment out
// the next 2 lines and comment out the call to startUi() below.
// document.getElementById("realtime").style.display = "block";
// Blockly.Realtime.startRealtime(startUi);
// If you don't want to use the realtime collaboration features then uncomment
// out the next line and comment out the call to
// Blockly.Realtime.startRealtime() above it. You can also comment out
// (or delete) the loading of the realtime related libraries up above in this
// case, if you want.
startUi();
var toolbox = document.getElementById('toolbox');
Blockly.inject(document.getElementById('blocklyDiv'),
{rtl: rtl, path: '../', toolbox: toolbox, realtime: false,
realtimeOptions: {chatbox: {elementId: 'chatbox'}}});
if (Blockly.Realtime.isEnabled()) {
enableRealtimeSpecificUi();
}
}
function toXml() {
@ -337,11 +331,9 @@ h1 {
<div id="realtime" style="display: none">
<p>Test realtime collaboration by opening
<a target="_blank" href="#" onmouseover="this.href = window.location.href">this link in a separate
browser window or tab</a> and they will be synchronized. If this is the first time you've used
realtime collaboration with Blockly you'll need to authorize using the following button if it is enabled.</p>
<button id="authorizeButton">You must authorize</button>
<a target="_blank" href="#" onmouseover="this.href = window.location.href">
this link</a> in a separate browser window or tab and they will be
synchronized. You can even share the link with a friend!.</p>
<br>
<br>