@kumologica/sdk 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (540) hide show
  1. package/README.md +1 -0
  2. package/bin/kl.js +3 -0
  3. package/cli/cli.js +6 -0
  4. package/cli/commands/build-commands/aws.js +49 -0
  5. package/cli/commands/build-commands/azure.js +43 -0
  6. package/cli/commands/build-commands/kumohub.js +7 -0
  7. package/cli/commands/build.js +6 -0
  8. package/cli/commands/create.js +32 -0
  9. package/cli/commands/deploy-commands/kumohub.js +114 -0
  10. package/cli/commands/deploy.js +6 -0
  11. package/cli/commands/doc-commands/html.js +61 -0
  12. package/cli/commands/doc.js +6 -0
  13. package/cli/commands/export-commands/cloudformation.js +338 -0
  14. package/cli/commands/export-commands/serverless.js +164 -0
  15. package/cli/commands/export-commands/terraform-commands/aws.js +193 -0
  16. package/cli/commands/export-commands/terraform-commands/azure.js +148 -0
  17. package/cli/commands/export-commands/terraform.js +6 -0
  18. package/cli/commands/export-commands/utils/validator.js +152 -0
  19. package/cli/commands/export.js +6 -0
  20. package/cli/commands/import-commands/mulesoft.js +61 -0
  21. package/cli/commands/import.js +6 -0
  22. package/cli/commands/open.js +46 -0
  23. package/cli/commands/test-utils/TestSuiteController.js +359 -0
  24. package/cli/commands/test-utils/TestSuiteController.test.js +171 -0
  25. package/cli/commands/test-utils/fixtures/example3-flow.json +148 -0
  26. package/cli/commands/test-utils/fixtures/package.json +6 -0
  27. package/cli/commands/test-utils/fixtures/s3-event.js +43 -0
  28. package/cli/commands/test-utils/util/output.js +14 -0
  29. package/cli/commands/test-utils/util/updates/index.js +17 -0
  30. package/cli/commands/test-utils/util/updates/pkg.js +13 -0
  31. package/cli/commands/test-utils/util/updates/templates/default-settings.js +209 -0
  32. package/cli/commands/test.js +66 -0
  33. package/cli/commands/utils.js +14 -0
  34. package/package.json +158 -0
  35. package/src/app/lib/aws/aws-profile.js +43 -0
  36. package/src/app/lib/aws/ca-alexa-api.js +29 -0
  37. package/src/app/lib/aws/ca-apigw-api.js +216 -0
  38. package/src/app/lib/aws/ca-cloudwatch-api.js +78 -0
  39. package/src/app/lib/aws/ca-codecommit-api.js +63 -0
  40. package/src/app/lib/aws/ca-dynamodb-api.js +27 -0
  41. package/src/app/lib/aws/ca-elb-api.js +44 -0
  42. package/src/app/lib/aws/ca-events-api.js +27 -0
  43. package/src/app/lib/aws/ca-iot-api.js +105 -0
  44. package/src/app/lib/aws/ca-s3-api.js +115 -0
  45. package/src/app/lib/aws/ca-sns-api.js +38 -0
  46. package/src/app/lib/aws/ca-sqs-api.js +51 -0
  47. package/src/app/lib/aws/cf.js +439 -0
  48. package/src/app/lib/aws/index.js +970 -0
  49. package/src/app/lib/aws/kl-iam-api.js +27 -0
  50. package/src/app/lib/aws/kl-rekognition-api.js +66 -0
  51. package/src/app/lib/aws/kl-ssm-api.js +24 -0
  52. package/src/app/lib/azure/index.js +80 -0
  53. package/src/app/lib/dependencies.js +50 -0
  54. package/src/app/lib/kumohub/index.js +201 -0
  55. package/src/app/lib/runtime-loader/index.js +42 -0
  56. package/src/app/lib/serverless/index.js +318 -0
  57. package/src/app/lib/stores/aws-cloud-config-store.js +35 -0
  58. package/src/app/lib/stores/azure-config-store.js +24 -0
  59. package/src/app/lib/stores/kumohub-config-store.js +24 -0
  60. package/src/app/lib/stores/project-info-config-store.js +26 -0
  61. package/src/app/lib/stores/settings-cloud-store.js +117 -0
  62. package/src/app/lib/stores/settings-cloud-store.spec.js +26 -0
  63. package/src/app/lib/stores/settings-network-store.js +119 -0
  64. package/src/app/lib/stores/settings-network-store.spec.js +27 -0
  65. package/src/app/lib/stores/store.js +97 -0
  66. package/src/app/lib/stores/test-config-store.js +26 -0
  67. package/src/app/lib/stores/user-preference-store.js +44 -0
  68. package/src/app/lib/utils/editor.js +98 -0
  69. package/src/app/lib/utils/fix-path.js +15 -0
  70. package/src/app/main-process/favicon.ico +0 -0
  71. package/src/app/main-process/main-window.js +209 -0
  72. package/src/app/main-process/menu.js +219 -0
  73. package/src/app/main-process/modal-home.js +118 -0
  74. package/src/app/main-process/modal-newproject.js +119 -0
  75. package/src/app/main-process/modal-nodelibrary.js +90 -0
  76. package/src/app/main-process/modal-welcome.js +114 -0
  77. package/src/app/main-process/runtime-manager.js +141 -0
  78. package/src/app/main.js +590 -0
  79. package/src/app/preload.js +633 -0
  80. package/src/app/ui/editor-api/lib/admin/context.js +42 -0
  81. package/src/app/ui/editor-api/lib/admin/flow.js +55 -0
  82. package/src/app/ui/editor-api/lib/admin/flows.js +53 -0
  83. package/src/app/ui/editor-api/lib/admin/index.js +155 -0
  84. package/src/app/ui/editor-api/lib/admin/nodes.js +164 -0
  85. package/src/app/ui/editor-api/lib/auth/clients.js +17 -0
  86. package/src/app/ui/editor-api/lib/auth/index.js +267 -0
  87. package/src/app/ui/editor-api/lib/auth/permissions.js +51 -0
  88. package/src/app/ui/editor-api/lib/auth/strategies.js +144 -0
  89. package/src/app/ui/editor-api/lib/auth/tokens.js +138 -0
  90. package/src/app/ui/editor-api/lib/auth/users.js +122 -0
  91. package/src/app/ui/editor-api/lib/editor/comms.js +247 -0
  92. package/src/app/ui/editor-api/lib/editor/credentials.js +22 -0
  93. package/src/app/ui/editor-api/lib/editor/index.js +234 -0
  94. package/src/app/ui/editor-api/lib/editor/library.js +69 -0
  95. package/src/app/ui/editor-api/lib/editor/locales.js +37 -0
  96. package/src/app/ui/editor-api/lib/editor/projects.js +497 -0
  97. package/src/app/ui/editor-api/lib/editor/settings.js +118 -0
  98. package/src/app/ui/editor-api/lib/editor/sshkeys.js +87 -0
  99. package/src/app/ui/editor-api/lib/editor/theme.js +184 -0
  100. package/src/app/ui/editor-api/lib/editor/ui.js +149 -0
  101. package/src/app/ui/editor-api/lib/index.js +149 -0
  102. package/src/app/ui/editor-api/lib/runner/index.js +81 -0
  103. package/src/app/ui/editor-api/lib/util.js +51 -0
  104. package/src/app/ui/editor-client/README.md +10 -0
  105. package/src/app/ui/editor-client/constants.js +5 -0
  106. package/src/app/ui/editor-client/index.js +3 -0
  107. package/src/app/ui/editor-client/public/favicon.ico +0 -0
  108. package/src/app/ui/editor-client/public/red/images/bolt.png +0 -0
  109. package/src/app/ui/editor-client/public/red/images/debugger/continue-full.png +0 -0
  110. package/src/app/ui/editor-client/public/red/images/debugger/continue-outline.png +0 -0
  111. package/src/app/ui/editor-client/public/red/images/debugger/pause.png +0 -0
  112. package/src/app/ui/editor-client/public/red/images/debugger/restart.png +0 -0
  113. package/src/app/ui/editor-client/public/red/images/debugger/stepover.png +0 -0
  114. package/src/app/ui/editor-client/public/red/images/debugger/stop.png +0 -0
  115. package/src/app/ui/editor-client/public/red/images/deploy-flows-o.png +0 -0
  116. package/src/app/ui/editor-client/public/red/images/deploy-flows.png +0 -0
  117. package/src/app/ui/editor-client/public/red/images/deploy-full-o.png +0 -0
  118. package/src/app/ui/editor-client/public/red/images/deploy-full.png +0 -0
  119. package/src/app/ui/editor-client/public/red/images/deploy-nodes-o.png +0 -0
  120. package/src/app/ui/editor-client/public/red/images/deploy-nodes.png +0 -0
  121. package/src/app/ui/editor-client/public/red/images/deploy-reload.png +0 -0
  122. package/src/app/ui/editor-client/public/red/images/grip.png +0 -0
  123. package/src/app/ui/editor-client/public/red/images/icons/arrow-in.png +0 -0
  124. package/src/app/ui/editor-client/public/red/images/icons/bolt.png +0 -0
  125. package/src/app/ui/editor-client/public/red/images/icons/node-changed.png +0 -0
  126. package/src/app/ui/editor-client/public/red/images/icons/node-error.png +0 -0
  127. package/src/app/ui/editor-client/public/red/images/icons/node-play.png +0 -0
  128. package/src/app/ui/editor-client/public/red/images/kumologica-app.png +0 -0
  129. package/src/app/ui/editor-client/public/red/images/node-red-256.png +0 -0
  130. package/src/app/ui/editor-client/public/red/images/node-red-icon-black.svg +9 -0
  131. package/src/app/ui/editor-client/public/red/images/node-red-icon.svg +33 -0
  132. package/src/app/ui/editor-client/public/red/images/node-red.png +0 -0
  133. package/src/app/ui/editor-client/public/red/images/pw_maze_white.png +0 -0
  134. package/src/app/ui/editor-client/public/red/images/spin.svg +41 -0
  135. package/src/app/ui/editor-client/public/red/images/spinner.gif +0 -0
  136. package/src/app/ui/editor-client/public/red/images/subflow_tab.png +0 -0
  137. package/src/app/ui/editor-client/public/red/images/test-icon.png +0 -0
  138. package/src/app/ui/editor-client/public/red/images/typedInput/09.png +0 -0
  139. package/src/app/ui/editor-client/public/red/images/typedInput/az.png +0 -0
  140. package/src/app/ui/editor-client/public/red/images/typedInput/bin.png +0 -0
  141. package/src/app/ui/editor-client/public/red/images/typedInput/bool.png +0 -0
  142. package/src/app/ui/editor-client/public/red/images/typedInput/env.png +0 -0
  143. package/src/app/ui/editor-client/public/red/images/typedInput/expr.png +0 -0
  144. package/src/app/ui/editor-client/public/red/images/typedInput/json.png +0 -0
  145. package/src/app/ui/editor-client/public/red/images/typedInput/re.png +0 -0
  146. package/src/app/ui/editor-client/public/red/keymap.json +54 -0
  147. package/src/app/ui/editor-client/public/red/main-modals.js +14 -0
  148. package/src/app/ui/editor-client/public/red/main-modals.min.js +16 -0
  149. package/src/app/ui/editor-client/public/red/main.js +10 -0
  150. package/src/app/ui/editor-client/public/red/main.min.js +16 -0
  151. package/src/app/ui/editor-client/public/red/red.js +44903 -0
  152. package/src/app/ui/editor-client/public/red/red.min.js +16 -0
  153. package/src/app/ui/editor-client/public/red/style.min.css +24 -0
  154. package/src/app/ui/editor-client/public/vendor/ace/LICENSE +24 -0
  155. package/src/app/ui/editor-client/public/vendor/ace/ace.js +17 -0
  156. package/src/app/ui/editor-client/public/vendor/ace/ext-language_tools.js +8 -0
  157. package/src/app/ui/editor-client/public/vendor/ace/ext-searchbox.js +8 -0
  158. package/src/app/ui/editor-client/public/vendor/ace/mode-css.js +8 -0
  159. package/src/app/ui/editor-client/public/vendor/ace/mode-handlebars.js +8 -0
  160. package/src/app/ui/editor-client/public/vendor/ace/mode-html.js +8 -0
  161. package/src/app/ui/editor-client/public/vendor/ace/mode-javascript.js +8 -0
  162. package/src/app/ui/editor-client/public/vendor/ace/mode-json.js +8 -0
  163. package/src/app/ui/editor-client/public/vendor/ace/mode-jsonata.js +1 -0
  164. package/src/app/ui/editor-client/public/vendor/ace/mode-markdown.js +8 -0
  165. package/src/app/ui/editor-client/public/vendor/ace/mode-properties.js +8 -0
  166. package/src/app/ui/editor-client/public/vendor/ace/mode-python.js +8 -0
  167. package/src/app/ui/editor-client/public/vendor/ace/mode-sql.js +8 -0
  168. package/src/app/ui/editor-client/public/vendor/ace/mode-swift.js +8 -0
  169. package/src/app/ui/editor-client/public/vendor/ace/mode-text.js +8 -0
  170. package/src/app/ui/editor-client/public/vendor/ace/mode-xml.js +8 -0
  171. package/src/app/ui/editor-client/public/vendor/ace/mode-yaml.js +8 -0
  172. package/src/app/ui/editor-client/public/vendor/ace/snippets/css.js +8 -0
  173. package/src/app/ui/editor-client/public/vendor/ace/snippets/handlebars.js +8 -0
  174. package/src/app/ui/editor-client/public/vendor/ace/snippets/html.js +8 -0
  175. package/src/app/ui/editor-client/public/vendor/ace/snippets/javascript.js +8 -0
  176. package/src/app/ui/editor-client/public/vendor/ace/snippets/json.js +8 -0
  177. package/src/app/ui/editor-client/public/vendor/ace/snippets/jsonata.js +1 -0
  178. package/src/app/ui/editor-client/public/vendor/ace/snippets/markdown.js +8 -0
  179. package/src/app/ui/editor-client/public/vendor/ace/snippets/properties.js +8 -0
  180. package/src/app/ui/editor-client/public/vendor/ace/snippets/python.js +8 -0
  181. package/src/app/ui/editor-client/public/vendor/ace/snippets/sql.js +8 -0
  182. package/src/app/ui/editor-client/public/vendor/ace/snippets/swift.js +8 -0
  183. package/src/app/ui/editor-client/public/vendor/ace/snippets/text.js +8 -0
  184. package/src/app/ui/editor-client/public/vendor/ace/snippets/xml.js +8 -0
  185. package/src/app/ui/editor-client/public/vendor/ace/snippets/yaml.js +8 -0
  186. package/src/app/ui/editor-client/public/vendor/ace/theme-chrome.js +8 -0
  187. package/src/app/ui/editor-client/public/vendor/ace/theme-tomorrow.js +8 -0
  188. package/src/app/ui/editor-client/public/vendor/ace/worker-css.js +1 -0
  189. package/src/app/ui/editor-client/public/vendor/ace/worker-html.js +1 -0
  190. package/src/app/ui/editor-client/public/vendor/ace/worker-javascript.js +1 -0
  191. package/src/app/ui/editor-client/public/vendor/ace/worker-json.js +1 -0
  192. package/src/app/ui/editor-client/public/vendor/ace/worker-jsonata.js +2140 -0
  193. package/src/app/ui/editor-client/public/vendor/ace/worker-xml.js +1 -0
  194. package/src/app/ui/editor-client/public/vendor/beautifyjs/beautify.min.js +1 -0
  195. package/src/app/ui/editor-client/public/vendor/bootstrap/css/bootstrap.min.css +9 -0
  196. package/src/app/ui/editor-client/public/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
  197. package/src/app/ui/editor-client/public/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
  198. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/active-line.js +72 -0
  199. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/coffeescript-lint.js +47 -0
  200. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/javascript-hint.js +157 -0
  201. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/javascript-lint.js +63 -0
  202. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/jshint.js +29591 -0
  203. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/lint.css +73 -0
  204. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/lint.js +252 -0
  205. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/show-hint.css +36 -0
  206. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/show-hint.js +460 -0
  207. package/src/app/ui/editor-client/public/vendor/code-mirror/addon/sql-hint.js +304 -0
  208. package/src/app/ui/editor-client/public/vendor/code-mirror/lib/codemirror.css +350 -0
  209. package/src/app/ui/editor-client/public/vendor/code-mirror/lib/codemirror.js +9800 -0
  210. package/src/app/ui/editor-client/public/vendor/code-mirror/mode/javascript.js +927 -0
  211. package/src/app/ui/editor-client/public/vendor/code-mirror/mode/sql.js +494 -0
  212. package/src/app/ui/editor-client/public/vendor/code-mirror/theme/base16-dark.css +38 -0
  213. package/src/app/ui/editor-client/public/vendor/code-mirror/theme/monokai.css +42 -0
  214. package/src/app/ui/editor-client/public/vendor/code-mirror/theme/solarized.css +168 -0
  215. package/src/app/ui/editor-client/public/vendor/d3-context-menu/d3-context-menu.css +43 -0
  216. package/src/app/ui/editor-client/public/vendor/d3-context-menu/d3-context-menu.js +87 -0
  217. package/src/app/ui/editor-client/public/vendor/easy-json-schema/index.js +88 -0
  218. package/src/app/ui/editor-client/public/vendor/font-awesome/css/font-awesome.min.css +4 -0
  219. package/src/app/ui/editor-client/public/vendor/font-awesome/fonts/FontAwesome.otf +0 -0
  220. package/src/app/ui/editor-client/public/vendor/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  221. package/src/app/ui/editor-client/public/vendor/font-awesome/fonts/fontawesome-webfont.svg +2671 -0
  222. package/src/app/ui/editor-client/public/vendor/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  223. package/src/app/ui/editor-client/public/vendor/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  224. package/src/app/ui/editor-client/public/vendor/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
  225. package/src/app/ui/editor-client/public/vendor/icofont/fonts/icofont.eot +0 -0
  226. package/src/app/ui/editor-client/public/vendor/icofont/fonts/icofont.svg +2105 -0
  227. package/src/app/ui/editor-client/public/vendor/icofont/fonts/icofont.ttf +0 -0
  228. package/src/app/ui/editor-client/public/vendor/icofont/fonts/icofont.woff +0 -0
  229. package/src/app/ui/editor-client/public/vendor/icofont/fonts/icofont.woff2 +0 -0
  230. package/src/app/ui/editor-client/public/vendor/icofont/icofont.min.css +7 -0
  231. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/animated-overlay.gif +0 -0
  232. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  233. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  234. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  235. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  236. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  237. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  238. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  239. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  240. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  241. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  242. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  243. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  244. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  245. package/src/app/ui/editor-client/public/vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css +5 -0
  246. package/src/app/ui/editor-client/public/vendor/jsonata/jsonata.min.js +183 -0
  247. package/src/app/ui/editor-client/public/vendor/misc/toggleswitch.css +181 -0
  248. package/src/app/ui/editor-client/public/vendor/misc/toggleswitch.js +48 -0
  249. package/src/app/ui/editor-client/public/vendor/simplemde/simplemde.min.css +7 -0
  250. package/src/app/ui/editor-client/public/vendor/simplemde/simplemde.min.js +15 -0
  251. package/src/app/ui/editor-client/public/vendor/vendor.css +0 -0
  252. package/src/app/ui/editor-client/public/vendor/vendor.js +125 -0
  253. package/src/app/ui/editor-client/public/vendor/xterm/lib/xterm.js +2 -0
  254. package/src/app/ui/editor-client/src/ace/README.md +50 -0
  255. package/src/app/ui/editor-client/src/ace/mode/nrjavascript.js +35 -0
  256. package/src/app/ui/editor-client/src/ace/mode/nrjavascript_worker.js +189 -0
  257. package/src/app/ui/editor-client/src/favicon.ico +0 -0
  258. package/src/app/ui/editor-client/src/images/bolt.png +0 -0
  259. package/src/app/ui/editor-client/src/images/debugger/continue-full.png +0 -0
  260. package/src/app/ui/editor-client/src/images/debugger/continue-outline.png +0 -0
  261. package/src/app/ui/editor-client/src/images/debugger/pause.png +0 -0
  262. package/src/app/ui/editor-client/src/images/debugger/restart.png +0 -0
  263. package/src/app/ui/editor-client/src/images/debugger/stepover.png +0 -0
  264. package/src/app/ui/editor-client/src/images/debugger/stop.png +0 -0
  265. package/src/app/ui/editor-client/src/images/deploy-flows-o.png +0 -0
  266. package/src/app/ui/editor-client/src/images/deploy-flows.png +0 -0
  267. package/src/app/ui/editor-client/src/images/deploy-full-o.png +0 -0
  268. package/src/app/ui/editor-client/src/images/deploy-full.png +0 -0
  269. package/src/app/ui/editor-client/src/images/deploy-nodes-o.png +0 -0
  270. package/src/app/ui/editor-client/src/images/deploy-nodes.png +0 -0
  271. package/src/app/ui/editor-client/src/images/deploy-reload.png +0 -0
  272. package/src/app/ui/editor-client/src/images/grip.png +0 -0
  273. package/src/app/ui/editor-client/src/images/icons/arrow-in.png +0 -0
  274. package/src/app/ui/editor-client/src/images/icons/bolt.png +0 -0
  275. package/src/app/ui/editor-client/src/images/icons/node-changed.png +0 -0
  276. package/src/app/ui/editor-client/src/images/icons/node-error.png +0 -0
  277. package/src/app/ui/editor-client/src/images/icons/node-play.png +0 -0
  278. package/src/app/ui/editor-client/src/images/kumologica-app.png +0 -0
  279. package/src/app/ui/editor-client/src/images/node-red-256.png +0 -0
  280. package/src/app/ui/editor-client/src/images/node-red-icon-black.svg +9 -0
  281. package/src/app/ui/editor-client/src/images/node-red-icon.svg +33 -0
  282. package/src/app/ui/editor-client/src/images/node-red.png +0 -0
  283. package/src/app/ui/editor-client/src/images/pw_maze_white.png +0 -0
  284. package/src/app/ui/editor-client/src/images/spin.svg +41 -0
  285. package/src/app/ui/editor-client/src/images/spinner.gif +0 -0
  286. package/src/app/ui/editor-client/src/images/subflow_tab.png +0 -0
  287. package/src/app/ui/editor-client/src/images/test-icon.png +0 -0
  288. package/src/app/ui/editor-client/src/images/typedInput/09.png +0 -0
  289. package/src/app/ui/editor-client/src/images/typedInput/az.png +0 -0
  290. package/src/app/ui/editor-client/src/images/typedInput/bin.png +0 -0
  291. package/src/app/ui/editor-client/src/images/typedInput/bool.png +0 -0
  292. package/src/app/ui/editor-client/src/images/typedInput/env.png +0 -0
  293. package/src/app/ui/editor-client/src/images/typedInput/expr.png +0 -0
  294. package/src/app/ui/editor-client/src/images/typedInput/json.png +0 -0
  295. package/src/app/ui/editor-client/src/images/typedInput/re.png +0 -0
  296. package/src/app/ui/editor-client/src/js/comms.js +174 -0
  297. package/src/app/ui/editor-client/src/js/events.js +39 -0
  298. package/src/app/ui/editor-client/src/js/font-awesome.js +818 -0
  299. package/src/app/ui/editor-client/src/js/history.js +337 -0
  300. package/src/app/ui/editor-client/src/js/i18n.js +81 -0
  301. package/src/app/ui/editor-client/src/js/jquery-addons.js +21 -0
  302. package/src/app/ui/editor-client/src/js/keymap.json +54 -0
  303. package/src/app/ui/editor-client/src/js/main-modals.js +14 -0
  304. package/src/app/ui/editor-client/src/js/main.js +10 -0
  305. package/src/app/ui/editor-client/src/js/modals/modal-home.js +162 -0
  306. package/src/app/ui/editor-client/src/js/modals/modal-new-project.js +86 -0
  307. package/src/app/ui/editor-client/src/js/modals/modal-node-library.js +255 -0
  308. package/src/app/ui/editor-client/src/js/modals/modal-welcome.js +102 -0
  309. package/src/app/ui/editor-client/src/js/nodes.js +1736 -0
  310. package/src/app/ui/editor-client/src/js/red.js +704 -0
  311. package/src/app/ui/editor-client/src/js/settings.js +275 -0
  312. package/src/app/ui/editor-client/src/js/text/bidi.js +116 -0
  313. package/src/app/ui/editor-client/src/js/text/format.js +1316 -0
  314. package/src/app/ui/editor-client/src/js/ui/actions.js +39 -0
  315. package/src/app/ui/editor-client/src/js/ui/clipboard.js +510 -0
  316. package/src/app/ui/editor-client/src/js/ui/common/checkboxSet.js +117 -0
  317. package/src/app/ui/editor-client/src/js/ui/common/editableList.js +322 -0
  318. package/src/app/ui/editor-client/src/js/ui/common/menu.js +277 -0
  319. package/src/app/ui/editor-client/src/js/ui/common/panels.js +104 -0
  320. package/src/app/ui/editor-client/src/js/ui/common/popover.js +268 -0
  321. package/src/app/ui/editor-client/src/js/ui/common/searchBox.js +98 -0
  322. package/src/app/ui/editor-client/src/js/ui/common/stack.js +184 -0
  323. package/src/app/ui/editor-client/src/js/ui/common/tabs.js +730 -0
  324. package/src/app/ui/editor-client/src/js/ui/common/treeList.js +170 -0
  325. package/src/app/ui/editor-client/src/js/ui/common/typedInput.js +819 -0
  326. package/src/app/ui/editor-client/src/js/ui/common/typedInputLong.js +829 -0
  327. package/src/app/ui/editor-client/src/js/ui/deploy.js +422 -0
  328. package/src/app/ui/editor-client/src/js/ui/diff.js +2225 -0
  329. package/src/app/ui/editor-client/src/js/ui/editor.js +3020 -0
  330. package/src/app/ui/editor-client/src/js/ui/editors/buffer.js +195 -0
  331. package/src/app/ui/editor-client/src/js/ui/editors/expression.js +627 -0
  332. package/src/app/ui/editor-client/src/js/ui/editors/js.js +89 -0
  333. package/src/app/ui/editor-client/src/js/ui/editors/json.js +107 -0
  334. package/src/app/ui/editor-client/src/js/ui/editors/markdown.js +267 -0
  335. package/src/app/ui/editor-client/src/js/ui/editors/string.js +75 -0
  336. package/src/app/ui/editor-client/src/js/ui/event-log.js +107 -0
  337. package/src/app/ui/editor-client/src/js/ui/header.js +372 -0
  338. package/src/app/ui/editor-client/src/js/ui/keyboard.js +565 -0
  339. package/src/app/ui/editor-client/src/js/ui/library.js +570 -0
  340. package/src/app/ui/editor-client/src/js/ui/logviewer.js +116 -0
  341. package/src/app/ui/editor-client/src/js/ui/notifications.js +282 -0
  342. package/src/app/ui/editor-client/src/js/ui/palette-editor.js +1061 -0
  343. package/src/app/ui/editor-client/src/js/ui/palette.js +788 -0
  344. package/src/app/ui/editor-client/src/js/ui/project-info.js +232 -0
  345. package/src/app/ui/editor-client/src/js/ui/projects/projectSettings.js +1651 -0
  346. package/src/app/ui/editor-client/src/js/ui/projects/projectUserSettings.js +404 -0
  347. package/src/app/ui/editor-client/src/js/ui/projects/projects.js +2395 -0
  348. package/src/app/ui/editor-client/src/js/ui/projects/tab-versionControl.js +1383 -0
  349. package/src/app/ui/editor-client/src/js/ui/search.js +366 -0
  350. package/src/app/ui/editor-client/src/js/ui/sidebar.js +409 -0
  351. package/src/app/ui/editor-client/src/js/ui/state.js +14 -0
  352. package/src/app/ui/editor-client/src/js/ui/subflow.js +748 -0
  353. package/src/app/ui/editor-client/src/js/ui/tab-awsDeploy.js +1427 -0
  354. package/src/app/ui/editor-client/src/js/ui/tab-azure.js +852 -0
  355. package/src/app/ui/editor-client/src/js/ui/tab-config.js +452 -0
  356. package/src/app/ui/editor-client/src/js/ui/tab-context.js +406 -0
  357. package/src/app/ui/editor-client/src/js/ui/tab-info.js +661 -0
  358. package/src/app/ui/editor-client/src/js/ui/tab-kumohub.js +800 -0
  359. package/src/app/ui/editor-client/src/js/ui/tab-nodeInfo.js +60 -0
  360. package/src/app/ui/editor-client/src/js/ui/tab-test.js +915 -0
  361. package/src/app/ui/editor-client/src/js/ui/terminal.js +240 -0
  362. package/src/app/ui/editor-client/src/js/ui/touch/radialMenu.js +170 -0
  363. package/src/app/ui/editor-client/src/js/ui/tray.js +411 -0
  364. package/src/app/ui/editor-client/src/js/ui/typeSearch.js +411 -0
  365. package/src/app/ui/editor-client/src/js/ui/ui-settings.js +422 -0
  366. package/src/app/ui/editor-client/src/js/ui/update-panel.js +84 -0
  367. package/src/app/ui/editor-client/src/js/ui/userSettings.js +673 -0
  368. package/src/app/ui/editor-client/src/js/ui/utils.js +1287 -0
  369. package/src/app/ui/editor-client/src/js/ui/view-navigator.js +169 -0
  370. package/src/app/ui/editor-client/src/js/ui/view-tools.js +123 -0
  371. package/src/app/ui/editor-client/src/js/ui/view.js +5333 -0
  372. package/src/app/ui/editor-client/src/js/ui/workspaces.js +498 -0
  373. package/src/app/ui/editor-client/src/js/user.js +282 -0
  374. package/src/app/ui/editor-client/src/js/validators.js +54 -0
  375. package/src/app/ui/editor-client/src/kumologica-app.png +0 -0
  376. package/src/app/ui/editor-client/src/sass/ace.scss +29 -0
  377. package/src/app/ui/editor-client/src/sass/bootstrap.scss +21 -0
  378. package/src/app/ui/editor-client/src/sass/colors.scss +76 -0
  379. package/src/app/ui/editor-client/src/sass/debug.scss +383 -0
  380. package/src/app/ui/editor-client/src/sass/diff.scss +695 -0
  381. package/src/app/ui/editor-client/src/sass/dragdrop.scss +37 -0
  382. package/src/app/ui/editor-client/src/sass/dropdownMenu.scss +93 -0
  383. package/src/app/ui/editor-client/src/sass/editor.scss +683 -0
  384. package/src/app/ui/editor-client/src/sass/flow.scss +330 -0
  385. package/src/app/ui/editor-client/src/sass/forms.scss +1093 -0
  386. package/src/app/ui/editor-client/src/sass/header.scss +502 -0
  387. package/src/app/ui/editor-client/src/sass/jquery.scss +152 -0
  388. package/src/app/ui/editor-client/src/sass/keyboard.scss +136 -0
  389. package/src/app/ui/editor-client/src/sass/library.scss +54 -0
  390. package/src/app/ui/editor-client/src/sass/mixins.scss +283 -0
  391. package/src/app/ui/editor-client/src/sass/modals/modalHome.scss +138 -0
  392. package/src/app/ui/editor-client/src/sass/modals/modalNewProject.scss +96 -0
  393. package/src/app/ui/editor-client/src/sass/modals/modalNodeLibrary.scss +131 -0
  394. package/src/app/ui/editor-client/src/sass/modals/modalWelcome.scss +102 -0
  395. package/src/app/ui/editor-client/src/sass/notifications.scss +118 -0
  396. package/src/app/ui/editor-client/src/sass/palette-editor.scss +275 -0
  397. package/src/app/ui/editor-client/src/sass/palette.scss +279 -0
  398. package/src/app/ui/editor-client/src/sass/panels.scss +61 -0
  399. package/src/app/ui/editor-client/src/sass/popover.scss +166 -0
  400. package/src/app/ui/editor-client/src/sass/project-info.scss +74 -0
  401. package/src/app/ui/editor-client/src/sass/projects.scss +875 -0
  402. package/src/app/ui/editor-client/src/sass/search.scss +201 -0
  403. package/src/app/ui/editor-client/src/sass/sidebar.scss +201 -0
  404. package/src/app/ui/editor-client/src/sass/style.scss +170 -0
  405. package/src/app/ui/editor-client/src/sass/tab-azure.scss +68 -0
  406. package/src/app/ui/editor-client/src/sass/tab-cloud.scss +67 -0
  407. package/src/app/ui/editor-client/src/sass/tab-config.scss +100 -0
  408. package/src/app/ui/editor-client/src/sass/tab-context.scss +54 -0
  409. package/src/app/ui/editor-client/src/sass/tab-info.scss +307 -0
  410. package/src/app/ui/editor-client/src/sass/tab-kumohub.scss +68 -0
  411. package/src/app/ui/editor-client/src/sass/tab-test.scss +257 -0
  412. package/src/app/ui/editor-client/src/sass/tabs.scss +395 -0
  413. package/src/app/ui/editor-client/src/sass/terminal.scss +246 -0
  414. package/src/app/ui/editor-client/src/sass/ui/common/checkboxSet.scss +29 -0
  415. package/src/app/ui/editor-client/src/sass/ui/common/editableList.scss +81 -0
  416. package/src/app/ui/editor-client/src/sass/ui/common/nodeList.scss +65 -0
  417. package/src/app/ui/editor-client/src/sass/ui/common/searchBox.scss +77 -0
  418. package/src/app/ui/editor-client/src/sass/ui/common/stack.scss +26 -0
  419. package/src/app/ui/editor-client/src/sass/ui/common/treeList.scss +108 -0
  420. package/src/app/ui/editor-client/src/sass/ui/common/typedInput.scss +181 -0
  421. package/src/app/ui/editor-client/src/sass/ui/common/typedInputLong.scss +183 -0
  422. package/src/app/ui/editor-client/src/sass/ui-settings.scss +119 -0
  423. package/src/app/ui/editor-client/src/sass/update-panel.scss +18 -0
  424. package/src/app/ui/editor-client/src/sass/userSettings.scss +93 -0
  425. package/src/app/ui/editor-client/src/sass/widgetStyle.scss +23 -0
  426. package/src/app/ui/editor-client/src/sass/workspace.scss +123 -0
  427. package/src/app/ui/editor-client/src/sass/workspaceToolbar.scss +85 -0
  428. package/src/app/ui/editor-client/src/vendor/ace/LICENSE +24 -0
  429. package/src/app/ui/editor-client/src/vendor/ace/ace.js +17 -0
  430. package/src/app/ui/editor-client/src/vendor/ace/ext-language_tools.js +8 -0
  431. package/src/app/ui/editor-client/src/vendor/ace/ext-searchbox.js +8 -0
  432. package/src/app/ui/editor-client/src/vendor/ace/mode-css.js +8 -0
  433. package/src/app/ui/editor-client/src/vendor/ace/mode-handlebars.js +8 -0
  434. package/src/app/ui/editor-client/src/vendor/ace/mode-html.js +8 -0
  435. package/src/app/ui/editor-client/src/vendor/ace/mode-javascript.js +8 -0
  436. package/src/app/ui/editor-client/src/vendor/ace/mode-json.js +8 -0
  437. package/src/app/ui/editor-client/src/vendor/ace/mode-markdown.js +8 -0
  438. package/src/app/ui/editor-client/src/vendor/ace/mode-properties.js +8 -0
  439. package/src/app/ui/editor-client/src/vendor/ace/mode-python.js +8 -0
  440. package/src/app/ui/editor-client/src/vendor/ace/mode-sql.js +8 -0
  441. package/src/app/ui/editor-client/src/vendor/ace/mode-swift.js +8 -0
  442. package/src/app/ui/editor-client/src/vendor/ace/mode-text.js +8 -0
  443. package/src/app/ui/editor-client/src/vendor/ace/mode-xml.js +8 -0
  444. package/src/app/ui/editor-client/src/vendor/ace/mode-yaml.js +8 -0
  445. package/src/app/ui/editor-client/src/vendor/ace/snippets/css.js +8 -0
  446. package/src/app/ui/editor-client/src/vendor/ace/snippets/handlebars.js +8 -0
  447. package/src/app/ui/editor-client/src/vendor/ace/snippets/html.js +8 -0
  448. package/src/app/ui/editor-client/src/vendor/ace/snippets/javascript.js +8 -0
  449. package/src/app/ui/editor-client/src/vendor/ace/snippets/json.js +8 -0
  450. package/src/app/ui/editor-client/src/vendor/ace/snippets/markdown.js +8 -0
  451. package/src/app/ui/editor-client/src/vendor/ace/snippets/properties.js +8 -0
  452. package/src/app/ui/editor-client/src/vendor/ace/snippets/python.js +8 -0
  453. package/src/app/ui/editor-client/src/vendor/ace/snippets/sql.js +8 -0
  454. package/src/app/ui/editor-client/src/vendor/ace/snippets/swift.js +8 -0
  455. package/src/app/ui/editor-client/src/vendor/ace/snippets/text.js +8 -0
  456. package/src/app/ui/editor-client/src/vendor/ace/snippets/xml.js +8 -0
  457. package/src/app/ui/editor-client/src/vendor/ace/snippets/yaml.js +8 -0
  458. package/src/app/ui/editor-client/src/vendor/ace/theme-chrome.js +8 -0
  459. package/src/app/ui/editor-client/src/vendor/ace/theme-tomorrow.js +8 -0
  460. package/src/app/ui/editor-client/src/vendor/ace/worker-css.js +1 -0
  461. package/src/app/ui/editor-client/src/vendor/ace/worker-html.js +1 -0
  462. package/src/app/ui/editor-client/src/vendor/ace/worker-javascript.js +1 -0
  463. package/src/app/ui/editor-client/src/vendor/ace/worker-json.js +1 -0
  464. package/src/app/ui/editor-client/src/vendor/ace/worker-xml.js +1 -0
  465. package/src/app/ui/editor-client/src/vendor/beautifyjs/beautify.min.js +1 -0
  466. package/src/app/ui/editor-client/src/vendor/bootstrap/css/bootstrap.css +5406 -0
  467. package/src/app/ui/editor-client/src/vendor/bootstrap/css/bootstrap.min.css +9 -0
  468. package/src/app/ui/editor-client/src/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
  469. package/src/app/ui/editor-client/src/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
  470. package/src/app/ui/editor-client/src/vendor/bootstrap/js/bootstrap.min.js +6 -0
  471. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/active-line.js +72 -0
  472. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/coffeescript-lint.js +47 -0
  473. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/javascript-hint.js +157 -0
  474. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/javascript-lint.js +63 -0
  475. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/jshint.js +29591 -0
  476. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/lint.css +73 -0
  477. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/lint.js +252 -0
  478. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/show-hint.css +36 -0
  479. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/show-hint.js +460 -0
  480. package/src/app/ui/editor-client/src/vendor/code-mirror/addon/sql-hint.js +304 -0
  481. package/src/app/ui/editor-client/src/vendor/code-mirror/lib/codemirror.css +350 -0
  482. package/src/app/ui/editor-client/src/vendor/code-mirror/lib/codemirror.js +9800 -0
  483. package/src/app/ui/editor-client/src/vendor/code-mirror/mode/javascript.js +927 -0
  484. package/src/app/ui/editor-client/src/vendor/code-mirror/mode/sql.js +494 -0
  485. package/src/app/ui/editor-client/src/vendor/code-mirror/theme/base16-dark.css +38 -0
  486. package/src/app/ui/editor-client/src/vendor/code-mirror/theme/monokai.css +42 -0
  487. package/src/app/ui/editor-client/src/vendor/code-mirror/theme/solarized.css +168 -0
  488. package/src/app/ui/editor-client/src/vendor/d3/d3.v3.min.js +4 -0
  489. package/src/app/ui/editor-client/src/vendor/d3/d3.v4.min.js +2 -0
  490. package/src/app/ui/editor-client/src/vendor/d3-context-menu/d3-context-menu.css +43 -0
  491. package/src/app/ui/editor-client/src/vendor/d3-context-menu/d3-context-menu.js +87 -0
  492. package/src/app/ui/editor-client/src/vendor/easy-json-schema/index.js +88 -0
  493. package/src/app/ui/editor-client/src/vendor/font-awesome/css/font-awesome.min.css +4 -0
  494. package/src/app/ui/editor-client/src/vendor/font-awesome/fonts/FontAwesome.otf +0 -0
  495. package/src/app/ui/editor-client/src/vendor/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  496. package/src/app/ui/editor-client/src/vendor/font-awesome/fonts/fontawesome-webfont.svg +2671 -0
  497. package/src/app/ui/editor-client/src/vendor/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  498. package/src/app/ui/editor-client/src/vendor/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  499. package/src/app/ui/editor-client/src/vendor/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
  500. package/src/app/ui/editor-client/src/vendor/i18next/i18next.min.js +5 -0
  501. package/src/app/ui/editor-client/src/vendor/icofont/fonts/icofont.eot +0 -0
  502. package/src/app/ui/editor-client/src/vendor/icofont/fonts/icofont.svg +2105 -0
  503. package/src/app/ui/editor-client/src/vendor/icofont/fonts/icofont.ttf +0 -0
  504. package/src/app/ui/editor-client/src/vendor/icofont/fonts/icofont.woff +0 -0
  505. package/src/app/ui/editor-client/src/vendor/icofont/fonts/icofont.woff2 +0 -0
  506. package/src/app/ui/editor-client/src/vendor/icofont/icofont.min.css +7 -0
  507. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/animated-overlay.gif +0 -0
  508. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  509. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  510. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  511. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  512. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  513. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  514. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  515. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  516. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  517. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  518. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  519. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  520. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  521. package/src/app/ui/editor-client/src/vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css +5 -0
  522. package/src/app/ui/editor-client/src/vendor/jquery/js/jquery-1.11.3.min.js +5 -0
  523. package/src/app/ui/editor-client/src/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js +7 -0
  524. package/src/app/ui/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js +11 -0
  525. package/src/app/ui/editor-client/src/vendor/jsonata/formatter.js +183 -0
  526. package/src/app/ui/editor-client/src/vendor/jsonata/mode-jsonata.js +134 -0
  527. package/src/app/ui/editor-client/src/vendor/jsonata/snippets-jsonata.js +11 -0
  528. package/src/app/ui/editor-client/src/vendor/jsonata/worker-jsonata.js +2140 -0
  529. package/src/app/ui/editor-client/src/vendor/marked/marked.min.js +6 -0
  530. package/src/app/ui/editor-client/src/vendor/misc/toggleswitch.css +181 -0
  531. package/src/app/ui/editor-client/src/vendor/misc/toggleswitch.js +48 -0
  532. package/src/app/ui/editor-client/templates/index.mst +314 -0
  533. package/src/app/ui/editor-client/templates/modals/modalHome.mst +107 -0
  534. package/src/app/ui/editor-client/templates/modals/modalNewProject.mst +104 -0
  535. package/src/app/ui/editor-client/templates/modals/modalNodeLibrary.mst +72 -0
  536. package/src/app/ui/editor-client/templates/modals/modalWelcome.mst +111 -0
  537. package/src/assets/eula.txt +170 -0
  538. package/src/assets/icon.icns +0 -0
  539. package/src/assets/kumologica-app.png +0 -0
  540. package/src/assets/license_en.txt +170 -0
@@ -0,0 +1,3020 @@
1
+ /**
2
+ * @namespace RED.editor
3
+ */
4
+ RED.editor = (function () {
5
+ var editStack = [];
6
+ let nodeInfoEditor = null;
7
+
8
+ let latestNodeSelected = null; // Keep track of latest node selected, so the sidebar can adjust the horizontal position, so it is visible after sidebar is shown.
9
+
10
+ var customEditTypes = {};
11
+
12
+ var editTrayWidthCache = {};
13
+
14
+ function getCredentialsURL(nodeType, nodeID) {
15
+ var dashedType = nodeType.replace(/\s+/g, '-');
16
+ return 'credentials/' + dashedType + '/' + nodeID;
17
+ }
18
+
19
+
20
+ function getLatestNodeSelected() {
21
+ return latestNodeSelected;
22
+ }
23
+
24
+ function setLatestNodeSelected(newLatestNodeSelected){
25
+ // console.log('[editor] setLatestNodeSelected=', newLatestNodeSelected);
26
+ latestNodeSelected = newLatestNodeSelected;
27
+ }
28
+
29
+ /**
30
+ * Validate a node
31
+ * @param node - the node being validated
32
+ * @returns {boolean} whether the node is valid. Sets node.dirty if needed
33
+ */
34
+ function validateNode(node) {
35
+ var oldValue = node.valid;
36
+ var oldChanged = node.changed;
37
+ node.valid = true;
38
+ var subflow;
39
+ var isValid;
40
+ var hasChanged;
41
+ if (node.type.indexOf('subflow:') === 0) {
42
+ subflow = RED.nodes.subflow(node.type.substring(8));
43
+ isValid = subflow.valid;
44
+ hasChanged = subflow.changed;
45
+ if (isValid === undefined) {
46
+ isValid = validateNode(subflow);
47
+ hasChanged = subflow.changed;
48
+ }
49
+ node.valid =
50
+ isValid && validateNodeProperties(node, node._def.defaults, node);
51
+ node.changed = node.changed || hasChanged;
52
+ } else if (node._def) {
53
+ node.valid = validateNodeProperties(node, node._def.defaults, node);
54
+ // console.log(`[editor] Node ${node.name}. Valid: ${node.valid}`);
55
+ if (node._def._creds) {
56
+ node.valid =
57
+ node.valid &&
58
+ validateNodeProperties(node, node._def.credentials, node._def._creds);
59
+ }
60
+ } else if (node.type == 'subflow') {
61
+ var subflowNodes = RED.nodes.filterNodes({ z: node.id });
62
+ for (var i = 0; i < subflowNodes.length; i++) {
63
+ isValid = subflowNodes[i].valid;
64
+ hasChanged = subflowNodes[i].changed;
65
+ if (isValid === undefined) {
66
+ isValid = validateNode(subflowNodes[i]);
67
+ hasChanged = subflowNodes[i].changed;
68
+ }
69
+ node.valid = node.valid && isValid;
70
+ node.changed = node.changed || hasChanged;
71
+ }
72
+ var subflowInstances = RED.nodes.filterNodes({
73
+ type: 'subflow:' + node.id,
74
+ });
75
+ var modifiedTabs = {};
76
+ for (i = 0; i < subflowInstances.length; i++) {
77
+ subflowInstances[i].valid = node.valid;
78
+ subflowInstances[i].changed =
79
+ subflowInstances[i].changed || node.changed;
80
+ subflowInstances[i].dirty = true;
81
+ modifiedTabs[subflowInstances[i].z] = true;
82
+ }
83
+ Object.keys(modifiedTabs).forEach(function (id) {
84
+ var subflow = RED.nodes.subflow(id);
85
+ if (subflow) {
86
+ validateNode(subflow);
87
+ }
88
+ });
89
+ }
90
+ if (oldValue !== node.valid || oldChanged !== node.changed) {
91
+ node.dirty = true;
92
+ subflow = RED.nodes.subflow(node.z);
93
+ if (subflow) {
94
+ validateNode(subflow);
95
+ }
96
+ }
97
+ // console.log('[editor] node valid?', node.valid)
98
+ return node.valid;
99
+ }
100
+
101
+ /**
102
+ * Validate a node's properties for the given set of property definitions
103
+ * @param node - the node being validated
104
+ * @param definition - the node property definitions (either def.defaults or def.creds)
105
+ * @param properties - the node property values to validate
106
+ * @returns {boolean} whether the node's properties are valid
107
+ */
108
+ function validateNodeProperties(node, definition, properties) {
109
+ var isValid = true;
110
+ for (var prop in definition) {
111
+ if (definition.hasOwnProperty(prop)) {
112
+ if (!validateNodeProperty(node, definition, prop, properties[prop])) {
113
+ isValid = false;
114
+ }
115
+ }
116
+ }
117
+ // console.log(`[editor] Validating properties for node: ${node.name}. Valid? ${isValid}`)
118
+ return isValid;
119
+ }
120
+
121
+ /**
122
+ * Validate a individual node property
123
+ * @param node - the node being validated
124
+ * @param definition - the node property definitions (either def.defaults or def.creds)
125
+ * @param property - the property name being validated
126
+ * @param value - the property value being validated
127
+ * @returns {boolean} whether the node proprty is valid
128
+ */
129
+ function validateNodeProperty(node, definition, property, value) {
130
+ var valid = true;
131
+ if (/^\$\([a-zA-Z_][a-zA-Z0-9_]*\)$/.test(value)) {
132
+ return true;
133
+ }
134
+ if (/^\$\{[a-zA-Z_][a-zA-Z0-9_]*\}$/.test(value)) {
135
+ return true;
136
+ }
137
+ if ('required' in definition[property] && definition[property].required) {
138
+ valid = value !== '';
139
+ }
140
+ if (valid && 'validate' in definition[property]) {
141
+ try {
142
+ valid = definition[property].validate.call(node, value);
143
+ } catch (err) {
144
+ console.log(
145
+ 'Validation error:',
146
+ node.type,
147
+ node.id,
148
+ 'property: ' + property,
149
+ 'value:',
150
+ value,
151
+ err
152
+ );
153
+ }
154
+ }
155
+ if (
156
+ valid &&
157
+ definition[property].type &&
158
+ RED.nodes.getType(definition[property].type) &&
159
+ !('validate' in definition[property])
160
+ ) {
161
+ if (!value || value == '_ADD_') {
162
+ valid =
163
+ definition[property].hasOwnProperty('required') &&
164
+ !definition[property].required;
165
+ } else {
166
+ var configNode = RED.nodes.node(value);
167
+ valid =
168
+ configNode !== null && (configNode.valid == null || configNode.valid);
169
+ }
170
+ }
171
+ return valid;
172
+ }
173
+
174
+ function validateNodeEditor(node, prefix) {
175
+ for (var prop in node._def.defaults) {
176
+ if (node._def.defaults.hasOwnProperty(prop)) {
177
+ validateNodeEditorProperty(node, node._def.defaults, prop, prefix);
178
+ }
179
+ }
180
+ if (node._def.credentials) {
181
+ for (prop in node._def.credentials) {
182
+ if (node._def.credentials.hasOwnProperty(prop)) {
183
+ validateNodeEditorProperty(node, node._def.credentials, prop, prefix);
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ function validateNodeEditorProperty(node, defaults, property, prefix) {
190
+ var input = $('#' + prefix + '-' + property);
191
+ if (input.length > 0) {
192
+ var value = input.val();
193
+ if (
194
+ defaults[property].hasOwnProperty('format') &&
195
+ defaults[property].format !== '' &&
196
+ input[0].nodeName === 'DIV'
197
+ ) {
198
+ value = input.text();
199
+ }
200
+ if (!validateNodeProperty(node, defaults, property, value)) {
201
+ input.addClass('input-error');
202
+ } else {
203
+ input.removeClass('input-error');
204
+ }
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Called when the node's properties have changed.
210
+ * Marks the node as dirty and needing a size check.
211
+ * Removes any links to non-existant outputs.
212
+ * @param node - the node that has been updated
213
+ * @param outputMap - (optional) a map of old->new port numbers if wires should be moved
214
+ * @returns {array} the links that were removed due to this update
215
+ */
216
+ function updateNodeProperties(node, outputMap) {
217
+ node.resize = true;
218
+ node.dirty = true;
219
+ var removedLinks = [];
220
+ if (node.ports) {
221
+ if (outputMap) {
222
+ RED.nodes.eachLink(function (l) {
223
+ if (l.source === node && outputMap.hasOwnProperty(l.sourcePort)) {
224
+ if (outputMap[l.sourcePort] === '-1') {
225
+ removedLinks.push(l);
226
+ } else {
227
+ l.sourcePort = outputMap[l.sourcePort];
228
+ }
229
+ }
230
+ });
231
+ }
232
+ if (node.outputs < node.ports.length) {
233
+ while (node.outputs < node.ports.length) {
234
+ node.ports.pop();
235
+ }
236
+ RED.nodes.eachLink(function (l) {
237
+ if (
238
+ l.source === node &&
239
+ l.sourcePort >= node.outputs &&
240
+ removedLinks.indexOf(l) === -1
241
+ ) {
242
+ removedLinks.push(l);
243
+ }
244
+ });
245
+ } else if (node.outputs > node.ports.length) {
246
+ while (node.outputs > node.ports.length) {
247
+ node.ports.push(node.ports.length);
248
+ }
249
+ }
250
+ }
251
+ if (node.inputs === 0) {
252
+ removedLinks.concat(RED.nodes.filterLinks({ target: node }));
253
+ }
254
+ for (var l = 0; l < removedLinks.length; l++) {
255
+ RED.nodes.removeLink(removedLinks[l]);
256
+ }
257
+ return removedLinks;
258
+ }
259
+
260
+ /**
261
+ * Create a config-node select box for this property
262
+ * @param node - the node being edited
263
+ * @param property - the name of the field
264
+ * @param type - the type of the config-node
265
+ */
266
+ function prepareConfigNodeSelect(node, property, type, prefix) {
267
+ var input = $('#' + prefix + '-' + property);
268
+ if (input.length === 0) {
269
+ return;
270
+ }
271
+ var newWidth = input.width();
272
+ var attrStyle = input.attr('style');
273
+ var m;
274
+ if ((m = /width\s*:\s*(\d+(%|[a-z]+))/i.exec(attrStyle)) !== null) {
275
+ newWidth = m[1];
276
+ } else {
277
+ newWidth = '70%';
278
+ }
279
+ var outerWrap = $('<div></div>').css({
280
+ display: 'inline-block',
281
+ position: 'relative',
282
+ });
283
+ var selectWrap = $('<div></div>')
284
+ .css({ position: 'absolute', left: 0, right: '40px' })
285
+ .appendTo(outerWrap);
286
+ var select = $(
287
+ '<select id="' + prefix + '-' + property + '"></select>'
288
+ ).appendTo(selectWrap);
289
+
290
+ outerWrap.width(newWidth).height(input.height());
291
+ if (outerWrap.width() === 0) {
292
+ outerWrap.width('70%');
293
+ }
294
+ input.replaceWith(outerWrap);
295
+ // set the style attr directly - using width() on FF causes a value of 114%...
296
+ select.attr('style', 'width:100%');
297
+ updateConfigNodeSelect(property, type, node[property], prefix);
298
+ $(
299
+ '<a id="' +
300
+ prefix +
301
+ '-lookup-' +
302
+ property +
303
+ '" class="editor-button"><i class="fa fa-pencil"></i></a>'
304
+ )
305
+ .css({ position: 'absolute', right: 0, top: 0 })
306
+ .appendTo(outerWrap);
307
+ $('#' + prefix + '-lookup-' + property).click(function (e) {
308
+ showEditConfigNodeDialog(
309
+ property,
310
+ type,
311
+ select.find(':selected').val(),
312
+ prefix
313
+ );
314
+ e.preventDefault();
315
+ });
316
+ var label = '';
317
+ var configNode = RED.nodes.node(node[property]);
318
+ var node_def = RED.nodes.getType(type);
319
+
320
+ if (configNode) {
321
+ label = RED.utils.getNodeLabel(configNode, configNode.id);
322
+ }
323
+ input.val(label);
324
+ }
325
+
326
+ /**
327
+ * Create a config-node button for this property
328
+ * @param node - the node being edited
329
+ * @param property - the name of the field
330
+ * @param type - the type of the config-node
331
+ */
332
+ function prepareConfigNodeButton(node, property, type, prefix) {
333
+ var input = $('#' + prefix + '-' + property);
334
+ input.val(node[property]);
335
+ input.attr('type', 'hidden');
336
+
337
+ var button = $('<a>', {
338
+ id: prefix + '-edit-' + property,
339
+ class: 'editor-button',
340
+ });
341
+ input.after(button);
342
+
343
+ if (node[property]) {
344
+ button.text('Edit');
345
+ } else {
346
+ button.text('Add');
347
+ }
348
+
349
+ button.click(function (e) {
350
+ showEditConfigNodeDialog(property, type, input.val() || '_ADD_', prefix);
351
+ e.preventDefault();
352
+ });
353
+ }
354
+
355
+ /**
356
+ * Populate the editor dialog input field for this property
357
+ * @param node - the node being edited
358
+ * @param property - the name of the field
359
+ * @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
360
+ * @param definition - the definition of the field
361
+ */
362
+ function preparePropertyEditor(node, property, prefix, definition) {
363
+ var input = $('#' + prefix + '-' + property);
364
+ if (input.length === 0) {
365
+ return;
366
+ }
367
+ if (input.attr('type') === 'checkbox') {
368
+ input.prop('checked', node[property]);
369
+ } else {
370
+ var val = node[property];
371
+ if (val == null) {
372
+ val = '';
373
+ }
374
+ if (
375
+ definition !== undefined &&
376
+ definition[property].hasOwnProperty('format') &&
377
+ definition[property].format !== '' &&
378
+ input[0].nodeName === 'DIV'
379
+ ) {
380
+ input.html(
381
+ RED.text.format.getHtml(
382
+ val,
383
+ definition[property].format,
384
+ {},
385
+ false,
386
+ 'en'
387
+ )
388
+ );
389
+ RED.text.format.attach(
390
+ input[0],
391
+ definition[property].format,
392
+ {},
393
+ false,
394
+ 'en'
395
+ );
396
+ } else {
397
+ input.val(val);
398
+ if (input[0].nodeName === 'INPUT' || input[0].nodeName === 'TEXTAREA') {
399
+ RED.text.bidi.prepareInput(input);
400
+ }
401
+ }
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Add an on-change handler to revalidate a node field
407
+ * @param node - the node being edited
408
+ * @param definition - the definition of the node
409
+ * @param property - the name of the field
410
+ * @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
411
+ */
412
+ function attachPropertyChangeHandler(node, definition, property, prefix) {
413
+ var input = $('#' + prefix + '-' + property);
414
+
415
+ // Make visual mark that field supports template
416
+ if (
417
+ definition[property].hasOwnProperty('templateable') &&
418
+ definition[property].templateable
419
+ ) {
420
+ input.addClass('templateable');
421
+
422
+ // Add the icon of dynamic expression
423
+
424
+ //input
425
+ //.parent()
426
+ // .append(
427
+ // '<span style="display:none;float:right;position:relative;top:-23px;right:5px;color:#9c27b0;font-size:14px" class="fa fa-bolt icon-templatable"></span>'
428
+ // );
429
+
430
+ RED.popover.tooltip(
431
+ input.parent().find($('span.icon-templatable')),
432
+ 'Dynamic Expression Enabled'
433
+ );
434
+
435
+ input.focusin(() => {
436
+ input.parent().find($('span.icon-templatable')).show();
437
+ });
438
+
439
+ input.focusout(() => {
440
+ input.parent().find($('span.icon-templatable')).hide();
441
+ });
442
+
443
+ // $('<span class="fa fa-book"></span>').after(input);
444
+ }
445
+
446
+ if (
447
+ definition !== undefined &&
448
+ 'format' in definition[property] &&
449
+ definition[property].format !== '' &&
450
+ input[0].nodeName === 'DIV'
451
+ ) {
452
+ $('#' + prefix + '-' + property).on('change keyup', function (
453
+ event,
454
+ skipValidation
455
+ ) {
456
+ if (!skipValidation) {
457
+ validateNodeEditor(node, prefix);
458
+ }
459
+ });
460
+ } else {
461
+ $('#' + prefix + '-' + property).change(function (event, skipValidation) {
462
+ if (!skipValidation) {
463
+ validateNodeEditor(node, prefix);
464
+ }
465
+ });
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Assign the value to each credential field
471
+ * @param node
472
+ * @param credDef
473
+ * @param credData
474
+ * @param prefix
475
+ */
476
+ function populateCredentialsInputs(node, credDef, credData, prefix) {
477
+ var cred;
478
+ for (cred in credDef) {
479
+ if (credDef.hasOwnProperty(cred)) {
480
+ if (credDef[cred].type == 'password') {
481
+ if (credData[cred]) {
482
+ $('#' + prefix + '-' + cred).val(credData[cred]);
483
+ } else if (credData['has_' + cred]) {
484
+ $('#' + prefix + '-' + cred).val('__PWRD__');
485
+ } else {
486
+ $('#' + prefix + '-' + cred).val('');
487
+ }
488
+ } else {
489
+ preparePropertyEditor(credData, cred, prefix, credDef);
490
+ }
491
+ attachPropertyChangeHandler(node, credDef, cred, prefix);
492
+ }
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Update the node credentials from the edit form
498
+ * @param node - the node containing the credentials
499
+ * @param credDefinition - definition of the credentials
500
+ * @param prefix - prefix of the input fields
501
+ * @return {boolean} whether anything has changed
502
+ */
503
+ function updateNodeCredentials(node, credDefinition, prefix) {
504
+ var changed = false;
505
+ if (!node.credentials) {
506
+ node.credentials = { _: {} };
507
+ }
508
+
509
+ for (var cred in credDefinition) {
510
+ if (credDefinition.hasOwnProperty(cred)) {
511
+ var input = $('#' + prefix + '-' + cred);
512
+ var value = input.val();
513
+ if (credDefinition[cred].type == 'password') {
514
+ node.credentials['has_' + cred] = value !== '';
515
+ if (value == '__PWRD__') {
516
+ continue;
517
+ }
518
+ changed = true;
519
+ }
520
+ node.credentials[cred] = value;
521
+ if (value != node.credentials._[cred]) {
522
+ changed = true;
523
+ }
524
+ }
525
+ }
526
+ return changed;
527
+ }
528
+
529
+ /**
530
+ * Prepare all of the editor dialog fields
531
+ * @param node - the node being edited
532
+ * @param definition - the node definition
533
+ * @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
534
+ */
535
+ function prepareEditDialog(node, definition, prefix, done) {
536
+ for (var d in definition.defaults) {
537
+ if (definition.defaults.hasOwnProperty(d)) {
538
+ if (definition.defaults[d].type) {
539
+ var configTypeDef = RED.nodes.getType(definition.defaults[d].type);
540
+ if (configTypeDef) {
541
+ if (configTypeDef.exclusive) {
542
+ prepareConfigNodeButton(
543
+ node,
544
+ d,
545
+ definition.defaults[d].type,
546
+ prefix
547
+ );
548
+ } else {
549
+ prepareConfigNodeSelect(
550
+ node,
551
+ d,
552
+ definition.defaults[d].type,
553
+ prefix
554
+ );
555
+ }
556
+ } else {
557
+ console.log('Unknown type:', definition.defaults[d].type);
558
+ preparePropertyEditor(node, d, prefix, definition.defaults);
559
+ }
560
+ } else {
561
+ preparePropertyEditor(node, d, prefix, definition.defaults);
562
+ }
563
+ attachPropertyChangeHandler(node, definition.defaults, d, prefix);
564
+ }
565
+ }
566
+ var completePrepare = function () {
567
+ if (definition.oneditprepare) {
568
+ try {
569
+ definition.oneditprepare.call(node);
570
+ } catch (err) {
571
+ console.log('oneditprepare', node.id, node.type, err.toString());
572
+ }
573
+ }
574
+ // Now invoke any change handlers added to the fields - passing true
575
+ // to prevent full node validation from being triggered each time
576
+ for (var d in definition.defaults) {
577
+ if (definition.defaults.hasOwnProperty(d)) {
578
+ $('#' + prefix + '-' + d).trigger('change', [true]);
579
+ }
580
+ }
581
+ if (definition.credentials) {
582
+ for (d in definition.credentials) {
583
+ if (definition.credentials.hasOwnProperty(d)) {
584
+ $('#' + prefix + '-' + d).trigger('change', [true]);
585
+ }
586
+ }
587
+ }
588
+ validateNodeEditor(node, prefix);
589
+ if (done) {
590
+ done();
591
+ }
592
+ };
593
+
594
+ if (definition.credentials) {
595
+ if (node.credentials) {
596
+ populateCredentialsInputs(
597
+ node,
598
+ definition.credentials,
599
+ node.credentials,
600
+ prefix
601
+ );
602
+ completePrepare();
603
+ } else {
604
+ $.getJSON(getCredentialsURL(node.type, node.id), function (data) {
605
+ node.credentials = data;
606
+ node.credentials._ = $.extend(true, {}, data);
607
+ populateCredentialsInputs(
608
+ node,
609
+ definition.credentials,
610
+ node.credentials,
611
+ prefix
612
+ );
613
+ completePrepare();
614
+ });
615
+ }
616
+ } else {
617
+ completePrepare();
618
+ }
619
+ }
620
+
621
+ function getNodeIconPath() {
622
+ var nodeIconPath;
623
+ for (var i = editStack.length - 1; i < editStack.length; i++) {
624
+ var node = editStack[i];
625
+ var iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
626
+ defaultIcon = iconPath.module + '/' + iconPath.file;
627
+ if (iconPath.module === 'kumologica-core') {
628
+ nodeIconPath = `icons/${iconPath.module}/${iconPath.file}`;
629
+ }
630
+ }
631
+ return nodeIconPath;
632
+ }
633
+
634
+ function getEditStackTitle() {
635
+ var label;
636
+ for (var i = editStack.length - 1; i < editStack.length; i++) {
637
+ var node = editStack[i];
638
+ label = node.type;
639
+ // Commented out as not sure why so much control over here.
640
+ // anyway, we only need to use the node title as label for the properties window
641
+
642
+ // if (node.type === '_expression') {
643
+ // label = RED._('expressionEditor.title');
644
+ // } else if (node.type === '_js') {
645
+ // label = RED._('jsEditor.title');
646
+ // } else if (node.type === '_json') {
647
+ // label = RED._('jsonEditor.title');
648
+ // } else if (node.type === '_markdown') {
649
+ // label = RED._('markdownEditor.title');
650
+ // } else if (node.type === '_buffer') {
651
+ // label = RED._('bufferEditor.title');
652
+ // } else if (node.type === 'subflow') {
653
+ // label = RED._('subflow.editSubflow', {
654
+ // name: RED.utils.sanitize(node.name)
655
+ // });
656
+ // } else if (node.type.indexOf('subflow:') === 0) {
657
+ // var subflow = RED.nodes.subflow(node.type.substring(8));
658
+ // label = RED._('subflow.editSubflowInstance', {
659
+ // name: RED.utils.sanitize(subflow.name)
660
+ // });
661
+ // } else if (node._def !== undefined) {
662
+ // if (typeof node._def.paletteLabel !== 'undefined') {
663
+ // try {
664
+ // label = RED.utils.sanitize(
665
+ // (typeof node._def.paletteLabel === 'function'
666
+ // ? node._def.paletteLabel.call(node._def)
667
+ // : node._def.paletteLabel) || ''
668
+ // );
669
+ // } catch (err) {
670
+ // console.log(
671
+ // 'Definition error: ' + node.type + '.paletteLabel',
672
+ // err
673
+ // );
674
+ // }
675
+ // }
676
+ // if (i === editStack.length - 1) {
677
+ // if (RED.nodes.node(node.id)) {
678
+ // label = RED._('editor.editNode', {
679
+ // type: RED.utils.sanitize(label)
680
+ // });
681
+ // } else {
682
+ // label = RED._('editor.addNewConfig', {
683
+ // type: RED.utils.sanitize(label)
684
+ // });
685
+ // }
686
+ // }
687
+ // }
688
+ }
689
+ //console.log('editor.js - getEditStackTitle is label AFTER=', label);
690
+ return label;
691
+ }
692
+
693
+ function buildEnvForm(container, node) {
694
+ var env_container = $('#node-input-env-container');
695
+ env_container
696
+ .css({
697
+ 'min-height': '150px',
698
+ 'min-width': '450px',
699
+ })
700
+ .editableList({
701
+ addItem: function (container, i, opt) {
702
+ var row = $('<div/>').appendTo(container);
703
+ if (opt.parent) {
704
+ $('<div/>', {
705
+ class: 'uneditable-input',
706
+ style: 'margin-left: 5px; width: calc(40% - 8px)',
707
+ })
708
+ .appendTo(row)
709
+ .text(opt.name);
710
+ } else {
711
+ $('<input/>', {
712
+ class: 'node-input-env-name',
713
+ type: 'text',
714
+ style: 'margin-left: 5px; width: calc(40% - 8px)',
715
+ placeholder: 'Name',
716
+ })
717
+ .appendTo(row)
718
+ .val(opt.name);
719
+ }
720
+ var valueField = $('<input/>', {
721
+ class: 'node-input-env-value',
722
+ type: 'text',
723
+ style: 'margin-left: 5px; width: calc(60% - 8px)',
724
+ }).appendTo(row);
725
+
726
+ valueField.typedInput({
727
+ default: 'str',
728
+ types: ['str', 'num', 'bool', 'json', 'bin', 'env'],
729
+ });
730
+
731
+ valueField.typedInput(
732
+ 'type',
733
+ opt.parent ? opt.type || opt.parent.type : opt.type
734
+ );
735
+ valueField.typedInput(
736
+ 'value',
737
+ opt.parent
738
+ ? opt.value !== undefined
739
+ ? opt.value
740
+ : opt.parent.value
741
+ : opt.value
742
+ );
743
+
744
+ var actionButton = $('<a/>', {
745
+ href: '#',
746
+ class:
747
+ 'red-ui-editableList-item-remove editor-button editor-button-small',
748
+ }).appendTo(container);
749
+ $('<i/>', {
750
+ class: 'fa ' + (opt.parent ? 'fa-reply' : 'fa-remove'),
751
+ }).appendTo(actionButton);
752
+ container.parent().addClass('red-ui-editableList-item-removable');
753
+ if (opt.parent) {
754
+ if (
755
+ opt.value !== undefined &&
756
+ (opt.value !== opt.parent.value || opt.type !== opt.parent.type)
757
+ ) {
758
+ actionButton.show();
759
+ } else {
760
+ actionButton.hide();
761
+ }
762
+ var restoreTip = RED.popover.tooltip(
763
+ actionButton, 'Restore to subflow default');
764
+
765
+ valueField.change(function (evt) {
766
+ var newType = valueField.typedInput('type');
767
+ var newValue = valueField.typedInput('value');
768
+ if (
769
+ newType === opt.parent.type &&
770
+ newValue === opt.parent.value
771
+ ) {
772
+ actionButton.hide();
773
+ } else {
774
+ actionButton.show();
775
+ }
776
+ });
777
+ actionButton.click(function (evt) {
778
+ evt.preventDefault();
779
+ restoreTip.close();
780
+ valueField.typedInput('type', opt.parent.type);
781
+ valueField.typedInput('value', opt.parent.value);
782
+ });
783
+ } else {
784
+ var removeTip = RED.popover.tooltip(
785
+ actionButton,
786
+ "Remove environment variable"
787
+ );
788
+ actionButton.click(function (evt) {
789
+ evt.preventDefault();
790
+ removeTip.close();
791
+ container.parent().addClass('red-ui-editableList-item-deleting');
792
+ container.fadeOut(300, function () {
793
+ env_container.editableList('removeItem', opt);
794
+ });
795
+ });
796
+ }
797
+ },
798
+ sortable: false,
799
+ removable: false,
800
+ });
801
+ var parentEnv = {};
802
+ var envList = [];
803
+ if (/^subflow:/.test(node.type)) {
804
+ var subflowDef = RED.nodes.subflow(node.type.substring(8));
805
+ if (subflowDef.env) {
806
+ subflowDef.env.forEach(function (env) {
807
+ var item = {
808
+ name: env.name,
809
+ parent: {
810
+ type: env.type,
811
+ value: env.value,
812
+ },
813
+ };
814
+ envList.push(item);
815
+ parentEnv[env.name] = item;
816
+ });
817
+ }
818
+ }
819
+
820
+ if (node.env) {
821
+ for (var i = 0; i < node.env.length; i++) {
822
+ var env = node.env[i];
823
+ if (parentEnv.hasOwnProperty(env.name)) {
824
+ parentEnv[env.name].type = env.type;
825
+ parentEnv[env.name].value = env.value;
826
+ } else {
827
+ envList.push({
828
+ name: env.name,
829
+ type: env.type,
830
+ value: env.value,
831
+ });
832
+ }
833
+ }
834
+ }
835
+ envList.forEach(function (env) {
836
+ env_container.editableList('addItem', env);
837
+ });
838
+ }
839
+
840
+ function exportEnvList(list) {
841
+ if (list) {
842
+ var env = [];
843
+ list.each(function (i) {
844
+ var entry = $(this);
845
+ var item = entry.data('data');
846
+ var name = (item.parent
847
+ ? item.name
848
+ : entry.find('.node-input-env-name').val()
849
+ ).trim();
850
+ if (name !== '') {
851
+ var valueInput = entry.find('.node-input-env-value');
852
+ var value = valueInput.typedInput('value');
853
+ var type = valueInput.typedInput('type');
854
+ if (
855
+ !item.parent ||
856
+ item.parent.value !== value ||
857
+ item.parent.type !== type
858
+ ) {
859
+ var item = {
860
+ name: name,
861
+ type: type,
862
+ value: value,
863
+ };
864
+ env.push(item);
865
+ }
866
+ }
867
+ });
868
+ return env;
869
+ }
870
+ return null;
871
+ }
872
+
873
+ function isSameEnv(env0, env1) {
874
+ return JSON.stringify(env0) === JSON.stringify(env1);
875
+ }
876
+
877
+ function buildEditForm(container, formId, type, ns, node) {
878
+ var dialogForm = $(
879
+ '<form id="' +
880
+ formId +
881
+ '" class="form-horizontal" autocomplete="off"></form>'
882
+ ).appendTo(container);
883
+ dialogForm.html($("script[data-template-name='" + type + "']").html());
884
+ ns = ns || 'kumologica-core';
885
+ dialogForm.find('[data-i18n]').each(function () {
886
+ var current = $(this).attr('data-i18n');
887
+ var keys = current.split(';');
888
+ for (var i = 0; i < keys.length; i++) {
889
+ var key = keys[i];
890
+ if (key.indexOf(':') === -1) {
891
+ var prefix = '';
892
+ if (key.indexOf('[') === 0) {
893
+ var parts = key.split(']');
894
+ prefix = parts[0] + ']';
895
+ key = parts[1];
896
+ }
897
+ keys[i] = prefix + ns + ':' + key;
898
+ }
899
+ }
900
+ $(this).attr('data-i18n', keys.join(';'));
901
+ });
902
+
903
+ if (type === 'subflow' || type === 'subflow-template') {
904
+ buildEnvForm(dialogForm, node);
905
+ }
906
+
907
+ // Add dummy fields to prevent 'Enter' submitting the form in some
908
+ // cases, and also prevent browser auto-fill of password
909
+ // Add in reverse order as they are prepended...
910
+ $('<input type="password" style="display: none;" />').prependTo(dialogForm);
911
+ $('<input type="text" style="display: none;" />').prependTo(dialogForm);
912
+ dialogForm.submit(function (e) {
913
+ e.preventDefault();
914
+ });
915
+ return dialogForm;
916
+ }
917
+
918
+ function refreshLabelForm(container, node) {
919
+ var inputPlaceholder = node._def.inputLabels
920
+ ? 'use default label'
921
+ : 'none';
922
+ var outputPlaceholder = node._def.outputLabels
923
+ ? 'use default label'
924
+ : 'none';
925
+
926
+ var inputsDiv = $('#node-label-form-inputs');
927
+ var outputsDiv = $('#node-label-form-outputs');
928
+
929
+ var inputCount;
930
+ if (node.type === 'subflow') {
931
+ inputCount = node.in.length;
932
+ } else {
933
+ inputCount = node.inputs || node._def.inputs || 0;
934
+ }
935
+
936
+ var children = inputsDiv.children();
937
+ var childCount = children.length;
938
+ if (childCount === 1 && $(children[0]).hasClass('node-label-form-none')) {
939
+ childCount--;
940
+ }
941
+
942
+ if (childCount < inputCount) {
943
+ if (childCount === 0) {
944
+ // remove the 'none' placeholder
945
+ $(children[0]).remove();
946
+ }
947
+ for (i = childCount; i < inputCount; i++) {
948
+ buildLabelRow('input', i, '', inputPlaceholder).appendTo(inputsDiv);
949
+ }
950
+ } else if (childCount > inputCount) {
951
+ for (i = inputCount; i < childCount; i++) {
952
+ $(children[i]).remove();
953
+ }
954
+ if (inputCount === 0) {
955
+ buildLabelRow().appendTo(inputsDiv);
956
+ }
957
+ }
958
+
959
+ var outputCount;
960
+ var i;
961
+ var formOutputs = $('#node-input-outputs').val();
962
+
963
+ if (formOutputs === undefined) {
964
+ if (node.type === 'subflow') {
965
+ outputCount = node.out.length;
966
+ } else {
967
+ inputCount = node.outputs || node._def.outputs || 0;
968
+ }
969
+ } else if (isNaN(formOutputs)) {
970
+ var outputMap = JSON.parse(formOutputs);
971
+ var keys = Object.keys(outputMap);
972
+ children = outputsDiv.children();
973
+ childCount = children.length;
974
+ if (childCount === 1 && $(children[0]).hasClass('node-label-form-none')) {
975
+ childCount--;
976
+ }
977
+
978
+ outputCount = 0;
979
+ var rows = [];
980
+ keys.forEach(function (p) {
981
+ var row = $('#node-label-form-output-' + p).parent();
982
+ if (row.length === 0 && outputMap[p] !== -1) {
983
+ if (childCount === 0) {
984
+ $(children[0]).remove();
985
+ childCount = -1;
986
+ }
987
+ row = buildLabelRow('output', p, '', outputPlaceholder);
988
+ } else {
989
+ row.detach();
990
+ }
991
+ if (outputMap[p] !== -1) {
992
+ outputCount++;
993
+ rows.push({ i: parseInt(outputMap[p]), r: row });
994
+ }
995
+ });
996
+ rows.sort(function (A, B) {
997
+ return A.i - B.i;
998
+ });
999
+ rows.forEach(function (r, i) {
1000
+ r.r.find('label').text(i + 1 + '.');
1001
+ r.r.appendTo(outputsDiv);
1002
+ });
1003
+ if (rows.length === 0) {
1004
+ buildLabelRow('output', i, '').appendTo(outputsDiv);
1005
+ } else {
1006
+ }
1007
+ } else {
1008
+ outputCount = Math.max(0, parseInt(formOutputs));
1009
+ }
1010
+ children = outputsDiv.children();
1011
+ childCount = children.length;
1012
+ if (childCount === 1 && $(children[0]).hasClass('node-label-form-none')) {
1013
+ childCount--;
1014
+ }
1015
+ if (childCount < outputCount) {
1016
+ if (childCount === 0) {
1017
+ // remove the 'none' placeholder
1018
+ $(children[0]).remove();
1019
+ }
1020
+ for (i = childCount; i < outputCount; i++) {
1021
+ buildLabelRow('output', i, '').appendTo(outputsDiv);
1022
+ }
1023
+ } else if (childCount > outputCount) {
1024
+ for (i = outputCount; i < childCount; i++) {
1025
+ $(children[i]).remove();
1026
+ }
1027
+ if (outputCount === 0) {
1028
+ buildLabelRow().appendTo(outputsDiv);
1029
+ }
1030
+ }
1031
+ }
1032
+ function buildLabelRow(type, index, value, placeHolder) {
1033
+ var result = $('<div>', { class: 'node-label-form-row' });
1034
+ if (type === undefined) {
1035
+ $('<span>').text('none').appendTo(result);
1036
+ result.addClass('node-label-form-none');
1037
+ } else {
1038
+ result.addClass('');
1039
+ var id = 'node-label-form-' + type + '-' + index;
1040
+ $('<label>', { for: id })
1041
+ .text(index + 1 + '.')
1042
+ .appendTo(result);
1043
+ var input = $('<input>', {
1044
+ type: 'text',
1045
+ id: id,
1046
+ placeholder: placeHolder,
1047
+ })
1048
+ .val(value)
1049
+ .appendTo(result);
1050
+ var clear = $(
1051
+ '<button type="button" class="editor-button editor-button-small"><i class="fa fa-times"></i></button>'
1052
+ ).appendTo(result);
1053
+ clear.click(function (evt) {
1054
+ evt.preventDefault();
1055
+ input.val('');
1056
+ });
1057
+ }
1058
+ return result;
1059
+ }
1060
+ function showIconPicker(container, node, iconPath, done) {
1061
+ var containerPos = container.offset();
1062
+ var pickerBackground = $('<div>')
1063
+ .css({
1064
+ position: 'absolute',
1065
+ top: 0,
1066
+ bottom: 0,
1067
+ left: 0,
1068
+ right: 0,
1069
+ zIndex: 20,
1070
+ })
1071
+ .appendTo('body');
1072
+
1073
+ var top = containerPos.top - 30;
1074
+
1075
+ if (top + 280 > $(window).height()) {
1076
+ top = $(window).height() - 280;
1077
+ }
1078
+ var picker = $('<div class="red-ui-icon-picker">')
1079
+ .css({
1080
+ top: top + 'px',
1081
+ left: containerPos.left + 'px',
1082
+ })
1083
+ .appendTo('body');
1084
+
1085
+ var hide = function () {
1086
+ pickerBackground.remove();
1087
+ picker.remove();
1088
+ RED.keyboard.remove('escape');
1089
+ };
1090
+ RED.keyboard.add('*', 'escape', function () {
1091
+ hide();
1092
+ });
1093
+ pickerBackground.on('mousedown', hide);
1094
+
1095
+ var searchDiv = $('<div>', { class: 'red-ui-search-container' }).appendTo(
1096
+ picker
1097
+ );
1098
+ searchInput = $('<input type="text">')
1099
+ .attr('placeholder', 'Search icons')
1100
+ .appendTo(searchDiv)
1101
+ .searchBox({
1102
+ delay: 50,
1103
+ change: function () {
1104
+ var searchTerm = $(this).val().trim();
1105
+ if (searchTerm === '') {
1106
+ iconList.find('.red-ui-icon-list-module').show();
1107
+ iconList.find('.red-ui-icon-list-icon').show();
1108
+ } else {
1109
+ iconList.find('.red-ui-icon-list-module').hide();
1110
+ iconList.find('.red-ui-icon-list-icon').each(function (i, n) {
1111
+ if ($(n).data('icon').indexOf(searchTerm) === -1) {
1112
+ $(n).hide();
1113
+ } else {
1114
+ $(n).show();
1115
+ }
1116
+ });
1117
+ }
1118
+ },
1119
+ });
1120
+
1121
+ var row = $('<div>').appendTo(picker);
1122
+ var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
1123
+ var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
1124
+ var summary = $('<span>').appendTo(metaRow);
1125
+ var resetButton = $(
1126
+ '<button type="button" class="editor-button editor-button-small">' +
1127
+ 'use default' +
1128
+ '</button>'
1129
+ )
1130
+ .appendTo(metaRow)
1131
+ .click(function (e) {
1132
+ e.preventDefault();
1133
+ hide();
1134
+ done(null);
1135
+ });
1136
+ var iconSets = RED.nodes.getIconSets();
1137
+ Object.keys(iconSets).forEach(function (moduleName) {
1138
+ var icons = iconSets[moduleName];
1139
+ if (icons.length > 0) {
1140
+ // selectIconModule.append($("<option></option>").val(moduleName).text(moduleName));
1141
+ var header = $('<div class="red-ui-icon-list-module"></div>')
1142
+ .text(moduleName)
1143
+ .appendTo(iconList);
1144
+ $('<i class="fa fa-cube"></i>').prependTo(header);
1145
+ icons.forEach(function (icon) {
1146
+ var iconDiv = $('<div>', { class: 'red-ui-icon-list-icon' }).appendTo(
1147
+ iconList
1148
+ );
1149
+ var nodeDiv = $('<div>', {
1150
+ class: 'red-ui-search-result-node',
1151
+ }).appendTo(iconDiv);
1152
+ var colour = RED.utils.getNodeColor(node.type, node._def);
1153
+ var icon_url =
1154
+ RED.settings.apiRootUrl + 'icons/' + moduleName + '/' + icon;
1155
+ iconDiv.data('icon', icon_url);
1156
+ nodeDiv.css('backgroundColor', colour);
1157
+ var iconContainer = $('<div/>', {
1158
+ class: 'palette_icon_container',
1159
+ }).appendTo(nodeDiv);
1160
+ RED.utils.createIconElement(icon_url, iconContainer, true);
1161
+
1162
+ if (iconPath.module === moduleName && iconPath.file === icon) {
1163
+ iconDiv.addClass('selected');
1164
+ }
1165
+ iconDiv.on('mouseover', function () {
1166
+ summary.text(icon);
1167
+ });
1168
+ iconDiv.on('mouseout', function () {
1169
+ summary.html('&nbsp;');
1170
+ });
1171
+ iconDiv.click(function () {
1172
+ hide();
1173
+ done(moduleName + '/' + icon);
1174
+ });
1175
+ });
1176
+ }
1177
+ });
1178
+ picker.slideDown(100);
1179
+ searchInput.focus();
1180
+ }
1181
+
1182
+ function buildAppearanceForm(container, node) {
1183
+ var dialogForm = $(
1184
+ '<form class="dialog-form form-horizontal" autocomplete="off"></form>'
1185
+ ).appendTo(container);
1186
+
1187
+ var i, row;
1188
+
1189
+ $(
1190
+ '<div class="form-row">' +
1191
+ '<label for="node-input-show-label-btn" data-i18n="editor.label"></label>' +
1192
+ '<button type="button" id="node-input-show-label-btn" class="editor-button" style="min-width: 80px; text-align: left;" type="button"><i id="node-input-show-label-btn-i" class="fa fa-toggle-on"></i> <span id="node-input-show-label-label"></span></button> ' +
1193
+ '<input type="checkbox" id="node-input-show-label" style="display: none;"/>' +
1194
+ '</div>'
1195
+ ).appendTo(dialogForm);
1196
+
1197
+ var setToggleState = function (state) {
1198
+ var i = $('#node-input-show-label-btn-i');
1199
+ if (!state) {
1200
+ i.addClass('fa-toggle-off');
1201
+ i.removeClass('fa-toggle-on');
1202
+ $('#node-input-show-label').prop('checked', false);
1203
+ $('#node-input-show-label-label').text('Hide');
1204
+ } else {
1205
+ i.addClass('fa-toggle-on');
1206
+ i.removeClass('fa-toggle-off');
1207
+ $('#node-input-show-label').prop('checked', true);
1208
+ $('#node-input-show-label-label').text('Show');
1209
+ }
1210
+ };
1211
+ dialogForm.find('#node-input-show-label-btn').on('click', function (e) {
1212
+ e.preventDefault();
1213
+ var i = $('#node-input-show-label-btn-i');
1214
+ setToggleState(i.hasClass('fa-toggle-off'));
1215
+ });
1216
+
1217
+ // if (!node.hasOwnProperty('l')) {
1218
+ // // Show label if type not link
1219
+ // node.l = !/^link (in|out)$/.test(node._def.type);
1220
+ // }
1221
+ // setToggleState(node.l);
1222
+
1223
+ // If a node has icon property in defaults, the icon of the node cannot be modified. (e.g, ui_button node in dashboard)
1224
+ if (!node._def.defaults || !node._def.defaults.hasOwnProperty('icon')) {
1225
+ var iconRow = $('<div class="form-row"></div>').appendTo(dialogForm);
1226
+ $('<label data-i18n="editor.settingIcon">').appendTo(iconRow);
1227
+
1228
+ var iconButton = $(
1229
+ '<button type="button" class="editor-button" id="node-settings-icon-button">'
1230
+ ).appendTo(iconRow);
1231
+
1232
+ var nodeDiv = $('<div>', { class: 'red-ui-search-result-node' }).appendTo(
1233
+ iconButton
1234
+ );
1235
+ var colour = RED.utils.getNodeColor(node.type, node._def);
1236
+ var icon_url = RED.utils.getNodeIcon(node._def, node);
1237
+ nodeDiv.css('backgroundColor', colour);
1238
+ var iconContainer = $('<div/>', {
1239
+ class: 'palette_icon_container',
1240
+ }).appendTo(nodeDiv);
1241
+ RED.utils.createIconElement(icon_url, iconContainer, true);
1242
+
1243
+ iconButton.click(function (e) {
1244
+ e.preventDefault();
1245
+ var iconPath;
1246
+ var icon = $('#node-settings-icon').text() || '';
1247
+ if (icon) {
1248
+ iconPath = RED.utils.separateIconPath(icon);
1249
+ } else {
1250
+ iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
1251
+ }
1252
+ showIconPicker(iconRow, node, iconPath, function (newIcon) {
1253
+ $('#node-settings-icon').text(newIcon || '');
1254
+ var icon_url = RED.utils.getNodeIcon(node._def, {
1255
+ type: node.type,
1256
+ icon: newIcon,
1257
+ });
1258
+ RED.utils.createIconElement(icon_url, iconContainer, true);
1259
+ });
1260
+ });
1261
+ $('<div id="node-settings-icon">').text(node.icon).appendTo(iconButton);
1262
+ }
1263
+
1264
+ $(
1265
+ '<div class="form-row"><span data-i18n="editor.portLabels"></span></div>'
1266
+ ).appendTo(dialogForm);
1267
+
1268
+ var inputCount = node.inputs || node._def.inputs || 0;
1269
+ var outputCount = node.outputs || node._def.outputs || 0;
1270
+ if (node.type === 'subflow') {
1271
+ inputCount = node.in.length;
1272
+ outputCount = node.out.length;
1273
+ }
1274
+
1275
+ var inputLabels = node.inputLabels || [];
1276
+ var outputLabels = node.outputLabels || [];
1277
+
1278
+ var inputPlaceholder = node._def.inputLabels
1279
+ ? 'use default label'
1280
+ : 'none';
1281
+ var outputPlaceholder = node._def.outputLabels
1282
+ ? 'use default label'
1283
+ : 'none';
1284
+
1285
+ $(
1286
+ '<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelInputs"></span><div id="node-label-form-inputs"></div></div>'
1287
+ ).appendTo(dialogForm);
1288
+ var inputsDiv = $('#node-label-form-inputs');
1289
+ if (inputCount > 0) {
1290
+ for (i = 0; i < inputCount; i++) {
1291
+ buildLabelRow('input', i, inputLabels[i], inputPlaceholder).appendTo(
1292
+ inputsDiv
1293
+ );
1294
+ }
1295
+ } else {
1296
+ buildLabelRow().appendTo(inputsDiv);
1297
+ }
1298
+ $(
1299
+ '<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelOutputs"></span><div id="node-label-form-outputs"></div></div>'
1300
+ ).appendTo(dialogForm);
1301
+ var outputsDiv = $('#node-label-form-outputs');
1302
+ if (outputCount > 0) {
1303
+ for (i = 0; i < outputCount; i++) {
1304
+ buildLabelRow('output', i, outputLabels[i], outputPlaceholder).appendTo(
1305
+ outputsDiv
1306
+ );
1307
+ }
1308
+ } else {
1309
+ buildLabelRow().appendTo(outputsDiv);
1310
+ }
1311
+ }
1312
+
1313
+ function updateLabels(editing_node, changes, outputMap) {
1314
+ var inputLabels = $('#node-label-form-inputs').children().find('input');
1315
+ var outputLabels = $('#node-label-form-outputs').children().find('input');
1316
+
1317
+ var hasNonBlankLabel = false;
1318
+ var changed = false;
1319
+ var newValue = inputLabels
1320
+ .map(function () {
1321
+ var v = $(this).val();
1322
+ hasNonBlankLabel = hasNonBlankLabel || v !== '';
1323
+ return v;
1324
+ })
1325
+ .toArray()
1326
+ .slice(0, editing_node.inputs);
1327
+ if (
1328
+ (editing_node.inputLabels === undefined && hasNonBlankLabel) ||
1329
+ (editing_node.inputLabels !== undefined &&
1330
+ JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels))
1331
+ ) {
1332
+ changes.inputLabels = editing_node.inputLabels;
1333
+ editing_node.inputLabels = newValue;
1334
+ changed = true;
1335
+ }
1336
+ hasNonBlankLabel = false;
1337
+ newValue = new Array(editing_node.outputs);
1338
+ outputLabels.each(function () {
1339
+ var index = $(this).attr('id').substring(23); // node-label-form-output-<index>
1340
+ if (outputMap && outputMap.hasOwnProperty(index)) {
1341
+ index = parseInt(outputMap[index]);
1342
+ if (index === -1) {
1343
+ return;
1344
+ }
1345
+ }
1346
+ var v = $(this).val();
1347
+ hasNonBlankLabel = hasNonBlankLabel || v !== '';
1348
+ newValue[index] = v;
1349
+ });
1350
+
1351
+ if (
1352
+ (editing_node.outputLabels === undefined && hasNonBlankLabel) ||
1353
+ (editing_node.outputLabels !== undefined &&
1354
+ JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels))
1355
+ ) {
1356
+ changes.outputLabels = editing_node.outputLabels;
1357
+ editing_node.outputLabels = newValue;
1358
+ changed = true;
1359
+ }
1360
+ return changed;
1361
+ }
1362
+
1363
+ function buildDescriptionForm(container, node) {
1364
+ var dialogForm = $(
1365
+ '<form class="dialog-form form-horizontal" style="padding: 5px 10px;" autocomplete="off"></form>'
1366
+ ).appendTo(container);
1367
+ var toolbarRow = $('<div></div>').appendTo(dialogForm);
1368
+ var row = $(
1369
+ `<div class="form-row node-text-editor-row" style="position:relative; padding-top: 4px; height: 100%"></div>
1370
+ <div class="form-row node-text-editor-preview" style="display: none; padding: 0px 20px;"></div>
1371
+ `
1372
+ ).appendTo(dialogForm);
1373
+ $(
1374
+ '<div style="height: 100%" class="node-text-editor" id="node-info-input-info-editor" ></div>'
1375
+ ).appendTo(row);
1376
+
1377
+ // console.log('[editor] Creating notes editor...')
1378
+ nodeInfoEditor = RED.editor.createEditor({
1379
+ id: 'node-info-input-info-editor',
1380
+ mode: 'ace/mode/markdown',
1381
+ value: node.info || '',
1382
+ lineNumbers: false,
1383
+ toolbar: false,
1384
+ onChange: function(delta) {
1385
+ // console.log('[editor] InfoTab changed. Delta=', delta);
1386
+ notifyChanges(getLatestNodeSelected());
1387
+ }
1388
+ });
1389
+
1390
+ return nodeInfoEditor;
1391
+ }
1392
+
1393
+ function resetEditor(){
1394
+ // console.log('[editor] reset the editor')
1395
+ editStack.pop();
1396
+ RED.sidebar.nodeinfo.emptyTab();
1397
+ RED.actions.invoke('core:hide-sidebar');
1398
+ }
1399
+
1400
+ function forceNotifyChanges() {
1401
+ notifyChanges(getLatestNodeSelected());
1402
+ }
1403
+
1404
+ function notifyChanges(nodeSelected){
1405
+ console.log('[editor] notifyChanges with nodeSelected: ', nodeSelected);
1406
+ let editing_node = nodeSelected;
1407
+ let node = nodeSelected;
1408
+
1409
+ var changes = {};
1410
+ var changed = false;
1411
+ var wasDirty = RED.nodes.dirty();
1412
+ var d;
1413
+ var outputMap;
1414
+
1415
+ if (editing_node._def.oneditsave) {
1416
+ var oldValues = {};
1417
+ for (d in editing_node._def.defaults) {
1418
+ if (editing_node._def.defaults.hasOwnProperty(d)) {
1419
+ if (
1420
+ typeof editing_node[d] === 'string' ||
1421
+ typeof editing_node[d] === 'number'
1422
+ ) {
1423
+ oldValues[d] = editing_node[d];
1424
+ } else {
1425
+ oldValues[d] = $.extend(true, {}, { v: editing_node[d] }).v;
1426
+ }
1427
+ }
1428
+ }
1429
+ try {
1430
+ var rc = editing_node._def.oneditsave.call(editing_node);
1431
+ if (rc === true) {
1432
+ changed = true;
1433
+ }
1434
+ } catch (err) {
1435
+ console.log(
1436
+ 'oneditsave',
1437
+ editing_node.id,
1438
+ editing_node.type,
1439
+ err.toString()
1440
+ );
1441
+ }
1442
+
1443
+ for (d in editing_node._def.defaults) {
1444
+ if (editing_node._def.defaults.hasOwnProperty(d)) {
1445
+ if (
1446
+ oldValues[d] === null ||
1447
+ typeof oldValues[d] === 'string' ||
1448
+ typeof oldValues[d] === 'number'
1449
+ ) {
1450
+ if (oldValues[d] !== editing_node[d]) {
1451
+ changes[d] = oldValues[d];
1452
+ changed = true;
1453
+ }
1454
+ } else {
1455
+ if (
1456
+ JSON.stringify(oldValues[d]) !==
1457
+ JSON.stringify(editing_node[d])
1458
+ ) {
1459
+ changes[d] = oldValues[d];
1460
+ changed = true;
1461
+ }
1462
+ }
1463
+ }
1464
+ }
1465
+ }
1466
+
1467
+ var newValue;
1468
+ if (editing_node._def.defaults) {
1469
+ for (d in editing_node._def.defaults) {
1470
+ if (editing_node._def.defaults.hasOwnProperty(d)) {
1471
+ var input = $('#node-input-' + d);
1472
+ if (input.attr('type') === 'checkbox') {
1473
+ newValue = input.prop('checked');
1474
+ } else if (
1475
+ input.prop('nodeName') === 'select' &&
1476
+ input.attr('multiple') === 'multiple'
1477
+ ) {
1478
+ // An empty select-multiple box returns null.
1479
+ // Need to treat that as an empty array.
1480
+ newValue = input.val();
1481
+ if (newValue == null) {
1482
+ newValue = [];
1483
+ }
1484
+ } else if (
1485
+ 'format' in editing_node._def.defaults[d] &&
1486
+ editing_node._def.defaults[d].format !== '' &&
1487
+ input[0].nodeName === 'DIV'
1488
+ ) {
1489
+ newValue = input.text();
1490
+ } else {
1491
+ newValue = input.val();
1492
+ }
1493
+ if (newValue != null) {
1494
+ if (d === 'outputs') {
1495
+ if (newValue.trim() === '') {
1496
+ continue;
1497
+ }
1498
+ if (isNaN(newValue)) {
1499
+ outputMap = JSON.parse(newValue);
1500
+ var outputCount = 0;
1501
+ var outputsChanged = false;
1502
+ var keys = Object.keys(outputMap);
1503
+ keys.forEach(function (p) {
1504
+ if (isNaN(p)) {
1505
+ // New output;
1506
+ outputCount++;
1507
+ delete outputMap[p];
1508
+ } else {
1509
+ outputMap[p] = outputMap[p] + '';
1510
+ if (outputMap[p] !== '-1') {
1511
+ outputCount++;
1512
+ if (outputMap[p] !== p) {
1513
+ // Output moved
1514
+ outputsChanged = true;
1515
+ } else {
1516
+ delete outputMap[p];
1517
+ }
1518
+ } else {
1519
+ // Output removed
1520
+ outputsChanged = true;
1521
+ }
1522
+ }
1523
+ });
1524
+
1525
+ newValue = outputCount;
1526
+ if (outputsChanged) {
1527
+ changed = true;
1528
+ }
1529
+ } else {
1530
+ newValue = parseInt(newValue);
1531
+ }
1532
+ }
1533
+ if (editing_node[d] != newValue) {
1534
+ if (editing_node._def.defaults[d].type) {
1535
+ if (newValue == '_ADD_') {
1536
+ newValue = '';
1537
+ }
1538
+ // Change to a related config node
1539
+ var configNode = RED.nodes.node(editing_node[d]);
1540
+ if (configNode) {
1541
+ var users = configNode.users;
1542
+ users.splice(users.indexOf(editing_node), 1);
1543
+ }
1544
+ configNode = RED.nodes.node(newValue);
1545
+ if (configNode) {
1546
+ configNode.users.push(editing_node);
1547
+ }
1548
+ }
1549
+ changes[d] = editing_node[d];
1550
+ editing_node[d] = newValue;
1551
+ changed = true;
1552
+ }
1553
+ }
1554
+ }
1555
+ }
1556
+ }
1557
+ if (editing_node._def.credentials) {
1558
+ var prefix = 'node-input';
1559
+ var credDefinition = editing_node._def.credentials;
1560
+ var credsChanged = updateNodeCredentials(
1561
+ editing_node,
1562
+ credDefinition,
1563
+ prefix
1564
+ );
1565
+ changed = changed || credsChanged;
1566
+ }
1567
+ if (editing_node.hasOwnProperty("_outputs")) {
1568
+ outputMap = editing_node._outputs;
1569
+ delete editing_node._outputs;
1570
+ if (Object.keys(outputMap).length > 0) {
1571
+ changed = true;
1572
+ }
1573
+ }
1574
+ var removedLinks = updateNodeProperties(editing_node, outputMap);
1575
+
1576
+ if (updateLabels(editing_node, changes, outputMap)) {
1577
+ changed = true;
1578
+ }
1579
+
1580
+ // deleted all references about the l property (not needed as we have decommisioned the link node), it was about hiding the label for link type;
1581
+
1582
+ node.resize = true;
1583
+
1584
+ var oldInfo = node.info;
1585
+ if (nodeInfoEditor) {
1586
+ var newInfo = nodeInfoEditor.getValue();
1587
+ if (!!oldInfo) {
1588
+ // Has existing info property
1589
+ if (newInfo.trim() === '') {
1590
+ // New value is blank - remove the property
1591
+ changed = true;
1592
+ changes.info = oldInfo;
1593
+ delete node.info;
1594
+ } else if (newInfo !== oldInfo) {
1595
+ // New value is different
1596
+ changed = true;
1597
+ changes.info = oldInfo;
1598
+ node.info = newInfo;
1599
+ }
1600
+ } else {
1601
+ // No existing info
1602
+ if (newInfo.trim() !== '') {
1603
+ // New value is not blank
1604
+ changed = true;
1605
+ changes.info = undefined;
1606
+ node.info = newInfo;
1607
+ }
1608
+ }
1609
+ }
1610
+
1611
+
1612
+ if (changed) {
1613
+ var wasChanged = editing_node.changed;
1614
+ editing_node.changed = true;
1615
+ RED.nodes.dirty(true);
1616
+
1617
+ var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
1618
+ var subflowInstances = null;
1619
+ if (activeSubflow) {
1620
+ subflowInstances = [];
1621
+ RED.nodes.eachNode(function (n) {
1622
+ if (n.type == 'subflow:' + RED.workspaces.active()) {
1623
+ subflowInstances.push({
1624
+ id: n.id,
1625
+ changed: n.changed,
1626
+ });
1627
+ n.changed = true;
1628
+ n.dirty = true;
1629
+ updateNodeProperties(n);
1630
+ }
1631
+ });
1632
+ }
1633
+ var historyEvent = {
1634
+ t: 'edit',
1635
+ node: editing_node,
1636
+ changes: changes,
1637
+ links: removedLinks,
1638
+ dirty: wasDirty,
1639
+ changed: wasChanged,
1640
+ };
1641
+ if (outputMap) {
1642
+ historyEvent.outputMap = outputMap;
1643
+ }
1644
+ if (subflowInstances) {
1645
+ historyEvent.subflow = {
1646
+ instances: subflowInstances,
1647
+ };
1648
+ }
1649
+ RED.history.push(historyEvent);
1650
+ editing_node.dirty = true;
1651
+ validateNode(editing_node);
1652
+ setLatestNodeSelected(editing_node);
1653
+ // console.log('[editor] Node changed. Required to be saved', editing_node);
1654
+ RED.events.emit('editor:save', editing_node);
1655
+ }else{
1656
+ // console.log('[editor] Editing node is same as current node. No saving required');
1657
+ return;
1658
+ }
1659
+
1660
+ }
1661
+
1662
+ function attachListenerToFieldsChange() {
1663
+ // console.log('[editor] Node properties changed. Event: keyup change');
1664
+ notifyChanges(getLatestNodeSelected());
1665
+ // Wait until the DOM has been modified as part of the click event, to set the new listener to the new elements
1666
+ setTimeout(()=> {
1667
+ listenEditorChanges();
1668
+ }, 300);
1669
+ }
1670
+
1671
+ function attachListenerToClickBtn() {
1672
+ // console.log('[editor] Node properties changed. Event: a click');
1673
+
1674
+ // Wait until the DOM has been modified as part of the click event, to set the new listener to the new elements
1675
+ setTimeout(()=> {
1676
+ notifyChanges(getLatestNodeSelected());
1677
+ listenEditorChanges();
1678
+ }, 300);
1679
+ }
1680
+
1681
+ function listenEditorChanges(){
1682
+ // console.log('[editor] Setting new listeners...')
1683
+ $('#editor-stack :input').off('keyup change', attachListenerToFieldsChange);
1684
+ $('#editor-stack :input').on('keyup change', attachListenerToFieldsChange);
1685
+
1686
+ $('#editor-stack a').off('click', attachListenerToClickBtn)
1687
+ $('#editor-stack a').on('click', attachListenerToClickBtn)
1688
+ }
1689
+
1690
+ function showEditDialog(node) {
1691
+ let editing_node;
1692
+ // console.log('[editor] showEditDialog. Node=', node);
1693
+ if (Object.keys(node).length === 0 && node.constructor === Object){
1694
+ resetEditor();
1695
+ return;
1696
+ }
1697
+ // Case selection is about a `link`
1698
+ if (node && node.hasOwnProperty('link')){
1699
+ return;
1700
+ }
1701
+
1702
+ // Case selection is about a `node`
1703
+ if (node && node.hasOwnProperty('nodes') && node.nodes.length === 1) { // Single node selection
1704
+ // Ignore if sidebar is not visible - only double click will pull initially the sidebar
1705
+ if (RED.sidebar.isSidebarVisible()){
1706
+ editing_node = node.nodes[0];
1707
+ } else {
1708
+ setLatestNodeSelected(node.nodes[0]);
1709
+ return;
1710
+ }
1711
+
1712
+ } else if (node && node.hasOwnProperty('nodes') && Array.isArray(node.nodes)){ // Multinode selection
1713
+ return;
1714
+ } else { // Double click on node
1715
+ editing_node = node;
1716
+ }
1717
+
1718
+ node = editing_node; // backwards compatibility
1719
+ setLatestNodeSelected(node);
1720
+ var finishedBuilding = false;
1721
+
1722
+ // console.log('[editor] Before editStack.push() =', editStack);
1723
+ editStack.pop();
1724
+ editStack.push(node);
1725
+
1726
+ //RED.view.state(RED.state.EDITING);
1727
+ var type = node.type;
1728
+
1729
+ if (node.type.substring(0, 8) == 'subflow:') {
1730
+ type = 'subflow';
1731
+ }
1732
+
1733
+ var trayOptions = {
1734
+ nodeId: node.id,
1735
+ title: getEditStackTitle(),
1736
+ nodeIconPath: getNodeIconPath(),
1737
+ buttons: [
1738
+ ],
1739
+ resize: function (dimensions) {
1740
+ editTrayWidthCache[type] = dimensions.width;
1741
+ $('.editor-tray-content').height(dimensions.height - 50);
1742
+ var form = $('.editor-tray-content form').height(
1743
+ dimensions.height - 50 - 40
1744
+ );
1745
+ if (editing_node && editing_node._def.oneditresize) {
1746
+ try {
1747
+ editing_node._def.oneditresize.call(editing_node, {
1748
+ width: form.width(),
1749
+ height: form.height(),
1750
+ });
1751
+ } catch (err) {
1752
+ console.log(
1753
+ 'oneditresize',
1754
+ editing_node.id,
1755
+ editing_node.type,
1756
+ err.toString()
1757
+ );
1758
+ }
1759
+ }
1760
+ },
1761
+ open: function (tray, done) {
1762
+ var trayFooter = tray.find('.editor-tray-footer');
1763
+ var trayBody = tray.find('.editor-tray-body');
1764
+ trayBody.parent().css('overflow', 'hidden');
1765
+
1766
+ var editorTabEl = $('<ul></ul>').appendTo(trayBody);
1767
+ var editorContent = $('<div id="editorContent"></div>').appendTo(trayBody);
1768
+
1769
+ var editorTabs = RED.tabs.create({
1770
+ element: editorTabEl,
1771
+ onchange: function (tab) {
1772
+ editorContent.children().hide();
1773
+ if (tab.onchange) {
1774
+ tab.onchange.call(tab);
1775
+ }
1776
+ tab.content.show();
1777
+ if (finishedBuilding) {
1778
+ RED.tray.resize();
1779
+ }
1780
+ },
1781
+ collapsible: true,
1782
+ menu: false,
1783
+ });
1784
+ if (editing_node) {
1785
+ RED.sidebar.info.refresh(editing_node);
1786
+ }
1787
+ var ns;
1788
+ if (node._def.set.module === 'kumologica-core') {
1789
+ ns = 'kumologica-core';
1790
+ } else {
1791
+ ns = node._def.set.id;
1792
+ }
1793
+
1794
+ var iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
1795
+ defaultIcon = iconPath.module + '/' + iconPath.file;
1796
+ if (iconPath.module === 'kumologica-core') {
1797
+ nodeIconPath = `icons/${iconPath.module}/${iconPath.file}`;
1798
+ isDefaultIcon = true;
1799
+ } else {
1800
+ isDefaultIcon = false;
1801
+ }
1802
+
1803
+ // Properties tab
1804
+ var nodePropertiesTab = {
1805
+ id: 'editor-tab-properties',
1806
+ label: 'Properties',
1807
+ name: 'Properties',
1808
+ content: $('<div>', {
1809
+ class: 'editor-tray-content',
1810
+ id: 'properties-tab',
1811
+ })
1812
+ .appendTo(editorContent)
1813
+ .hide(),
1814
+ iconClass: 'fa fa-cog',
1815
+ };
1816
+ buildEditForm(nodePropertiesTab.content, 'dialog-form', type, ns, node);
1817
+ editorTabs.addTab(nodePropertiesTab);
1818
+
1819
+ // Help tab
1820
+ let helpTab = {
1821
+ id: 'editor-tab-help',
1822
+ label: 'Help',
1823
+ name: 'Help',
1824
+ content: $('<div>', {
1825
+ class: 'editor-tray-content',
1826
+ id: 'help-tab',
1827
+ })
1828
+ .appendTo(editorContent)
1829
+ .hide(),
1830
+ iconClass: 'fa fa-cog',
1831
+ }
1832
+ editorTabs.addTab(helpTab);
1833
+ let editorTabContent = $('#help-tab');
1834
+
1835
+ let helpText =
1836
+ $("script[data-help-name='" + node.type + "']").html() ||
1837
+ '<span class="node-info-none">' +
1838
+ 'None' +
1839
+ '</span>';
1840
+
1841
+ $(`<div class="node-help">${helpText}</div>`).appendTo(editorTabContent);
1842
+
1843
+ // Notes tab
1844
+ if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
1845
+ var descriptionTab = {
1846
+ id: 'editor-tab-description',
1847
+ label: 'Description',
1848
+ name: 'Description',
1849
+ content: $('<div>', {
1850
+ class: 'editor-tray-content',
1851
+ id: 'documentation-tab',
1852
+ })
1853
+ .appendTo(editorContent)
1854
+ .hide(),
1855
+ iconClass: 'fa fa-file-text-o',
1856
+ onchange: function () {
1857
+ if (nodeInfoEditor) {
1858
+ nodeInfoEditor.focus();
1859
+ } else {
1860
+ console.log('WARN - nodeInfoEditor is undefined');
1861
+ }
1862
+ },
1863
+ };
1864
+ editorTabs.addTab(descriptionTab);
1865
+ nodeInfoEditor = buildDescriptionForm(descriptionTab.content, node);
1866
+ }
1867
+
1868
+ var appearanceTab = {
1869
+ id: 'editor-tab-appearance',
1870
+ label: 'Appearance',
1871
+ name: 'Appearance',
1872
+ content: $('<div>', { class: 'editor-tray-content' })
1873
+ .appendTo(editorContent)
1874
+ .hide(),
1875
+ iconClass: 'fa fa-object-group',
1876
+ onchange: function () {
1877
+ refreshLabelForm(this.content, node);
1878
+ },
1879
+ };
1880
+ buildAppearanceForm(appearanceTab.content, node);
1881
+ //editorTabs.addTab(appearanceTab);
1882
+
1883
+ prepareEditDialog(node, node._def, 'node-input', function () {
1884
+ trayBody.i18n();
1885
+ finishedBuilding = true;
1886
+ done();
1887
+ });
1888
+ },
1889
+ close: function () {
1890
+ // console.log('[editor] trayoptions->close')
1891
+ if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
1892
+ RED.view.state(RED.state.DEFAULT);
1893
+ }
1894
+ if (editing_node) {
1895
+ RED.sidebar.info.refresh(editing_node);
1896
+ }
1897
+ RED.workspaces.refresh();
1898
+ if (nodeInfoEditor) {
1899
+ nodeInfoEditor.destroy();
1900
+ nodeInfoEditor = null;
1901
+ }
1902
+ RED.view.redraw(true);
1903
+ editStack.pop();
1904
+ },
1905
+ show: function () {
1906
+ if (editing_node) {
1907
+ // console.log('[editor] Showing editor ...')
1908
+ RED.sidebar.info.refresh(editing_node);
1909
+ // activate the save button when node properties have changed
1910
+ setTimeout( ()=> {
1911
+ listenEditorChanges();
1912
+ }, 300);
1913
+ }
1914
+ },
1915
+ };
1916
+
1917
+ // if (editTrayWidthCache.hasOwnProperty(type)) {
1918
+ // trayOptions.width = editTrayWidthCache[type];
1919
+ // }
1920
+ RED.actions.invoke('core:show-sidebar', { selectIndex: 0 });
1921
+ RED.tray.show(trayOptions);
1922
+
1923
+ // // activate the save button when node properties have changed
1924
+ // listenEditorChanges(latestNodeSelected);
1925
+ }
1926
+
1927
+ /**
1928
+ * name - name of the property that holds this config node
1929
+ * type - type of config node
1930
+ * id - id of config node to edit. _ADD_ for a new one
1931
+ * prefix - the input prefix of the parent property
1932
+ */
1933
+ function showEditConfigNodeDialog(name, type, id, prefix) {
1934
+ var adding = id == '_ADD_';
1935
+ var node_def = RED.nodes.getType(type);
1936
+ var editing_config_node = RED.nodes.node(id);
1937
+ var nodeInfoEditor;
1938
+ var finishedBuilding = false;
1939
+
1940
+ var ns;
1941
+ if (node_def.set.module === 'kumologica-core') {
1942
+ ns = 'kumologica-core';
1943
+ } else {
1944
+ ns = node_def.set.id;
1945
+ }
1946
+ var configNodeScope = ''; // default to global
1947
+ var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
1948
+ if (activeSubflow) {
1949
+ configNodeScope = activeSubflow.id;
1950
+ }
1951
+ if (editing_config_node == null) {
1952
+ editing_config_node = {
1953
+ id: RED.nodes.id(),
1954
+ _def: node_def,
1955
+ type: type,
1956
+ z: configNodeScope,
1957
+ users: [],
1958
+ };
1959
+ for (var d in node_def.defaults) {
1960
+ if (node_def.defaults[d].value) {
1961
+ editing_config_node[d] = JSON.parse(
1962
+ JSON.stringify(node_def.defaults[d].value)
1963
+ );
1964
+ }
1965
+ }
1966
+ editing_config_node['_'] = node_def._;
1967
+ }
1968
+ editStack.push(editing_config_node);
1969
+
1970
+ RED.view.state(RED.state.EDITING);
1971
+ var trayOptions = {
1972
+ title: getEditStackTitle(),
1973
+ nodeIconPath: getNodeIconPath(),
1974
+ resize: function (dimensions) {
1975
+ $('.editor-tray-content').height(dimensions.height - 50);
1976
+ if (editing_config_node && editing_config_node._def.oneditresize) {
1977
+ var form = $('#node-config-dialog-edit-form');
1978
+ try {
1979
+ editing_config_node._def.oneditresize.call(editing_config_node, {
1980
+ width: form.width(),
1981
+ height: form.height(),
1982
+ });
1983
+ } catch (err) {
1984
+ console.log(
1985
+ 'oneditresize',
1986
+ editing_config_node.id,
1987
+ editing_config_node.type,
1988
+ err.toString()
1989
+ );
1990
+ }
1991
+ }
1992
+ },
1993
+ open: function (tray, done) {
1994
+ var trayHeader = tray.find('.editor-tray-header');
1995
+ var trayBody = tray.find('.editor-tray-body');
1996
+ var trayFooter = tray.find('.editor-tray-footer');
1997
+
1998
+ if (node_def.hasUsers !== false) {
1999
+ trayFooter.prepend(
2000
+ '<div id="node-config-dialog-user-count"><i class="fa fa-info-circle"></i> <span></span></div>'
2001
+ );
2002
+ }
2003
+ trayFooter.append(
2004
+ '<span id="node-config-dialog-scope-container"><span id="node-config-dialog-scope-warning" data-i18n="[title]editor.errors.scopeChange"><i class="fa fa-warning"></i></span><select id="node-config-dialog-scope"></select></span>'
2005
+ );
2006
+
2007
+ //var editorTabEl = $('<ul></ul>').appendTo(trayBody);
2008
+ var editorContent = $('<div id="editorContent"></div>').appendTo(trayBody);
2009
+
2010
+ var editorTabs = RED.tabs.create({
2011
+ element: editorTabEl,
2012
+ onchange: function (tab) {
2013
+ editorContent.children().hide();
2014
+ if (tab.onchange) {
2015
+ tab.onchange.call(tab);
2016
+ }
2017
+ tab.content.show();
2018
+ if (finishedBuilding) {
2019
+ RED.tray.resize();
2020
+ }
2021
+ },
2022
+ collapsible: true,
2023
+ });
2024
+
2025
+ var nodePropertiesTab = {
2026
+ id: 'editor-tab-cproperties',
2027
+ label: 'Properties',
2028
+ name: 'Properties',
2029
+ content: $('<div>', {
2030
+ class: 'editor-tray-content',
2031
+ })
2032
+ .appendTo(editorContent)
2033
+ .hide(),
2034
+ iconClass: 'fa fa-cog',
2035
+ };
2036
+ editorTabs.addTab(nodePropertiesTab);
2037
+ buildEditForm(
2038
+ nodePropertiesTab.content,
2039
+ 'node-config-dialog-edit-form',
2040
+ type,
2041
+ ns
2042
+ );
2043
+
2044
+ if (!node_def.defaults || !node_def.defaults.hasOwnProperty('info')) {
2045
+ var descriptionTab = {
2046
+ id: 'editor-tab-description',
2047
+ label: 'Description',
2048
+ name: 'Description',
2049
+ content: $('<div>', { class: 'editor-tray-content' })
2050
+ .appendTo(editorContent)
2051
+ .hide(),
2052
+ iconClass: 'fa fa-file-text-o',
2053
+ onchange: function () {
2054
+ nodeInfoEditor.focus();
2055
+ },
2056
+ };
2057
+ editorTabs.addTab(descriptionTab);
2058
+ nodeInfoEditor = buildDescriptionForm(
2059
+ descriptionTab.content,
2060
+ editing_config_node
2061
+ );
2062
+ }
2063
+
2064
+ prepareEditDialog(
2065
+ editing_config_node,
2066
+ node_def,
2067
+ 'node-config-input',
2068
+ function () {
2069
+ if (editing_config_node._def.exclusive) {
2070
+ $('#node-config-dialog-scope').hide();
2071
+ } else {
2072
+ $('#node-config-dialog-scope').show();
2073
+ }
2074
+ $('#node-config-dialog-scope-warning').hide();
2075
+
2076
+ var nodeUserFlows = {};
2077
+ editing_config_node.users.forEach(function (n) {
2078
+ nodeUserFlows[n.z] = true;
2079
+ });
2080
+ var flowCount = Object.keys(nodeUserFlows).length;
2081
+ var tabSelect = $('#node-config-dialog-scope').empty();
2082
+ tabSelect.off('change');
2083
+ tabSelect.append(
2084
+ '<option value=""' +
2085
+ (!editing_config_node.z ? ' selected' : '') +
2086
+ ' data-i18n="sidebar.config.global"></option>'
2087
+ );
2088
+ tabSelect.append(
2089
+ '<option disabled data-i18n="sidebar.config.flows"></option>'
2090
+ );
2091
+ RED.nodes.eachWorkspace(function (ws) {
2092
+ var workspaceLabel = ws.label;
2093
+ if (nodeUserFlows[ws.id]) {
2094
+ workspaceLabel = '* ' + workspaceLabel;
2095
+ }
2096
+ $(
2097
+ '<option value="' +
2098
+ ws.id +
2099
+ '"' +
2100
+ (ws.id == editing_config_node.z ? ' selected' : '') +
2101
+ '></option>'
2102
+ )
2103
+ .text(workspaceLabel)
2104
+ .appendTo(tabSelect);
2105
+ });
2106
+ tabSelect.append(
2107
+ '<option disabled data-i18n="sidebar.config.subflows"></option>'
2108
+ );
2109
+ RED.nodes.eachSubflow(function (ws) {
2110
+ var workspaceLabel = ws.name;
2111
+ if (nodeUserFlows[ws.id]) {
2112
+ workspaceLabel = '* ' + workspaceLabel;
2113
+ }
2114
+ $(
2115
+ '<option value="' +
2116
+ ws.id +
2117
+ '"' +
2118
+ (ws.id == editing_config_node.z ? ' selected' : '') +
2119
+ '></option>'
2120
+ )
2121
+ .text(workspaceLabel)
2122
+ .appendTo(tabSelect);
2123
+ });
2124
+ if (flowCount > 0) {
2125
+ tabSelect.on('change', function () {
2126
+ var newScope = $(this).val();
2127
+ if (newScope === '') {
2128
+ // global scope - everyone can use it
2129
+ $('#node-config-dialog-scope-warning').hide();
2130
+ } else if (!nodeUserFlows[newScope] || flowCount > 1) {
2131
+ // a user will loose access to it
2132
+ $('#node-config-dialog-scope-warning').show();
2133
+ } else {
2134
+ $('#node-config-dialog-scope-warning').hide();
2135
+ }
2136
+ });
2137
+ }
2138
+ if (node_def.hasUsers !== false) {
2139
+ $('#node-config-dialog-user-count')
2140
+ .find('span')
2141
+ .text(`${editing_config_node.users.length} nodes use this config`)
2142
+ .parent()
2143
+ .show();
2144
+ }
2145
+ trayBody.i18n();
2146
+ trayFooter.i18n();
2147
+ finishedBuilding = true;
2148
+ done();
2149
+ }
2150
+ );
2151
+ },
2152
+ close: function () {
2153
+ RED.workspaces.refresh();
2154
+ if (nodeInfoEditor) {
2155
+ nodeInfoEditor.destroy();
2156
+ nodeInfoEditor = null;
2157
+ }
2158
+ editStack.pop();
2159
+ },
2160
+ show: function () {
2161
+ if (editing_config_node) {
2162
+ RED.sidebar.info.refresh(editing_config_node);
2163
+ }
2164
+ },
2165
+ };
2166
+ trayOptions.buttons = [
2167
+ {
2168
+ id: 'node-config-dialog-cancel',
2169
+ text: 'Cancel',
2170
+ click: function () {
2171
+ var configType = type;
2172
+ var configId = editing_config_node.id;
2173
+ var configAdding = adding;
2174
+ var configTypeDef = RED.nodes.getType(configType);
2175
+
2176
+ if (configTypeDef.oneditcancel) {
2177
+ // TODO: what to pass as this to call
2178
+ if (configTypeDef.oneditcancel) {
2179
+ var cn = RED.nodes.node(configId);
2180
+ if (cn) {
2181
+ try {
2182
+ configTypeDef.oneditcancel.call(cn, false);
2183
+ } catch (err) {
2184
+ console.log('oneditcancel', cn.id, cn.type, err.toString());
2185
+ }
2186
+ } else {
2187
+ try {
2188
+ configTypeDef.oneditcancel.call({ id: configId }, true);
2189
+ } catch (err) {
2190
+ console.log(
2191
+ 'oneditcancel',
2192
+ configId,
2193
+ configType,
2194
+ err.toString()
2195
+ );
2196
+ }
2197
+ }
2198
+ }
2199
+ }
2200
+ RED.tray.close();
2201
+ },
2202
+ },
2203
+ {
2204
+ id: 'node-config-dialog-ok',
2205
+ text: adding ? 'Add' : 'Update',
2206
+ class: 'primary',
2207
+ click: function () {
2208
+ var configProperty = name;
2209
+ var configId = editing_config_node.id;
2210
+ var configType = type;
2211
+ var configAdding = adding;
2212
+ var configTypeDef = RED.nodes.getType(configType);
2213
+ var d;
2214
+ var input;
2215
+ var scope = $('#node-config-dialog-scope').val();
2216
+
2217
+ if (configTypeDef.oneditsave) {
2218
+ try {
2219
+ configTypeDef.oneditsave.call(editing_config_node);
2220
+ } catch (err) {
2221
+ console.log(
2222
+ 'oneditsave',
2223
+ editing_config_node.id,
2224
+ editing_config_node.type,
2225
+ err.toString()
2226
+ );
2227
+ }
2228
+ }
2229
+
2230
+ for (d in configTypeDef.defaults) {
2231
+ if (configTypeDef.defaults.hasOwnProperty(d)) {
2232
+ var newValue;
2233
+ input = $('#node-config-input-' + d);
2234
+ if (input.attr('type') === 'checkbox') {
2235
+ newValue = input.prop('checked');
2236
+ } else if (
2237
+ 'format' in configTypeDef.defaults[d] &&
2238
+ configTypeDef.defaults[d].format !== '' &&
2239
+ input[0].nodeName === 'DIV'
2240
+ ) {
2241
+ newValue = input.text();
2242
+ } else {
2243
+ newValue = input.val();
2244
+ }
2245
+ if (newValue != null && newValue !== editing_config_node[d]) {
2246
+ if (editing_config_node._def.defaults[d].type) {
2247
+ if (newValue == '_ADD_') {
2248
+ newValue = '';
2249
+ }
2250
+ // Change to a related config node
2251
+ var configNode = RED.nodes.node(editing_config_node[d]);
2252
+ if (configNode) {
2253
+ var users = configNode.users;
2254
+ users.splice(users.indexOf(editing_config_node), 1);
2255
+ }
2256
+ configNode = RED.nodes.node(newValue);
2257
+ if (configNode) {
2258
+ configNode.users.push(editing_config_node);
2259
+ }
2260
+ }
2261
+ editing_config_node[d] = newValue;
2262
+ }
2263
+ }
2264
+ }
2265
+
2266
+ if (nodeInfoEditor) {
2267
+ editing_config_node.info = nodeInfoEditor.getValue();
2268
+
2269
+ var oldInfo = editing_config_node.info;
2270
+ if (nodeInfoEditor) {
2271
+ var newInfo = nodeInfoEditor.getValue();
2272
+ if (!!oldInfo) {
2273
+ // Has existing info property
2274
+ if (newInfo.trim() === '') {
2275
+ // New value is blank - remove the property
2276
+ delete editing_config_node.info;
2277
+ } else if (newInfo !== oldInfo) {
2278
+ // New value is different
2279
+ editing_config_node.info = newInfo;
2280
+ }
2281
+ } else {
2282
+ // No existing info
2283
+ if (newInfo.trim() !== '') {
2284
+ // New value is not blank
2285
+ editing_config_node.info = newInfo;
2286
+ }
2287
+ }
2288
+ }
2289
+ }
2290
+ editing_config_node.label = configTypeDef.label;
2291
+ editing_config_node.z = scope;
2292
+
2293
+ if (scope) {
2294
+ // Search for nodes that use this one that are no longer
2295
+ // in scope, so must be removed
2296
+ editing_config_node.users = editing_config_node.users.filter(
2297
+ function (n) {
2298
+ var keep = true;
2299
+ for (var d in n._def.defaults) {
2300
+ if (n._def.defaults.hasOwnProperty(d)) {
2301
+ if (
2302
+ n._def.defaults[d].type === editing_config_node.type &&
2303
+ n[d] === editing_config_node.id &&
2304
+ n.z !== scope
2305
+ ) {
2306
+ keep = false;
2307
+ // Remove the reference to this node
2308
+ // and revalidate
2309
+ n[d] = null;
2310
+ n.dirty = true;
2311
+ n.changed = true;
2312
+ validateNode(n);
2313
+ }
2314
+ }
2315
+ }
2316
+ return keep;
2317
+ }
2318
+ );
2319
+ }
2320
+
2321
+ if (configAdding) {
2322
+ RED.nodes.add(editing_config_node);
2323
+ }
2324
+
2325
+ if (configTypeDef.credentials) {
2326
+ updateNodeCredentials(
2327
+ editing_config_node,
2328
+ configTypeDef.credentials,
2329
+ 'node-config-input'
2330
+ );
2331
+ }
2332
+ validateNode(editing_config_node);
2333
+ var validatedNodes = {};
2334
+ validatedNodes[editing_config_node.id] = true;
2335
+
2336
+ var userStack = editing_config_node.users.slice();
2337
+ while (userStack.length > 0) {
2338
+ var user = userStack.pop();
2339
+ if (!validatedNodes[user.id]) {
2340
+ validatedNodes[user.id] = true;
2341
+ if (user.users) {
2342
+ userStack = userStack.concat(user.users);
2343
+ }
2344
+ validateNode(user);
2345
+ }
2346
+ }
2347
+ RED.nodes.dirty(true);
2348
+ RED.view.redraw(true);
2349
+ if (!configAdding) {
2350
+ RED.events.emit('editor:save', editing_config_node);
2351
+ }
2352
+ RED.tray.close(function () {
2353
+ updateConfigNodeSelect(
2354
+ configProperty,
2355
+ configType,
2356
+ editing_config_node.id,
2357
+ prefix
2358
+ );
2359
+ });
2360
+ },
2361
+ },
2362
+ ];
2363
+
2364
+ if (!adding) {
2365
+ trayOptions.buttons.unshift({
2366
+ class: 'leftButton',
2367
+ text: 'Delete', //'<i class="fa fa-trash"></i>',
2368
+ click: function () {
2369
+ var configProperty = name;
2370
+ var configId = editing_config_node.id;
2371
+ var configType = type;
2372
+ var configTypeDef = RED.nodes.getType(configType);
2373
+
2374
+ try {
2375
+ if (configTypeDef.ondelete) {
2376
+ // Deprecated: never documented but used by some early nodes
2377
+ console.log(
2378
+ 'Deprecated API warning: config node type ',
2379
+ configType,
2380
+ ' has an ondelete function - should be oneditdelete'
2381
+ );
2382
+ configTypeDef.ondelete.call(editing_config_node);
2383
+ }
2384
+ if (configTypeDef.oneditdelete) {
2385
+ configTypeDef.oneditdelete.call(editing_config_node);
2386
+ }
2387
+ } catch (err) {
2388
+ console.log(
2389
+ 'oneditdelete',
2390
+ editing_config_node.id,
2391
+ editing_config_node.type,
2392
+ err.toString()
2393
+ );
2394
+ }
2395
+
2396
+ var historyEvent = {
2397
+ t: 'delete',
2398
+ nodes: [editing_config_node],
2399
+ changes: {},
2400
+ dirty: RED.nodes.dirty(),
2401
+ };
2402
+ for (var i = 0; i < editing_config_node.users.length; i++) {
2403
+ var user = editing_config_node.users[i];
2404
+ historyEvent.changes[user.id] = {
2405
+ changed: user.changed,
2406
+ valid: user.valid,
2407
+ };
2408
+ for (var d in user._def.defaults) {
2409
+ if (user._def.defaults.hasOwnProperty(d) && user[d] == configId) {
2410
+ historyEvent.changes[user.id][d] = configId;
2411
+ user[d] = '';
2412
+ user.changed = true;
2413
+ user.dirty = true;
2414
+ }
2415
+ }
2416
+ validateNode(user);
2417
+ }
2418
+ RED.nodes.remove(configId);
2419
+ RED.nodes.dirty(true);
2420
+ RED.view.redraw(true);
2421
+ RED.history.push(historyEvent);
2422
+ RED.tray.close(function () {
2423
+ updateConfigNodeSelect(configProperty, configType, '', prefix);
2424
+ });
2425
+ },
2426
+ });
2427
+ }
2428
+
2429
+ RED.tray.show(trayOptions);
2430
+ }
2431
+
2432
+ function defaultConfigNodeSort(A, B) {
2433
+ if (A.__label__ < B.__label__) {
2434
+ return -1;
2435
+ } else if (A.__label__ > B.__label__) {
2436
+ return 1;
2437
+ }
2438
+ return 0;
2439
+ }
2440
+
2441
+ function updateConfigNodeSelect(name, type, value, prefix) {
2442
+ // if prefix is null, there is no config select to update
2443
+ if (prefix) {
2444
+ var button = $('#' + prefix + '-edit-' + name);
2445
+ if (button.length) {
2446
+ if (value) {
2447
+ button.text('Edit');
2448
+ } else {
2449
+ button.text('Add');
2450
+ }
2451
+ $('#' + prefix + '-' + name).val(value);
2452
+ } else {
2453
+ var select = $('#' + prefix + '-' + name);
2454
+ var node_def = RED.nodes.getType(type);
2455
+ select.children().remove();
2456
+
2457
+ var activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
2458
+ if (!activeWorkspace) {
2459
+ activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
2460
+ }
2461
+
2462
+ var configNodes = [];
2463
+
2464
+ RED.nodes.eachConfig(function (config) {
2465
+ if (
2466
+ config.type == type &&
2467
+ (!config.z || config.z === activeWorkspace.id)
2468
+ ) {
2469
+ var label = RED.utils.getNodeLabel(config, config.id);
2470
+ config.__label__ = label;
2471
+ configNodes.push(config);
2472
+ }
2473
+ });
2474
+ var configSortFn = defaultConfigNodeSort;
2475
+ if (typeof node_def.sort == 'function') {
2476
+ configSortFn = node_def.sort;
2477
+ }
2478
+ try {
2479
+ configNodes.sort(configSortFn);
2480
+ } catch (err) {
2481
+ console.log('Definition error: ' + node_def.type + '.sort', err);
2482
+ }
2483
+
2484
+ configNodes.forEach(function (cn) {
2485
+ $(
2486
+ '<option value="' +
2487
+ cn.id +
2488
+ '"' +
2489
+ (value == cn.id ? ' selected' : '') +
2490
+ '></option>'
2491
+ )
2492
+ .text(RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__))
2493
+ .appendTo(select);
2494
+ delete cn.__label__;
2495
+ });
2496
+
2497
+ select.append(
2498
+ '<option value="_ADD_"' +
2499
+ (value === '' ? ' selected' : '') +
2500
+ '>' + `Add new ${type}...` +
2501
+ '</option>'
2502
+ );
2503
+ window.setTimeout(function () {
2504
+ select.change();
2505
+ }, 50);
2506
+ }
2507
+ }
2508
+ }
2509
+
2510
+ function showEditSubflowDialog(subflow) {
2511
+ var editing_node = subflow;
2512
+ editStack.push(subflow);
2513
+ RED.view.state(RED.state.EDITING);
2514
+ var subflowEditor;
2515
+ var finishedBuilding = false;
2516
+ var trayOptions = {
2517
+ title: getEditStackTitle(),
2518
+ buttons: [
2519
+ {
2520
+ id: 'node-dialog-cancel',
2521
+ text: 'Close',
2522
+ click: function () {
2523
+ RED.tray.close();
2524
+ },
2525
+ },
2526
+ {
2527
+ id: 'node-dialog-ok',
2528
+ class: 'primary',
2529
+ text: 'Save',
2530
+ click: function () {
2531
+ var i;
2532
+ var changes = {};
2533
+ var changed = false;
2534
+ var wasDirty = RED.nodes.dirty();
2535
+
2536
+ var newName = $('#subflow-input-name').val();
2537
+
2538
+ if (newName != editing_node.name) {
2539
+ changes['name'] = editing_node.name;
2540
+ editing_node.name = newName;
2541
+ changed = true;
2542
+ }
2543
+
2544
+ var newDescription = subflowEditor.getValue();
2545
+
2546
+ if (newDescription != editing_node.info) {
2547
+ changes['info'] = editing_node.info;
2548
+ editing_node.info = newDescription;
2549
+ changed = true;
2550
+ }
2551
+ if (updateLabels(editing_node, changes, null)) {
2552
+ changed = true;
2553
+ }
2554
+ var icon = $('#node-settings-icon').text() || '';
2555
+ if (
2556
+ (editing_node.icon === undefined &&
2557
+ icon !== 'kumologica-core/subflow.png') ||
2558
+ (editing_node.icon !== undefined && editing_node.icon !== icon)
2559
+ ) {
2560
+ changes.icon = editing_node.icon;
2561
+ editing_node.icon = icon;
2562
+ changed = true;
2563
+ }
2564
+ var newCategory = $('#subflow-input-category').val().trim();
2565
+ if (newCategory === '_custom_') {
2566
+ newCategory = $('#subflow-input-custom-category').val().trim();
2567
+ if (newCategory === '') {
2568
+ newCategory = editing_node.category;
2569
+ }
2570
+ }
2571
+ if (newCategory === 'subflows') {
2572
+ newCategory = '';
2573
+ }
2574
+ if (newCategory != editing_node.category) {
2575
+ changes['category'] = editing_node.category;
2576
+ editing_node.category = newCategory;
2577
+ changed = true;
2578
+ }
2579
+
2580
+ var old_env = editing_node.env;
2581
+ var new_env = exportEnvList(
2582
+ $('#node-input-env-container').editableList('items')
2583
+ );
2584
+ if (!isSameEnv(old_env, new_env)) {
2585
+ editing_node.env = new_env;
2586
+ changes.env = editing_node.env;
2587
+ changed = true;
2588
+ }
2589
+
2590
+ RED.palette.refresh();
2591
+
2592
+ if (changed) {
2593
+ var wasChanged = editing_node.changed;
2594
+ editing_node.changed = true;
2595
+ validateNode(editing_node);
2596
+ var subflowInstances = [];
2597
+ RED.nodes.eachNode(function (n) {
2598
+ if (n.type == 'subflow:' + editing_node.id) {
2599
+ subflowInstances.push({
2600
+ id: n.id,
2601
+ changed: n.changed,
2602
+ });
2603
+ n.changed = true;
2604
+ n.dirty = true;
2605
+ updateNodeProperties(n);
2606
+ validateNode(n);
2607
+ }
2608
+ });
2609
+ RED.nodes.dirty(true);
2610
+ var historyEvent = {
2611
+ t: 'edit',
2612
+ node: editing_node,
2613
+ changes: changes,
2614
+ dirty: wasDirty,
2615
+ changed: wasChanged,
2616
+ subflow: {
2617
+ instances: subflowInstances,
2618
+ },
2619
+ };
2620
+
2621
+ RED.history.push(historyEvent);
2622
+ }
2623
+ editing_node.dirty = true;
2624
+ RED.tray.close();
2625
+ },
2626
+ },
2627
+ ],
2628
+ resize: function (size) {
2629
+ $('.editor-tray-content').height(size.height - 50);
2630
+ // var form = $(".editor-tray-content form").height(size.height - 50 - 40);
2631
+ var rows = $('#dialog-form>div:not(.node-input-env-container-row)');
2632
+ var height = size.height;
2633
+ for (var i = 0; i < rows.size(); i++) {
2634
+ height -= $(rows[i]).outerHeight(true);
2635
+ }
2636
+ var editorRow = $('#dialog-form>div.node-input-env-container-row');
2637
+ height -=
2638
+ parseInt(editorRow.css('marginTop')) +
2639
+ parseInt(editorRow.css('marginBottom'));
2640
+ $('#node-input-env-container').editableList('height', height - 80);
2641
+ },
2642
+ open: function (tray) {
2643
+ var trayFooter = tray.find('.editor-tray-footer');
2644
+ var trayBody = tray.find('.editor-tray-body');
2645
+ trayBody.parent().css('overflow', 'hidden');
2646
+
2647
+ if (editing_node) {
2648
+ RED.sidebar.info.refresh(editing_node);
2649
+ }
2650
+
2651
+ var editorTabEl = $('<ul></ul>').appendTo(trayBody);
2652
+ var editorContent = $('<div></div>').appendTo(trayBody);
2653
+
2654
+ var editorTabs = RED.tabs.create({
2655
+ element: editorTabEl,
2656
+ onchange: function (tab) {
2657
+ editorContent.children().hide();
2658
+ if (tab.onchange) {
2659
+ tab.onchange.call(tab);
2660
+ }
2661
+ tab.content.show();
2662
+ if (finishedBuilding) {
2663
+ RED.tray.resize();
2664
+ }
2665
+ },
2666
+ collapsible: true,
2667
+ });
2668
+
2669
+ var nodePropertiesTab = {
2670
+ id: 'editor-tab-properties',
2671
+ label: 'Properties',
2672
+ name: 'Properties',
2673
+ content: $('<div>', { class: 'editor-tray-content' })
2674
+ .appendTo(editorContent)
2675
+ .hide(),
2676
+ iconClass: 'fa fa-cog',
2677
+ };
2678
+ buildEditForm(
2679
+ nodePropertiesTab.content,
2680
+ 'dialog-form',
2681
+ 'subflow-template',
2682
+ undefined,
2683
+ editing_node
2684
+ );
2685
+ editorTabs.addTab(nodePropertiesTab);
2686
+
2687
+ var descriptionTab = {
2688
+ id: 'editor-tab-description',
2689
+ label: 'Description',
2690
+ name: 'Description',
2691
+ content: $('<div>', { class: 'editor-tray-content' })
2692
+ .appendTo(editorContent)
2693
+ .hide(),
2694
+ iconClass: 'fa fa-file-text-o',
2695
+ onchange: function () {
2696
+ subflowEditor.focus();
2697
+ },
2698
+ };
2699
+ editorTabs.addTab(descriptionTab);
2700
+ subflowEditor = buildDescriptionForm(
2701
+ descriptionTab.content,
2702
+ editing_node
2703
+ );
2704
+
2705
+ var appearanceTab = {
2706
+ id: 'editor-tab-appearance',
2707
+ label: 'Apperance',
2708
+ name: 'Apperance',
2709
+ content: $('<div>', { class: 'editor-tray-content' })
2710
+ .appendTo(editorContent)
2711
+ .hide(),
2712
+ iconClass: 'fa fa-object-group',
2713
+ onchange: function () {
2714
+ refreshLabelForm(this.content, editing_node);
2715
+ },
2716
+ };
2717
+ buildAppearanceForm(appearanceTab.content, editing_node);
2718
+ editorTabs.addTab(appearanceTab);
2719
+
2720
+ $('#subflow-input-name').val(subflow.name);
2721
+ RED.text.bidi.prepareInput($('#subflow-input-name'));
2722
+
2723
+ $('#subflow-input-category').empty();
2724
+ var categories = RED.palette.getCategories();
2725
+ categories.sort(function (A, B) {
2726
+ return A.label.localeCompare(B.label);
2727
+ });
2728
+ categories.forEach(function (cat) {
2729
+ $('#subflow-input-category').append(
2730
+ $('<option></option>').val(cat.id).text(cat.label)
2731
+ );
2732
+ });
2733
+ $('#subflow-input-category').append(
2734
+ $('<option></option>').attr('disabled', true).text('---')
2735
+ );
2736
+ $('#subflow-input-category').append(
2737
+ $('<option></option>')
2738
+ .val('_custom_')
2739
+ .text('Add new...')
2740
+ );
2741
+
2742
+ $('#subflow-input-category').change(function () {
2743
+ var val = $(this).val();
2744
+ if (val === '_custom_') {
2745
+ $('#subflow-input-category').width(120);
2746
+ $('#subflow-input-custom-category').show();
2747
+ } else {
2748
+ $('#subflow-input-category').width(250);
2749
+ $('#subflow-input-custom-category').hide();
2750
+ }
2751
+ });
2752
+
2753
+ $('#subflow-input-category').val(subflow.category || 'subflows');
2754
+ var userCount = 0;
2755
+ var subflowType = 'subflow:' + editing_node.id;
2756
+
2757
+ RED.nodes.eachNode(function (n) {
2758
+ if (n.type === subflowType) {
2759
+ userCount++;
2760
+ }
2761
+ });
2762
+ $('#subflow-dialog-user-count')
2763
+ .text(`There is ${userCount} instance of this subflow template`)
2764
+ .show();
2765
+
2766
+ // trayBody.i18n();
2767
+ finishedBuilding = true;
2768
+ },
2769
+ close: function () {
2770
+ if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
2771
+ RED.view.state(RED.state.DEFAULT);
2772
+ }
2773
+ RED.sidebar.info.refresh(editing_node);
2774
+ RED.workspaces.refresh();
2775
+ subflowEditor.destroy();
2776
+ subflowEditor = null;
2777
+ editStack.pop();
2778
+ editing_node = null;
2779
+ },
2780
+ show: function () {},
2781
+ };
2782
+ RED.tray.show(trayOptions);
2783
+ }
2784
+
2785
+ function showTypeEditor(type, options) {
2786
+ if (customEditTypes.hasOwnProperty(type)) {
2787
+ if (editStack.length > 0) {
2788
+ options.parent = editStack[editStack.length - 1].id;
2789
+ }
2790
+ editStack.push({ type: type });
2791
+ options.title = options.title || getEditStackTitle();
2792
+ options.onclose = function () {
2793
+ editStack.pop();
2794
+ };
2795
+ customEditTypes[type].show(options);
2796
+ } else {
2797
+ console.log('Unknown type editor:', type);
2798
+ }
2799
+ }
2800
+
2801
+ function createEditor(options) {
2802
+ var el = options.element || $('#' + options.id)[0];
2803
+ var toolbarRow = $('<div>').appendTo(el);
2804
+ el = $('<div>').appendTo(el).addClass('node-text-editor-container')[0];
2805
+ var editor = ace.edit(el);
2806
+ editor.setTheme('ace/theme/tomorrow');
2807
+ var session = editor.getSession();
2808
+
2809
+ session.on('changeAnnotation', function () {
2810
+ var annotations = session.getAnnotations() || [];
2811
+ var i = annotations.length;
2812
+ var len = annotations.length;
2813
+ while (i--) {
2814
+ if (/doctype first\. Expected/.test(annotations[i].text)) {
2815
+ annotations.splice(i, 1);
2816
+ } else if (
2817
+ /Unexpected End of file\. Expected/.test(annotations[i].text)
2818
+ ) {
2819
+ annotations.splice(i, 1);
2820
+ }
2821
+ }
2822
+ if (len > annotations.length) {
2823
+ session.setAnnotations(annotations);
2824
+ }
2825
+ });
2826
+ if (options.mode) {
2827
+ session.setMode(options.mode);
2828
+ }
2829
+ if (options.foldStyle) {
2830
+ session.setFoldStyle(options.foldStyle);
2831
+ } else {
2832
+ session.setFoldStyle('markbeginend');
2833
+ }
2834
+ if (options.options) {
2835
+ editor.setOptions(options.options);
2836
+ } else {
2837
+ editor.setOptions({
2838
+ enableBasicAutocompletion: true,
2839
+ enableSnippets: true,
2840
+ tooltipFollowsMouse: false,
2841
+ });
2842
+ }
2843
+ if (options.readOnly) {
2844
+ editor.setOption('readOnly', options.readOnly);
2845
+ editor.container.classList.add('ace_read-only');
2846
+ }
2847
+ if (options.hasOwnProperty('lineNumbers')) {
2848
+ editor.renderer.setOption('showGutter', options.lineNumbers);
2849
+ }
2850
+ editor.$blockScrolling = Infinity;
2851
+ if (options.value) {
2852
+ session.setValue(options.value, -1);
2853
+ }
2854
+ if (options.globals) {
2855
+ setTimeout(function () {
2856
+ if (!!session.$worker) {
2857
+ session.$worker.send('setOptions', [
2858
+ {
2859
+ globals: options.globals,
2860
+ esversion: 6,
2861
+ sub: true,
2862
+ asi: true,
2863
+ maxerr: 1000,
2864
+ },
2865
+ ]);
2866
+ }
2867
+ }, 100);
2868
+ }
2869
+ if (options.mode === 'ace/mode/markdown') {
2870
+ $(el).addClass('node-text-editor-container-toolbar');
2871
+ console.log('[editor] options', options);
2872
+
2873
+ if (options.toolbar === false ){
2874
+ // do not show the toolbar
2875
+ } else {
2876
+ editor.toolbar = customEditTypes['_markdown'].buildToolbar(
2877
+ toolbarRow,
2878
+ editor
2879
+ );
2880
+ }
2881
+
2882
+
2883
+ if (options.expandable !== false) {
2884
+ // var previewButton = $(
2885
+ // '<button type="button" class="editor-button md-option" style="float: right; outline: none">Preview</button>'
2886
+ // ).appendTo(editor.toolbar);
2887
+
2888
+ // previewButton.click(function (e) {
2889
+ // e.preventDefault();
2890
+ // let $this = $(e.currentTarget); // handle to the preview button
2891
+ // $('.node-text-editor-preview').html(marked(editor.getValue()));
2892
+ // clickPreview($this);
2893
+ // });
2894
+ }
2895
+ // var helpButton = $(
2896
+ // '<button type="button" class="node-text-editor-help editor-button editor-button-small"><i class="fa fa-question"></i></button>'
2897
+ // ).appendTo($(el).parent());
2898
+ // RED.popover.create({
2899
+ // target: helpButton,
2900
+ // trigger: 'click',
2901
+ // size: 'small',
2902
+ // direction: 'left',
2903
+ // content: 'Formatted with markdown',
2904
+ // autoClose: 50,
2905
+ // });
2906
+ }
2907
+ if (options.onChange){
2908
+ session.on("change", function(delta){
2909
+ options.onChange(delta);
2910
+ })
2911
+ }
2912
+ return editor;
2913
+ }
2914
+
2915
+ function clickPreview(previewButton) {
2916
+ let previewShow = previewButton.hasClass('buttonSelected');
2917
+ if (previewShow) {
2918
+ // editor part
2919
+ $('.node-text-editor-row').height('100%');
2920
+ $('.node-text-editor-container').show();
2921
+ // $('.node-text-editor-help').show(); -- this is the question mark on the bottom right. No need for the time being
2922
+
2923
+ // preview part
2924
+ $('.node-text-editor-preview').hide();
2925
+
2926
+ // toolbar part
2927
+ $('.md-option').show();
2928
+ previewButton.html('Preview');
2929
+ previewButton.removeClass('buttonSelected');
2930
+ } else {
2931
+ // editor part
2932
+ $('.node-text-editor-row').height('35px'); // hack to show only the toolbar, but hiding the rest of the editor.
2933
+ $('.node-text-editor-container').hide();
2934
+ $('.node-text-editor-help').hide();
2935
+
2936
+ // preview part
2937
+ $('.node-text-editor-preview').show();
2938
+
2939
+ // toolbar part
2940
+ $('.md-option').hide();
2941
+ previewButton.html('Hide Preview');
2942
+ previewButton.addClass('buttonSelected');
2943
+ }
2944
+ }
2945
+
2946
+ return {
2947
+ init: function () {
2948
+ RED.tray.init();
2949
+ RED.actions.add('core:confirm-edit-tray', function () {
2950
+ // console.log('[editor] core:confirm-editor-tray -- invoked!!!')
2951
+ $('#node-dialog-ok').click();
2952
+ $('#node-config-dialog-ok').click();
2953
+ });
2954
+ RED.actions.add('core:cancel-edit-tray', function () {
2955
+ $('#node-dialog-cancel').click();
2956
+ $('#node-config-dialog-cancel').click();
2957
+ });
2958
+ },
2959
+ edit: showEditDialog,
2960
+ editConfig: showEditConfigNodeDialog,
2961
+ editSubflow: showEditSubflowDialog,
2962
+ editJavaScript: function (options) {
2963
+ showTypeEditor('_js', options);
2964
+ },
2965
+ editExpression: function (options) {
2966
+ showTypeEditor('_expression', options);
2967
+ },
2968
+ editJSON: function (options) {
2969
+ showTypeEditor('_json', options);
2970
+ },
2971
+ editMarkdown: function (options) {
2972
+ showTypeEditor('_markdown', options);
2973
+ },
2974
+ editBuffer: function (options) {
2975
+ showTypeEditor('_buffer', options);
2976
+ },
2977
+ editText: function(options){
2978
+ showTypeEditor('_string', options);
2979
+ },
2980
+ buildEditForm: buildEditForm,
2981
+ validateNode: validateNode,
2982
+ updateNodeProperties: updateNodeProperties, // TODO: only exposed for edit-undo
2983
+
2984
+ /**
2985
+ * Show a type editor.
2986
+ * @param {string} type - the type to display
2987
+ * @param {object} options - options for the editor
2988
+ * @function
2989
+ * @memberof RED.editor
2990
+ */
2991
+ showTypeEditor: showTypeEditor,
2992
+
2993
+ /**
2994
+ * Register a type editor.
2995
+ * @param {string} type - the type name
2996
+ * @param {object} options - the editor definition
2997
+ * @function
2998
+ * @memberof RED.editor
2999
+ */
3000
+ registerTypeEditor: function (type, definition) {
3001
+ customEditTypes[type] = definition;
3002
+ },
3003
+
3004
+ /**
3005
+ * Create a editor ui component
3006
+ * @param {object} options - the editor options
3007
+ * @function
3008
+ * @memberof RED.editor
3009
+ */
3010
+ createEditor: createEditor,
3011
+
3012
+ getLatestNodeSelected: getLatestNodeSelected,
3013
+
3014
+ notifyChanges: notifyChanges,
3015
+
3016
+ resetEditor: resetEditor,
3017
+ forceNotifyChanges: forceNotifyChanges
3018
+
3019
+ };
3020
+ })();