From 2d6a91ebcd82ce283bad4c8d8ec8b557b3132b56 Mon Sep 17 00:00:00 2001 From: "ellen.spertus" Date: Sat, 8 Feb 2014 03:00:02 -0800 Subject: [PATCH] Automatic commit Sat Feb 8 03:00:02 PST 2014 --- blockly_compressed.js | 55 +++++++++++--- blockly_uncompressed.js | 5 +- core/inject.js | 21 +++++- core/realtime-client-utils.js | 27 ++++--- core/realtime.js | 138 ++++++++++++++++++++++++++++------ msg/messages.js | 2 + tests/playground.html | 38 ++++------ 7 files changed, 212 insertions(+), 74 deletions(-) diff --git a/blockly_compressed.js b/blockly_compressed.js index 163eb673e..fe6e4a7fd 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -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;cBlockly.getUidCounter()&&Blockly.setUidCounter(c+1)}a=Blockly.Realtime.topBlocks_;for(b=0;b>>/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(<<>>/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}, diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index be0921e74..cbfca09ac 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -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; diff --git a/core/inject.js b/core/inject.js index 0b001aa05..79e7a7ad8 100644 --- a/core/inject.js +++ b/core/inject.js @@ -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 }; }; diff --git a/core/realtime-client-utils.js b/core/realtime-client-utils.js index 947df22d0..196d8de5f 100644 --- a/core/realtime-client-utils.js +++ b/core/realtime-client-utils.js @@ -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', diff --git a/core/realtime.js b/core/realtime.js index 76150532a..b8226ccfd 100644 --- a/core/realtime.js +++ b/core/realtime.js @@ -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; +}; diff --git a/msg/messages.js b/msg/messages.js index 83c009ada..44e2ba129 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -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. diff --git a/tests/playground.html b/tests/playground.html index c7e370419..64c3aaa52 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -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 {