Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

452 rindas
15KB

  1. /**
  2. * Copyright 2013 IBM Corp.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. **/
  16. RED.nodes = (function() {
  17. var node_defs = {};
  18. var nodes = [];
  19. var configNodes = {};
  20. var links = [];
  21. var defaultWorkspace;
  22. var workspaces = {};
  23. function registerType(nt,def) {
  24. node_defs[nt] = def;
  25. // TODO: too tightly coupled into palette UI
  26. RED.palette.add(nt,def);
  27. }
  28. function getID() {
  29. return (1+Math.random()*4294967295).toString(16);
  30. }
  31. function getType(type) {
  32. return node_defs[type];
  33. }
  34. function addNode(n) {
  35. if (n._def.category == "config") {
  36. configNodes[n.id] = n;
  37. RED.sidebar.config.refresh();
  38. } else {
  39. n.dirty = true;
  40. nodes.push(n);
  41. var updatedConfigNode = false;
  42. for (var d in n._def.defaults) {
  43. if (n._def.defaults.hasOwnProperty(d)) {
  44. var property = n._def.defaults[d];
  45. if (property.type) {
  46. var type = getType(property.type)
  47. if (type && type.category == "config") {
  48. var configNode = configNodes[n[d]];
  49. if (configNode) {
  50. updatedConfigNode = true;
  51. configNode.users.push(n);
  52. }
  53. }
  54. }
  55. }
  56. }
  57. if (updatedConfigNode) {
  58. RED.sidebar.config.refresh();
  59. }
  60. }
  61. }
  62. function addLink(l) {
  63. links.push(l);
  64. }
  65. function addConfig(c) {
  66. configNodes[c.id] = c;
  67. }
  68. function getNode(id) {
  69. if (id in configNodes) {
  70. return configNodes[id];
  71. } else {
  72. for (var n in nodes) {
  73. if (nodes[n].id == id) {
  74. return nodes[n];
  75. }
  76. }
  77. }
  78. return null;
  79. }
  80. function removeNode(id) {
  81. var removedLinks = [];
  82. if (id in configNodes) {
  83. delete configNodes[id];
  84. RED.sidebar.config.refresh();
  85. } else {
  86. var node = getNode(id);
  87. if (node) {
  88. nodes.splice(nodes.indexOf(node),1);
  89. removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
  90. removedLinks.map(function(l) {links.splice(links.indexOf(l), 1); });
  91. }
  92. var updatedConfigNode = false;
  93. for (var d in node._def.defaults) {
  94. if (node._def.defaults.hasOwnProperty(d)) {
  95. var property = node._def.defaults[d];
  96. if (property.type) {
  97. var type = getType(property.type)
  98. if (type && type.category == "config") {
  99. var configNode = configNodes[node[d]];
  100. if (configNode) {
  101. updatedConfigNode = true;
  102. var users = configNode.users;
  103. users.splice(users.indexOf(node),1);
  104. }
  105. }
  106. }
  107. }
  108. }
  109. if (updatedConfigNode) {
  110. RED.sidebar.config.refresh();
  111. }
  112. }
  113. return removedLinks;
  114. }
  115. function removeLink(l) {
  116. var index = links.indexOf(l);
  117. if (index != -1) {
  118. links.splice(index,1);
  119. }
  120. }
  121. function refreshValidation() {
  122. for (var n=0;n<nodes.length;n++) {
  123. RED.editor.validateNode(nodes[n]);
  124. }
  125. }
  126. function addWorkspace(ws) {
  127. workspaces[ws.id] = ws;
  128. }
  129. function getWorkspace(id) {
  130. return workspaces[id];
  131. }
  132. function removeWorkspace(id) {
  133. delete workspaces[id];
  134. var removedNodes = [];
  135. var removedLinks = [];
  136. var n;
  137. for (n=0;n<nodes.length;n++) {
  138. var node = nodes[n];
  139. if (node.z == id) {
  140. removedNodes.push(node);
  141. }
  142. }
  143. for (n=0;n<removedNodes.length;n++) {
  144. var rmlinks = removeNode(removedNodes[n].id);
  145. removedLinks = removedLinks.concat(rmlinks);
  146. }
  147. return {nodes:removedNodes,links:removedLinks};
  148. }
  149. function getAllFlowNodes(node) {
  150. var visited = {};
  151. visited[node.id] = true;
  152. var nns = [node];
  153. var stack = [node];
  154. while(stack.length !== 0) {
  155. var n = stack.shift();
  156. var childLinks = links.filter(function(d) { return (d.source === n) || (d.target === n);});
  157. for (var i=0;i<childLinks.length;i++) {
  158. var child = (childLinks[i].source === n)?childLinks[i].target:childLinks[i].source;
  159. if (!visited[child.id]) {
  160. visited[child.id] = true;
  161. nns.push(child);
  162. stack.push(child);
  163. }
  164. }
  165. }
  166. return nns;
  167. }
  168. /**
  169. * Converts a node to an exportable JSON Object
  170. **/
  171. function convertNode(n, exportCreds) {
  172. exportCreds = exportCreds || false;
  173. var node = {};
  174. node.id = n.id;
  175. node.type = n.type;
  176. for (var d in n._def.defaults) {
  177. if (n._def.defaults.hasOwnProperty(d)) {
  178. node[d] = n[d];
  179. }
  180. }
  181. if(exportCreds && n.credentials) {
  182. node.credentials = {};
  183. for (var cred in n._def.credentials) {
  184. if (n._def.credentials.hasOwnProperty(cred)) {
  185. if (n.credentials[cred] != null) {
  186. node.credentials[cred] = n.credentials[cred];
  187. }
  188. }
  189. }
  190. }
  191. if (n._def.category != "config") {
  192. node.x = n.x;
  193. node.y = n.y;
  194. node.z = n.z;
  195. node.wires = [];
  196. for(var i=0;i<n.outputs;i++) {
  197. node.wires.push([]);
  198. }
  199. var wires = links.filter(function(d){return d.source === n;});
  200. for (var j=0;j<wires.length;j++) {
  201. var w = wires[j];
  202. node.wires[w.sourcePort].push(w.target.id);
  203. }
  204. }
  205. return node;
  206. }
  207. /**
  208. * Converts the current node selection to an exportable JSON Object
  209. **/
  210. function createExportableNodeSet(set) {
  211. var nns = [];
  212. var exportedConfigNodes = {};
  213. for (var n=0;n<set.length;n++) {
  214. var node = set[n].n;
  215. var convertedNode = RED.nodes.convertNode(node);
  216. for (var d in node._def.defaults) {
  217. if (node._def.defaults[d].type && node[d] in configNodes) {
  218. var confNode = configNodes[node[d]];
  219. var exportable = getType(node._def.defaults[d].type).exportable;
  220. if ((exportable == null || exportable)) {
  221. if (!(node[d] in exportedConfigNodes)) {
  222. exportedConfigNodes[node[d]] = true;
  223. nns.unshift(RED.nodes.convertNode(confNode));
  224. }
  225. } else {
  226. convertedNode[d] = "";
  227. }
  228. }
  229. }
  230. nns.push(convertedNode);
  231. }
  232. return nns;
  233. }
  234. //TODO: rename this (createCompleteNodeSet)
  235. function createCompleteNodeSet() {
  236. var nns = [];
  237. var i;
  238. for (i in workspaces) {
  239. if (workspaces.hasOwnProperty(i)) {
  240. nns.push(workspaces[i]);
  241. }
  242. }
  243. for (i in configNodes) {
  244. if (configNodes.hasOwnProperty(i)) {
  245. nns.push(convertNode(configNodes[i], true));
  246. }
  247. }
  248. for (i=0;i<nodes.length;i++) {
  249. var node = nodes[i];
  250. nns.push(convertNode(node, true));
  251. }
  252. return nns;
  253. }
  254. function importNodes(newNodesObj,createNewIds) {
  255. try {
  256. var i;
  257. var n;
  258. var newNodes;
  259. if (typeof newNodesObj === "string") {
  260. if (newNodesObj === "") {
  261. return;
  262. }
  263. newNodes = JSON.parse(newNodesObj);
  264. } else {
  265. newNodes = newNodesObj;
  266. }
  267. if (!$.isArray(newNodes)) {
  268. newNodes = [newNodes];
  269. }
  270. var unknownTypes = [];
  271. for (i=0;i<newNodes.length;i++) {
  272. n = newNodes[i];
  273. // TODO: remove workspace in next release+1
  274. if (n.type != "workspace" && n.type != "tab" && !getType(n.type)) {
  275. // TODO: get this UI thing out of here! (see below as well)
  276. n.name = n.type;
  277. n.type = "unknown";
  278. if (unknownTypes.indexOf(n.name)==-1) {
  279. unknownTypes.push(n.name);
  280. }
  281. if (n.x == null && n.y == null) {
  282. // config node - remove it
  283. newNodes.splice(i,1);
  284. i--;
  285. }
  286. }
  287. }
  288. if (unknownTypes.length > 0) {
  289. var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
  290. var type = "type"+(unknownTypes.length > 1?"s":"");
  291. RED.notify("<strong>Imported unrecognised "+type+":</strong>"+typeList,"error",false,10000);
  292. //"DO NOT DEPLOY while in this state.<br/>Either, add missing types to Node-RED, restart and then reload page,<br/>or delete unknown "+n.name+", rewire as required, and then deploy.","error");
  293. }
  294. for (i=0;i<newNodes.length;i++) {
  295. n = newNodes[i];
  296. // TODO: remove workspace in next release+1
  297. if (n.type === "workspace" || n.type === "tab") {
  298. if (n.type === "workspace") {
  299. n.type = "tab";
  300. }
  301. if (defaultWorkspace == null) {
  302. defaultWorkspace = n;
  303. }
  304. addWorkspace(n);
  305. RED.view.addWorkspace(n);
  306. }
  307. }
  308. if (defaultWorkspace == null) {
  309. defaultWorkspace = { type:"tab", id:getID(), label:"Sheet 1" };
  310. addWorkspace(defaultWorkspace);
  311. RED.view.addWorkspace(defaultWorkspace);
  312. }
  313. var node_map = {};
  314. var new_nodes = [];
  315. var new_links = [];
  316. for (i=0;i<newNodes.length;i++) {
  317. n = newNodes[i];
  318. // TODO: remove workspace in next release+1
  319. if (n.type !== "workspace" && n.type !== "tab") {
  320. var def = getType(n.type);
  321. if (def && def.category == "config") {
  322. if (!RED.nodes.node(n.id)) {
  323. var configNode = {id:n.id,type:n.type,users:[]};
  324. for (var d in def.defaults) {
  325. if (def.defaults.hasOwnProperty(d)) {
  326. configNode[d] = n[d];
  327. }
  328. }
  329. configNode.label = def.label;
  330. configNode._def = def;
  331. RED.nodes.add(configNode);
  332. }
  333. } else {
  334. var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
  335. if (createNewIds) {
  336. node.z = RED.view.getWorkspace();
  337. node.id = getID();
  338. } else {
  339. node.id = n.id;
  340. if (node.z == null || !workspaces[node.z]) {
  341. node.z = RED.view.getWorkspace();
  342. }
  343. }
  344. node.type = n.type;
  345. node._def = def;
  346. if (!node._def) {
  347. node._def = {
  348. color:"#fee",
  349. defaults: {},
  350. label: "unknown: "+n.type,
  351. labelStyle: "node_label_italic",
  352. outputs: n.outputs||n.wires.length
  353. }
  354. }
  355. node.outputs = n.outputs||node._def.outputs;
  356. for (var d2 in node._def.defaults) {
  357. if (node._def.defaults.hasOwnProperty(d2)) {
  358. node[d2] = n[d2];
  359. }
  360. }
  361. addNode(node);
  362. RED.editor.validateNode(node);
  363. node_map[n.id] = node;
  364. new_nodes.push(node);
  365. }
  366. }
  367. }
  368. for (i=0;i<new_nodes.length;i++) {
  369. n = new_nodes[i];
  370. for (var w1=0;w1<n.wires.length;w1++) {
  371. var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
  372. for (var w2=0;w2<wires.length;w2++) {
  373. if (wires[w2] in node_map) {
  374. var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]};
  375. addLink(link);
  376. new_links.push(link);
  377. }
  378. }
  379. }
  380. delete n.wires;
  381. }
  382. return [new_nodes,new_links];
  383. } catch(error) {
  384. //TODO: get this UI thing out of here! (see above as well)
  385. RED.notify("<strong>Error</strong>: "+error,"error");
  386. return null;
  387. }
  388. }
  389. return {
  390. registerType: registerType,
  391. getType: getType,
  392. convertNode: convertNode,
  393. add: addNode,
  394. addLink: addLink,
  395. remove: removeNode,
  396. removeLink: removeLink,
  397. addWorkspace: addWorkspace,
  398. removeWorkspace: removeWorkspace,
  399. workspace: getWorkspace,
  400. eachNode: function(cb) {
  401. for (var n=0;n<nodes.length;n++) {
  402. cb(nodes[n]);
  403. }
  404. },
  405. eachLink: function(cb) {
  406. for (var l=0;l<links.length;l++) {
  407. cb(links[l]);
  408. }
  409. },
  410. eachConfig: function(cb) {
  411. for (var id in configNodes) {
  412. if (configNodes.hasOwnProperty(id)) {
  413. cb(configNodes[id]);
  414. }
  415. }
  416. },
  417. node: getNode,
  418. import: importNodes,
  419. refreshValidation: refreshValidation,
  420. getAllFlowNodes: getAllFlowNodes,
  421. createExportableNodeSet: createExportableNodeSet,
  422. createCompleteNodeSet: createCompleteNodeSet,
  423. id: getID,
  424. nodes: nodes, // TODO: exposed for d3 vis
  425. links: links // TODO: exposed for d3 vis
  426. };
  427. })();