@maddytp/node-red-dashboard-2-ui-reef
Version:
Set of UI nodes for aquarium automation based on @flowfuse/node-red-dashboard
201 lines (199 loc) • 10.2 kB
HTML
<script type="text/javascript">
RED.nodes.registerType('ui-input', {
category: 'ui reef',
color: 'rgb( 63, 173, 181)',
defaults: {
name: { value: '' },
group: { type: 'ui-group', required: true },
order: { value: 0 },
width: {
value: 6,
validate: function (v) {
const width = v || 0
const currentGroup = $('#node-input-group').val() || this.group
const groupNode = RED.nodes.node(currentGroup)
const valid = !groupNode || +width <= +groupNode.width
$('#node-input-size').toggleClass('input-error', !valid)
return valid
}
},
height: { value: 1 },
label: { value: 'input' },
stateField: { value: 'payload', required: true },
useThemeColors: { value: true },
options: {
value: [],
validate: function (v) {
const unique = new Set(v.map(function (o) { return o.value; }));
return v.length === unique.size && v.length > 1;
},
},
},
inputs: 1,
outputs: 1,
icon: 'font-awesome/fa-long-arrow-right',
align: 'left',
paletteLabel: 'input',
label: function () { return this.name || (!this.label.indexOf('{{') ? null : this.label) || 'input'; },
labelStyle: function () { return (this.name ? 'node_label_italic' : ''); },
oneditprepare: function () {
if (RED.nodes.subflow(this.z)) {
// change inputs from hidden to text & display them
$('#node-input-width').attr('type', 'text')
$('#node-input-height').attr('type', 'text')
$('div.form-row.nr-db-ui-element-sizer-row').hide()
$('div.form-row.nr-db-ui-manual-size-row').show()
} else {
// not in a subflow, use the elementSizer
$('div.form-row.nr-db-ui-element-sizer-row').show()
$('div.form-row.nr-db-ui-manual-size-row').hide()
$('#node-input-size').elementSizer({
width: '#node-input-width',
height: '#node-input-height',
group: '#node-input-group'
})
}
this.useThemeColors = this.useThemeColors ?? true
function getColor(idx) {
const colors = ['#009933', '#999999', '#ff6666', '#009999', '#cccc00', '#ff33cc', '#cc6600',
'#99ff66', '#660033',
];
if (idx > colors.length - 1) {
return colors[Math.floor(Math.random() * colors.length)];
}
return colors[idx];
}
const optionsList = $('#node-input-opts-container').css('min-height', '200px').editableList({
header: $('<div>').css({ 'padding-left': '32px', 'padding-right': '32px', gap: '12px', display: 'flex' }).append($.parseHTML(
"<div style='width:40%; display: inline-grid'><b>Label</b></div>"
+ "<div style='width:40%; display: inline-grid'><b>Value</b></div>"
+ "<div style='width:10%; display: inline-grid' class='node-input-option-color'><b>Color</b></div>",
)),
addItem: function (container, i, option) {
const row = $('<div/>').appendTo(container);
const labelField = $('<input/>', { class: 'node-input-option-label', type: 'text' }).css({ width: '40%', 'margin-left': '5px', 'margin-right': '5px' }).appendTo(row);
labelField.val(option.label || 'Option ' + i);
const valueField = $('<input/>', { class: 'node-input-option-value', type: 'text' }).css({ width: '40%', 'margin-left': '5px', 'margin-right': '5px' }).appendTo(row);
valueField.typedInput({ types: ['str', 'num', 'bool'] });
valueField.typedInput('type', option.valueType || 'str');
valueField.typedInput('value', option.value || 'option_' + i);
valueField.on('change', function (type, value) {
validate();
});
const colofield = $('#node-input-useThemeColors').prop('checked') ? 'none' : 'inline-block'
const colorField = $('<input/>', { class: 'node-input-option-color', type: 'color' }).css({ width: '10%', 'margin-left': '5px', display: colofield }).appendTo(row)
colorField.val(option.color || getColor(i))
validate();
},
removeItem: function (data) {
validate();
},
removable: true,
sortable: true,
});
if (this.options) {
this.options.forEach(function (option, index) {
optionsList.editableList('addItem', {
index: index, label: option.label, value: option.value, valueType: option.valueType, color: option.color,
});
});
}
$('#node-input-useThemeColors').on('change', function () {
const colorFields = $('.node-input-option-color');
if ($(this)[0].checked) {
colorFields.hide();
} else {
colorFields.show();
}
});
$('#node-input-doubleClickZoomEnabled').change();
$('#node-input-stateField').val(this.stateField);
$('#node-input-stateField').typedInput({
types: ['msg'],
default: 'msg',
});
function validate() {
const that = this;
this.options = [];
const optionsList = $('#node-input-opts-container').editableList('items');
optionsList.each(function (i) {
const option = $(this);
const index = i;
const label = option.find('.node-input-option-label').val();
const value = option.find('.node-input-option-value').typedInput('value');
const valueType = option.find('.node-input-option-value').typedInput('type');
const color = option.find('.node-input-option-color').val();
that.options.push({
index: index, label: label, value: value, valueType: valueType, color: color,
});
});
const un = new Set(this.options.map(function (o) { return o.value; }));
if (this.options.length !== un.size) {
$('#configError').text('Values must be unique!');
$('#configError').show();
} else if (this.options.length < 2) {
$('#configError').text('Configure at least two options!');
$('#configError').show();
} else {
$('#configError').hide();
}
}
if (this.options) {
validate();
}
},
oneditsave: function () {
const node = this;
node.options = [];
const optionsList = $('#node-input-opts-container').editableList('items');
optionsList.each(function (i) {
const option = $(this);
const index = i;
const label = option.find('.node-input-option-label').val();
const value = option.find('.node-input-option-value').typedInput('value');
const valueType = option.find('.node-input-option-value').typedInput('type');
const color = option.find('.node-input-option-color').val();
node.options.push({
index, label, value, valueType, color,
});
});
console.log(node.options);
},
});
</script>
<script type="text/html" data-template-name="ui-input">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name"></div>
</div>
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-group"></div>
</div>
<div class="form-row">
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-label"></div>
</div>
<div class="form-row" id="template-row-size">
<label><i class="fa fa-object-group"></i> Size</span></label>
<input type="hidden" id="node-input-width">
<input type="hidden" id="node-input-height">
<button class="editor-button" id="node-input-size"></button>
</div>
<div class="form-row">
<label for="node-input-stateField"><i class="fa fa-toggle-off"></i> Input</label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-stateField"></div>
</div>
<div class="form-row">
<label for='node-input-useThemeColors'><i class='fa fa-paint-brush'></i> Colors</label>
<input type='checkbox' id='node-input-useThemeColors' style='width: auto; border: none; vertical-align: baseline;'>
<span for='node-input-useThemeColors' style="padding-left: 5px;">Use theme colors?</span>
</div>
<div class="form-row" style="margin-bottom:0;">
<label style="width: 100px"><i class="fa fa-list"></i> Options:</label>
<span id="configError" style="color:#DD0000"><b>All Values must be unique.</b></span>
</div>
<div class="form-row">
<ol id="node-input-opts-container"></ol>
</div>
</script>