node-red-contrib-sun-position
Version:
NodeRED nodes to get sun and moon position
875 lines (804 loc) • 62.5 kB
HTML
<!DOCTYPE HTML>
<!--
This code is licensed under the Apache License Version 2.0.
Copyright (c) 2022 Robert Gester
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
-->
<script type="text/javascript">
(function() {
const preassignedSunPositions = ['solarNoon','nadir',
'goldenHourDawnEnd', 'goldenHourDuskStart',
'sunriseEnd', 'sunsetStart',
'sunriseStart', 'sunsetEnd',
'goldenHourDawnStart', 'goldenHourDuskEnd',
'blueHourDawnEnd', 'blueHourDuskStart',
'civilDawn', 'civilDusk',
'blueHourDawnStart', 'blueHourDuskEnd',
'nauticalDawn', 'nauticalDusk',
'amateurDawn', 'amateurDusk',
'astronomicalDawn', 'astronomicalDusk'];
RED.nodes.registerType('position-config', {
category: 'config',
credentials: {
posLatitude: {
type: 'text',
value: '',
required: true,
validate(v){
const n = Number(v);
return RED.validators.number()(v) && ((n >= -90) && (n <= 90));
}
},
posLongitude: {
type: 'text',
value: '',
required: true,
validate(v){
const n = Number(v);
return RED.validators.number()(v) && ((n >= -180) && (n <= 180));
}
},
height: {
type: 'text',
value: '0',
required: false,
validate(v){
return (v === '') || RED.validators.number()(v);
}
}
},
defaults: {
name: {
value: '',
required: false
},
isValide: {
value: false,
required: true,
validate(v){
return (v === true) || (v === 'true');
}
},
longitude: {value: '' },
latitude: {value: ''},
angleType: {
value: 'deg',
required: true,
validate(v){
return (v === 'rad' || v === 'deg');
}
},
timeZoneOffset: {
value: 99
},
timeZoneDST: {
value: 0
},
stateTimeFormat: {
value: 3 // 3 - date.toLocaleTimeString()
},
stateDateFormat: {
value: 12 // 12 - date.toLocaleDateString()
},
contextStore: {value: ''},
sunPositions: {
value: [],
validate(v) {
if (v && (v.length > 0)) {
const EXP = /^(?![0-9])[a-zA-Z0-9$_]+$/;
const names = preassignedSunPositions.slice();
let valid = true;
// check for invalid names
for (let i=0; i<v.length; ++i) {
if (!EXP.test(v[i].riseName) ||
!EXP.test(v[i].setName) ||
!RED.validators.number()(v[i].angle) ||
isNaN(v[i].angle) ||
typeof v[i].angle !== 'number') {
valid = false;
break;
}
names.push(v[i].riseName);
names.push(v[i].setName);
if (hasDuplicates(names)) {
valid = false;
break;
}
}
return valid;
}
return true;
/** check array for duplicates */
function hasDuplicates(arr) {
return arr.some(item => {
return (arr.indexOf(item) !== arr.lastIndexOf(item));
});
}
}
},
predefAngles: {
value: [],
validate(v) {
if (v && (v.length > 0)) {
const EXP = /^[0-9a-zA-Z_\s]+$/;
let valid = true;
const names = [];
// check for invalid names
for (let i=0; i<v.length; ++i) {
if (!EXP.test(v[i].name) ||
!RED.validators.number()(v[i].angle) ||
isNaN(v[i].angle) ||
typeof v[i].angle !== 'number') {
valid = false;
break;
}
if (names.includes(v[i].name)) {
valid = false;
break;
}
names.push(v[i].name);
}
return valid;
}
return true;
}
}
},
label() {
return this.name || 'timeControl';
},
oneditprepare() {
setTimeout(() => {
$('.is-to-show-initially').show();
$('.is-to-hide-initially').hide();
}, 300);
$('#node-config-map-row').hide();
const node = this;
const validateCoords = function(_event, _ui) {
const val = $(this).spinner('value');
if (/^(\+|-)?\d+(\.\d+)?$/.test(val)) {
const value = parseFloat($(this).spinner('value'));
const min = $(this).spinner('option', 'min');
const max = $(this).spinner('option', 'max');
if (value < min) {
$(this).spinner('value', min);
} else if (value > max) {
$(this).spinner('value', max);
}
} else {
$(this).spinner('value', 0);
}
coordChanged();
};
const $nodeInputContextStore = $('#node-config-input-contextStore');
RED.settings.context.stores.forEach(store => {
$nodeInputContextStore.append('<option value="' + store + '"' + (this.contextStore === store ? ' selected' : '') + '>' + store + '</option>');
});
let tsOffset = parseInt($('#node-config-input-timeZoneOffset').val());
if (isNaN(tsOffset) || tsOffset >= 99 || tsOffset <= -99) {
this.timeZoneOffset = 99;
$('#node-config-input-timeZoneOffset').val(99);
tsOffset = 99;
}
const tsDST = parseInt($('#node-config-input-timeZoneOffset').val());
if (isNaN(tsDST) || tsDST >= 99 || tsDST <= -99) {
this.timeZoneDST = 0;
$('#node-config-input-timeZoneDST').val(0);
}
$('#node-config-input-timeZoneOffset').on('change focus focusin focusout', () => {
const tsOffset = parseInt($('#node-config-input-timeZoneOffset').val());
if (tsOffset === 99 || isNaN(tsOffset) || tsOffset >= 99 || tsOffset <= -99) {
$('#node-config-input-timeZoneOffset').val(99);
$('#node-config-input-timeZoneDST').attr('disabled', true);
$('.row-timeZoneDST').hide();
} else {
$('.row-timeZoneDST').show();
$('#node-config-input-timeZoneDST').attr('disabled', false);
}
});
$('#node-config-input-timeZoneOffset').change();
$('#node-config-input-isValide').val(false);
const $lat = $('#node-config-input-posLatitude');
const $lon = $('#node-config-input-posLongitude');
const $height = $('#node-config-input-height');
let latVal = parseFloat($lat.val());
let lonVal = parseFloat($lon.val());
const coordChanged = (_type, _value) => {
const lat = $('#node-config-input-posLatitude').val();
const lon = $('#node-config-input-posLongitude').val();
const isValid = !isNaN(lat) && !isNaN(lon) && (lat !== '') && (lon !== '') && (lat !== 0) && (lon !== 0);
$('#node-config-input-isValide').val(isValid);
if (isValid) {
$('#node-config-map-row').show();
const clat = parseFloat(lat);
const clon = parseFloat(lon);
$('#node-config-map-content').attr('src', `https://www.openstreetmap.org/export/embed.html?bbox=${(clon-0.004).toFixed(14)}%2C${(clat-0.004).toFixed(14)}%2C${(clon+0.004).toFixed(14)}%2C${(clat+0.004).toFixed(14)}&layer=mapnik&marker=${clat.toFixed(14)}%2C${clon.toFixed(14)}`);
$('#node-config-map-link').html(`<a href="https://www.openstreetmap.org/#map=17/${lat}/${lon}" target="_blank">Openstreetmap</a>`);
} else {
$('#node-config-map-row').hide();
}
};
$lat.on('change focus focusin focusout', coordChanged);
$lon.on('change focus focusin focusout', coordChanged);
$lat.spinner({
step: 0.00001,
min: -90,
max: 90,
numberFormat: 'n',
change: validateCoords
});
$lon.spinner({
step: 0.00001,
min: -180,
max: 180,
numberFormat: 'n',
change: validateCoords
});
$height.spinner({
step: 0.00001,
numberFormat: 'n'
});
if ($lat.val() === '' || isNaN(latVal)) {
if (node.longitude !== '' && !isNaN(node.longitude) && node.longitude !== 0) {
$lat.val(node.longitude);
} else {
$lat.val('');
}
latVal = parseFloat($lat.val());
}
if ($lon.val() === '' || isNaN(lonVal)) {
if (node.longitude !== '' && !isNaN(node.longitude) && node.longitude !== 0) {
$lon.val(node.longitude);
} else {
$lon.val('');
}
lonVal = parseFloat($lon.val());
}
if ((($lat.val() === '') || isNaN(latVal) || (latVal === 0)) &&
(($lon.val() === '') || isNaN(lonVal) || (lonVal === 0))) {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(position => {
$lat.val(Number(position.coords.latitude.toFixed(5)));
$lon.val(Number(position.coords.longitude.toFixed(5)));
});
}
}
$lat.change();
$lon.change();
const validateMyAngle = function(_event, _ui) {
const angleValue = $(this).spinner('value');
// Show a red border around the fileName field, when the same file name value is used in multiple input fields
if (isNaN(angleValue) ||
angleValue === null ||
typeof angleValue !== 'number' ||
!RED.validators.number()(angleValue)) {
$(this).css('border', '1px solid rgb(214, 97, 95)');
$(this).addClass('input-error');
} else {
if (angleValue < -360) {
$(this).spinner('value', -360);
} else if (angleValue > 720) {
$(this).spinner('value', 720);
}
$(this).css('border', '');
$(this).removeClass('input-error');
}
};
const predefAngleList = $('#node-input-predefAngleList').css('min-width', '500px').css('min-height', '150px')
.editableList({
removable: true,
sortable: true,
addItem(item, index, data) {
const fragment = document.createDocumentFragment();
const $angleLabel = $('<label/>', {class: 'spinner-Small', style: 'width: auto; margin-left: 5px; margin-bottom: 0px;'})
// .html("<i class='fa fa-sun-o' aria-hidden='true'></i> " + node._("position-config.label.angle") + " ")
.text(node._('position-config.label.angle') + ' ')
.appendTo(fragment);
const $angle = $('<input/>', {class: 'node-input-angle', style: 'width: 60px; margin-left: 4px;'})
.appendTo($angleLabel)
.spinner({
step: 0.1,
min: -360,
max: 720,
numberFormat: 'n',
change: validateMyAngle
}).width(60);
const $nameLabel = $('<label/>', {title: node._('position-config.label.name'), style: 'width: auto; margin-left: 12px; margin-bottom: 0px;'})
.html("<i class='fa fa-tag' aria-hidden='true'></i>")
.appendTo(fragment);
const $name = $('<input/>', {type: 'text', class: 'node-input-name', placeholder: node._('position-config.label.name'), style: 'width: 110px; margin-left: 4px;'})
.appendTo($nameLabel);
if (!('angle' in data)) {
data = {angle: 0, name: ''};
}
$name.prop('required',true);
$angle.prop('required',true);
$name.on('change keyup paste', function() {
const angleName = this.value;
// Find all fileName input fields with the same file name value
const angleNameFields = predefAngleList.find('.node-input-name').filter(function() {
return this.value === angleName;
});
// Show a red border around the fileName field, when the same file name value is used in multiple input fields
if (angleNameFields.length > 1 || !(/^[0-9a-zA-Z_\s]+$/.test(angleName))) {
$(this).css('border', '1px solid rgb(214, 97, 95)');
$(this).addClass('input-error');
} else {
$(this).css('border', '');
$(this).removeClass('input-error');
}
});
$angle.spinner('value', data.angle);
$name.val(data.name);
$name.change();
$angle.change();
validateMyAngle.call($angle[0]);
item[0].appendChild(fragment);
}
});
if (!node.predefAngles) { // backward compatibility
node.predefAngles = [];
}
node.predefAngles.forEach(data => {
predefAngleList.editableList('addItem', data);
});
const sunPositionList = $('#node-input-sunPositionList').css('min-width', '500px').css('min-height', '150px').editableList(
{
removable: true,
sortable: true,
addItem(item, index, data) {
const fragment = document.createDocumentFragment();
const $angleLabel = $('<label/>', {class: 'spinner-Small', style: 'width: auto; margin-left: 5px; margin-bottom: 0px;'})
// .html("<i class='fa fa-sun-o' aria-hidden='true'></i> " + node._("position-config.label.angle") + " ")
.text(node._('position-config.label.angle') + ' ')
.appendTo(fragment);
const $angle = $('<input/>', {class: 'node-input-angle', style: 'width: 60px; margin-left: 4px;'})
.appendTo($angleLabel)
.spinner({
step: 0.1,
min: -360,
max: 720,
numberFormat: 'n',
change: validateMyAngle
}).width(60);
const $riseLabel = $('<label/>', {title: node._('position-config.label.riseName'), style: 'width: auto; margin-left: 12px; margin-bottom: 0px;'})
.html("<i class='fa fa-arrow-up' aria-hidden='true'></i>")
.appendTo(fragment);
const $riseName = $('<input/>', {type: 'text', class: 'node-input-riseName', placeholder: node._('position-config.label.riseName'), style: 'width: 110px; margin-left: 4px;'})
.appendTo($riseLabel);
const $setLabel = $('<label/>', {title: node._('position-config.label.setName'), style: 'width: auto; margin-left: 12px; margin-bottom: 0px;'})
.html("<i class='fa fa-arrow-down' aria-hidden='true'></i>")
.appendTo(fragment);
const $setName = $('<input/>', {type: 'text', class: 'node-input-setName', placeholder: node._('position-config.label.setName'), style: 'width: 110px; margin-left: 4px;'})
.appendTo($setLabel);
if (!('angle' in data)) {
data = {angle: 0, riseName: '', setName: ''};
}
$riseName.prop('required',true);
$setName.prop('required',true);
$angle.prop('required',true);
const validateName = function() {
const angleName = this.value;
// Find all fileName input fields with the same file name value
const riseNameFields = predefAngleList.find('.node-input-riseName').filter(function() {
return this.value === angleName;
});
const setNameFields = predefAngleList.find('.node-input-setName').filter(function() {
return this.value === angleName;
});
// Show a red border around the fileName field, when the same file name value is used in multiple input fields
if (preassignedSunPositions.includes(angleName) ||
riseNameFields.length > 1 ||
setNameFields.length > 1 ||
!(/^(?![0-9])[a-zA-Z0-9$_]+$/.test(angleName))) {
$(this).css('border', '1px solid rgb(214, 97, 95)');
$(this).addClass('input-error');
} else {
$(this).css('border', '');
$(this).removeClass('input-error');
}
};
$riseName.on('change keyup paste', validateName);
$setName.on('change keyup paste', validateName);
$angle.spinner('value', data.angle);
$riseName.val(data.riseName);
$setName.val(data.setName);
$riseName.change();
$setName.change();
$angle.change();
validateMyAngle.call($angle[0]);
item[0].appendChild(fragment);
}
});
if (!node.sunPositions) { // backward compatibility
node.sunPositions = [];
}
node.sunPositions.forEach(data => {
sunPositionList.editableList('addItem', data);
});
const setup = function(_node) {
/* global initCombobox */
initCombobox(node, $('#node-config-input-stateDateFormatSel'), $('#node-config-input-stateDateFormat'), 'dateOutFormat', 'outputFormats', node.stateDateFormat || 12, 50, 'isoDate');
initCombobox(node, $('#node-config-input-stateTimeFormatSel'), $('#node-config-input-stateTimeFormat'), 'dateOutFormat', 'outputFormats', node.stateTimeFormat || 3, 50, 'isoTime');
}; // setup
$.getScript('sun-position/js/htmlglobal.js')
.done((_data, _textStatus, _jqxhr) => {
try {
setup(node);
} catch (err) {
console.log("failed to setup editor"); // eslint-disable-line
console.log(err); // eslint-disable-line
console.log(err.stack); // eslint-disable-line
}
})
.fail((jqxhr, settings, exception) => {
console.log("failed to load htmlglobal.js"); // eslint-disable-line
console.log(exception); // eslint-disable-line
console.log(exception.stack); // eslint-disable-line
});
},
oneditsave() {
delete this.longitude;
delete this.latitude;
const node = this;
const predefAngleList = $('#node-input-predefAngleList').editableList('items');
node.predefAngles = [];
predefAngleList.each(function(_index) {
const data = {};
const angle = $(this).find('.node-input-angle');
const name = $(this).find('.node-input-name');
data.angle = angle.spinner('value');
data.name = name.val();
node.predefAngles.push(data);
});
const sunPositionList = $('#node-input-sunPositionList').editableList('items');
node.sunPositions = [];
sunPositionList.each(function(_index) {
const data = {};
const angle = $(this).find('.node-input-angle');
const riseName = $(this).find('.node-input-riseName');
const setName = $(this).find('.node-input-setName');
data.angle = angle.spinner('value');
data.riseName = riseName.val();
data.setName = setName.val();
node.sunPositions.push(data);
});
},
/**
* clip a test to a maximum length
* @param {string} v text to clip
* @param {number} l length to clip the text
*/
clipValueLength(v, l) {
l = l || 15;
v = String(v);
if (v.length > l) {
return v.slice(0, (l - 3)) + '...';
}
return v;
},
/**
* clip a test to a maximum length
* @param {string} v text to clip
* @param {number} l length to clip the text
*/
clipValueLengthRight(v, l) {
l = l || 15;
v = String(v);
if (v.length > l) {
return '...' + v.slice(-(l - 3));
}
return v;
},
/**
* convert a time with a multipier to a string
* @param {*} node - the node object for getting i18N Data (node._())
* @param {number} mp - the multipier
* @param {number} v - the value
* @returns {string} the time as string
*/
convertMsToString(node, mp, v) {
if (!mp) {
return String(v);
}
mp = parseInt(mp);
if (mp === 604800000) {
if (v === 1) {
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.week');
}
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.weeks');
} else if (mp === 86400000) {
if (v === 1) {
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.day');
}
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.days');
} else if (mp === 3600000) {
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.hour');
} else if (mp === 60000) {
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.min');
} else if (mp === 1000) {
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.sec');
}
return String(v) + node._('node-red-contrib-sun-position/position-config:common.units.ms');
},
/**
* get the label for a typed input vlaue
* @param {*} node - the node object for getting i18N Data (node._())
* @param {string} t - the type of the value
* @param {string} v - the value
* @param {number} [o] - a optional offset to the value
* @param {number} [oT] - a optional type of the offset to the value
* @param {number} [oM] - a optional multiplier of the offset
* @param {number} [l] - the desired maximum length (default = 30)
* @returns {string} the value clipped to the given length
*/
getRDGNodeValLbl(node, t, v, oT, o, oM, l) {
// console.log('getRDGNodeValLbl global');
l = l || 30;
let suffix = '';
if (o && oT !== 'none') {
if (oT && (oT.startsWith('randomNum') || oT.startsWith('randmNum'))) {
suffix += '⤨';
} else if (o > 0) {
suffix += '⤽';
suffix += RED.nodes.getType('position-config').convertMsToString(node, oM, o);
} else if (o < 0) {
suffix += '⤼';
suffix += RED.nodes.getType('position-config').convertMsToString(node, oM, o);
} else suffix = '↷';
}
switch (t) {
case 'none':
return '';
case 'levelFixed': {
if (!v) {
return '?%';
}
if (v.includes('open')) {
return node._('blind-control.typeOptions.100') + suffix;
}
if (v.includes('closed')) {
return node._('blind-control.typeOptions.0') + suffix;
}
return String(v) + suffix;
}
case 'jsonata':
v = String(v) + suffix;
if (v.length < l) { return v + suffix; }
return node._('node-red-contrib-sun-position/position-config:common.label.jsonata') + suffix;
case 'json':
v = String(v) + suffix;
if (v.length < l) { return v + suffix; }
return node._('node-red-contrib-sun-position/position-config:common.label.json') + suffix;
case 'bin':
return node._('node-red-contrib-sun-position/position-config:common.label.binary') + suffix;
case 'date':
return node._('node-red-contrib-sun-position/position-config:common.label.timestamp') + suffix;
case 'dateSpecific':
return node._('node-red-contrib-sun-position/position-config:common.label.timestamp') + '+' + suffix;
case 'string':
case 'str':
case 'strPlaceholder':
case 'dayOfMonth':
if (v === '') { return node._('node-red-contrib-sun-position/position-config:common.label.blank') + suffix; }
return '"' + RED.nodes.getType('position-config').clipValueLength(v, l) + '"' + suffix;
case 'num':
if (v === '') { return '0' + suffix; }
return String(v) + suffix;
case 'bool':
if (v === '') { return 'false' + suffix; }
return String(v) + suffix;
case 'msg':
case 'env':
return t + '.' + RED.nodes.getType('position-config').clipValueLength(v, l) + suffix;
case 'flow':
case 'global': {
const result = RED.utils.parseContextKey(v);
// special for Homematic Devices
if (/^.+\[('|").{18,}('|")\].*$/.test(result.key)) {
result.key = result.key.replace(/^.+\[('|")/, '').replace(/('|")\].*$/, '');
}
return t + '.' + RED.nodes.getType('position-config').clipValueLengthRight(result.key, l) + suffix;
}
case 'pdsCalcData':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.suncalc')}"${suffix}`;
case 'pdsCalcPercent':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.suninsky')}"${suffix}`;
case 'pdsCalcAzimuth':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.sunAzimuth')}"${suffix}`;
case 'pdsCalcElevation':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.sunElevation')}"${suffix}`;
case 'numAzimuth':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.numAzimuth')}"${suffix}`;
case 'numAltitude':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.numAltitude')}"${suffix}`;
case 'numAnglePreDef':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.numAnglePreDef')}"${suffix}`;
case 'pdsTimeByAzimuth':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.SunTimeByAzimuth')}"${suffix}`;
case 'pdsTimeByElevation':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.SunTimeByElevationObj')}"${suffix}`;
case 'pdsTimeByElevationNext':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.SunTimeByElevationNext')}"${suffix}`;
case 'pdsTimeByElevationRise':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.SunTimeByElevationRise')}"${suffix}`;
case 'pdsTimeByElevationSet':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.SunTimeByElevationSet')}"${suffix}`;
case 'pdmCalcData':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.mooncalc')}"${suffix}`;
case 'pdmPhase':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.moonPhase')}"${suffix}`;
case 'pdsTime': {
switch (v) {
case 'astronomicalDawn':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.astronomicalDawn'), l) + suffix;
case 'amateurDawn':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.amateurDawn'), l) + suffix;
case 'nauticalDawn':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.nauticalDawn'), l) + suffix;
case 'blueHourDawnStart':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDawnStart'), l) + suffix;
case 'civilDawn':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.civilDawn'), l) + suffix;
case 'blueHourDawnEnd':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDawnEnd'), l) + suffix;
case 'goldenHourDawnStart':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDawnStart'), l) + suffix;
case 'sunriseStart':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunriseStart'), l) + suffix;
case 'sunriseEnd':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunriseEnd'), l) + suffix;
case 'goldenHourDawnEnd':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDawnEnd'), l) + suffix;
case 'solarNoon':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.solarNoon'), l) + suffix;
case 'goldenHourDuskStart':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDuskStart'), l) + suffix;
case 'sunsetStart':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunsetStart'), l) + suffix;
case 'sunsetEnd':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunsetEnd'), l) + suffix;
case 'goldenHourDuskEnd':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDuskEnd'), l) + suffix;
case 'blueHourDuskStart':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDuskStart'), l) + suffix;
case 'civilDusk':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.civilDusk'), l) + suffix;
case 'blueHourDuskEnd':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDuskEnd'), l) + suffix;
case 'nauticalDusk':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.nauticalDusk'), l) + suffix;
case 'amateurDusk':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.amateurDusk'), l) + suffix;
case 'astronomicalDusk':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.astronomicalDusk'), l) + suffix;
case 'nadir':
return RED.nodes.getType('position-config').clipValueLength(node._('node-red-contrib-sun-position/position-config:common.typeOptions.nadir'), l) + suffix;
default: {
const res = v.replace('astronomical', 'astro-').replace('nautical', 'naut-').replace('amateur', 'amat-').replace('blueHour', 'blueHr-').replace('goldenHour', 'goldHr-');
return RED.nodes.getType('position-config').clipValueLength(res, l) + suffix;
}
}
}
case 'pdsTimeCustom': return `"${node._('node-red-contrib-sun-position/position-config:common.types.timesuncustomnamed',{value:v})}"${suffix}`;
case 'pdmTime':
switch (v) {
case 'rise':
return node._('node-red-contrib-sun-position/position-config:common.typeOptions.moonRise', 'rise') + suffix;
case 'set':
return node._('node-red-contrib-sun-position/position-config:common.typeOptions.moonSet', 'set') + suffix;
default:
return 'moon' + v + suffix;
}
case 'pdsTimeNow':
return node._('node-red-contrib-sun-position/position-config:common.label.suntimeObj') + suffix;
case 'numPct':
return String(v).replace('%','').trim() + '%' + suffix;
case 'nodeId':
return node._('node-red-contrib-sun-position/position-config:common.types.nodeId') + suffix;
case 'nodeName':
return node._('node-red-contrib-sun-position/position-config:common.types.nodeName') + suffix;
case 'nodePath':
return node._('node-red-contrib-sun-position/position-config:common.types.nodePath') + suffix;
case 'PlT':
return node._('node-red-contrib-sun-position/position-config:common.typeOptions.PlTRes',{topic: RED.nodes.getType('position-config').clipValueLength(v, l), suffix} );
case 'msgPayload':
return 'msg.payload';
case 'msgTopic':
return 'msg.topic';
case 'msgTs':
return 'msg.ts';
case 'msgLc':
return 'msg.lc';
case 'msgValue':
return 'msg.value';
case 'input':
return 'input data';
case 'timespan':
return 'timespan';
case 'operand1':
return 'operand1 data';
case 'operand2':
return 'operand2 data';
case 'pdbIsDST':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.isDST')}"${suffix}`;
case 'pdnWeekOfYear':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.WeekOfYear')}"${suffix}`;
case 'pdbWeekOfYearEven':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.isWeekOfYearEven')}"${suffix}`;
case 'pdnDayOfYear':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.DayOfYear')}"${suffix}`;
case 'pdbDayOfYearEven':
return `"${node._('node-red-contrib-sun-position/position-config:common.types.isDayOfYearEven')}"${suffix}`;
case 'randomNum':
return `${node._('node-red-contrib-sun-position/position-config:common.label.randNum')} ${RED.nodes.getType('position-config').clipValueLength(v, l)}${suffix}`;
case 'randmNumCachedDay':
return `${node._('node-red-contrib-sun-position/position-config:common.label.randNumCachedDay')} ${RED.nodes.getType('position-config').clipValueLength(v, l)}${suffix}`;
case 'randmNumCachedWeek':
return `${node._('node-red-contrib-sun-position/position-config:common.label.randNumCachedWeek')} ${RED.nodes.getType('position-config').clipValueLength(v, l)}${suffix}`;
default: {
if (v === '') {
return node._('node-red-contrib-sun-position/position-config:common.label.blank');
}
return RED.nodes.getType('position-config').clipValueLength(v, l) + suffix;
}
}
}
});
})();</script>
<script type="text/html" data-template-name="position-config">
<div class="form-row">
<label for="node-config-input-posLatitude"><i class="fa fa-globe"></i> <span data-i18n="position-config.label.latitude"></span></label>
<input type="text" id="node-config-input-posLatitude" data-i18n="[placeholder]position-config.placeholder.latitude">
</div>
<div class="form-row">
<label for="node-config-input-posLongitude"><i class="fa fa-globe"></i> <span data-i18n="position-config.label.longitude"></span></label>
<input type="text" id="node-config-input-posLongitude" data-i18n="[placeholder]position-config.placeholder.longitude">
<input type="hidden" id="node-config-input-isValide">
</div>
<div class="form-row">
<label for="node-config-input-height"><i class="fa fa-globe"></i> <span data-i18n="position-config.label.height"></span></label>
<input type="text" id="node-config-input-height" data-i18n="[placeholder]position-config.placeholder.height">
</div>
<div class="form-row" id="node-config-map-row">
<div id="node-config-map-link">Karte</div>
<iframe id="node-config-map-content" src="about:blank" width="100%" height="250" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" style="border: 1px solid black"></iframe>
</div>
<div class="form-row form-tips is-to-show-initially" data-i18n="[html]position-config.tips.config"></div>
<div class="form-row">
<label for="node-config-input-angleType"><i class="fa fa-angle-left"></i> <span data-i18n="position-config.label.angleType"></span></label>
<select type="text" id="node-config-input-angleType" style="width:70%;">
<option value="deg" >degrees</option>
<option value="rad" >radians</option>
</select>
</div>
<hr>
<div class="form-row form-tips is-to-show-initially" data-i18n="[html]position-config.tips.timeZoneOffset"></div>
<div class="form-row">
<label for="node-config-input-timeZoneOffset"><i class="fa fa-clock-o"></i> <span data-i18n="position-config.label.timeZoneOffset"></span></label>
<select type="text" id="node-config-input-timeZoneOffset" style="width:70%;" disabled>
<option timeZoneId="1" gmtAdjustment="GMT-12:00" useDaylightTime="0" value="99">Operating system standard</option>
<option timeZoneId="1" gmtAdjustment="GMT-12:00" useDaylightTime="0" value="-12">(GMT-12:00) International Date Line West</option>
<option timeZoneId="2" gmtAdjustment="GMT-11:00" useDaylightTime="0" value="-11">(GMT-11:00) Midway Island, Samoa</option>
<option timeZoneId="3" gmtAdjustment="GMT-10:00" useDaylightTime="0" value="-10">(GMT-10:00) Hawaii</option>
<option timeZoneId="4" gmtAdjustment="GMT-09:00" useDaylightTime="1" value="-9">(GMT-09:00) Alaska</option>
<option timeZoneId="5" gmtAdjustment="GMT-08:00" useDaylightTime="1" value="-8">(GMT-08:00) Pacific Time (US & Canada)</option>
<option timeZoneId="6" gmtAdjustment="GMT-08:00" useDaylightTime="1" value="-8">(GMT-08:00) Tijuana, Baja California</option>
<option timeZoneId="7" gmtAdjustment="GMT-07:00" useDaylightTime="0" value="-7">(GMT-07:00) Arizona</option>
<option timeZoneId="8" gmtAdjustment="GMT-07:00" useDaylightTime="1" value="-7">(GMT-07:00) Chihuahua, La Paz, Mazatlan</option>
<option timeZoneId="9" gmtAdjustment="GMT-07:00" useDaylightTime="1" value="-7">(GMT-07:00) Mountain Time (US & Canada)</option>
<option timeZoneId="10" gmtAdjustment="GMT-06:00" useDaylightTime="0" value="-6">(GMT-06:00) Central America</option>
<option timeZoneId="11" gmtAdjustment="GMT-06:00" useDaylightTime="1" value="-6">(GMT-06:00) Central Time (US & Canada)</option>
<option timeZoneId="12" gmtAdjustment="GMT-06:00" useDaylightTime="1" value="-6">(GMT-06:00) Guadalajara, Mexico City, Monterrey</option>
<option timeZoneId="13" gmtAdjustment="GMT-06:00" useDaylightTime="0" value="-6">(GMT-06:00) Saskatchewan</option>
<option timeZoneId="14" gmtAdjustment="GMT-05:00" useDaylightTime="0" value="-5">(GMT-05:00) Bogota, Li