Adding BlocklyDevTools.Analytics (#1217)

Adding BlocklyDevTools.Analytics, an interface for integrating an analytics
library to track basic usage, including:
 * navigation.
 * saving, importing, and exporting.
 * warnings and errors.
This commit is contained in:
Andrew n marshall
2017-07-11 15:39:35 -07:00
committed by GitHub
parent ca2f0cacf4
commit abcc9b82a1
6 changed files with 335 additions and 35 deletions

View File

@@ -0,0 +1,210 @@
/**
* @license
* Blockly Demos: Block Factory
*
* Copyright 2017 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Stubbed interface functions for analytics integration.
*/
goog.provide('BlocklyDevTools.Analytics');
/**
* Whether these stub methods should log analytics calls to the console.
* @private
* @const
*/
BlocklyDevTools.Analytics.LOG_TO_CONSOLE_ = false;
/**
* An import/export type id for a library of BlockFactory's original block
* save files (each a serialized workspace of block definition blocks).
* @package
* @const
*/
BlocklyDevTools.Analytics.BLOCK_FACTORY_LIBRARY = "Block Factory library";
/**
* An import/export type id for a standard Blockly library of block
* definitions.
* @package
* @const
*/
BlocklyDevTools.Analytics.BLOCK_DEFINITIONS = "Block definitions";
/**
* An import/export type id for a code generation function, or a
* boilerplate stub of the same.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.GENERATOR = "Generator";
/**
* An import/export type id for a Blockly Toolbox.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.TOOLBOX = "Toolbox";
/**
* An import/export type id for the serialized contents of a workspace.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.WORKSPACE_CONTENTS = "Workspace contents";
/**
* Format id for imported/exported JavaScript resources.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.FORMAT_JS = "JavaScript";
/**
* Format id for imported/exported JSON resources.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.FORMAT_JSON = "JSON";
/**
* Format id for imported/exported XML resources.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.FORMAT_XML = "XML";
/**
* Platform id for resources exported for use in Android projects.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.PLATFORM_ANDROID = "Android";
/**
* Platform id for resources exported for use in iOS projects.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.PLATFORM_IOS = "iOS";
/**
* Platform id for resources exported for use in web projects.
*
* @package
* @const
*/
BlocklyDevTools.Analytics.PLATFORM_WEB = "web";
/**
* Initializes the analytics framework, including noting that the page/app was
* opened.
* @package
*/
BlocklyDevTools.Analytics.init = function() {
// stub
this.LOG_TO_CONSOLE_ && console.log('Analytics.init');
};
/**
* Event noting the user navigated to a specific view.
*
* @package
* @param viewId {string} An identifier for the view state.
*/
BlocklyDevTools.Analytics.onNavigateTo = function(viewId) {
// stub
this.LOG_TO_CONSOLE_ &&
console.log('Analytics.onNavigateTo(' + viewId + ')');
};
/**
* Event noting a project resource was saved. In the web Block Factory, this
* means saved to localStorage.
*
* @package
* @param typeId {string} An identifying string for the saved type.
*/
BlocklyDevTools.Analytics.onSave = function(typeId) {
// stub
this.LOG_TO_CONSOLE_ && console.log('Analytics.onSave(' + typeId + ')');
};
/**
* Event noting the user attempted to import a resource file.
*
* @package
* @param typeId {string} An identifying string for the imported type.
* @param optMetadata {Object} Metadata about the import, such as format and
* platform.
*/
BlocklyDevTools.Analytics.onImport = function(typeId, optMetadata) {
// stub
this.LOG_TO_CONSOLE_ && console.log('Analytics.onImport(' + typeId +
(optMetadata ? '): ' + JSON.stringify(optMetadata) : ')'));
};
/**
* Event noting a project resource was saved. In the web Block Factory, this
* means downloaded to the user's system.
*
* @package
* @param typeId {string} An identifying string for the exported object type.
* @param optMetadata {Object} Metadata about the import, such as format and
* platform.
*/
BlocklyDevTools.Analytics.onExport = function(typeId, optMetadata) {
// stub
this.LOG_TO_CONSOLE_ && console.log('Analytics.onExport(' + typeId +
(optMetadata ? '): ' + JSON.stringify(optMetadata) : ')'));
};
/**
* Event noting the system encountered an error. It should attempt to send
* immediately.
*
* @package
* @param e {!Object} A value representing or describing the error.
*/
BlocklyDevTools.Analytics.onError = function(e) {
// stub
this.LOG_TO_CONSOLE_ &&
console.log('Analytics.onError("' + e.toString() + '")');
};
/**
* Event noting the user was notified with a warning.
*
* @package
* @param msg {string} The warning message, or a description thereof.
*/
BlocklyDevTools.Analytics.onWarning = function(msg) {
// stub
this.LOG_TO_CONSOLE_ && console.log('Analytics.onWarning("' + msg + '")');
};
/**
* Request the analytics framework to send any queued events to the server.
* @package
*/
BlocklyDevTools.Analytics.sendQueued = function() {
// stub
this.LOG_TO_CONSOLE_ && console.log('Analytics.sendQueued');
};

View File

@@ -28,6 +28,7 @@
goog.provide('AppController'); goog.provide('AppController');
goog.require('BlockFactory'); goog.require('BlockFactory');
goog.require('BlocklyDevTools.Analytics');
goog.require('FactoryUtils'); goog.require('FactoryUtils');
goog.require('BlockLibraryController'); goog.require('BlockLibraryController');
goog.require('BlockExporterController'); goog.require('BlockExporterController');
@@ -85,6 +86,10 @@ AppController.prototype.importBlockLibraryFromFile = function() {
var files = document.getElementById('files'); var files = document.getElementById('files');
// If the file list is empty, the user likely canceled in the dialog. // If the file list is empty, the user likely canceled in the dialog.
if (files.files.length > 0) { if (files.files.length > 0) {
BlocklyDevTools.Analytics.onImport(
BlocklyDevTools.Analytics.BLOCK_FACTORY_LIBRARY,
{ format: BlocklyDevTools.Analytics.FORMAT_XML });
// The input tag doesn't have the "multiple" attribute // The input tag doesn't have the "multiple" attribute
// so the user can only choose 1 file. // so the user can only choose 1 file.
var file = files.files[0]; var file = files.files[0];
@@ -137,9 +142,14 @@ AppController.prototype.exportBlockLibraryToFile = function() {
// Download file if all necessary parameters are provided. // Download file if all necessary parameters are provided.
if (filename) { if (filename) {
FactoryUtils.createAndDownloadFile(blockLibText, filename, 'xml'); FactoryUtils.createAndDownloadFile(blockLibText, filename, 'xml');
BlocklyDevTools.Analytics.onExport(
BlocklyDevTools.Analytics.BLOCK_FACTORY_LIBRARY,
{ format: BlocklyDevTools.Analytics.FORMAT_XML });
} else { } else {
alert('Could not export Block Library without file name under which to ' + var msg = 'Could not export Block Library without file name under which ' +
'save library.'); 'to save library.';
BlocklyDevTools.Analytics.onWarning(msg);
alert(msg);
} }
}; };
@@ -201,7 +211,7 @@ AppController.prototype.formatBlockLibraryForImport_ = function(xmlText) {
var blockType = this.getBlockTypeFromXml_(xmlText).toLowerCase(); var blockType = this.getBlockTypeFromXml_(xmlText).toLowerCase();
// Some names are invalid so fix them up. // Some names are invalid so fix them up.
blockType = FactoryUtils.cleanBlockType(blockType); blockType = FactoryUtils.cleanBlockType(blockType);
blockXmlTextMap[blockType] = xmlText; blockXmlTextMap[blockType] = xmlText;
} }
@@ -285,13 +295,17 @@ AppController.prototype.onTab = function() {
var hasUnsavedChanges = var hasUnsavedChanges =
!FactoryUtils.savedBlockChanges(this.blockLibraryController); !FactoryUtils.savedBlockChanges(this.blockLibraryController);
if (hasUnsavedChanges && if (hasUnsavedChanges) {
!confirm('You have unsaved changes in Block Factory.')) { var msg = 'You have unsaved changes in Block Factory.';
// If the user doesn't want to switch tabs with unsaved changes, var continueAnyway = confirm(msg);
// stay on Block Factory Tab. BlocklyDevTools.Analytics.onWarning(msg);
this.setSelected_(AppController.BLOCK_FACTORY); if (!continueAnyway) {
this.lastSelectedTab = AppController.BLOCK_FACTORY; // If the user doesn't want to switch tabs with unsaved changes,
return; // stay on Block Factory Tab.
this.setSelected_(AppController.BLOCK_FACTORY);
this.lastSelectedTab = AppController.BLOCK_FACTORY;
return;
}
} }
} }
@@ -304,6 +318,8 @@ AppController.prototype.onTab = function() {
this.styleTabs_(); this.styleTabs_();
if (this.selectedTab == AppController.EXPORTER) { if (this.selectedTab == AppController.EXPORTER) {
BlocklyDevTools.Analytics.onNavigateTo('Exporter');
// Hide other tabs. // Hide other tabs.
FactoryUtils.hide('workspaceFactoryContent'); FactoryUtils.hide('workspaceFactoryContent');
FactoryUtils.hide('blockFactoryContent'); FactoryUtils.hide('blockFactoryContent');
@@ -325,6 +341,8 @@ AppController.prototype.onTab = function() {
this.exporter.updatePreview(); this.exporter.updatePreview();
} else if (this.selectedTab == AppController.BLOCK_FACTORY) { } else if (this.selectedTab == AppController.BLOCK_FACTORY) {
BlocklyDevTools.Analytics.onNavigateTo('BlockFactory');
// Hide other tabs. // Hide other tabs.
FactoryUtils.hide('blockLibraryExporter'); FactoryUtils.hide('blockLibraryExporter');
FactoryUtils.hide('workspaceFactoryContent'); FactoryUtils.hide('workspaceFactoryContent');
@@ -332,6 +350,9 @@ AppController.prototype.onTab = function() {
FactoryUtils.show('blockFactoryContent'); FactoryUtils.show('blockFactoryContent');
} else if (this.selectedTab == AppController.WORKSPACE_FACTORY) { } else if (this.selectedTab == AppController.WORKSPACE_FACTORY) {
// TODO: differentiate Workspace and Toolbox editor, based on the other tab state.
BlocklyDevTools.Analytics.onNavigateTo('WorkspaceFactory');
// Hide other tabs. // Hide other tabs.
FactoryUtils.hide('blockLibraryExporter'); FactoryUtils.hide('blockLibraryExporter');
FactoryUtils.hide('blockFactoryContent'); FactoryUtils.hide('blockFactoryContent');
@@ -624,12 +645,14 @@ AppController.prototype.onresize = function(event) {
* @param {!Event} e beforeunload event. * @param {!Event} e beforeunload event.
*/ */
AppController.prototype.confirmLeavePage = function(e) { AppController.prototype.confirmLeavePage = function(e) {
BlocklyDevTools.Analytics.sendQueued();
if ((!BlockFactory.isStarterBlock() && if ((!BlockFactory.isStarterBlock() &&
!FactoryUtils.savedBlockChanges(blocklyFactory.blockLibraryController)) || !FactoryUtils.savedBlockChanges(blocklyFactory.blockLibraryController)) ||
blocklyFactory.workspaceFactoryController.hasUnsavedChanges()) { blocklyFactory.workspaceFactoryController.hasUnsavedChanges()) {
var confirmationMessage = 'You will lose any unsaved changes. ' + var confirmationMessage = 'You will lose any unsaved changes. ' +
'Are you sure you want to exit this page?'; 'Are you sure you want to exit this page?';
BlocklyDevTools.Analytics.onWarning(confirmationMessage);
e.returnValue = confirmationMessage; e.returnValue = confirmationMessage;
return confirmationMessage; return confirmationMessage;
} }

View File

@@ -31,6 +31,7 @@
goog.provide('BlockExporterController'); goog.provide('BlockExporterController');
goog.require('BlocklyDevTools.Analytics');
goog.require('FactoryUtils'); goog.require('FactoryUtils');
goog.require('StandardCategories'); goog.require('StandardCategories');
goog.require('BlockExporterView'); goog.require('BlockExporterView');
@@ -103,7 +104,9 @@ BlockExporterController.prototype.export = function() {
// User wants to export selected blocks' definitions. // User wants to export selected blocks' definitions.
if (!blockDef_filename) { if (!blockDef_filename) {
// User needs to enter filename. // User needs to enter filename.
alert('Please enter a filename for your block definition(s) download.'); var msg = 'Please enter a filename for your block definition(s) download.';
BlocklyDevTools.Analytics.onWarning(msg);
alert(msg);
} else { } else {
// Get block definition code in the selected format for the blocks. // Get block definition code in the selected format for the blocks.
var blockDefs = this.tools.getBlockDefinitions(blockXmlMap, var blockDefs = this.tools.getBlockDefinitions(blockXmlMap,
@@ -111,6 +114,13 @@ BlockExporterController.prototype.export = function() {
// Download the file, using .js file ending for JSON or Javascript. // Download the file, using .js file ending for JSON or Javascript.
FactoryUtils.createAndDownloadFile( FactoryUtils.createAndDownloadFile(
blockDefs, blockDef_filename, 'javascript'); blockDefs, blockDef_filename, 'javascript');
BlocklyDevTools.Analytics.onExport(
BlocklyDevTools.Analytics.BLOCK_DEFINITIONS,
{
format: (definitionFormat == 'JSON' ?
BlocklyDevTools.Analytics.FORMAT_JSON :
BlocklyDevTools.Analytics.FORMAT_JS)
});
} }
} }
@@ -118,7 +128,9 @@ BlockExporterController.prototype.export = function() {
// User wants to export selected blocks' generator stubs. // User wants to export selected blocks' generator stubs.
if (!generatorStub_filename) { if (!generatorStub_filename) {
// User needs to enter filename. // User needs to enter filename.
alert('Please enter a filename for your generator stub(s) download.'); var msg = 'Please enter a filename for your generator stub(s) download.';
BlocklyDevTools.Analytics.onWarning(msg);
alert(msg);
} else { } else {
// Get generator stub code in the selected language for the blocks. // Get generator stub code in the selected language for the blocks.
var genStubs = this.tools.getGeneratorCode(blockXmlMap, var genStubs = this.tools.getGeneratorCode(blockXmlMap,
@@ -128,6 +140,10 @@ BlockExporterController.prototype.export = function() {
// Download the file. // Download the file.
FactoryUtils.createAndDownloadFile( FactoryUtils.createAndDownloadFile(
genStubs, generatorStub_filename, fileType); genStubs, generatorStub_filename, fileType);
BlocklyDevTools.Analytics.onExport(
BlocklyDevTools.Analytics.GENERATOR,
(fileType == 'javascript' ?
{ format: BlocklyDevTools.Analytics.FORMAT_JS } : undefined));
} }
} }

View File

@@ -34,6 +34,7 @@
goog.provide('BlockLibraryController'); goog.provide('BlockLibraryController');
goog.require('BlocklyDevTools.Analytics');
goog.require('BlockLibraryStorage'); goog.require('BlockLibraryStorage');
goog.require('BlockLibraryView'); goog.require('BlockLibraryView');
goog.require('BlockFactory'); goog.require('BlockFactory');
@@ -110,8 +111,9 @@ BlockLibraryController.prototype.getSelectedBlockType = function() {
* updating the dropdown and displaying the starter block (factory_base). * updating the dropdown and displaying the starter block (factory_base).
*/ */
BlockLibraryController.prototype.clearBlockLibrary = function() { BlockLibraryController.prototype.clearBlockLibrary = function() {
var check = confirm('Delete all blocks from library?'); var msg = 'Delete all blocks from library?';
if (check) { BlocklyDevTools.Analytics.onWarning(msg);
if (confirm(msg)) {
// Clear Block Library Storage. // Clear Block Library Storage.
this.storage.clear(); this.storage.clear();
this.storage.saveToLocalStorage(); this.storage.saveToLocalStorage();
@@ -133,9 +135,11 @@ BlockLibraryController.prototype.saveToBlockLibrary = function() {
// If user has not changed the name of the starter block. // If user has not changed the name of the starter block.
if (blockType == 'block_type') { if (blockType == 'block_type') {
// Do not save block if it has the default type, 'block_type'. // Do not save block if it has the default type, 'block_type'.
alert('You cannot save a block under the name "block_type". Try changing ' + var msg = 'You cannot save a block under the name "block_type". Try ' +
'the name before saving. Then, click on the "Block Library" button ' + 'changing the name before saving. Then, click on the "Block Library"' +
'to view your saved blocks.'); ' button to view your saved blocks.';
alert(msg);
BlocklyDevTools.Analytics.onWarning(msg);
return; return;
} }
@@ -159,6 +163,7 @@ BlockLibraryController.prototype.saveToBlockLibrary = function() {
// Add select handler to the new option. // Add select handler to the new option.
this.addOptionSelectHandler(blockType); this.addOptionSelectHandler(blockType);
BlocklyDevTools.Analytics.onSave('Block');
}; };
/** /**

View File

@@ -9,6 +9,7 @@
<script src="../../msg/js/en.js"></script> <script src="../../msg/js/en.js"></script>
<script src="../../blocks_compressed.js"></script> <script src="../../blocks_compressed.js"></script>
<script src="../../../closure-library/closure/goog/base.js"></script> <script src="../../../closure-library/closure/goog/base.js"></script>
<script src="analytics.js"></script>
<script src="factory_utils.js"></script> <script src="factory_utils.js"></script>
<script src="workspacefactory/wfactory_model.js"></script> <script src="workspacefactory/wfactory_model.js"></script>
<script src="standard_categories.js"></script> <script src="standard_categories.js"></script>
@@ -32,6 +33,8 @@
<script> <script>
var blocklyFactory; var blocklyFactory;
var init = function() { var init = function() {
BlocklyDevTools.Analytics.init();
blocklyFactory = new AppController(); blocklyFactory = new AppController();
blocklyFactory.init(); blocklyFactory.init();
window.addEventListener('beforeunload', blocklyFactory.confirmLeavePage); window.addEventListener('beforeunload', blocklyFactory.confirmLeavePage);

View File

@@ -34,8 +34,9 @@
* @author Emma Dauterman (evd2014) * @author Emma Dauterman (evd2014)
*/ */
goog.require('FactoryUtils'); goog.require('BlocklyDevTools.Analytics');
goog.require('StandardCategories'); goog.require('FactoryUtils');
goog.require('StandardCategories');
/** /**
@@ -342,13 +343,25 @@ WorkspaceFactoryController.prototype.exportXmlFile = function(exportMode) {
this.hasUnsavedPreloadChanges = false; this.hasUnsavedPreloadChanges = false;
} else { } else {
// Unknown mode. Throw error. // Unknown mode. Throw error.
throw new Error ("Unknown export mode: " + exportMode); var msg = "Unknown export mode: " + exportMode;
BlocklyDevTools.Analytics.onError(msg);
throw new Error(msg);
} }
// Download file. // Download file.
var data = new Blob([configXml], {type: 'text/xml'}); var data = new Blob([configXml], {type: 'text/xml'});
this.view.createAndDownloadFile(fileName, data); this.view.createAndDownloadFile(fileName, data);
};
if (exportMode == WorkspaceFactoryController.MODE_TOOLBOX) {
BlocklyDevTools.Analytics.onExport(
BlocklyDevTools.Analytics.TOOLBOX,
{ format: BlocklyDevTools.Analytics.FORMAT_XML });
} else if (exportMode == WorkspaceFactoryController.MODE_PRELOAD) {
BlocklyDevTools.Analytics.onExport(
BlocklyDevTools.Analytics.WORKSPACE_CONTENTS,
{ format: BlocklyDevTools.Analytics.FORMAT_XML });
}
};
/** /**
* Export the options object to be used for the Blockly inject call. Gets a * Export the options object to be used for the Blockly inject call. Gets a
@@ -366,6 +379,13 @@ WorkspaceFactoryController.prototype.exportInjectFile = function() {
var printableOptions = this.generator.generateInjectString() var printableOptions = this.generator.generateInjectString()
var data = new Blob([printableOptions], {type: 'text/javascript'}); var data = new Blob([printableOptions], {type: 'text/javascript'});
this.view.createAndDownloadFile(fileName, data); this.view.createAndDownloadFile(fileName, data);
BlocklyDevTools.Analytics.onExport(
BlocklyDevTools.Analytics.STARTER_CODE,
{
format: BlocklyDevTools.Analytics.FORMAT_JS,
platform: BlocklyDevTools.Analytics.PLATFORM_WEB
});
}; };
/** /**
@@ -729,33 +749,45 @@ WorkspaceFactoryController.prototype.importFile = function(file, importMode) {
// Confirm that the user wants to override their current toolbox. // Confirm that the user wants to override their current toolbox.
var hasToolboxElements = controller.model.hasElements() || var hasToolboxElements = controller.model.hasElements() ||
controller.toolboxWorkspace.getAllBlocks().length > 0; controller.toolboxWorkspace.getAllBlocks().length > 0;
if (hasToolboxElements && if (hasToolboxElements) {
!confirm('Are you sure you want to import? You will lose your ' + var msg = 'Are you sure you want to import? You will lose your ' +
'current toolbox.')) { 'current toolbox.';
return; BlocklyDevTools.Analytics.onWarning(msg);
var continueAnyway = confirm();
if (!continueAnyway) {
return;
}
} }
// Import toolbox XML. // Import toolbox XML.
controller.importToolboxFromTree_(tree); controller.importToolboxFromTree_(tree);
BlocklyDevTools.Analytics.onImport('Toolbox.xml');
} else if (importMode == WorkspaceFactoryController.MODE_PRELOAD) { } else if (importMode == WorkspaceFactoryController.MODE_PRELOAD) {
// Switch mode. // Switch mode.
controller.setMode(WorkspaceFactoryController.MODE_PRELOAD); controller.setMode(WorkspaceFactoryController.MODE_PRELOAD);
// Confirm that the user wants to override their current blocks. // Confirm that the user wants to override their current blocks.
if (controller.toolboxWorkspace.getAllBlocks().length > 0 && if (controller.toolboxWorkspace.getAllBlocks().length > 0) {
!confirm('Are you sure you want to import? You will lose your ' + var msg = 'Are you sure you want to import? You will lose your ' +
'current workspace blocks.')) { 'current workspace blocks.';
var continueAnyway = confirm(msg);
BlocklyDevTools.Analytics.onWarning(msg);
if (!continueAnyway) {
return; return;
}
} }
// Import pre-loaded workspace XML. // Import pre-loaded workspace XML.
controller.importPreloadFromTree_(tree); controller.importPreloadFromTree_(tree);
BlocklyDevTools.Analytics.onImport('WorkspaceContents.xml');
} else { } else {
// Throw error if invalid mode. // Throw error if invalid mode.
throw new Error("Unknown import mode: " + importMode); throw new Error("Unknown import mode: " + importMode);
} }
} catch(e) { } catch(e) {
alert('Cannot load XML from file.'); var msg = 'Cannot load XML from file.';
alert(msg);
BlocklyDevTools.Analytics.onError(msg);
console.log(e); console.log(e);
} finally { } finally {
Blockly.Events.enable(); Blockly.Events.enable();
@@ -888,8 +920,10 @@ WorkspaceFactoryController.prototype.importPreloadFromTree_ = function(tree) {
* "Clear" button. * "Clear" button.
*/ */
WorkspaceFactoryController.prototype.clearAll = function() { WorkspaceFactoryController.prototype.clearAll = function() {
if (!confirm('Are you sure you want to clear all of your work in Workspace' + var msg = 'Are you sure you want to clear all of your work in Workspace' +
' Factory?')) { ' Factory?';
BlocklyDevTools.Analytics.onWarning(msg);
if (!confirm(msg)) {
return; return;
} }
var hasCategories = this.model.hasElements(); var hasCategories = this.model.hasElements();
@@ -1213,11 +1247,15 @@ WorkspaceFactoryController.prototype.importBlocks = function(file, format) {
// If an imported block type is already defined, check if the user wants // If an imported block type is already defined, check if the user wants
// to override the current block definition. // to override the current block definition.
if (controller.model.hasDefinedBlockTypes(blockTypes) && if (controller.model.hasDefinedBlockTypes(blockTypes)) {
!confirm('An imported block uses the same name as a block ' var msg = 'An imported block uses the same name as a block '
+ 'already in your toolbox. Are you sure you want to override the ' + 'already in your toolbox. Are you sure you want to override the '
+ 'currently defined block?')) { + 'currently defined block?';
var continueAnyway = confirm(msg);
BlocklyDevTools.Analytics.onWarning(msg);
if (!continueAnyway) {
return; return;
}
} }
var blocks = controller.generator.getDefinedBlocks(blockTypes); var blocks = controller.generator.getDefinedBlocks(blockTypes);
@@ -1234,8 +1272,13 @@ WorkspaceFactoryController.prototype.importBlocks = function(file, format) {
// Reload current category to possibly reflect any newly defined blocks. // Reload current category to possibly reflect any newly defined blocks.
controller.clearAndLoadXml_ controller.clearAndLoadXml_
(Blockly.Xml.workspaceToDom(controller.toolboxWorkspace)); (Blockly.Xml.workspaceToDom(controller.toolboxWorkspace));
BlocklyDevTools.Analytics.onImport('BlockDefinitions' +
(format == 'JSON' ? '.json' : '.js'));
} catch (e) { } catch (e) {
alert('Cannot read blocks from file.'); msg = 'Cannot read blocks from file.';
alert(msg);
BlocklyDevTools.Analytics.onError(msg);
window.console.log(e); window.console.log(e);
} }
} }