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.

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