diff --git a/red/runtime/nodes/index.js b/red/runtime/nodes/index.js index 8f135fa07..17b5c7d47 100644 --- a/red/runtime/nodes/index.js +++ b/red/runtime/nodes/index.js @@ -1,5 +1,5 @@ /** - * Copyright 2013, 2015 IBM Corp. + * Copyright 2013, 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,15 +33,25 @@ var settings; /** * Registers a node constructor + * @param nodeSet - the nodeSet providing the node (module/set) * @param type - the string type name * @param constructor - the constructor function for this node type * @param opts - optional additional options for the node */ -function registerType(type,constructor,opts) { +function registerType(nodeSet,type,constructor,opts) { + if (typeof type !== "string") { + // This is someone calling the api directly, rather than via the + // RED object provided to a node. Log a warning + log.warn("Deprecated call to RED.runtime.nodes.registerType - node-set name must be provided as first argument"); + opts = constructor; + constructor = type; + type = nodeSet; + nodeSet = ""; + } if (opts && opts.credentials) { credentials.register(type,opts.credentials); } - registry.registerType(type,constructor); + registry.registerType(nodeSet,type,constructor); } /** diff --git a/red/runtime/nodes/registry/loader.js b/red/runtime/nodes/registry/loader.js index 3e0648c09..d160a561a 100644 --- a/red/runtime/nodes/registry/loader.js +++ b/red/runtime/nodes/registry/loader.js @@ -71,7 +71,10 @@ function createNodeApi(node) { util: runtime.util, version: runtime.version, } - copyObjectProperties(runtime.nodes,red.nodes,["createNode","getNode","eachNode","registerType","addCredentials","getCredentials","deleteCredentials" ]); + copyObjectProperties(runtime.nodes,red.nodes,["createNode","getNode","eachNode","addCredentials","getCredentials","deleteCredentials" ]); + red.nodes.registerType = function(type,constructor,opts) { + runtime.nodes.registerType(node.id,type,constructor,opts); + } copyObjectProperties(runtime.log,red.log,null,["init"]); copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]); if (runtime.adminApi) { diff --git a/red/runtime/nodes/registry/registry.js b/red/runtime/nodes/registry/registry.js index a437981be..dfb657479 100644 --- a/red/runtime/nodes/registry/registry.js +++ b/red/runtime/nodes/registry/registry.js @@ -1,5 +1,5 @@ /** - * Copyright 2015 IBM Corp. + * Copyright 2015, 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -347,7 +347,7 @@ function inheritNode(constructor) { } } -function registerNodeConstructor(type,constructor) { +function registerNodeConstructor(nodeSet,type,constructor) { if (nodeConstructors[type]) { throw new Error(type+" already registered"); } @@ -358,6 +358,17 @@ function registerNodeConstructor(type,constructor) { inheritNode(constructor); } + var nodeSetInfo = getFullNodeInfo(nodeSet); + if (nodeSetInfo) { + if (nodeSetInfo.types.indexOf(type) === -1) { + // A type is being registered for a known set, but for some reason + // we didn't spot it when parsing the HTML file. + // Registered a type is the definitive action - not the presence + // of an edit template. Ensure it is on the list of known types. + nodeSetInfo.types.push(type); + } + } + nodeConstructors[type] = constructor; events.emit("type-registered",type); } diff --git a/test/red/runtime/nodes/registry/loader_spec.js b/test/red/runtime/nodes/registry/loader_spec.js index 3071ff032..bf8589ae8 100644 --- a/test/red/runtime/nodes/registry/loader_spec.js +++ b/test/red/runtime/nodes/registry/loader_spec.js @@ -114,7 +114,8 @@ describe("red/nodes/registry/loader",function() { registry.addNodeSet.lastCall.args[1].should.not.have.a.property('err'); nodes.registerType.calledOnce.should.be.true; - nodes.registerType.lastCall.args[0].should.eql('test-node-1'); + nodes.registerType.lastCall.args[0].should.eql('node-red/TestNode1'); + nodes.registerType.lastCall.args[1].should.eql('test-node-1'); done(); }).otherwise(function(err) { @@ -162,8 +163,10 @@ describe("red/nodes/registry/loader",function() { registry.addNodeSet.lastCall.args[1].should.not.have.a.property('err'); nodes.registerType.calledTwice.should.be.true; - nodes.registerType.firstCall.args[0].should.eql('test-node-multiple-1a'); - nodes.registerType.secondCall.args[0].should.eql('test-node-multiple-1b'); + nodes.registerType.firstCall.args[0].should.eql('node-red/MultipleNodes1'); + nodes.registerType.firstCall.args[1].should.eql('test-node-multiple-1a'); + nodes.registerType.secondCall.args[0].should.eql('node-red/MultipleNodes1'); + nodes.registerType.secondCall.args[1].should.eql('test-node-multiple-1b'); done(); }).otherwise(function(err) { @@ -212,7 +215,8 @@ describe("red/nodes/registry/loader",function() { registry.addNodeSet.lastCall.args[1].should.not.have.a.property('err'); nodes.registerType.calledOnce.should.be.true; - nodes.registerType.lastCall.args[0].should.eql('test-node-2'); + nodes.registerType.lastCall.args[0].should.eql('node-red/TestNode2'); + nodes.registerType.lastCall.args[1].should.eql('test-node-2'); done(); }).otherwise(function(err) { diff --git a/test/red/runtime/nodes/registry/registry_spec.js b/test/red/runtime/nodes/registry/registry_spec.js index afe1b46aa..ea57339d6 100644 --- a/test/red/runtime/nodes/registry/registry_spec.js +++ b/test/red/runtime/nodes/registry/registry_spec.js @@ -442,25 +442,25 @@ describe("red/nodes/registry/registry",function() { events.emit.restore(); }); it('registers a node constructor', function() { - typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor); + typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor); events.emit.calledOnce.should.be.true; events.emit.lastCall.args[0].should.eql('type-registered'); events.emit.lastCall.args[1].should.eql('node-type'); }) it('throws error on duplicate node registration', function() { - typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor); + typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor); events.emit.calledOnce.should.be.true; events.emit.lastCall.args[0].should.eql('type-registered'); events.emit.lastCall.args[1].should.eql('node-type'); /*jshint immed: false */ (function(){ - typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor); + typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor); }).should.throw("node-type already registered"); events.emit.calledOnce.should.be.true; }); it('extends a constructor with the Node constructor', function() { TestNodeConstructor.prototype.should.not.be.an.instanceOf(Node); - typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor); + typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor); TestNodeConstructor.prototype.should.be.an.instanceOf(Node); }); it('does not override a constructor\'s prototype', function() { @@ -469,12 +469,12 @@ describe("red/nodes/registry/registry",function() { TestNodeConstructor.prototype.should.be.an.instanceOf(Foo); TestNodeConstructor.prototype.should.not.be.an.instanceOf(Node); - typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor); + typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor); TestNodeConstructor.prototype.should.be.an.instanceOf(Node); TestNodeConstructor.prototype.should.be.an.instanceOf(Foo); - typeRegistry.registerNodeConstructor('node-type2',TestNodeConstructor); + typeRegistry.registerNodeConstructor('node-set','node-type2',TestNodeConstructor); TestNodeConstructor.prototype.should.be.an.instanceOf(Node); TestNodeConstructor.prototype.should.be.an.instanceOf(Foo); });