Support XML serialization in Node.js (#3126)

* Support XML serialization in Node.js
This commit is contained in:
Sam El-Husseini
2019-10-01 14:40:35 -07:00
committed by GitHub
parent ae5c7527b6
commit d7a7c7b4d5
4 changed files with 43 additions and 28 deletions

View File

@@ -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=

View File

@@ -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);
};

View File

@@ -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(
'<xml xmlns="https://developers.google.com/blockly/xml"></xml>');
Blockly.utils.xml.document = function() {
return doc;
};
}`))
.pipe(packageCommonJS('Blockly', []))

View File

@@ -26,25 +26,33 @@ var assert = require('chai').assert;
var Blockly = require('../../dist/');
var xmlText = `<xml xmlns="https://developers.google.com/blockly/xml">
<block type="text_print" x="37" y="63">
<value name="TEXT">
<shadow type="text">
<field name="TEXT">Hello from Blockly!</field>
</shadow>
</value>
</block>
<block type="text_print" x="37" y="63">
<value name="TEXT">
<shadow type="text">
<field name="TEXT">Hello from Blockly!</field>
</shadow>
</value>
</block>
</xml>`;
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);