UNPKG

node-red-contrib-vocalrec

Version:

Nodos personalizados de Node-RED para la API de VocalRec

196 lines (173 loc) 7.1 kB
<script type="text/javascript"> RED.nodes.registerType('vocalrec-extract-properties', { category: 'VocalRec', color: '#cae2c9', inputs: 1, outputs: 1, icon: "icons/logo-vr.png", label: function () { return this.name || "extract properties"; }, paletteLabel: "Extract properties", defaults: { name: { value: "" }, mappings: { value: [], validate: function(v) { if (!Array.isArray(v)) return false; for (var i = 0; i < v.length; i++) { if (!v[i].dest || !v[i].source) { return "Todos los mapeos deben tener propiedad destino y origen"; } } return true; } } }, oneditprepare: function() { var node = this; function resizeDialog(size) { size = size || { height: $(".red-ui-tray-content form").height() } var rows = $("#dialog-form>div:not(.node-input-mapping-container-row):visible"); var height = size.height; for (var i = 0; i < rows.length; i++) { height -= $(rows[i]).outerHeight(true); } var editorRow = $("#dialog-form>div.node-input-mapping-container-row"); height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom"))); height += 16; $("#node-input-mapping-container").editableList('height', height); } var mappingList = $('#node-input-mapping-container').css('min-height', '150px').css('min-width', '450px'); mappingList.editableList({ addItem: function(container, i, opt) { var mapping = opt; if (!mapping.hasOwnProperty('dest')) { mapping = { dest: "", source: "" }; } var row = $('<div/>').css({ display: 'flex', alignItems: 'center', gap: '6px' }).appendTo(container); // Campo para propiedad destino con typedInput var destInput = $('<input/>', { class: "node-input-mapping-dest", type: "text" }) .css("width", "45%") .appendTo(row) .typedInput({ default: 'msg', types: ['msg'] }); destInput.typedInput('value', mapping.dest); // Separador $('<div/>', { style: 'display:inline-block; padding:0px 6px;' }) .text('←') .appendTo(row); // Campo para propiedad origen con typedInput var sourceInput = $('<input/>', { class: "node-input-mapping-source", type: "text" }) .css("width", "calc(100% - 5px)") .appendTo(row) .typedInput({ default: 'msg', types: ['msg'] }); sourceInput.typedInput('value', mapping.source); }, removable: true, sortable: true }); // Cargar mappings existentes if (node.mappings && node.mappings.length > 0) { for (var i = 0; i < node.mappings.length; i++) { mappingList.editableList('addItem', node.mappings[i]); } } else { // Agregar un mapeo por defecto mappingList.editableList('addItem', { dest: "", source: "" }); } // Función para redimensionar node.oneditresize = resizeDialog; }, oneditsave: function() { var mappings = []; var items = $("#node-input-mapping-container").editableList('items'); items.each(function(i) { var mapping = $(this); var dest = mapping.find(".node-input-mapping-dest").typedInput('value'); var source = mapping.find(".node-input-mapping-source").typedInput('value'); if (dest && source) { mappings.push({ dest: dest, source: source }); } }); this.mappings = mappings; }, oneditresize: function(size) { // Se define en oneditprepare } }); </script> <script type="text/html" data-template-name="vocalrec-extract-properties"> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> Nombre</label> <input type="text" id="node-input-name" placeholder="Nombre del nodo"> </div> <div class="form-row node-input-mapping-container-row"> <label><i class="fa fa-list"></i> Mapeo de propiedades</label> <ol id="node-input-mapping-container"></ol> </div> </script> <script type="text/html" data-help-name="vocalrec-extract-properties"> <p>Extrae propiedades específicas del objeto <code>msg</code> y las asigna a propiedades específicas del mensaje de salida.</p> <h3>Configuración</h3> <p>Define mapeos entre propiedades de origen y destino:</p> <ul> <li><strong>Propiedad destino:</strong> La ruta en msg donde se guardará el valor (ej: msg.payload.nombre, msg.data.usuario)</li> <li><strong>Propiedad origen:</strong> La ruta a la propiedad en el objeto msg usando typedInput</li> </ul> <h3>Ejemplo</h3> <p>Si el mensaje de entrada es:</p> <pre> { "payload": { "user": { "name": "Juan", "email": "juan@email.com" }, "timestamp": "2024-01-01" }, "topic": "usuarios" } </pre> <p>Y configuras los mapeos:</p> <ul> <li>msg.payload.nombre ← msg.payload.user.name</li> <li>msg.payload.correo ← msg.payload.user.email</li> <li>msg.data.fecha ← msg.payload.timestamp</li> <li>msg.customTopic ← msg.topic</li> </ul> <p>El mensaje de salida será:</p> <pre> { "payload": { "user": { ... }, // datos originales "timestamp": "2024-01-01", "nombre": "Juan", "correo": "juan@email.com" }, "data": { "fecha": "2024-01-01" }, "topic": "usuarios", "customTopic": "usuarios" } </pre> </script>