node-red-contrib-vocalrec
Version:
Nodos personalizados de Node-RED para la API de VocalRec
196 lines (173 loc) • 7.1 kB
HTML
<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>