Timoney, Daniel (dt5972) | 324ee36 | 2017-02-15 10:37:53 -0500 | [diff] [blame^] | 1 | /** |
| 2 | * Copyright 2013, 2014 IBM Corp. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | **/ |
| 16 | RED.editor = (function() { |
| 17 | var editing_node = null; |
| 18 | // TODO: should IMPORT/EXPORT get their own dialogs? |
| 19 | |
| 20 | function getCredentialsURL(nodeType, nodeID) { |
| 21 | var dashedType = nodeType.replace(/\s+/g, '-'); |
| 22 | return 'credentials/' + dashedType + "/" + nodeID; |
| 23 | } |
| 24 | |
| 25 | /** |
| 26 | * Validate a node |
| 27 | * @param node - the node being validated |
| 28 | * @returns {boolean} whether the node is valid. Sets node.dirty if needed |
| 29 | */ |
| 30 | function validateNode(node) { |
| 31 | var oldValue = node.valid; |
| 32 | node.valid = validateNodeProperties(node, node._def.defaults, node); |
| 33 | if (node._def._creds) { |
| 34 | node.valid = node.valid && validateNodeProperties(node, node._def.credentials, node._def._creds); |
| 35 | } |
| 36 | if (oldValue != node.valid) { |
| 37 | node.dirty = true; |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Validate a node's properties for the given set of property definitions |
| 43 | * @param node - the node being validated |
| 44 | * @param definition - the node property definitions (either def.defaults or def.creds) |
| 45 | * @param properties - the node property values to validate |
| 46 | * @returns {boolean} whether the node's properties are valid |
| 47 | */ |
| 48 | function validateNodeProperties(node, definition, properties) { |
| 49 | var isValid = true; |
| 50 | for (var prop in definition) { |
| 51 | if (definition.hasOwnProperty(prop)) { |
| 52 | if (!validateNodeProperty(node, definition, prop, properties[prop])) { |
| 53 | isValid = false; |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | return isValid; |
| 58 | } |
| 59 | |
| 60 | /** |
| 61 | * Validate a individual node property |
| 62 | * @param node - the node being validated |
| 63 | * @param definition - the node property definitions (either def.defaults or def.creds) |
| 64 | * @param property - the property name being validated |
| 65 | * @param value - the property value being validated |
| 66 | * @returns {boolean} whether the node proprty is valid |
| 67 | */ |
| 68 | function validateNodeProperty(node,definition,property,value) { |
| 69 | var valid = true; |
| 70 | if ("required" in definition[property] && definition[property].required) { |
| 71 | valid = value !== ""; |
| 72 | } |
| 73 | if (valid && "validate" in definition[property]) { |
| 74 | valid = definition[property].validate.call(node,value); |
| 75 | } |
| 76 | if (valid && definition[property].type && RED.nodes.getType(definition[property].type) && !("validate" in definition[property])) { |
| 77 | if (!value || value == "_ADD_") { |
| 78 | valid = false; |
| 79 | } else { |
| 80 | var v = RED.nodes.node(value).valid; |
| 81 | valid = (v==null || v); |
| 82 | } |
| 83 | } |
| 84 | return valid; |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * Called when the node's properties have changed. |
| 89 | * Marks the node as dirty and needing a size check. |
| 90 | * Removes any links to non-existant outputs. |
| 91 | * @param node - the node that has been updated |
| 92 | * @returns {array} the links that were removed due to this update |
| 93 | */ |
| 94 | function updateNodeProperties(node) { |
| 95 | node.resize = true; |
| 96 | node.dirty = true; |
| 97 | var removedLinks = []; |
| 98 | if (node.outputs < node.ports.length) { |
| 99 | while (node.outputs < node.ports.length) { |
| 100 | node.ports.pop(); |
| 101 | } |
| 102 | RED.nodes.eachLink(function(l) { |
| 103 | if (l.source === node && l.sourcePort >= node.outputs) { |
| 104 | removedLinks.push(l); |
| 105 | } |
| 106 | }); |
| 107 | for (var l=0;l<removedLinks.length;l++) { |
| 108 | RED.nodes.removeLink(removedLinks[l]); |
| 109 | } |
| 110 | } else if (node.outputs > node.ports.length) { |
| 111 | while (node.outputs > node.ports.length) { |
| 112 | node.ports.push(node.ports.length); |
| 113 | } |
| 114 | } |
| 115 | return removedLinks; |
| 116 | } |
| 117 | |
| 118 | |
| 119 | |
| 120 | $( "#dialog" ).dialog({ |
| 121 | modal: true, |
| 122 | autoOpen: false, |
| 123 | closeOnEscape: false, |
| 124 | width: 500, |
| 125 | buttons: [ |
| 126 | { |
| 127 | id: "node-dialog-ok", |
| 128 | text: "Ok", |
| 129 | click: function() { |
| 130 | if (editing_node) { |
| 131 | var changes = {}; |
| 132 | var changed = false; |
| 133 | var wasDirty = RED.view.dirty(); |
| 134 | var d; |
| 135 | |
| 136 | if (editing_node._def.oneditsave) { |
| 137 | var oldValues = {}; |
| 138 | for (d in editing_node._def.defaults) { |
| 139 | if (editing_node._def.defaults.hasOwnProperty(d)) { |
| 140 | if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") { |
| 141 | oldValues[d] = editing_node[d]; |
| 142 | } else { |
| 143 | oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v; |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | var rc = editing_node._def.oneditsave.call(editing_node); |
| 148 | if (rc === true) { |
| 149 | changed = true; |
| 150 | } |
| 151 | |
| 152 | for (d in editing_node._def.defaults) { |
| 153 | if (editing_node._def.defaults.hasOwnProperty(d)) { |
| 154 | if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") { |
| 155 | if (oldValues[d] !== editing_node[d]) { |
| 156 | changes[d] = oldValues[d]; |
| 157 | changed = true; |
| 158 | } |
| 159 | } else { |
| 160 | if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) { |
| 161 | changes[d] = oldValues[d]; |
| 162 | changed = true; |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | |
| 169 | } |
| 170 | |
| 171 | if (editing_node._def.defaults) { |
| 172 | for (d in editing_node._def.defaults) { |
| 173 | if (editing_node._def.defaults.hasOwnProperty(d)) { |
| 174 | var input = $("#node-input-"+d); |
| 175 | var newValue; |
| 176 | if (input.attr('type') === "checkbox") { |
| 177 | newValue = input.prop('checked'); |
| 178 | } else { |
| 179 | newValue = input.val(); |
| 180 | } |
| 181 | if (newValue != null) { |
| 182 | if (editing_node[d] != newValue) { |
| 183 | if (editing_node._def.defaults[d].type) { |
| 184 | if (newValue == "_ADD_") { |
| 185 | newValue = ""; |
| 186 | } |
| 187 | // Change to a related config node |
| 188 | var configNode = RED.nodes.node(editing_node[d]); |
| 189 | if (configNode) { |
| 190 | var users = configNode.users; |
| 191 | users.splice(users.indexOf(editing_node),1); |
| 192 | } |
| 193 | configNode = RED.nodes.node(newValue); |
| 194 | if (configNode) { |
| 195 | configNode.users.push(editing_node); |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | changes[d] = editing_node[d]; |
| 200 | editing_node[d] = newValue; |
| 201 | changed = true; |
| 202 | } |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | if (editing_node._def.credentials) { |
| 208 | var prefix = 'node-input'; |
| 209 | var credDefinition = editing_node._def.credentials; |
| 210 | var credsChanged = updateNodeCredentials(editing_node,credDefinition,prefix); |
| 211 | changed = changed || credsChanged; |
| 212 | } |
| 213 | |
| 214 | |
| 215 | var removedLinks = updateNodeProperties(editing_node); |
| 216 | if (changed) { |
| 217 | var wasChanged = editing_node.changed; |
| 218 | editing_node.changed = true; |
| 219 | RED.view.dirty(true); |
| 220 | RED.history.push({t:'edit',node:editing_node,changes:changes,links:removedLinks,dirty:wasDirty,changed:wasChanged}); |
| 221 | } |
| 222 | editing_node.dirty = true; |
| 223 | validateNode(editing_node); |
| 224 | RED.view.redraw(); |
| 225 | } else if (RED.view.state() == RED.state.EXPORT) { |
| 226 | if (/library/.test($( "#dialog" ).dialog("option","title"))) { |
| 227 | //TODO: move this to RED.library |
| 228 | var flowName = $("#node-input-filename").val(); |
| 229 | if (!/^\s*$/.test(flowName)) { |
| 230 | $.post('library/flows/'+flowName,$("#node-input-filename").attr('nodes'),function() { |
| 231 | RED.library.loadFlowLibrary(); |
| 232 | RED.notify("Saved nodes","success"); |
| 233 | }); |
| 234 | } |
| 235 | } |
| 236 | } else if (RED.view.state() == RED.state.IMPORT) { |
| 237 | RED.view.importNodes($("#node-input-import").val()); |
| 238 | } |
| 239 | $( this ).dialog( "close" ); |
| 240 | } |
| 241 | }, |
| 242 | { |
| 243 | id: "node-dialog-cancel", |
| 244 | text: "Cancel", |
| 245 | click: function() { |
| 246 | $( this ).dialog( "close" ); |
| 247 | } |
| 248 | } |
| 249 | ], |
| 250 | resize: function(e,ui) { |
| 251 | if (editing_node) { |
| 252 | $(this).dialog('option',"sizeCache-"+editing_node.type,ui.size); |
| 253 | } |
| 254 | }, |
| 255 | open: function(e) { |
| 256 | RED.keyboard.disable(); |
| 257 | if (editing_node) { |
| 258 | var size = $(this).dialog('option','sizeCache-'+editing_node.type); |
| 259 | if (size) { |
| 260 | $(this).dialog('option','width',size.width); |
| 261 | $(this).dialog('option','height',size.height); |
| 262 | } |
| 263 | } |
| 264 | }, |
| 265 | close: function(e) { |
| 266 | RED.keyboard.enable(); |
| 267 | |
| 268 | if (RED.view.state() != RED.state.IMPORT_DRAGGING) { |
| 269 | RED.view.state(RED.state.DEFAULT); |
| 270 | } |
| 271 | $( this ).dialog('option','height','auto'); |
| 272 | $( this ).dialog('option','width','500'); |
| 273 | if (editing_node) { |
| 274 | RED.sidebar.info.refresh(editing_node); |
| 275 | } |
| 276 | RED.sidebar.config.refresh(); |
| 277 | editing_node = null; |
| 278 | } |
| 279 | }); |
| 280 | |
| 281 | /** |
| 282 | * Create a config-node select box for this property |
| 283 | * @param node - the node being edited |
| 284 | * @param property - the name of the field |
| 285 | * @param type - the type of the config-node |
| 286 | */ |
| 287 | function prepareConfigNodeSelect(node,property,type) { |
| 288 | var input = $("#node-input-"+property); |
| 289 | var node_def = RED.nodes.getType(type); |
| 290 | |
| 291 | input.replaceWith('<select style="width: 60%;" id="node-input-'+property+'"></select>'); |
| 292 | updateConfigNodeSelect(property,type,node[property]); |
| 293 | var select = $("#node-input-"+property); |
| 294 | select.after(' <a id="node-input-lookup-'+property+'" class="btn"><i class="fa fa-pencil"></i></a>'); |
| 295 | $('#node-input-lookup-'+property).click(function(e) { |
| 296 | showEditConfigNodeDialog(property,type,select.find(":selected").val()); |
| 297 | e.preventDefault(); |
| 298 | }); |
| 299 | var label = ""; |
| 300 | var configNode = RED.nodes.node(node[property]); |
| 301 | if (configNode && node_def.label) { |
| 302 | if (typeof node_def.label == "function") { |
| 303 | label = node_def.label.call(configNode); |
| 304 | } else { |
| 305 | label = node_def.label; |
| 306 | } |
| 307 | } |
| 308 | input.val(label); |
| 309 | } |
| 310 | |
| 311 | /** |
| 312 | * Populate the editor dialog input field for this property |
| 313 | * @param node - the node being edited |
| 314 | * @param property - the name of the field |
| 315 | * @param prefix - the prefix to use in the input element ids (node-input|node-config-input) |
| 316 | */ |
| 317 | function preparePropertyEditor(node,property,prefix) { |
| 318 | var input = $("#"+prefix+"-"+property); |
| 319 | if (input.attr('type') === "checkbox") { |
| 320 | input.prop('checked',node[property]); |
| 321 | } else { |
| 322 | var val = node[property]; |
| 323 | if (val == null) { |
| 324 | val = ""; |
| 325 | } |
| 326 | input.val(val); |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Add an on-change handler to revalidate a node field |
| 332 | * @param node - the node being edited |
| 333 | * @param definition - the definition of the node |
| 334 | * @param property - the name of the field |
| 335 | * @param prefix - the prefix to use in the input element ids (node-input|node-config-input) |
| 336 | */ |
| 337 | function attachPropertyChangeHandler(node,definition,property,prefix) { |
| 338 | $("#"+prefix+"-"+property).change(function() { |
| 339 | if (!validateNodeProperty(node, definition, property,this.value)) { |
| 340 | $(this).addClass("input-error"); |
| 341 | } else { |
| 342 | $(this).removeClass("input-error"); |
| 343 | } |
| 344 | }); |
| 345 | } |
| 346 | |
| 347 | /** |
| 348 | * Assign the value to each credential field |
| 349 | * @param node |
| 350 | * @param credDef |
| 351 | * @param credData |
| 352 | * @param prefix |
| 353 | */ |
| 354 | function populateCredentialsInputs(node, credDef, credData, prefix) { |
| 355 | var cred; |
| 356 | for (cred in credDef) { |
| 357 | if (credDef.hasOwnProperty(cred)) { |
| 358 | if (credDef[cred].type == 'password') { |
| 359 | if (credData[cred]) { |
| 360 | $('#' + prefix + '-' + cred).val(credData[cred]); |
| 361 | } else if (credData['has_' + cred]) { |
| 362 | $('#' + prefix + '-' + cred).val('__PWRD__'); |
| 363 | } |
| 364 | else { |
| 365 | $('#' + prefix + '-' + cred).val(''); |
| 366 | } |
| 367 | } else { |
| 368 | preparePropertyEditor(credData, cred, prefix); |
| 369 | } |
| 370 | attachPropertyChangeHandler(node, credDef, cred, prefix); |
| 371 | } |
| 372 | } |
| 373 | for (cred in credDef) { |
| 374 | if (credDef.hasOwnProperty(cred)) { |
| 375 | $("#" + prefix + "-" + cred).change(); |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | /** |
| 381 | * Update the node credentials from the edit form |
| 382 | * @param node - the node containing the credentials |
| 383 | * @param credDefinition - definition of the credentials |
| 384 | * @param prefix - prefix of the input fields |
| 385 | * @return {boolean} whether anything has changed |
| 386 | */ |
| 387 | function updateNodeCredentials(node, credDefinition, prefix) { |
| 388 | var changed = false; |
| 389 | if(!node.credentials) { |
| 390 | node.credentials = {_:{}}; |
| 391 | } |
| 392 | |
| 393 | for (var cred in credDefinition) { |
| 394 | if (credDefinition.hasOwnProperty(cred)) { |
| 395 | var input = $("#" + prefix + '-' + cred); |
| 396 | var value = input.val(); |
| 397 | if (credDefinition[cred].type == 'password') { |
| 398 | node.credentials['has_' + cred] = (value !== ""); |
| 399 | if (value == '__PWRD__') { |
| 400 | continue; |
| 401 | } |
| 402 | changed = true; |
| 403 | |
| 404 | } |
| 405 | node.credentials[cred] = value; |
| 406 | if (value != node.credentials._[cred]) { |
| 407 | changed = true; |
| 408 | } |
| 409 | } |
| 410 | } |
| 411 | return changed; |
| 412 | } |
| 413 | |
| 414 | /** |
| 415 | * Prepare all of the editor dialog fields |
| 416 | * @param node - the node being edited |
| 417 | * @param definition - the node definition |
| 418 | * @param prefix - the prefix to use in the input element ids (node-input|node-config-input) |
| 419 | */ |
| 420 | function prepareEditDialog(node,definition,prefix) { |
| 421 | for (var d in definition.defaults) { |
| 422 | if (definition.defaults.hasOwnProperty(d)) { |
| 423 | if (definition.defaults[d].type) { |
| 424 | prepareConfigNodeSelect(node,d,definition.defaults[d].type); |
| 425 | } else { |
| 426 | preparePropertyEditor(node,d,prefix); |
| 427 | } |
| 428 | attachPropertyChangeHandler(node,definition.defaults,d,prefix); |
| 429 | } |
| 430 | } |
| 431 | var completePrepare = function() { |
| 432 | if (definition.oneditprepare) { |
| 433 | definition.oneditprepare.call(node); |
| 434 | } |
| 435 | for (var d in definition.defaults) { |
| 436 | if (definition.defaults.hasOwnProperty(d)) { |
| 437 | $("#"+prefix+"-"+d).change(); |
| 438 | } |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | if (definition.credentials) { |
| 443 | if (node.credentials) { |
| 444 | populateCredentialsInputs(node, definition.credentials, node.credentials, prefix); |
| 445 | completePrepare(); |
| 446 | } else { |
| 447 | $.getJSON(getCredentialsURL(node.type, node.id), function (data) { |
| 448 | node.credentials = data; |
| 449 | node.credentials._ = $.extend(true,{},data); |
| 450 | populateCredentialsInputs(node, definition.credentials, node.credentials, prefix); |
| 451 | completePrepare(); |
| 452 | }); |
| 453 | } |
| 454 | } else { |
| 455 | completePrepare(); |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | function showEditDialog(node) { |
| 460 | editing_node = node; |
| 461 | RED.view.state(RED.state.EDITING); |
| 462 | $("#dialog-form").html($("script[data-template-name='"+node.type+"']").html()); |
| 463 | $('<input type="text" style="display: none;" />').appendTo("#dialog-form"); |
| 464 | prepareEditDialog(node,node._def,"node-input"); |
| 465 | $( "#dialog" ).dialog("option","title","Edit "+node.type+" node").dialog( "open" ); |
| 466 | } |
| 467 | |
| 468 | function showEditConfigNodeDialog(name,type,id) { |
| 469 | var adding = (id == "_ADD_"); |
| 470 | var node_def = RED.nodes.getType(type); |
| 471 | |
| 472 | var configNode = RED.nodes.node(id); |
| 473 | if (configNode == null) { |
| 474 | configNode = { |
| 475 | id: (1+Math.random()*4294967295).toString(16), |
| 476 | _def: node_def, |
| 477 | type: type |
| 478 | } |
| 479 | for (var d in node_def.defaults) { |
| 480 | if (node_def.defaults[d].value) { |
| 481 | configNode[d] = node_def.defaults[d].value; |
| 482 | } |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | $("#dialog-config-form").html($("script[data-template-name='"+type+"']").html()); |
| 487 | prepareEditDialog(configNode,node_def,"node-config-input"); |
| 488 | |
| 489 | var buttons = $( "#node-config-dialog" ).dialog("option","buttons"); |
| 490 | if (adding) { |
| 491 | if (buttons.length == 3) { |
| 492 | buttons = buttons.splice(1); |
| 493 | } |
| 494 | buttons[0].text = "Add"; |
| 495 | $("#node-config-dialog-user-count").html("").hide(); |
| 496 | } else { |
| 497 | if (buttons.length == 2) { |
| 498 | buttons.unshift({ |
| 499 | class: 'leftButton', |
| 500 | text: "Delete", |
| 501 | click: function() { |
| 502 | var configProperty = $(this).dialog('option','node-property'); |
| 503 | var configId = $(this).dialog('option','node-id'); |
| 504 | var configType = $(this).dialog('option','node-type'); |
| 505 | var configNode = RED.nodes.node(configId); |
| 506 | var configTypeDef = RED.nodes.getType(configType); |
| 507 | |
| 508 | if (configTypeDef.ondelete) { |
| 509 | configTypeDef.ondelete.call(RED.nodes.node(configId)); |
| 510 | } |
| 511 | RED.nodes.remove(configId); |
| 512 | for (var i=0;i<configNode.users.length;i++) { |
| 513 | var user = configNode.users[i]; |
| 514 | for (var d in user._def.defaults) { |
| 515 | if (user._def.defaults.hasOwnProperty(d) && user[d] == configId) { |
| 516 | user[d] = ""; |
| 517 | } |
| 518 | } |
| 519 | validateNode(user); |
| 520 | } |
| 521 | updateConfigNodeSelect(configProperty,configType,""); |
| 522 | RED.view.dirty(true); |
| 523 | $( this ).dialog( "close" ); |
| 524 | RED.view.redraw(); |
| 525 | } |
| 526 | }); |
| 527 | } |
| 528 | buttons[1].text = "Update"; |
| 529 | $("#node-config-dialog-user-count").html(configNode.users.length+" node"+(configNode.users.length==1?" uses":"s use")+" this config").show(); |
| 530 | } |
| 531 | $( "#node-config-dialog" ).dialog("option","buttons",buttons); |
| 532 | |
| 533 | $( "#node-config-dialog" ) |
| 534 | .dialog("option","node-adding",adding) |
| 535 | .dialog("option","node-property",name) |
| 536 | .dialog("option","node-id",configNode.id) |
| 537 | .dialog("option","node-type",type) |
| 538 | .dialog("option","title",(adding?"Add new ":"Edit ")+type+" config node") |
| 539 | .dialog( "open" ); |
| 540 | } |
| 541 | |
| 542 | function updateConfigNodeSelect(name,type,value) { |
| 543 | var select = $("#node-input-"+name); |
| 544 | var node_def = RED.nodes.getType(type); |
| 545 | select.children().remove(); |
| 546 | RED.nodes.eachConfig(function(config) { |
| 547 | if (config.type == type) { |
| 548 | var label = ""; |
| 549 | if (typeof node_def.label == "function") { |
| 550 | label = node_def.label.call(config); |
| 551 | } else { |
| 552 | label = node_def.label; |
| 553 | } |
| 554 | select.append('<option value="'+config.id+'"'+(value==config.id?" selected":"")+'>'+label+'</option>'); |
| 555 | } |
| 556 | }); |
| 557 | |
| 558 | select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>Add new '+type+'...</option>'); |
| 559 | window.setTimeout(function() { select.change();},50); |
| 560 | } |
| 561 | |
| 562 | $( "#node-config-dialog" ).dialog({ |
| 563 | modal: true, |
| 564 | autoOpen: false, |
| 565 | width: 500, |
| 566 | closeOnEscape: false, |
| 567 | buttons: [ |
| 568 | { |
| 569 | id: "node-config-dialog-ok", |
| 570 | text: "Ok", |
| 571 | click: function() { |
| 572 | var configProperty = $(this).dialog('option','node-property'); |
| 573 | var configId = $(this).dialog('option','node-id'); |
| 574 | var configType = $(this).dialog('option','node-type'); |
| 575 | var configAdding = $(this).dialog('option','node-adding'); |
| 576 | var configTypeDef = RED.nodes.getType(configType); |
| 577 | var configNode; |
| 578 | var d; |
| 579 | |
| 580 | if (configAdding) { |
| 581 | configNode = {type:configType,id:configId,users:[]}; |
| 582 | for (d in configTypeDef.defaults) { |
| 583 | if (configTypeDef.defaults.hasOwnProperty(d)) { |
| 584 | configNode[d] = $("#node-config-input-"+d).val(); |
| 585 | } |
| 586 | } |
| 587 | configNode.label = configTypeDef.label; |
| 588 | configNode._def = configTypeDef; |
| 589 | RED.nodes.add(configNode); |
| 590 | updateConfigNodeSelect(configProperty,configType,configNode.id); |
| 591 | } else { |
| 592 | configNode = RED.nodes.node(configId); |
| 593 | for (d in configTypeDef.defaults) { |
| 594 | if (configTypeDef.defaults.hasOwnProperty(d)) { |
| 595 | var input = $("#node-config-input-"+d); |
| 596 | if (input.attr('type') === "checkbox") { |
| 597 | configNode[d] = input.prop('checked'); |
| 598 | } else { |
| 599 | configNode[d] = input.val(); |
| 600 | } |
| 601 | } |
| 602 | } |
| 603 | updateConfigNodeSelect(configProperty,configType,configId); |
| 604 | } |
| 605 | if (configTypeDef.credentials) { |
| 606 | updateNodeCredentials(configNode,configTypeDef.credentials,"node-config-input"); |
| 607 | } |
| 608 | if (configTypeDef.oneditsave) { |
| 609 | configTypeDef.oneditsave.call(RED.nodes.node(configId)); |
| 610 | } |
| 611 | validateNode(configNode); |
| 612 | |
| 613 | RED.view.dirty(true); |
| 614 | $(this).dialog("close"); |
| 615 | |
| 616 | } |
| 617 | }, |
| 618 | { |
| 619 | id: "node-config-dialog-cancel", |
| 620 | text: "Cancel", |
| 621 | click: function() { |
| 622 | var configType = $(this).dialog('option','node-type'); |
| 623 | var configId = $(this).dialog('option','node-id'); |
| 624 | var configAdding = $(this).dialog('option','node-adding'); |
| 625 | var configTypeDef = RED.nodes.getType(configType); |
| 626 | |
| 627 | if (configTypeDef.oneditcancel) { |
| 628 | // TODO: what to pass as this to call |
| 629 | if (configTypeDef.oneditcancel) { |
| 630 | var cn = RED.nodes.node(configId); |
| 631 | if (cn) { |
| 632 | configTypeDef.oneditcancel.call(cn,false); |
| 633 | } else { |
| 634 | configTypeDef.oneditcancel.call({id:configId},true); |
| 635 | } |
| 636 | } |
| 637 | } |
| 638 | $( this ).dialog( "close" ); |
| 639 | } |
| 640 | } |
| 641 | ], |
| 642 | resize: function(e,ui) { |
| 643 | }, |
| 644 | open: function(e) { |
| 645 | if (RED.view.state() != RED.state.EDITING) { |
| 646 | RED.keyboard.disable(); |
| 647 | } |
| 648 | }, |
| 649 | close: function(e) { |
| 650 | $("#dialog-config-form").html(""); |
| 651 | if (RED.view.state() != RED.state.EDITING) { |
| 652 | RED.keyboard.enable(); |
| 653 | } |
| 654 | RED.sidebar.config.refresh(); |
| 655 | } |
| 656 | }); |
| 657 | |
| 658 | |
| 659 | return { |
| 660 | edit: showEditDialog, |
| 661 | editConfig: showEditConfigNodeDialog, |
| 662 | validateNode: validateNode, |
| 663 | updateNodeProperties: updateNodeProperties // TODO: only exposed for edit-undo |
| 664 | } |
| 665 | })(); |