block library now exports valid xml and properly handles the imported xml in a robust way (#555)

This commit is contained in:
Tina Quach
2016-08-18 09:20:09 -07:00
committed by picklesrus
parent 6da1f56879
commit 204e28f63f
2 changed files with 44 additions and 21 deletions

View File

@@ -123,7 +123,7 @@ AppController.prototype.exportBlockLibraryToFile = function() {
// Concatenate the xmls, each separated by a blank line.
var blockLibText = this.formatBlockLibForExport_(blockLib);
// Get file name.
var filename = prompt('Enter the file name under which to save your block' +
var filename = prompt('Enter the file name under which to save your block ' +
'library.');
// Download file if all necessary parameters are provided.
if (filename) {
@@ -138,38 +138,60 @@ AppController.prototype.exportBlockLibraryToFile = function() {
* Converts an object mapping block type to xml to text file for output.
* @private
*
* @param {!Object} blockXmlMap - object mapping block type to xml
* @return {string} String of each block's xml separated by a new line.
* @param {!Object} blockXmlMap - Object mapping block type to xml.
* @return {string} Xml text containing the block xmls.
*/
AppController.prototype.formatBlockLibForExport_ = function(blockXmlMap) {
var blockXmls = [];
// Create DOM for XML.
var xmlDom = goog.dom.createDom('xml', {
'xmlns':"http://www.w3.org/1999/xhtml"
});
// Append each block node to xml dom.
for (var blockType in blockXmlMap) {
blockXmls.push(blockXmlMap[blockType]);
var blockXmlDom = Blockly.Xml.textToDom(blockXmlMap[blockType]);
var blockNode = blockXmlDom.firstElementChild;
xmlDom.appendChild(blockNode);
}
return blockXmls.join("\n\n");
// Return the xml text.
return Blockly.Xml.domToText(xmlDom);
};
/**
* Converts imported block library to an object mapping block type to block xml.
* @private
*
* @param {string} xmlText - String containing each block's xml optionally
* separated by whitespace.
* @param {string} xmlText - String representation of an xml with each block as
* a child node.
* @return {!Object} object mapping block type to xml text.
*/
AppController.prototype.formatBlockLibForImport_ = function(xmlText) {
// Get array of xmls.
var xmlText = goog.string.collapseWhitespace(xmlText);
var blockXmls = goog.string.splitLimit(xmlText, '</xml>', 500);
var xmlDom = Blockly.Xml.textToDom(xmlText);
// Create and populate map.
// Get array of xmls. Use an asterisk (*) instead of a tag name for the XPath
// selector, to match all elements at that level and get all factory_base
// blocks.
var blockNodes = goog.dom.xml.selectNodes(xmlDom, '*');
// Create empty map. The line below creates a truly empy object. It doesn't
// have built-in attributes/functions such as length or toString.
var blockXmlTextMap = Object.create(null);
// The line above is equivalent of {} except that this object is TRULY
// empty. It doesn't have built-in attributes/functions such as length or
// toString.
for (var i = 0, xmlText; xmlText = blockXmls[i]; i++) {
// Populate map.
for (var i = 0, blockNode; blockNode = blockNodes[i]; i++) {
// Add outer xml tag to the block for proper injection in to the
// main workspace.
// Create DOM for XML.
var xmlDom = goog.dom.createDom('xml', {
'xmlns':"http://www.w3.org/1999/xhtml"
});
xmlDom.appendChild(blockNode);
var xmlText = Blockly.Xml.domToText(xmlDom);
var blockType = this.getBlockTypeFromXml_(xmlText);
// TODO(quachtina96): Make the xml pretty before storing in map.
blockXmlTextMap[blockType] = xmlText;
}
@@ -185,9 +207,9 @@ AppController.prototype.formatBlockLibForImport_ = function(xmlText) {
* @return {string} The block type that corresponds to the provided xml text.
*/
AppController.prototype.getBlockTypeFromXml_ = function(xmlText) {
var xmlText = Blockly.Options.parseToolboxTree(xmlText);
var xmlDom = Blockly.Xml.textToDom(xmlText);
// Find factory base block.
var factoryBaseBlockXml = xmlText.getElementsByTagName('block')[0];
var factoryBaseBlockXml = xmlDom.getElementsByTagName('block')[0];
// Get field elements from factory base.
var fields = factoryBaseBlockXml.getElementsByTagName('field');
for (var i = 0; i < fields.length; i++) {
@@ -206,7 +228,8 @@ AppController.prototype.getBlockTypeFromXml_ = function(xmlText) {
* @param {!Element} blockLibraryDropdown - HTML select element from which the
* user selects a block to work on.
*/
AppController.prototype.onSelectedBlockChanged = function(blockLibraryDropdown) {
AppController.prototype.onSelectedBlockChanged
= function(blockLibraryDropdown) {
// Get selected block type.
var blockType = this.blockLibraryController.getSelectedBlockType(
blockLibraryDropdown);

View File

@@ -871,4 +871,4 @@ FactoryUtils.defineAndGetBlockTypes = function(blockDefsString, format) {
}
return blockTypes;
};
};