diff --git a/blockly_compressed.js b/blockly_compressed.js
index 8fdab6f2c..dc6efca41 100644
--- a/blockly_compressed.js
+++ b/blockly_compressed.js
@@ -43,7 +43,8 @@ Blockly.Events.fromJson=function(a,b){switch(a.type){case Blockly.Events.CREATE:
new Blockly.Events.VarRename(null,"");break;case Blockly.Events.UI:c=new Blockly.Events.Ui(null);break;case Blockly.Events.COMMENT_CREATE:c=new Blockly.Events.CommentCreate(null);break;case Blockly.Events.COMMENT_CHANGE:c=new Blockly.Events.CommentChange(null);break;case Blockly.Events.COMMENT_MOVE:c=new Blockly.Events.CommentMove(null);break;case Blockly.Events.COMMENT_DELETE:c=new Blockly.Events.CommentDelete(null);break;default:throw Error("Unknown event type.");}c.fromJson(a);c.workspaceId=b.id;
return c};Blockly.Events.disableOrphans=function(a){if(a.type==Blockly.Events.MOVE||a.type==Blockly.Events.CREATE){var b=Blockly.Workspace.getById(a.workspaceId);if(a=b.getBlockById(a.blockId)){var c=a.getParent();if(c&&c.isEnabled())for(b=a.getDescendants(!1),a=0;c=b[a];a++)c.setEnabled(!0);else if((a.outputConnection||a.previousConnection)&&!b.isDragging()){do a.setEnabled(!1),a=a.getNextBlock();while(a)}}}};
Blockly.Events.Abstract=function(){this.workspaceId=void 0;this.group=Blockly.Events.group_;this.recordUndo=Blockly.Events.recordUndo};Blockly.Events.Abstract.prototype.toJson=function(){var a={type:this.type};this.group&&(a.group=this.group);return a};Blockly.Events.Abstract.prototype.fromJson=function(a){this.group=a.group};Blockly.Events.Abstract.prototype.isNull=function(){return!1};Blockly.Events.Abstract.prototype.run=function(a){};
-Blockly.Events.Abstract.prototype.getEventWorkspace_=function(){var a=Blockly.Workspace.getById(this.workspaceId);if(!a)throw Error("Workspace is null. Event must have been generated from real Blockly events.");return a};Blockly.utils.object={};Blockly.utils.object.inherits=function(a,b){a.superClass_=b.prototype;a.prototype=Object.create(b.prototype);a.prototype.constructor=a};Blockly.utils.object.mixin=function(a,b){for(var c in b)a[c]=b[c]};Blockly.utils.object.values=function(a){return Object.values?Object.values(a):Object.keys(a).map(function(b){return a[b]})};Blockly.utils.xml={};Blockly.utils.xml.NAME_SPACE="https://developers.google.com/blockly/xml";Blockly.utils.xml.createElement=function(a){return document.createElementNS(Blockly.utils.xml.NAME_SPACE,a)};Blockly.utils.xml.createTextNode=function(a){return document.createTextNode(a)};Blockly.utils.xml.textToDomDocument=function(a){return(new DOMParser).parseFromString(a,"text/xml")};Blockly.utils.xml.domToText=function(a){return(new XMLSerializer).serializeToString(a)};Blockly.Events.BlockBase=function(a){Blockly.Events.BlockBase.superClass_.constructor.call(this);this.blockId=a.id;this.workspaceId=a.workspace.id};Blockly.utils.object.inherits(Blockly.Events.BlockBase,Blockly.Events.Abstract);Blockly.Events.BlockBase.prototype.toJson=function(){var a=Blockly.Events.BlockBase.superClass_.toJson.call(this);a.blockId=this.blockId;return a};
+Blockly.Events.Abstract.prototype.getEventWorkspace_=function(){var a=Blockly.Workspace.getById(this.workspaceId);if(!a)throw Error("Workspace is null. Event must have been generated from real Blockly events.");return a};Blockly.utils.object={};Blockly.utils.object.inherits=function(a,b){a.superClass_=b.prototype;a.prototype=Object.create(b.prototype);a.prototype.constructor=a};Blockly.utils.object.mixin=function(a,b){for(var c in b)a[c]=b[c]};Blockly.utils.object.values=function(a){return Object.values?Object.values(a):Object.keys(a).map(function(b){return a[b]})};Blockly.utils.xml={};Blockly.utils.xml.NAME_SPACE="https://developers.google.com/blockly/xml";Blockly.utils.xml.document=function(){return document};Blockly.utils.xml.createElement=function(a){return Blockly.utils.xml.document().createElementNS(Blockly.utils.xml.NAME_SPACE,a)};Blockly.utils.xml.createTextNode=function(a){return Blockly.utils.xml.document().createTextNode(a)};Blockly.utils.xml.textToDomDocument=function(a){return(new DOMParser).parseFromString(a,"text/xml")};
+Blockly.utils.xml.domToText=function(a){return(new XMLSerializer).serializeToString(a)};Blockly.Events.BlockBase=function(a){Blockly.Events.BlockBase.superClass_.constructor.call(this);this.blockId=a.id;this.workspaceId=a.workspace.id};Blockly.utils.object.inherits(Blockly.Events.BlockBase,Blockly.Events.Abstract);Blockly.Events.BlockBase.prototype.toJson=function(){var a=Blockly.Events.BlockBase.superClass_.toJson.call(this);a.blockId=this.blockId;return a};
Blockly.Events.BlockBase.prototype.fromJson=function(a){Blockly.Events.BlockBase.superClass_.fromJson.call(this,a);this.blockId=a.blockId};Blockly.Events.Change=function(a,b,c,d,e){a&&(Blockly.Events.Change.superClass_.constructor.call(this,a),this.element=b,this.name=c,this.oldValue=d,this.newValue=e)};Blockly.utils.object.inherits(Blockly.Events.Change,Blockly.Events.BlockBase);Blockly.Events.BlockChange=Blockly.Events.Change;Blockly.Events.Change.prototype.type=Blockly.Events.CHANGE;
Blockly.Events.Change.prototype.toJson=function(){var a=Blockly.Events.Change.superClass_.toJson.call(this);a.element=this.element;this.name&&(a.name=this.name);a.newValue=this.newValue;return a};Blockly.Events.Change.prototype.fromJson=function(a){Blockly.Events.Change.superClass_.fromJson.call(this,a);this.element=a.element;this.name=a.name;this.newValue=a.newValue};Blockly.Events.Change.prototype.isNull=function(){return this.oldValue==this.newValue};
Blockly.Events.Change.prototype.run=function(a){var b=this.getEventWorkspace_().getBlockById(this.blockId);if(b)switch(b.mutator&&b.mutator.setVisible(!1),a=a?this.newValue:this.oldValue,this.element){case "field":(b=b.getField(this.name))?b.setValue(a):console.warn("Can't set non-existent field: "+this.name);break;case "comment":b.setCommentText(a||null);break;case "collapsed":b.setCollapsed(a);break;case "disabled":b.setEnabled(!a);break;case "inline":b.setInputsInline(a);break;case "mutation":var c=
diff --git a/core/utils/xml.js b/core/utils/xml.js
index 87854714c..082844ec1 100644
--- a/core/utils/xml.js
+++ b/core/utils/xml.js
@@ -37,6 +37,16 @@ goog.provide('Blockly.utils.xml');
*/
Blockly.utils.xml.NAME_SPACE = 'https://developers.google.com/blockly/xml';
+/**
+ * Get the document object. This method is overridden in the Node.js build of
+ * Blockly. See gulpfile.js, package-blockly-node task.
+ * @return {!Document} The document object.
+ * @public
+ */
+Blockly.utils.xml.document = function() {
+ return document;
+};
+
/**
* Create DOM element for XML.
* @param {string} tagName Name of DOM element.
@@ -44,8 +54,8 @@ Blockly.utils.xml.NAME_SPACE = 'https://developers.google.com/blockly/xml';
* @public
*/
Blockly.utils.xml.createElement = function(tagName) {
- // TODO (#2082): Support node.js.
- return document.createElementNS(Blockly.utils.xml.NAME_SPACE, tagName);
+ return Blockly.utils.xml.document().createElementNS(
+ Blockly.utils.xml.NAME_SPACE, tagName);
};
/**
@@ -55,13 +65,11 @@ Blockly.utils.xml.createElement = function(tagName) {
* @public
*/
Blockly.utils.xml.createTextNode = function(text) {
- // TODO (#2082): Support node.js.
- return document.createTextNode(text);
+ return Blockly.utils.xml.document().createTextNode(text);
};
/**
- * Converts an XML string into a DOM tree. This method will be overridden in
- * the Node.js build of Blockly. See gulpfile.js, blockly_javascript_en task.
+ * Converts an XML string into a DOM tree.
* @param {string} text XML string.
* @return {Document} The DOM document.
* @throws if XML doesn't parse.
@@ -80,7 +88,6 @@ Blockly.utils.xml.textToDomDocument = function(text) {
* @public
*/
Blockly.utils.xml.domToText = function(dom) {
- // TODO (#2082): Support node.js.
var oSerializer = new XMLSerializer();
return oSerializer.serializeToString(dom);
};
diff --git a/gulpfile.js b/gulpfile.js
index f7614dc1f..4624f6da0 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -453,13 +453,12 @@ gulp.task('package-blockly-node', function() {
return gulp.src('blockly_compressed.js')
.pipe(gulp.insert.append(`
if (typeof DOMParser !== 'function') {
- var JSDOM = require('jsdom').JSDOM;
- var window = (new JSDOM()).window;
- var document = window.document;
- var Element = window.Element;
- Blockly.utils.xml.textToDomDocument = function(text) {
- var jsdom = new JSDOM(text, { contentType: 'text/xml' });
- return jsdom.window.document;
+ var DOMParser = require("jsdom/lib/jsdom/living").DOMParser;
+ var XMLSerializer = require("jsdom/lib/jsdom/living").XMLSerializer;
+ var doc = Blockly.utils.xml.textToDomDocument(
+ '');
+ Blockly.utils.xml.document = function() {
+ return doc;
};
}`))
.pipe(packageCommonJS('Blockly', []))
diff --git a/tests/node/run_node_test.js b/tests/node/run_node_test.js
index cc76ebfab..c2c9847ee 100644
--- a/tests/node/run_node_test.js
+++ b/tests/node/run_node_test.js
@@ -26,25 +26,33 @@ var assert = require('chai').assert;
var Blockly = require('../../dist/');
var xmlText = `
-
-
-
- Hello from Blockly!
-
-
-
+
+
+
+ Hello from Blockly!
+
+
+
`;
suite('Test Node.js', function() {
test('Import XML', function() {
- assert.doesNotThrow(function() {
- const xml = Blockly.Xml.textToDom(xmlText);
+ const xml = Blockly.Xml.textToDom(xmlText);
- // Create workspace and import the XML
- const workspace = new Blockly.Workspace();
- Blockly.Xml.domToWorkspace(xml, workspace);
+ // Create workspace and import the XML
+ const workspace = new Blockly.Workspace();
+ Blockly.Xml.domToWorkspace(xml, workspace);
+ });
+ test('Roundtrip XML', function() {
+ const xml = Blockly.Xml.textToDom(xmlText);
- }, "Failed to import XML");
+ const workspace = new Blockly.Workspace();
+ Blockly.Xml.domToWorkspace(xml, workspace);
+
+ var headlessXml = Blockly.Xml.workspaceToDom(workspace, true);
+ var headlessText = Blockly.Xml.domToPrettyText(headlessXml);
+
+ assert.equal(headlessText, xmlText, 'equal');
});
test('Generate Code', function() {
const xml = Blockly.Xml.textToDom(xmlText);