smart-energy-monitor/software/dashboard/grafana/csv/Node-RED.html

24404 lines
1.6 MiB
HTML
Raw Normal View History

2023-02-27 17:21:01 +01:00
<!DOCTYPE html>
<!-- saved from url=(0043)http://localhost:1880/#flow/f6f2187d.f17ca8 -->
<html data-lt-installed="true"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><style id="autocompletion.css">.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line { background-color: #CAD6FA; z-index: 1;}.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line { background-color: #3a674e;}.ace_editor.ace_autocomplete .ace_line-hover { border: 1px solid #abbffe; margin-top: -1px; background: rgba(233,233,253,0.4); position: absolute; z-index: 2;}.ace_dark.ace_editor.ace_autocomplete .ace_line-hover { border: 1px solid rgba(109, 150, 13, 0.8); background: rgba(58, 103, 78, 0.62);}.ace_completion-meta { opacity: 0.5; margin: 0.9em;}.ace_completion-message { color: blue;}.ace_editor.ace_autocomplete .ace_completion-highlight{ color: #2d69c7;}.ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight{ color: #93ca12;}.ace_editor.ace_autocomplete { width: 300px; z-index: 200000; border: 1px lightgray solid; position: fixed; box-shadow: 2px 3px 5px rgba(0,0,0,.2); line-height: 1.4; background: #fefefe; color: #111;}.ace_dark.ace_editor.ace_autocomplete { border: 1px #484747 solid; box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.51); line-height: 1.4; background: #25282c; color: #c1c1c1;}
/*# sourceURL=ace/css/autocompletion.css */</style><style>.ace_snippet-marker { -moz-box-sizing: border-box; box-sizing: border-box; background: rgba(194, 193, 208, 0.09); border: 1px dotted rgba(211, 208, 235, 0.62); position: absolute;}</style><style> .error_widget_wrapper { background: inherit; color: inherit; border:none } .error_widget { border-top: solid 2px; border-bottom: solid 2px; margin: 5px 0; padding: 10px 40px; white-space: pre-wrap; } .error_widget.ace_error, .error_widget_arrow.ace_error{ border-color: #ff5a5a } .error_widget.ace_warning, .error_widget_arrow.ace_warning{ border-color: #F1D817 } .error_widget.ace_info, .error_widget_arrow.ace_info{ border-color: #5a5a5a } .error_widget.ace_ok, .error_widget_arrow.ace_ok{ border-color: #5aaa5a } .error_widget_arrow { position: absolute; border: solid 5px; border-top-color: transparent!important; border-right-color: transparent!important; border-left-color: transparent!important; top: -5px; }</style><style id="ace-tm">.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}
/*# sourceURL=ace/css/ace-tm */</style><style id="ace_editor.css">.ace_br1 {border-top-left-radius : 3px;}.ace_br2 {border-top-right-radius : 3px;}.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_editor {position: relative;overflow: hidden;padding: 0;font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;direction: ltr;text-align: left;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;box-sizing: border-box;min-width: 100%;contain: style size layout;font-variant-ligatures: no-common-ligatures;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: '';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;contain: style size layout;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {position: absolute;top: 0;left: 0;right: 0;padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ
/*# sourceURL=ace/css/ace_editor.css */</style>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<!--
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<title>Node-RED</title>
<link rel="icon" type="image/png" href="http://localhost:1880/favicon.ico">
<link rel="mask-icon" href="http://localhost:1880/red/images/node-red-icon-black.svg" color="#8f0000">
<link rel="stylesheet" href="./Node-RED_files/jquery-ui.min.css">
<link rel="stylesheet" href="./Node-RED_files/font-awesome.min.css">
<link rel="stylesheet" href="./Node-RED_files/style.min.css">
<link rel="stylesheet" href="./Node-RED_files/style.css">
<style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .accessibilityHelpWidget {
padding: 10px;
vertical-align: middle;
overflow: scroll;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-aria-container {
position: absolute; /* try to hide from window but not from screen readers */
left:-999em;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .selection-anchor {
background-color: #007ACC;
width: 2px !important;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .bracket-match {
box-sizing: border-box;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .monaco-editor-overlaymessage {
padding-bottom: 8px;
z-index: 10000;
}
.monaco-editor .monaco-editor-overlaymessage.below {
padding-bottom: 0;
padding-top: 8px;
z-index: 10000;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.monaco-editor .monaco-editor-overlaymessage.fadeIn {
animation: fadeIn 150ms ease-out;
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.monaco-editor .monaco-editor-overlaymessage.fadeOut {
animation: fadeOut 100ms ease-out;
}
.monaco-editor .monaco-editor-overlaymessage .message {
padding: 1px 4px;
color: var(--vscode-inputValidation-infoForeground);
background-color: var(--vscode-inputValidation-infoBackground);
border: 1px solid var(--vscode-inputValidation-infoBorder);
}
.monaco-editor.hc-black .monaco-editor-overlaymessage .message {
border-width: 2px;
}
.monaco-editor .monaco-editor-overlaymessage .anchor {
width: 0 !important;
height: 0 !important;
border-color: transparent;
border-style: solid;
z-index: 1000;
border-width: 8px;
position: absolute;
}
.monaco-editor .monaco-editor-overlaymessage .anchor.top {
border-bottom-color: var(--vscode-inputValidation-infoBorder);
}
.monaco-editor .monaco-editor-overlaymessage .anchor.below {
border-top-color: var(--vscode-inputValidation-infoBorder);
}
.monaco-editor .monaco-editor-overlaymessage:not(.below) .anchor.top,
.monaco-editor .monaco-editor-overlaymessage.below .anchor.below {
display: none;
}
.monaco-editor .monaco-editor-overlaymessage.below .anchor.top {
display: inherit;
top: -8px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .contentWidgets .codicon-light-bulb,
.monaco-editor .contentWidgets .codicon-lightbulb-autofix {
display: flex;
align-items: center;
justify-content: center;
}
.monaco-editor .contentWidgets .codicon-light-bulb:hover,
.monaco-editor .contentWidgets .codicon-lightbulb-autofix:hover {
cursor: pointer;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .codelens-decoration {
overflow: hidden;
display: inline-block;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--vscode-editorCodeLens-foreground)
}
.monaco-editor .codelens-decoration > span,
.monaco-editor .codelens-decoration > a {
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
white-space: nowrap;
vertical-align: sub;
}
.monaco-editor .codelens-decoration > a {
text-decoration: none;
}
.monaco-editor .codelens-decoration > a:hover {
cursor: pointer;
color: var(--vscode-editorLink-activeForeground) !important;
}
.monaco-editor .codelens-decoration > a:hover .codicon {
color: var(--vscode-editorLink-activeForeground) !important;
}
.monaco-editor .codelens-decoration .codicon {
vertical-align: middle;
color: currentColor !important;
color: var(--vscode-editorCodeLens-foreground);
}
.monaco-editor .codelens-decoration > a:hover .codicon::before {
cursor: pointer;
}
@keyframes fadein {
0% { opacity: 0; visibility: visible;}
100% { opacity: 1; }
}
.monaco-editor .codelens-decoration.fadein {
animation: fadein 0.1s linear;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.colorpicker-widget {
height: 190px;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
/* Decoration */
.colorpicker-color-decoration {
border: solid 0.1em #000;
box-sizing: border-box;
margin: 0.1em 0.2em 0 0.2em;
width: 0.8em;
height: 0.8em;
line-height: 0.8em;
display: inline-block;
cursor: pointer;
}
.hc-black .colorpicker-color-decoration,
.vs-dark .colorpicker-color-decoration {
border: solid 0.1em #eee;
}
/* Header */
.colorpicker-header {
display: flex;
height: 24px;
position: relative;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAHUlEQVQYV2PYvXu3JAi7uLiAMaYAjAGTQBPYLQkAa/0Zef3qRswAAAAASUVORK5CYII=);
background-size: 9px 9px;
image-rendering: pixelated;
}
.colorpicker-header .picked-color {
width: 216px;
display: flex;
align-items: center;
justify-content: center;
line-height: 24px;
cursor: pointer;
color: white;
flex: 1;
}
.colorpicker-header .picked-color .codicon {
color: inherit;
font-size: 14px;
position: absolute;
left: 8px;
}
.colorpicker-header .picked-color.light {
color: black;
}
.colorpicker-header .original-color {
width: 74px;
z-index: inherit;
cursor: pointer;
}
/* Body */
.colorpicker-body {
display: flex;
padding: 8px;
position: relative;
}
.colorpicker-body .saturation-wrap {
overflow: hidden;
height: 150px;
position: relative;
min-width: 220px;
flex: 1;
}
.colorpicker-body .saturation-box {
height: 150px;
position: absolute;
}
.colorpicker-body .saturation-selection {
width: 9px;
height: 9px;
margin: -5px 0 0 -5px;
border: 1px solid rgb(255, 255, 255);
border-radius: 100%;
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.8);
position: absolute;
}
.colorpicker-body .strip {
width: 25px;
height: 150px;
}
.colorpicker-body .hue-strip {
position: relative;
margin-left: 8px;
cursor: grab;
background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
}
.colorpicker-body .opacity-strip {
position: relative;
margin-left: 8px;
cursor: grab;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTZEaa/1AAAAHUlEQVQYV2PYvXu3JAi7uLiAMaYAjAGTQBPYLQkAa/0Zef3qRswAAAAASUVORK5CYII=);
background-size: 9px 9px;
image-rendering: pixelated;
}
.colorpicker-body .strip.grabbing {
cursor: grabbing;
}
.colorpicker-body .slider {
position: absolute;
top: 0;
left: -2px;
width: calc(100% + 4px);
height: 4px;
box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 0.71);
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.85);
}
.colorpicker-body .strip .overlay {
height: 150px;
pointer-events: none;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .goto-definition-link {
text-decoration: underline;
cursor: pointer;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-action-bar {
white-space: nowrap;
height: 100%;
}
.monaco-action-bar .actions-container {
display: flex;
margin: 0 auto;
padding: 0;
height: 100%;
width: 100%;
align-items: center;
}
.monaco-action-bar.vertical .actions-container {
display: inline-block;
}
.monaco-action-bar .action-item {
display: block;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */
}
.monaco-action-bar .action-item.disabled {
cursor: default;
}
.monaco-action-bar .action-item .icon,
.monaco-action-bar .action-item .codicon {
display: block;
}
.monaco-action-bar .action-item .codicon {
display: flex;
align-items: center;
width: 16px;
height: 16px;
}
.monaco-action-bar .action-label {
font-size: 11px;
padding: 3px;
border-radius: 5px;
}
.monaco-action-bar .action-item.disabled .action-label,
.monaco-action-bar .action-item.disabled .action-label::before,
.monaco-action-bar .action-item.disabled .action-label:hover {
opacity: 0.4;
}
/* Vertical actions */
.monaco-action-bar.vertical {
text-align: left;
}
.monaco-action-bar.vertical .action-item {
display: block;
}
.monaco-action-bar.vertical .action-label.separator {
display: block;
border-bottom: 1px solid #bbb;
padding-top: 1px;
margin-left: .8em;
margin-right: .8em;
}
.monaco-action-bar .action-item .action-label.separator {
width: 1px;
height: 16px;
margin: 5px 4px !important;
cursor: default;
min-width: 1px;
padding: 0;
background-color: #bbb;
}
.secondary-actions .monaco-action-bar .action-label {
margin-left: 6px;
}
/* Action Items */
.monaco-action-bar .action-item.select-container {
overflow: hidden; /* somehow the dropdown overflows its container, we prevent it here to not push */
flex: 1;
max-width: 170px;
min-width: 60px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
.monaco-action-bar .action-item.action-dropdown-item {
display: flex;
}
.monaco-action-bar .action-item.action-dropdown-item > .action-label {
margin-right: 1px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .peekview-widget .head {
box-sizing: border-box;
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
}
.monaco-editor .peekview-widget .head .peekview-title {
display: flex;
align-items: center;
font-size: 13px;
margin-left: 20px;
min-width: 0;
text-overflow: ellipsis;
overflow: hidden;
}
.monaco-editor .peekview-widget .head .peekview-title.clickable {
cursor: pointer;
}
.monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty) {
font-size: 0.9em;
margin-left: 0.5em;
text-overflow: ellipsis;
overflow: hidden;
}
.monaco-editor .peekview-widget .head .peekview-title .meta {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-editor .peekview-widget .head .peekview-title .dirname {
white-space: nowrap;
}
.monaco-editor .peekview-widget .head .peekview-title .filename {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty)::before {
content: '-';
padding: 0 0.3em;
}
.monaco-editor .peekview-widget .head .peekview-actions {
flex: 1;
text-align: right;
padding-right: 2px;
}
.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar {
display: inline-block;
}
.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar,
.monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar > .actions-container {
height: 100%;
}
.monaco-editor .peekview-widget > .body {
border-top: 1px solid;
position: relative;
}
.monaco-editor .peekview-widget .head .peekview-title .codicon {
margin-right: 4px;
}
.monaco-editor .peekview-widget .monaco-list .monaco-list-row.focused .codicon {
color: inherit !important;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* -------------------- IE10 remove auto clear button -------------------- */
::-ms-clear {
display: none;
}
/* All widgets */
/* I am not a big fan of this rule */
.monaco-editor .editor-widget input {
color: inherit;
}
/* -------------------- Editor -------------------- */
.monaco-editor {
position: relative;
overflow: visible;
-webkit-text-size-adjust: 100%;
}
/* -------------------- Misc -------------------- */
.monaco-editor .overflow-guard {
position: relative;
overflow: hidden;
}
.monaco-editor .view-overlays {
position: absolute;
top: 0;
}
/*
.monaco-editor .auto-closed-character {
opacity: 0.3;
}
*/
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .inputarea {
min-width: 0;
min-height: 0;
margin: 0;
padding: 0;
position: absolute;
outline: none !important;
resize: none;
border: none;
overflow: hidden;
color: transparent;
background-color: transparent;
}
/*.monaco-editor .inputarea {
position: fixed !important;
width: 800px !important;
height: 500px !important;
top: initial !important;
left: initial !important;
bottom: 0 !important;
right: 0 !important;
color: black !important;
background: white !important;
line-height: 15px !important;
font-size: 14px !important;
}*/
.monaco-editor .inputarea.ime-input {
z-index: 10;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .margin-view-overlays .line-numbers {
font-variant-numeric: tabular-nums;
position: absolute;
text-align: right;
display: inline-block;
vertical-align: middle;
box-sizing: border-box;
cursor: default;
height: 100%;
}
.monaco-editor .relative-current-line-number {
text-align: left;
display: inline-block;
width: 100%;
}
.monaco-editor .margin-view-overlays .line-numbers.lh-odd {
margin-top: 1px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-mouse-cursor-text {
cursor: text;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .view-overlays .current-line {
display: block;
position: absolute;
left: 0;
top: 0;
box-sizing: border-box;
}
.monaco-editor .margin-view-overlays .current-line {
display: block;
position: absolute;
left: 0;
top: 0;
box-sizing: border-box;
}
.monaco-editor .margin-view-overlays .current-line.current-line-margin.current-line-margin-both {
border-right: 0;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*
Keeping name short for faster parsing.
cdr = core decorations rendering (div)
*/
.monaco-editor .lines-content .cdr {
position: absolute;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Arrows */
.monaco-scrollable-element > .scrollbar > .scra {
cursor: pointer;
font-size: 11px !important;
}
.monaco-scrollable-element > .visible {
opacity: 1;
/* Background rule added for IE9 - to allow clicks on dom node */
background:rgba(0,0,0,0);
transition: opacity 100ms linear;
}
.monaco-scrollable-element > .invisible {
opacity: 0;
pointer-events: none;
}
.monaco-scrollable-element > .invisible.fade {
transition: opacity 800ms linear;
}
/* Scrollable Content Inset Shadow */
.monaco-scrollable-element > .shadow {
position: absolute;
display: none;
}
.monaco-scrollable-element > .shadow.top {
display: block;
top: 0;
left: 3px;
height: 3px;
width: 100%;
}
.monaco-scrollable-element > .shadow.left {
display: block;
top: 3px;
left: 0;
height: 100%;
width: 3px;
}
.monaco-scrollable-element > .shadow.top-left-corner {
display: block;
top: 0;
left: 0;
height: 3px;
width: 3px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .glyph-margin {
position: absolute;
top: 0;
}
/*
Keeping name short for faster parsing.
cgmr = core glyph margin rendering (div)
*/
.monaco-editor .margin-view-overlays .cgmr {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .lines-content .core-guide {
position: absolute;
box-sizing: border-box;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Uncomment to see lines flashing when they're painted */
/*.monaco-editor .view-lines > .view-line {
background-color: none;
animation-name: flash-background;
animation-duration: 800ms;
}
@keyframes flash-background {
0% { background-color: lightgreen; }
100% { background-color: none }
}*/
.mtkcontrol {
color: rgb(255, 255, 255) !important;
background: rgb(150, 0, 0) !important;
}
.monaco-editor.no-user-select .lines-content,
.monaco-editor.no-user-select .view-line,
.monaco-editor.no-user-select .view-lines {
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.monaco-editor .view-lines {
white-space: nowrap;
}
.monaco-editor .view-line {
position: absolute;
width: 100%;
}
.monaco-editor .mtkz {
display: inline-block;
}
/* TODO@tokenization bootstrap fix */
/*.monaco-editor .view-line > span > span {
float: none;
min-height: inherit;
margin-left: inherit;
}*/
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .lines-decorations {
position: absolute;
top: 0;
background: white;
}
/*
Keeping name short for faster parsing.
cldr = core lines decorations rendering (div)
*/
.monaco-editor .margin-view-overlays .cldr {
position: absolute;
height: 100%;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*
Keeping name short for faster parsing.
cmdr = core margin decorations rendering (div)
*/
.monaco-editor .margin-view-overlays .cmdr {
position: absolute;
left: 0;
width: 100%;
height: 100%;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* START cover the case that slider is visible on mouseover */
.monaco-editor .minimap.slider-mouseover .minimap-slider {
opacity: 0;
transition: opacity 100ms linear;
}
.monaco-editor .minimap.slider-mouseover:hover .minimap-slider {
opacity: 1;
}
.monaco-editor .minimap.slider-mouseover .minimap-slider.active {
opacity: 1;
}
/* END cover the case that slider is visible on mouseover */
.monaco-editor .minimap-shadow-hidden {
position: absolute;
width: 0;
}
.monaco-editor .minimap-shadow-visible {
position: absolute;
left: -6px;
width: 6px;
}
.monaco-editor.no-minimap-shadow .minimap-shadow-visible {
position: absolute;
left: -1px;
width: 1px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .overlayWidgets {
position: absolute;
top: 0;
left:0;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .view-ruler {
position: absolute;
top: 0;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .scroll-decoration {
position: absolute;
top: 0;
left: 0;
height: 6px;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*
Keeping name short for faster parsing.
cslr = core selections layer rendering (div)
*/
.monaco-editor .lines-content .cslr {
position: absolute;
}
.monaco-editor .top-left-radius { border-top-left-radius: 3px; }
.monaco-editor .bottom-left-radius { border-bottom-left-radius: 3px; }
.monaco-editor .top-right-radius { border-top-right-radius: 3px; }
.monaco-editor .bottom-right-radius { border-bottom-right-radius: 3px; }
.monaco-editor.hc-black .top-left-radius { border-top-left-radius: 0; }
.monaco-editor.hc-black .bottom-left-radius { border-bottom-left-radius: 0; }
.monaco-editor.hc-black .top-right-radius { border-top-right-radius: 0; }
.monaco-editor.hc-black .bottom-right-radius { border-bottom-right-radius: 0; }
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .cursors-layer {
position: absolute;
top: 0;
}
.monaco-editor .cursors-layer > .cursor {
position: absolute;
overflow: hidden;
}
/* -- smooth-caret-animation -- */
.monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor {
transition: all 80ms;
}
/* -- block-outline-style -- */
.monaco-editor .cursors-layer.cursor-block-outline-style > .cursor {
box-sizing: border-box;
background: transparent !important;
border-style: solid;
border-width: 1px;
}
/* -- underline-style -- */
.monaco-editor .cursors-layer.cursor-underline-style > .cursor {
border-bottom-width: 2px;
border-bottom-style: solid;
background: transparent !important;
box-sizing: border-box;
}
/* -- underline-thin-style -- */
.monaco-editor .cursors-layer.cursor-underline-thin-style > .cursor {
border-bottom-width: 1px;
border-bottom-style: solid;
background: transparent !important;
box-sizing: border-box;
}
@keyframes monaco-cursor-smooth {
0%,
20% {
opacity: 1;
}
60%,
100% {
opacity: 0;
}
}
@keyframes monaco-cursor-phase {
0%,
20% {
opacity: 1;
}
90%,
100% {
opacity: 0;
}
}
@keyframes monaco-cursor-expand {
0%,
20% {
transform: scaleY(1);
}
80%,
100% {
transform: scaleY(0);
}
}
.cursor-smooth {
animation: monaco-cursor-smooth 0.5s ease-in-out 0s 20 alternate;
}
.cursor-phase {
animation: monaco-cursor-phase 0.5s ease-in-out 0s 20 alternate;
}
.cursor-expand > .cursor {
animation: monaco-cursor-expand 0.5s ease-in-out 0s 20 alternate;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
:root {
--sash-size: 4px;
}
.monaco-sash {
position: absolute;
z-index: 35;
touch-action: none;
}
.monaco-sash.disabled {
pointer-events: none;
}
.monaco-sash.mac.vertical {
cursor: col-resize;
}
.monaco-sash.vertical.minimum {
cursor: e-resize;
}
.monaco-sash.vertical.maximum {
cursor: w-resize;
}
.monaco-sash.mac.horizontal {
cursor: row-resize;
}
.monaco-sash.horizontal.minimum {
cursor: s-resize;
}
.monaco-sash.horizontal.maximum {
cursor: n-resize;
}
.monaco-sash.disabled {
cursor: default !important;
pointer-events: none !important;
}
.monaco-sash.vertical {
cursor: ew-resize;
top: 0;
width: var(--sash-size);
height: 100%;
}
.monaco-sash.horizontal {
cursor: ns-resize;
left: 0;
width: 100%;
height: var(--sash-size);
}
.monaco-sash:not(.disabled) > .orthogonal-drag-handle {
content: " ";
height: calc(var(--sash-size) * 2);
width: calc(var(--sash-size) * 2);
z-index: 100;
display: block;
cursor: all-scroll;
position: absolute;
}
.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)
> .orthogonal-drag-handle.start,
.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)
> .orthogonal-drag-handle.end {
cursor: nwse-resize;
}
.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)
> .orthogonal-drag-handle.end,
.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)
> .orthogonal-drag-handle.start {
cursor: nesw-resize;
}
.monaco-sash.vertical > .orthogonal-drag-handle.start {
left: calc(var(--sash-size) * -0.5);
top: calc(var(--sash-size) * -1);
}
.monaco-sash.vertical > .orthogonal-drag-handle.end {
left: calc(var(--sash-size) * -0.5);
bottom: calc(var(--sash-size) * -1);
}
.monaco-sash.horizontal > .orthogonal-drag-handle.start {
top: calc(var(--sash-size) * -0.5);
left: calc(var(--sash-size) * -1);
}
.monaco-sash.horizontal > .orthogonal-drag-handle.end {
top: calc(var(--sash-size) * -0.5);
right: calc(var(--sash-size) * -1);
}
.monaco-sash:before {
content: '';
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
transition: background-color 0.1s ease-out;
background: transparent;
}
.monaco-sash.vertical:before {
width: var(--sash-hover-size);
left: calc(50% - (var(--sash-hover-size) / 2));
}
.monaco-sash.horizontal:before {
height: var(--sash-hover-size);
top: calc(50% - (var(--sash-hover-size) / 2));
}
.pointer-events-disabled {
pointer-events: none !important;
}
/** Debug **/
.monaco-sash.debug {
background: cyan;
}
.monaco-sash.debug.disabled {
background: rgba(0, 255, 255, 0.2);
}
.monaco-sash.debug:not(.disabled) > .orthogonal-drag-handle {
background: red;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .zone-widget {
position: absolute;
z-index: 10;
}
.monaco-editor .zone-widget .zone-widget-container {
border-top-style: solid;
border-bottom-style: solid;
border-top-width: 0;
border-bottom-width: 0;
position: relative;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-dropdown {
height: 100%;
padding: 0;
}
.monaco-dropdown > .dropdown-label {
cursor: pointer;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.monaco-dropdown > .dropdown-label > .action-label.disabled {
cursor: default;
}
.monaco-dropdown-with-primary {
display: flex !important;
flex-direction: row;
border-radius: 5px;
}
.monaco-dropdown-with-primary > .action-container > .action-label {
margin-right: 0;
}
.monaco-dropdown-with-primary > .dropdown-action-container > .monaco-dropdown > .dropdown-label .codicon[class*='codicon-'] {
font-size: 12px;
padding-left: 0px;
padding-right: 0px;
line-height: 16px;
margin-left: -3px;
}
.monaco-dropdown-with-primary > .dropdown-action-container > .monaco-dropdown > .dropdown-label > .action-label {
display: block;
background-size: 16px;
background-position: center center;
background-repeat: no-repeat;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-action-bar .action-item.menu-entry .action-label.icon {
width: 16px;
height: 16px;
background-repeat: no-repeat;
background-position: 50%;
background-size: 16px;
}
.monaco-action-bar .action-item.menu-entry .action-label {
background-image: var(--menu-entry-icon-light);
}
.vs-dark .monaco-action-bar .action-item.menu-entry .action-label,
.hc-black .monaco-action-bar .action-item.menu-entry .action-label {
background-image: var(--menu-entry-icon-dark);
}
.monaco-dropdown-with-default {
display: flex !important;
flex-direction: row;
border-radius: 5px;
}
.monaco-dropdown-with-default > .action-container > .action-label {
margin-right: 0;
}
.monaco-dropdown-with-default > .action-container.menu-entry > .action-label.icon {
width: 16px;
height: 16px;
background-repeat: no-repeat;
background-position: 50%;
background-size: 16px;
}
.monaco-dropdown-with-default > .action-container.menu-entry > .action-label {
background-image: var(--menu-entry-icon-light);
}
.vs-dark .monaco-dropdown-with-default > .action-container.menu-entry > .action-label,
.hc-black .monaco-dropdown-with-default > .action-container.menu-entry > .action-label {
background-image: var(--menu-entry-icon-dark);
}
.monaco-dropdown-with-default > .dropdown-action-container > .monaco-dropdown > .dropdown-label .codicon[class*='codicon-'] {
font-size: 12px;
padding-left: 0px;
padding-right: 0px;
line-height: 16px;
margin-left: -3px;
}
.monaco-dropdown-with-default > .dropdown-action-container > .monaco-dropdown > .dropdown-label > .action-label {
display: block;
background-size: 16px;
background-position: center center;
background-repeat: no-repeat;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-list {
position: relative;
height: 100%;
width: 100%;
white-space: nowrap;
}
.monaco-list.mouse-support {
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.monaco-list > .monaco-scrollable-element {
height: 100%;
}
.monaco-list-rows {
position: relative;
width: 100%;
height: 100%;
}
.monaco-list.horizontal-scrolling .monaco-list-rows {
width: auto;
min-width: 100%;
}
.monaco-list-row {
position: absolute;
box-sizing: border-box;
overflow: hidden;
width: 100%;
}
.monaco-list.mouse-support .monaco-list-row {
cursor: pointer;
touch-action: none;
}
/* for OS X ballistic scrolling */
.monaco-list-row.scrolling {
display: none !important;
}
/* Focus */
.monaco-list.element-focused,
.monaco-list.selection-single,
.monaco-list.selection-multiple {
outline: 0 !important;
}
/* Dnd */
.monaco-drag-image {
display: inline-block;
padding: 1px 7px;
border-radius: 10px;
font-size: 12px;
position: absolute;
z-index: 1000;
}
/* Type filter */
.monaco-list-type-filter {
display: flex;
align-items: center;
position: absolute;
border-radius: 2px;
padding: 0px 3px;
max-width: calc(100% - 10px);
text-overflow: ellipsis;
overflow: hidden;
text-align: right;
box-sizing: border-box;
cursor: all-scroll;
font-size: 13px;
line-height: 18px;
height: 20px;
z-index: 1;
top: 4px;
}
.monaco-list-type-filter.dragging {
transition: top 0.2s, left 0.2s;
}
.monaco-list-type-filter.ne {
right: 4px;
}
.monaco-list-type-filter.nw {
left: 4px;
}
.monaco-list-type-filter > .controls {
display: flex;
align-items: center;
box-sizing: border-box;
transition: width 0.2s;
width: 0;
}
.monaco-list-type-filter.dragging > .controls,
.monaco-list-type-filter:hover > .controls {
width: 36px;
}
.monaco-list-type-filter > .controls > * {
border: none;
box-sizing: border-box;
-webkit-appearance: none;
-moz-appearance: none;
background: none;
width: 16px;
height: 16px;
flex-shrink: 0;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.monaco-list-type-filter > .controls > .filter {
margin-left: 4px;
}
.monaco-list-type-filter-message {
position: absolute;
box-sizing: border-box;
width: 100%;
height: 100%;
top: 0;
left: 0;
padding: 40px 1em 1em 1em;
text-align: center;
white-space: normal;
opacity: 0.7;
pointer-events: none;
}
.monaco-list-type-filter-message:empty {
display: none;
}
/* Electron */
.monaco-list-type-filter {
cursor: grab;
}
.monaco-list-type-filter.dragging {
cursor: grabbing;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-split-view2 {
position: relative;
width: 100%;
height: 100%;
}
.monaco-split-view2 > .sash-container {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
}
.monaco-split-view2 > .sash-container > .monaco-sash {
pointer-events: initial;
}
.monaco-split-view2 > .monaco-scrollable-element {
width: 100%;
height: 100%;
}
.monaco-split-view2 > .monaco-scrollable-element > .split-view-container {
width: 100%;
height: 100%;
white-space: nowrap;
position: relative;
}
.monaco-split-view2 > .monaco-scrollable-element > .split-view-container > .split-view-view {
white-space: initial;
position: absolute;
}
.monaco-split-view2 > .monaco-scrollable-element > .split-view-container > .split-view-view:not(.visible) {
display: none;
}
.monaco-split-view2.vertical > .monaco-scrollable-element > .split-view-container > .split-view-view {
width: 100%;
}
.monaco-split-view2.horizontal > .monaco-scrollable-element > .split-view-container > .split-view-view {
height: 100%;
}
.monaco-split-view2.separator-border > .monaco-scrollable-element > .split-view-container > .split-view-view:not(:first-child)::before {
content: ' ';
position: absolute;
top: 0;
left: 0;
z-index: 5;
pointer-events: none;
background-color: var(--separator-border);
}
.monaco-split-view2.separator-border.horizontal > .monaco-scrollable-element > .split-view-container > .split-view-view:not(:first-child)::before {
height: 100%;
width: 1px;
}
.monaco-split-view2.separator-border.vertical > .monaco-scrollable-element > .split-view-container > .split-view-view:not(:first-child)::before {
height: 1px;
width: 100%;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-table {
display: flex;
flex-direction: column;
position: relative;
height: 100%;
width: 100%;
white-space: nowrap;
}
.monaco-table > .monaco-split-view2 {
border-bottom: 1px solid transparent;
}
.monaco-table > .monaco-list {
flex: 1;
}
.monaco-table-tr {
display: flex;
height: 100%;
}
.monaco-table-th {
width: 100%;
height: 100%;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-table-th,
.monaco-table-td {
box-sizing: border-box;
flex-shrink: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.monaco-table > .monaco-split-view2 .monaco-sash.vertical::before {
content: "";
position: absolute;
left: calc(var(--sash-size) / 2);
width: 0;
border-left: 1px solid transparent;
}
.monaco-table > .monaco-split-view2,
.monaco-table > .monaco-split-view2 .monaco-sash.vertical::before {
transition: border-color 0.2s ease-out;
}
/*
.monaco-table:hover > .monaco-split-view2,
.monaco-table:hover > .monaco-split-view2 .monaco-sash.vertical::before {
border-color: rgba(204, 204, 204, 0.2);
} */
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-tl-row {
display: flex;
height: 100%;
align-items: center;
position: relative;
}
.monaco-tl-indent {
height: 100%;
position: absolute;
top: 0;
left: 16px;
pointer-events: none;
}
.hide-arrows .monaco-tl-indent {
left: 12px;
}
.monaco-tl-indent > .indent-guide {
display: inline-block;
box-sizing: border-box;
height: 100%;
border-left: 1px solid transparent;
}
.monaco-tl-indent > .indent-guide {
transition: border-color 0.1s linear;
}
.monaco-tl-twistie,
.monaco-tl-contents {
height: 100%;
}
.monaco-tl-twistie {
font-size: 10px;
text-align: right;
padding-right: 6px;
flex-shrink: 0;
width: 16px;
display: flex !important;
align-items: center;
justify-content: center;
transform: translateX(3px);
}
.monaco-tl-contents {
flex: 1;
overflow: hidden;
}
.monaco-tl-twistie::before {
border-radius: 20px;
}
.monaco-tl-twistie.collapsed::before {
transform: rotate(-90deg);
}
.monaco-tl-twistie.codicon-tree-item-loading::before {
/* Use steps to throttle FPS to reduce CPU usage */
animation: codicon-spin 1.25s steps(30) infinite;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* -- zone widget */
.monaco-editor .zone-widget .zone-widget-container.reference-zone-widget {
border-top-width: 1px;
border-bottom-width: 1px;
}
.monaco-editor .reference-zone-widget .inline {
display: inline-block;
vertical-align: top;
}
.monaco-editor .reference-zone-widget .messages {
height: 100%;
width: 100%;
text-align: center;
padding: 3em 0;
}
.monaco-editor .reference-zone-widget .ref-tree {
line-height: 23px;
background-color: var(--vscode-peekViewResult-background);
color: var(--vscode-peekViewResult-lineForeground);
}
.monaco-editor .reference-zone-widget .ref-tree .reference {
text-overflow: ellipsis;
overflow: hidden;
}
.monaco-editor .reference-zone-widget .ref-tree .reference-file {
display: inline-flex;
width: 100%;
height: 100%;
color: var(--vscode-peekViewResult-fileForeground);
}
.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .selected .reference-file {
color: inherit !important;
}
.monaco-editor .reference-zone-widget .ref-tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) {
background-color: var(--vscode-peekViewResult-selectionBackground);
color: var(--vscode-peekViewResult-selectionForeground) !important;
}
.monaco-editor .reference-zone-widget .ref-tree .reference-file .count {
margin-right: 12px;
margin-left: auto;
}
.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight {
background-color: var(--vscode-peekViewResult-matchHighlightBackground);
}
.monaco-editor .reference-zone-widget .preview .reference-decoration {
background-color: var(--vscode-peekViewEditor-matchHighlightBackground);
border: 2px solid var(--vscode-peekViewEditor-matchHighlightBorder);
box-sizing: border-box;
}
.monaco-editor .reference-zone-widget .preview .monaco-editor .monaco-editor-background,
.monaco-editor .reference-zone-widget .preview .monaco-editor .inputarea.ime-input {
background-color: var(--vscode-peekViewEditor-background);
}
.monaco-editor .reference-zone-widget .preview .monaco-editor .margin {
background-color: var(--vscode-peekViewEditorGutter-background);
}
/* High Contrast Theming */
.monaco-editor.hc-black .reference-zone-widget .ref-tree .reference-file {
font-weight: bold;
}
.monaco-editor.hc-black .reference-zone-widget .ref-tree .referenceMatch .highlight {
border: 1px dotted var(--vscode-contrastActiveBorder, transparent);
box-sizing: border-box;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-count-badge {
padding: 3px 6px;
border-radius: 11px;
font-size: 11px;
min-width: 18px;
min-height: 18px;
line-height: 11px;
font-weight: normal;
text-align: center;
display: inline-block;
box-sizing: border-box;
}
.monaco-count-badge.long {
padding: 2px 3px;
border-radius: 2px;
min-height: auto;
line-height: normal;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* ---------- Icon label ---------- */
.monaco-icon-label {
display: flex; /* required for icons support :before rule */
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-icon-label::before {
/* svg icons rendered as background image */
background-size: 16px;
background-position: left center;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
line-height: inherit !important;
display: inline-block;
/* fonts icons */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
vertical-align: top;
flex-shrink: 0; /* fix for https://github.com/microsoft/vscode/issues/13787 */
}
.monaco-icon-label > .monaco-icon-label-container {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-name-container > .label-name {
color: inherit;
white-space: pre; /* enable to show labels that include multiple whitespaces */
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-name-container > .label-name > .label-separator {
margin: 0 2px;
opacity: 0.5;
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
opacity: .7;
margin-left: 0.5em;
font-size: 0.9em;
white-space: pre; /* enable to show labels that include multiple whitespaces */
}
.monaco-icon-label.nowrap > .monaco-icon-label-container > .monaco-icon-description-container > .label-description{
white-space: nowrap
}
.vs .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
opacity: .95;
}
.monaco-icon-label.italic > .monaco-icon-label-container > .monaco-icon-name-container > .label-name,
.monaco-icon-label.italic > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
font-style: italic;
}
.monaco-icon-label.deprecated {
text-decoration: line-through;
opacity: 0.66;
}
/* make sure apply italic font style to decorations as well */
.monaco-icon-label.italic::after {
font-style: italic;
}
.monaco-icon-label.strikethrough > .monaco-icon-label-container > .monaco-icon-name-container > .label-name,
.monaco-icon-label.strikethrough > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
text-decoration: line-through;
}
.monaco-icon-label::after {
opacity: 0.75;
font-size: 90%;
font-weight: 600;
margin: auto 16px 0 5px; /* https://github.com/microsoft/vscode/issues/113223 */
text-align: center;
}
/* make sure selection color wins when a label is being selected */
.monaco-list:focus .selected .monaco-icon-label, /* list */
.monaco-list:focus .selected .monaco-icon-label::after
{
color: inherit !important;
}
.monaco-list-row.focused.selected .label-description,
.monaco-list-row.selected .label-description {
opacity: .8;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-hover {
cursor: default;
position: absolute;
overflow: hidden;
z-index: 50;
user-select: text;
-webkit-user-select: text;
-ms-user-select: text;
box-sizing: initial;
animation: fadein 100ms linear;
line-height: 1.5em;
}
.monaco-hover.hidden {
display: none;
}
.monaco-hover a:hover {
cursor: pointer;
}
.monaco-hover .hover-contents:not(.html-hover-contents) {
padding: 4px 8px;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
max-width: 500px;
word-wrap: break-word;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
min-width: 100%;
}
.monaco-hover p,
.monaco-hover .code,
.monaco-hover ul {
margin: 8px 0;
}
.monaco-hover code {
font-family: var(--monaco-monospace-font);
}
.monaco-hover hr {
box-sizing: border-box;
border-left: 0px;
border-right: 0px;
margin-top: 4px;
margin-bottom: -4px;
margin-left: -8px;
margin-right: -8px;
height: 1px;
}
.monaco-hover p:first-child,
.monaco-hover .code:first-child,
.monaco-hover ul:first-child {
margin-top: 0;
}
.monaco-hover p:last-child,
.monaco-hover .code:last-child,
.monaco-hover ul:last-child {
margin-bottom: 0;
}
/* MarkupContent Layout */
.monaco-hover ul {
padding-left: 20px;
}
.monaco-hover ol {
padding-left: 20px;
}
.monaco-hover li > p {
margin-bottom: 0;
}
.monaco-hover li > ul {
margin-top: 0;
}
.monaco-hover code {
border-radius: 3px;
padding: 0 0.4em;
}
.monaco-hover .monaco-tokenized-source {
white-space: pre-wrap;
}
.monaco-hover .hover-row.status-bar {
font-size: 12px;
line-height: 22px;
}
.monaco-hover .hover-row.status-bar .actions {
display: flex;
padding: 0px 8px;
}
.monaco-hover .hover-row.status-bar .actions .action-container {
margin-right: 16px;
cursor: pointer;
}
.monaco-hover .hover-row.status-bar .actions .action-container .action .icon {
padding-right: 4px;
}
.monaco-hover .markdown-hover .hover-contents .codicon {
color: inherit;
font-size: inherit;
vertical-align: middle;
}
.monaco-hover .hover-contents a.code-link:hover,
.monaco-hover .hover-contents a.code-link {
color: inherit;
}
.monaco-hover .hover-contents a.code-link:before {
content: '(';
}
.monaco-hover .hover-contents a.code-link:after {
content: ')';
}
.monaco-hover .hover-contents a.code-link > span {
text-decoration: underline;
/** Hack to force underline to show **/
border-bottom: 1px solid transparent;
text-underline-position: under;
}
/** Spans in markdown hovers need a margin-bottom to avoid looking cramped: https://github.com/microsoft/vscode/issues/101496 **/
.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span {
margin-bottom: 4px;
display: inline-block;
}
.monaco-hover-content .action-container a {
-webkit-user-select: none;
user-select: none;
}
.monaco-hover-content .action-container.disabled {
pointer-events: none;
opacity: 0.4;
cursor: default;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-custom-checkbox {
margin-left: 2px;
float: left;
cursor: pointer;
overflow: hidden;
width: 20px;
height: 20px;
border-radius: 3px;
border: 1px solid transparent;
padding: 1px;
box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.monaco-custom-checkbox:hover {
background-color: var(--vscode-inputOption-hoverBackground);
}
.hc-black .monaco-custom-checkbox:hover {
border: 1px dashed var(--vscode-focusBorder);
}
.hc-black .monaco-custom-checkbox {
background: none;
}
.hc-black .monaco-custom-checkbox:hover {
background: none;
}
.monaco-custom-checkbox.monaco-simple-checkbox {
height: 18px;
width: 18px;
border: 1px solid transparent;
border-radius: 3px;
margin-right: 9px;
margin-left: 0px;
padding: 0px;
opacity: 1;
background-size: 16px !important;
}
/* hide check when unchecked */
.monaco-custom-checkbox.monaco-simple-checkbox:not(.checked)::before {
visibility: hidden;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-inputbox {
position: relative;
display: block;
padding: 0;
box-sizing: border-box;
/* Customizable */
font-size: inherit;
}
.monaco-inputbox.idle {
border: 1px solid transparent;
}
.monaco-inputbox > .ibwrapper > .input,
.monaco-inputbox > .ibwrapper > .mirror {
/* Customizable */
padding: 4px;
}
.monaco-inputbox > .ibwrapper {
position: relative;
width: 100%;
height: 100%;
}
.monaco-inputbox > .ibwrapper > .input {
display: inline-block;
box-sizing: border-box;
width: 100%;
height: 100%;
line-height: inherit;
border: none;
font-family: inherit;
font-size: inherit;
resize: none;
color: inherit;
}
.monaco-inputbox > .ibwrapper > input {
text-overflow: ellipsis;
}
.monaco-inputbox > .ibwrapper > textarea.input {
display: block;
-ms-overflow-style: none; /* IE 10+: hide scrollbars */
scrollbar-width: none; /* Firefox: hide scrollbars */
outline: none;
}
.monaco-inputbox > .ibwrapper > textarea.input::-webkit-scrollbar {
display: none; /* Chrome + Safari: hide scrollbar */
}
.monaco-inputbox > .ibwrapper > textarea.input.empty {
white-space: nowrap;
}
.monaco-inputbox > .ibwrapper > .mirror {
position: absolute;
display: inline-block;
width: 100%;
top: 0;
left: 0;
box-sizing: border-box;
white-space: pre-wrap;
visibility: hidden;
word-wrap: break-word;
}
/* Context view */
.monaco-inputbox-container {
text-align: right;
}
.monaco-inputbox-container .monaco-inputbox-message {
display: inline-block;
overflow: hidden;
text-align: left;
width: 100%;
box-sizing: border-box;
padding: 0.4em;
font-size: 12px;
line-height: 17px;
margin-top: -1px;
word-wrap: break-word;
}
/* Action bar support */
.monaco-inputbox .monaco-action-bar {
position: absolute;
right: 2px;
top: 4px;
}
.monaco-inputbox .monaco-action-bar .action-item {
margin-left: 2px;
}
.monaco-inputbox .monaco-action-bar .action-item .codicon {
background-repeat: no-repeat;
width: 16px;
height: 16px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* ---------- Find input ---------- */
.monaco-findInput {
position: relative;
}
.monaco-findInput .monaco-inputbox {
font-size: 13px;
width: 100%;
}
.monaco-findInput > .controls {
position: absolute;
top: 3px;
right: 2px;
}
.vs .monaco-findInput.disabled {
background-color: #E1E1E1;
}
/* Theming */
.vs-dark .monaco-findInput.disabled {
background-color: #333;
}
/* Highlighting */
.monaco-findInput.highlight-0 .controls {
animation: monaco-findInput-highlight-0 100ms linear 0s;
}
.monaco-findInput.highlight-1 .controls {
animation: monaco-findInput-highlight-1 100ms linear 0s;
}
.hc-black .monaco-findInput.highlight-0 .controls,
.vs-dark .monaco-findInput.highlight-0 .controls {
animation: monaco-findInput-highlight-dark-0 100ms linear 0s;
}
.hc-black .monaco-findInput.highlight-1 .controls,
.vs-dark .monaco-findInput.highlight-1 .controls {
animation: monaco-findInput-highlight-dark-1 100ms linear 0s;
}
@keyframes monaco-findInput-highlight-0 {
0% { background: rgba(253, 255, 0, 0.8); }
100% { background: transparent; }
}
@keyframes monaco-findInput-highlight-1 {
0% { background: rgba(253, 255, 0, 0.8); }
/* Made intentionally different such that the CSS minifier does not collapse the two animations into a single one*/
99% { background: transparent; }
}
@keyframes monaco-findInput-highlight-dark-0 {
0% { background: rgba(255, 255, 255, 0.44); }
100% { background: transparent; }
}
@keyframes monaco-findInput-highlight-dark-1 {
0% { background: rgba(255, 255, 255, 0.44); }
/* Made intentionally different such that the CSS minifier does not collapse the two animations into a single one*/
99% { background: transparent; }
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* marker zone */
.monaco-editor .peekview-widget .head .peekview-title .severity-icon {
display: inline-block;
vertical-align: text-top;
margin-right: 4px;
}
.monaco-editor .marker-widget {
text-overflow: ellipsis;
white-space: nowrap;
}
.monaco-editor .marker-widget > .stale {
opacity: 0.6;
font-style: italic;
}
.monaco-editor .marker-widget .title {
display: inline-block;
padding-right: 5px;
}
.monaco-editor .marker-widget .descriptioncontainer {
position: absolute;
white-space: pre;
user-select: text;
-webkit-user-select: text;
-ms-user-select: text;
padding: 8px 12px 0 20px;
}
.monaco-editor .marker-widget .descriptioncontainer .message {
display: flex;
flex-direction: column;
}
.monaco-editor .marker-widget .descriptioncontainer .message .details {
padding-left: 6px;
}
.monaco-editor .marker-widget .descriptioncontainer .message .source,
.monaco-editor .marker-widget .descriptioncontainer .message span.code {
opacity: 0.6;
}
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link {
opacity: 0.6;
color: inherit;
}
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:before {
content: '(';
}
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link:after {
content: ')';
}
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link > span {
text-decoration: underline;
/** Hack to force underline to show **/
border-bottom: 1px solid transparent;
text-underline-position: under;
color: var(--vscode-textLink-foreground);
}
.monaco-editor .marker-widget .descriptioncontainer .message a.code-link > span {
color: var(--vscode-textLink-activeForeground);
}
.monaco-editor .marker-widget .descriptioncontainer .filename {
cursor: pointer;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor.vs .dnd-target {
border-right: 2px dotted black;
color: white; /* opposite of black */
}
.monaco-editor.vs-dark .dnd-target {
border-right: 2px dotted #AEAFAD;
color: #51504f; /* opposite of #AEAFAD */
}
.monaco-editor.hc-black .dnd-target {
border-right: 2px dotted #fff;
color: #000; /* opposite of #fff */
}
.monaco-editor.mouse-default .view-lines,
.monaco-editor.vs-dark.mac.mouse-default .view-lines,
.monaco-editor.hc-black.mac.mouse-default .view-lines {
cursor: default;
}
.monaco-editor.mouse-copy .view-lines,
.monaco-editor.vs-dark.mac.mouse-copy .view-lines,
.monaco-editor.hc-black.mac.mouse-copy .view-lines {
cursor: copy;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Find widget */
.monaco-editor .find-widget {
position: absolute;
z-index: 35;
height: 33px;
overflow: hidden;
line-height: 19px;
transition: transform 200ms linear;
padding: 0 4px;
box-sizing: border-box;
transform: translateY(calc(-100% - 10px)); /* shadow (10px) */
}
.monaco-editor .find-widget textarea {
margin: 0px;
}
.monaco-editor .find-widget.hiddenEditor {
display: none;
}
/* Find widget when replace is toggled on */
.monaco-editor .find-widget.replaceToggled > .replace-part {
display: flex;
}
.monaco-editor .find-widget.visible {
transform: translateY(0);
}
.monaco-editor .find-widget .monaco-inputbox.synthetic-focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
.monaco-editor .find-widget .monaco-inputbox .input {
background-color: transparent;
min-height: 0;
}
.monaco-editor .find-widget .monaco-findInput .input {
font-size: 13px;
}
.monaco-editor .find-widget > .find-part,
.monaco-editor .find-widget > .replace-part {
margin: 4px 0 0 17px;
font-size: 12px;
display: flex;
}
.monaco-editor .find-widget > .find-part .monaco-inputbox,
.monaco-editor .find-widget > .replace-part .monaco-inputbox {
min-height: 25px;
}
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .ibwrapper > .mirror {
padding-right: 22px;
}
.monaco-editor .find-widget > .find-part .monaco-inputbox > .ibwrapper > .input,
.monaco-editor .find-widget > .find-part .monaco-inputbox > .ibwrapper > .mirror,
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .ibwrapper > .input,
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .ibwrapper > .mirror {
padding-top: 2px;
padding-bottom: 2px;
}
.monaco-editor .find-widget > .find-part .find-actions {
height: 25px;
display: flex;
align-items: center;
}
.monaco-editor .find-widget > .replace-part .replace-actions {
height: 25px;
display: flex;
align-items: center;
}
.monaco-editor .find-widget .monaco-findInput {
vertical-align: middle;
display: flex;
flex:1;
}
.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element {
/* Make sure textarea inherits the width correctly */
width: 100%;
}
.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element .scrollbar.vertical {
/* Hide vertical scrollbar */
opacity: 0;
}
.monaco-editor .find-widget .matchesCount {
display: flex;
flex: initial;
margin: 0 0 0 3px;
padding: 2px 0 0 2px;
height: 25px;
vertical-align: middle;
box-sizing: border-box;
text-align: center;
line-height: 23px;
}
.monaco-editor .find-widget .button {
width: 16px;
height: 16px;
padding: 3px;
border-radius: 5px;
display: flex;
flex: initial;
margin-left: 3px;
background-position: center center;
background-repeat: no-repeat;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
/* find in selection button */
.monaco-editor .find-widget .codicon-find-selection {
width: 22px;
height: 22px;
padding: 3px;
border-radius: 5px;
}
.monaco-editor .find-widget .button.left {
margin-left: 0;
margin-right: 3px;
}
.monaco-editor .find-widget .button.wide {
width: auto;
padding: 1px 6px;
top: -1px;
}
.monaco-editor .find-widget .button.toggle {
position: absolute;
top: 0;
left: 3px;
width: 18px;
height: 100%;
border-radius: 0;
box-sizing: border-box;
}
.monaco-editor .find-widget .button.toggle.disabled {
display: none;
}
.monaco-editor .find-widget .disabled {
opacity: 0.3;
cursor: default;
}
.monaco-editor .find-widget > .replace-part {
display: none;
}
.monaco-editor .find-widget > .replace-part > .monaco-findInput {
position: relative;
display: flex;
vertical-align: middle;
flex: auto;
flex-grow: 0;
flex-shrink: 0;
}
.monaco-editor .find-widget > .replace-part > .monaco-findInput > .controls {
position: absolute;
top: 3px;
right: 2px;
}
/* REDUCED */
.monaco-editor .find-widget.reduced-find-widget .matchesCount {
display:none;
}
/* NARROW (SMALLER THAN REDUCED) */
.monaco-editor .find-widget.narrow-find-widget {
max-width: 257px !important;
}
/* COLLAPSED (SMALLER THAN NARROW) */
.monaco-editor .find-widget.collapsed-find-widget {
max-width: 170px !important;
}
.monaco-editor .find-widget.collapsed-find-widget .button.previous,
.monaco-editor .find-widget.collapsed-find-widget .button.next,
.monaco-editor .find-widget.collapsed-find-widget .button.replace,
.monaco-editor .find-widget.collapsed-find-widget .button.replace-all,
.monaco-editor .find-widget.collapsed-find-widget > .find-part .monaco-findInput .controls {
display:none;
}
.monaco-editor .findMatch {
animation-duration: 0;
animation-name: inherit !important;
}
.monaco-editor .find-widget .monaco-sash {
left: 0 !important;
}
.monaco-editor.hc-black .find-widget .button:before {
position: relative;
top: 1px;
left: 2px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .margin-view-overlays .codicon-folding-expanded,
.monaco-editor .margin-view-overlays .codicon-folding-collapsed {
cursor: pointer;
opacity: 0;
transition: opacity 0.5s;
display: flex;
align-items: center;
justify-content: center;
font-size: 140%;
margin-left: 2px;
}
.monaco-editor .margin-view-overlays:hover .codicon,
.monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed,
.monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons {
opacity: 1;
}
.monaco-editor .inline-folded:after {
color: grey;
margin: 0.1em 0.2em 0 0.2em;
content: "⋯";
display: inline;
line-height: 1em;
cursor: pointer;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .iPadShowKeyboard {
width: 58px;
min-width: 0;
height: 36px;
min-height: 0;
margin: 0;
padding: 0;
position: absolute;
resize: none;
overflow: hidden;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCA1MyAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwKSI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNDguMDM2NCA0LjAxMDQySDQuMDA3NzlMNC4wMDc3OSAzMi4wMjg2SDQ4LjAzNjRWNC4wMTA0MlpNNC4wMDc3OSAwLjAwNzgxMjVDMS43OTcyMSAwLjAwNzgxMjUgMC4wMDUxODc5OSAxLjc5OTg0IDAuMDA1MTg3OTkgNC4wMTA0MlYzMi4wMjg2QzAuMDA1MTg3OTkgMzQuMjM5MiAxLjc5NzIxIDM2LjAzMTIgNC4wMDc3OSAzNi4wMzEySDQ4LjAzNjRDNTAuMjQ3IDM2LjAzMTIgNTIuMDM5IDM0LjIzOTIgNTIuMDM5IDMyLjAyODZWNC4wMTA0MkM1Mi4wMzkgMS43OTk4NCA1MC4yNDcgMC4wMDc4MTI1IDQ4LjAzNjQgMC4wMDc4MTI1SDQuMDA3NzlaTTguMDEwNDIgOC4wMTMwMkgxMi4wMTNWMTIuMDE1Nkg4LjAxMDQyVjguMDEzMDJaTTIwLjAxODIgOC4wMTMwMkgxNi4wMTU2VjEyLjAxNTZIMjAuMDE4MlY4LjAxMzAyWk0yNC4wMjA4IDguMDEzMDJIMjguMDIzNFYxMi4wMTU2SDI0LjAyMDhWOC4wMTMwMlpNMzYuMDI4NiA4LjAxMzAySDMyLjAyNlYxMi4wMTU2SDM2LjAyODZWOC4wMTMwMlpNNDAuMDMxMiA4LjAxMzAySDQ0LjAzMzlWMTIuMDE1Nkg0MC4wMzEyVjguMDEzMDJaTTE2LjAxNTYgMTYuMDE4Mkg4LjAxMDQyVjIwLjAyMDhIMTYuMDE1NlYxNi4wMTgyWk0yMC4wMTgyIDE2LjAxODJIMjQuMDIwOFYyMC4wMjA4SDIwLjAxODJWMTYuMDE4MlpNMzIuMDI2IDE2LjAxODJIMjguMDIzNFYyMC4wMjA4SDMyLjAyNlYxNi4wMTgyWk00NC4wMzM5IDE2LjAxODJWMjAuMDIwOEgzNi4wMjg2VjE2LjAxODJINDQuMDMzOVpNMTIuMDEzIDI0LjAyMzRIOC4wMTA0MlYyOC4wMjZIMTIuMDEzVjI0LjAyMzRaTTE2LjAxNTYgMjQuMDIzNEgzNi4wMjg2VjI4LjAyNkgxNi4wMTU2VjI0LjAyMzRaTTQ0LjAzMzkgMjQuMDIzNEg0MC4wMzEyVjI4LjAyNkg0NC4wMzM5VjI0LjAyMzRaIiBmaWxsPSIjNDI0MjQyIi8+CjwvZz4KPGRlZnM+CjxjbGlwUGF0aCBpZD0iY2xpcDAiPgo8cmVjdCB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==) center center no-repeat;
border: 4px solid #F6F6F6;
border-radius: 4px;
}
.monaco-editor.vs-dark .iPadShowKeyboard {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCA1MyAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwKSI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNDguMDM2NCA0LjAxMDQySDQuMDA3NzlMNC4wMDc3OSAzMi4wMjg2SDQ4LjAzNjRWNC4wMTA0MlpNNC4wMDc3OSAwLjAwNzgxMjVDMS43OTcyMSAwLjAwNzgxMjUgMC4wMDUxODc5OSAxLjc5OTg0IDAuMDA1MTg3OTkgNC4wMTA0MlYzMi4wMjg2QzAuMDA1MTg3OTkgMzQuMjM5MiAxLjc5NzIxIDM2LjAzMTIgNC4wMDc3OSAzNi4wMzEySDQ4LjAzNjRDNTAuMjQ3IDM2LjAzMTIgNTIuMDM5IDM0LjIzOTIgNTIuMDM5IDMyLjAyODZWNC4wMTA0MkM1Mi4wMzkgMS43OTk4NCA1MC4yNDcgMC4wMDc4MTI1IDQ4LjAzNjQgMC4wMDc4MTI1SDQuMDA3NzlaTTguMDEwNDIgOC4wMTMwMkgxMi4wMTNWMTIuMDE1Nkg4LjAxMDQyVjguMDEzMDJaTTIwLjAxODIgOC4wMTMwMkgxNi4wMTU2VjEyLjAxNTZIMjAuMDE4MlY4LjAxMzAyWk0yNC4wMjA4IDguMDEzMDJIMjguMDIzNFYxMi4wMTU2SDI0LjAyMDhWOC4wMTMwMlpNMzYuMDI4NiA4LjAxMzAySDMyLjAyNlYxMi4wMTU2SDM2LjAyODZWOC4wMTMwMlpNNDAuMDMxMiA4LjAxMzAySDQ0LjAzMzlWMTIuMDE1Nkg0MC4wMzEyVjguMDEzMDJaTTE2LjAxNTYgMTYuMDE4Mkg4LjAxMDQyVjIwLjAyMDhIMTYuMDE1NlYxNi4wMTgyWk0yMC4wMTgyIDE2LjAxODJIMjQuMDIwOFYyMC4wMjA4SDIwLjAxODJWMTYuMDE4MlpNMzIuMDI2IDE2LjAxODJIMjguMDIzNFYyMC4wMjA4SDMyLjAyNlYxNi4wMTgyWk00NC4wMzM5IDE2LjAxODJWMjAuMDIwOEgzNi4wMjg2VjE2LjAxODJINDQuMDMzOVpNMTIuMDEzIDI0LjAyMzRIOC4wMTA0MlYyOC4wMjZIMTIuMDEzVjI0LjAyMzRaTTE2LjAxNTYgMjQuMDIzNEgzNi4wMjg2VjI4LjAyNkgxNi4wMTU2VjI0LjAyMzRaTTQ0LjAzMzkgMjQuMDIzNEg0MC4wMzEyVjI4LjAyNkg0NC4wMzM5VjI0LjAyMzRaIiBmaWxsPSIjQzVDNUM1Ii8+CjwvZz4KPGRlZnM+CjxjbGlwUGF0aCBpZD0iY2xpcDAiPgo8cmVjdCB3aWR0aD0iNTMiIGhlaWdodD0iMzYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==) center center no-repeat;
border: 4px solid #252526;
}</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .snippet-placeholder {
min-width: 2px;
outline-style: solid;
outline-width: 1px;
background-color: var(--vscode-editor-snippetTabstopHighlightBackground, transparent);
outline-color: var(--vscode-editor-snippetTabstopHighlightBorder, transparent);
}
.monaco-editor .finish-snippet-placeholder {
outline-style: solid;
outline-width: 1px;
background-color: var(--vscode-editor-snippetFinalTabstopHighlightBackground, transparent);
outline-color: var(--vscode-editor-snippetFinalTabstopHighlightBorder, transparent);
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@font-face {
font-family: "codicon";
font-display: block;
src: url(http://localhost:1880/vendor/monaco/dist/ade705761eb7e702770d.ttf) format("truetype");
}
.codicon[class*='codicon-'] {
font: normal normal normal 16px/1 codicon;
display: inline-block;
text-decoration: none;
text-rendering: auto;
text-align: center;
text-transform: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
/* icon rules are dynamically created by the platform theme service (see iconsStyleSheet.ts) */
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.codicon-wrench-subaction {
opacity: 0.5;
}
@keyframes codicon-spin {
100% {
transform:rotate(360deg);
}
}
.codicon-sync.codicon-modifier-spin,
.codicon-loading.codicon-modifier-spin,
.codicon-gear.codicon-modifier-spin,
.codicon-notebook-state-executing.codicon-modifier-spin {
/* Use steps to throttle FPS to reduce CPU usage */
animation: codicon-spin 1.5s steps(30) infinite;
}
.codicon-modifier-disabled {
opacity: 0.4;
}
/* custom speed & easing for loading icon */
.codicon-loading,
.codicon-tree-item-loading::before {
animation-duration: 1s !important;
animation-timing-function: cubic-bezier(0.53, 0.21, 0.29, 0.67) !important;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Suggest widget*/
.monaco-editor .suggest-widget {
width: 430px;
z-index: 40;
display: flex;
flex-direction: column;
}
.monaco-editor .suggest-widget.message {
flex-direction: row;
align-items: center;
}
.monaco-editor .suggest-widget,
.monaco-editor .suggest-details {
flex: 0 1 auto;
width: 100%;
border-style: solid;
border-width: 1px;
border-color: var(--vscode-editorSuggestWidget-border);
background-color: var(--vscode-editorSuggestWidget-background);
}
.monaco-editor.hc-black .suggest-widget,
.monaco-editor.hc-black .suggest-details {
border-width: 2px;
}
/* Styles for status bar part */
.monaco-editor .suggest-widget .suggest-status-bar {
box-sizing: border-box;
display: none;
flex-flow: row nowrap;
justify-content: space-between;
width: 100%;
font-size: 80%;
padding: 0 4px 0 4px;
border-top: 1px solid var(--vscode-editorSuggestWidget-border);
overflow: hidden;
}
.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar {
display: flex;
}
.monaco-editor .suggest-widget .suggest-status-bar .left {
padding-right: 8px;
}
.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-label {
color: var(--vscode-editorSuggestWidgetStatus-foreground);
}
.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-item:not(:last-of-type) .action-label {
margin-right: 0;
}
.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar .action-item:not(:last-of-type) .action-label::after {
content: ', ';
margin-right: 0.3em;
}
.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row>.contents>.main>.right>.readMore,
.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore {
display: none;
}
.monaco-editor .suggest-widget.with-status-bar:not(.docs-side) .monaco-list .monaco-list-row:hover>.contents>.main>.right.can-expand-details>.details-label {
width: 100%;
}
/* Styles for Message element for when widget is loading or is empty */
.monaco-editor .suggest-widget>.message {
padding-left: 22px;
}
/** Styles for the list element **/
.monaco-editor .suggest-widget>.tree {
height: 100%;
width: 100%;
}
.monaco-editor .suggest-widget .monaco-list {
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
/** Styles for each row in the list element **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row {
display: flex;
-mox-box-sizing: border-box;
box-sizing: border-box;
padding-right: 10px;
background-repeat: no-repeat;
background-position: 2px 2px;
white-space: nowrap;
cursor: pointer;
touch-action: none;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused {
color: var(--vscode-editorSuggestWidget-selectedForeground);
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused .codicon {
color: var(--vscode-editorSuggestWidget-selectedIconForeground);
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents {
flex: 1;
height: 100%;
overflow: hidden;
padding-left: 2px;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main {
display: flex;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
justify-content: space-between;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left, .monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right {
display: flex;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused)>.contents>.main .monaco-icon-label {
color: var(--vscode-editorSuggestWidget-foreground);
}
.monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight {
font-weight: bold;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main .monaco-highlighted-label .highlight {
color: var(--vscode-editorSuggestWidget-highlightForeground);
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused>.contents>.main .monaco-highlighted-label .highlight {
color: var(--vscode-editorSuggestWidget-focusHighlightForeground);
}
/** ReadMore Icon styles **/
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close,
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore::before {
color: inherit;
opacity: 1;
font-size: 14px;
cursor: pointer;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close {
position: absolute;
top: 6px;
right: 2px;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.codicon-close:hover,
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore:hover {
opacity: 1;
}
/** signature, qualifier, type/details opacity **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label {
opacity: 0.7;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.signature-label {
overflow: hidden;
text-overflow: ellipsis;
opacity: 0.6;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.qualifier-label {
margin-left: 12px;
opacity: 0.4;
font-size: 85%;
line-height: initial;
text-overflow: ellipsis;
overflow: hidden;
align-self: center;
}
/** Type Info and icon next to the label in the focused completion item **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label {
font-size: 85%;
margin-left: 1.1em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label>.monaco-tokenized-source {
display: inline;
}
/** Details: if using CompletionItem#details, show on focus **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.details-label {
display: none;
}
.monaco-editor .suggest-widget:not(.shows-details) .monaco-list .monaco-list-row.focused>.contents>.main>.right>.details-label {
display: inline;
}
/** Details: if using CompletionItemLabel#details, always show **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.right>.details-label,
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused:not(.string-label)>.contents>.main>.right>.details-label {
display: inline;
}
/** Ellipsis on hover **/
.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right.can-expand-details>.details-label {
width: calc(100% - 26px);
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left {
flex-shrink: 1;
flex-grow: 1;
overflow: hidden;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.left>.monaco-icon-label {
flex-shrink: 0;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label)>.contents>.main>.left>.monaco-icon-label {
max-width: 100%;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.left>.monaco-icon-label {
flex-shrink: 1;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right {
overflow: hidden;
flex-shrink: 4;
max-width: 70%;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row>.contents>.main>.right>.readMore {
display: inline-block;
position: absolute;
right: 10px;
width: 18px;
height: 18px;
visibility: hidden;
}
/** Do NOT display ReadMore when docs is side/below **/
.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row>.contents>.main>.right>.readMore {
display: none !important;
}
/** Do NOT display ReadMore when using plain CompletionItemLabel (details/documentation might not be resolved) **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label>.contents>.main>.right>.readMore {
display: none;
}
/** Focused item can show ReadMore, but can't when docs is side/below **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused.string-label>.contents>.main>.right>.readMore {
display: inline-block;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused:hover>.contents>.main>.right>.readMore {
visibility: visible;
}
/** Styles for each row in the list **/
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated {
opacity: 0.66;
text-decoration: unset;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated>.monaco-icon-label-container>.monaco-icon-name-container {
text-decoration: line-through;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label::before {
height: 100%;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon {
display: block;
height: 16px;
width: 16px;
margin-left: 2px;
background-repeat: no-repeat;
background-size: 80%;
background-position: center;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.hide {
display: none;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon {
display: flex;
align-items: center;
margin-right: 4px;
}
.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .icon, .monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .suggest-icon::before {
display: none;
}
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor .colorspan {
margin: 0 0 0 0.3em;
border: 0.1em solid #000;
width: 0.7em;
height: 0.7em;
display: inline-block;
}
/** Styles for the docs of the completion item in focus **/
.monaco-editor .suggest-details-container {
z-index: 41;
}
.monaco-editor .suggest-details {
display: flex;
flex-direction: column;
cursor: default;
color: var(--vscode-editorSuggestWidget-foreground);
}
.monaco-editor .suggest-details.focused {
border-color: var(--vscode-focusBorder);
}
.monaco-editor .suggest-details a {
color: var(--vscode-textLink-foreground);
}
.monaco-editor .suggest-details a:hover {
color: var(--vscode-textLink-activeForeground);
}
.monaco-editor .suggest-details code {
background-color: var(--vscode-textCodeBlock-background);
}
.monaco-editor .suggest-details.no-docs {
display: none;
}
.monaco-editor .suggest-details>.monaco-scrollable-element {
flex: 1;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body {
box-sizing: border-box;
height: 100%;
width: 100%;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type {
flex: 2;
overflow: hidden;
text-overflow: ellipsis;
opacity: 0.7;
white-space: pre;
margin: 0 24px 0 0;
padding: 4px 0 12px 5px;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.header>.type.auto-wrap {
white-space: normal;
word-break: break-all;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs {
margin: 0;
padding: 4px 5px;
white-space: pre-wrap;
}
.monaco-editor .suggest-details.no-type>.monaco-scrollable-element>.body>.docs {
margin-right: 24px;
overflow: hidden;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs {
padding: 0;
white-space: initial;
min-height: calc(1rem + 8px);
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div,
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>span:not(:empty) {
padding: 4px 5px;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:first-child {
margin-top: 0;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs>div>p:last-child {
margin-bottom: 0;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .monaco-tokenized-source {
white-space: pre;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs .code {
white-space: pre-wrap;
word-wrap: break-word;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>.docs.markdown-docs .codicon {
vertical-align: sub;
}
.monaco-editor .suggest-details>.monaco-scrollable-element>.body>p:empty {
display: none;
}
.monaco-editor .suggest-details code {
border-radius: 3px;
padding: 0 0.4em;
}
.monaco-editor .suggest-details ul {
padding-left: 20px;
}
.monaco-editor .suggest-details ol {
padding-left: 20px;
}
.monaco-editor .suggest-details p code {
font-family: var(--monaco-monospace-font);
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .suggest-preview-additional-widget {
white-space: nowrap;
}
.monaco-editor .suggest-preview-additional-widget .content-spacer {
color: transparent;
white-space: pre;
}
.monaco-editor .suggest-preview-additional-widget .button {
display: inline-block;
cursor: pointer;
text-decoration: underline;
text-underline-position: under;
}
.monaco-editor .ghost-text-hidden {
opacity: 0;
font-size: 0;
}
.monaco-editor .ghost-text-decoration {
font-style: italic;
}
.monaco-editor .suggest-preview-text {
font-style: italic;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .tokens-inspect-widget {
z-index: 50;
user-select: text;
-webkit-user-select: text;
-ms-user-select: text;
padding: 10px;
}
.tokens-inspect-separator {
height: 1px;
border: 0;
}
.monaco-editor .tokens-inspect-widget .tm-token {
font-family: var(--monaco-monospace-font);
}
.monaco-editor .tokens-inspect-widget .tm-token-length {
font-weight: normal;
font-size: 60%;
float: right;
}
.monaco-editor .tokens-inspect-widget .tm-metadata-table {
width: 100%;
}
.monaco-editor .tokens-inspect-widget .tm-metadata-value {
font-family: var(--monaco-monospace-font);
text-align: right;
}
.monaco-editor .tokens-inspect-widget .tm-token-type {
font-family: var(--monaco-monospace-font);
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .detected-link,
.monaco-editor .detected-link-active {
text-decoration: underline;
text-underline-position: under;
}
.monaco-editor .detected-link-active {
cursor: pointer;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .parameter-hints-widget {
/* Must be higher than the sash's z-index and terminal canvases but lower than the suggest widget */
z-index: 39;
display: flex;
flex-direction: column;
line-height: 1.5em;
}
.monaco-editor .parameter-hints-widget > .phwrapper {
max-width: 440px;
display: flex;
flex-direction: row;
}
.monaco-editor .parameter-hints-widget.multiple {
min-height: 3.3em;
padding: 0;
}
.monaco-editor .parameter-hints-widget.visible {
transition: left .05s ease-in-out;
}
.monaco-editor .parameter-hints-widget p,
.monaco-editor .parameter-hints-widget ul {
margin: 8px 0;
}
.monaco-editor .parameter-hints-widget .monaco-scrollable-element,
.monaco-editor .parameter-hints-widget .body {
display: flex;
flex: 1;
flex-direction: column;
min-height: 100%;
}
.monaco-editor .parameter-hints-widget .signature {
padding: 4px 5px;
}
.monaco-editor .parameter-hints-widget .docs {
padding: 0 10px 0 5px;
white-space: pre-wrap;
}
.monaco-editor .parameter-hints-widget .docs.empty {
display: none;
}
.monaco-editor .parameter-hints-widget .docs .markdown-docs {
white-space: initial;
}
.monaco-editor .parameter-hints-widget .docs .markdown-docs code {
font-family: var(--monaco-monospace-font);
}
.monaco-editor .parameter-hints-widget .docs .monaco-tokenized-source,
.monaco-editor .parameter-hints-widget .docs .code {
white-space: pre-wrap;
}
.monaco-editor .parameter-hints-widget .docs code {
border-radius: 3px;
padding: 0 0.4em;
}
.monaco-editor .parameter-hints-widget .controls {
display: none;
flex-direction: column;
align-items: center;
min-width: 22px;
justify-content: flex-end;
}
.monaco-editor .parameter-hints-widget.multiple .controls {
display: flex;
padding: 0 2px;
}
.monaco-editor .parameter-hints-widget.multiple .button {
width: 16px;
height: 16px;
background-repeat: no-repeat;
cursor: pointer;
}
.monaco-editor .parameter-hints-widget .button.previous {
bottom: 24px;
}
.monaco-editor .parameter-hints-widget .overloads {
text-align: center;
height: 12px;
line-height: 12px;
font-family: var(--monaco-monospace-font);
}
.monaco-editor .parameter-hints-widget .signature .parameter.active {
font-weight: bold;
}
.monaco-editor .parameter-hints-widget .documentation-parameter > .parameter {
font-weight: bold;
margin-right: 0.5em;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .rename-box {
z-index: 100;
color: inherit;
}
.monaco-editor .rename-box.preview {
padding: 3px 3px 0 3px;
}
.monaco-editor .rename-box .rename-input {
padding: 3px;
width: calc(100% - 6px);
}
.monaco-editor .rename-box .rename-label {
display: none;
opacity: .8;
}
.monaco-editor .rename-box.preview .rename-label {
display: inherit;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .unicode-highlight {
border: 1px solid var(--vscode-editorUnicodeHighlight-border);
box-sizing: border-box;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.editor-banner {
box-sizing: border-box;
cursor: default;
width: 100%;
font-size: 12px;
display: flex;
overflow: visible;
height: 26px;
background: var(--vscode-banner-background);
}
.editor-banner .icon-container {
display: flex;
flex-shrink: 0;
align-items: center;
padding: 0 6px 0 10px;
}
.editor-banner .icon-container.custom-icon {
background-repeat: no-repeat;
background-position: center center;
background-size: 16px;
width: 16px;
padding: 0;
margin: 0 6px 0 10px;
}
.editor-banner .message-container {
display: flex;
align-items: center;
line-height: 26px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.editor-banner .message-container p {
margin-block-start: 0;
margin-block-end: 0;
}
.editor-banner .message-actions-container {
flex-grow: 1;
flex-shrink: 0;
line-height: 26px;
margin: 0 4px;
}
.editor-banner .message-actions-container a.monaco-button {
width: inherit;
margin: 2px 8px;
padding: 0px 12px;
}
.editor-banner .message-actions-container a {
padding: 3px;
margin-left: 12px;
text-decoration: underline;
}
.editor-banner .action-container {
padding: 0 10px 0 6px;
}
.editor-banner {
background-color: var(--vscode-banner-background);
}
.editor-banner,
.editor-banner .action-container .codicon,
.editor-banner .message-actions-container .monaco-link {
color: var(--vscode-banner-foreground);
}
.editor-banner .icon-container .codicon {
color: var(--vscode-banner-iconForeground);
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Default standalone editor fonts */
.monaco-editor {
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", system-ui, "Ubuntu", "Droid Sans", sans-serif;
--monaco-monospace-font: "SF Mono", Monaco, Menlo, Consolas, "Ubuntu Mono", "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace;
}
.monaco-menu .monaco-action-bar.vertical .action-item .action-menu-item:focus .action-label {
stroke-width: 1.2px;
}
.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,
.monaco-editor.hc-black .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label {
stroke-width: 1.2px;
}
.monaco-hover p {
margin: 0;
}
/* See https://github.com/microsoft/monaco-editor/issues/2168#issuecomment-780078600 */
.monaco-aria-container {
position: absolute !important;
top: 0; /* avoid being placed underneath a sibling element */
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
}
/* The hc-black theme is already high contrast optimized */
.monaco-editor.hc-black {
-ms-high-contrast-adjust: none;
}
/* In case the browser goes into high contrast mode and the editor is not configured with the hc-black theme */
@media screen and (-ms-high-contrast:active) {
/* current line highlight */
.monaco-editor.vs .view-overlays .current-line,
.monaco-editor.vs-dark .view-overlays .current-line {
border-color: windowtext !important;
border-left: 0;
border-right: 0;
}
/* view cursors */
.monaco-editor.vs .cursor,
.monaco-editor.vs-dark .cursor {
background-color: windowtext !important;
}
/* dnd target */
.monaco-editor.vs .dnd-target,
.monaco-editor.vs-dark .dnd-target {
border-color: windowtext !important;
}
/* selected text background */
.monaco-editor.vs .selected-text,
.monaco-editor.vs-dark .selected-text {
background-color: highlight !important;
}
/* allow the text to have a transparent background. */
.monaco-editor.vs .view-line,
.monaco-editor.vs-dark .view-line {
-ms-high-contrast-adjust: none;
}
/* text color */
.monaco-editor.vs .view-line span,
.monaco-editor.vs-dark .view-line span {
color: windowtext !important;
}
/* selected text color */
.monaco-editor.vs .view-line span.inline-selected-text,
.monaco-editor.vs-dark .view-line span.inline-selected-text {
color: highlighttext !important;
}
/* allow decorations */
.monaco-editor.vs .view-overlays,
.monaco-editor.vs-dark .view-overlays {
-ms-high-contrast-adjust: none;
}
/* various decorations */
.monaco-editor.vs .selectionHighlight,
.monaco-editor.vs-dark .selectionHighlight,
.monaco-editor.vs .wordHighlight,
.monaco-editor.vs-dark .wordHighlight,
.monaco-editor.vs .wordHighlightStrong,
.monaco-editor.vs-dark .wordHighlightStrong,
.monaco-editor.vs .reference-decoration,
.monaco-editor.vs-dark .reference-decoration {
border: 2px dotted highlight !important;
background: transparent !important;
box-sizing: border-box;
}
.monaco-editor.vs .rangeHighlight,
.monaco-editor.vs-dark .rangeHighlight {
background: transparent !important;
border: 1px dotted activeborder !important;
box-sizing: border-box;
}
.monaco-editor.vs .bracket-match,
.monaco-editor.vs-dark .bracket-match {
border-color: windowtext !important;
background: transparent !important;
}
/* find widget */
.monaco-editor.vs .findMatch,
.monaco-editor.vs-dark .findMatch,
.monaco-editor.vs .currentFindMatch,
.monaco-editor.vs-dark .currentFindMatch {
border: 2px dotted activeborder !important;
background: transparent !important;
box-sizing: border-box;
}
.monaco-editor.vs .find-widget,
.monaco-editor.vs-dark .find-widget {
border: 1px solid windowtext;
}
/* list - used by suggest widget */
.monaco-editor.vs .monaco-list .monaco-list-row,
.monaco-editor.vs-dark .monaco-list .monaco-list-row {
-ms-high-contrast-adjust: none;
color: windowtext !important;
}
.monaco-editor.vs .monaco-list .monaco-list-row.focused,
.monaco-editor.vs-dark .monaco-list .monaco-list-row.focused {
color: highlighttext !important;
background-color: highlight !important;
}
.monaco-editor.vs .monaco-list .monaco-list-row:hover,
.monaco-editor.vs-dark .monaco-list .monaco-list-row:hover {
background: transparent !important;
border: 1px solid highlight;
box-sizing: border-box;
}
/* scrollbars */
.monaco-editor.vs .monaco-scrollable-element > .scrollbar,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar {
-ms-high-contrast-adjust: none;
background: background !important;
border: 1px solid windowtext;
box-sizing: border-box;
}
.monaco-editor.vs .monaco-scrollable-element > .scrollbar > .slider,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar > .slider {
background: windowtext !important;
}
.monaco-editor.vs .monaco-scrollable-element > .scrollbar > .slider:hover,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar > .slider:hover {
background: highlight !important;
}
.monaco-editor.vs .monaco-scrollable-element > .scrollbar > .slider.active,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar > .slider.active {
background: highlight !important;
}
/* overview ruler */
.monaco-editor.vs .decorationsOverviewRuler,
.monaco-editor.vs-dark .decorationsOverviewRuler {
opacity: 0;
}
/* minimap */
.monaco-editor.vs .minimap,
.monaco-editor.vs-dark .minimap {
display: none;
}
/* squiggles */
.monaco-editor.vs .squiggly-d-error,
.monaco-editor.vs-dark .squiggly-d-error {
background: transparent !important;
border-bottom: 4px double #E47777;
}
.monaco-editor.vs .squiggly-c-warning,
.monaco-editor.vs-dark .squiggly-c-warning {
border-bottom: 4px double #71B771;
}
.monaco-editor.vs .squiggly-b-info,
.monaco-editor.vs-dark .squiggly-b-info {
border-bottom: 4px double #71B771;
}
.monaco-editor.vs .squiggly-a-hint,
.monaco-editor.vs-dark .squiggly-a-hint {
border-bottom: 4px double #6c6c6c;
}
/* contextmenu */
.monaco-editor.vs .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label,
.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .action-label {
-ms-high-contrast-adjust: none;
color: highlighttext !important;
background-color: highlight !important;
}
.monaco-editor.vs .monaco-menu .monaco-action-bar.vertical .action-menu-item:hover .action-label,
.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-menu-item:hover .action-label {
-ms-high-contrast-adjust: none;
background: transparent !important;
border: 1px solid highlight;
box-sizing: border-box;
}
/* diff editor */
.monaco-diff-editor.vs .diffOverviewRuler,
.monaco-diff-editor.vs-dark .diffOverviewRuler {
display: none;
}
.monaco-editor.vs .line-insert,
.monaco-editor.vs-dark .line-insert,
.monaco-editor.vs .line-delete,
.monaco-editor.vs-dark .line-delete {
background: transparent !important;
border: 1px solid highlight !important;
box-sizing: border-box;
}
.monaco-editor.vs .char-insert,
.monaco-editor.vs-dark .char-insert,
.monaco-editor.vs .char-delete,
.monaco-editor.vs-dark .char-delete {
background: transparent !important;
}
}
/*.monaco-editor.vs [tabindex="0"]:focus {
outline: 1px solid rgba(0, 122, 204, 0.4);
outline-offset: -1px;
opacity: 1 !important;
}
.monaco-editor.vs-dark [tabindex="0"]:focus {
outline: 1px solid rgba(14, 99, 156, 0.6);
outline-offset: -1px;
opacity: 1 !important;
}*/
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* ---------- DiffEditor ---------- */
.monaco-diff-editor .diffOverview {
z-index: 9;
}
.monaco-diff-editor .diffOverview .diffViewport {
z-index: 10;
}
/* colors not externalized: using transparancy on background */
.monaco-diff-editor.vs .diffOverview { background: rgba(0, 0, 0, 0.03); }
.monaco-diff-editor.vs-dark .diffOverview { background: rgba(255, 255, 255, 0.01); }
.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar { background: rgba(0,0,0,0); }
.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar { background: rgba(0,0,0,0); }
.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar { background: none; }
.monaco-scrollable-element.modified-in-monaco-diff-editor .slider {
z-index: 10;
}
.modified-in-monaco-diff-editor .slider.active { background: rgba(171, 171, 171, .4); }
.modified-in-monaco-diff-editor.hc-black .slider.active { background: none; }
/* ---------- Diff ---------- */
.monaco-editor .insert-sign,
.monaco-diff-editor .insert-sign,
.monaco-editor .delete-sign,
.monaco-diff-editor .delete-sign {
font-size: 11px !important;
opacity: 0.7 !important;
display: flex !important;
align-items: center;
}
.monaco-editor.hc-black .insert-sign,
.monaco-diff-editor.hc-black .insert-sign,
.monaco-editor.hc-black .delete-sign,
.monaco-diff-editor.hc-black .delete-sign {
opacity: 1;
}
.monaco-editor .inline-deleted-margin-view-zone {
text-align: right;
}
.monaco-editor .inline-added-margin-view-zone {
text-align: right;
}
/* ---------- Inline Diff ---------- */
.monaco-editor .view-zones .view-lines .view-line span {
display: inline-block;
}
.monaco-editor .margin-view-zones .lightbulb-glyph:hover {
cursor: pointer;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-diff-editor .diff-review-line-number {
text-align: right;
display: inline-block;
}
.monaco-diff-editor .diff-review {
position: absolute;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.monaco-diff-editor .diff-review-summary {
padding-left: 10px;
}
.monaco-diff-editor .diff-review-shadow {
position: absolute;
}
.monaco-diff-editor .diff-review-row {
white-space: pre;
}
.monaco-diff-editor .diff-review-table {
display: table;
min-width: 100%;
}
.monaco-diff-editor .diff-review-row {
display: table-row;
width: 100%;
}
.monaco-diff-editor .diff-review-spacer {
display: inline-block;
width: 10px;
vertical-align: middle;
}
.monaco-diff-editor .diff-review-spacer > .codicon {
font-size: 9px !important;
}
.monaco-diff-editor .diff-review-actions {
display: inline-block;
position: absolute;
right: 10px;
top: 2px;
}
.monaco-diff-editor .diff-review-actions .action-label {
width: 16px;
height: 16px;
margin: 2px 0;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.context-view {
position: absolute;
z-index: 2500;
}
.context-view.fixed {
all: initial;
font-family: inherit;
font-size: 13px;
position: fixed;
z-index: 2500;
color: inherit;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.context-view .monaco-menu {
min-width: 130px;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.quick-input-widget {
font-size: 13px;
}
.quick-input-widget .monaco-highlighted-label .highlight,
.quick-input-widget .monaco-highlighted-label .highlight {
color: #0066BF;
}
.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight,
.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight {
color: #9DDDFF;
}
.vs-dark .quick-input-widget .monaco-highlighted-label .highlight,
.vs-dark .quick-input-widget .monaco-highlighted-label .highlight {
color: #0097fb;
}
.hc-black .quick-input-widget .monaco-highlighted-label .highlight,
.hc-black .quick-input-widget .monaco-highlighted-label .highlight {
color: #F38518;
}
.monaco-keybinding > .monaco-keybinding-key {
background-color: rgba(221, 221, 221, 0.4);
border: solid 1px rgba(204, 204, 204, 0.4);
border-bottom-color: rgba(187, 187, 187, 0.4);
box-shadow: inset 0 -1px 0 rgba(187, 187, 187, 0.4);
color: #555;
}
.hc-black .monaco-keybinding > .monaco-keybinding-key {
background-color: transparent;
border: solid 1px rgb(111, 195, 223);
box-shadow: none;
color: #fff;
}
.vs-dark .monaco-keybinding > .monaco-keybinding-key {
background-color: rgba(128, 128, 128, 0.17);
border: solid 1px rgba(51, 51, 51, 0.6);
border-bottom-color: rgba(68, 68, 68, 0.6);
box-shadow: inset 0 -1px 0 rgba(68, 68, 68, 0.6);
color: #ccc;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-text-button {
box-sizing: border-box;
display: flex;
width: 100%;
padding: 4px;
text-align: center;
cursor: pointer;
justify-content: center;
align-items: center;
}
.monaco-text-button:focus {
outline-offset: 2px !important;
}
.monaco-text-button:hover {
text-decoration: none !important;
}
.monaco-button.disabled:focus,
.monaco-button.disabled {
opacity: 0.4 !important;
cursor: default;
}
.monaco-text-button > .codicon {
margin: 0 0.2em;
color: inherit !important;
}
.monaco-button-dropdown {
display: flex;
cursor: pointer;
}
.monaco-button-dropdown > .monaco-dropdown-button {
margin-left: 1px;
}
.monaco-description-button {
flex-direction: column;
}
.monaco-description-button .monaco-button-label {
font-weight: 500;
}
.monaco-description-button .monaco-button-description {
font-style: italic;
}
.monaco-description-button .monaco-button-label,
.monaco-description-button .monaco-button-description
{
display: flex;
justify-content: center;
align-items: center;
}
.monaco-description-button .monaco-button-label > .codicon,
.monaco-description-button .monaco-button-description > .codicon
{
margin: 0 0.2em;
color: inherit !important;
}
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-progress-container {
width: 100%;
height: 5px;
overflow: hidden; /* keep progress bit in bounds */
}
.monaco-progress-container .progress-bit {
width: 2%;
height: 5px;
position: absolute;
left: 0;
display: none;
}
.monaco-progress-container.active .progress-bit {
display: inherit;
}
.monaco-progress-container.discrete .progress-bit {
left: 0;
transition: width 100ms linear;
}
.monaco-progress-container.discrete.done .progress-bit {
width: 100%;
}
.monaco-progress-container.infinite .progress-bit {
animation-name: progress;
animation-duration: 4s;
animation-iteration-count: infinite;
transform: translate3d(0px, 0px, 0px);
animation-timing-function: linear;
}
.monaco-progress-container.infinite.infinite-long-running .progress-bit {
/*
The more smooth `linear` timing function can cause
higher GPU consumption as indicated in
https://github.com/microsoft/vscode/issues/97900 &
https://github.com/microsoft/vscode/issues/138396
*/
animation-timing-function: steps(100);
}
/**
* The progress bit has a width: 2% (1/50) of the parent container. The animation moves it from 0% to 100% of
* that container. Since translateX is relative to the progress bit size, we have to multiple it with
* its relative size to the parent container:
* parent width: 5000%
* bit width: 100%
* translateX should be as follow:
* 50%: 5000% * 50% - 50% (set to center) = 2450%
* 100%: 5000% * 100% - 100% (do not overflow) = 4900%
*/
@keyframes progress { from { transform: translateX(0%) scaleX(1) } 50% { transform: translateX(2500%) scaleX(3) } to { transform: translateX(4900%) scaleX(1) } }
</style><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.quick-input-widget {
position: absolute;
width: 600px;
z-index: 2000;
padding: 0 1px 1px 1px;
left: 50%;
margin-left: -300px;
}
.quick-input-titlebar {
display: flex;
align-items: center;
}
.quick-input-left-action-bar {
display: flex;
margin-left: 4px;
flex: 1;
}
.quick-input-title {
padding: 3px 0px;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
.quick-input-right-action-bar {
display: flex;
margin-right: 4px;
flex: 1;
}
.quick-input-right-action-bar > .actions-container {
justify-content: flex-end;
}
.quick-input-titlebar .monaco-action-bar .action-label.codicon {
background-position: center;
background-repeat: no-repeat;
padding: 2px;
}
.quick-input-description {
margin: 6px;
}
.quick-input-header .quick-input-description {
margin: 4px 2px;
}
.quick-input-header {
display: flex;
padding: 6px 6px 0px 6px;
margin-bottom: -2px;
}
.quick-input-widget.hidden-input .quick-input-header {
/* reduce margins and paddings when input box hidden */
padding: 0;
margin-bottom: 0;
}
.quick-input-and-message {
display: flex;
flex-direction: column;
flex-grow: 1;
min-width: 0;
position: relative;
}
.quick-input-check-all {
align-self: center;
margin: 0;
}
.quick-input-filter {
flex-grow: 1;
display: flex;
position: relative;
}
.quick-input-box {
flex-grow: 1;
}
.quick-input-widget.show-checkboxes .quick-input-box,
.quick-input-widget.show-checkboxes .quick-input-message {
margin-left: 5px;
}
.quick-input-visible-count {
position: absolute;
left: -10000px;
}
.quick-input-count {
align-self: center;
position: absolute;
right: 4px;
display: flex;
align-items: center;
}
.quick-input-count .monaco-count-badge {
vertical-align: middle;
padding: 2px 4px;
border-radius: 2px;
min-height: auto;
line-height: normal;
}
.quick-input-action {
margin-left: 6px;
}
.quick-input-action .monaco-text-button {
font-size: 11px;
padding: 0 6px;
display: flex;
height: 27.5px;
align-items: center;
}
.quick-input-message {
margin-top: -1px;
padding: 5px;
overflow-wrap: break-word;
}
.quick-input-message > .codicon {
margin: 0 0.2em;
vertical-align: text-bottom;
}
.quick-input-progress.monaco-progress-container {
position: relative;
}
.quick-input-progress.monaco-progress-container,
.quick-input-progress.monaco-progress-container .progress-bit {
height: 2px;
}
.quick-input-list {
line-height: 22px;
margin-top: 6px;
}
.quick-input-widget.hidden-input .quick-input-list {
margin-top: 0; /* reduce margins when input box hidden */
}
.quick-input-list .monaco-list {
overflow: hidden;
max-height: calc(20 * 22px);
}
.quick-input-list .quick-input-list-entry {
box-sizing: border-box;
overflow: hidden;
display: flex;
height: 100%;
padding: 0 6px;
}
.quick-input-list .quick-input-list-entry.quick-input-list-separator-border {
border-top-width: 1px;
border-top-style: solid;
}
.quick-input-list .monaco-list-row[data-index="0"] .quick-input-list-entry.quick-input-list-separator-border {
border-top-style: none;
}
.quick-input-list .quick-input-list-label {
overflow: hidden;
display: flex;
height: 100%;
flex: 1;
}
.quick-input-list .quick-input-list-checkbox {
align-self: center;
margin: 0;
}
.quick-input-list .quick-input-list-rows {
overflow: hidden;
text-overflow: ellipsis;
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
margin-left: 5px;
}
.quick-input-widget.show-checkboxes .quick-input-list .quick-input-list-rows {
margin-left: 10px;
}
.quick-input-widget .quick-input-list .quick-input-list-checkbox {
display: none;
}
.quick-input-widget.show-checkboxes .quick-input-list .quick-input-list-checkbox {
display: inline;
}
.quick-input-list .quick-input-list-rows > .quick-input-list-row {
display: flex;
align-items: center;
}
.quick-input-list .quick-input-list-rows > .quick-input-list-row .monaco-icon-label,
.quick-input-list .quick-input-list-rows > .quick-input-list-row .monaco-icon-label .monaco-icon-label-container > .monaco-icon-name-container {
flex: 1; /* make sure the icon label grows within the row */
}
.quick-input-list .quick-input-list-rows > .quick-input-list-row .codicon[class*='codicon-'] {
vertical-align: text-bottom;
}
.quick-input-list .quick-input-list-rows .monaco-highlighted-label span {
opacity: 1;
}
.quick-input-list .quick-input-list-entry .quick-input-list-entry-keybinding {
margin-right: 8px; /* separate from the separator label or scrollbar if any */
}
.quick-input-list .quick-input-list-label-meta {
opacity: 0.7;
line-height: normal;
text-overflow: ellipsis;
overflow: hidden;
}
.quick-input-list .monaco-highlighted-label .highlight {
font-weight: bold;
}
.quick-input-list .quick-input-list-entry .quick-input-list-separator {
margin-right: 8px; /* separate from keybindings or actions */
}
.quick-input-list .quick-input-list-entry-action-bar {
display: flex;
flex: 0;
overflow: visible;
}
.quick-input-list .quick-input-list-entry-action-bar .action-label {
/*
* By default, actions in the quick input action bar are hidden
* until hovered over them or selected.
*/
display: none;
}
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
margin-right: 4px;
padding: 0px 2px 2px 2px;
}
.quick-input-list .quick-input-list-entry-action-bar {
margin-top: 1px;
}
.quick-input-list .quick-input-list-entry-action-bar {
margin-right: 4px; /* separate from scrollbar */
}
.quick-input-list .quick-input-list-entry .quick-input-list-entry-action-bar .action-label.always-visible,
.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar .action-label,
.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label {
display: flex;
}
/* focused items in quick pick */
.quick-input-list .monaco-list-row.focused .monaco-keybinding-key,
.quick-input-list .monaco-list-row.focused .quick-input-list-entry .quick-input-list-separator {
color: inherit
}
.quick-input-list .monaco-list-row.focused .monaco-keybinding-key {
background: none;
}
</style><script type="module" src="chrome-extension://jdkknkkbebbapilgoeccciglkfbmbnfm/hook.js"></script><style>/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-keybinding {
display: flex;
align-items: center;
line-height: 10px;
}
.monaco-keybinding > .monaco-keybinding-key {
display: inline-block;
border-style: solid;
border-width: 1px;
border-radius: 3px;
vertical-align: middle;
font-size: 11px;
padding: 3px 5px;
margin: 0 2px;
}
.monaco-keybinding > .monaco-keybinding-key:first-child {
margin-left: 0;
}
.monaco-keybinding > .monaco-keybinding-key:last-child {
margin-right: 0;
}
.monaco-keybinding > .monaco-keybinding-key-separator {
display: inline-block;
}
.monaco-keybinding > .monaco-keybinding-key-chord-separator {
width: 6px;
}
</style><style type="text/css">/* Copyright 2014-present Evernote Corporation. All rights reserved. */
@keyframes caretBlink {
from { opacity: 1.0; }
to { opacity: 0.0; }
}
@keyframes rotateSpinner {
from {
transform:rotate(0deg);
}
to {
transform:rotate(360deg);
}
}
#text-tool-caret {
animation-name: caretBlink;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(1.0,0,0,1.0);
animation-duration: 1s;
}
#en-markup-loading-spinner {
position: absolute;
top: calc(50% - 16px);
left: calc(50% - 16px);
width: 32px;
height: 32px;
}
#en-markup-loading-spinner img {
position: relative;
top: 0px;
left: 0px;
animation-name: rotateSpinner;
animation-duration: 0.6s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
</style><style type="text/css">/* Copyright 2014-present Evernote Corporation. All rights reserved. */
.skitchToastBoxContainer {
position: absolute;
width: 100%;
text-align: center;
top: 30px;
-webkit-user-select: none;
-moz-user-select: none;
pointer-events: none;
}
.skitchToastBox {
width: 200px;
height: 16px;
padding: 12px;
background-color: rgba(47, 55, 61, 0.95);
border-radius: 4px;
color: white;
cursor: default;
font-size: 10pt;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.32);
font-family: 'Soleil', Helvetica, Arial, sans-serif;
border: 2px rgba(255, 255, 255, 0.38) solid;
}
.lang-zh-cn .skitchToastBox {
font-family: '微软雅黑', 'Microsoft YaHei', SimSun,
'&#x30E1;&#x30A4;&#x30EA;&#x30AA;', Meiryo, 'MS PGothic', 'Soleil',
Helvetica, Arial, sans-serif;
}
.lang-ja-jp .skitchToastBox {
font-family: '&#x30E1;&#x30A4;&#x30EA;&#x30AA;', Meiryo, 'MS PGothic',
'微软雅黑', 'Microsoft YaHei', SimSun, 'Soleil', Helvetica, Arial,
sans-serif;
}
.skitchToast {
padding-left: 20px;
padding-right: 20px;
display: inline-block;
height: 10px;
color: #f1f5f8;
text-align: center;
}
.skitchVisible {
/* Don't remove this class it's a hack used by the Evernote Clipper */
}
</style><style type="text/css">/* Copyright 2014-present Evernote Corporation. All rights reserved. */
@font-face {
font-family: 'Soleil';
src: url(data:application/font-woff2;base64,d09GMgABAAAAAQ5sABIAAAADuOQAAQ4EAAEAgwAAAAAAAAAAAAAAAAAAAAAAAAAAG4SpIhy4XhSHMgZgAJJmCF4JgnMREAqGskiFyggSgrVoATYCJAOdOAuOXgAEIAWPGAfGYAyDGFsKfLME/nOMvX+HnQoMqyRqK6tt2TW8K2BDX9Umu4PZkCXwtMjpcHYNTx6UUmu30UdwcxxnVMvcNgAim7rdXiPZ////////////C5dF2ObuXM7ZvQeSECARwueHlaLVtkJEIaLRAI3ulswSE13cSPdM15RCyYQuuS7A0mBqpQO9pYZWQQMqa9lQb0dpJzHxHpLyCHIi8uBdwF58nNH+YOA40OpJvEjJtaokKaUkx/N5UeSinp5TWoW1vSpFjimBgeFGeCF66U0n6ZUN/qSqC4XC11GKUNmzSy2d5Jxyqw5JzGUlJUnyi0lKkE8BlxadTZsyRm8c1/Cti2hEjzIHnuOZ0fU6OjKc8DbYCHncqnchZTOgK1VPZRW/YGuwBmwn7Zu9nsUDKh5Cf+FWtrJRPdVHvMS330QH2MJdhDcZZTcpF0Nk4/uQLvb9VMH9BIm7mNJnDvMIs7Kz8oegHuEHJOFz4xnnmPexMfyG7y+G7HrXb+LulK9WFjg1OI/rT/VepENU74ARXdTlRumtpFnXEk5cm/OvP1kvp37Fnco3fIeP3lSv8jdKcGDbqm2V1PwCE1/Hb1mq+5RasMwwM9waPesf3YO/Dbiw2Vb/I/yveWLoShvVic5jU/fQEyN8Dx2EiMJo1jLIfJBOJlU2C1nEtxiWpid99q42kCokIYkPeIN/5qFNS1Ui/pszOD0A24DXSN4D6Lh1KgiMEA3R8QiTnoOJWIiNKIRO1SV4nG8S//x7/f/XmCudxvEFrSd82d4Znp9b7/1Ys2LABtsYK0ZsjAkDERE9bkYNxJo4jMbDQs8zsKhDJAci2sdhFWLc7AbFoGq0pJNj9A9/L/9Va5/bAZtDxAzSYCELNFhPMEs0YCP0AccGNL+j2lL7AZrLiXSYPGGzFHQzWhWuSV0qtSxfOhn0hKG5WYZmfQi7nQIAywboT1iSHWADhXjMNnYA5qbQSi+qWMBgY4wVq2ZjGzFqZIoKCgZGNSpiBdbNK0b/2r+VV7xRP//N2U/a3MiBzkEOMjR7kGmzF5mVW0nl4mHAV6na54r71zOoCpZQE31m1Hz4dV9pQzpVaMEhHznztQihnP1n+2897J8vtXJXCmmkkEEuMpxDIdbIJI36izdCXraeoUluHi5JwNkgxaJgIN4/ccnyUx99wWmh8ARHvqrfXamwcz4Xf2yZC0hV2wA4ymlVJdkze1XqwDG9KPAbWmIPuLtLVifpKI6jzCiwwP7I3/jr2IFdDtACB5ZeyB0AIDDQ/N/v8wshKnRPnVy9ukD4dAoUc03M0pgxY1KYQgp/r6vyfSTpi1tqUOOo56Z35mYPePfMHCQOLzRW7siXOjIHGdBfuvp8krrFLeSRRisaxAX6QLt7QJyf7Si0g8wOAYPQlV8Sm+eNC/LdBSQnvPDBOlOxygq0ZSlexTIewbghomtEAE37m4iq5RuRGIfFJdlJ299UrG1g+WC1WlI5Mch0MMdrdXBOOwY9PV3hjsL6+wsVwAJQ2nnnPk/tTSKoE2p6ekoi6g9U5CRN+xkPmAdEA3SzSxfm38ojXurd8E1q7cJUvq68oDU8BA4P9RNrtdCYrp2ItxP9NbUzw0L5TGxkUqCxDBc5v7ZAnGC10zfftumsZpZFxpZswjX9plBeKL/6ojPkRQQTLgzpXLDyK/jc8mIyqW4brLBWJSatR7R+Set3OZ5h+mO66qqS8nXly+1yqsmJExgkyBAkVvTNH+H2vV9qBwSS1VmVKPD0vG2Z2vP0cc/v7N2Z35OmCRJMIdQQUw12aFvY59gp58AfaoduobTllTCe6m+A1cxx/PnxyspxQlx1nzOAg5HbevAoFKNAKQCBNuKReY3IBoPPaJy0qdIqpe0aYj2YOACkty7W9YBonUwAg/NK6ItBvgLEUmHxZ3s19iddkK9JfTV3nYsnO6bwFQankHjTBgTYsgqfz61rb8HmGgUSJHT6zzQegntV/7iXeUfZGI54OIax0lj6qdRSBSZhRVuuWLk8PF2m7s671MHFAI7wfcMDz/60DlaF0kXCiXAIS9UAUHw+nVWpfutqbe/2u2sPLGTr4wknyJqWoGcOotRSlVxdrlZrgDwarxeol72Ekkol27LdM7zDC3yIEWDIECWXXppJ7kN6+SVReFlwPP/9sv/Zu+pX1++BLOSRT46QRKm7Z/qHzfwQgSHlS36FGkcMlmw88hUKicRZjMSp5DX/v6n2tu8OMLsDhX8AaQPXkWMtjklHyaHnz/H039XvfFy992YAzJuHIRFIGYMRKYpUIBi0ALkBIDcQICkBYFAGKa42p5/igFQAN31xpZ9S0n7HVIUUq1z5uHL5j0tXVY5l4dZFl4veRf871/b/Vap2rWoArWqoAYI0ExOC7JDMBiWz0PbhIpl885BlPWXmFM8pz9fZuqp+d3V1dYMk0KTYIEhKpJwIlOUBteRpm3kNgMhAsPkew2ywNKtmVXyabReZbdds2+Eyl0u2+0jJ+P+vWlaK+x5YqB5pDYZNMVrDgxqXZCwjE/qTz9kkIT4e8YX6/IWeUkk6rVJ1rfGtVkdrPIEHskkA1XK9c9qui2Z8kK6N801DKVMkwPPQ5fu6m6GEcuyKrttO6muUUoo1KgBSukUgJvDpU9Au3ZmAArMuwTTA5EH8ewMQGBkpwuQAJDgECrUFtbU0Nal0sjv0vy/dCxawNxMUo+8oThtbnZPNjdY4dx4sfFhYQAtQ4etbmlQhQQcAjYhM2XXVn+0n7a5GThlgZzrHxkIHqf3eqdL0Sep+vAyejiLZ/mrGmrAbjc3koFMIK2AtxeTmf6CWRi1IF/n4b6S0LoIJy3KYxbnfizWxqjqk3SoAG1xbNGYwptAaIYQQIhGJEIkQwpim9rubB5rD8KXjVDoUeURCOOJ7fk9/Z/f3fvw8XmNURVVVxaiqiog6ohb+txC9941zLD2IplK2gUChEObrr6w0sSkJyPILpWWCZODuPluJg/+Me+F3boUhrDtLaKTifb6fa2x1C8Z1YaKEgFFf7fw2ph36Y22oDyhKJCEE7CWbNdzTFzHEQpASwZMVCteYVaUXPkY3pAmOGRUUBIWGbhz/79f0e5jrluOuv3Sj2FGxA2pAZ0D96n3dl9ONwgXDVrvIPvRFsWMCTiWOZbnnWBqNXpacxP+3uf5cYVrCg5U1gA0kNCvFgg78xX7y/FSsjX/hNkax9MHvBTCTkAqyxod/A/RLzoyLBXwYwGBTgDEJ3NV88Pv93i58Lw7V4vt0RcvvTDv+PdgNIiLy2wpTK0KvKLNi7DPn+Ljldok061OURVaIFdduiaQGBNgpSZps+Y7MTqGVAgSYGgrQWCVbf/0Nn5Q3MhKcglqgUBNANRAKKlEQS4ThLZ69GQGcNP6ht8e/9aez/nFUGS75zf9XKNN4E0w0yWRTTKd30CGHHXHSGeecB0FsEIKJBX5wOYABtQCTdiHdnH7aOG58Z0Ii6SZRk7zJjcmLKX86a1o/GzfPNK9yPn++YdGrRdbFTKacGRafiNuSpORQUlnNqYa5ftxFdXWDuMJ+xp0rf6a8oMSUA+WZspktmlcfU39Ta9TZ8qJ3GdCSaGpaNq2BNo12lQ6jM+g59Br6MiaBG8rlcI2CDUlNKb9S/5ToldFKjGa/5rSGA6n0icDFPQmfjFwZ18ldzG1xnz4NAQaAA/Jy4Vx77thclJvLHQSqQTaoyqvPPwp9gpqhfhgVAGAcTIG5sBjWFvgK9IJVhINwkL7Ct+jq4tm8I/IcUbf4lNomvq35aXNqPusvayfWThocw143tW7WpNUTTGN9W/2yxbZoVkXDxoaPttpukOyU/HQ8R+zkSN0yltsumyhDspJs0C11G91BT5SzPLV8rDwjn/Y6fKbP8ccrCorHAUEJC/iBUSlTepWmsqacDaqDHyFSQUKZClK1qJ6Gvd
font-weight: normal;
font-style: normal;
}
</style><style type="text/css">/* Copyright 2019-present Evernote Corporation. All rights reserved. */
#en-markup-disabled {
position: fixed;
z-index: 9999;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
cursor: default;
-webkit-user-select: none;
}
#en-markup-alert-container {
position: absolute;
z-index: 9999;
width: 450px;
left: calc(50% - 225px);
top: calc(50% - 85px);
background-color: white;
box-shadow: 0 2px 7px 1px rgba(0,0,0,0.35);
-webkit-user-select: none;
}
#en-markup-alert-container .cell-1 {
position: relative;
height: 110px;
width: 105px;
float: left;
text-align: center;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAABT3SURBVFhHvZj3V5PptsfvvzBzxhHP8TrjmjnjXHXUQXoJPYAESOg1CSSBhBZCSWgJaQTpRbp0kN6ki1KkgwiE3nsRLChVKbPuDkH0ztx1zy93nb02L0/evHn2J9+9n5b/OPlXdvz/Z0dHR2et4+Oz3v9i/wLoCDo5FvVyePQJGp8OP4kaR/APGl+uHw8/iq/nN8V3wOFh+Dh8Fj4IDndEL48OofP/FesMaO/jjm8BXsH38h2vbyQZ39z1uSDle0Ha73vZAAlwOeYlhUDwfyhxLitzriB4V1R4V9T4P6gGXQVXP73+ydX4V1V4VxHcK8rcK/BBBdY/5FmXoB85poR0gIS0//fQ/12fv0E4Jb/LEBoAxCQiICCl59rCewpsCfX7l5HhP9yL+ckg4ZpR8g2ztNvWmdLYXDm7PHmHQlVyibpLGZJaoU2rvOdVjaLXGDBqDX3q0D51GLgyakVOrzH0rjbwqkLRKvXcynXheXKxOqlA1T5PCZcjB71ZpEmaJN/GJN7Qf3BNO+InFf5lSfrfAEAsmAjo06dP0j4SilwJ7agfjZKuWWTcxuXJOJYouVZoeFTrMOpRAc8wnBYzQZt1WBc+uocQ2+fwoJ/woN8ubsA+YZCYKCQmD5FTh6hpQo/UQc+UQY/kfvfEfmp8n0tMLyWiixjWYSdos+G2WAQ8M4bePGp03B5rUcrUSIXK9rnypsm3VYOvyPj9HTDOgPb29u54f6MWetk45b9sc+8CCrVKk16PYjYa8dssQ7rx0X0OiYMuqaO0jHH3nEmP9HGHqH40p1Hdv0rd/7FGYK1mcDMq4aVt/rRn5XxQ1Xxo5VxI+WxwyXRQ0RQnb5KVO+6XNuKdLHSP66dE9BKCO2zYLaa+Tw29anVdKzRJBYqoB79AkQDGGdDu7q6U3zfIyB8sMm87lCq612j5PEVxnpuFdGKj+4hJQteMMa/8af/cGWrGJCFrnMJt0DBj3NXASKvpyqrqymoayuuYyWPIstQkjaIx37aNpPaNtNZXD5vXkp+txj9Zjq1ZjKiYFxTNsB9N+qWOeMQNOEX02Ae1WTGbjOj1ei7l6mZpt+TZEjs722dAOzs7Un5/uxf7Ey5filqlwWhAQYJCunCxL8kpw9ScSZ/iOXbxIj1+yDgw3ziq2cLQUUrqtry8rJKSAgKhrKqKUFdDaKohtFTVVLwfYJrXIps3Q1s2Ipo3Ilo2oR3VtBnTuBFTvxpRuRhcMBOYOUZPHHSN6iVADbAajTyqtXGPZBD8f7z78O4LkLT/BVT8PwmF8l51uqBnSKdtbB/54QgNvlPZAr982T9l3IoYLmftoJ/QaqekKquogFBRUVFTU1NXV9fS0tLW1tbR1dFB6hlaaFEzZFyzfqfmSNIKbnuXSTLrZUPatRKFJjkzxPIVxuNldvEsO2ucAUyRPQR+q6XPE5RDsZJm6NXNrY2vgAIuGCZeg+rxazAIareKekFIGaLmTvlVLPArVpkZE1jnWISMtAyFhs3qcVFWV1BBqJ6j6Orq6unp6evrG5yaPkYHXM8IqWeiqWeqjrJEGBCkMe53sHxJer5qmpBQvhBQPBOYMUqPe+kU0okLbDJxLVe/F/XPtTfLMNDOgGRYF9BJ1yhlCMhraBc+fsA5e5xRNs+rWPHPmsS7xWooKsmrKqvTWS6F/Qx1JCRJHYlEilEAwtDQEIPBGInMxMTY1NTE3OzUTY3NTdBmGEMzNMpEXw99T1/XMRD1aJRWvsjKn2I+HKJF9TjwW608qrQN468vbMx8AZILvGCSesO5Qo3bYgrypA3TimYCSxa808exbrGaCory6hpII2NTfqh/9QhPW09NS1NEg0KhzlFMTU3Nzc0tLCwsLS2tvjJ4CffNzMxMTEwxaCM9HYPwQkrNOrt0jpc95hPf7xzSjqPXoYyTfpteG/0KiP2dafoNaqWGoM0qvt8pZ8KncM4rd5pEi9WTkZZVRWiaGJs5Ep0eJIY3TITdM9DS0daFHKHRaECBYGIOa2trW1tb7P80uGNjYwNvicn09TC+90mNb4IeL/LzJ1kPhbSILoLfE0Pz1NuTq0Ow2J0BKXAlzDN/86jRCumyTRG6FUwHlC57lkx5hBbg4h+7ptYxsus4uTWhZU0JMdleUDf6qC80X6PY2dnZ29sTPhu0wfB4vJgMHjNGm7n54JpfCWpXQkpm+Bkj9NgXjsxGY8t06YkVoQgIVNre2VbkS1jl3KbX6YZ34yFfxbPMokXnpG5LMgdpjFM3wSKt7PVtSWhrOyO9e1A3KKAxMTGBbwxJAQHEKEQi0eHUHL8yeAn3AQ4egMcszK0c3WybVgTP1iMez4XkjPnF9zlxmkxtM6XHVwZEQIeHh++33ysHSVjn/u7ToBfdS8gepRfOe2ZN4syclG9ek5S+Kycvo6ikiFBVUddU14LSEWsjpoHvDQJAPAhMJpOdnJycnZ1dPhu0weA+kJFIJFDL1gZLcMQ2LgY3b0bAnP5oPCCp35XXYoHNljkD2tvfe/f+jbJAwibvrt9TVGwfMXfcF/KVNWyHUJOVuiunqKgIUw4McvGwgjElztQ5DQgA8SgUChC4ublRqVR3d3faqUEb7ojJAAug7fD2BBK+YTbo+ZvI2sXIgkl2yqB7UKsVNld2cm1IVNQ7uzsApHRfAp8vxWwyiO93zJvwr1pnFE1SFJRk5WRkEQiEqqqqpqamjo4ODCtxsqCKIVPnNCCMq6srhAcIT09Pr88GbTDgE2MBNIlIsifgHw+xOrYi65eiYbFLFdIErda4HJnp9WGRQgD0/sM7RIiEfZFUYDMmYYCSPxlQt+FXv8LQ0FGSkxYB/VUeKE8oCMjUOQ1Ehdje3t4MBsPns0GbTqcDmYeHB+ACE9mRYk+wL+727/4Q1bASWzLNSx/yDG63xuXKzL6aOFNo6/1bldBLhGIZdgsmcZBSMBVQv87s2OIbW2vJSMmK8wUjC+bAc3kgWVCkUBbiTIlpIDZA+Pn5+fv7BwQEMMECmNCEmwAqZnJ2cibYE/Na/Xq3o56uxJbO8NKHPe932OAfiYBECu3u7YJCqmESxFIZznNMspBSOMWsW2UPHIWTvY2lfpf7Ol8wB4qr51weKA5IBwSDkBBYzBEYGMjhsH19/ClOoAjJxdnVh+EDOkFCXV1cCfaknEa/FzuRT1celM5yASik08YuX3b21fhXQBGXSKUy3FYjMVDNCnv4OIob5wBAsILCmvWnfImrB+pUnCwIBjQgDIvFYrPZXC43kMXmhfp0TxRMrNamFgYDCp3OABWpblQiwTHriX/ffvjT1ZiyWV7miGfoKdCcOGUwykRAUZdIZbLcdqOkIUrBtH/NMg8Uyqj3h5T9CQhGu7icxfkCIJAHkuXr6wvygDZAw+cHsdjMrunst0e9bw/7dk5ehkQzvTxFxQT0JAI5q57Ztx/2dDW6bJabMeoR2mVjVyAz92pcBLR/sL/1YUst+hKpXI7XjkkaIhdM+9UsC3oPghvGw5SUlCBl4oqGZesc6LyAxPkCICgdkIfD4fD5fIFAcD+Un5kflZAWmpgpqG1JTckK9fZifAai5NQHvjwIfboaVTbHyRylhXZZ2xfKzG9MilImBlKPuehQIcPtACDH/GmfmqXg9ve8/vcJaBNdJSWVr4H+VNHnQP5+onyJgYKDg0NCQgCMy+EFsjhQV4FsJuT0a6AX8IVXIktn2Rkj7iFdVvgCqcXNaZFCBwcHAKQRe8mxUpZ3CpQ3Ta+GmfQNZ+r4IcXTUkFO6f9I2XlF0+neUM5QQDweLygoCEQCAzjIIIBCeX0Bsqfk1LH7DoKfrISVzLIyRqn3uy3tCqWWXp9uPz5+/AhLh9aDS+RKGW4nOnGI+GjK8/Ei79kGd+I4ISKdJiet8KeiPp8Sz2qI5uHpTaMySCIlROOLA0yAAgYNeAmgkFAxEIx8oh05u4794iC
background-position: 65% 50%;
background-repeat: no-repeat;
}
#en-markup-alert-container .cell-2 {
position: relative;
float: left;
width: 345px;
margin-top: 29px;
margin-bottom: 20px;
}
#en-markup-alert-container .cell-2 .cell-2-title {
margin-bottom: 5px;
padding-right: 30px;
font-size: 12pt;
font-family: Tahoma, Arial;
}
#en-markup-alert-container .cell-2 .cell-2-message {
padding-right: 30px;
font-size: 9.5pt;
font-family: Tahoma, Arial;
}
#en-markup-alert-container .cell-3 {
position: relative;
width: 450px;
height: 60px;
float: left;
background-color: rgb(240,240,240);
}
#en-markup-alert-container .cell-3 button {
position: absolute;
top: 12px;
right: 15px;
width: 110px;
height: 36px;
}
#en-markup-alert-container .cell-3 button.alt-button {
position: absolute;
top: 12px;
right: 140px;
width: 110px;
height: 36px;
}
</style><style type="text/css" media="screen" class="monaco-colors">.codicon-add:before { content: '\ea60'; }
.codicon-plus:before { content: '\ea60'; }
.codicon-gist-new:before { content: '\ea60'; }
.codicon-repo-create:before { content: '\ea60'; }
.codicon-lightbulb:before { content: '\ea61'; }
.codicon-light-bulb:before { content: '\ea61'; }
.codicon-repo:before { content: '\ea62'; }
.codicon-repo-delete:before { content: '\ea62'; }
.codicon-gist-fork:before { content: '\ea63'; }
.codicon-repo-forked:before { content: '\ea63'; }
.codicon-git-pull-request:before { content: '\ea64'; }
.codicon-git-pull-request-abandoned:before { content: '\ea64'; }
.codicon-record-keys:before { content: '\ea65'; }
.codicon-keyboard:before { content: '\ea65'; }
.codicon-tag:before { content: '\ea66'; }
.codicon-tag-add:before { content: '\ea66'; }
.codicon-tag-remove:before { content: '\ea66'; }
.codicon-person:before { content: '\ea67'; }
.codicon-person-follow:before { content: '\ea67'; }
.codicon-person-outline:before { content: '\ea67'; }
.codicon-person-filled:before { content: '\ea67'; }
.codicon-git-branch:before { content: '\ea68'; }
.codicon-git-branch-create:before { content: '\ea68'; }
.codicon-git-branch-delete:before { content: '\ea68'; }
.codicon-source-control:before { content: '\ea68'; }
.codicon-mirror:before { content: '\ea69'; }
.codicon-mirror-public:before { content: '\ea69'; }
.codicon-star:before { content: '\ea6a'; }
.codicon-star-add:before { content: '\ea6a'; }
.codicon-star-delete:before { content: '\ea6a'; }
.codicon-star-empty:before { content: '\ea6a'; }
.codicon-comment:before { content: '\ea6b'; }
.codicon-comment-add:before { content: '\ea6b'; }
.codicon-alert:before { content: '\ea6c'; }
.codicon-warning:before { content: '\ea6c'; }
.codicon-search:before { content: '\ea6d'; }
.codicon-search-save:before { content: '\ea6d'; }
.codicon-log-out:before { content: '\ea6e'; }
.codicon-sign-out:before { content: '\ea6e'; }
.codicon-log-in:before { content: '\ea6f'; }
.codicon-sign-in:before { content: '\ea6f'; }
.codicon-eye:before { content: '\ea70'; }
.codicon-eye-unwatch:before { content: '\ea70'; }
.codicon-eye-watch:before { content: '\ea70'; }
.codicon-circle-filled:before { content: '\ea71'; }
.codicon-primitive-dot:before { content: '\ea71'; }
.codicon-close-dirty:before { content: '\ea71'; }
.codicon-debug-breakpoint:before { content: '\ea71'; }
.codicon-debug-breakpoint-disabled:before { content: '\ea71'; }
.codicon-debug-hint:before { content: '\ea71'; }
.codicon-primitive-square:before { content: '\ea72'; }
.codicon-edit:before { content: '\ea73'; }
.codicon-pencil:before { content: '\ea73'; }
.codicon-info:before { content: '\ea74'; }
.codicon-issue-opened:before { content: '\ea74'; }
.codicon-gist-private:before { content: '\ea75'; }
.codicon-git-fork-private:before { content: '\ea75'; }
.codicon-lock:before { content: '\ea75'; }
.codicon-mirror-private:before { content: '\ea75'; }
.codicon-close:before { content: '\ea76'; }
.codicon-remove-close:before { content: '\ea76'; }
.codicon-x:before { content: '\ea76'; }
.codicon-repo-sync:before { content: '\ea77'; }
.codicon-sync:before { content: '\ea77'; }
.codicon-clone:before { content: '\ea78'; }
.codicon-desktop-download:before { content: '\ea78'; }
.codicon-beaker:before { content: '\ea79'; }
.codicon-microscope:before { content: '\ea79'; }
.codicon-vm:before { content: '\ea7a'; }
.codicon-device-desktop:before { content: '\ea7a'; }
.codicon-file:before { content: '\ea7b'; }
.codicon-file-text:before { content: '\ea7b'; }
.codicon-more:before { content: '\ea7c'; }
.codicon-ellipsis:before { content: '\ea7c'; }
.codicon-kebab-horizontal:before { content: '\ea7c'; }
.codicon-mail-reply:before { content: '\ea7d'; }
.codicon-reply:before { content: '\ea7d'; }
.codicon-organization:before { content: '\ea7e'; }
.codicon-organization-filled:before { content: '\ea7e'; }
.codicon-organization-outline:before { content: '\ea7e'; }
.codicon-new-file:before { content: '\ea7f'; }
.codicon-file-add:before { content: '\ea7f'; }
.codicon-new-folder:before { content: '\ea80'; }
.codicon-file-directory-create:before { content: '\ea80'; }
.codicon-trash:before { content: '\ea81'; }
.codicon-trashcan:before { content: '\ea81'; }
.codicon-history:before { content: '\ea82'; }
.codicon-clock:before { content: '\ea82'; }
.codicon-folder:before { content: '\ea83'; }
.codicon-file-directory:before { content: '\ea83'; }
.codicon-symbol-folder:before { content: '\ea83'; }
.codicon-logo-github:before { content: '\ea84'; }
.codicon-mark-github:before { content: '\ea84'; }
.codicon-github:before { content: '\ea84'; }
.codicon-terminal:before { content: '\ea85'; }
.codicon-console:before { content: '\ea85'; }
.codicon-repl:before { content: '\ea85'; }
.codicon-zap:before { content: '\ea86'; }
.codicon-symbol-event:before { content: '\ea86'; }
.codicon-error:before { content: '\ea87'; }
.codicon-stop:before { content: '\ea87'; }
.codicon-variable:before { content: '\ea88'; }
.codicon-symbol-variable:before { content: '\ea88'; }
.codicon-array:before { content: '\ea8a'; }
.codicon-symbol-array:before { content: '\ea8a'; }
.codicon-symbol-module:before { content: '\ea8b'; }
.codicon-symbol-package:before { content: '\ea8b'; }
.codicon-symbol-namespace:before { content: '\ea8b'; }
.codicon-symbol-object:before { content: '\ea8b'; }
.codicon-symbol-method:before { content: '\ea8c'; }
.codicon-symbol-function:before { content: '\ea8c'; }
.codicon-symbol-constructor:before { content: '\ea8c'; }
.codicon-symbol-boolean:before { content: '\ea8f'; }
.codicon-symbol-null:before { content: '\ea8f'; }
.codicon-symbol-numeric:before { content: '\ea90'; }
.codicon-symbol-number:before { content: '\ea90'; }
.codicon-symbol-structure:before { content: '\ea91'; }
.codicon-symbol-struct:before { content: '\ea91'; }
.codicon-symbol-parameter:before { content: '\ea92'; }
.codicon-symbol-type-parameter:before { content: '\ea92'; }
.codicon-symbol-key:before { content: '\ea93'; }
.codicon-symbol-text:before { content: '\ea93'; }
.codicon-symbol-reference:before { content: '\ea94'; }
.codicon-go-to-file:before { content: '\ea94'; }
.codicon-symbol-enum:before { content: '\ea95'; }
.codicon-symbol-value:before { content: '\ea95'; }
.codicon-symbol-ruler:before { content: '\ea96'; }
.codicon-symbol-unit:before { content: '\ea96'; }
.codicon-activate-breakpoints:before { content: '\ea97'; }
.codicon-archive:before { content: '\ea98'; }
.codicon-arrow-both:before { content: '\ea99'; }
.codicon-arrow-down:before { content: '\ea9a'; }
.codicon-arrow-left:before { content: '\ea9b'; }
.codicon-arrow-right:before { content: '\ea9c'; }
.codicon-arrow-small-down:before { content: '\ea9d'; }
.codicon-arrow-small-left:before { content: '\ea9e'; }
.codicon-arrow-small-right:before { content: '\ea9f'; }
.codicon-arrow-small-up:before { content: '\eaa0'; }
.codicon-arrow-up:before { content: '\eaa1'; }
.codicon-bell:before { content: '\eaa2'; }
.codicon-bold:before { content: '\eaa3'; }
.codicon-book:before { content: '\eaa4'; }
.codicon-bookmark:before { content: '\eaa5'; }
.codicon-debug-breakpoint-conditional-unverified:before { content: '\eaa6'; }
.codicon-debug-breakpoint-conditional:before { content: '\eaa7'; }
.codicon-debug-breakpoint-conditional-disabled:before { content: '\eaa7'; }
.codicon-debug-breakpoint-data-unverified:before { content: '\eaa8'; }
.codicon-debug-breakpoint-data:before { content: '\eaa9'; }
.codicon-debug-breakpoint-data-disabled:before { content: '\eaa9'; }
.codicon-debug-breakpoint-log-unverified:before { content: '\eaaa'; }
.codicon-debug-breakpoint-log:before { content: '\eaab'; }
.codicon-debug-breakpoint-log-disabled:before { content: '\eaab'; }
.codicon-briefcase:before { content: '\eaac'; }
.codicon-broadcast:before { content: '\eaad'; }
.codicon-browser:before { content: '\eaae'; }
.codicon-bug:before { content: '\eaaf'; }
.codicon-calendar:before { content: '\eab0'; }
.codicon-case-sensitive:before { content: '\eab1'; }
.codicon-check:before { content: '\eab2'; }
.codicon-checklist:before { content: '\eab3'; }
.codicon-chevron-down:before { content: '\eab4'; }
.codicon-drop-down-button:before { content: '\eab4'; }
.codicon-chevron-left:before { content: '\eab5'; }
.codicon-chevron-right:before { content: '\eab6'; }
.codicon-chevron-up:before { content: '\eab7'; }
.codicon-chrome-close:before { content: '\eab8'; }
.codicon-chrome-maximize:before { content: '\eab9'; }
.codicon-chrome-minimize:before { content: '\eaba'; }
.codicon-chrome-restore:before { content: '\eabb'; }
.codicon-circle-outline:before { content: '\eabc'; }
.codicon-debug-breakpoint-unverified:before { content: '\eabc'; }
.codicon-circle-slash:before { content: '\eabd'; }
.codicon-circuit-board:before { content: '\eabe'; }
.codicon-clear-all:before { content: '\eabf'; }
.codicon-clippy:before { content: '\eac0'; }
.codicon-close-all:before { content: '\eac1'; }
.codicon-cloud-download:before { content: '\eac2'; }
.codicon-cloud-upload:before { content: '\eac3'; }
.codicon-code:before { content: '\eac4'; }
.codicon-collapse-all:before { content: '\eac5'; }
.codicon-color-mode:before { content: '\eac6'; }
.codicon-comment-discussion:before { content: '\eac7'; }
.codicon-compare-changes:before { content: '\eafd'; }
.codicon-credit-card:before { content: '\eac9'; }
.codicon-dash:before { content: '\eacc'; }
.codicon-dashboard:before { content: '\eacd'; }
.codicon-database:before { content: '\eace'; }
.codicon-debug-continue:before { content: '\eacf'; }
.codicon-debug-disconnect:before { content: '\ead0'; }
.codicon-debug-pause:before { content: '\ead1'; }
.codicon-debug-restart:before { content: '\ead2'; }
.codicon-debug-start:before { content: '\ead3'; }
.codicon-debug-step-into:before { content: '\ead4'; }
.codicon-debug-step-out:before { content: '\ead5'; }
.codicon-debug-step-over:before { content: '\ead6'; }
.codicon-debug-stop:before { content: '\ead7'; }
.codicon-debug:before { content: '\ead8'; }
.codicon-device-camera-video:before { content: '\ead9'; }
.codicon-device-camera:before { content: '\eada'; }
.codicon-device-mobile:before { content: '\eadb'; }
.codicon-diff-added:before { content: '\eadc'; }
.codicon-diff-ignored:before { content: '\eadd'; }
.codicon-diff-modified:before { content: '\eade'; }
.codicon-diff-removed:before { content: '\eadf'; }
.codicon-diff-renamed:before { content: '\eae0'; }
.codicon-diff:before { content: '\eae1'; }
.codicon-discard:before { content: '\eae2'; }
.codicon-editor-layout:before { content: '\eae3'; }
.codicon-empty-window:before { content: '\eae4'; }
.codicon-exclude:before { content: '\eae5'; }
.codicon-extensions:before { content: '\eae6'; }
.codicon-eye-closed:before { content: '\eae7'; }
.codicon-file-binary:before { content: '\eae8'; }
.codicon-file-code:before { content: '\eae9'; }
.codicon-file-media:before { content: '\eaea'; }
.codicon-file-pdf:before { content: '\eaeb'; }
.codicon-file-submodule:before { content: '\eaec'; }
.codicon-file-symlink-directory:before { content: '\eaed'; }
.codicon-file-symlink-file:before { content: '\eaee'; }
.codicon-file-zip:before { content: '\eaef'; }
.codicon-files:before { content: '\eaf0'; }
.codicon-filter:before { content: '\eaf1'; }
.codicon-flame:before { content: '\eaf2'; }
.codicon-fold-down:before { content: '\eaf3'; }
.codicon-fold-up:before { content: '\eaf4'; }
.codicon-fold:before { content: '\eaf5'; }
.codicon-folder-active:before { content: '\eaf6'; }
.codicon-folder-opened:before { content: '\eaf7'; }
.codicon-gear:before { content: '\eaf8'; }
.codicon-gift:before { content: '\eaf9'; }
.codicon-gist-secret:before { content: '\eafa'; }
.codicon-gist:before { content: '\eafb'; }
.codicon-git-commit:before { content: '\eafc'; }
.codicon-git-compare:before { content: '\eafd'; }
.codicon-git-merge:before { content: '\eafe'; }
.codicon-github-action:before { content: '\eaff'; }
.codicon-github-alt:before { content: '\eb00'; }
.codicon-globe:before { content: '\eb01'; }
.codicon-grabber:before { content: '\eb02'; }
.codicon-graph:before { content: '\eb03'; }
.codicon-gripper:before { content: '\eb04'; }
.codicon-heart:before { content: '\eb05'; }
.codicon-home:before { content: '\eb06'; }
.codicon-horizontal-rule:before { content: '\eb07'; }
.codicon-hubot:before { content: '\eb08'; }
.codicon-inbox:before { content: '\eb09'; }
.codicon-issue-closed:before { content: '\eba4'; }
.codicon-issue-reopened:before { content: '\eb0b'; }
.codicon-issues:before { content: '\eb0c'; }
.codicon-italic:before { content: '\eb0d'; }
.codicon-jersey:before { content: '\eb0e'; }
.codicon-json:before { content: '\eb0f'; }
.codicon-kebab-vertical:before { content: '\eb10'; }
.codicon-key:before { content: '\eb11'; }
.codicon-law:before { content: '\eb12'; }
.codicon-lightbulb-autofix:before { content: '\eb13'; }
.codicon-link-external:before { content: '\eb14'; }
.codicon-link:before { content: '\eb15'; }
.codicon-list-ordered:before { content: '\eb16'; }
.codicon-list-unordered:before { content: '\eb17'; }
.codicon-live-share:before { content: '\eb18'; }
.codicon-loading:before { content: '\eb19'; }
.codicon-location:before { content: '\eb1a'; }
.codicon-mail-read:before { content: '\eb1b'; }
.codicon-mail:before { content: '\eb1c'; }
.codicon-markdown:before { content: '\eb1d'; }
.codicon-megaphone:before { content: '\eb1e'; }
.codicon-mention:before { content: '\eb1f'; }
.codicon-milestone:before { content: '\eb20'; }
.codicon-mortar-board:before { content: '\eb21'; }
.codicon-move:before { content: '\eb22'; }
.codicon-multiple-windows:before { content: '\eb23'; }
.codicon-mute:before { content: '\eb24'; }
.codicon-no-newline:before { content: '\eb25'; }
.codicon-note:before { content: '\eb26'; }
.codicon-octoface:before { content: '\eb27'; }
.codicon-open-preview:before { content: '\eb28'; }
.codicon-package:before { content: '\eb29'; }
.codicon-paintcan:before { content: '\eb2a'; }
.codicon-pin:before { content: '\eb2b'; }
.codicon-play:before { content: '\eb2c'; }
.codicon-run:before { content: '\eb2c'; }
.codicon-plug:before { content: '\eb2d'; }
.codicon-preserve-case:before { content: '\eb2e'; }
.codicon-preview:before { content: '\eb2f'; }
.codicon-project:before { content: '\eb30'; }
.codicon-pulse:before { content: '\eb31'; }
.codicon-question:before { content: '\eb32'; }
.codicon-quote:before { content: '\eb33'; }
.codicon-radio-tower:before { content: '\eb34'; }
.codicon-reactions:before { content: '\eb35'; }
.codicon-references:before { content: '\eb36'; }
.codicon-refresh:before { content: '\eb37'; }
.codicon-regex:before { content: '\eb38'; }
.codicon-remote-explorer:before { content: '\eb39'; }
.codicon-remote:before { content: '\eb3a'; }
.codicon-remove:before { content: '\eb3b'; }
.codicon-replace-all:before { content: '\eb3c'; }
.codicon-replace:before { content: '\eb3d'; }
.codicon-repo-clone:before { content: '\eb3e'; }
.codicon-repo-force-push:before { content: '\eb3f'; }
.codicon-repo-pull:before { content: '\eb40'; }
.codicon-repo-push:before { content: '\eb41'; }
.codicon-report:before { content: '\eb42'; }
.codicon-request-changes:before { content: '\eb43'; }
.codicon-rocket:before { content: '\eb44'; }
.codicon-root-folder-opened:before { content: '\eb45'; }
.codicon-root-folder:before { content: '\eb46'; }
.codicon-rss:before { content: '\eb47'; }
.codicon-ruby:before { content: '\eb48'; }
.codicon-save-all:before { content: '\eb49'; }
.codicon-save-as:before { content: '\eb4a'; }
.codicon-save:before { content: '\eb4b'; }
.codicon-screen-full:before { content: '\eb4c'; }
.codicon-screen-normal:before { content: '\eb4d'; }
.codicon-search-stop:before { content: '\eb4e'; }
.codicon-server:before { content: '\eb50'; }
.codicon-settings-gear:before { content: '\eb51'; }
.codicon-settings:before { content: '\eb52'; }
.codicon-shield:before { content: '\eb53'; }
.codicon-smiley:before { content: '\eb54'; }
.codicon-sort-precedence:before { content: '\eb55'; }
.codicon-split-horizontal:before { content: '\eb56'; }
.codicon-split-vertical:before { content: '\eb57'; }
.codicon-squirrel:before { content: '\eb58'; }
.codicon-star-full:before { content: '\eb59'; }
.codicon-star-half:before { content: '\eb5a'; }
.codicon-symbol-class:before { content: '\eb5b'; }
.codicon-symbol-color:before { content: '\eb5c'; }
.codicon-symbol-customcolor:before { content: '\eb5c'; }
.codicon-symbol-constant:before { content: '\eb5d'; }
.codicon-symbol-enum-member:before { content: '\eb5e'; }
.codicon-symbol-field:before { content: '\eb5f'; }
.codicon-symbol-file:before { content: '\eb60'; }
.codicon-symbol-interface:before { content: '\eb61'; }
.codicon-symbol-keyword:before { content: '\eb62'; }
.codicon-symbol-misc:before { content: '\eb63'; }
.codicon-symbol-operator:before { content: '\eb64'; }
.codicon-symbol-property:before { content: '\eb65'; }
.codicon-wrench:before { content: '\eb65'; }
.codicon-wrench-subaction:before { content: '\eb65'; }
.codicon-symbol-snippet:before { content: '\eb66'; }
.codicon-tasklist:before { content: '\eb67'; }
.codicon-telescope:before { content: '\eb68'; }
.codicon-text-size:before { content: '\eb69'; }
.codicon-three-bars:before { content: '\eb6a'; }
.codicon-thumbsdown:before { content: '\eb6b'; }
.codicon-thumbsup:before { content: '\eb6c'; }
.codicon-tools:before { content: '\eb6d'; }
.codicon-triangle-down:before { content: '\eb6e'; }
.codicon-triangle-left:before { content: '\eb6f'; }
.codicon-triangle-right:before { content: '\eb70'; }
.codicon-triangle-up:before { content: '\eb71'; }
.codicon-twitter:before { content: '\eb72'; }
.codicon-unfold:before { content: '\eb73'; }
.codicon-unlock:before { content: '\eb74'; }
.codicon-unmute:before { content: '\eb75'; }
.codicon-unverified:before { content: '\eb76'; }
.codicon-verified:before { content: '\eb77'; }
.codicon-versions:before { content: '\eb78'; }
.codicon-vm-active:before { content: '\eb79'; }
.codicon-vm-outline:before { content: '\eb7a'; }
.codicon-vm-running:before { content: '\eb7b'; }
.codicon-watch:before { content: '\eb7c'; }
.codicon-whitespace:before { content: '\eb7d'; }
.codicon-whole-word:before { content: '\eb7e'; }
.codicon-window:before { content: '\eb7f'; }
.codicon-word-wrap:before { content: '\eb80'; }
.codicon-zoom-in:before { content: '\eb81'; }
.codicon-zoom-out:before { content: '\eb82'; }
.codicon-list-filter:before { content: '\eb83'; }
.codicon-list-flat:before { content: '\eb84'; }
.codicon-list-selection:before { content: '\eb85'; }
.codicon-selection:before { content: '\eb85'; }
.codicon-list-tree:before { content: '\eb86'; }
.codicon-debug-breakpoint-function-unverified:before { content: '\eb87'; }
.codicon-debug-breakpoint-function:before { content: '\eb88'; }
.codicon-debug-breakpoint-function-disabled:before { content: '\eb88'; }
.codicon-debug-stackframe-active:before { content: '\eb89'; }
.codicon-debug-stackframe-dot:before { content: '\eb8a'; }
.codicon-debug-stackframe:before { content: '\eb8b'; }
.codicon-debug-stackframe-focused:before { content: '\eb8b'; }
.codicon-debug-breakpoint-unsupported:before { content: '\eb8c'; }
.codicon-symbol-string:before { content: '\eb8d'; }
.codicon-debug-reverse-continue:before { content: '\eb8e'; }
.codicon-debug-step-back:before { content: '\eb8f'; }
.codicon-debug-restart-frame:before { content: '\eb90'; }
.codicon-call-incoming:before { content: '\eb92'; }
.codicon-call-outgoing:before { content: '\eb93'; }
.codicon-menu:before { content: '\eb94'; }
.codicon-expand-all:before { content: '\eb95'; }
.codicon-feedback:before { content: '\eb96'; }
.codicon-group-by-ref-type:before { content: '\eb97'; }
.codicon-ungroup-by-ref-type:before { content: '\eb98'; }
.codicon-account:before { content: '\eb99'; }
.codicon-bell-dot:before { content: '\eb9a'; }
.codicon-debug-console:before { content: '\eb9b'; }
.codicon-library:before { content: '\eb9c'; }
.codicon-output:before { content: '\eb9d'; }
.codicon-run-all:before { content: '\eb9e'; }
.codicon-sync-ignored:before { content: '\eb9f'; }
.codicon-pinned:before { content: '\eba0'; }
.codicon-github-inverted:before { content: '\eba1'; }
.codicon-debug-alt:before { content: '\eb91'; }
.codicon-server-process:before { content: '\eba2'; }
.codicon-server-environment:before { content: '\eba3'; }
.codicon-pass:before { content: '\eba4'; }
.codicon-stop-circle:before { content: '\eba5'; }
.codicon-play-circle:before { content: '\eba6'; }
.codicon-record:before { content: '\eba7'; }
.codicon-debug-alt-small:before { content: '\eba8'; }
.codicon-vm-connect:before { content: '\eba9'; }
.codicon-cloud:before { content: '\ebaa'; }
.codicon-merge:before { content: '\ebab'; }
.codicon-export:before { content: '\ebac'; }
.codicon-graph-left:before { content: '\ebad'; }
.codicon-magnet:before { content: '\ebae'; }
.codicon-notebook:before { content: '\ebaf'; }
.codicon-redo:before { content: '\ebb0'; }
.codicon-check-all:before { content: '\ebb1'; }
.codicon-pinned-dirty:before { content: '\ebb2'; }
.codicon-pass-filled:before { content: '\ebb3'; }
.codicon-circle-large-filled:before { content: '\ebb4'; }
.codicon-circle-large-outline:before { content: '\ebb5'; }
.codicon-combine:before { content: '\ebb6'; }
.codicon-gather:before { content: '\ebb6'; }
.codicon-table:before { content: '\ebb7'; }
.codicon-variable-group:before { content: '\ebb8'; }
.codicon-type-hierarchy:before { content: '\ebb9'; }
.codicon-type-hierarchy-sub:before { content: '\ebba'; }
.codicon-type-hierarchy-super:before { content: '\ebbb'; }
.codicon-git-pull-request-create:before { content: '\ebbc'; }
.codicon-run-above:before { content: '\ebbd'; }
.codicon-run-below:before { content: '\ebbe'; }
.codicon-notebook-template:before { content: '\ebbf'; }
.codicon-debug-rerun:before { content: '\ebc0'; }
.codicon-workspace-trusted:before { content: '\ebc1'; }
.codicon-workspace-untrusted:before { content: '\ebc2'; }
.codicon-workspace-unspecified:before { content: '\ebc3'; }
.codicon-terminal-cmd:before { content: '\ebc4'; }
.codicon-terminal-debian:before { content: '\ebc5'; }
.codicon-terminal-linux:before { content: '\ebc6'; }
.codicon-terminal-powershell:before { content: '\ebc7'; }
.codicon-terminal-tmux:before { content: '\ebc8'; }
.codicon-terminal-ubuntu:before { content: '\ebc9'; }
.codicon-terminal-bash:before { content: '\ebca'; }
.codicon-arrow-swap:before { content: '\ebcb'; }
.codicon-copy:before { content: '\ebcc'; }
.codicon-person-add:before { content: '\ebcd'; }
.codicon-filter-filled:before { content: '\ebce'; }
.codicon-wand:before { content: '\ebcf'; }
.codicon-debug-line-by-line:before { content: '\ebd0'; }
.codicon-inspect:before { content: '\ebd1'; }
.codicon-layers:before { content: '\ebd2'; }
.codicon-layers-dot:before { content: '\ebd3'; }
.codicon-layers-active:before { content: '\ebd4'; }
.codicon-compass:before { content: '\ebd5'; }
.codicon-compass-dot:before { content: '\ebd6'; }
.codicon-compass-active:before { content: '\ebd7'; }
.codicon-azure:before { content: '\ebd8'; }
.codicon-issue-draft:before { content: '\ebd9'; }
.codicon-git-pull-request-closed:before { content: '\ebda'; }
.codicon-git-pull-request-draft:before { content: '\ebdb'; }
.codicon-debug-all:before { content: '\ebdc'; }
.codicon-debug-coverage:before { content: '\ebdd'; }
.codicon-run-errors:before { content: '\ebde'; }
.codicon-folder-library:before { content: '\ebdf'; }
.codicon-debug-continue-small:before { content: '\ebe0'; }
.codicon-beaker-stop:before { content: '\ebe1'; }
.codicon-graph-line:before { content: '\ebe2'; }
.codicon-graph-scatter:before { content: '\ebe3'; }
.codicon-pie-chart:before { content: '\ebe4'; }
.codicon-bracket:before { content: '\eb0f'; }
.codicon-bracket-dot:before { content: '\ebe5'; }
.codicon-bracket-error:before { content: '\ebe6'; }
.codicon-lock-small:before { content: '\ebe7'; }
.codicon-azure-devops:before { content: '\ebe8'; }
.codicon-verified-filled:before { content: '\ebe9'; }
.codicon-newline:before { content: '\ebea'; }
.codicon-layout:before { content: '\ebeb'; }
.codicon-layout-activitybar-left:before { content: '\ebec'; }
.codicon-layout-activitybar-right:before { content: '\ebed'; }
.codicon-layout-panel-left:before { content: '\ebee'; }
.codicon-layout-panel-center:before { content: '\ebef'; }
.codicon-layout-panel-justify:before { content: '\ebf0'; }
.codicon-layout-panel-right:before { content: '\ebf1'; }
.codicon-layout-panel:before { content: '\ebf2'; }
.codicon-layout-sidebar-left:before { content: '\ebf3'; }
.codicon-layout-sidebar-right:before { content: '\ebf4'; }
.codicon-layout-statusbar:before { content: '\ebf5'; }
.codicon-layout-menubar:before { content: '\ebf6'; }
.codicon-layout-centered:before { content: '\ebf7'; }
.codicon-target:before { content: '\ebf8'; }
.codicon-indent:before { content: '\ebf9'; }
.codicon-record-small:before { content: '\ebfa'; }
.codicon-error-small:before { content: '\ebfb'; }
.codicon-arrow-circle-down:before { content: '\ebfc'; }
.codicon-arrow-circle-left:before { content: '\ebfd'; }
.codicon-arrow-circle-right:before { content: '\ebfe'; }
.codicon-arrow-circle-up:before { content: '\ebff'; }
.codicon-dialog-error:before { content: '\ea87'; }
.codicon-dialog-warning:before { content: '\ea6c'; }
.codicon-dialog-info:before { content: '\ea74'; }
.codicon-dialog-close:before { content: '\ea76'; }
.codicon-tree-item-expanded:before { content: '\eab4'; }
.codicon-tree-filter-on-type-on:before { content: '\eb83'; }
.codicon-tree-filter-on-type-off:before { content: '\eb85'; }
.codicon-tree-filter-clear:before { content: '\ea76'; }
.codicon-tree-item-loading:before { content: '\eb19'; }
.codicon-menu-selection:before { content: '\eab2'; }
.codicon-menu-submenu:before { content: '\eab6'; }
.codicon-menubar-more:before { content: '\ea7c'; }
.codicon-scrollbar-button-left:before { content: '\eb6f'; }
.codicon-scrollbar-button-right:before { content: '\eb70'; }
.codicon-scrollbar-button-up:before { content: '\eb71'; }
.codicon-scrollbar-button-down:before { content: '\eb6e'; }
.codicon-toolbar-more:before { content: '\ea7c'; }
.codicon-quick-input-back:before { content: '\ea9b'; }
.codicon-widget-close:before { content: '\ea76'; }
.codicon-goto-previous-location:before { content: '\eaa1'; }
.codicon-goto-next-location:before { content: '\ea9a'; }
.codicon-marker-navigation-next:before { content: '\ea9a'; }
.codicon-marker-navigation-previous:before { content: '\eaa1'; }
.codicon-find-selection:before { content: '\eb85'; }
.codicon-find-collapsed:before { content: '\eab6'; }
.codicon-find-expanded:before { content: '\eab4'; }
.codicon-find-replace:before { content: '\eb3d'; }
.codicon-find-replace-all:before { content: '\eb3c'; }
.codicon-find-previous-match:before { content: '\eaa1'; }
.codicon-find-next-match:before { content: '\ea9a'; }
.codicon-folding-expanded:before { content: '\eab4'; }
.codicon-folding-collapsed:before { content: '\eab6'; }
.codicon-suggest-more-info:before { content: '\eab6'; }
.codicon-parameter-hints-next:before { content: '\eab4'; }
.codicon-parameter-hints-previous:before { content: '\eab7'; }
.codicon-extensions-warning-message:before { content: '\ea6c'; }
.codicon-diff-review-insert:before { content: '\ea60'; }
.codicon-diff-review-remove:before { content: '\eb3b'; }
.codicon-diff-review-close:before { content: '\ea76'; }
.codicon-diff-insert:before { content: '\ea60'; }
.codicon-diff-remove:before { content: '\eb3b'; }
.monaco-editor .accessibilityHelpWidget { background-color: #f3f3f3; }
.monaco-editor .accessibilityHelpWidget { color: #616161; }
.monaco-editor .accessibilityHelpWidget { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.16); }
.monaco-editor, .monaco-editor-background, .monaco-editor .inputarea.ime-input { background-color: #fffffe; }
.monaco-editor, .monaco-editor .inputarea.ime-input { color: #000000; }
.monaco-editor .margin { background-color: #fffffe; }
.monaco-editor .rangeHighlight { background-color: rgba(253, 255, 0, 0.2); }
.monaco-editor .symbolHighlight { background-color: rgba(234, 92, 0, 0.33); }
.monaco-editor .mtkw { color: rgba(51, 51, 51, 0.2) !important; }
.monaco-editor .mtkz { color: rgba(51, 51, 51, 0.2) !important; }
.monaco-editor .unexpected-closing-bracket { color: rgba(255, 18, 18, 0.8); }
.monaco-editor .bracket-highlighting-0 { color: #0431fa; }
.monaco-editor .bracket-highlighting-1 { color: #319331; }
.monaco-editor .bracket-highlighting-2 { color: #7b3814; }
.monaco-editor .bracket-highlighting-3 { color: #0431fa; }
.monaco-editor .bracket-highlighting-4 { color: #319331; }
.monaco-editor .bracket-highlighting-5 { color: #7b3814; }
.monaco-editor .bracket-highlighting-6 { color: #0431fa; }
.monaco-editor .bracket-highlighting-7 { color: #319331; }
.monaco-editor .bracket-highlighting-8 { color: #7b3814; }
.monaco-editor .bracket-highlighting-9 { color: #0431fa; }
.monaco-editor .bracket-highlighting-10 { color: #319331; }
.monaco-editor .bracket-highlighting-11 { color: #7b3814; }
.monaco-editor .bracket-highlighting-12 { color: #0431fa; }
.monaco-editor .bracket-highlighting-13 { color: #319331; }
.monaco-editor .bracket-highlighting-14 { color: #7b3814; }
.monaco-editor .bracket-highlighting-15 { color: #0431fa; }
.monaco-editor .bracket-highlighting-16 { color: #319331; }
.monaco-editor .bracket-highlighting-17 { color: #7b3814; }
.monaco-editor .bracket-highlighting-18 { color: #0431fa; }
.monaco-editor .bracket-highlighting-19 { color: #319331; }
.monaco-editor .bracket-highlighting-20 { color: #7b3814; }
.monaco-editor .bracket-highlighting-21 { color: #0431fa; }
.monaco-editor .bracket-highlighting-22 { color: #319331; }
.monaco-editor .bracket-highlighting-23 { color: #7b3814; }
.monaco-editor .bracket-highlighting-24 { color: #0431fa; }
.monaco-editor .bracket-highlighting-25 { color: #319331; }
.monaco-editor .bracket-highlighting-26 { color: #7b3814; }
.monaco-editor .bracket-highlighting-27 { color: #0431fa; }
.monaco-editor .bracket-highlighting-28 { color: #319331; }
.monaco-editor .bracket-highlighting-29 { color: #7b3814; }
.monaco-editor .bracket-match { background-color: rgba(0, 100, 0, 0.1); }
.monaco-editor .bracket-match { border: 1px solid #b9b9b9; }
.monaco-editor .contentWidgets .codicon.codicon-light-bulb {
color: #ddb100;
background-color: rgba(255, 255, 254, 0.7);
}
.monaco-editor .contentWidgets .codicon.codicon-lightbulb-autofix {
color: #007acc;
background-color: rgba(255, 255, 254, 0.7);
}
.monaco-editor .line-numbers { color: #237893; }
.monaco-editor .line-numbers.active-line-number { color: #0b216f; }
.monaco-editor .view-overlays .current-line { border: 2px solid #eeeeee; }
.monaco-editor .margin-view-overlays .current-line-margin { border: 2px solid #eeeeee; }
.monaco-scrollable-element > .shadow.top {
box-shadow: #dddddd 0 6px 6px -6px inset;
}
.monaco-scrollable-element > .shadow.left {
box-shadow: #dddddd 6px 0 6px -6px inset;
}
.monaco-scrollable-element > .shadow.top.left {
box-shadow: #dddddd 6px 6px 6px -6px inset;
}
.monaco-scrollable-element > .scrollbar > .slider {
background: rgba(100, 100, 100, 0.4);
}
.monaco-scrollable-element > .scrollbar > .slider:hover {
background: rgba(100, 100, 100, 0.7);
}
.monaco-scrollable-element > .scrollbar > .slider.active {
background: rgba(0, 0, 0, 0.6);
}
.monaco-editor .lines-content .core-guide-indent { box-shadow: 1px 0 0 0 #d3d3d3 inset; }
.monaco-editor .lines-content .core-guide-indent-active { box-shadow: 1px 0 0 0 #939393 inset; }
.monaco-editor .bracket-indent-guide.lvl-0 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-1 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-2 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-3 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-4 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-5 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-6 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-7 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-8 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-9 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-10 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-11 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-12 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-13 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-14 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-15 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-16 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-17 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-18 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-19 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-20 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-21 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-22 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-23 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-24 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-25 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-26 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .bracket-indent-guide.lvl-27 { --guide-color: rgba(4, 49, 250, 0.3); --guide-color-active: #0431fa; }
.monaco-editor .bracket-indent-guide.lvl-28 { --guide-color: rgba(49, 147, 49, 0.3); --guide-color-active: #319331; }
.monaco-editor .bracket-indent-guide.lvl-29 { --guide-color: rgba(123, 56, 20, 0.3); --guide-color-active: #7b3814; }
.monaco-editor .vertical { box-shadow: 1px 0 0 0 var(--guide-color) inset; }
.monaco-editor .horizontal-top { border-top: 1px solid var(--guide-color); }
.monaco-editor .horizontal-bottom { border-bottom: 1px solid var(--guide-color); }
.monaco-editor .vertical.indent-active { box-shadow: 1px 0 0 0 var(--guide-color-active) inset; }
.monaco-editor .horizontal-top.indent-active { border-top: 1px solid var(--guide-color-active); }
.monaco-editor .horizontal-bottom.indent-active { border-bottom: 1px solid var(--guide-color-active); }
.monaco-editor .minimap-slider .minimap-slider-horizontal { background: rgba(100, 100, 100, 0.2); }
.monaco-editor .minimap-slider:hover .minimap-slider-horizontal { background: rgba(100, 100, 100, 0.35); }
.monaco-editor .minimap-slider.active .minimap-slider-horizontal { background: rgba(0, 0, 0, 0.3); }
.monaco-editor .minimap-shadow-visible { box-shadow: #dddddd -6px 0 6px -6px inset; }
.monaco-editor .view-ruler { box-shadow: 1px 0 0 0 #d3d3d3 inset; }
.monaco-editor .scroll-decoration { box-shadow: #dddddd 0 6px 6px -6px inset; }
.monaco-editor .focused .selected-text { background-color: #add6ff; }
.monaco-editor .selected-text { background-color: #e5ebf1; }
.monaco-editor .inputarea.ime-input { caret-color: #000000; }
.monaco-editor .cursors-layer .cursor { background-color: #000000; border-color: #000000; color: #ffffff; }
.monaco-editor .squiggly-error { background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23e51400'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left; }
.monaco-editor .squiggly-warning { background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23bf8803'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left; }
.monaco-editor .squiggly-info { background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%231a85ff'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left; }
.monaco-editor .squiggly-hint { background: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%223%22%20width%3D%2212%22%3E%3Cg%20fill%3D%22%236c6c6c%22%3E%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%221%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%229%22%20cy%3D%221%22%20r%3D%221%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") no-repeat bottom left; }
.monaco-editor.showUnused .squiggly-inline-unnecessary { opacity: 0.467; }
.monaco-editor.showDeprecated .squiggly-inline-deprecated { text-decoration: line-through; text-decoration-color: #000000}
.monaco-editor .goto-definition-link { color: #0000ff !important; }
.monaco-editor .zone-widget .codicon.codicon-error,
.markers-panel .marker-icon.codicon.codicon-error,
.text-search-provider-messages .providerMessage .codicon.codicon-error,
.extensions-viewlet > .extensions .codicon.codicon-error {
color: #e51400;
}
.monaco-editor .zone-widget .codicon.codicon-warning,
.markers-panel .marker-icon.codicon.codicon-warning,
.extensions-viewlet > .extensions .codicon.codicon-warning,
.extension-editor .codicon.codicon-warning,
.text-search-provider-messages .providerMessage .codicon.codicon-warning,
.preferences-editor .codicon.codicon-warning {
color: #bf8803;
}
.monaco-editor .zone-widget .codicon.codicon-info,
.markers-panel .marker-icon.codicon.codicon-info,
.extensions-viewlet > .extensions .codicon.codicon-info,
.text-search-provider-messages .providerMessage .codicon.codicon-info,
.extension-editor .codicon.codicon-info {
color: #1a85ff;
}
.monaco-hover .hover-contents a.code-link span { color: #006ab1; }
.monaco-hover .hover-contents a.code-link span:hover { color: #006ab1; }
.monaco-editor .hoverHighlight { background-color: rgba(173, 214, 255, 0.15); }
.monaco-editor .monaco-hover { background-color: #f3f3f3; }
.monaco-editor .monaco-hover { border: 1px solid #c8c8c8; }
.monaco-editor .monaco-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid rgba(200, 200, 200, 0.5); }
.monaco-editor .monaco-hover hr { border-top: 1px solid rgba(200, 200, 200, 0.5); }
.monaco-editor .monaco-hover hr { border-bottom: 0px solid rgba(200, 200, 200, 0.5); }
.monaco-editor .monaco-hover a { color: #006ab1; }
.monaco-editor .monaco-hover a:hover { color: #006ab1; }
.monaco-editor .monaco-hover { color: #616161; }
.monaco-editor .monaco-hover .hover-row .actions { background-color: #e7e7e7; }
.monaco-editor .monaco-hover code { background-color: rgba(220, 220, 220, 0.4); }
.monaco-editor .findOptionsWidget { background-color: #f3f3f3; }
.monaco-editor .findOptionsWidget { color: #616161; }
.monaco-editor .findOptionsWidget { box-shadow: 0 0 8px 2px rgba(0, 0, 0, 0.16); }
.monaco-editor .findMatch { background-color: rgba(234, 92, 0, 0.33); }
.monaco-editor .currentFindMatch { background-color: #a8ac94; }
.monaco-editor .findScope { background-color: rgba(180, 180, 180, 0.3); }
.monaco-editor .find-widget { background-color: #f3f3f3; }
.monaco-editor .find-widget { box-shadow: 0 0 8px 2px rgba(0, 0, 0, 0.16); }
.monaco-editor .find-widget { color: #616161; }
.monaco-editor .find-widget.no-results .matchesCount { color: #a1260d; }
.monaco-editor .find-widget .monaco-sash { background-color: #c8c8c8; }
.monaco-editor .find-widget .button:not(.disabled):hover,
.monaco-editor .find-widget .codicon-find-selection:hover {
background-color: rgba(184, 184, 184, 0.31) !important;
}
.monaco-editor .find-widget .monaco-inputbox.synthetic-focus { outline-color: #0090f1; }
.monaco-editor .folded-background { background-color: rgba(173, 214, 255, 0.3); }
.monaco-editor .cldr.codicon.codicon-folding-expanded,
.monaco-editor .cldr.codicon.codicon-folding-collapsed {
color: #424242 !important;
}
.monaco-editor.vs .valueSetReplacement { outline: solid 2px #b9b9b9; }
.codicon.codicon-symbol-array { color: #616161; }
.codicon.codicon-symbol-boolean { color: #616161; }
.codicon.codicon-symbol-class { color: #d67e00; }
.codicon.codicon-symbol-method { color: #652d90; }
.codicon.codicon-symbol-color { color: #616161; }
.codicon.codicon-symbol-constant { color: #616161; }
.codicon.codicon-symbol-constructor { color: #652d90; }
.codicon.codicon-symbol-value,.codicon.codicon-symbol-enum { color: #d67e00; }
.codicon.codicon-symbol-enum-member { color: #007acc; }
.codicon.codicon-symbol-event { color: #d67e00; }
.codicon.codicon-symbol-field { color: #007acc; }
.codicon.codicon-symbol-file { color: #616161; }
.codicon.codicon-symbol-folder { color: #616161; }
.codicon.codicon-symbol-function { color: #652d90; }
.codicon.codicon-symbol-interface { color: #007acc; }
.codicon.codicon-symbol-key { color: #616161; }
.codicon.codicon-symbol-keyword { color: #616161; }
.codicon.codicon-symbol-module { color: #616161; }
.codicon.codicon-symbol-namespace { color: #616161; }
.codicon.codicon-symbol-null { color: #616161; }
.codicon.codicon-symbol-number { color: #616161; }
.codicon.codicon-symbol-object { color: #616161; }
.codicon.codicon-symbol-operator { color: #616161; }
.codicon.codicon-symbol-package { color: #616161; }
.codicon.codicon-symbol-property { color: #616161; }
.codicon.codicon-symbol-reference { color: #616161; }
.codicon.codicon-symbol-snippet { color: #616161; }
.codicon.codicon-symbol-string { color: #616161; }
.codicon.codicon-symbol-struct { color: #616161; }
.codicon.codicon-symbol-text { color: #616161; }
.codicon.codicon-symbol-type-parameter { color: #616161; }
.codicon.codicon-symbol-unit { color: #616161; }
.codicon.codicon-symbol-variable { color: #007acc; }
.monaco-editor .ghost-text-decoration { color: rgba(0, 0, 0, 0.47) !important; }
.monaco-editor .ghost-text-decoration-preview { color: rgba(0, 0, 0, 0.47) !important; }
.monaco-editor .suggest-preview-text .ghost-text { color: rgba(0, 0, 0, 0.47) !important; }
.monaco-editor .tokens-inspect-widget { border: 1px solid #c8c8c8; }
.monaco-editor .tokens-inspect-widget .tokens-inspect-separator { background-color: #c8c8c8; }
.monaco-editor .tokens-inspect-widget { background-color: #f3f3f3; }
.monaco-editor .tokens-inspect-widget { color: #616161; }
.monaco-editor .linked-editing-decoration { background: rgba(255, 0, 0, 0.3); border-left-color: rgba(255, 0, 0, 0.3); }
.monaco-editor .detected-link-active { color: #0000ff !important; }
.monaco-editor .parameter-hints-widget { border: 1px solid #c8c8c8; }
.monaco-editor .parameter-hints-widget.multiple .body { border-left: 1px solid rgba(200, 200, 200, 0.5); }
.monaco-editor .parameter-hints-widget .signature.has-docs { border-bottom: 1px solid rgba(200, 200, 200, 0.5); }
.monaco-editor .parameter-hints-widget { background-color: #f3f3f3; }
.monaco-editor .parameter-hints-widget a { color: #006ab1; }
.monaco-editor .parameter-hints-widget a:hover { color: #006ab1; }
.monaco-editor .parameter-hints-widget { color: #616161; }
.monaco-editor .parameter-hints-widget code { background-color: rgba(220, 220, 220, 0.4); }
.monaco-editor .parameter-hints-widget .parameter.active { color: #0066bf}
.monaco-link { color: #006ab1; }
.monaco-link:hover { color: #006ab1; }
.monaco-editor .focused .selectionHighlight { background-color: rgba(173, 214, 255, 0.3); }
.monaco-editor .selectionHighlight { background-color: rgba(173, 214, 255, 0.15); }
.monaco-editor .wordHighlight { background-color: rgba(87, 87, 87, 0.25); }
.monaco-editor .wordHighlightStrong { background-color: rgba(14, 99, 156, 0.25); }
.monaco-diff-editor .diff-review-line-number { color: #237893; }
.monaco-diff-editor .diff-review-shadow { box-shadow: #dddddd 0 -6px 6px -6px inset; }
.monaco-editor .char-insert, .monaco-diff-editor .char-insert { background-color: rgba(155, 185, 85, 0.2); }
.monaco-editor .line-insert, .monaco-diff-editor .line-insert { background-color: rgba(155, 185, 85, 0.2); }
.monaco-editor .inline-added-margin-view-zone { background-color: rgba(155, 185, 85, 0.2); }
.monaco-editor .gutter-insert, .monaco-diff-editor .gutter-insert { background-color: rgba(155, 185, 85, 0.2); }
.monaco-editor .char-delete, .monaco-diff-editor .char-delete { background-color: rgba(255, 0, 0, 0.2); }
.monaco-editor .line-delete, .monaco-diff-editor .line-delete { background-color: rgba(255, 0, 0, 0.2); }
.monaco-editor .inline-deleted-margin-view-zone { background-color: rgba(255, 0, 0, 0.2); }
.monaco-editor .gutter-delete, .monaco-diff-editor .gutter-delete { background-color: rgba(255, 0, 0, 0.2); }
.monaco-diff-editor.side-by-side .editor.modified { box-shadow: -6px 0 5px -5px #dddddd; }
.monaco-diff-editor .diffViewport {
background: rgba(100, 100, 100, 0.4);
}
.monaco-diff-editor .diffViewport:hover {
background: rgba(100, 100, 100, 0.7);
}
.monaco-diff-editor .diffViewport:active {
background: rgba(0, 0, 0, 0.6);
}
.monaco-editor .diagonal-fill {
background-image: linear-gradient(
-45deg,
rgba(34, 34, 34, 0.2) 12.5%,
#0000 12.5%, #0000 50%,
rgba(34, 34, 34, 0.2) 50%, rgba(34, 34, 34, 0.2) 62.5%,
#0000 62.5%, #0000 100%
);
background-size: 8px 8px;
}
.monaco-editor { --vscode-foreground: #616161;
--vscode-errorForeground: #a1260d;
--vscode-descriptionForeground: #717171;
--vscode-icon-foreground: #424242;
--vscode-focusBorder: #0090f1;
--vscode-textSeparator-foreground: rgba(0, 0, 0, 0.18);
--vscode-textLink-foreground: #006ab1;
--vscode-textLink-activeForeground: #006ab1;
--vscode-textPreformat-foreground: #a31515;
--vscode-textBlockQuote-background: rgba(127, 127, 127, 0.1);
--vscode-textBlockQuote-border: rgba(0, 122, 204, 0.5);
--vscode-textCodeBlock-background: rgba(220, 220, 220, 0.4);
--vscode-widget-shadow: rgba(0, 0, 0, 0.16);
--vscode-input-background: #ffffff;
--vscode-input-foreground: #616161;
--vscode-inputOption-activeBorder: rgba(0, 122, 204, 0);
--vscode-inputOption-hoverBackground: rgba(184, 184, 184, 0.31);
--vscode-inputOption-activeBackground: rgba(0, 144, 241, 0.2);
--vscode-inputOption-activeForeground: #000000;
--vscode-input-placeholderForeground: rgba(97, 97, 97, 0.5);
--vscode-inputValidation-infoBackground: #d6ecf2;
--vscode-inputValidation-infoBorder: #007acc;
--vscode-inputValidation-warningBackground: #f6f5d2;
--vscode-inputValidation-warningBorder: #b89500;
--vscode-inputValidation-errorBackground: #f2dede;
--vscode-inputValidation-errorBorder: #be1100;
--vscode-dropdown-background: #ffffff;
--vscode-dropdown-border: #cecece;
--vscode-checkbox-background: #ffffff;
--vscode-checkbox-border: #cecece;
--vscode-button-foreground: #ffffff;
--vscode-button-background: #007acc;
--vscode-button-hoverBackground: #0062a3;
--vscode-button-secondaryForeground: #ffffff;
--vscode-button-secondaryBackground: #5f6a79;
--vscode-button-secondaryHoverBackground: #4c5561;
--vscode-badge-background: #c4c4c4;
--vscode-badge-foreground: #333333;
--vscode-scrollbar-shadow: #dddddd;
--vscode-scrollbarSlider-background: rgba(100, 100, 100, 0.4);
--vscode-scrollbarSlider-hoverBackground: rgba(100, 100, 100, 0.7);
--vscode-scrollbarSlider-activeBackground: rgba(0, 0, 0, 0.6);
--vscode-progressBar-background: #0e70c0;
--vscode-editorError-foreground: #e51400;
--vscode-editorWarning-foreground: #bf8803;
--vscode-editorInfo-foreground: #1a85ff;
--vscode-editorHint-foreground: #6c6c6c;
--vscode-sash-hoverBorder: #0090f1;
--vscode-editor-background: #fffffe;
--vscode-editor-foreground: #000000;
--vscode-editorWidget-background: #f3f3f3;
--vscode-editorWidget-foreground: #616161;
--vscode-editorWidget-border: #c8c8c8;
--vscode-quickInput-background: #f3f3f3;
--vscode-quickInput-foreground: #616161;
--vscode-quickInputTitle-background: rgba(0, 0, 0, 0.06);
--vscode-pickerGroup-foreground: #0066bf;
--vscode-pickerGroup-border: #cccedb;
--vscode-keybindingLabel-background: rgba(221, 221, 221, 0.4);
--vscode-keybindingLabel-foreground: #555555;
--vscode-keybindingLabel-border: rgba(204, 204, 204, 0.4);
--vscode-keybindingLabel-bottomBorder: rgba(187, 187, 187, 0.4);
--vscode-editor-selectionBackground: #add6ff;
--vscode-editor-inactiveSelectionBackground: #e5ebf1;
--vscode-editor-selectionHighlightBackground: rgba(173, 214, 255, 0.3);
--vscode-editor-findMatchBackground: #a8ac94;
--vscode-editor-findMatchHighlightBackground: rgba(234, 92, 0, 0.33);
--vscode-editor-findRangeHighlightBackground: rgba(180, 180, 180, 0.3);
--vscode-searchEditor-findMatchBackground: rgba(234, 92, 0, 0.22);
--vscode-editor-hoverHighlightBackground: rgba(173, 214, 255, 0.15);
--vscode-editorHoverWidget-background: #f3f3f3;
--vscode-editorHoverWidget-foreground: #616161;
--vscode-editorHoverWidget-border: #c8c8c8;
--vscode-editorHoverWidget-statusBarBackground: #e7e7e7;
--vscode-editorLink-activeForeground: #0000ff;
--vscode-editorInlayHint-foreground: rgba(51, 51, 51, 0.8);
--vscode-editorInlayHint-background: rgba(196, 196, 196, 0.3);
--vscode-editorInlayHint-typeForeground: rgba(51, 51, 51, 0.8);
--vscode-editorInlayHint-typeBackground: rgba(196, 196, 196, 0.3);
--vscode-editorInlayHint-parameterForeground: rgba(51, 51, 51, 0.8);
--vscode-editorInlayHint-parameterBackground: rgba(196, 196, 196, 0.3);
--vscode-editorLightBulb-foreground: #ddb100;
--vscode-editorLightBulbAutoFix-foreground: #007acc;
--vscode-diffEditor-insertedTextBackground: rgba(155, 185, 85, 0.2);
--vscode-diffEditor-removedTextBackground: rgba(255, 0, 0, 0.2);
--vscode-diffEditor-diagonalFill: rgba(34, 34, 34, 0.2);
--vscode-list-focusOutline: #0090f1;
--vscode-list-activeSelectionBackground: #0060c0;
--vscode-list-activeSelectionForeground: #ffffff;
--vscode-list-inactiveSelectionBackground: #e4e6f1;
--vscode-list-hoverBackground: #f0f0f0;
--vscode-list-dropBackground: #d6ebff;
--vscode-list-highlightForeground: #0066bf;
--vscode-list-focusHighlightForeground: #9dddff;
--vscode-list-invalidItemForeground: #b89500;
--vscode-list-errorForeground: #b01011;
--vscode-list-warningForeground: #855f00;
--vscode-listFilterWidget-background: #efc1ad;
--vscode-listFilterWidget-outline: rgba(0, 0, 0, 0);
--vscode-listFilterWidget-noMatchesOutline: #be1100;
--vscode-list-filterMatchBackground: rgba(234, 92, 0, 0.33);
--vscode-tree-indentGuidesStroke: #a9a9a9;
--vscode-tree-tableColumnsBorder: rgba(97, 97, 97, 0.13);
--vscode-tree-tableOddRowsBackground: rgba(97, 97, 97, 0.04);
--vscode-list-deemphasizedForeground: #8e8e90;
--vscode-quickInputList-focusForeground: #ffffff;
--vscode-quickInputList-focusBackground: #0060c0;
--vscode-menu-foreground: #616161;
--vscode-menu-background: #ffffff;
--vscode-menu-selectionForeground: #ffffff;
--vscode-menu-selectionBackground: #0060c0;
--vscode-menu-separatorBackground: #888888;
--vscode-toolbar-hoverBackground: rgba(184, 184, 184, 0.31);
--vscode-toolbar-activeBackground: rgba(166, 166, 166, 0.31);
--vscode-editor-snippetTabstopHighlightBackground: rgba(10, 50, 100, 0.2);
--vscode-editor-snippetFinalTabstopHighlightBorder: rgba(10, 50, 100, 0.5);
--vscode-breadcrumb-foreground: rgba(97, 97, 97, 0.8);
--vscode-breadcrumb-background: #fffffe;
--vscode-breadcrumb-focusForeground: #4e4e4e;
--vscode-breadcrumb-activeSelectionForeground: #4e4e4e;
--vscode-breadcrumbPicker-background: #f3f3f3;
--vscode-merge-currentHeaderBackground: rgba(64, 200, 174, 0.5);
--vscode-merge-currentContentBackground: rgba(64, 200, 174, 0.2);
--vscode-merge-incomingHeaderBackground: rgba(64, 166, 255, 0.5);
--vscode-merge-incomingContentBackground: rgba(64, 166, 255, 0.2);
--vscode-merge-commonHeaderBackground: rgba(96, 96, 96, 0.4);
--vscode-merge-commonContentBackground: rgba(96, 96, 96, 0.16);
--vscode-editorOverviewRuler-currentContentForeground: rgba(64, 200, 174, 0.5);
--vscode-editorOverviewRuler-incomingContentForeground: rgba(64, 166, 255, 0.5);
--vscode-editorOverviewRuler-commonContentForeground: rgba(96, 96, 96, 0.4);
--vscode-editorOverviewRuler-findMatchForeground: rgba(209, 134, 22, 0.49);
--vscode-editorOverviewRuler-selectionHighlightForeground: rgba(160, 160, 160, 0.8);
--vscode-minimap-findMatchHighlight: #d18616;
--vscode-minimap-selectionOccurrenceHighlight: #c9c9c9;
--vscode-minimap-selectionHighlight: #add6ff;
--vscode-minimap-errorHighlight: rgba(255, 18, 18, 0.7);
--vscode-minimap-warningHighlight: #bf8803;
--vscode-minimap-foregroundOpacity: #000000;
--vscode-minimapSlider-background: rgba(100, 100, 100, 0.2);
--vscode-minimapSlider-hoverBackground: rgba(100, 100, 100, 0.35);
--vscode-minimapSlider-activeBackground: rgba(0, 0, 0, 0.3);
--vscode-problemsErrorIcon-foreground: #e51400;
--vscode-problemsWarningIcon-foreground: #bf8803;
--vscode-problemsInfoIcon-foreground: #1a85ff;
--vscode-charts-foreground: #616161;
--vscode-charts-lines: rgba(97, 97, 97, 0.5);
--vscode-charts-red: #e51400;
--vscode-charts-blue: #1a85ff;
--vscode-charts-yellow: #bf8803;
--vscode-charts-orange: #d18616;
--vscode-charts-green: #388a34;
--vscode-charts-purple: #652d90;
--vscode-editor-lineHighlightBorder: #eeeeee;
--vscode-editor-rangeHighlightBackground: rgba(253, 255, 0, 0.2);
--vscode-editor-symbolHighlightBackground: rgba(234, 92, 0, 0.33);
--vscode-editorCursor-foreground: #000000;
--vscode-editorWhitespace-foreground: rgba(51, 51, 51, 0.2);
--vscode-editorIndentGuide-background: #d3d3d3;
--vscode-editorIndentGuide-activeBackground: #939393;
--vscode-editorLineNumber-foreground: #237893;
--vscode-editorActiveLineNumber-foreground: #0b216f;
--vscode-editorLineNumber-activeForeground: #0b216f;
--vscode-editorRuler-foreground: #d3d3d3;
--vscode-editorCodeLens-foreground: #919191;
--vscode-editorBracketMatch-background: rgba(0, 100, 0, 0.1);
--vscode-editorBracketMatch-border: #b9b9b9;
--vscode-editorOverviewRuler-border: rgba(127, 127, 127, 0.3);
--vscode-editorGutter-background: #fffffe;
--vscode-editorUnnecessaryCode-opacity: rgba(0, 0, 0, 0.47);
--vscode-editorGhostText-foreground: rgba(0, 0, 0, 0.47);
--vscode-editorOverviewRuler-rangeHighlightForeground: rgba(0, 122, 204, 0.6);
--vscode-editorOverviewRuler-errorForeground: rgba(255, 18, 18, 0.7);
--vscode-editorOverviewRuler-warningForeground: #bf8803;
--vscode-editorOverviewRuler-infoForeground: #1a85ff;
--vscode-editorBracketHighlight-foreground1: #0431fa;
--vscode-editorBracketHighlight-foreground2: #319331;
--vscode-editorBracketHighlight-foreground3: #7b3814;
--vscode-editorBracketHighlight-foreground4: rgba(0, 0, 0, 0);
--vscode-editorBracketHighlight-foreground5: rgba(0, 0, 0, 0);
--vscode-editorBracketHighlight-foreground6: rgba(0, 0, 0, 0);
--vscode-editorBracketHighlight-unexpectedBracket-foreground: rgba(255, 18, 18, 0.8);
--vscode-editorBracketPairGuide-background1: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-background2: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-background3: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-background4: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-background5: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-background6: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-activeBackground1: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-activeBackground2: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-activeBackground3: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-activeBackground4: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-activeBackground5: rgba(0, 0, 0, 0);
--vscode-editorBracketPairGuide-activeBackground6: rgba(0, 0, 0, 0);
--vscode-editorUnicodeHighlight-border: #cea33d;
--vscode-editorOverviewRuler-bracketMatchForeground: #a0a0a0;
--vscode-peekViewTitle-background: rgba(26, 133, 255, 0.1);
--vscode-peekViewTitleLabel-foreground: #000000;
--vscode-peekViewTitleDescription-foreground: #616161;
--vscode-peekView-border: #1a85ff;
--vscode-peekViewResult-background: #f3f3f3;
--vscode-peekViewResult-lineForeground: #646465;
--vscode-peekViewResult-fileForeground: #1e1e1e;
--vscode-peekViewResult-selectionBackground: rgba(51, 153, 255, 0.2);
--vscode-peekViewResult-selectionForeground: #6c6c6c;
--vscode-peekViewEditor-background: #f2f8fc;
--vscode-peekViewEditorGutter-background: #f2f8fc;
--vscode-peekViewResult-matchHighlightBackground: rgba(234, 92, 0, 0.3);
--vscode-peekViewEditor-matchHighlightBackground: rgba(245, 216, 2, 0.87);
--vscode-editorMarkerNavigationError-background: #e51400;
--vscode-editorMarkerNavigationError-headerBackground: rgba(229, 20, 0, 0.1);
--vscode-editorMarkerNavigationWarning-background: #bf8803;
--vscode-editorMarkerNavigationWarning-headerBackground: rgba(191, 136, 3, 0.1);
--vscode-editorMarkerNavigationInfo-background: #1a85ff;
--vscode-editorMarkerNavigationInfo-headerBackground: rgba(26, 133, 255, 0.1);
--vscode-editorMarkerNavigation-background: #fffffe;
--vscode-editor-foldBackground: rgba(173, 214, 255, 0.3);
--vscode-editorGutter-foldingControlForeground: #424242;
--vscode-symbolIcon-arrayForeground: #616161;
--vscode-symbolIcon-booleanForeground: #616161;
--vscode-symbolIcon-classForeground: #d67e00;
--vscode-symbolIcon-colorForeground: #616161;
--vscode-symbolIcon-constantForeground: #616161;
--vscode-symbolIcon-constructorForeground: #652d90;
--vscode-symbolIcon-enumeratorForeground: #d67e00;
--vscode-symbolIcon-enumeratorMemberForeground: #007acc;
--vscode-symbolIcon-eventForeground: #d67e00;
--vscode-symbolIcon-fieldForeground: #007acc;
--vscode-symbolIcon-fileForeground: #616161;
--vscode-symbolIcon-folderForeground: #616161;
--vscode-symbolIcon-functionForeground: #652d90;
--vscode-symbolIcon-interfaceForeground: #007acc;
--vscode-symbolIcon-keyForeground: #616161;
--vscode-symbolIcon-keywordForeground: #616161;
--vscode-symbolIcon-methodForeground: #652d90;
--vscode-symbolIcon-moduleForeground: #616161;
--vscode-symbolIcon-namespaceForeground: #616161;
--vscode-symbolIcon-nullForeground: #616161;
--vscode-symbolIcon-numberForeground: #616161;
--vscode-symbolIcon-objectForeground: #616161;
--vscode-symbolIcon-operatorForeground: #616161;
--vscode-symbolIcon-packageForeground: #616161;
--vscode-symbolIcon-propertyForeground: #616161;
--vscode-symbolIcon-referenceForeground: #616161;
--vscode-symbolIcon-snippetForeground: #616161;
--vscode-symbolIcon-stringForeground: #616161;
--vscode-symbolIcon-structForeground: #616161;
--vscode-symbolIcon-textForeground: #616161;
--vscode-symbolIcon-typeParameterForeground: #616161;
--vscode-symbolIcon-unitForeground: #616161;
--vscode-symbolIcon-variableForeground: #007acc;
--vscode-editorSuggestWidget-background: #f3f3f3;
--vscode-editorSuggestWidget-border: #c8c8c8;
--vscode-editorSuggestWidget-foreground: #000000;
--vscode-editorSuggestWidget-selectedForeground: #ffffff;
--vscode-editorSuggestWidget-selectedBackground: #0060c0;
--vscode-editorSuggestWidget-highlightForeground: #0066bf;
--vscode-editorSuggestWidget-focusHighlightForeground: #9dddff;
--vscode-editorSuggestWidgetStatus-foreground: rgba(0, 0, 0, 0.5);
--vscode-editor-linkedEditingBackground: rgba(255, 0, 0, 0.3);
--vscode-editorHoverWidget-highlightForeground: #0066bf;
--vscode-editor-wordHighlightBackground: rgba(87, 87, 87, 0.25);
--vscode-editor-wordHighlightStrongBackground: rgba(14, 99, 156, 0.25);
--vscode-editorOverviewRuler-wordHighlightForeground: rgba(160, 160, 160, 0.8);
--vscode-editorOverviewRuler-wordHighlightStrongForeground: rgba(192, 160, 192, 0.8); }
.mtk1 { color: #000000; }
.mtk2 { color: #fffffe; }
.mtk3 { color: #808080; }
.mtk4 { color: #ff0000; }
.mtk5 { color: #0451a5; }
.mtk6 { color: #0000ff; }
.mtk7 { color: #098658; }
.mtk8 { color: #008000; }
.mtk9 { color: #dd0000; }
.mtk10 { color: #383838; }
.mtk11 { color: #cd3131; }
.mtk12 { color: #863b00; }
.mtk13 { color: #af00db; }
.mtk14 { color: #800000; }
.mtk15 { color: #e00000; }
.mtk16 { color: #3030c0; }
.mtk17 { color: #666666; }
.mtk18 { color: #778899; }
.mtk19 { color: #c700c7; }
.mtk20 { color: #a31515; }
.mtk21 { color: #4f76ac; }
.mtk22 { color: #008080; }
.mtk23 { color: #001188; }
.mtk24 { color: #4864aa; }
.mtki { font-style: italic; }
.mtkb { font-weight: bold; }
.mtku { text-decoration: underline; text-underline-position: under; }
.mtks { text-decoration: line-through; }
.mtks.mtku { text-decoration: underline line-through; text-underline-position: under; }</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f61 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f61) }
.monaco-editor .codelens-decoration._ee1f61 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f62 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f62) }
.monaco-editor .codelens-decoration._ee1f62 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f63 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f63) }
.monaco-editor .codelens-decoration._ee1f63 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f64 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f64) }
.monaco-editor .codelens-decoration._ee1f64 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f65 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f65) }
.monaco-editor .codelens-decoration._ee1f65 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f66 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f66) }
.monaco-editor .codelens-decoration._ee1f66 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f67 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f67) }
.monaco-editor .codelens-decoration._ee1f67 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f68 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f68) }
.monaco-editor .codelens-decoration._ee1f68 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._ee1f69 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_ee1f69) }
.monaco-editor .codelens-decoration._ee1f69 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccef { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccef) }
.monaco-editor .codelens-decoration._1cd5ccef span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf0 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf0) }
.monaco-editor .codelens-decoration._1cd5ccf0 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf1 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf1) }
.monaco-editor .codelens-decoration._1cd5ccf1 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf2 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf2) }
.monaco-editor .codelens-decoration._1cd5ccf2 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf3 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf3) }
.monaco-editor .codelens-decoration._1cd5ccf3 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf4 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf4) }
.monaco-editor .codelens-decoration._1cd5ccf4 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf5 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf5) }
.monaco-editor .codelens-decoration._1cd5ccf5 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf6 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf6) }
.monaco-editor .codelens-decoration._1cd5ccf6 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf7 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf7) }
.monaco-editor .codelens-decoration._1cd5ccf7 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5ccf8 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5ccf8) }
.monaco-editor .codelens-decoration._1cd5ccf8 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd0e { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd0e) }
.monaco-editor .codelens-decoration._1cd5cd0e span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd0f { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd0f) }
.monaco-editor .codelens-decoration._1cd5cd0f span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd10 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd10) }
.monaco-editor .codelens-decoration._1cd5cd10 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd11 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd11) }
.monaco-editor .codelens-decoration._1cd5cd11 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd12 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd12) }
.monaco-editor .codelens-decoration._1cd5cd12 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd13 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd13) }
.monaco-editor .codelens-decoration._1cd5cd13 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd14 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd14) }
.monaco-editor .codelens-decoration._1cd5cd14 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd15 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd15) }
.monaco-editor .codelens-decoration._1cd5cd15 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd16 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd16) }
.monaco-editor .codelens-decoration._1cd5cd16 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd17 { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd17) }
.monaco-editor .codelens-decoration._1cd5cd17 span.codicon { line-height: 18px; font-size: 10px; }
</style><style type="text/css" media="screen">
.monaco-editor .codelens-decoration._1cd5cd2d { line-height: 18px; font-size: 10px; padding-right: 5px; font-feature-settings: var(--codelens-font-features_1cd5cd2d) }
.monaco-editor .codelens-decoration._1cd5cd2d span.codicon { line-height: 18px; font-size: 10px; }
</style></head>
<body spellcheck="false" style="">
<div id="red-ui-editor" class="red-ui-editor"><div id="red-ui-header"><span class="red-ui-header-logo"><img src="./Node-RED_files/node-red.svg"><span>Node-RED</span></span><ul class="red-ui-header-toolbar hide" style="display: block;"><li><span class="red-ui-deploy-button-group button-group"><a id="red-ui-header-button-deploy" class="red-ui-deploy-button disabled" href="http://localhost:1880/#"><span class="red-ui-deploy-button-content" style="opacity: 1;"><img id="red-ui-header-button-deploy-icon" src="./Node-RED_files/deploy-full-o.svg"> <span>Übernahme (deploy)</span></span><span class="red-ui-deploy-button-spinner hide" style="display: none;"><img src="./Node-RED_files/spin.svg"></span></a><a id="red-ui-header-button-deploy-options" class="red-ui-deploy-button" href="http://localhost:1880/#"><i class="fa fa-caret-down"></i></a><ul class="red-ui-menu red-ui-menu-dropdown pull-right" id="red-ui-header-button-deploy-options-submenu"><li><a id="deploymenu-item-full" tabindex="-1" href="http://localhost:1880/#" class="active"><i class="fa fa-square pull-left"></i><i class="fa fa-check-square pull-left"></i><img src="./Node-RED_files/deploy-full.svg"> <span class="red-ui-menu-label-container"><span class="red-ui-menu-label">Vollständig</span><span class="red-ui-menu-sublabel">Übernimmt alles im Arbeitsbereich</span></span></a></li><li><a id="deploymenu-item-flow" tabindex="-1" href="http://localhost:1880/#"><i class="fa fa-square pull-left"></i><i class="fa fa-check-square pull-left"></i><img src="./Node-RED_files/deploy-flows.svg"> <span class="red-ui-menu-label-container"><span class="red-ui-menu-label">Geänderte Flows</span><span class="red-ui-menu-sublabel">Übernimmt nur Flows, die geänderte Nodes enthalten</span></span></a></li><li><a id="deploymenu-item-node" tabindex="-1" href="http://localhost:1880/#"><i class="fa fa-square pull-left"></i><i class="fa fa-check-square pull-left"></i><img src="./Node-RED_files/deploy-nodes.svg"> <span class="red-ui-menu-label-container"><span class="red-ui-menu-label">Geänderte Nodes</span><span class="red-ui-menu-sublabel">Übernimmt nur Nodes, die sich geändert haben</span></span></a></li><li class="red-ui-menu-divider"></li><li><a id="deploymenu-item-reload" tabindex="-1" href="http://localhost:1880/#"><img src="./Node-RED_files/deploy-reload.svg"> <span class="red-ui-menu-label-container"><span class="red-ui-menu-label">Flows neustarten</span><span class="red-ui-menu-sublabel">Startet die aktuell übernommenen Flows (ohne vorheriges Deploy)</span></span></a></li></ul></span></li><li style="display: none;"><a class="button" href="http://localhost:1880/#"><i class="fa fa-warning"></i></a></li><li><a id="red-ui-header-button-sidemenu" class="button" href="http://localhost:1880/#"><i class="fa fa-bars"></i></a><ul class="red-ui-menu red-ui-menu-dropdown pull-right red-ui-menu-dropdown-noicons red-ui-menu-dropdown-submenus" id="red-ui-header-button-sidemenu-submenu"><li class="red-ui-menu-dropdown-submenu pull-left"><a id="menu-item-projects-menu" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>Projekte</span></span></a><ul id="menu-item-projects-menu-submenu" class="red-ui-menu-dropdown red-ui-menu-dropdown-noicons"><li><a id="menu-item-projects-new" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>Neu</span><span class="red-ui-popover-key">⌘⌥n</span></span></a></li><li class="disabled"><a id="menu-item-projects-open" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>Öffnen</span><span class="red-ui-popover-key">⌘⌥o</span></span></a></li><li class="disabled"><a id="menu-item-projects-settings" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>Einstellungen</span></span></a></li></ul></li><li class="red-ui-menu-dropdown-submenu pull-left"><a id="menu-item-edit-menu" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>Bearbeiten</span></span></a><ul id="menu-item-edit-menu-submenu" class="red-ui-menu-drop
<style>
.func-tabs-row {
margin-bottom: 0;
}
#node-input-libs-container-row .red-ui-editableList-container {
padding: 0px;
}
#node-input-libs-container-row .red-ui-editableList-container li {
padding:0px;
}
#node-input-libs-container-row .red-ui-editableList-item-remove {
right: 5px;
}
#node-input-libs-container-row .red-ui-editableList-header {
display: flex;
background: var(--red-ui-tertiary-background);
padding-right: 75px;
}
#node-input-libs-container-row .red-ui-editableList-header > div {
flex-grow: 1;
}
.node-libs-entry {
display: flex;
}
.node-libs-entry .red-ui-typedInput-container {
border-radius: 0;
border: none;
}
.node-libs-entry .red-ui-typedInput-type-select {
border-radius: 0 !important;
height: 34px;
}
.node-libs-entry > span > input[type=text] {
border-radius: 0;
border-top-color: var(--red-ui-form-background);
border-bottom-color: var(--red-ui-form-background);
border-right-color: var(--red-ui-form-background);
}
.node-libs-entry > span > input[type=text].input-error {
}
.node-libs-entry > span {
flex-grow: 1;
width: 50%;
position: relative;
}
.node-libs-entry span .node-input-libs-var, .node-libs-entry span .red-ui-typedInput-container {
width: 100%;
}
.node-libs-entry > span > span > i {
display: none;
}
.node-libs-entry > span > span.input-error > i {
display: inline;
}
</style>
<input type="hidden" id="node-input-func" autocomplete="off" value="return {
payload: {
power: Number(msg.payload.ENERGY.Power),
volate: Number(msg.payload.ENERGY.Voltage),
current: Number(msg.payload.ENERGY.Current)
}
};
" dir="">
<input type="hidden" id="node-input-noerr" autocomplete="off" value="0" dir="" class="input-error">
<input type="hidden" id="node-input-finalize" autocomplete="off" value="" dir="">
<input type="hidden" id="node-input-initialize" autocomplete="off" value="" dir="">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name">Name</span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name" autocomplete="off" dir="" style="width: calc(100% - 52px);" placeholder="Name"><div style="margin-left:5px; display: inline-block;position: relative;"><a id="node-input-function-lookup" class="red-ui-button"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></a><ul class="red-ui-menu red-ui-menu-dropdown pull-right red-ui-menu-dropdown-noicons" id="node-input-function-lookup-submenu"><li><a id="node-input-function-menu-open-library" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>Bibliothek öffnen ...</span></span></a></li><li><a id="node-input-function-menu-save-library" tabindex="-1" href="http://localhost:1880/#"><span class="red-ui-menu-label"><span>In Bibliothek speichern ...</span></span></a></li></ul></div></div>
</div>
<div class="form-row func-tabs-row">
<div class="red-ui-tabs"><div><ul style="min-width: 600px; margin-bottom: 20px;" id="func-tabs"><li class="red-ui-tab" id="red-ui-tab-func-tab-config" style="width: 23.5%;"><a href="http://localhost:1880/#func-tab-config" class="red-ui-tab-label"><i class="red-ui-tab-icon fa fa-cog"></i><span class="red-ui-text-bidi-aware" dir="">Setup</span></a><span class="red-ui-tabs-fade"></span><span class="red-ui-tabs-badges"></span></li><li class="red-ui-tab" id="red-ui-tab-func-tab-init" style="width: 23.5%;"><a href="http://localhost:1880/#func-tab-init" class="red-ui-tab-label"><span class="red-ui-text-bidi-aware" dir="">Start</span></a><span class="red-ui-tabs-fade"></span><span class="red-ui-tabs-badges"></span></li><li class="red-ui-tab active" id="red-ui-tab-func-tab-body" style="width: 23.5%;"><a href="http://localhost:1880/#func-tab-body" class="red-ui-tab-label"><span class="red-ui-text-bidi-aware" dir="">Funktion</span></a><span class="red-ui-tabs-fade"></span><span class="red-ui-tabs-badges"></span></li><li class="red-ui-tab" id="red-ui-tab-func-tab-finalize" style="width: 23.5%;"><a href="http://localhost:1880/#func-tab-finalize" class="red-ui-tab-label"><span class="red-ui-text-bidi-aware" dir="">Stopp</span></a><span class="red-ui-tabs-fade"></span><span class="red-ui-tabs-badges"></span></li></ul></div></div>
</div>
<div id="func-tabs-content" style="min-height: calc(100% - 95px);">
<div id="func-tab-config" style="display: none;">
<div class="form-row">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="node-red:function.label.outputs">Ausgänge</span></label>
<span class="ui-spinner ui-corner-all ui-widget ui-widget-content"><input id="node-input-outputs" style="width: 60px;" value="1" autocomplete="off" dir="" aria-valuemin="0" aria-valuenow="1" class="ui-spinner-input" role="spinbutton"><a tabindex="-1" aria-hidden="true" class="ui-button ui-widget ui-spinner-button ui-spinner-up ui-corner-tr ui-button-icon-only" role="button"><span class="ui-button-icon ui-icon ui-icon-triangle-1-n"></span><span class="ui-button-icon-space"> </span></a><a tabindex="-1" aria-hidden="true" class="ui-button ui-widget ui-spinner-button ui-spinner-down ui-corner-br ui-button-icon-only" role="button"><span class="ui-button-icon ui-icon ui-icon-triangle-1-s"></span><span class="ui-button-icon-space"> </span></a></span>
</div>
<div class="form-row node-input-libs-row hide" style="margin-bottom: 0px; display: block;">
<label><i class="fa fa-cubes"></i> <span data-i18n="node-red:function.label.modules">Module</span></label>
</div>
<div class="form-row node-input-libs-row hide" id="node-input-libs-container-row" style="display: block;">
<div class="red-ui-editableList"><div class="red-ui-editableList-border"><div class="red-ui-editableList-header"><div data-i18n="node-red:function.require.moduleName">Module name</div><div data-i18n="node-red:function.require.importAs">Import as</div></div><div class="red-ui-editableList-container" style="min-height: 100px; max-height: none; overflow-y: auto;"><ol id="node-input-libs-container" class="red-ui-editableList-list" style="min-height: 0px; min-width: 450px; height: 503px;"></ol></div></div><button type="button" class="red-ui-button red-ui-button-small red-ui-editableList-addButton" style="margin-top: 4px; margin-right: 5px;" title="Element hinzufügen"><i class="fa fa-plus"></i><span> hinzufügen</span></button></div>
</div>
</div>
<div id="func-tab-init" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 612px; min-height: 150px;" class="node-text-editor" id="node-input-init-editor"><div></div><div class="red-ui-editor-text-container" data-keybinding-context="28" data-mode-id="plaintext" style="--codelens-font-features_1cd5cd16:&quot;liga&quot; off, &quot;calt&quot; off;"><div class="monaco-editor no-user-select mac showUnused showDeprecated vs" role="code" data-uri="inmemory://model/36" style="width: 5px; height: 5px;"><div data-mprt="3" class="overflow-guard" style="width: 5px; height: 5px;"><div class="margin" role="presentation" aria-hidden="true" style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; height: 54px; width: 62px;"><div class="glyph-margin" style="left: 0px; width: 0px; height: 54px;"></div><div class="margin-view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="margin-view-overlays" role="presentation" aria-hidden="true" style="position: absolute; width: 62px; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; height: 54px;"><div style="position:absolute;top:0px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">1</div></div></div></div><div class="monaco-scrollable-element editor-scrollable vs mac" role="presentation" data-mprt="5" style="position: absolute; overflow: hidden; left: 62px; height: 5px;"><div class="lines-content monaco-editor-background" style="position: absolute; overflow: hidden; width: 1e+06px; height: 1e+06px; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; left: 0px;"><div class="view-overlays" role="presentation" aria-hidden="true" style="position: absolute; height: 0px; width: 37px;"><div style="position:absolute;top:0px;width:100%;height:18px;"></div></div><div role="presentation" aria-hidden="true" class="view-rulers"></div><div class="view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="view-lines monaco-mouse-cursor-text" role="presentation" aria-hidden="true" data-mprt="7" style="position: absolute; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; width: 37px; height: 54px;"><div style="top:0px;height:18px;" class="view-line"><span><span class="mtk1">//&nbsp;Der&nbsp;Code&nbsp;hier&nbsp;wird&nbsp;ausgeführt,</span></span></div></div><div data-mprt="1" class="contentWidgets" style="position: absolute; top: 0px;"></div><div role="presentation" aria-hidden="true" class="cursors-layer cursor-line-style cursor-solid"><div class="cursor monaco-mouse-cursor-text" style="height: 18px; top: 0px; left: 0px; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; display: none; visibility: hidden;"></div></div></div><div role="presentation" aria-hidden="true" class="invisible scrollbar horizontal fade" style="position: absolute; width: 0px; height: 12px; left: 0px; bottom: 0px;"><div class="slider" style="position: absolute; top: 0px; left: 0px; height: 12px; transform: translate3d(0px, 0px, 0px); contain: strict; width: 20px;"></div></div><canvas class="decorationsOverviewRuler" aria-hidden="true" width="28" height="10" style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; right: 0px; width: 14px; height: 5px; display: block;"></canvas><div role="presentation" aria-hidden="true" class="invisible scrollbar vertical fade" style="position: absolute; width: 14px; height: 5px; right: 0px; top: 0px;"><div class="slider" style="position: absolute; top: 0px; left: 0px; width: 14px; transform: translate3d(0px, 0px, 0px); contain: strict; height: 20px;"></div></div></div><div role="presentation" ari
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-body" style="">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 612px; min-height: 150px;" class="node-text-editor" id="node-input-func-editor"><div></div><div class="red-ui-editor-text-container" data-keybinding-context="29" style="--codelens-font-features_1cd5cd17:&quot;liga&quot; off, &quot;calt&quot; off; --code-editorInlayHintsFontFamily:Menlo, Monaco, &quot;Courier New&quot;, monospace;" data-mode-id="javascript"><div class="monaco-editor no-user-select mac showUnused showDeprecated vs focused" role="code" data-uri="inmemory://model/39" style="width: 598px; height: 612px;"><div data-mprt="3" class="overflow-guard" style="width: 598px; height: 612px;"><div class="margin" role="presentation" aria-hidden="true" style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; height: 738px; width: 62px;"><div class="glyph-margin" style="left: 0px; width: 0px; height: 738px;"></div><div class="margin-view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="margin-view-overlays focused" role="presentation" aria-hidden="true" style="position: absolute; width: 62px; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; height: 738px;"><div style="position:absolute;top:0px;width:100%;height:18px;"><div class="cldr codicon codicon-folding-expanded" style="left:36px;width:26px;"></div><div class="line-numbers" style="left:0px;width:36px;">1</div></div><div style="position:absolute;top:18px;width:100%;height:18px;"><div class="cldr codicon codicon-folding-expanded" style="left:36px;width:26px;"></div><div class="line-numbers" style="left:0px;width:36px;">2</div></div><div style="position:absolute;top:36px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">3</div></div><div style="position:absolute;top:54px;width:100%;height:18px;"><div class="current-line current-line-margin-both" style="width:62px; height:18px;"></div><div class="active-line-number line-numbers" style="left:0px;width:36px;">4</div></div><div style="position:absolute;top:72px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">5</div></div><div style="position:absolute;top:90px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">6</div></div><div style="position:absolute;top:108px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">7</div></div><div style="position:absolute;top:126px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">8</div></div></div></div><div class="monaco-scrollable-element editor-scrollable vs mac" role="presentation" data-mprt="5" style="position: absolute; overflow: hidden; left: 62px; width: 536px; height: 612px;"><div class="lines-content monaco-editor-background" style="position: absolute; overflow: hidden; width: 1e+06px; height: 1e+06px; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; left: 0px;"><div class="view-overlays focused" role="presentation" aria-hidden="true" style="position: absolute; height: 0px; width: 486px;"><div style="position:absolute;top:0px;width:100%;height:18px;"></div><div style="position:absolute;top:18px;width:100%;height:18px;"><div class="core-guide core-guide-indent vertical" style="left:0px;height:18px;width:7.2265625px"></div><div class="cdr bracket-match" style="left:94px;width:7px;height:18px;"></div></div><div style="position:absolute;top:36px;width:100%;height:18px;"><div class="core-guide core-guide-indent vertical" style="left:0px;height:18px;width:7.2265625px"></div><div class="core-guide core-guide-indent-active vertical" style="left:28.90625px;height:18px;width:7.2265625px"></div></div><div style="position:absolute;top:54px;width:100%;height:18px;"><div class="current-line" style="width:486px; height:18px;"></div><div class="core-guide core-guide-indent vertical" style="left:0px;height:18px;width:7.2265625px"></div><div class="core-guide core-gui
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 612px; min-height: 150px;" class="node-text-editor" id="node-input-finalize-editor"><div></div><div class="red-ui-editor-text-container" data-keybinding-context="30" data-mode-id="plaintext" style="--codelens-font-features_1cd5cd2d:&quot;liga&quot; off, &quot;calt&quot; off;"><div class="monaco-editor no-user-select mac showUnused showDeprecated vs" role="code" data-uri="inmemory://model/38" style="width: 5px; height: 5px;"><div data-mprt="3" class="overflow-guard" style="width: 5px; height: 5px;"><div class="margin" role="presentation" aria-hidden="true" style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; height: 54px; width: 62px;"><div class="glyph-margin" style="left: 0px; width: 0px; height: 54px;"></div><div class="margin-view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="margin-view-overlays" role="presentation" aria-hidden="true" style="position: absolute; width: 62px; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; height: 54px;"><div style="position:absolute;top:0px;width:100%;height:18px;"><div class="line-numbers" style="left:0px;width:36px;">1</div></div></div></div><div class="monaco-scrollable-element editor-scrollable vs mac" role="presentation" data-mprt="5" style="position: absolute; overflow: hidden; left: 62px; height: 5px;"><div class="lines-content monaco-editor-background" style="position: absolute; overflow: hidden; width: 1e+06px; height: 1e+06px; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; left: 0px;"><div class="view-overlays" role="presentation" aria-hidden="true" style="position: absolute; height: 0px; width: 37px;"><div style="position:absolute;top:0px;width:100%;height:18px;"></div></div><div role="presentation" aria-hidden="true" class="view-rulers"></div><div class="view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="view-lines monaco-mouse-cursor-text" role="presentation" aria-hidden="true" data-mprt="7" style="position: absolute; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; width: 37px; height: 54px;"><div style="top:0px;height:18px;" class="view-line"><span><span class="mtk1">//&nbsp;Der&nbsp;Code&nbsp;hier&nbsp;wird&nbsp;ausgeführt,</span></span></div></div><div data-mprt="1" class="contentWidgets" style="position: absolute; top: 0px;"></div><div role="presentation" aria-hidden="true" class="cursors-layer cursor-line-style cursor-solid"><div class="cursor monaco-mouse-cursor-text" style="height: 18px; top: 0px; left: 0px; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; display: none; visibility: hidden;"></div></div></div><div role="presentation" aria-hidden="true" class="invisible scrollbar horizontal fade" style="position: absolute; width: 0px; height: 12px; left: 0px; bottom: 0px;"><div class="slider" style="position: absolute; top: 0px; left: 0px; height: 12px; transform: translate3d(0px, 0px, 0px); contain: strict; width: 20px;"></div></div><canvas class="decorationsOverviewRuler" aria-hidden="true" width="28" height="10" style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; right: 0px; width: 14px; height: 5px; display: block;"></canvas><div role="presentation" aria-hidden="true" class="invisible scrollbar vertical fade" style="position: absolute; width: 14px; height: 5px; right: 0px; top: 0px;"><div class="slider" style="position: absolute; top: 0px; left: 0px; width: 14px; transform: translate3d(0px, 0px, 0px); contain: strict; height: 20px;"></div></div></div><div role="presentation"
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
</div>
</form></div><div class="red-ui-tray-content" style="display: none; height: 735px;"><form class="dialog-form form-horizontal" autocomplete="off" style="height: 695px;"><div></div><div class="form-row node-text-editor-row" style="position:relative; padding-top: 4px; height: 100%"><div style="height: 100%" class="node-text-editor" id="node-info-input-info-editor-268"><div><div style="margin-bottom: 5px"><span class="button-group"><button type="button" class="red-ui-button" data-style="h1" style="font-size:1.1em; font-weight: bold">h1</button><button type="button" class="red-ui-button" data-style="h2" style="font-size:1.0em; font-weight: bold">h2</button><button type="button" class="red-ui-button" data-style="h3" style="font-size:0.9em; font-weight: bold">h3</button></span><span class="button-group"><button type="button" class="red-ui-button" data-style="b"><i class="fa fa-bold"></i></button><button type="button" class="red-ui-button" data-style="i"><i class="fa fa-italic"></i></button><button type="button" class="red-ui-button" data-style="code"><i class="fa fa-code"></i></button></span><span class="button-group"><button type="button" class="red-ui-button" data-style="ol"><i class="fa fa-list-ol"></i></button><button type="button" class="red-ui-button" data-style="ul"><i class="fa fa-list-ul"></i></button><button type="button" class="red-ui-button" data-style="bq"><i class="fa fa-quote-left"></i></button><button type="button" class="red-ui-button" data-style="hr"><i class="fa fa-minus"></i></button><button type="button" class="red-ui-button" data-style="link"><i class="fa fa-link"></i></button></span><button type="button" class="red-ui-button" style="float: right;"><i class="fa fa-expand"></i></button></div></div><div class="red-ui-editor-text-container red-ui-editor-text-container-toolbar" data-keybinding-context="27" data-mode-id="markdown" style="--codelens-font-features_1cd5cd15:&quot;liga&quot; off, &quot;calt&quot; off;"><div class="monaco-editor no-user-select mac showUnused showDeprecated vs" role="code" data-uri="inmemory://model/35" style="width: 5px; height: 5px;"><div data-mprt="3" class="overflow-guard" style="width: 5px; height: 5px;"><div class="margin" role="presentation" aria-hidden="true" style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; height: 18px; width: 62px;"><div class="glyph-margin" style="left: 0px; width: 0px; height: 18px;"></div><div class="margin-view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="margin-view-overlays" role="presentation" aria-hidden="true" style="position: absolute; width: 62px; font-family: Menlo, Monaco, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; line-height: 18px; letter-spacing: 0px; height: 18px;"><div style="position:absolute;top:0px;width:100%;height:18px;"><div class="current-line current-line-margin-both" style="width:62px; height:18px;"></div><div class="active-line-number line-numbers" style="left:0px;width:36px;">1</div></div></div></div><div class="monaco-scrollable-element editor-scrollable vs mac" role="presentation" data-mprt="5" style="position: absolute; overflow: hidden; left: 62px; height: 5px;"><div class="lines-content monaco-editor-background" style="position: absolute; overflow: hidden; width: 1e+06px; height: 1e+06px; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; left: 0px;"><div class="view-overlays" role="presentation" aria-hidden="true" style="position: absolute; height: 0px; width: 37px;"><div style="position:absolute;top:0px;width:100%;height:18px;"><div class="current-line" style="width:37px; height:18px;"></div></div></div><div role="presentation" aria-hidden="true" class="view-rulers"></div><div class="view-zones" role="presentation" aria-hidden="true" style="position: absolute;"></div><div class="view-lines monaco-mouse-cursor-text" role="presentation" aria-hidden="true" data-mprt="7" style="position: absolute; font-family: Menlo, Monaco, &q
<p>JavaScript-Funktion zur Weiterverarbeitung eingehender Nachrichten.</p>
<p>Die empfangenen Nachrichten werden der Funktion als JavaScript-Objekt mit dem Namen <code>msg</code> übergeben.</p>
<p>Per Konvention enthält die <code>msg.payload</code>-Eigenschaft die eigentliche Nachricht.</p>
<p>Von der Funktion wird erwartet, dass sie ein (oder mehrere) Nachrichtenobjekt(e) zurückgibt.
Es kann aber auch nichts zurückgeben werden, um einen Flow zu stoppen.</p>
<p>In den <b>Start</b>-Tab kann Code eingetragen werden, der beim Node-Start ausgeführt wird.
In den <b>Stopp</b>-Tab kann Code eingetragen werden, der beim Node-Stopp ausgeführt wird.</p>
<p>Wenn ein promise-Objekt aus dem Start-Code zurückgegeben wird,
beginnt danach die reguläre Verarbeitung der Eingangsnachrichten.</p>
<h3><a class="red-ui-help-info-header expanded" href="http://localhost:1880/#"><i class="fa fa-angle-right"></i>Details</a></h3>
<p>Siehe <a target="_blank" href="http://nodered.org/docs/writing-functions.html">Onlinedokumentation</a>
für weitere Informationen zum Schreiben von Funktionen.</p>
<h4><b>Nachrichten senden</b></h4>
<p>Die Funktion kann die Nachrichten zurückgeben, die sie an die nächsten Nodes im Flow weitergeben möchte,
oder kann <code>node.send(msg)</code> aufrufen.</p>
<p>Es kann folgendes zurückgeben/senden werden:</p>
<ul>
<li>Ein einzelnes Nachrichtenobjekt, das an Nodes am ersten Ausgang übergeben wird</li>
<li>Ein Array von Nachrichtenobjekten, die an die Nodes an den entsprechenden Ausgängen übergeben werden</li>
</ul>
<p><b>Hinweis</b>: Der Start-Code wird nur während der Initialisierung des Nodes ausgeführt.
Wenn <code>node.send</code> im Start-Code aufgerufen wird, können nachfolgende Nodes die Nachricht möglicherweise nicht empfangen.</p>
<p>Wenn ein Element des Arrays selbst ein Array von Nachrichten ist, werden mehrere Nachrichten an den entsprechenden Ausgang gesendet.</p>
<p>Wenn null zurückgegeben wird, entweder direkt oder als ein Array-Element, wird keine Nachricht weitergegeben.</p>
<h4><b>Protokollierung und Fehlerbehandlung</b></h4>
<p>Um alle Informationen zu protokollieren oder einen Fehler zu melden, sind die folgenden Funktionen verfügbar:</p>
<ul>
<li><code>node.log("Protokollnachricht")</code></li>
<li><code>node.warn("Warnmeldungstext")</code></li>
<li><code>node.error("Fehlermeldungstext")</code></li>
</ul>
<p></p>
<p>Der catch-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
Er wird aufgerufen, indem <code>msg</code> als zweites Argument an <code>node.error</code> übergeben wird:</p>
<pre>node.error("Fehlermeldungstext" ,msg);</pre>
<h4><b>Zugriff auf Node-Informationen</b></h4>
<p>Im Funktionsblock können die ID und der Name des Nodes mit den folgenden Eigenschaften referenziert werden:</p>
<ul>
<li><code>node.id</code> - ID des Nodes</li>
<li><code>node.name</code> - Name des Nodes</li>
</ul>
<h4><b>Umgebungsvariablen verwenden</b></h4>
<p>Auf Umgebungsvariablen kann mit <code>env.get("Umgebungsvariablenname")</code> zugegriffen werden.</p>
</span></div></div></div></div></div></div><div style="height: 100%; display: none;"><div class="red-ui-sidebar-node-config" id="red-ui-sidebar-node-config" tabindex="0"><div class="red-ui-sidebar-header"><span class="button-group"><a class="red-ui-sidebar-header-button-toggle selected" id="red-ui-sidebar-config-filter-all" href="http://localhost:1880/#"><span data-i18n="sidebar.config.filterAll">alle</span></a><a class="red-ui-sidebar-header-button-toggle" id="red-ui-sidebar-config-filter-unused" href="http://localhost:1880/#"><span data-i18n="sidebar.config.filterUnused">Nicht verwendet</span></a> </span></div><div><div class="red-ui-palette-category red-ui-sidebar-config-category" id="red-ui-sidebar-config-category-global"><div class="red-ui-sidebar-config-tray-header red-ui-palette-header"><i class="fa fa-angle-down expanded"></i><span class="red-ui-palette-node-config-label" data-i18n="sidebar.config.global">Bei allen Flows</span><span class="red-ui-sidebar-node-config-filter-info" style="display: none;"></span></div><ul class="red-ui-palette-content red-ui-sidebar-node-config-list" style=""><li class="red-ui-palette-node-config-type">influxdb</li><li class="red-ui-palette-node_id_eeb221fb-ab27f"><div class="red-ui-palette-node-config red-ui-palette-node red-ui-palette-node-config-unused"><div class="red-ui-palette-label">[v1.x] test</div><div class="red-ui-palette-icon-container red-ui-palette-icon-container-right">0</div></div></li><li class="red-ui-palette-node_id_d61a7da6caeb26aa"><div class="red-ui-palette-node-config red-ui-palette-node"><div class="red-ui-palette-label">[v2.0] influx</div><div class="red-ui-palette-icon-container red-ui-palette-icon-container-right"><a href="http://localhost:1880/#">3</a></div></div></li><li class="red-ui-palette-node-config-type">mqtt-broker</li><li class="red-ui-palette-node_id_7ce136dbb8c897d1"><div class="red-ui-palette-node-config red-ui-palette-node"><div class="red-ui-palette-label">mosquitto:1833</div><div class="red-ui-palette-icon-container red-ui-palette-icon-container-right"><a href="http://localhost:1880/#">4</a></div></div></li><li class="red-ui-palette-node-config-type">tls-config</li><li class="red-ui-palette-node_id_d50d0c9f-31e858"><div class="red-ui-palette-node-config red-ui-palette-node"><div class="red-ui-palette-label">TLS-Konfiguration</div><div class="red-ui-palette-icon-container red-ui-palette-icon-container-right"><a href="http://localhost:1880/#">2</a></div></div></li><li class="red-ui-palette-node-config-type">ui_base</li><li class="red-ui-palette-node_id_90bc7a058a6ccbd7"><div class="red-ui-palette-node-config red-ui-palette-node"><div class="red-ui-palette-label">Node-RED Dashboard</div></div></li><li class="red-ui-palette-node-config-type">ui_group</li><li class="red-ui-palette-node_id_368e029bdaefea73"><div class="red-ui-palette-node-config red-ui-palette-node"><div class="red-ui-palette-label">[Powermonitor] Power</div><div class="red-ui-palette-icon-container red-ui-palette-icon-container-right"><a href="http://localhost:1880/#">2</a></div></div></li><li class="red-ui-palette-node-config-type">ui_tab</li><li class="red-ui-palette-node_id_8eef9f1fd7446608"><div class="red-ui-palette-node-config red-ui-palette-node"><div class="red-ui-palette-label">Powermonitor</div><div class="red-ui-palette-icon-container red-ui-palette-icon-container-right"><a href="http://localhost:1880/#">1</a></div></div></li></ul></div></div><div><div class="red-ui-palette-category red-ui-sidebar-config-category" id="red-ui-sidebar-config-category-f6f2187d-f17ca8"><div class="red-ui-sidebar-config-tray-header red-ui-palette-header"><i class="fa fa-angle-down"></i><span class="red-ui-palette-node-config-label">MQTT2Influxdb</span><span class="red-ui-sidebar-node-config-filter-info" style="display: none;"></span></div><ul class="red-ui-palette-content red-ui-sidebar-node-config-list" style="display: none;"><li class="red-ui-palette-node-config-none" data-i18n="sidebar.config.none">keine</li></ul></div><div class="red-ui-palette-category red-ui-sidebar-config-category"
<!--
05-junction.html
This file exists so that the runtime loads the Junction node into the registry,
but it is empty so it doesn't appear in the editor palette
-->
</div><div><!-- --- [red-module:node-red/inject] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="inject">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row node-input-property-container-row">
<ol id="node-input-property-container"></ol>
</div>
<div class="form-row" id="node-once">
<label for="node-input-once">&nbsp;</label>
<input type="checkbox" id="node-input-once" style="display:inline-block; width:15px; vertical-align:baseline;">
<span data-i18n="inject.onstart"></span>&nbsp;
<input type="text" id="node-input-onceDelay" placeholder="0.1" style="width:45px; height:28px;">&nbsp;
<span data-i18n="inject.onceDelay"></span>
</div>
<div class="form-row">
<label for=""><i class="fa fa-repeat"></i> <span data-i18n="inject.label.repeat"></span></label>
<select id="inject-time-type-select">
<option value="none" data-i18n="inject.none"></option>
<option value="interval" data-i18n="inject.interval"></option>
<option value="interval-time" data-i18n="inject.interval-time"></option>
<option value="time" data-i18n="inject.time"></option>
</select>
<input type="hidden" id="node-input-repeat">
<input type="hidden" id="node-input-crontab">
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-interval">
<span data-i18n="inject.every"></span>
<input id="inject-time-interval-count" class="inject-time-count" value="1"></input>
<select style="width:100px" id="inject-time-interval-units">
<option value="s" data-i18n="inject.seconds"></option>
<option value="m" data-i18n="inject.minutes"></option>
<option value="h" data-i18n="inject.hours"></option>
</select><br/>
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-interval-time">
<span data-i18n="inject.every"></span> <select style="width:90px; margin-left:20px;" id="inject-time-interval-time-units" class="inject-time-int-count" value="1">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="10">10</option>
<option value="12">12</option>
<option value="15">15</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="0">60</option>
</select> <span data-i18n="inject.minutes"></span><br/>
<span data-i18n="inject.between"></span> <select id="inject-time-interval-time-start" class="inject-time-times"></select>
<span data-i18n="inject.and"></span> <select id="inject-time-interval-time-end" class="inject-time-times"></select><br/>
<div id="inject-time-interval-time-days" class="inject-time-days" style="margin-top:5px">
<div style="display:inline-block; vertical-align:top; margin-right:5px;" data-i18n="inject.on">on</div>
<div style="display:inline-block;">
<div>
<label><input type='checkbox' checked value='1'/> <span data-i18n="inject.days.0"></span></label>
<label><input type='checkbox' checked value='2'/> <span data-i18n="inject.days.1"></span></label>
<label><input type='checkbox' checked value='3'/> <span data-i18n="inject.days.2"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='4'/> <span data-i18n="inject.days.3"></span></label>
<label><input type='checkbox' checked value='5'/> <span data-i18n="inject.days.4"></span></label>
<label><input type='checkbox' checked value='6'/> <span data-i18n="inject.days.5"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='0'/> <span data-i18n="inject.days.6"></span></label>
</div>
</div>
</div>
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-time">
<span data-i18n="inject.at"></span> <input type="text" id="inject-time-time" value="12:00"></input><br/>
<div id="inject-time-time-days" class="inject-time-days">
<div style="display:inline-block; vertical-align:top; margin-right:5px;" data-i18n="inject.on"></div>
<div style="display:inline-block;">
<div>
<label><input type='checkbox' checked value='1'/> <span data-i18n="inject.days.0"></span></label>
<label><input type='checkbox' checked value='2'/> <span data-i18n="inject.days.1"></span></label>
<label><input type='checkbox' checked value='3'/> <span data-i18n="inject.days.2"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='4'/> <span data-i18n="inject.days.3"></span></label>
<label><input type='checkbox' checked value='5'/> <span data-i18n="inject.days.4"></span></label>
<label><input type='checkbox' checked value='6'/> <span data-i18n="inject.days.5"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='0'/> <span data-i18n="inject.days.6"></span></label>
</div>
</div>
</div>
</div>
</script>
<style>
.inject-time-row {
padding-left: 110px;
}
.inject-time-row:not(#inject-time-row-interval) select {
margin: 3px 0;
}
.inject-time-days label {
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
vertical-align: baseline;
width: 100px;
}
.inject-time-days input {
width: auto !important;
vertical-align: baseline !important;
}
.inject-time-times {
width: 90px !important;
}
#inject-time-time {
width: 75px;
margin-left: 8px;
margin-bottom: 8px;
}
.inject-time-count {
padding-left: 3px !important;
width: 80px !important;
}
</style>
<script type="text/javascript">
(function() {
function resizeDialog(size) {
size = size || { height: $(".red-ui-tray-content form").height() }
var rows = $("#dialog-form>div:not(.node-input-property-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-property-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-property-container").editableList('height',height);
}
/** Retrieve editableList items (refactored for re-use in the form inject button)*/
function getProps(el, legacy) {
var result = {
props: []
}
el.each(function(i) {
var prop = $(this);
var p = {
p:prop.find(".node-input-prop-property-name").typedInput('value')
};
if (p.p) {
p.v = prop.find(".node-input-prop-property-value").typedInput('value');
p.vt = prop.find(".node-input-prop-property-value").typedInput('type');
if(legacy) {
if (p.p === "payload") { // save payload to old "legacy" property
result.payloadType = p.vt;
result.payload = p.v;
delete p.v;
delete p.vt;
} else if (p.p === "topic" && p.vt === "str") {
result.topic = p.v;
delete p.v;
}
}
result.props.push(p);
}
});
return result;
}
/** Perform inject, optionally sending a custom msg (refactored for re-use in the form inject button)*/
function doInject(node, customMsg) {
var label = node._def.label.call(node,customMsg?customMsg.__user_inject_props__:undefined);
if (label.length > 30) {
label = label.substring(0, 50) + "...";
}
label = label.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
$.ajax({
url: "inject/" + node.id,
type: "POST",
data: JSON.stringify(customMsg||{}),
contentType: "application/json; charset=utf-8",
success: function (resp) {
RED.notify(node._("inject.success", { label: label }), { type: "success", id: "inject", timeout: 2000 });
},
error: function (jqXHR, textStatus, errorThrown) {
if (jqXHR.status == 404) {
RED.notify(node._("common.notification.error", { message: node._("common.notification.errors.not-deployed") }), "error");
} else if (jqXHR.status == 500) {
RED.notify(node._("common.notification.error", { message: node._("inject.errors.failed") }), "error");
} else if (jqXHR.status == 0) {
RED.notify(node._("common.notification.error", { message: node._("common.notification.errors.no-response") }), "error");
} else {
RED.notify(node._("common.notification.error", { message: node._("common.notification.errors.unexpected", { status: jqXHR.status, message: textStatus }) }), "error");
}
}
});
}
RED.nodes.registerType('inject',{  
category: 'common',
color:"#a6bbcf",
defaults: {
name: {value:""},
props:{value:[{p:"payload"},{p:"topic",vt:"str"}], validate:function(v, opt) {
if (!v || v.length === 0) { return true }
for (var i=0;i<v.length;i++) {
if (/msg|flow|global/.test(v[i].vt)) {
if (!RED.utils.validatePropertyExpression(v[i].v)) {
return RED._("node-red:inject.errors.invalid-prop", { prop: 'msg.'+v[i].p, error: v[i].v });
}
} else if (v[i].vt === "jsonata") {
try{ jsonata(v[i].v); }
catch(e){
return RED._("node-red:inject.errors.invalid-jsonata", { prop: 'msg.'+v[i].p, error: e.message });
}
} else if (v[i].vt === "json") {
try{ JSON.parse(v[i].v); }
catch(e){
return RED._("node-red:inject.errors.invalid-json", { prop: 'msg.'+v[i].p, error: e.message });
}
} else if (v[i].vt === "num"){
if (!/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v[i].v)) {
return RED._("node-red:inject.errors.invalid-prop", { prop: 'msg.'+v[i].p, error: v[i].v });
}
}
}
return true;
}
},
repeat: {
value:"", validate: function(v, opt) {
if ((v === "") ||
(RED.validators.number(v) &&
(v >= 0) && (v <= 2147483))) {
return true;
}
return RED._("node-red:inject.errors.invalid-repeat");
}
},
crontab: {value:""},
once: {value:false},
onceDelay: {value:0.1},
topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType", false) },
payloadType: {value:"date"},
},
icon: "inject.svg",
inputs:0,
outputs:1,
outputLabels: function(index) {
var lab = '';
// if only payload and topic - display payload type
// if only one property - show it's type
// if more than one property (other than payload and topic) - show "x properties" where x is the number of properties.
// this.props will not be an array for legacy inject nodes until they are re-deployed
//
var props = this.props;
if (!Array.isArray(props)) {
props = [
{ p:"payload", v: this.payload, vt: this.payloadType },
{ p:"topic", v: this.topic, vt: "str" }
]
}
if (props) {
for (var i=0,l=props.length; i<l; i++) {
if (i > 0) lab += "\n";
if (i === 5) {
lab += "... +"+(props.length-5);
break;
}
lab += props[i].p+": ";
var propType = props[i].p === "payload"? this.payloadType : props[i].vt;
if (propType === "json") {
try {
var parsedProp = JSON.parse(props[i].p === "payload"? this.payload : props[i].v);
propType = typeof parsedProp;
if (propType === "object" && Array.isArray(parsedProp)) {
propType = "Array";
}
} catch(e) {
propType = "invalid";
}
}
lab += this._("inject.label."+propType);
}
}
return lab;
},
label: function(customProps) {
var suffix = "";
// if fire once then add small indication
if (this.once) {
suffix = " ¹";
}
// but replace with repeat one if set to repeat
if ((this.repeat && this.repeat != 0) || this.crontab) {
suffix = " ↻";
}
if (this.name) {
return this.name+suffix;
}
var payload = "";
var payloadType = "str";
var topic = "";
if (customProps) {
for (var i=0;i<customProps.length;i++) {
if (customProps[i].p === "payload") {
payload = customProps[i].v;
payloadType = customProps[i].vt;
} else if (customProps[i].p === "topic") {
topic = customProps[i].v;
}
}
} else {
payload = this.payload || "";
payloadType = this.payloadType || "str";
topic = this.topic || "";
}
if (payloadType === "string" ||
payloadType === "str" ||
payloadType === "num" ||
payloadType === "bool" ||
payloadType === "json") {
if ((topic !== "") && ((topic.length + payload.length) <= 32)) {
return topic + ":" + payload+suffix;
} else if (payload.length > 0 && payload.length < 24) {
return payload+suffix;
} else {
return this._("inject.inject")+suffix;
}
} else if (payloadType === 'date' || payloadType === 'bin' || payloadType === 'env') {
if ((topic !== "") && (topic.length <= 16)) {
return topic + ":" + this._('inject.label.'+payloadType)+suffix;
} else {
return this._('inject.label.'+payloadType)+suffix;
}
} else if (payloadType === 'flow' || payloadType === 'global') {
var key = RED.utils.parseContextKey(payload);
return payloadType+"."+key.key+suffix;
} else {
return this._("inject.inject")+suffix;
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
var payloadType = node.payloadType;
if (node.payloadType == null) {
if (node.payload == "") {
payloadType = "date";
} else {
payloadType = "str";
}
} else if (node.payloadType === 'string' || node.payloadType === 'none') {
payloadType = "str";
}
$("#inject-time-type-select").on("change", function() {
$("#node-input-crontab").val('');
var id = $("#inject-time-type-select").val();
$(".inject-time-row").hide();
$("#inject-time-row-"+id).show();
// Scroll down
var scrollDiv = $("#dialog-form").parent();
scrollDiv.scrollTop(scrollDiv.prop('scrollHeight'));
resizeDialog();
});
$("#node-input-once").on("change", function() {
$("#node-input-onceDelay").attr('disabled', !$("#node-input-once").prop('checked'));
})
$(".inject-time-times").each(function() {
for (var i=0; i<24; i++) {
var l = (i<10?"0":"")+i+":00";
$(this).append($("<option></option>").val(i).text(l));
}
});
$("<option></option>").val(24).text("00:00").appendTo("#inject-time-interval-time-end");
$("#inject-time-interval-time-start").on("change", function() {
var start = Number($("#inject-time-interval-time-start").val());
var end = Number($("#inject-time-interval-time-end").val());
$("#inject-time-interval-time-end option").remove();
for (var i=start+1; i<25; i++) {
var l = (i<10?"0":"")+i+":00";
if (i==24) {
l = "00:00";
}
var opt = $("<option></option>").val(i).text(l).appendTo("#inject-time-interval-time-end");
if (i === end) {
opt.attr("selected","selected");
}
}
});
$(".inject-time-count").spinner({
//max:60,
min:1
});
var repeattype = "none";
if (node.repeat != "" && node.repeat != 0) {
repeattype = "interval";
var r = "s";
var c = node.repeat;
if (node.repeat % 60 === 0) { r = "m"; c = c/60; }
if (node.repeat % 1440 === 0) { r = "h"; c = c/60; }
$("#inject-time-interval-count").val(c);
$("#inject-time-interval-units").val(r);
$("#inject-time-interval-days").prop("disabled","disabled");
} else if (node.crontab) {
var cronparts = node.crontab.split(" ");
var days = cronparts[4];
if (!isNaN(cronparts[0]) && !isNaN(cronparts[1])) {
repeattype = "time";
// Fixed time
var time = cronparts[1]+":"+cronparts[0];
$("#inject-time-time").val(time);
$("#inject-time-type-select").val("s");
if (days == "*") {
$("#inject-time-time-days input[type=checkbox]").prop("checked",true);
} else {
$("#inject-time-time-days input[type=checkbox]").removeAttr("checked");
days.split(",").forEach(function(v) {
$("#inject-time-time-days [value=" + v + "]").prop("checked", true);
});
}
} else {
repeattype = "interval-time";
// interval - time period
var minutes = cronparts[0].slice(2);
if (minutes === "") { minutes = "0"; }
$("#inject-time-interval-time-units").val(minutes);
if (days == "*") {
$("#inject-time-interval-time-days input[type=checkbox]").prop("checked",true);
} else {
$("#inject-time-interval-time-days input[type=checkbox]").removeAttr("checked");
days.split(",").forEach(function(v) {
$("#inject-time-interval-time-days [value=" + v + "]").prop("checked", true);
});
}
var time = cronparts[1];
var timeparts = time.split(",");
var start;
var end;
if (timeparts.length == 1) {
// 0 or 0-10
var hours = timeparts[0].split("-");
if (hours.length == 1) {
if (hours[0] === "") {
start = "0";
end = "0";
}
else {
start = hours[0];
end = Number(hours[0])+1;
}
} else {
start = hours[0];
end = Number(hours[1])+1;
}
} else {
// 23,0 or 17-23,0-10 or 23,0-2 or 17-23,0
var startparts = timeparts[0].split("-");
start = startparts[0];
var endparts = timeparts[1].split("-");
if (endparts.length == 1) {
end = Number(endparts[0])+1;
} else {
end = Number(endparts[1])+1;
}
}
$("#inject-time-interval-time-end").val(end);
$("#inject-time-interval-time-start").val(start);
}
} else {
$("#inject-time-type-select").val("none");
}
$(".inject-time-row").hide();
$("#inject-time-type-select").val(repeattype);
$("#inject-time-row-"+repeattype).show();
/* */
var eList = $('#node-input-property-container').css('min-height','120px').css('min-width','450px');
eList.editableList({
buttons: [
{
id: "node-inject-test-inject-button",
label: node._("inject.injectNow"),
click: function(e) {
var items = eList.editableList('items');
var props = getProps(items);
var m = {__user_inject_props__: props.props};
doInject(node, m);
}
}
],
addItem: function(container,i,opt) {
var prop = opt;
if (!prop.hasOwnProperty('p')) {
prop = {p:"",v:"",vt:"str"};
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
var row = $('<div/>').appendTo(container);
var propertyName = $('<input/>',{class:"node-input-prop-property-name",type:"text"})
.css("width","30%")
.appendTo(row)
.typedInput({types:['msg']});
$('<div/>',{style: 'display:inline-block; padding:0px 6px;'})
.text('=')
.appendTo(row);
var propertyValue = $('<input/>',{class:"node-input-prop-property-value",type:"text"})
.css("width","calc(70% - 30px)")
.appendTo(row)
.typedInput({default:prop.vt || 'str',types:['flow','global','str','num','bool','json','bin','date','jsonata','env','msg']});
propertyName.typedInput('value',prop.p);
propertyValue.typedInput('value',prop.v);
},
removable: true,
sortable: true
});
$('#node-inject-test-inject-button').css("float", "right").css("margin-right", "unset");
if (RED.nodes.subflow(node.z)) {
$('#node-inject-test-inject-button').attr("disabled",true);
}
if (!node.props) {
var payload = {
p:'payload',
v: node.payload ? node.payload : '',
vt:payloadType ? payloadType : 'date'
};
var topic = {
p:'topic',
v: node.topic ? node.topic : '',
vt:'str'
}
node.props = [payload,topic];
}
for (var i=0; i<node.props.length; i++) {
var prop = node.props[i];
var newProp = { p: prop.p, v: prop.v, vt: prop.vt };
if (newProp.v === undefined) {
if (prop.p === 'payload') {
newProp.v = node.payload ? node.payload : '';
newProp.vt = payloadType ? payloadType : 'date';
} else if (prop.p === 'topic' && prop.vt === "str") {
newProp.v = node.topic ? node.topic : '';
}
}
if (newProp.vt === "string") {
// Fix bug in pre 2.1 where an old Inject node might have
// a migrated rule with type 'string' not 'str'
newProp.vt = "str";
}
eList.editableList('addItem',newProp);
}
$("#inject-time-type-select").trigger("change");
$("#inject-time-interval-time-start").trigger("change");
},
oneditsave: function() {
var repeat = "";
var crontab = "";
var type = $("#inject-time-type-select").val();
if (type == "none") {
// nothing
} else if (type == "interval") {
var count = $("#inject-time-interval-count").val();
var units = $("#inject-time-interval-units").val();
if (units == "s") {
repeat = count;
} else {
if (units == "m") {
//crontab = "*/"+count+" * * * "+days;
repeat = count * 60;
} else if (units == "h") {
//crontab = "0 */"+count+" * * "+days;
repeat = count * 60 * 60;
}
}
} else if (type == "interval-time") {
repeat = "";
var count = $("#inject-time-interval-time-units").val();
var startTime = Number($("#inject-time-interval-time-start").val());
var endTime = Number($("#inject-time-interval-time-end").val());
var days = $('#inject-time-interval-time-days input[type=checkbox]:checked').map(function(_, el) {
return $(el).val()
}).get();
if (days.length == 0) {
crontab = "";
} else {
if (days.length == 7) {
days="*";
} else {
days = days.join(",");
}
var timerange = "";
if (endTime == 0) {
timerange = startTime+"-23";
} else if (startTime+1 < endTime) {
timerange = startTime+"-"+(endTime-1);
} else if (startTime+1 == endTime) {
timerange = startTime;
} else {
var startpart = "";
var endpart = "";
if (startTime == 23) {
startpart = "23";
} else {
startpart = startTime+"-23";
}
if (endTime == 1) {
endpart = "0";
} else {
endpart = "0-"+(endTime-1);
}
timerange = startpart+","+endpart;
}
if (count === "0") {
crontab = count+" "+timerange+" * * "+days;
} else {
crontab = "*/"+count+" "+timerange+" * * "+days;
}
}
} else if (type == "time") {
var time = $("#inject-time-time").val();
var days = $('#inject-time-time-days input[type=checkbox]:checked').map(function(_, el) {
return $(el).val()
}).get();
if (days.length == 0) {
crontab = "";
} else {
if (days.length == 7) {
days="*";
} else {
days = days.join(",");
}
var parts = time.split(":");
if (parts.length === 2) {
repeat = "";
parts[1] = ("00" + (parseInt(parts[1]) % 60)).substr(-2);
parts[0] = ("00" + (parseInt(parts[0]) % 24)).substr(-2);
crontab = parts[1]+" "+parts[0]+" * * "+days;
}
else { crontab = ""; }
}
}
$("#node-input-repeat").val(repeat);
$("#node-input-crontab").val(crontab);
/* Gather the properties */
var items = $("#node-input-property-container").editableList('items');
delete this.payloadType;
delete this.payload;
this.topic = "";
var result = getProps(items, true);
this.props = result.props;
if(result.hasOwnProperty('payloadType')) { this.payloadType = result.payloadType; };
if(result.hasOwnProperty('payload')) { this.payload = result.payload; };
if(result.hasOwnProperty('topic')) { this.topic = result.topic; };
},
button: {
enabled: function() {
return !this.changed
},
onclick: function () {
if (this.changed) {
return RED.notify(RED._("notification.warning", { message: RED._("notification.warnings.undeployedChanges") }), "warning");
}
doInject(this);
}
},
oneditresize: resizeDialog
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="inject">
<p>Injektion einer Nachricht manuell oder in regelmäßigen Intervallen in einen Flow.
Bei den Nutzdaten (Payload) der Nachricht kann es sich um eine Vielzahl von Typen handeln,
einschließlich Zeichenfolgen (string), JavaScript-Objekte oder die aktuelle Zeit.</p>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">Verschiedene Typen</span></dt>
<dd>Eingestellte Nutzdaten (Payload) der Nachricht.</dd>
<dt class="optional">topic <span class="property-type">string</span></dt>
<dd>Optional nutzbare Nachrichten-Eigenschaft.</dd>
</dl>
<h3>Details</h3>
<p>Der inject-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
Der voreingestellte Payload ist die aktuelle Zeit als Zeitstempel in Millisekunden
seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC).</p>
<p>Der Node unterstützt auch die Injektion von Zeichenfolgen, Zahlenwerten, Booleschen Werten,
JavaScript-Objekten oder Flow-lokalen oder globalen Kontextwerten.</p>
<p>Der Node wird normalerweise manuell ausgelöst, indem im Editor auf seine Schaltfläche geklickt wird.
Er kann auch in regelmäßigen Intervallen oder nach einem Zeitplan injizieren.</p>
<p>Er kann auch so eingestellt werden, dass er jedes Mal einen Wert injiziert, wenn der Flow gestartet wird.</p>
<p>Das maximal einstellbare Intervall beträgt etwa 596 Stunden bzw. 24 Tage.
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein scheduler-Node verwendet werden,
der mit Stromausfällen und Neustarts besser umgehen kann.</p>
<p><b>Hinweis</b>: Die Optionen <i>"Intervall zwischen Uhrzeiten"</i> und <i>"Täglicher Zeitpunkt"</i>
verwenden das Standard-Cron-System.</p>
<p>Beispiel "Intervall zwischen Uhrzeiten": Von 3:00 bis 4:00 in 15-Minuten-Intervall ergibt die Zeitpunkte
3:00, 3:15, 3:30, 3:45 und 4:00.</p>
<p>Wenn Sie alle 20 Minuten ab sofort verwenden möchten, verwenden Sie die Option<i>"Intervall"</i>.</p>
<p><b>Hinweis</b>: Um einen Zeilenvorschub in eine Zeichenfolge einzuschließen, muss ein Funktions-Node
zur Erstellung der Nutzdaten (Payload) verwendet werden.</p>
</script>
</div><script src="./Node-RED_files/debug-utils.js"></script><div><!-- --- [red-module:node-red/debug] --- -->
<script type="text/html" data-template-name="debug">
<div class="form-row">
<label for="node-input-typed-complete"><i class="fa fa-list"></i> <span data-i18n="debug.output"></span></label>
<input id="node-input-typed-complete" type="text" style="width: 70%">
<input id="node-input-complete" type="hidden">
<input id="node-input-targetType" type="hidden">
</div>
<div class="form-row">
<label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
<label for="node-input-tosidebar" style="width:70%">
<input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toSidebar"></span>
</label>
</div>
<div class="form-row">
<label for="node-input-console"> </label>
<label for="node-input-console" style="width:70%">
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toConsole"></span>
</label>
</div>
<div class="form-row">
<label for="node-input-tostatus"> </label>
<label for="node-input-tostatus" style="width:70%">
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toStatus"></span>
</label>
</div>
<div class="form-row" id="node-tostatus-line">
<label for="node-input-typed-status"></label>
<input id="node-input-typed-status" type="text" style="width: 70%">
<input id="node-input-statusVal" type="hidden">
<input id="node-input-statusType" type="hidden">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
(function() {
var subWindow = null;
function activateAjaxCall(node, active, successCallback) {
var url;
var body;
if (Array.isArray(node)) {
url = "debug/"+(active?"enable":"disable");
body = {nodes: node.map(function(n) { return n.id})}
node = node[0];
} else {
url = "debug/"+node.id+"/"+(active?"enable":"disable");
}
$.ajax({
url: url,
type: "POST",
data: body,
success: successCallback,
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status == 404) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
} else if (jqXHR.status === 0) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
} else {
// TODO where is the err.status comming from?
RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
}
}
});
}
RED.nodes.registerType('debug',{
category: 'common',
defaults: {
name: {value:"_DEFAULT_"},
active: {value:true},
tosidebar: {value:true},
console: {value:false},
tostatus: {value:false},
complete: {value:"false", required:true},
targetType: {value:undefined},
statusVal: {value:""},
statusType: {value:"auto"}
},
label: function() {
var suffix = "";
if (this.console === true || this.console === "true") { suffix = " ⇲"; }
if (this.targetType === "jsonata") {
return (this.name || "JSONata") + suffix;
}
if (this.complete === true || this.complete === "true") {
return (this.name||"msg") + suffix;
} else {
return (this.name || "msg." + ((!this.complete || this.complete === "false") ? "payload" : this.complete)) + suffix;
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
color:"#87a980",
inputs:1,
outputs:0,
icon: "debug.svg",
align: "right",
button: {
toggle: "active",
visible: function() { return this.tosidebar; },
onclick: function() {
var label = RED.utils.sanitize(this.name||"debug");
var node = this;
activateAjaxCall(node, node.active, function(resp, textStatus, xhr) {
var historyEvent = {
t:'edit',
node:node,
changes:{
active:!node.active
},
dirty:node.dirty,
changed:node.changed,
callback: function(ev) {
activateAjaxCall(ev.node, ev.node.active);
}
};
node.changed = true;
node.dirty = true;
RED.nodes.dirty(true);
RED.history.push(historyEvent);
RED.view.redraw();
if (xhr.status == 200) {
RED.notify(node._("debug.notification.activated",{label:label}),{type: "success", timeout: 2000});
} else if (xhr.status == 201) {
RED.notify(node._("debug.notification.deactivated",{label:label}),{type: "success", timeout: 2000});
}
});
}
},
onpaletteadd: function() {
var options = {
messageMouseEnter: function(sourceId) {
if (sourceId) {
var n = RED.nodes.node(sourceId);
if (n) {
n.highlighted = true;
n.dirty = true;
}
RED.view.redraw();
}
},
messageMouseLeave: function(sourceId) {
if (sourceId) {
var n = RED.nodes.node(sourceId);
if (n) {
n.highlighted = false;
n.dirty = true;
}
RED.view.redraw();
}
},
messageSourceClick: function(sourceId, aliasId, path) {
// Get all of the nodes that could have logged this message
if (RED.nodes.workspace(sourceId)) {
RED.view.reveal(sourceId);
return
}
var candidateNodes = [RED.nodes.node(sourceId)]
if (path) {
for (var i=2;i<path.length;i++) {
candidateNodes.push(RED.nodes.node(path[i]))
}
}
if (aliasId) {
candidateNodes.push(RED.nodes.node(aliasId));
}
if (candidateNodes.length > 1) {
// The node is in a subflow. Check to see if the active
// workspace is a subflow in the node's parentage. If
// so, reveal the relevant subflow instance node.
var ws = RED.workspaces.active();
for (var i=0;i<candidateNodes.length;i++) {
if (candidateNodes[i].z === ws) {
RED.view.reveal(candidateNodes[i].id);
return
}
}
// The active workspace is unrelated to the node. So
// fall back to revealing the top most node
}
RED.view.reveal(candidateNodes[0].id);
},
clear: function() {
RED.nodes.eachNode(function(node) {
node.highlighted = false;
node.dirty = true;
});
RED.view.redraw();
}
};
var uiComponents = RED.debug.init(options);
RED.sidebar.addTab({
id: "debug",
label: this._("debug.sidebar.label"),
name: this._("debug.sidebar.name"),
content: uiComponents.content,
toolbar: uiComponents.footer,
enableOnEdit: true,
pinned: true,
iconClass: "fa fa-bug",
action: "core:show-debug-tab"
});
RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });
var that = this;
RED._debug = function(msg) {
that.handleDebugMessage("", {
name:"debug",
msg:msg
});
};
this.refreshMessageList = function() {
RED.debug.refreshMessageList(RED.workspaces.active());
if (subWindow) {
try {
subWindow.postMessage({event:"workspaceChange",activeWorkspace:RED.workspaces.active()},"*");
} catch(err) {
console.log(err);
}
}
};
RED.events.on("workspace:change", this.refreshMessageList);
this.handleDebugMessage = function(t,o) {
// console.log("->",o.id,o.z,o._alias);
//
// sourceNode should be the top-level node - one that is on a flow.
var sourceNode;
var pathParts;
var pathHierarchy;
if (o.path) {
// Path is a `/`-separated list of ids that identifies the
// complete parentage of the node that generated this message.
// flow-id/subflow-A-instance/subflow-B-instance
// If it has one id, that is a top level flow or config node/global
// each subsequent id is the instance id of a subflow node
//
pathParts = o.path.split("/");
if (pathParts.length === 1) {
// The source node is on a flow or is a global/config - so can use its id to find
sourceNode = RED.nodes.node(o.id);
} else if (pathParts.length > 1) {
// Highlight the subflow instance node.
sourceNode = RED.nodes.node(pathParts[1]);
}
const getNodeLabel = (n) => n.name || (typeof n.label === "function" && n.label()) || (typeof n.label === "string" && n.label) || (n.type + ":" + n.id);
pathHierarchy = pathParts.map((id,index) => {
if (index === 0) {
if (id === "global") {
return { id: sourceNode.id, label: getNodeLabel(sourceNode) }
}
return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
} else {
const instanceNode = RED.nodes.node(id)
const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
return { id: id, label: pathLabel }
}
})
if (pathParts.length === 1 && pathParts[0] !== "global") {
pathHierarchy.push({ id: o.id, label: getNodeLabel(sourceNode) })
}
if (o._alias) {
let aliasNode = RED.nodes.node(o._alias)
if (aliasNode) {
pathHierarchy.push({ id: o._alias, label: getNodeLabel(aliasNode) })
}
}
} else {
// This is probably redundant...
sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
}
if (sourceNode) {
var sourceFlow = RED.nodes.workspace(sourceNode.z)
o._source = {
id:sourceNode.id,
z:sourceNode.z,
name:sourceNode.name,
type:sourceNode.type,
// _alias identifies the actual logging node. This is
// not necessarily the same as sourceNode, which will be
// the top-level subflow instance node.
// This means the node's name is displayed in the sidebar.
_alias:o._alias,
flowName: sourceFlow?(sourceFlow.label||sourceNode.z):sourceNode.z,
path: pathParts,
pathHierarchy: pathHierarchy
};
}
RED.debug.handleDebugMessage(o);
if (subWindow) {
try {
subWindow.postMessage({event:"message",msg:o},"*");
} catch(err) {
console.log(err);
}
}
};
RED.comms.subscribe("debug",this.handleDebugMessage);
this.clearMessageList = function() {
RED.debug.clearMessageList(true);
if (subWindow) {
try {
subWindow.postMessage({event:"projectChange"},"*");
} catch(err) {
console.log(err);
}
}
};
RED.events.on("project:change", this.clearMessageList);
RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) });
RED.actions.add("core:clear-filtered-debug-messages", function() { RED.debug.clearMessageList(true, true) });
RED.actions.add("core:activate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(true), true); });
RED.actions.add("core:activate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, true),true); });
RED.actions.add("core:activate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, false),true); });
RED.actions.add("core:deactivate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(false), false); });
RED.actions.add("core:deactivate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, true),false); });
RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, false),false); });
function getSelectedDebugNodes(state) {
var nodes = [];
var selection = RED.view.selection();
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (RED.nodes.subflow(n.z)) {
return;
}
if (n.type === 'debug' && n.active !== state) {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true).filter(function(n) {
return n.type === 'debug' && n.active !== state
}));
}
});
}
return nodes;
}
function getMatchingDebugNodes(state,globally) {
var nodes = [];
var filter = {type:"debug"};
if (!globally) {
filter.z = RED.workspaces.active();
}
var candidateNodes = RED.nodes.filterNodes(filter);
nodes = candidateNodes.filter(function(n) {
return n.active !== state && !RED.nodes.subflow(n.z)
})
return nodes;
}
function setDebugNodeState(nodes,state) {
var historyEvents = [];
if (nodes.length > 0) {
activateAjaxCall(nodes,false, function(resp, textStatus, xhr) {
nodes.forEach(function(n) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
active: n.active
}
});
n.active = state;
n.changed = true;
n.dirty = true;
})
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty(),
callback: function() {
activateAjaxCall(nodes,nodes[0].active);
}
});
RED.nodes.dirty(true);
RED.view.redraw();
});
}
}
$("#red-ui-sidebar-debug-open").on("click", function(e) {
e.preventDefault();
subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
subWindow.onload = function() {
subWindow.postMessage({event:"workspaceChange",activeWorkspace:RED.workspaces.active()},"*");
};
});
RED.popover.tooltip($("#red-ui-sidebar-debug-open"),RED._('node-red:debug.sidebar.openWindow'));
$(window).on('beforeunload',function() {
if (subWindow) {
try {
subWindow.close();
} catch(err) {
console.log(err);
}
}
});
this.handleWindowMessage = function(evt) {
var msg = evt.data;
if (msg.event === "mouseEnter") {
options.messageMouseEnter(msg.id);
} else if (msg.event === "mouseLeave") {
options.messageMouseLeave(msg.id);
} else if (msg.event === "mouseClick") {
options.messageSourceClick(msg.id,msg._alias,msg.path);
} else if (msg.event === "clear") {
options.clear();
}
};
window.addEventListener('message',this.handleWindowMessage);
},
onpaletteremove: function() {
RED.comms.unsubscribe("debug",this.handleDebugMessage);
RED.sidebar.removeTab("debug");
RED.events.off("workspace:change", this.refreshMessageList);
window.removeEventListener("message",this.handleWindowMessage);
RED.actions.remove("core:show-debug-tab");
RED.actions.remove("core:clear-debug-messages");
delete RED._debug;
},
oneditprepare: function() {
var autoType = {
value: "auto",
label: RED._("node-red:debug.autostatus"),
hasValue: false
};
var counter = {
value: "counter",
label: RED._("node-red:debug.messageCount"),
hasValue: false
};
$("#node-input-typed-status").typedInput({
default: "auto",
types:[autoType, "msg", "jsonata", counter],
typeField: $("#node-input-statusType")
});
var that = this;
var none = {
value: "none",
label: RED._("node-red:debug.none"),
hasValue: false
};
if (this.tosidebar === undefined) {
this.tosidebar = true;
$("#node-input-tosidebar").prop('checked', true);
}
if (this.statusVal === undefined) {
this.statusVal = (this.complete === "false") ? "payload" : ((this.complete === "true") ? "payload" : this.complete+"");
$("#node-input-typed-status").typedInput('value',this.statusVal || "");
}
if (this.statusType === undefined) {
this.statusType = "auto";
$("#node-input-typed-status").typedInput('type',this.statusType || "auto");
}
if (typeof this.console === "string") {
this.console = (this.console == 'true');
$("#node-input-console").prop('checked', this.console);
$("#node-input-tosidebar").prop('checked', true);
}
var fullType = {
value: "full",
label: RED._("node-red:debug.msgobj"),
hasValue: false
};
$("#node-input-typed-complete").typedInput({
default: "msg",
types:['msg', fullType, "jsonata"],
typeField: $("#node-input-targetType")
});
if (this.targetType === "jsonata") {
var property = this.complete || "";
$("#node-input-typed-complete").typedInput('type','jsonata');
$("#node-input-typed-complete").typedInput('value',property);
} else if ((this.targetType === "full") || this.complete === "true" || this.complete === true) {
// show complete message object
$("#node-input-typed-complete").typedInput('type','full');
} else {
var property = (!this.complete||(this.complete === "false")) ? "payload" : this.complete+"";
$("#node-input-typed-complete").typedInput('type','msg');
$("#node-input-typed-complete").typedInput('value',property);
}
$("#node-input-typed-complete").on('change',function() {
if ($("#node-input-typed-complete").typedInput('type') === 'msg' &&
$("#node-input-typed-complete").typedInput('value') === ''
) {
$("#node-input-typed-complete").typedInput('value','payload');
}
});
$("#node-input-tostatus").on('change',function() {
if ($(this).is(":checked")) {
if (that.statusType === "counter") {
that.statusVal = "";
}
else if (!that.hasOwnProperty("statusVal") || that.statusVal === "") {
var type = $("#node-input-typed-complete").typedInput('type');
var comp = "payload";
if (type !== 'full') {
comp = $("#node-input-typed-complete").typedInput('value');
}
that.statusType = "auto";
that.statusVal = comp;
}
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
$("#node-tostatus-line").show();
}
else {
$("#node-tostatus-line").hide();
that.statusType = "auto";
that.statusVal = "";
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
}
});
},
oneditsave: function() {
var type = $("#node-input-typed-complete").typedInput('type');
if (type === 'full') {
$("#node-input-complete").val("true");
} else {
$("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
}
$("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
},
onadd: function() {
if (this.name === '_DEFAULT_') {
this.name = ''
RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
}
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="debug">
<p>Anzeige ausgewählter Nachrichten wahlweise im Debug-Tab, als Node-Status und in der Systemkonsole.
Standardmäßig wird <code>msg.payload</code> angezeigt.</p>
<h3>Details</h3>
<p>Der Debug-Tab zeigt ein strukturiertes Protokoll der empfangenen Nachrichten an,
wodurch die ihre Struktur leichter zu verstehen ist.</p>
<p>JavaScript-Objekte und -Arrays können nach Bedarf ein- und ausgeblendet werden.
Binäre Puffer-Objekte (buffer objects) können nach Möglichkeit als Rohdaten oder als Zeichenfolge (string) angezeigt werden.</p>
<p>Neben der eigentlichen Nachricht werden im Debug-Tab auch der Empfangszeitpunkt,
der empfangende debug-Node, sowie Name und Typ der Nachricht protokolliert.
Durch Klicken auf die Node-ID wird der entsprechende debug-Node im Arbeitsbereich angezeigt.</p>
<p>Die Schaltfläche des debug-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
Es ist empfehlenswert, alle nicht verwendeten debug-Nodes zu deaktivieren oder gleich zu entfernen.</p>
<p>Der debug-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
als kurze Statustexte (max. 32 Zeichen) unter dem debug-Node angezeigt werden.</p>
</script>
</div><div><!-- --- [red-module:node-red/complete] --- -->
<script type="text/html" data-template-name="complete">
<div class="form-row node-input-target-row">
<button id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-complete-target-filter"></div>
<div id="node-input-complete-target-container-div"></div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('complete',{
category: 'common',
color:"#c0edc0",
defaults: {
name: {value:""},
scope: {value:[], type:"*[]"},
uncaught: {value:false}
},
inputs:0,
outputs:1,
icon: "alert.svg",
label: function() {
if (this.name) {
return this.name;
}
return this._("complete.completeNodes",{number:this.scope.length});
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
var scope = node.scope || [];
this._resize = function() {
var rows = $("#dialog-form>div:not(.node-input-target-list-row)");
var height = $("#dialog-form").height();
for (var i=0;i<rows.length;i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-target-list-row");
editorRow.css("height",height+"px");
};
var search = $("#node-input-complete-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
dirList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = dirList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || item.node.type.toLowerCase().indexOf(val) > -1
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var dirList = $("#node-input-complete-target-container-div").css({width: "100%", height: "100%"})
.treeList({multi:true}).on("treelistitemmouseover", function(e, item) {
item.node.highlighted = true;
item.node.dirty = true;
RED.view.redraw();
}).on("treelistitemmouseout", function(e, item) {
item.node.highlighted = false;
item.node.dirty = true;
RED.view.redraw();
})
var candidateNodes = RED.nodes.filterNodes({z:node.z});
var allChecked = true;
var items = [];
var nodeItemMap = {};
candidateNodes.forEach(function(n) {
if (n.id === node.id) {
return;
}
var isChecked = scope.indexOf(n.id) !== -1;
allChecked = allChecked && isChecked;
var nodeDef = RED.nodes.getType(n.type);
var label;
var sublabel;
if (nodeDef) {
var l = nodeDef.label;
label = (typeof l === "function" ? l.call(n) : l)||"";
sublabel = n.type;
if (sublabel.indexOf("subflow:") === 0) {
var subflowId = sublabel.substring(8);
var subflow = RED.nodes.subflow(subflowId);
sublabel = "subflow : "+subflow.name;
}
}
if (!nodeDef || !label) {
label = n.type;
}
nodeItemMap[n.id] = {
node: n,
label: label,
sublabel: sublabel,
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});
dirList.treeList('data',items);
$("#node-input-complete-target-select").on("click", function(e) {
e.preventDefault();
var preselected = dirList.treeList('selected').map(function(n) {return n.node.id});
RED.tray.hide();
RED.view.selectNodes({
selected: preselected,
onselect: function(selection) {
RED.tray.show();
var newlySelected = {};
selection.forEach(function(n) {
newlySelected[n.id] = true;
if (nodeItemMap[n.id]) {
nodeItemMap[n.id].treeList.select(true);
}
})
preselected.forEach(function(id) {
if (!newlySelected[id]) {
nodeItemMap[id].treeList.select(false);
}
})
},
oncancel: function() {
RED.tray.show();
},
filter: function(n) {
return n.id !== node.id;
}
});
})
},
oneditsave: function() {
this.scope = $("#node-input-complete-target-container-div").treeList('selected').map(function(i) { return i.node.id})
},
oneditresize: function(size) {
this._resize();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="complete">
<p>Anstoß eines weiteren Flows, wenn ein anderer Node seine Nachrichtenbearbeitung abgeschlossen hat.</p>
<h3>Details</h3>
<p>Wenn ein Node die Bearbeitung seiner Nachrichten abgeschlossen hat,
kann der complete-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
<p>Der Node kann z.B. mit einem anderen Node ohne Ausgang verknüpft werden
(z.B. E-Mail-Sende-Node), um den Flow fortzusetzen.</p>
<p>Im Node werden dazu die zu überwachenden Nodes des selben Flows ausgewählt.
Im Gegensatz zum catch-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
<p>Nicht alle Nodes können diesen Node anstoßen.
Es hängt davon ab, ob die auslösenden Knoten diese Funktion unterstützen,
welche erst mit Node-RED 1.0 eingeführt wurde.</p>
</script>
</div><div><!-- --- [red-module:node-red/catch] --- -->
<script type="text/html" data-template-name="catch">
<div class="form-row">
<label style="width: auto" for="node-input-scope" data-i18n="catch.label.source"></label>
<select id="node-input-scope-select">
<option value="all" data-i18n="catch.scope.all"></option>
<option value="target" data-i18n="catch.scope.selected"></options>
</select>
</div>
<div class="form-row node-input-uncaught-row">
<input type="checkbox" id="node-input-uncaught" style="display: inline-block; width: auto; vertical-align: top; margin-left: 30px; margin-right: 5px;">
<label for="node-input-uncaught" style="width: auto" data-i18n="catch.label.uncaught"></label>
</div>
<div class="form-row node-input-target-row">
<button id="node-input-catch-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-catch-target-filter"></div>
<div id="node-input-catch-target-container-div"></div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('catch',{
category: 'common',
color:"#e49191",
defaults: {
name: {value:""},
scope: {value:null, type:"*[]"},
uncaught: {value:false}
},
inputs:0,
outputs:1,
icon: "alert.svg",
label: function() {
if (this.name) {
return this.name;
}
if (this.scope) {
return this._("catch.catchNodes",{number:this.scope.length});
}
return this.uncaught?this._("catch.catchUncaught"):this._("catch.catch")
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
var scope = node.scope || [];
this._resize = function() {
var rows = $("#dialog-form>div:not(.node-input-target-list-row)");
var height = $("#dialog-form").height();
for (var i=0;i<rows.length;i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-target-list-row");
editorRow.css("height",height+"px");
};
var search = $("#node-input-catch-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
dirList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = dirList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || item.node.type.toLowerCase().indexOf(val) > -1
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var dirList = $("#node-input-catch-target-container-div").css({width: "100%", height: "100%"})
.treeList({multi:true}).on("treelistitemmouseover", function(e, item) {
item.node.highlighted = true;
item.node.dirty = true;
RED.view.redraw();
}).on("treelistitemmouseout", function(e, item) {
item.node.highlighted = false;
item.node.dirty = true;
RED.view.redraw();
})
var candidateNodes = RED.nodes.filterNodes({z:node.z});
var allChecked = true;
var items = [];
var nodeItemMap = {};
candidateNodes.forEach(function(n) {
if (n.id === node.id) {
return;
}
var isChecked = scope.indexOf(n.id) !== -1;
allChecked = allChecked && isChecked;
var nodeDef = RED.nodes.getType(n.type);
var label;
var sublabel;
if (nodeDef) {
var l = nodeDef.label;
label = (typeof l === "function" ? l.call(n) : l)||"";
sublabel = n.type;
if (sublabel.indexOf("subflow:") === 0) {
var subflowId = sublabel.substring(8);
var subflow = RED.nodes.subflow(subflowId);
sublabel = "subflow : "+subflow.name;
}
}
if (!nodeDef || !label) {
label = n.type;
}
nodeItemMap[n.id] = {
node: n,
label: label,
sublabel: sublabel,
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});
dirList.treeList('data',items);
$("#node-input-catch-target-select").on("click", function(e) {
e.preventDefault();
var preselected = dirList.treeList('selected').map(function(n) {return n.node.id});
RED.tray.hide();
RED.view.selectNodes({
selected: preselected,
onselect: function(selection) {
RED.tray.show();
var newlySelected = {};
selection.forEach(function(n) {
newlySelected[n.id] = true;
if (nodeItemMap[n.id]) {
nodeItemMap[n.id].treeList.select(true);
}
})
preselected.forEach(function(id) {
if (!newlySelected[id]) {
nodeItemMap[id].treeList.select(false);
}
})
},
oncancel: function() {
RED.tray.show();
},
filter: function(n) {
return n.id !== node.id;
}
});
})
$("#node-input-scope-select").on("change", function(e) {
var scope = $(this).val();
if (scope === "target") {
$(".node-input-target-row").show();
$(".node-input-uncaught-row").hide();
} else {
$(".node-input-target-row").hide();
$(".node-input-uncaught-row").show();
}
node._resize();
});
if (this.scope === null) {
$("#node-input-scope-select").val("all");
} else {
$("#node-input-scope-select").val("target");
}
$("#node-input-scope-select").trigger("change");
},
oneditsave: function() {
var scope = $("#node-input-scope-select").val();
if (scope === 'all') {
this.scope = null;
} else {
$("#node-input-uncaught").prop("checked",false);
this.scope = $("#node-input-catch-target-container-div").treeList('selected').map(function(i) { return i.node.id})
}
},
oneditresize: function(size) {
this._resize();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="catch">
<p>Abfang von Fehlern von Nodes im selben Flow-Tab.</p>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>error.message <span class="property-type">string</span></dt>
<dd>Fehlermeldung.</dd>
<dt>error.source.id <span class="property-type">string</span></dt>
<dd>ID des fehlerauslösenden Nodes.</dd>
<dt>error.source.type <span class="property-type">string</span></dt>
<dd>Typ des fehlerauslösenden Nodes.</dd>
<dt>error.source.name <span class="property-type">string</span></dt>
<dd>Name des fehlerauslösenden Nodes (falls festgelegt).</dd>
</dl>
<h3>Details</h3>
<p>Wenn ein Node bei der Verarbeitung einer Nachricht einen Fehler verursacht, wird der Flow in der Regel angehalten.
Der catch-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
<p>Der Node fängt standardmäßig die Fehler aller Nodes im selben Flow ab.
Alternativ kann er auch an bestimmte Nodes gebunden werden.</p>
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen catch-Nodes die Fehlermeldung.</p>
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem catch-Node
innerhalb des Subflows abgefangen.
Wenn im Subflow keine catch-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
in der sich die Subflow-Instanz befindet.</p>
<p>Wenn die Nachricht bereits über eine <code>error</code>-Eigenschaft verfügt, wird sie nach <code>_error</code> kopiert.</p>
</script>
</div><div><!-- --- [red-module:node-red/status] --- -->
<script type="text/html" data-template-name="status">
<div class="form-row">
<label style="width: auto" for="node-input-scope" data-i18n="status.label.source"></label>
<select id="node-input-scope-select">
<option value="all" data-i18n="status.scope.all"></option>
<option value="target" data-i18n="status.scope.selected"></options>
</select>
</div>
<div class="form-row node-input-target-row">
<button id="node-input-status-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-status-target-filter"></div>
<div id="node-input-status-target-container-div"></div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('status',{
category: 'common',
color:"#94c1d0",
defaults: {
name: {value:""},
scope: {value:null, type:"*[]"}
},
inputs:0,
outputs:1,
icon: "status.svg",
label: function() {
return this.name||(this.scope?this._("status.statusNodes",{number:this.scope.length}):this._("status.status"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
var scope = node.scope || [];
this._resize = function() {
var rows = $("#dialog-form>div:not(.node-input-target-list-row)");
var height = $("#dialog-form").height();
for (var i=0;i<rows.length;i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-target-list-row");
editorRow.css("height",height+"px");
};
var search = $("#node-input-status-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
dirList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = dirList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || item.node.type.toLowerCase().indexOf(val) > -1
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var dirList = $("#node-input-status-target-container-div").css({width: "100%", height: "100%"})
.treeList({multi:true}).on("treelistitemmouseover", function(e, item) {
item.node.highlighted = true;
item.node.dirty = true;
RED.view.redraw();
}).on("treelistitemmouseout", function(e, item) {
item.node.highlighted = false;
item.node.dirty = true;
RED.view.redraw();
})
var candidateNodes = RED.nodes.filterNodes({z:node.z});
var allChecked = true;
var items = [];
var nodeItemMap = {};
candidateNodes.forEach(function(n) {
if (n.id === node.id) {
return;
}
var isChecked = scope.indexOf(n.id) !== -1;
allChecked = allChecked && isChecked;
var nodeDef = RED.nodes.getType(n.type);
var label;
var sublabel;
if (nodeDef) {
var l = nodeDef.label;
label = (typeof l === "function" ? l.call(n) : l)||"";
sublabel = n.type;
if (sublabel.indexOf("subflow:") === 0) {
var subflowId = sublabel.substring(8);
var subflow = RED.nodes.subflow(subflowId);
sublabel = "subflow : "+subflow.name;
}
}
if (!nodeDef || !label) {
label = n.type;
}
nodeItemMap[n.id] = {
node: n,
label: label,
sublabel: sublabel,
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});
dirList.treeList('data',items);
$("#node-input-status-target-select").on("click", function(e) {
e.preventDefault();
var preselected = dirList.treeList('selected').map(function(n) {return n.node.id});
RED.tray.hide();
RED.view.selectNodes({
selected: preselected,
onselect: function(selection) {
RED.tray.show();
var newlySelected = {};
selection.forEach(function(n) {
newlySelected[n.id] = true;
if (nodeItemMap[n.id]) {
nodeItemMap[n.id].treeList.select(true);
}
})
preselected.forEach(function(id) {
if (!newlySelected[id]) {
nodeItemMap[id].treeList.select(false);
}
})
},
oncancel: function() {
RED.tray.show();
},
filter: function(n) {
return n.id !== node.id;
}
});
})
$("#node-input-scope-select").on("change", function(e) {
var scope = $(this).val();
if (scope === "target") {
$(".node-input-target-row").show();
} else {
$(".node-input-target-row").hide();
}
node._resize();
});
if (this.scope === null) {
$("#node-input-scope-select").val("all");
} else {
$("#node-input-scope-select").val("target");
}
$("#node-input-scope-select").trigger("change");
},
oneditsave: function() {
var scope = $("#node-input-scope-select").val();
if (scope === 'all') {
this.scope = null;
} else {
this.scope = $("#node-input-status-target-container-div").treeList('selected').map(function(i) { return i.node.id})
}
},
oneditresize: function(size) {
this._resize();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="status">
<p>Berichten von Statusnachrichten anderer Nodes im selben Flow.</p>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>status.text <span class="property-type">string</span></dt>
<dd>Statustext.</dd>
<dt>status.source.type <span class="property-type">string</span></dt>
<dd>Typ des Status meldenden Nodes.</dd>
<dt>status.source.id <span class="property-type">string</span></dt>
<dd>ID des Status meldenden Nodes.</dd>
<dt>status.source.name <span class="property-type">string</span></dt>
<dd>Name des Status meldenden Nodes (falls festgelegt).</dd>
</dl>
<h3>Details</h3>
<p>Dieser Node erzeugt keine Nutzdaten (Payload).</p>
<p>Der Node meldet standardmäßig den Status aller Nodes im selben Flow.
Alternativ kann er auch an bestimmte Nodes gebunden werden.</p>
</script>
</div><div><!-- --- [red-module:node-red/link] --- -->
<script type="text/html" data-template-name="link in">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div style="position:relative; height: 30px; text-align: right;"><div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div></div>
<div class="form-row node-input-link-row"></div>
</script>
<script type="text/html" data-template-name="link out">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-mode"><span data-i18n="link.outMode"></span></label>
<select id="node-input-mode" style="width: 70%">
<option value="link" selected data-i18n="link.sendToAll"></option>
<option value="return" data-i18n="link.returnToCaller"></option>
</select>
</div>
<div class="node-input-link-rows" style="position:relative; height: 30px; text-align: right;"><div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div></div>
<div class="form-row node-input-link-row node-input-link-rows"></div>
</script>
<script type="text/html" data-template-name="link call">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-timeout"><span data-i18n="exec.label.timeout"></span></label>
<input type="text" id="node-input-timeout" placeholder="30" style="width: 70px; margin-right: 5px;"><span data-i18n="inject.seconds"></span>
</div>
<div class="form-row">
<label for="node-input-linkType" data-i18n="link.linkCallType"></label>
<select id="node-input-linkType" style="width: 70%">
<option value="static" data-i18n="link.staticLinkCall"></option>
<option value="dynamic" data-i18n="link.dynamicLinkCall"></option>
</select>
</div>
<div class="link-call-target-tree" style="position:relative; height: 30px; text-align: right;">
<div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div>
</div>
<div class="form-row node-input-link-row link-call-target-tree"></div>
</script>
<script type="text/javascript">
(function() {
let treeList;
function onEditPrepare(node,targetType) {
if (!node.links) {
node.links = [];
}
node.oldLinks = [];
const activeSubflow = RED.nodes.subflow(node.z);
treeList = $("<div>")
.css({width: "100%", height: "100%"})
.appendTo(".node-input-link-row")
.treeList({autoSelect:false})
.on('treelistitemmouseover',function(e,item) {
if (item.node) {
item.node.highlighted = true;
item.node.dirty = true;
RED.view.redraw();
}
})
.on('treelistitemmouseout',function(e,item) {
if (item.node) {
item.node.highlighted = false;
item.node.dirty = true;
RED.view.redraw();
}
});
const candidateNodes = RED.nodes.filterNodes({type:targetType});
let candidateNodesCount = 0;
const search = $("#node-input-link-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
treeList.treeList("filter", null);
search.searchBox("count","");
} else {
const count = treeList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || (item.node && item.node.type.toLowerCase().indexOf(val) > -1)
});
search.searchBox("count",count+" / "+candidateNodesCount);
}
}
});
const flows = [];
const flowMap = {};
if (activeSubflow) {
flowMap[activeSubflow.id] = {
id: activeSubflow.id,
class: 'red-ui-palette-header',
label: "Subflow : " + (activeSubflow.name || activeSubflow.id),
expanded: true,
children: []
};
flows.push(flowMap[activeSubflow.id])
}
if (!activeSubflow || node.type === "link call") {
// Only "Link Call" can look outside of its own subflow
// Link In and Link Out nodes outside of a subflow should be ignored
RED.nodes.eachWorkspace(function (ws) {
flowMap[ws.id] = {
id: ws.id,
class: 'red-ui-palette-header',
label: (ws.label || ws.id) + (node.z === ws.id ? " *" : ""),
expanded: true,
children: []
}
flows.push(flowMap[ws.id])
})
}
candidateNodes.forEach(function (n) {
if (flowMap[n.z]) {
if (targetType === "link out" && n.mode === 'return') {
// Link In nodes looking for Link Out nodes should not
// include return-mode nodes.
return;
}
const isChecked = (node.links.indexOf(n.id) !== -1) || (n.links || []).indexOf(node.id) !== -1;
if (isChecked) {
node.oldLinks.push(n.id);
}
flowMap[n.z].children.push({
id: n.id,
node: n,
label: n.name || n.id,
selected: isChecked,
checkbox: node.type !== "link call",
radio: node.type === "link call"
})
candidateNodesCount++;
}
});
const flowsFiltered = flows.filter(function(f) { return f.children.length > 0 })
treeList.treeList('data',flowsFiltered);
setTimeout(function() {
treeList.treeList('show',node.z);
},100);
}
function resizeNodeList() {
var rows = $("#dialog-form>div:not(.node-input-link-row)");
var height = $("#dialog-form").height();
for (var i=0;i<rows.length;i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-link-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$(".node-input-link-row").css("height",height+"px");
}
function onEditSave(node) {
var flows = treeList.treeList('data');
node.links = [];
if (node.type !== "link out" || $("#node-input-mode").val() === 'link') {
flows.forEach(function(f) {
f.children.forEach(function(n) {
if (n.selected) {
node.links.push(n.id);
}
})
})
}
node.oldLinks.sort();
node.links.sort();
if (node.type === "link call") {
return
}
var nodeMap = {};
var length = Math.max(node.oldLinks.length,node.links.length);
for (var i=0;i<length;i++) {
if (i<node.oldLinks.length) {
nodeMap[node.oldLinks[i]] = nodeMap[node.oldLinks[i]]||{};
nodeMap[node.oldLinks[i]].old = true;
}
if (i<node.links.length) {
nodeMap[node.links[i]] = nodeMap[node.links[i]]||{};
nodeMap[node.links[i]].new = true;
}
}
var n;
for (var id in nodeMap) {
if (nodeMap.hasOwnProperty(id)) {
n = RED.nodes.node(id);
if (n) {
if (nodeMap[id].old && !nodeMap[id].new) {
// Removed id
i = n.links.indexOf(node.id);
if (i > -1) {
n.links.splice(i,1);
}
} else if (!nodeMap[id].old && nodeMap[id].new) {
// Added id
i = n.links.indexOf(id);
if (i === -1) {
n.links.push(node.id);
}
}
}
}
}
}
function onAdd() {
if (this.name === '_DEFAULT_') {
this.name = ''
RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
}
for (var i=0;i<this.links.length;i++) {
var n = RED.nodes.node(this.links[i]);
if (n && n.links.indexOf(this.id) === -1) {
n.links.push(this.id);
}
}
}
RED.nodes.registerType('link in',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: { value: "_DEFAULT_" },
links: { value: [], type:"link out[]" }
},
inputs:0,
outputs:1,
icon: "link-out.svg",
outputLabels: function(i) {
return this.name||this._("link.linkIn");
},
showLabel: false,
label: function() {
return this.name||this._("link.linkIn");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
onEditPrepare(this,"link out");
},
oneditsave: function() {
onEditSave(this);
// In case the name has changed, ensure any link call nodes on this
// tab are redrawn with the updated name
var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"});
localCallNodes.forEach(function(node) {
node.dirty = true;
});
},
onadd: onAdd,
oneditresize: resizeNodeList
});
RED.nodes.registerType('link call',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: { value: "" },
links: { value: [], type:"link in[]" },
linkType: { value:"static" },
timeout: {
value: "30",
label: RED._("node-red:link.timeout"),
validate:RED.validators.number(true)
}
},
inputs: 1,
outputs: 1,
icon: "link-call.svg",
inputLabels: function(i) {
return this.name||this._("link.linkCall");
},
label: function() {
if (this.name) {
return this.name;
}
if (this.linkType === "dynamic") {
return this._("link.dynamicLinkLabel");
} else if (this.links.length > 0) {
var targetNode = RED.nodes.node(this.links[0]);
return targetNode && (targetNode.name || this._("link.linkCall"));
}
return this._("inject.none");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
const updateVisibility = function() {
const static = $('#node-input-linkType').val() !== "dynamic";
if(static) {
$("div.link-call-target-tree").show();
} else {
$("div.link-call-target-tree").hide();
}
}
$("#node-input-linkType").on("change",function(d){
updateVisibility();
});
if (["static","dynamic"].indexOf(this.linkType) < 0) {
$("#node-input-linkType").val('static');
}
updateVisibility();
onEditPrepare(this,"link in");
},
oneditsave: function() {
onEditSave(this);
},
oneditresize: resizeNodeList
});
RED.nodes.registerType('link out',{
category: 'common',
color:"#ddd",//"#87D8CF",
defaults: {
name: { value:"_DEFAULT_" },
mode: { value: "link" },// link || return
links: { value: [], type:"link in[]" }
},
align:"right",
inputs:1,
outputs:0,
icon: function() {
if (this.mode === "return") {
return "link-return.svg";
} else {
return "link-out.svg";
}
},
inputLabels: function(i) {
return this.name||(this.mode === "return" ?this._("link.linkOutReturn"):this._("link.linkOut"));
},
showLabel: false,
label: function() {
return this.name||(this.mode === "return" ?this._("link.linkOutReturn"):this._("link.linkOut"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
onEditPrepare(this,"link in");
$("#node-input-mode").on("change", function() {
$(".node-input-link-rows").toggle(this.value === "link")
})
if (!this.mode) {
$("#node-input-mode").val('link').trigger("change");
}
},
oneditsave: function() {
onEditSave(this);
},
onadd: onAdd,
oneditresize: resizeNodeList
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="link in">
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
<h3>Details</h3>
<p>Der Node kann mit jedem beliebigen link&nbsp;out-Node in einen beliebigen Flow-Tab verlinkt werden.
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
über die durch Klicken zum entsprechenden Flow-Tab gesprungen werden kann.</p>
<p><b>Hinweis</b>: Links können zu Subflows weder rein- noch rausgehend erstellt werden.</p>
</script>
<script type="text/html" data-help-name="link out">
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
<h3>Details</h3>
<p>Der Node kann mit jedem beliebigen link&nbsp;in-Node in einen beliebigen Flow-Tab verlinkt werden.
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
über die durch Klicken zum entsprechenden Flow-Tab gesprungen werden kann.</p>
<p><b>Hinweis</b>: Links können zu Subflows weder rein- noch rausgehend erstellt werden.</p>
</script>
</div><div><!-- --- [red-module:node-red/comment] --- -->
<script type="text/html" data-template-name="comment">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row node-text-editor-row">
<input type="hidden" id="node-input-info" autofocus="autofocus">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-info-editor"></div>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('comment',{
category: 'common',
color:"#ffffff",
defaults: {
name: {value:""},
info: {value:""}
},
inputs:0,
outputs:0,
icon: "comment.svg",
label: function() {
return this.name||this._("comment.comment");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
info: function() {
return this.name?"# "+this.name+"\n\n---\n\n":"";
},
oneditprepare: function() {
var that = this;
this.editor = RED.editor.createEditor({
id: 'node-input-info-editor',
mode: 'ace/mode/markdown',
value: $("#node-input-info").val()
});
this.editor.focus();
},
oneditsave: function() {
$("#node-input-info").val(this.editor.getValue());
this.editor.destroy();
delete this.editor;
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
this.editor.resize();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="comment">
<p>Kommentierung von Flows.</p>
<h3>Details</h3>
<p>Das Textfeld des Nodes verwendet den Markdown-Syntax.
Der eingegebene Text wird in der Info-Seitenleiste angezeigt.</p>
</script>
</div><div><!-- --- [red-module:node-red/unknown] --- -->
<script type="text/html" data-template-name="unknown">
<div class="form-tips"><span data-i18n="[html]unknown.tip"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('unknown',{
category: 'unknown',
color:"#fff0f0",
defaults: {
name: {value:""}
},
inputs:1,
outputs:1,
icon: "",
label: function() {
return "("+this.name+")"||this._("unknown.label.unknown");
},
labelStyle: function() {
return "node_label_unknown";
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="unknown">
<p>Unbekannter Node-Typ für diese Node-RED-Installation.</p>
<h3>Details</h3>
<p><i>Wenn Sie den Node in diesem Zustand übernehmen (deploy), wird die Konfiguration beibehalten,
aber der Flow wird erst gestartet, wenn der fehlende Node-Typ installiert ist.</i></p>
<p>Benutzen Sie Menü-Option <code>Palette verwalten</code>, um die fehlenden Nodes zu suchen und zu installieren,
oder verwenden Sie <b>npm install &lt;module&gt;</b>, um die fehlenden Module zu installieren.
Starten Sie danach Node-RED neu und importieren Sie die Nodes erneut.</p>
<p>Es ist möglich, dass der Node-Typ bereits installiert ist, aber bestimmte Abhängigkeiten vermisst werden.
Prüfen Sie das Node-RED-Protokoll auf Fehlermeldungen in Bezug auf den vermissten Node-Typ.</p>
<p>Andernfalls kontaktieren Sie den Entwickler des Nodes, um Informationen über den vermissten Node-Typ zu bekommen.</p>
</script>
</div><div><!-- --- [red-module:node-red/function] --- -->
<script type="text/html" data-template-name="function">
<style>
.func-tabs-row {
margin-bottom: 0;
}
#node-input-libs-container-row .red-ui-editableList-container {
padding: 0px;
}
#node-input-libs-container-row .red-ui-editableList-container li {
padding:0px;
}
#node-input-libs-container-row .red-ui-editableList-item-remove {
right: 5px;
}
#node-input-libs-container-row .red-ui-editableList-header {
display: flex;
background: var(--red-ui-tertiary-background);
padding-right: 75px;
}
#node-input-libs-container-row .red-ui-editableList-header > div {
flex-grow: 1;
}
.node-libs-entry {
display: flex;
}
.node-libs-entry .red-ui-typedInput-container {
border-radius: 0;
border: none;
}
.node-libs-entry .red-ui-typedInput-type-select {
border-radius: 0 !important;
height: 34px;
}
.node-libs-entry > span > input[type=text] {
border-radius: 0;
border-top-color: var(--red-ui-form-background);
border-bottom-color: var(--red-ui-form-background);
border-right-color: var(--red-ui-form-background);
}
.node-libs-entry > span > input[type=text].input-error {
}
.node-libs-entry > span {
flex-grow: 1;
width: 50%;
position: relative;
}
.node-libs-entry span .node-input-libs-var, .node-libs-entry span .red-ui-typedInput-container {
width: 100%;
}
.node-libs-entry > span > span > i {
display: none;
}
.node-libs-entry > span > span.input-error > i {
display: inline;
}
</style>
<input type="hidden" id="node-input-func">
<input type="hidden" id="node-input-noerr">
<input type="hidden" id="node-input-finalize">
<input type="hidden" id="node-input-initialize">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
</div>
<div class="form-row func-tabs-row">
<ul style="min-width: 600px; margin-bottom: 20px;" id="func-tabs"></ul>
</div>
<div id="func-tabs-content" style="min-height: calc(100% - 95px);">
<div id="func-tab-config" style="display:none">
<div class="form-row">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label>
<input id="node-input-outputs" style="width: 60px;" value="1">
</div>
<div class="form-row node-input-libs-row hide" style="margin-bottom: 0px;">
<label><i class="fa fa-cubes"></i> <span data-i18n="function.label.modules"></span></label>
</div>
<div class="form-row node-input-libs-row hide" id="node-input-libs-container-row">
<ol id="node-input-libs-container"></ol>
</div>
</div>
<div id="func-tab-init" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-body" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 220px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
</div>
</script>
<script type="text/javascript">
(function() {
var invalidModuleVNames = [
'console',
'util',
'Buffer',
'Date',
'RED',
'node',
'__node__',
'context',
'flow',
'global',
'env',
'setTimeout',
'clearTimeout',
'setInterval',
'clearInterval',
'promisify'
]
var knownFunctionNodes = {};
RED.events.on("nodes:add", function(n) {
if (n.type === "function") {
knownFunctionNodes[n.id] = n;
}
})
RED.events.on("nodes:remove", function(n) {
if (n.type === "function") {
delete knownFunctionNodes[n.id];
}
})
var missingModules = [];
var missingModuleReasons = {};
RED.events.on("runtime-state", function(event) {
if (event.error === "missing-modules") {
missingModules = event.modules.map(function(m) { missingModuleReasons[m.module] = m.error; return m.module });
for (var id in knownFunctionNodes) {
if (knownFunctionNodes.hasOwnProperty(id) && knownFunctionNodes[id].libs && knownFunctionNodes[id].libs.length > 0) {
RED.editor.validateNode(knownFunctionNodes[id])
}
}
} else if (!event.text) {
missingModuleReasons = {};
missingModules = [];
for (var id in knownFunctionNodes) {
if (knownFunctionNodes.hasOwnProperty(id) && knownFunctionNodes[id].libs && knownFunctionNodes[id].libs.length > 0) {
RED.editor.validateNode(knownFunctionNodes[id])
}
}
}
RED.view.redraw();
});
var installAllowList = ['*'];
var installDenyList = [];
var modulesEnabled = true;
if (RED.settings.get('externalModules.modules.allowInstall', true) === false) {
modulesEnabled = false;
}
var settingsAllowList = RED.settings.get("externalModules.modules.allowList")
var settingsDenyList = RED.settings.get("externalModules.modules.denyList")
if (settingsAllowList || settingsDenyList) {
installAllowList = settingsAllowList;
installDenyList = settingsDenyList
}
installAllowList = RED.utils.parseModuleList(installAllowList);
installDenyList = RED.utils.parseModuleList(installDenyList);
// object that maps from library name to its descriptor
var allLibs = [];
function moduleName(module) {
var match = /^([^@]+)@(.+)/.exec(module);
if (match) {
return [match[1], match[2]];
}
return [module, undefined];
}
function getAllUsedModules() {
var moduleSet = new Set();
for (var id in knownFunctionNodes) {
if (knownFunctionNodes.hasOwnProperty(id)) {
if (knownFunctionNodes[id].libs) {
for (var i=0, l=knownFunctionNodes[id].libs.length; i<l; i++) {
if (RED.utils.checkModuleAllowed(knownFunctionNodes[id].libs[i].module,null,installAllowList,installDenyList)) {
moduleSet.add(knownFunctionNodes[id].libs[i].module);
}
}
}
}
}
var modules = Array.from(moduleSet);
modules.sort();
return modules;
}
function prepareLibraryConfig(node) {
$(".node-input-libs-row").show();
var usedModules = getAllUsedModules();
var typedModules = usedModules.map(function(l) {
return {icon:"fa fa-cube", value:l,label:l,hasValue:false}
})
typedModules.push({
value:"_custom_", label:RED._("editor:subflow.licenseOther"), icon:"red/images/typedInput/az.svg"
})
var libList = $("#node-input-libs-container").css('min-height','100px').css('min-width','450px').editableList({
header: $('<div><div data-i18n="node-red:function.require.moduleName"></div><div data-i18n="node-red:function.require.importAs"></div></div>'),
addItem: function(container,i,opt) {
var parent = container.parent();
var row0 = $("<div/>").addClass("node-libs-entry").appendTo(container);
var fmoduleSpan = $("<span>").appendTo(row0);
var fmodule = $("<input/>", {
class: "node-input-libs-val",
placeholder: RED._("node-red:function.require.module"),
type: "text"
}).css({
}).appendTo(fmoduleSpan).typedInput({
types: typedModules,
default: usedModules.indexOf(opt.module) > -1 ? opt.module : "_custom_"
});
if (usedModules.indexOf(opt.module) === -1) {
fmodule.typedInput('value', opt.module);
}
var moduleWarning = $('<span style="position: absolute;right:2px;top:7px; display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(fmoduleSpan);
RED.popover.tooltip(moduleWarning.find("i"),function() {
var val = fmodule.typedInput("type");
if (val === "_custom_") {
val = fmodule.val();
}
var errors = [];
if (!RED.utils.checkModuleAllowed(val,null,installAllowList,installDenyList)) {
return RED._("node-red:function.error.moduleNotAllowed",{module:val});
} else {
return RED._("node-red:function.error.moduleLoadError",{module:val,error:missingModuleReasons[val]});
}
})
var fvarSpan = $("<span>").appendTo(row0);
var fvar = $("<input/>", {
class: "node-input-libs-var red-ui-font-code",
placeholder: RED._("node-red:function.require.var"),
type: "text"
}).css({
}).appendTo(fvarSpan).val(opt.var);
var vnameWarning = $('<span style="position: absolute; right:2px;top:7px;display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(fvarSpan);
RED.popover.tooltip(vnameWarning.find("i"),function() {
var val = fvar.val();
if (invalidModuleVNames.indexOf(val) !== -1) {
return RED._("node-red:function.error.moduleNameReserved",{name:val})
} else {
return RED._("node-red:function.error.moduleNameError",{name:val})
}
})
fvar.on("change keyup paste", function (e) {
var v = $(this).val().trim();
if (v === "" || / /.test(v) || invalidModuleVNames.indexOf(v) !== -1) {
fvar.addClass("input-error");
vnameWarning.addClass("input-error");
} else {
fvar.removeClass("input-error");
vnameWarning.removeClass("input-error");
}
});
fmodule.on("change keyup paste", function (e) {
var val = $(this).typedInput("type");
if (val === "_custom_") {
val = $(this).val();
}
var varName = val.trim().replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/].?/g, function(v) { return v[1]?v[1].toUpperCase():"" });
fvar.val(varName);
fvar.trigger("change");
if (RED.utils.checkModuleAllowed(val,null,installAllowList,installDenyList) && (missingModules.indexOf(val) === -1)) {
fmodule.removeClass("input-error");
moduleWarning.removeClass("input-error");
} else {
fmodule.addClass("input-error");
moduleWarning.addClass("input-error");
}
});
if (RED.utils.checkModuleAllowed(opt.module,null,installAllowList,installDenyList) && (missingModules.indexOf(opt.module) === -1)) {
fmodule.removeClass("input-error");
moduleWarning.removeClass("input-error");
} else {
fmodule.addClass("input-error");
moduleWarning.addClass("input-error");
}
if (opt.var) {
fvar.trigger("change");
}
},
removable: true
});
var libs = node.libs || [];
for (var i=0,l=libs.length;i<l; i++) {
libList.editableList('addItem',libs[i])
}
}
function getLibsList() {
var _libs = [];
if (RED.settings.functionExternalModules !== false) {
var libs = $("#node-input-libs-container").editableList("items");
libs.each(function(i) {
var item = $(this);
var v = item.find(".node-input-libs-var").val();
var n = item.find(".node-input-libs-val").typedInput("type");
if (n === "_custom_") {
n = item.find(".node-input-libs-val").val();
}
if ((!v || (v === "")) ||
(!n || (n === ""))) {
return;
}
_libs.push({
var: v,
module: n
});
});
}
return _libs;
}
RED.nodes.registerType('function',{
color:"#fdd0a2",
category: 'function',
defaults: {
name: {value:"_DEFAULT_"},
func: {value:"\nreturn msg;"},
outputs: {value:1},
noerr: {value:0,required:true,
validate: function(v, opt) {
if (!v) {
return true;
}
return RED._("node-red:function.error.invalid-js");
}},
initialize: {value:""},
finalize: {value:""},
libs: {value: [], validate: function(v, opt) {
if (!v) { return true; }
for (var i=0,l=v.length;i<l;i++) {
var m = v[i];
if (!RED.utils.checkModuleAllowed(m.module,null,installAllowList,installDenyList)) {
return RED._("node-red:function.error.moduleNotAllowed", {
module: m.module
});
}
if (m.var === "" || / /.test(m.var)) {
return RED._("node-red:function.error.moduleNameError", {
name: m.var
});
}
if (missingModules.indexOf(m.module) > -1) {
return RED._("node-red:function.error.missing-module", {
module: m.module
});
}
if (invalidModuleVNames.indexOf(m.var) !== -1){
return RED._("node-red:function.error.moduleNameError", {
name: m.var
});
}
}
return true;
}}
},
inputs:1,
outputs:1,
icon: "function.svg",
label: function() {
return this.name||this._("function.function");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var that = this;
var tabs = RED.tabs.create({
id: "func-tabs",
onchange: function(tab) {
$("#func-tabs-content").children().hide();
$("#" + tab.id).show();
let editor = $("#" + tab.id).find('.monaco-editor').first();
if(editor.length) {
if(that.editor.nodered && that.editor.type == "monaco") {
that.editor.nodered.refreshModuleLibs(getLibsList());
}
RED.tray.resize();
//auto focus editor on tab switch
if (that.initEditor.getDomNode() == editor[0]) {
that.initEditor.focus();
} else if (that.editor.getDomNode() == editor[0]) {
that.editor.focus();
} else if (that.finalizeEditor.getDomNode() == editor[0]) {
that.finalizeEditor.focus();
}
}
}
});
tabs.addTab({
id: "func-tab-config",
iconClass: "fa fa-cog",
label: that._("function.label.setup")
});
tabs.addTab({
id: "func-tab-init",
label: that._("function.label.initialize")
});
tabs.addTab({
id: "func-tab-body",
label: that._("function.label.function")
});
tabs.addTab({
id: "func-tab-finalize",
label: that._("function.label.finalize")
});
tabs.activateTab("func-tab-body");
$( "#node-input-outputs" ).spinner({
min:0,
change: function(event, ui) {
var value = this.value;
if (!value.match(/^\d+$/)) { value = 1; }
else if (value < this.min) { value = this.min; }
if (value !== this.value) { $(this).spinner("value", value); }
}
});
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
var editor = RED.editor.createEditor({
id: id,
mode: 'ace/mode/nrjavascript',
value: value || defaultValue || "",
stateId: stateId,
focus: true,
globals: {
msg:true,
context:true,
RED: true,
util: true,
flow: true,
global: true,
console: true,
Buffer: true,
setTimeout: true,
clearTimeout: true,
setInterval: true,
clearInterval: true
},
extraLibs: extraLibs
});
if (defaultValue && value === "") {
editor.moveCursorTo(defaultValue.split("\n").length +offset, 0);
}
editor.__stateId = stateId;
return editor;
}
this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"), undefined, 0);
this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [], undefined, -1);
this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"), undefined, 0);
RED.library.create({
url:"functions", // where to get the data from
type:"function", // the type of object the library is for
editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/nrjavascript",
fields:[
'name', 'outputs',
{
name: 'initialize',
get: function() {
return that.initEditor.getValue();
},
set: function(v) {
that.initEditor.setValue(v||RED._("node-red:function.text.initialize"), -1);
}
},
{
name: 'finalize',
get: function() {
return that.finalizeEditor.getValue();
},
set: function(v) {
that.finalizeEditor.setValue(v||RED._("node-red:function.text.finalize"), -1);
}
},
{
name: 'info',
get: function() {
return that.infoEditor.getValue();
},
set: function(v) {
that.infoEditor.setValue(v||"", -1);
}
}
],
ext:"js"
});
var expandButtonClickHandler = function(editor) {
return function (e) {
e.preventDefault();
var value = editor.getValue();
editor.saveView(`inside function-expandButtonClickHandler ${editor.__stateId}`);
var extraLibs = that.libs || [];
RED.editor.editJavaScript({
value: value,
width: "Infinity",
stateId: editor.__stateId,
mode: "ace/mode/nrjavascript",
focus: true,
cancel: function () {
setTimeout(function () {
editor.focus();
}, 250);
},
complete: function (v, cursor) {
editor.setValue(v, -1);
setTimeout(function () {
editor.restoreView();
editor.focus();
}, 250);
},
extraLibs: extraLibs
});
}
}
$("#node-init-expand-js").on("click", expandButtonClickHandler(this.initEditor));
$("#node-function-expand-js").on("click", expandButtonClickHandler(this.editor));
$("#node-finalize-expand-js").on("click", expandButtonClickHandler(this.finalizeEditor));
RED.popover.tooltip($("#node-init-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-function-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-finalize-expand-js"), RED._("node-red:common.label.expand"));
if (RED.settings.functionExternalModules !== false) {
prepareLibraryConfig(that);
}
},
oneditsave: function() {
var node = this;
var noerr = 0;
$("#node-input-noerr").val(0);
var disposeEditor = function(editorName,targetName,defaultValue) {
var editor = node[editorName];
var annot = editor.getSession().getAnnotations();
for (var k=0; k < annot.length; k++) {
if (annot[k].type === "error") {
noerr += annot.length;
break;
}
}
var val = editor.getValue();
if (defaultValue) {
if (val.trim() == defaultValue.trim()) {
val = "";
}
}
editor.destroy();
delete node[editorName];
$("#"+targetName).val(val);
}
disposeEditor("editor","node-input-func");
disposeEditor("initEditor","node-input-initialize", RED._("node-red:function.text.initialize"));
disposeEditor("finalizeEditor","node-input-finalize", RED._("node-red:function.text.finalize"));
$("#node-input-noerr").val(noerr);
this.noerr = noerr;
node.libs = getLibsList();
},
oneditcancel: function() {
var node = this;
node.editor.destroy();
delete node.editor;
node.initEditor.destroy();
delete node.initEditor;
node.finalizeEditor.destroy();
delete node.finalizeEditor;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("#dialog-form .node-text-editor").css("height",height+"px");
var height = size.height;
$("#node-input-init-editor").css("height", (height - 83)+"px");
$("#node-input-func-editor").css("height", (height - 83)+"px");
$("#node-input-finalize-editor").css("height", (height - 83)+"px");
this.initEditor.resize();
this.editor.resize();
this.finalizeEditor.resize();
$("#node-input-libs-container").css("height", (height - 192)+"px");
},
onadd: function() {
if (this.name === '_DEFAULT_') {
this.name = ''
RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
}
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="function">
<p>JavaScript-Funktion zur Weiterverarbeitung eingehender Nachrichten.</p>
<p>Die empfangenen Nachrichten werden der Funktion als JavaScript-Objekt mit dem Namen <code>msg</code> übergeben.</p>
<p>Per Konvention enthält die <code>msg.payload</code>-Eigenschaft die eigentliche Nachricht.</p>
<p>Von der Funktion wird erwartet, dass sie ein (oder mehrere) Nachrichtenobjekt(e) zurückgibt.
Es kann aber auch nichts zurückgeben werden, um einen Flow zu stoppen.</p>
<p>In den <b>Start</b>-Tab kann Code eingetragen werden, der beim Node-Start ausgeführt wird.
In den <b>Stopp</b>-Tab kann Code eingetragen werden, der beim Node-Stopp ausgeführt wird.</p>
<p>Wenn ein promise-Objekt aus dem Start-Code zurückgegeben wird,
beginnt danach die reguläre Verarbeitung der Eingangsnachrichten.</p>
<h3>Details</h3>
<p>Siehe <a target="_blank" href="http://nodered.org/docs/writing-functions.html">Onlinedokumentation</a>
für weitere Informationen zum Schreiben von Funktionen.</p>
<h4><b>Nachrichten senden</b></h4>
<p>Die Funktion kann die Nachrichten zurückgeben, die sie an die nächsten Nodes im Flow weitergeben möchte,
oder kann <code>node.send(msg)</code> aufrufen.</p>
<p>Es kann folgendes zurückgeben/senden werden:</p>
<ul>
<li>Ein einzelnes Nachrichtenobjekt, das an Nodes am ersten Ausgang übergeben wird</li>
<li>Ein Array von Nachrichtenobjekten, die an die Nodes an den entsprechenden Ausgängen übergeben werden</li>
</ul>
<p><b>Hinweis</b>: Der Start-Code wird nur während der Initialisierung des Nodes ausgeführt.
Wenn <code>node.send</code> im Start-Code aufgerufen wird, können nachfolgende Nodes die Nachricht möglicherweise nicht empfangen.</p>
<p>Wenn ein Element des Arrays selbst ein Array von Nachrichten ist, werden mehrere Nachrichten an den entsprechenden Ausgang gesendet.</p>
<p>Wenn null zurückgegeben wird, entweder direkt oder als ein Array-Element, wird keine Nachricht weitergegeben.</p>
<h4><b>Protokollierung und Fehlerbehandlung</b></h4>
<p>Um alle Informationen zu protokollieren oder einen Fehler zu melden, sind die folgenden Funktionen verfügbar:</p>
<ul>
<li><code>node.log("Protokollnachricht")</code></li>
<li><code>node.warn("Warnmeldungstext")</code></li>
<li><code>node.error("Fehlermeldungstext")</code></li>
</ul>
</p>
<p>Der catch-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
Er wird aufgerufen, indem <code>msg</code> als zweites Argument an <code>node.error</code> übergeben wird:</p>
<pre>node.error("Fehlermeldungstext" ,msg);</pre>
<h4><b>Zugriff auf Node-Informationen</b></h4>
<p>Im Funktionsblock können die ID und der Name des Nodes mit den folgenden Eigenschaften referenziert werden:</p>
<ul>
<li><code>node.id</code> - ID des Nodes</li>
<li><code>node.name</code> - Name des Nodes</li>
</ul>
<h4><b>Umgebungsvariablen verwenden</b></h4>
<p>Auf Umgebungsvariablen kann mit <code>env.get("Umgebungsvariablenname")</code> zugegriffen werden.</p>
</script>
</div><div><!-- --- [red-module:node-red/switch] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="switch">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" style="width: calc(100% - 105px)" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="switch.label.property"></span></label>
<input type="text" id="node-input-property" style="width: calc(100% - 105px)"/>
<input type="hidden" id="node-input-outputs"/>
</div>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
</div>
<div class="form-row">
<select id="node-input-checkall" style="width:100%; margin-right:5px;">
<option value="true" data-i18n="switch.checkall"></option>
<option value="false" data-i18n="switch.stopfirst"></option>
</select>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-repair" style="display: inline-block; width: auto; vertical-align: top;">
<label style="width: auto;" for="node-input-repair"><span data-i18n="switch.label.repair"></span></label></input>
</div>
</script>
<script type="text/javascript">
(function() {
var operators = [
{v:"eq",t:"==",kind:'V'},
{v:"neq",t:"!=",kind:'V'},
{v:"lt",t:"<",kind:'V'},
{v:"lte",t:"<=",kind:'V'},
{v:"gt",t:">",kind:'V'},
{v:"gte",t:">=",kind:'V'},
{v:"hask",t:"switch.rules.hask",kind:'V'},
{v:"btwn",t:"switch.rules.btwn",kind:'V'},
{v:"cont",t:"switch.rules.cont",kind:'V'},
{v:"regex",t:"switch.rules.regex",kind:'V'},
{v:"true",t:"switch.rules.true",kind:'V'},
{v:"false",t:"switch.rules.false",kind:'V'},
{v:"null",t:"switch.rules.null",kind:'V'},
{v:"nnull",t:"switch.rules.nnull",kind:'V'},
{v:"istype",t:"switch.rules.istype",kind:'V'},
{v:"empty",t:"switch.rules.empty",kind:'V'},
{v:"nempty",t:"switch.rules.nempty",kind:'V'},
{v:"head",t:"switch.rules.head",kind:'S'},
{v:"index",t:"switch.rules.index",kind:'S'},
{v:"tail",t:"switch.rules.tail",kind:'S'},
{v:"jsonata_exp",t:"switch.rules.exp",kind:'O'},
{v:"else",t:"switch.rules.else",kind:'O'}
];
var previousValueType = {value:"prev",label:RED._("node-red:switch.previous"),hasValue:false};
function clipValueLength(v) {
if (v.length > 15) {
return v.substring(0,15)+"...";
}
return v;
}
function prop2name(key) {
var result = RED.utils.parseContextKey(key);
return result.key;
}
function getValueLabel(t,v) {
if (t === 'str') {
return '"'+clipValueLength(v)+'"';
} else if (t === 'msg') {
return t+"."+clipValueLength(v);
} else if (t === 'flow' || t === 'global') {
return t+"."+clipValueLength(prop2name(v));
}
return clipValueLength(v);
}
function exportRule(rule) {
var type = rule.find("select").val();
var r = {t:type};
if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "empty" || type === "nempty" || type === "else")) {
if ((type === "btwn") || (type === "index")) {
r.v = rule.find(".node-input-rule-btwn-value").typedInput('value');
r.vt = rule.find(".node-input-rule-btwn-value").typedInput('type');
r.v2 = rule.find(".node-input-rule-btwn-value2").typedInput('value');
r.v2t = rule.find(".node-input-rule-btwn-value2").typedInput('type');
} else if ((type === "head") || (type === "tail")) {
r.v = rule.find(".node-input-rule-num-value").typedInput('value');
r.vt = rule.find(".node-input-rule-num-value").typedInput('type');
} else if (type === "istype") {
r.v = rule.find(".node-input-rule-type-value").typedInput('type');
r.vt = rule.find(".node-input-rule-type-value").typedInput('type');
} else if (type === "jsonata_exp") {
r.v = rule.find(".node-input-rule-exp-value").typedInput('value');
r.vt = rule.find(".node-input-rule-exp-value").typedInput('type');
} else {
r.v = rule.find(".node-input-rule-value").typedInput('value');
r.vt = rule.find(".node-input-rule-value").typedInput('type');
}
if (type === "regex") {
r.case = rule.find(".node-input-rule-case").prop("checked");
}
}
return r;
}
function createValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
}
function createNumValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-num-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:defaultType||'num',types:['flow','global','num','jsonata','env']});
}
function createExpValueField(row){
return $('<input/>',{class:"node-input-rule-exp-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:'jsonata',types:['jsonata']});
}
function createBtwnValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"width: 100%;"}).appendTo(row)
.typedInput({default:defaultType||'num',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
}
function createBtwnValue2Field(row3, andLabel, defaultType){
$('<div/>',{class:"node-input-rule-btwn-label", style:"width: 120px; text-align: right;"}).text(" "+andLabel+" ").appendTo(row3);
var row3InputCell = $('<div/>',{style:"flex-grow:1; margin-left: 5px;"}).appendTo(row3);
return $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"width: 100%"}).appendTo(row3InputCell)
.typedInput({default:defaultType||'num',types:['msg','flow','global','str','num','jsonata','env',previousValueType]});
}
function createTypeValueField(row, defaultType){
return $('<input/>',{class:"node-input-rule-type-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:defaultType || 'string',types:[
{value:"string",label:RED._("common.type.string"),hasValue:false,icon:"red/images/typedInput/az.svg"},
{value:"number",label:RED._("common.type.number"),hasValue:false,icon:"red/images/typedInput/09.svg"},
{value:"boolean",label:RED._("common.type.boolean"),hasValue:false,icon:"red/images/typedInput/bool.svg"},
{value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.svg"},
{value:"buffer",label:RED._("common.type.buffer"),hasValue:false,icon:"red/images/typedInput/bin.svg"},
{value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.svg"},
{value:"json",label:RED._("common.type.jsonString"),hasValue:false,icon:"red/images/typedInput/json.svg"},
{value:"undefined",label:RED._("common.type.undefined"),hasValue:false},
{value:"null",label:RED._("common.type.null"),hasValue:false}
]});
}
RED.nodes.registerType('switch', {
color: "#E2D96E",
category: 'function',
defaults: {
name: {value:""},
property: {value:"payload", required:true,
label:RED._("node-red:common.label.payload"),
validate: RED.validators.typedInput("propertyType", false)},
propertyType: { value:"msg" },
rules: {value:[{t:"eq", v:"", vt:"str"}]},
checkall: {value:"true", required:true},
repair: {value:false},
outputs: {value:1}
},
inputs: 1,
outputs: 1,
outputLabels: function(index) {
var rule = this.rules[index];
var label = "";
if (rule) {
for (var i=0;i<operators.length;i++) {
if (operators[i].v === rule.t) {
label = /^switch/.test(operators[i].t)?this._(operators[i].t):operators[i].t;
break;
}
}
if ((rule.t === 'btwn') || (rule.t === 'index')) {
label += " "+getValueLabel(rule.vt,rule.v)+" & "+getValueLabel(rule.v2t,rule.v2);
} else if (rule.t !== 'true' && rule.t !== 'false' && rule.t !== 'null' && rule.t !== 'nnull' && rule.t !== 'empty' && rule.t !== 'nempty' && rule.t !== 'else' ) {
label += " "+getValueLabel(rule.vt,rule.v);
}
return label;
}
},
icon: "switch.svg",
label: function() {
return this.name||this._("switch.switch");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
$("#node-input-property").typedInput({default:this.propertyType||'msg',types:['msg','flow','global','jsonata','env']});
var outputCount = $("#node-input-outputs").val("{}");
var andLabel = this._("switch.and");
var caseLabel = this._("switch.ignorecase");
$("#node-input-rule-container").css('min-height','150px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var focusValueField = false;
if (!opt.hasOwnProperty('r')) {
opt.r = {};
if (i > 0) {
var lastRule = $("#node-input-rule-container").editableList('getItemAt',i-1);
var exportedRule = exportRule(lastRule.element);
opt.r.vt = exportedRule.vt;
opt.r.v = "";
// We could copy the value over as well and preselect it (see the 'activeElement' code below)
// But not sure that feels right. Is copying over the last value 'expected' behaviour?
// It would make sense for an explicit 'copy' action, but not sure where the copy button would
// go for each rule without being wasted space for most users.
// opt.r.v = exportedRule.v;
focusValueField = true;
}
}
opt.element = container;
var rule = opt.r;
if (!rule.hasOwnProperty('t')) {
rule.t = 'eq';
}
if (!opt.hasOwnProperty('i')) {
opt._i = Math.floor((0x99999-0x10000)*Math.random()).toString();
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap',
display: "flex",
"align-items":"center"
});
var inputRows = $('<div></div>',{style:"flex-grow:1"}).appendTo(container);
var row = $('<div></div>',{style:"display: flex;"}).appendTo(inputRows);
var row2 = $('<div/>',{style:"display: flex; padding-top: 5px; padding-left: 175px;"}).appendTo(inputRows);
var row3 = $('<div/>',{style:"display: flex; padding-top: 5px; align-items: center"}).appendTo(inputRows);
var row4 = $('<div/>',{style:"visibility: hidden; height: 0px;"}).appendTo(inputRows);
var textSpan = $("<span/>").appendTo(row4);
var selectField = $('<select/>',{style:"width:120px; text-align: center;"}).appendTo(row);
var group0 = $('<optgroup/>', { label: RED._("node-red:switch.label.value-rules") }).appendTo(selectField);
for (var d in operators) {
if(operators[d].kind === 'V') {
group0.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
}
}
var group1 = $('<optgroup/>', { label: RED._("node-red:switch.label.sequence-rules") }).appendTo(selectField);
for (var d in operators) {
if(operators[d].kind === 'S') {
group1.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
}
}
for (var d in operators) {
if(operators[d].kind === 'O') {
selectField.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
}
}
var rowInputCell = $('<div>',{style:"flex-grow:1; margin-left: 5px;"}).appendTo(row);
var valueField = null;
var numValueField = null;
var expValueField = null;
var btwnAndLabel = null;
var btwnValueField = null;
var btwnValue2Field = null;
var typeValueField = null;
var finalspan = $('<span/>',{style:"margin-left: 5px;"}).appendTo(container);
finalspan.append(' &#8594; <span class="node-input-rule-index">'+(i+1)+'</span> ');
var caseSensitive = $('<input/>',{id:"node-input-rule-case-"+i,class:"node-input-rule-case",type:"checkbox",style:"width:auto;vertical-align:top"}).appendTo(row2);
$('<label/>',{for:"node-input-rule-case-"+i,style:"margin-left: 3px;"}).text(caseLabel).appendTo(row2);
selectField.on("change", function() {
var fieldToFocus;
var type = selectField.val();
if (valueField) { valueField.typedInput('hide'); }
if (expValueField) { expValueField.typedInput('hide'); }
if (numValueField) { numValueField.typedInput('hide'); }
if (typeValueField) { typeValueField.typedInput('hide'); }
if (btwnValueField) { btwnValueField.typedInput('hide'); }
if (btwnValue2Field) { btwnValue2Field.typedInput('hide'); }
if ((type === "btwn") || (type === "index")) {
if (!btwnValueField){
btwnValueField = createBtwnValueField(rowInputCell);
}
btwnValueField.typedInput('show');
fieldToFocus = btwnValueField;
} else if ((type === "head") || (type === "tail")) {
if (!numValueField){
numValueField = createNumValueField(rowInputCell);
}
numValueField.typedInput('show');
fieldToFocus = numValueField;
} else if (type === "jsonata_exp") {
if (!expValueField){
expValueField = createExpValueField(rowInputCell);
}
expValueField.typedInput('show');
fieldToFocus = expValueField;
} else if (type === "istype") {
if (!typeValueField){
typeValueField = createTypeValueField(rowInputCell);
}
typeValueField.typedInput('show');
fieldToFocus = typeValueField;
} else if (! (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "empty" || type === "nempty" || type === "else" )) {
if (!valueField){
valueField = createValueField(rowInputCell);
}
valueField.typedInput('show');
fieldToFocus = valueField;
}
if (type === "regex") {
row2.show();
row3.hide();
} else if ((type === "btwn") || (type === "index")) {
row2.hide();
row3.show();
if (!btwnValue2Field){
btwnValue2Field = createBtwnValue2Field(row3, andLabel);
}
btwnValue2Field.typedInput('show');
} else {
row2.hide();
row3.hide();
}
var selectedLabel = selectField.find("option:selected").text();
textSpan.text(selectedLabel);
var width = textSpan.width();
if (width <= 30) {
selectField.outerWidth(60);
} else if (width <= 85) {
selectField.outerWidth(120);
} else {
selectField.width("auto")
}
if (fieldToFocus) {
fieldToFocus.typedInput("focus");
}
// Preselect the contents of the element
// if (focusValueField && document.activeElement) {
// document.activeElement.selectionStart = 0;
// document.activeElement.selectionEnd = document.activeElement.value.length;
// }
});
selectField.val(rule.t);
if ((rule.t == "btwn") || (rule.t == "index")) {
btwnValueField = createBtwnValueField(rowInputCell,rule.vt||'num');
btwnValueField.typedInput('value',rule.v);
btwnValue2Field = createBtwnValue2Field(row3, andLabel,rule.v2t||'num');
btwnValue2Field.typedInput('value',rule.v2);
} else if ((rule.t === "head") || (rule.t === "tail")) {
numValueField = createNumValueField(rowInputCell,rule.vt||'num');
numValueField.typedInput('value',rule.v);
} else if (rule.t === "istype") {
typeValueField = createTypeValueField(rowInputCell,rule.vt);
typeValueField.typedInput('value',rule.vt);
} else if (rule.t === "jsonata_exp") {
expValueField = createExpValueField(rowInputCell,rule.vt||'jsonata');
expValueField.typedInput('value',rule.v);
} else if (typeof rule.v != "undefined") {
valueField = createValueField(rowInputCell,rule.vt||'str');
valueField.typedInput('value',rule.v);
}
caseSensitive.prop('checked',!!rule.case);
selectField.change();
var currentOutputs = JSON.parse(outputCount.val()||"{}");
currentOutputs[opt.hasOwnProperty('i')?opt.i:opt._i] = i;
outputCount.val(JSON.stringify(currentOutputs));
},
removeItem: function(opt) {
var currentOutputs = JSON.parse(outputCount.val()||"{}");
if (opt.hasOwnProperty('i')) {
currentOutputs[opt.i] = -1;
} else {
delete currentOutputs[opt._i];
}
var rules = $("#node-input-rule-container").editableList('items');
rules.each(function(i) {
$(this).find(".node-input-rule-index").html(i+1);
var data = $(this).data('data');
currentOutputs[data.hasOwnProperty('i')?data.i:data._i] = i;
});
outputCount.val(JSON.stringify(currentOutputs));
},
sortItems: function(rules) {
var currentOutputs = JSON.parse(outputCount.val()||"{}");
var rules = $("#node-input-rule-container").editableList('items');
rules.each(function(i) {
$(this).find(".node-input-rule-index").html(i+1);
var data = $(this).data('data');
currentOutputs[data.hasOwnProperty('i')?data.i:data._i] = i;
});
outputCount.val(JSON.stringify(currentOutputs));
},
sortable: true,
removable: true
});
for (var i=0;i<this.rules.length;i++) {
var rule = this.rules[i];
$("#node-input-rule-container").editableList('addItem',{r:rule,i:i});
}
},
oneditsave: function() {
var rules = $("#node-input-rule-container").editableList('items');
var node = this;
node.rules = [];
rules.each(function(i) {
node.rules.push(exportRule($(this)));
});
this.propertyType = $("#node-input-property").typedInput('type');
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-rule-container-row)");
var height = size.height;
for (var i=0;i<rows.length;i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-rule-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-rule-container").editableList('height',height);
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="switch">
<p>Weiterleitung von Nachrichten basierend auf den Werten ihrer Eigenschaften oder Position in der Sequenz.</p>
<h3>Details</h3>
<p>Bei Eingang einer Nachricht wertet der Node einstellbare Regeln aus und
leitet die Nachricht an den entsprechenden Ausgang der erfüllten Regel weiter.</p>
<p>Optional kann der Node so eingestellt werden, dass er die Auswertung nach der ersten erfüllten Regel beendet.</p>
<p>Die Regeln können anhand einer einzelnen Nachrichteneigenschaft, einer Flow- oder globalen Kontext-Eigenschaft oder
anhand dem Ergebnis eines JSONata-Ausdrucks ausgewertet werden.</p>
<h4><b>Regeln</b></h4>
<p>Es gibt vier Regeltypen:</p>
<ol>
<li><b>value rules</b>: Regeln werden hinsichtlich einer eingestellten Eigenschaft ausgewertet</li>
<li><b>sequence rules</b>: Regeln beziehen sich auf Nachrichtensequenzen,
wie sie beispielsweise durch den split-Node erzeugt werden</li>
<li>Ein <b>JSONata-Ausdruck</b> kann die gesamte Eingangsnachricht auswerten und einen <code>true</code>-Wert zurückliefern,
um eine Regelerfüllung zu signalisieren</li>
<li>Die <b>ansonsten</b>-Regel wird angewendet, wenn keine vorhergehende Regel übereinstimmt</li>
</ol>
<h4><b>Bemerkungen</b></h4>
<p>Die Regeln <code>ist true/false</code> und <code>ist null</code> führen strenge Vergleiche mit diesen Typen durch.
Sie konvertieren nicht zwischen den Typen.</p>
<p>Die Regeln <code>ist leer</code> und <code>ist nicht leer</code> können nur für Zeichenfolgen (string), Datenfelder (array) und binäre Puffer (buffer) benutzt werden,
sowie für Objekte, bei denen auf die Anzahl der Eigenschaften geprüft wird.
Die Regel ist niemals erfült, wenn die Eigenschaft einen <code>boolean</code>-, <code>null</code>- oder <code>undefined</code>-Wert hat.
<h4><b>Behandlung von Nachrichtensequenzen</b></h4>
<p>Standardmäßig ändert der Node nicht die <code>msg.parts</code>-Eigenschaft für Nachrichten, die Teil einer Sequenz sind.</p>
<p>Bei aktivierter Option <b>Nachrichtensequenzen erzeugen</b> werden Nachrichtensequenzen für jede passende Regel erzeugt.
In diesem Modus puffert der Node die gesamte eingehende Sequenz, bevor er die neuen Sequenzen weiter sendet.
Mit der Laufzeiteinstellung <code>nodeMessageBufferMaxLength</code> kann begrenzt werden,
wie viele Nachrichten im Node zwischengespeichert werden sollen.</p>
</script>
</div><div><!-- --- [red-module:node-red/change] --- -->
<script type="text/html" data-template-name="change">
<style>
ol#node-input-rule-container .red-ui-typedInput-container {
flex:1;
}
</style>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" style="width: calc(100% - 105px)" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row" style="margin-bottom:0;">
<label><i class="fa fa-list"></i> <span data-i18n="change.label.rules"></span></label>
</div>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
</div>
</script>
<script type="text/javascript">
(function() {
function isInvalidProperty(v,vt) {
if (/msg|flow|global/.test(vt)) {
if (!RED.utils.validatePropertyExpression(v)) {
return RED._("node-red:change.errors.invalid-prop", {
property: v
});
}
} else if (vt === "jsonata") {
try{ jsonata(v); } catch(e) {
return RED._("node-red:change.errors.invalid-expr", {
error: e.message
});
}
} else if (vt === "json") {
try{ JSON.parse(v); } catch(e) {
return RED._("node-red:change.errors.invalid-json-data", {
error: e.message
});
}
}
return false;
}
RED.nodes.registerType('change', {
color: "#E2D96E",
category: 'function',
defaults: {
name: {value:""},
rules:{value:[{t:"set",p:"payload",pt:"msg",to:"",tot:"str"}],validate: function(rules, opt) {
var msg;
if (!rules || rules.length === 0) { return true }
for (var i=0;i<rules.length;i++) {
var r = rules[i];
if (r.t === 'set') {
if (msg = isInvalidProperty(r.p,r.pt)) {
return msg;
}
if (msg = isInvalidProperty(r.to,r.tot)) {
return msg;
}
} else if (r.t === 'change') {
if (msg = isInvalidProperty(r.p,r.pt)) {
return msg;
}
if(msg = isInvalidProperty(r.from,r.fromt)) {
return msg;
}
if(msg = isInvalidProperty(r.to,r.tot)) {
return msg;
}
} else if (r.t === 'delete') {
if (msg = isInvalidProperty(r.p,r.pt)) {
return msg;
}
} else if (r.t === 'move') {
if (msg = isInvalidProperty(r.p,r.pt)) {
return msg;
}
if (msg = isInvalidProperty(r.to,r.tot)) {
return msg;
}
}
}
return true;
}},
// legacy
action: {value:""},
property: {value:""},
from: {value:""},
to: {value:""},
reg: {value:false}
},
inputs: 1,
outputs: 1,
icon: "swap.svg",
label: function() {
function prop2name(type, key) {
var result = RED.utils.parseContextKey(key);
return type +"." +result.key;
}
if (this.name) {
return this.name;
}
if (!this.rules) {
if (this.action === "replace") {
return this._("change.label.set",{property:"msg."+this.property});
} else if (this.action === "change") {
return this._("change.label.change",{property:"msg."+this.property});
} else if (this.action === "move") {
return this._("change.label.move",{property:"msg."+this.property});
} else {
return this._("change.label.delete",{property:"msg."+this.property});
}
} else {
if (this.rules.length == 1) {
if (this.rules[0].t === "set") {
return this._("change.label.set",{property:prop2name((this.rules[0].pt||"msg"), this.rules[0].p)});
} else if (this.rules[0].t === "change") {
return this._("change.label.change",{property:prop2name((this.rules[0].pt||"msg"), this.rules[0].p)});
} else if (this.rules[0].t === "move") {
return this._("change.label.move",{property:prop2name((this.rules[0].pt||"msg"), this.rules[0].p)});
} else {
return this._("change.label.delete",{property:prop2name((this.rules[0].pt||"msg"), this.rules[0].p)});
}
} else {
return this._("change.label.changeCount",{count:this.rules.length});
}
}
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
var set = this._("change.action.set");
var change = this._("change.action.change");
var del = this._("change.action.delete");
var move = this._("change.action.move");
var to = this._("change.action.to");
var toValueLabel = this._("change.action.toValue",to);
var search = this._("change.action.search");
var replace = this._("change.action.replace");
var regex = this._("change.label.regex");
var deepCopyLabel = this._("change.label.deepCopy");
function createPropertyValue(row2_1, row2_2, defaultType) {
var propValInput = $('<input/>',{class:"node-input-rule-property-value",type:"text"})
.appendTo(row2_1)
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
var dcLabel = $('<label style="padding-left: 130px;"></label>').appendTo(row2_2);
var deepCopy = $('<input type="checkbox" class="node-input-rule-property-deepCopy" style="width: auto; margin: 0 6px 0 0">').appendTo(dcLabel)
$('<span>').text(deepCopyLabel).appendTo(dcLabel)
propValInput.on("change", function(evt,type,val) {
row2_2.toggle(type === "msg" || type === "flow" || type === "global" || type === "env");
})
return [propValInput, deepCopy];
}
function createFromValue(row3_1, defaultType) {
return $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
.appendTo(row3_1)
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','re','num','bool','env']});
}
function createToValue(row3_2, defaultType) {
return $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
.appendTo(row3_2)
.typedInput({default:defaultType||'str',types:['msg','flow','global','str','num','bool','json','bin','env']});
}
function createMoveValue(row4, defaultType) {
return $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
.appendTo(row4)
.typedInput({default:defaultType||'msg',types:['msg','flow','global']});
}
$('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var rule = opt;
if (!rule.hasOwnProperty('t')) {
rule = {t:"set",p:"payload",to:"",tot:"str"};
}
if (rule.t === "change" && rule.re) {
rule.fromt = 're';
delete rule.re;
}
if (rule.t === "set" && !rule.tot) {
if (rule.to.indexOf("msg.") === 0 && !rule.tot) {
rule.to = rule.to.substring(4);
rule.tot = "msg";
} else {
rule.tot = "str";
}
}
if (rule.t === "move" && !rule.tot) {
rule.tot = "msg";
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
let fragment = document.createDocumentFragment();
var row1 = $('<div/>',{style:"display:flex; align-items: baseline"}).appendTo(fragment);
var row2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
var row4 = $('<div/>',{style:"display:flex;margin-top:8px;align-items: baseline"}).appendTo(fragment);
var selectField = $('<select/>',{class:"node-input-rule-type",style:"width:110px; margin-right:10px;"}).appendTo(row1);
var selectOptions = [{v:"set",l:set},{v:"change",l:change},{v:"delete",l:del},{v:"move",l:move}];
for (var i=0; i<4; i++) {
selectField.append($("<option></option>").val(selectOptions[i].v).text(selectOptions[i].l));
}
var propertyName = $('<input/>',{class:"node-input-rule-property-name",type:"text"})
.appendTo(row1)
.typedInput({types:['msg','flow','global']});
var row2_1 = $('<div/>', {style:"display:flex;align-items: baseline"}).appendTo(row2);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(toValueLabel)
.appendTo(row2_1);
var row2_2 = $('<div/>', {style:"margin-top: 4px;"}).appendTo(row2);
var row3_1 = $('<div/>', {style:"display:flex;align-items: baseline"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(search)
.appendTo(row3_1);
var row3_2 = $('<div/>',{style:"display:flex;margin-top:8px;align-items: baseline"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(replace)
.appendTo(row3_2);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(to)
.appendTo(row4);
let propertyValue = null;
let fromValue = null;
let toValue = null;
let moveValue = null;
selectField.on("change", function() {
var type = $(this).val();
if (propertyValue) {
propertyValue.typedInput('hide');
}
if (fromValue) {
fromValue.typedInput('hide');
}
if (toValue) {
toValue.typedInput('hide');
}
if (moveValue) {
moveValue.typedInput('hide');
}
if (type == "set") {
if(!propertyValue) {
var parts = createPropertyValue(row2_1, row2_2);
propertyValue = parts[0];
deepCopy = parts[1];
}
propertyValue.typedInput('show');
row2.show();
row3.hide();
row4.hide();
} else if (type == "change") {
if(!fromValue) {
fromValue = createFromValue(row3_1);
}
fromValue.typedInput('show');
if(!toValue) {
toValue = createToValue(row3_2);
}
toValue.typedInput('show');
row2.hide();
row3.show();
row4.hide();
} else if (type == "delete") {
row2.hide();
row3.hide();
row4.hide();
} else if (type == "move") {
if(!moveValue) {
moveValue = createMoveValue(row4);
}
moveValue.typedInput('show');
row2.hide();
row3.hide();
row4.show();
}
});
selectField.val(rule.t);
propertyName.typedInput('value',rule.p);
propertyName.typedInput('type',rule.pt);
if (rule.t == "set") {
var parts = createPropertyValue(row2_1, row2_2, rule.tot);
propertyValue = parts[0];
deepCopy = parts[1];
propertyValue.typedInput('value',rule.to);
deepCopy.prop("checked", !!rule.dc);
}
if (rule.t == "move") {
moveValue = createMoveValue(row4,rule.tot);
moveValue.typedInput('value',rule.to);
}
if (rule.t == "change") {
fromValue = createFromValue(row3_1, rule.fromt);
fromValue.typedInput('value',rule.from);
toValue = createToValue(row3_2,rule.tot);
toValue.typedInput('value',rule.to);
}
selectField.change();
container[0].appendChild(fragment);
},
removable: true,
sortable: true
});
if (!this.rules) {
var rule = {
t:(this.action=="replace"?"set":this.action),
p:this.property,
pt:"msg"
};
if ((rule.t === "set")||(rule.t === "move")) {
rule.to = this.to;
} else if (rule.t === "change") {
rule.from = this.from;
rule.to = this.to;
rule.re = this.reg;
}
delete this.to;
delete this.from;
delete this.reg;
delete this.action;
delete this.property;
this.rules = [rule];
}
for (var i=0; i<this.rules.length; i++) {
var rule = this.rules[i];
$("#node-input-rule-container").editableList('addItem',rule);
}
},
oneditsave: function() {
var rules = $("#node-input-rule-container").editableList('items');
var node = this;
node.rules= [];
rules.each(function(i) {
var rule = $(this);
var type = rule.find(".node-input-rule-type").val();
var r = {
t:type,
p:rule.find(".node-input-rule-property-name").typedInput('value'),
pt:rule.find(".node-input-rule-property-name").typedInput('type')
};
if (type === "set") {
r.to = rule.find(".node-input-rule-property-value").typedInput('value');
r.tot = rule.find(".node-input-rule-property-value").typedInput('type');
if (rule.find(".node-input-rule-property-deepCopy").prop("checked")) {
r.dc = true;
}
} else if (type === "move") {
r.to = rule.find(".node-input-rule-property-move-value").typedInput('value');
r.tot = rule.find(".node-input-rule-property-move-value").typedInput('type');
} else if (type === "change") {
r.from = rule.find(".node-input-rule-property-search-value").typedInput('value');
r.fromt = rule.find(".node-input-rule-property-search-value").typedInput('type');
r.to = rule.find(".node-input-rule-property-replace-value").typedInput('value');
r.tot = rule.find(".node-input-rule-property-replace-value").typedInput('type');
}
node.rules.push(r);
});
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-rule-container-row)");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-rule-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-rule-container").editableList('height',height);
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="change">
<p>Setzen, Ändern, Löschen oder Verschieben von Eigenschaften einer Nachricht, eines Flow- oder eines globalen Kontextes.</p>
<p>Im Node können mehrere Regeln definiert werden, die in vorgegebener Reihenfolge abgearbeitet werden.</p>
<h3>Details</h3>
<p>Die verfügbaren Operationen sind:</p>
<dl class="message-properties">
<dt>Setze</dt>
<dd>Setzen einer Eigenschaft.
Der Wert kann eine Vielzahl von verschiedenen Typen sein oder
von einer bestehenden Nachricht- oder einer Kontext-Eigenschaft übernommen werden.</dd>
<dt>Ändere</dt>
<dd>Suchen und Ersetzen von Teilen einer Eigenschaft.
Wenn reguläre Ausdrücke verwendet werden, kann auch durch sogenannte Capture Groups ersetzt werden, z.B. <code>$1</code>.
Beim Ersetzen wird der Typ nur geändert, wenn eine vollständige Übereinstimmung vorliegt.</dd>
<dt>Lösche</dt>
<dd>Löschen einer Eigenschaft.</dd>
<dt>Verschiebe</dt>
<dd>Verschieben oder umbenennen einer Eigenschaft.</dd>
</dl>
<!-- <p>Der Typ "expression" verwendet die Abfrage- und Ausdruckssprache <a href="http://jsonata.org/" target="_new">JSONata</a>.</p> -->
<!-- was ist mit "expression" gemeint?!? vermutlich nicht mehr aktuell -->
</script>
</div><div><!-- --- [red-module:node-red/range] --- -->
<script type="text/html" data-template-name="range">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:calc(70% - 1px)"/>
</div>
<div class="form-row">
<label for="node-input-action"><i class="fa fa-dot-circle-o"></i> <span data-i18n="range.label.action"></span></label>
<select id="node-input-action" style="width:70%;">
<option value="scale" data-i18n="range.scale.payload"></option>
<option value="clamp" data-i18n="range.scale.limit"></option>
<option value="roll" data-i18n="range.scale.wrap"></option>
</select>
</div>
<br/>
<div class="form-row"><i class="fa fa-sign-in"></i> <span data-i18n="range.label.inputrange"></span>:</div>
<div class="form-row"><label></label>
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minin" data-i18n="[placeholder]range.placeholder.min" style="width:100px;"/>
&nbsp;&nbsp;<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxin" data-i18n="[placeholder]range.placeholder.maxin" style="width:100px;"/>
</div>
<div class="form-row"><i class="fa fa-sign-out"></i> <span data-i18n="range.label.resultrange"></span>:</div>
<div class="form-row"><label></label>
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minout" data-i18n="[placeholder]range.placeholder.min" style="width:100px;"/>
&nbsp;&nbsp;<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxout" data-i18n="[placeholder]range.placeholder.maxout" style="width:100px;"/>
</div>
<br/>
<div class="form-row"><label></label>
<input type="checkbox" id="node-input-round" style="display: inline-block; width: auto; vertical-align: top;">
<label style="width: auto;" for="node-input-round"><span data-i18n="range.label.roundresult"></span></label></input>
</div>
<br/>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips" id="node-tip"><span data-i18n="range.tip"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('range', {
color: "#E2D96E",
category: 'function',
defaults: {
minin: {value:"", required: true,
label:RED._("node-red:range.label.minin"),
validate:RED.validators.number(false)},
maxin: {value:"", required: true,
label:RED._("node-red:range.label.maxin"),
validate:RED.validators.number(false)},
minout: {value:"", required:true,
label:RED._("node-red:range.label.minout"),
validate:RED.validators.number(false)},
maxout: {value:"", required:true,
label:RED._("node-red:range.label.maxout"),
validate:RED.validators.number(false)},
action: {value:"scale"},
round: {value:false},
property: {value:"payload",required:true,
label:RED._("node-red:common.label.property")},
name: {value:""}
},
inputs: 1,
outputs: 1,
icon: "range.svg",
label: function() {
if (this.minout !== "" && this.maxout !== "") { return this.name||this.minout + " - " + this.maxout; }
else { return this.name||this._("range.range"); }
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="range">
<p>Umskalierung eines Zahlenwertes auf einen anderen Wertebereich.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">number</span></dt>
<dd>Der Payload <i>muss</i> eine Zahl sein.
Alles andere wird versucht als Zahl interpretiert zu werden und bei Fehlschlag abgelehnt.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">number</span></dt>
<dd>Der auf den neuen Wertebereich umgerechnete Zahlenwert.</dd>
</dl>
<h3>Details</h3>
<p>Dieser Node skaliert den empfangenen Wert linear.
Standardmäßig ist das Ergebnis nicht auf Ausgangswertebereich beschränkt.</p>
<p><i>Skalierung und Begrenzung</i> bedeutet,
dass das Ergebnis niemals außerhalb des Ausgangswertebereich liegt.</p>
<p><i>Skalieren und Begrenzung mit Überlauf</i> bedeutet,
dass das Ergebnis in den Ausgangswertebereich <i>über- bzw. umlaufend gepackt</i> wird.</p>
<p>Beispiel einer Skalierung vom Eingangswerterbereich 0-10 auf Ausgangswertebereich 0-100:</p>
<table style="outline-width:#888 solid thin">
<tr><th width="260px">Modus</th><th width="110px">Eingangswert</th><th width="110px">Ausgangswert</th></tr>
<tr><td><center>Skalieren</center></td><td><center>12</center></td><td><center>120</center></td></tr>
<tr><td><center>Skalieren und begrenzen</center></td><td><center>12</center></td><td><center>100</center></td></tr>
<tr><td><center>Skalieren und begrenzen mit Überlauf</center></td><td><center>12</center></td><td><center>20</center></td></tr>
</table>
</script>
</div><div><!-- --- [red-module:node-red/template] --- -->
<script type="text/html" data-template-name="template">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
</div>
<div class="form-row">
<label for="node-input-field"><i class="fa fa-ellipsis-h"></i> <span data-i18n="template.label.property"></span></label>
<input type="text" id="node-input-field" placeholder="payload" style="width:250px;">
<input type="hidden" id="node-input-fieldType">
</div>
<div class="form-row" style="position: relative; margin-bottom: 0px;">
<label for="node-input-template"><i class="fa fa-file-code-o"></i> <span data-i18n="template.label.template"></span></label>
<input type="hidden" id="node-input-template" autofocus="autofocus">
<div style="position: absolute; right:0;display:inline-block; text-align: right; font-size: 0.8em;">
<span data-i18n="template.label.format"></span>:
<select id="node-input-format" style="width:110px; font-size: 10px !important; height: 24px; padding:0;">
<option value="handlebars">mustache</option>
<option value="html">HTML</option>
<option value="json">JSON</option>
<option value="javascript">JavaScript</option>
<option value="css">CSS</option>
<option value="markdown">Markdown</option>
<option value="python">Python</option>
<option value="sql">SQL</option>
<option value="yaml">YAML</option>
<option value="text" data-i18n="template.label.none"></option>
</select>
<button id="node-template-expand-editor" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button>
</div>
</div>
<div class="form-row node-text-editor-row">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-template-editor" ></div>
</div>
<div class="form-row">
<label for="node-input-syntax"><i class="fa fa-code"></i> <span data-i18n="template.label.syntax"></span></label>
<select id="node-input-syntax" style="width:180px;">
<option value="mustache" data-i18n="template.label.mustache"></option>
<option value="plain" data-i18n="template.label.plain"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-output"><i class="fa fa-long-arrow-right"></i> <span data-i18n="template.label.output"></span></label>
<select id="node-input-output" style="width:180px;">
<option value="str" data-i18n="template.label.plain"></option>
<option value="json" data-i18n="template.label.json"></option>
<option value="yaml" data-i18n="template.label.yaml"></option>
</select>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('template',{
color:"rgb(243, 181, 103)",
category: 'function',
defaults: {
name: {value:""},
field: {value:"payload",
label:"payload",
validate:RED.validators.typedInput("fieldType", false)},
fieldType: {value:"msg"},
format: {value:"handlebars"},
syntax: {value:"mustache"},
template: {value:"This is the payload: {{payload}} !"},
output: {value:"str"}
},
inputs:1,
outputs:1,
icon: "template.svg",
label: function() {
return this.name||this._("template.template");;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
const that = this;
const stateId = RED.editor.generateViewStateId("node", this, "");
if (!this.field) {
this.field = 'payload';
$("#node-input-field").val("payload");
}
if (!this.fieldType) {
this.fieldType = 'msg';
}
if (!this.syntax) {
this.syntax = 'mustache';
$("#node-input-syntax").val(this.syntax);
}
$("#node-input-field").typedInput({
default: 'msg',
types: ['msg','flow','global'],
typeField: $("#node-input-fieldType")
});
this.editor = RED.editor.createEditor({
id: 'node-input-template-editor',
mode: 'ace/mode/html',
stateId: stateId,
value: $("#node-input-template").val()
});
RED.library.create({
url:"templates", // where to get the data from
type:"template", // the type of object the library is for
editor:that.editor, // the field name the main text body goes to
fields:['name','format','output','syntax'],
ext: "txt"
});
$("#node-input-format").on("change", function() {
var mod = "ace/mode/"+$("#node-input-format").val();
that.editor.getSession().setMode({
path: mod,
v: Date.now()
});
});
RED.popover.tooltip($("#node-template-expand-editor"), RED._("node-red:common.label.expand"));
$("#node-template-expand-editor").on("click", function (e) {
e.preventDefault();
const value = that.editor.getValue();
that.editor.saveView();
RED.editor.editText({
mode: $("#node-input-format").val(),
value: value,
stateId: stateId,
width: "Infinity",
focus: true,
complete: function (v, cursor) {
that.editor.setValue(v, -1);
setTimeout(function () {
that.editor.restoreView();
that.editor.focus();
}, 250);
}
})
})
},
oneditsave: function() {
$("#node-input-template").val(this.editor.getValue());
this.editor.destroy();
delete this.editor;
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
this.editor.resize();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="template">
<p>Festlegen einer Eigenschaft anhand einer Vorlage (template).</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">object</span></dt>
<dd>msg-Objekt mit Informationen zum Befüllen der Vorlage.</dd>
<dt class="optional">template <span class="property-type">string</span></dt>
<dd>Mit msg.payload zu befüllende Vorlage.
Falls nicht im Editorfenster angegeben, kann die Vorlage auch als Eigenschaft von msg vorgegeben werden.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">object</span></dt>
<dd>Nachricht auf Basis der Vorlage und gefüllt mit Eigenschaften aus der eingehenden Nachricht.</dd>
</dl>
<h3>Details</h3>
<p>Die Vorlage verwendet standardmäßig das
<a href="http://mustache.github.io/mustache.5.html" target="_blank">Mustache</a>-Format,
was aber bei Bedarf ausgeschaltet werden kann.</p>
<p>Beispiel: Wenn die Vorlage</p>
<pre>Hallo {{payload.name}}. Heute ist {{date}}</pre>
<p>die Nachricht</p>
<pre>
{
date: "Montag",
payload: {
name: "Fred"
}
}
</pre>
<p>empfängt, wird die resultierende Ausgangsnachricht wie folgt sein:</p>
<pre>Hallo Fred. Heute ist Montag</pre>
<p>Es ist möglich, eine Eigenschaft aus dem Flowkontext oder dem globalen Kontext zu verwenden,
indem <code>{{flow.name}}</code> oder <code>{{global.name}}</code> verwendet wird.
Oder für den persistenten Speicher <code>store</code> kann <code>{{flow[store].name}}</code> oder
<code>{{global[store].name}}</code> verwendet werden.
<p><b>Hinweis</b>: Standardmäßig werden bei <i>Mustache</i> sog. <i>Escaper</i>
bei allen nicht-numerischen und HTML-Entitäten erzeugt.
Z.B. <code>&</code> wird durch <code>&amp;amp;</code> ersetzt.
Um dies zu verhindern, müssen <code>{{{dreifache}}}</code> Klammern verwendet werden.
</script>
</div><div><!-- --- [red-module:node-red/delay] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="delay">
<div class="form-row">
<label for="node-input-delay-action"><i class="fa fa-tasks"></i> <span data-i18n="delay.action"></span></label>
<select id="node-input-delay-action" style="width:270px !important">
<option value="delay" data-i18n="delay.delaymsg"></option>
<option value="rate" data-i18n="delay.limitrate"></option>
</select>
</div>
<div id="delay-details">
<div class="form-row">
<label></label>
<select id="node-input-delay-type" style="width:270px !important">
<option value="delay" data-i18n="delay.delayfixed"></option>
<option value="random" data-i18n="delay.randomdelay"></option>
<option value="delayv" data-i18n="delay.delayvarmsg"></option>
</select>
</div>
<div class="form-row" id="delay-details-for">
<label for="node-input-timeout"><i class="fa fa-clock-o"></i> <span data-i18n="delay.for"></span></label>
<input type="text" id="node-input-timeout" style="text-align:end; width:50px !important">
<select id="node-input-timeoutUnits" style="width:200px !important">
<option value="milliseconds" data-i18n="delay.milisecs"></option>
<option value="seconds" data-i18n="delay.secs"></option>
<option value="minutes" data-i18n="delay.mins"></option>
<option value="hours" data-i18n="delay.hours"></option>
<option value="days" data-i18n="delay.days"></option>
</select>
</div>
<div id="random-details" class="form-row">
<label for="node-input-randomFirst"><i class="fa fa-clock-o"></i> <span data-i18n="delay.between"></span></label>
<input type="text" id="node-input-randomFirst" placeholder="" style="text-align:end; width:50px !important">
&nbsp;<span data-i18n="delay.and"></span>&nbsp;
<input type="text" id="node-input-randomLast" placeholder="" style="text-align:end; width:50px !important">
<select id="node-input-randomUnits" style="width:140px !important">
<option value="milliseconds" data-i18n="delay.milisecs"></option>
<option value="seconds" data-i18n="delay.secs"></option>
<option value="minutes" data-i18n="delay.mins"></option>
<option value="hours" data-i18n="delay.hours"></option>
<option value="days" data-i18n="delay.days"></option>
</select>
</div>
</div>
<div id="rate-details">
<div class="form-row">
<label></label>
<select id="node-input-rate-type" style="width:270px !important">
<option value="all" data-i18n="delay.limitall"></option>
<option value="topic" data-i18n="delay.limittopic"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-rate"><i class="fa fa-clock-o"></i> <span data-i18n="delay.rate"></span></label>
<input type="text" id="node-input-rate" placeholder="1" style="text-align:end; width:40px !important">
<label for="node-input-rateUnits"><span data-i18n="delay.msgper"></span></label>
<input type="text" id="node-input-nbRateUnits" placeholder="1" style="text-align:end; width:40px !important">
<select id="node-input-rateUnits" style="width:90px !important">
<option value="second" data-i18n="delay.label.units.second.singular"></option>
<option value="minute" data-i18n="delay.label.units.minute.singular"></option>
<option value="hour" data-i18n="delay.label.units.hour.singular"></option>
<option value="day" data-i18n="delay.label.units.day.singular"></option>
</select>
</div>
<div class="form-row" id="rate-override" style="display: flex; align-items: center">
<label></label><input style="width:30px; margin:0" type="checkbox" id="node-input-allowrate"><label style="margin:0;width: auto;" for="node-input-allowrate" data-i18n="delay.allowrate"></label>
</div>
<div class="form-row" id="rate-details-drop">
<input type="hidden" id="node-input-outputs" value="1">
<label></label>
<select id="node-input-drop-select" style="width: 70%">
<option id="node-input-drop-select-queue" value="queue" data-i18n="delay.queuemsg"></option>
<option value="drop" data-i18n="delay.dropmsg"></option>
<option value="emit" data-i18n="delay.sendmsg"></option>
</select>
</div>
<div class="form-row" id="rate-details-per-topic">
<label></label>
<select id="node-input-rate-topic-type" style="width:270px !important">
<option value="queue" data-i18n="delay.fairqueue"></option>
<option value="timed" data-i18n="delay.timedqueue"></option>
</select>
</div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('delay',{
category: 'function',
color:"#E6E0F8",
defaults: {
name: {value:""},
pauseType: {value:"delay", required:true},
timeout: {
value:"5", required:true,
label:RED._("node-red:delay.label.delay"),
validate:function(v,opt) {
if (RED.validators.number(v) && (v >= 0)) {
return true;
}
return RED._("node-red:delay.errors.invalid-timeout");
}},
timeoutUnits: {value:"seconds"},
rate: {
value:"1",
required:true,
label:RED._("node-red:delay.label.rate"),
validate:function(v,opt) {
if (RED.validators.number(v) && (v >= 0)) {
return true;
}
return RED._("node-red:delay.errors.invalid-rate");
}
},
nbRateUnits: {
value:"1",
required:false,
validate:function(v,opt) {
if (v === undefined || (RED.validators.number(v) && (v >= 0))) {
return true;
}
return RED._("node-red:delay.errors.invalid-rate-unit");
}
},
rateUnits: {value: "second"},
randomFirst: {
value:"1", required:true,
validate:function(v,opt) {
if (RED.validators.number(v) && (v >= 0)) {
return true;
}
return RED._("node-red:delay.errors.invalid-random-first");
}},
randomLast: {
value:"5", required:true,
validate:function(v,opt) {
if (RED.validators.number(v) && (v >= 0)) {
return true;
}
return RED._("node-red:delay.errors.invalid-random-last");
}},
randomUnits: {value: "seconds"},
drop: {value:false},
allowrate: {value:false},
outputs: { value: 1},
},
inputs:1,
outputs:1,
icon: "timer.svg",
label: function() {
if (this.name) {
return this.name;
}
if (this.pauseType == "delayv") {
return this._("delay.label.variable");
} else if (this.pauseType == "delay") {
var units = this.timeoutUnits ? this.timeoutUnits.charAt(0) : "s";
if (this.timeoutUnits == "milliseconds") { units = "ms"; }
return this._("delay.label.delay")+" "+this.timeout+units;
} else if (this.pauseType == "random") {
return this._("delay.label.random");
} else {
var rate = this.rate+" msg/"+(this.rateUnits ? (this.nbRateUnits > 1 ? this.nbRateUnits : '') + this.rateUnits.charAt(0) : "s");
if (this.pauseType == "rate") {
return this._("delay.label.limit")+" "+rate;
} else if (this.pauseType == "timed") {
return this._("delay.label.limitTopic")+" "+rate;
} else {
return this._("delay.label.limitTopic")+" "+rate;
}
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
$( "#node-input-timeout" ).spinner({min:1});
$( "#node-input-rate" ).spinner({min:1});
$( "#node-input-nbRateUnits" ).spinner({min:1});
$( "#node-input-randomFirst" ).spinner({min:0});
$( "#node-input-randomLast" ).spinner({min:1});
$('.ui-spinner-button').on("click", function() {
$(this).siblings('input').trigger("change");
});
$( "#node-input-nbRateUnits" ).on('change keyup', function() {
var $this = $(this);
var val = parseInt($this.val());
var type = "singular";
if (val > 1) {
type = "plural";
}
if ($this.attr("data-type") == type) {
return;
}
$this.attr("data-type", type);
$("#node-input-rateUnits option").each(function () {
var $option = $(this);
var key = "delay.label.units." + $option.val() + "." + type;
$option.attr('data-i18n', 'node-red:' + key);
$option.html(node._(key));
});
});
if (this.pauseType == "delay") {
$("#node-input-delay-action").val('delay');
$("#node-input-delay-type").val('delay');
} else if (this.pauseType == "delayv") {
$("#node-input-delay-action").val('delay');
$("#node-input-delay-type").val('delayv');
} else if (this.pauseType == "random") {
$("#node-input-delay-action").val('delay');
$("#node-input-delay-type").val('random');
} else if (this.pauseType == "rate") {
$("#node-input-delay-action").val('rate');
$("#node-input-rate-type").val('all');
} else if (this.pauseType == "queue") {
$("#node-input-delay-action").val('rate');
$("#node-input-rate-type").val('topic');
$("#node-input-rate-topic-type").val('queue');
} else if (this.pauseType == "timed") {
$("#node-input-delay-action").val('rate');
$("#node-input-rate-type").val('topic');
$("#node-input-rate-topic-type").val('timed');
}
if (!this.timeoutUnits) {
$("#node-input-timeoutUnits option").filter(function() {
return $(this).val() == 'seconds';
}).attr('selected', true);
}
if (!this.randomUnits) {
$("#node-input-randomUnits option").filter(function() {
return $(this).val() == 'seconds';
}).attr('selected', true);
}
$("#node-input-delay-action").on("change",function() {
if (this.value === "delay") {
$("#delay-details").show();
$("#rate-details").hide();
} else if (this.value === "rate") {
$("#delay-details").hide();
$("#rate-details").show();
}
}).trigger("change");
$("#node-input-delay-type").on("change", function() {
if (this.value === "delay") {
$("#delay-details-for").show();
$("#random-details").hide();
} else if (this.value === "delayv") {
$("#delay-details-for").show();
$("#random-details").hide();
} else if (this.value === "random") {
$("#delay-details-for").hide();
$("#random-details").show();
}
}).trigger("change");
if (this.outputs === 2) {
$("#node-input-drop-select").val("emit");
} else if (this.drop) {
$("#node-input-drop-select").val("drop");
} else {
$("#node-input-drop-select").val("queue");
}
$("#node-input-rate-type").on("change", function() {
if (this.value === "all") {
$("#rate-details-per-topic").hide();
$("#node-input-drop-select-queue").attr('disabled', false);
} else if (this.value === "topic") {
if ($("#node-input-drop-select").val() === "queue") {
$("#node-input-drop-select").val("drop");
}
$("#node-input-drop-select-queue").attr('disabled', true);
$("#rate-details-per-topic").show();
}
}).trigger("change");
},
oneditsave: function() {
var action = $("#node-input-delay-action").val();
if (action === "delay") {
this.pauseType = $("#node-input-delay-type").val();
$("#node-input-outputs").val(1);
} else if (action === "rate") {
action = $("#node-input-rate-type").val();
if (action === "all") {
this.pauseType = "rate";
} else {
this.pauseType = $("#node-input-rate-topic-type").val();
}
var dropType = $("#node-input-drop-select").val();
this.drop = dropType !== "queue";
$("#node-input-outputs").val(dropType === "emit"?2:1);
}
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="delay">
<p>Verzögerung von Nachrichten oder Begrenzung ihrer Durchlaufrate.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">number</span></dt>
<dd>Legt die Verzögerung in Millisekunden fest, die auf die Nachricht angewendet werden soll.
Zur Nutzung dieser Option muss <i>Verzög. mit msg.delay überschreibbar</i> aktiviert sein.</dd>
<dt class="optional">reset</dt>
<dd>Wenn bei der empfangenen Nachricht diese Eigenschaft auf einen beliebigen Wert gesetzt ist,
werden alle im Node gepufferten Nachrichten gelöscht.</dd>
<dt class="optional">flush</dt>
<dd>Wenn bei der empfangenen Nachricht diese Eigenschaft auf einen beliebigen Wert gesetzt ist,
werden alle im Node gepufferten Nachrichten sofort gesendet.</dd>
</dl>
<h3>Details</h3>
<p>Wenn Verzögerung als Nachrichtenaktion eingestellt ist, kann die Verzögerungszeit ein fixer Wert,
ein Zufallswert innerhalb eines Bereichs oder ein für jede Nachricht dynamisch vorgebbarer Wert handeln.</p>
<p>Bei Begrenzung auf Nachrichtenrate werden die Nachrichten über den eingestellten Zeitraum verteilt.
Der Status zeigt die Anzahl der sich aktuell in der Warteschlange befindlichen Nachrichten an.
Zwischenzeitlich eintreffende Nachrichten können optional beim Eintreffen verworfen werden.</p>
<p>Die Ratenbegrenzung kann auf alle Nachrichten angewendet werden oder
die Nachrichten werden anhand des <code>msg.topic</code>-Wertes gruppiert.
Bei der Gruppierung werden zwischenzeitlich eintreffende Nachrichten automatisch gelöscht.
In jedem Zeitintervall werden die neuesten Nachricht entweder für alle oder
für das nächste Thema (Topic) in der Reihe gesendet.</p>
</script>
</div><div><!-- --- [red-module:node-red/trigger] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="trigger">
<div class="form-row">
<label data-i18n="trigger.send" for="node-input-op1"></label>
<input type="hidden" id="node-input-op1type">
<input style="width:70%" type="text" id="node-input-op1" placeholder="1">
</div>
<div class="form-row">
<label data-i18n="trigger.then"></label>
<select id="node-then-type" style="width:70%;">
<option value="block" data-i18n="trigger.wait-reset"></option>
<option value="wait" data-i18n="trigger.wait-for"></option>
<option value="loop" data-i18n="trigger.wait-loop"></option>
</select>
</div>
<div class="form-row node-type-duration">
<label></label>
<input type="text" id="node-input-duration" style="text-align:end; width:70px !important">
<select id="node-input-units" style="width:140px !important">
<option value="ms" data-i18n="trigger.duration.ms"></option>
<option value="s" data-i18n="trigger.duration.s"></option>
<option value="min" data-i18n="trigger.duration.m"></option>
<option value="hr" data-i18n="trigger.duration.h"></option>
</select>
</div>
<div class="form-row node-type-wait">
<label></label>
<input type="checkbox" id="node-input-extend" style="margin-left:0px; vertical-align:top; width:auto !important;"> <label style="width:auto !important;" for="node-input-extend" data-i18n="trigger.extend"></label>
</div>
<div class="form-row node-type-override">
<label></label>
<input type="checkbox" id="node-input-overrideDelay" style="margin-left:0px; vertical-align:top; width:auto !important;"> <label style="width:auto !important;" for="node-input-overrideDelay" data-i18n="trigger.override"></label>
</div>
<div class="form-row node-type-wait">
<label data-i18n="trigger.then-send"></label>
<input type="hidden" id="node-input-op2type">
<input style="width:70%" type="text" id="node-input-op2" placeholder="0">
</div>
<div class="form-row" id="node-second-output">
<label></label>
<input type="checkbox" id="node-input-second" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;" for="node-input-second" data-i18n="trigger.second"></label>
</div>
<div class="form-row">
<label data-i18n="trigger.label.reset" style="width:auto"></label>
<div style="display:inline-block; width:70%;vertical-align:top">
<ul>
<li data-i18n="trigger.label.resetMessage"></li>
<li><span data-i18n="trigger.label.resetPayload"></span> <input type="text" id="node-input-reset" style="width:150px" data-i18n="[placeholder]trigger.label.resetprompt"></li>
</ul>
</div>
<br/>
<div class="form-row">
<label data-i18n="trigger.for" for="node-input-bytopic"></label>
<select id="node-input-bytopic" style="width:120px;">
<option value="all" data-i18n="trigger.alltopics"></option>
<option value="topic" data-i18n="trigger.bytopics"></option>
</select>
<span class="form-row" id="node-stream-topic">
<input type="text" id="node-input-topic" style="width:46%;"/>
</span>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></input>
<input type="hidden" id="node-input-outputs" value="1">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('trigger',{
category: 'function',
color:"#E6E0F8",
defaults: {
name: {value:""},
op1: {value:"1",
label: RED._("node-red:trigger.send"),
validate: RED.validators.typedInput("op1type", false)},
op2: {value:"0",
label: RED._("node-red:trigger.then-send"),
validate: RED.validators.typedInput("op2type", false)},
op1type: {value:"val"},
op2type: {value:"val"},
duration: {
value:"250", required:true,
label:RED._("node-red:trigger.label.duration"),
validate:RED.validators.number(false)},
extend: {value:"false"},
overrideDelay: {value:"false"},
units: {value:"ms"},
reset: {value:""},
bytopic: {value:"all"},
topic: {value:"topic", required:true,
label:RED._("node-red:trigger.label.topic")},
outputs: {value:1}
},
inputs:1,
outputs:1,
icon: "trigger.svg",
label: function() {
if (this.duration > 0) {
return this.name|| this._("trigger.label.trigger")+" "+this.duration+this.units;
}
if (this.duration < 0) {
return this.name|| this._("trigger.label.trigger-loop")+" "+(this.duration * -1)+this.units;
}
else {
return this.name|| this._("trigger.label.trigger-block");
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var that = this;
if (this.topic === undefined) { $("#node-input-topic").val("topic"); }
$("#node-input-topic").typedInput({default:'msg',types:['msg']});
$("#node-input-bytopic").on("change", function() {
if ($("#node-input-bytopic").val() === "all") {
$("#node-stream-topic").hide();
} else {
$("#node-stream-topic").show();
}
});
if (this.outputs == 2) { $("#node-input-second").prop('checked', true) }
else { $("#node-input-second").prop('checked', false) }
$("#node-input-second").change(function() {
if ($("#node-input-second").is(":checked")) {
$("#node-input-outputs").val(2);
}
else {
$("#node-input-outputs").val(1);
}
});
$("#node-then-type").on("change", function() {
if ($(this).val() == "block") {
$(".node-type-wait").hide();
$(".node-type-override").hide();
$(".node-type-duration").hide();
$("#node-second-output").hide();
$("#node-input-second").prop('checked', false);
$("#node-input-outputs").val(1);
}
else if ($(this).val() == "loop") {
if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); }
$(".node-type-wait").hide();
$(".node-type-override").show();
$(".node-type-duration").show();
$("#node-second-output").hide();
$("#node-input-second").prop('checked', false);
$("#node-input-outputs").val(1);
} else {
if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); }
$(".node-type-wait").show();
$(".node-type-override").show();
$(".node-type-duration").show();
$("#node-second-output").show();
}
});
if (this.op1type === 'val') {
$("#node-input-op1type").val('str');
}
if (this.op2type === 'val') {
$("#node-input-op2type").val('str');
}
var optionNothing = {value:"nul",label:this._("trigger.output.nothing"),hasValue:false};
var optionPayload = {value:"pay",label:this._("trigger.output.existing"),hasValue:false};
var optionOriginalPayload = {value:"pay",label:this._("trigger.output.original"),hasValue:false};
var optionLatestPayload = {value:"payl",label:this._("trigger.output.latest"),hasValue:false};
$("#node-input-op1").typedInput({
default: 'str',
typeField: $("#node-input-op1type"),
types:['flow','global','str','num','bool','json','bin','date','env',
optionPayload,
optionNothing
]
});
$("#node-input-op2").typedInput({
default: 'str',
typeField: $("#node-input-op2type"),
types:['flow','global','str','num','bool','json','bin','date','env',
optionOriginalPayload,
optionLatestPayload,
optionNothing
]
});
if (this.bytopic === undefined) {
$("#node-input-bytopic").val("all");
}
if (this.duration == "0") {
$("#node-then-type").val("block");
}
else if ((this.duration * 1) < 0) {
$("#node-then-type").val("loop");
$("#node-input-duration").val(this.duration*-1);
} else {
$("#node-then-type").val("wait");
}
$("#node-then-type").trigger("change");
if (this.extend === "true" || this.extend === true) {
$("#node-input-extend").prop("checked",true);
} else {
$("#node-input-extend").prop("checked",false);
}
if (this.overrideDelay === "true" || this.overrideDelay === true) {
$("#node-input-overrideDelay").prop("checked",true);
} else {
$("#node-input-overrideDelay").prop("checked",false);
}
},
oneditsave: function() {
if ($("#node-then-type").val() == "block") {
$("#node-input-duration").val("0");
}
if ($("#node-then-type").val() == "loop") {
$("#node-input-duration").val($("#node-input-duration").val() * -1);
}
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="trigger">
<p>Senden einer und optional einer weiteren verzögerten Nachricht bei Auslösung (Trigger),
sofern der Trigger nicht verlängert oder zurückgesetzt wird.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">number</span></dt>
<dd>Legt die Verzögerung in Millisekunden fest, die auf die Nachricht angewendet werden soll.
Zur Nutzung dieser Funktion muss die Option <i>Verzögerung mit msg.delay überschreibbar</i> aktiviert sein.</dd>
<dt class="optional">reset</dt>
<dd>Bei Empfang einer Nachricht mit dieser Eigenschaft wird jede Verzögerung oder Wiederholung
rückgesetzt und keine weitere Nachricht gesendet.</dd>
</dl>
<h3>Details</h3>
<p>Dieser Node kann verwendet werden, um ein Zeitlimit in einem Flow zu erstellen.
Bei Empfang einer Nachricht wird standardmäßig eine Nachricht mit einem <code>payload</code> von <code>1</code> versendet.
Optional wird nach einer einstellbaren Wartezeit (standardmäßig 250 ms) eine zweite Nachricht
mit einem <code>payload</code> von <code>0</code> sendet.
Dies kann beispielsweise zum Blinken einer LED verwendet werden, die an einen GPIO-Pin des Raspberry Pi angeschlossen ist.</p>
<p>Als Nutzdaten (Payload) jeder zu sendenen Nachricht können eine Vielzahl von Werten eingestellt werden inklusive der Option,
überhaupt nicht zu senden.
Wenn beispielsweise die erste Ausgnagsnachricht auf <i>nichts</i> gesetzt und die Option
<i>Verzögerung verlängern bei Eingang neuer Nachrichten</i> aktiviert ist,
agiert der Node als Überwachungszeitgeber (Watchdog-Timer).
Er sendet hier nur dann eine Nachricht, wenn innerhalb der eingestellten Verzögerungszeit keine Nachricht empfangen wird.</p>
<p>Beim Nachrichtentyp <i>Zeichenfolge (string)</i> werden auch <a href="http://mustache.github.io/mustache.5.html" target="_blank">Mustache</a>-Vorlagen unterstützt.</p>
<p>Wenn eine Nachricht mit der <code>reset</code> oder <code>payload</code>-Eigenschaft gleich dem konfigurierten Wert empfangen wird,
wird eine laufende Verzögerung oder Wiederholung rückgesetzt und keine Nachricht gesendet.</p>
<p>Der Node kann auch so eingestellt werden, dass er eine Nachricht normal in den vorgegebenen Intervallen sendet,
bis er durch eine empfangene Nachricht rückgesetzt wird.</p>
<p>Außerdem kann der Node auch so eingestellt werden, dass er Nachrichten anhand einer einstellbaren <code>msg</code>-Eigenschaft
als separate Nachrichtenströme behandelt.</p>
<p>Der Status zeigt die Aktivität des Nodes an.
Bei Verwendung mehrerer Nachrichtenströme zeigt der Status deren aktuelle Anzahl an.</p>
</script>
</div><div><!-- --- [red-module:node-red/exec] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="exec">
<div class="form-row">
<label for="node-input-command"><i class="fa fa-file"></i> <span data-i18n="exec.label.command"></span></label>
<input type="text" id="node-input-command" data-i18n="[placeholder]exec.label.command">
</div>
<div class="form-row">
<label><i class="fa fa-plus"></i> <span data-i18n="exec.label.append"></span></label>
<input type="checkbox" id="node-input-addpay-cb" style="display:inline-block; width:auto;">
<input type="text" id="node-input-addpay" style="margin-left: 5px; width:160px;">
</div>
<div class="form-row">
<label for="node-input-append"> </label>
<input type="text" id="node-input-append" data-i18n="[placeholder]exec.placeholder.extraparams">
</div>
<div class="form-row">
<label><i class="fa fa-sign-out"></i> <span data-i18n="exec.label.return"></span></label>
<select type="text" id="node-input-useSpawn" style="width:70%">
<option value="false" data-i18n="exec.opt.exec"></option>
<option value="true" data-i18n="exec.opt.spawn"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-timer"><i class="fa fa-clock-o"></i> <span data-i18n="exec.label.timeout"></span></label>
<input type="text" id="node-input-timer" style="width:65px;" data-i18n="[placeholder]exec.label.timeoutplace">
<span data-i18n="exec.label.seconds"></span>
</div>
<div class="form-row">
<label for="node-input-winHide" style="width: auto !important; padding-right:10px"><i class="fa fa-windows"></i> <span data-i18n="exec.label.winHide"></span></label>
<input type="checkbox" id="node-input-winHide" style="margin-top: 0; display:inline-block; width:auto;">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('exec',{
category: 'function',
color:"darksalmon",
defaults: {
command: {value:""},
addpay: {value:""},
append: {value:""},
useSpawn: {value:"false"},
timer: {value:""},
winHide: {value:false},
oldrc: {value:false},
name: {value:""}
},
inputs:1,
outputs:3,
outputLabels: function(i) {
return [
this._("exec.label.stdout"),
this._("exec.label.stderr"),
this._("exec.label.retcode")
][i];
},
icon: "cog.svg",
label: function() {
return this.name||this.command.replace(/\\n /g,"\\\\n ")||(this.useSpawn=="true"?this._("exec.spawn"):this._("exec.exec"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if ($("#node-input-useSpawn").val() === null) {
$("#node-input-useSpawn").val(this.useSpawn.toString());
}
$("#node-input-addpay-cb").prop("checked", this.addpay === true || (this.addpay !== false && this.addpay !== ""))
var addpayValue = (this.addpay === true)?"payload":((this.addpay === false || this.addpay === "")?"payload":this.addpay);
$("#node-input-addpay-cb").on("change", function(evt) {
$("#node-input-addpay").typedInput("disable",!$("#node-input-addpay-cb").prop("checked"));
});
$("#node-input-addpay").val(addpayValue);
$("#node-input-addpay").typedInput({
default: "msg",
types: ["msg"]
});
$("#node-input-addpay-cb").trigger("change")
if (this.winHide === "true" || this.winHide === true) {
$("#node-input-winHide").prop("checked",true);
} else {
$("#node-input-winHide").prop("checked",false);
}
},
oneditsave: function() {
if (!$("#node-input-addpay-cb").prop("checked")) {
$("#node-input-addpay").val("");
}
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="exec">
<p>Ausführung eines Systembefehls und Rückgabe seiner Ausgabe.</p>
<p>Der Node kann so eingestellt werden, dass er entweder bis zum Befehlabschluss wartet (exec) oder
die Ausgabe sogleich sendet (spawn), wie der Befehl sie generiert.</p>
<p>Der auszuführende Befehl kann im Node eingestellt und/oder
über die empfangene Nachricht übergeben werden.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">payload <span class="property-type">string</span></dt>
<dd>Wird an auszuführenden Befehl angehängt, sofern im Node aktiviert.</dd>
<dt class="optional">kill <span class="property-type">string</span></dt>
<dd>Typ des Kill-Signals, das an den zu beendenden exec-Node-Prozess gesendet wird.</dd>
<dt class="optional">pid <span class="property-type">number | string</span></dt>
<dd>Prozess-ID des zu beendenden exec-Node-Prozesses.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<ol class="node-ports">
<li>Standardausgabe (stdout)
<dl class="message-properties">
<dt>payload <span class="property-type">string</span></dt>
<dd>Standardausgabe des Befehls.</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">object</span></dt>
<dd>Rückgabe-Code-Objekts (auch an Port 3 verfügbar) - nur im exec-Modus verfügbar.</dd>
</dl>
</li>
<li>Standardfehlerausgabe (stderr)
<dl class="message-properties">
<dt>payload <span class="property-type">string</span></dt>
<dd>Standardfehlerausgabe des Befehls.</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">object</span></dt>
<dd>Rückgabe-Code-Objekts (auch an Port 3 verfügbar) - nur im exec-Modus verfügbar.</dd>
</dl>
</li>
<li>Rückgabe-Code
<dl class="message-properties">
<dt>payload <span class="property-type">object</span></dt>
<dd>Objekt mit dem Rückgabe-Code und gegebenenfalls <code>message</code> oder <code>signal</code>-Eigenschaften.</dd>
</dl>
</li>
</ol>
<h3>Details</h3>
<p>Standardmäßig wartet der zur Befehlsausführung genutzte Systemaufruf <code>exec</code>,
bis die Ausführung abgeschlossen ist, und gibt anschließend dessen Ausgaben zurück.
Ein erfolgreich ausgeführter Befehl sollte z.B. den Rückgabe-Code <code>{ code: 0 }</code> haben.</p>
<p>Optional kann stattdessen <code>spawn</code> verwendet werden, wodurch die Standardausgabe und Standardfehlerausgabe
bereits während der Befehlsausführung in der Regel Zeile für Zeile rückgegeben werden.
Nach Befehlsabschluss wird ein Objekt am 3. Port ausgegeben.
Ein erfolgreich ausgeführter Befehl sollte z.B. <code>{ code: 0 }</code> zurückgeben.</p>
<p>Fehler können zusätzliche Informationen über den dritten Port als <code>msg.payload</code> zurückgeben,
z.B. eine <code>message</code>- oder <code>signal</code>-Zeichenfolge.</p>
<p>Der auszuführende Befehl wird innerhalb des Nodes mit der Option zum Anhängen von
<code>msg.payload</code> und weiteren Parametern definiert.</p>
<p>Befehle oder Parameter mit Leerzeichen sollten in Anführungszeichen eingeschlossen werden,
z.B. <code>"Dies ist ein einzelner Parameter"</code></p>
<p>Die zurückgegebenen Daten (Payload) sind in der Regel eine <i>Zeichenfolge (string)</i>,
außer es werden nicht UTF-8-Zeichen wie bei einem <i>binären Puffer (buffer)</i> erkannt.</p>
<p>Bei einem aktiven Node werden Status und die PID angezeigt.
Änderungen können mittels status-Node gelesen werden.</p>
<h4><b>Prozesse beenden</b></h4>
<p>Durch Senden von <code>msg.kill</code> wird ein einzelner aktiver Prozess beendet.
<code>msg.kill</code> sollte als Zeichenfolge (string) den Signaltyp enthalten,
z.B. <code>SIGINT</code>, <code>SIGQUIT</code> oder <code>SIGHUP</code>.
Der Standardwert ist <code>SIGTERM</code>, wenn die Zeichenfolge leer ist.</p>
<p>Wenn der Node mehr als einen Befehl bzw. Prozess ausführt,
muss zusätzlich über <code>msg.pid</code> die PID des zu beendenden Prozesses übergeben werden.</p>
<p>Wenn ein <code>Zeitlimit</code> angegeben ist, wird der Prozess automatisch nach Ablauf der Zeit beendet.</p>
<p><b>Tipp</b>: Wenn Sie eine Python-App ausführen, müssen Sie möglicherweise den Parameter <code>-u</code> verwenden,
um die Ausgabepufferung zu stoppen.</p>
</script>
</div><div><!-- --- [red-module:node-red/rbe] --- -->
<script type="text/html" data-template-name="rbe">
<div class="form-row">
<label for="node-input-func"><i class="fa fa-wrench"></i> <span data-i18n="rbe.label.func"></span></label>
<select type="text" id="node-input-func" style="width:70%;">
<option value="rbe" data-i18n="rbe.opts.rbe"></option>
<option value="rbei" data-i18n="rbe.opts.rbei"></option>
<option value="deadbandEq" data-i18n="rbe.opts.deadbandEq"></option>
<option value="deadband" data-i18n="rbe.opts.deadband"></option>
<option value="narrowbandEq" data-i18n="rbe.opts.narrowbandEq"></option>
<option value="narrowband" data-i18n="rbe.opts.narrowband"></option>
</select>
</div>
<div class="form-row" id="node-bandgap">
<label for="node-input-gap">&nbsp;</label>
<input type="text" id="node-input-gap" data-i18n="[placeholder]rbe.placeholder.bandgap" style="width:95px;">
<select type="text" id="node-input-inout" style="width:54%;">
<option value="out" data-i18n="rbe.opts.out"></option>
<option value="in" data-i18n="rbe.opts.in"></option>
</select>
</div>
<div class="form-row" id="node-startvalue">
<label for="node-input-start"><i class="fa fa-thumb-tack"></i> <span data-i18n="rbe.label.start"></span></label>
<input type="text" id="node-input-start" data-i18n="[placeholder]rbe.placeholder.start" style="width:70%;">
</div>
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row" style="margin-bottom: 0px;">
<label> </label>
<input type="checkbox" id="node-input-septopics" style="display:inline-block; width:20px; vertical-align:baseline;">
<label style="width: auto" for="node-input-septopics" data-i18n="rbe.label.septopics"></label>
</div>
<div class="form-row">
<label> </label>
<input type="text" id="node-input-topi" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="rbe.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]rbe.label.name" style="width:70%;">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType("rbe", {
color:"#E2D96E",
category: 'function',
defaults: {
name: {value:""},
func: {value:"rbe"},
gap: {value:"",
label: RED._("node-red:rbe.label.gap"),
validate:RED.validators.regex(/^(\d*[.]*\d*|)(%|)$/)},
start: {value:""},
inout: {value:"out"},
septopics: {value:true},
property: {value:"payload", required:true,
label:RED._("node-red:rbe.label.property")},
topi: {value:"topic", required:true,
label:RED._("node-red:rbe.label.topic")}
},
inputs:1,
outputs:1,
icon: "rbe.png",
paletteLabel: "filter",
label: function() {
var ll = (this.func||"").replace("Eq","").replace("rbei",this._("rbe.rbe")).replace("rbe",this._("rbe.rbe"))||this._("rbe.rbe");
return this.name||ll||this._("rbe.rbe");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
if (this.septopics === undefined) {
$("#node-input-septopics").prop('checked', true);
}
if (this.topi === undefined) {
$("#node-input-topi").val("topic");
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
$("#node-input-topi").typedInput({default:'msg',types:['msg']});
//$( "#node-input-gap" ).spinner({min:0});
if ($("#node-input-inout").val() === null) {
$("#node-input-inout").val("out");
}
$("#node-input-func").on("change",function() {
if (($("#node-input-func").val() === "rbe")||($("#node-input-func").val() === "rbei")) {
$("#node-bandgap").hide();
} else {
$("#node-bandgap").show();
}
if (($("#node-input-func").val() === "narrowband")||($("#node-input-func").val() === "narrowbandEq")) {
$("#node-startvalue").show();
} else {
$("#node-startvalue").hide();
}
});
$("#node-input-septopics").on("change", function() {
$("#node-input-topi").typedInput("disable",!this.checked);
})
$("#node-input-topi").typedInput("disable",!!!this.septopics);
}
});
</script>
<script type="text/html" data-help-name="rbe">
<p>Report by Exception (RBE) - Daten-Weiterleitung nur bei Änderung der Nutzdaten (Payload).
Der Node kann auch blockieren oder weiterleiten, wenn die Wertänderung eine Grenze überschreitet (Totband- und Nahband-Modus).</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">number | string | (object)</span>
</dt>
<dd>Der RBE-Modus mit Prüfung auf Wertänderung akzeptiert Zahlen (numbers), Zeichenfolgen (string) und einfache Objekte (object).
Bei den anderen wertvergleichenden Modies müssen analysierbare (parseable) Zahlenwerte übergeben werden.</dd>
<dt class="optional">topic <span class="property-type">string</span>
</dt>
<dd>Wenn vorgegeben erfolgt die Auswertung separat für jedes Topic</dd>
<dt class="optional">reset<span class="property-type">any</span></dt>
<dd>Wenn gesetzt wird/werden der/die gespeicherte(n) Wert(e) rückgesetzt</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">wie Eingangsdaten</span>
</dt>
<dd>Wenn Bedingung erfüllt, sind die Ausgangsdaten gleich den Eingangsdaten</dd>
</dl>
<h3>Details</h3>
<p>Im <i>RBE</i>-Modus mit Prüfung auf Wertänderung blockiert dieser Node die Datenweitergabe bis
<code>msg.payload</code> (oder die eingestellte Eigenschaft) verändert ist gegenüber dessen vorherigen Wert.
Wenn benötigt, wird der Anfangswert ignoriert, sodass beim Start nichts gesendet wird.</p>
<p>In den <i>Totband</i>-Modies werden die Eingangswerte geblockt,
<i>bis</i> die Wertänderung größer oder größer-gleich ist als &plusmn; des Bandes um den voherigen Wert.</p>
<p>In den <i>Nahband</i>-Modies werden die Eingangswerte geblockt,
<i>wenn</i> die Wertänderung größer oder größer-gleich ist als &plusmn; des Bandes um den voherigen Wert.
Dies ist beispielsweise nützlich, um Ausreißer eines fehlerhaften Sensors zu ignorieren.</p>
<p>In den Totband und Nahband-Modies müssen die Eingangswerte analysierbare (parseable) Zahlenwerte sein und
beide unterstützen auch % (prozentuale Angabe), d.h. der Node sendet nur, wenn der Eingangswert mehr als x% vom vorherigen Wert abweicht.</p>
<p>Die Totband- und Nahband-Modies erlauben den Vergleich entweder gegen den letzten gültigen Ausgangswert,
dieses zum Ignorieren von Werten außerhalb des gültigen Bereichs, oder gegen den des vorherigen Eingangswertes,
welches den Sollwert rücksetzt, was einen allmähligen Drift (Totband) oder einen eine schrittweise Veränderung (Nahband) ermöglicht.</p>
<p><b>Hinweis</b>: Dieser Node arbeitet auf per-<code>msg.topic</code>-Basis.
Dies bedeutet, dass ein einzelner rbe-Node mehrere verschiedene Topics parallel bearbeiten kann.</p>
</script>
</div><div><!-- --- [red-module:node-red/tls] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="tls-config">
<div class="form-row" class="hide" id="node-config-row-uselocalfiles">
<input type="checkbox" id="node-config-input-uselocalfiles" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-uselocalfiles" style="width: 70%;"><span data-i18n="tls.label.use-local-files"></label>
</div>
<div class="form-row">
<label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label>
<span class="tls-config-input-data">
<label class="red-ui-button" for="node-config-input-certfile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" id="node-config-input-certfile">
<span id="tls-config-certname" style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
<button class="red-ui-button red-ui-button-small" id="tls-config-button-cert-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
</span>
<input type="hidden" id="node-config-input-certname">
<input type="hidden" id="node-config-input-certdata">
<input class="hide tls-config-input-path" style="width: calc(100% - 170px);" type="text" id="node-config-input-cert" data-i18n="[placeholder]tls.placeholder.cert">
</div>
<div class="form-row">
<label style="width: 120px;" for="node-config-input-key"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.key"></span></label>
<span class="tls-config-input-data">
<label class="red-ui-button" for="node-config-input-keyfile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" id="node-config-input-keyfile">
<span id="tls-config-keyname" style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
<button class="red-ui-button red-ui-button-small" id="tls-config-button-key-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
</span>
<input type="hidden" id="node-config-input-keyname">
<input type="hidden" id="node-config-input-keydata">
<input class="hide tls-config-input-path" style="width: calc(100% - 170px);" type="text" id="node-config-input-key" data-i18n="[placeholder]tls.placeholder.key">
</div>
<div class="form-row">
<label style="width: 100px; margin-left: 20px;" for="node-config-input-passphrase"> <span data-i18n="tls.label.passphrase"></span></label>
<input type="password" style="width: calc(100% - 170px);" id="node-config-input-passphrase" data-i18n="[placeholder]tls.placeholder.passphrase">
</div>
<div class="form-row">
<label style="width: 120px;" for="node-config-input-ca"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.ca"></span></label>
<span class="tls-config-input-data">
<label class="red-ui-button" for="node-config-input-cafile"><i class="fa fa-upload"></i> <span data-i18n="tls.label.upload"></span></label>
<input class="hide" type="file" title=" " id="node-config-input-cafile">
<span id="tls-config-caname" style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;"> </span>
<button class="red-ui-button red-ui-button-small" id="tls-config-button-ca-clear" style="margin-left: 10px"><i class="fa fa-times"></i></button>
</span>
<input type="hidden" id="node-config-input-caname">
<input type="hidden" id="node-config-input-cadata">
<input class="hide tls-config-input-path" style="width: calc(100% - 170px);" type="text" id="node-config-input-ca" data-i18n="[placeholder]tls.placeholder.ca">
</div>
<div class="form-row">
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-verifyservercert" style="width: calc(100% - 170px);" data-i18n="tls.label.verify-server-cert"></label>
</div>
<div class="form-row">
<label style="width: 126px;" for="node-config-input-servername"><i class="fa fa-server"></i> <span data-i18n="tls.label.servername"></span></label>
<input style="width: calc(100% - 176px);" type="text" id="node-config-input-servername" data-i18n="[placeholder]tls.placeholder.servername">
</div>
<div class="form-row">
<label style="width: 126px;" for="node-config-input-alpnprotocol"><i class="fa fa-cogs"></i> <span data-i18n="tls.label.alpnprotocol"></span></label>
<input style="width: calc(100% - 176px);" type="text" id="node-config-input-alpnprotocol" data-i18n="[placeholder]tls.placeholder.alpnprotocol">
</div>
<hr>
<div class="form-row">
<label style="width: 120px;" for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input style="width: calc(100% - 170px);" type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('tls-config',{
category: 'config',
defaults: {
name: {value:""},
cert: {value:"", validate: function(v,opt) {
var currentKey = $("#node-config-input-key").val();
if (currentKey === undefined) {
currentKey = this.key;
}
if (currentKey === '' || v != '') {
return true;
}
return RED._("node-red:tls.error.invalid-cert");
}},
key: {value:"", validate: function(v,opt) {
var currentCert = $("#node-config-input-cert").val();
if (currentCert === undefined) {
currentCert = this.cert;
}
if (currentCert === '' || v != '') {
return true;
}
return RED._("node-red:tls.error.invalid-key");
}},
ca: {value:""},
certname: {value:""},
keyname: {value:""},
caname: {value:""},
servername: {value:""},
verifyservercert: {value: true},
alpnprotocol: {value: ""}
},
credentials: {
certdata: {type:"text"},
keydata: {type:"text"},
cadata: {type:"text"},
passphrase: {type:"password"}
},
label: function() {
return this.name || this._("tls.tls");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
function updateFileUpload() {
if ($("#node-config-input-uselocalfiles").is(':checked')) {
$(".tls-config-input-path").show();
$(".tls-config-input-data").hide();
} else {
$(".tls-config-input-data").show();
$(".tls-config-input-path").hide();
}
}
$("#node-config-input-uselocalfiles").on("click",function() {
updateFileUpload();
});
function saveFile(property, file) {
var dataInputId = "#node-config-input-"+property+"data";
var filenameInputId = "#node-config-input-"+property+"name";
var filename = file.name;
var reader = new FileReader();
reader.onload = function(event) {
$("#tls-config-"+property+"name").text(filename);
$(filenameInputId).val(filename);
$(dataInputId).val(event.target.result);
}
reader.readAsText(file,"UTF-8");
}
$("#node-config-input-certfile" ).on("change", function() {
saveFile("cert", this.files[0]);
});
$("#node-config-input-keyfile" ).on("change", function() {
saveFile("key", this.files[0]);
});
$("#node-config-input-cafile" ).on("change", function() {
saveFile("ca", this.files[0]);
});
function clearNameData(prop) {
$("#tls-config-"+prop+"name").text("");
$("#node-config-input-"+prop+"data").val("");
$("#node-config-input-"+prop+"name").val("");
}
$("#tls-config-button-cert-clear").on("click", function() {
clearNameData("cert");
});
$("#tls-config-button-key-clear").on("click", function() {
clearNameData("key");
});
$("#tls-config-button-ca-clear").on("click", function() {
clearNameData("ca");
});
if (RED.settings.tlsConfigDisableLocalFiles) {
$("#node-config-row-uselocalfiles").hide();
} else {
$("#node-config-row-uselocalfiles").show();
}
// in case paths were set from old TLS config
if(this.cert || this.key || this.ca) {
$("#node-config-input-uselocalfiles").prop('checked',true);
}
$("#tls-config-certname").text(this.certname);
$("#tls-config-keyname").text(this.keyname);
$("#tls-config-caname").text(this.caname);
updateFileUpload();
},
oneditsave: function() {
if ($("#node-config-input-uselocalfiles").is(':checked')) {
clearNameData("ca");
clearNameData("cert");
clearNameData("key");
} else {
$("#node-config-input-ca").val("");
$("#node-config-input-cert").val("");
$("#node-config-input-key").val("");
}
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="tls-config">
<p>Konfigurationsoptionen für TLS-Verbindungen.</p>
</script>
</div><div><!-- --- [red-module:node-red/httpproxy] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="http proxy">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-config-input-name">
</div>
<div class="form-row">
<label for="node-config-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
<input type="text" id="node-config-input-url" placeholder="http://hostname:port">
</div>
<div class="form-row">
<input type="checkbox" id="node-config-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-useAuth" style="width: 70%;"><span data-i18n="httpin.use-proxyauth"></span></label>
<div style="margin-left: 20px" class="node-config-input-useAuth-row hide">
<div class="form-row">
<label for="node-config-input-username"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
<input type="text" id="node-config-input-username">
</div>
<div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
<input type="password" id="node-config-input-password">
</div>
</div>
</div>
<div class="form-row" style="margin-bottom:0;">
<label><i class="fa fa-list"></i> <span data-i18n="httpin.noproxy-hosts"></span></label>
</div>
<div class="form-row node-config-input-noproxy-container-row">
<ol id="node-config-input-noproxy-container"></ol>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('http proxy', {
category: 'config',
defaults: {
name: {value:''},
url: {
value:'',
validate:function(v, opt) {
if ((v && (v.indexOf('://') !== -1) &&
(v.trim().indexOf('http') === 0))) {
return true;
}
return RED._("node-red:httpin.errors.invalid-url");
}
},
noproxy: {value:[]}
},
credentials: {
username: {type:'text'},
password: {type:'password'}
},
label: function() {
return this.name || this.url || ('http proxy:' + this.id);
},
oneditprepare: function() {
$('#node-config-input-useAuth').on("change", function() {
if ($(this).is(":checked")) {
$('.node-config-input-useAuth-row').show();
} else {
$('.node-config-input-useAuth-row').hide();
$('#node-config-input-username').val('');
$('#node-config-input-password').val('');
}
});
if (this.credentials.username || this.credentials.has_password) {
$('#node-config-input-useAuth').prop('checked', true);
} else {
$('#node-config-input-useAuth').prop('checked', false);
}
$('#node-config-input-useAuth').change();
var hostList = $('#node-config-input-noproxy-container')
.css({'min-height':'150px','min-width':'450px'})
.editableList({
addItem: function(container, index, data) {
var row = $('<div/>')
.css({overflow: 'hidden',whiteSpace: 'nowrap'})
.appendTo(container);
var hostField = $('<input/>',{class:'node-config-input-host',type:'text',placeholder:'hostname'})
.css({width:'100%'})
.appendTo(row);
if (data.host) {
hostField.val(data.host);
}
},
removable: true
});
if (this.noproxy) {
for (var i in this.noproxy) {
hostList.editableList('addItem', {host:this.noproxy[i]});
}
}
if (hostList.editableList('items').length == 0) {
hostList.editableList('addItem', {host:''});
}
},
oneditsave: function() {
var hosts = $('#node-config-input-noproxy-container').editableList('items');
var node = this;
node.noproxy = [];
hosts.each(function(i) {
var host = $(this).find('.node-config-input-host').val().trim();
if (host) {
node.noproxy.push(host);
}
});
},
oneditresize: function(size) {
var rows = $('#node-config-dialog-edit-form>div:not(.node-config-input-noproxy-container-row)');
var height = size.height;
for (var i = 0; i < rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $('#node-config-dialog-edit-form>div.node-config-input-noproxy-container-row');
height -= (parseInt(editorRow.css('margin-top')) + parseInt(editorRow.css('margin-bottom')));
$('#node-config-input-noproxy-container').editableList('height',height);
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="http proxy">
<p>Konfigurationsoptionen für HTTP-Proxy.</p>
<h3>Details</h3>
<p>Wenn auf einen Host zugegriffen wird, der auf der Liste der zu ignorierenden Hosts steht,
wird kein Proxy benutzt.</p>
</script>
</div><div><!-- --- [red-module:node-red/mqtt] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<style>
.mqtt-form-row-cols2 > input.mqtt-form-row-col1 {
width: calc(35% - 75px);
}
.mqtt-form-row-cols2 > select.mqtt-form-row-col1 {
width: calc(35% - 75px);
}
.mqtt-form-row-cols2 > label.mqtt-form-row-col2 {
width: 100px;
margin-left: 42px;
display: inline-block;
}
.mqtt-form-row-cols2 > input.mqtt-form-row-col2 {
width: calc(35% - 75px);
display: inline-block;
}
.mqtt-form-row-cols2 > select.mqtt-form-row-col2 {
width: calc(35% - 75px);
display: inline-block;
}
.form-row.mqtt5-out > label {
width: 130px;
}
.form-row.mqtt-flags-row > label {
vertical-align: top;
}
.form-row.mqtt-flags-row > .mqtt-flags {
display: inline-block;
width: 70%
}
.form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label {
display: block;
width: 100%;
}
.form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label > input {
position: relative;
vertical-align: bottom;
top: -2px;
width: 15px;
height: 15px;
}
.form-row-mqtt5 {
display: none;
}
.form-row-mqtt5.form-row-mqtt5-active:not(.form-row-mqtt-static-disabled) {
display: block
}
.form-row-mqtt-static-disabled {
display: none;
/* opacity: 0.3;
pointer-events: none; */
}
.form-row.form-row-mqtt-datatype-tip > .form-tips {
width: calc(70% - 18px);
display: inline-block;
margin-top: -8px;
}
</style>
<script type="text/html" data-template-name="mqtt in">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-topicType" data-i18n="mqtt.label.action"></label>
<select id="node-input-topicType" style="width: 70%">
<option value="topic" data-i18n="mqtt.label.staticTopic"></option>
<option value="dynamic" data-i18n="mqtt.label.dynamicTopic"></option>
</select>
<input type="hidden" id="node-input-inputs">
</div>
<div class="form-row form-row-mqtt-static">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
</div>
<div class="form-row form-row-mqtt-static">
<label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-input-qos" style="width:125px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-row mqtt-flags-row form-row-mqtt5 form-row-mqtt-static">
<label for="node-input-nl" ><i class="fa fa-flag"></i> <span data-i18n="mqtt.label.flags">Flags</span></label>
<div class="mqtt-flags">
<div class="mqtt-flag">
<label for="node-input-nl">
<input type="checkbox" id="node-input-nl">
<span data-i18n="mqtt.label.nl"></span>
</label>
</div>
<div class="mqtt-flag">
<label for="node-input-rap">
<input type="checkbox" id="node-input-rap">
<span data-i18n="mqtt.label.rap"></span>
</label>
</div>
</div>
</div>
<div class="form-row form-row-mqtt5 form-row-mqtt-static">
<label for="node-input-rh" style="width:100%"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.rh"></span></label>
<select id="node-input-rh" style="margin-left: 104px; width: 70%">
<option value="0" data-i18n="mqtt.label.rh0"></option>
<option value="1" data-i18n="mqtt.label.rh1"></option>
<option value="2" data-i18n="mqtt.label.rh2"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="mqtt.label.output"></span></label>
<select id="node-input-datatype" style="width:70%;">
<option value="auto-detect" data-i18n="mqtt.output.auto-detect"></option>
<option value="auto" data-i18n="mqtt.output.auto"></option>
<option value="buffer" data-i18n="mqtt.output.buffer"></option>
<option value="utf8" data-i18n="mqtt.output.string"></option>
<option value="json" data-i18n="mqtt.output.json"></option>
<option value="base64" data-i18n="mqtt.output.base64"></option>
</select>
</div>
<div class="form-row form-row-mqtt-datatype-tip">
<label> &nbsp; </label>
<div class="form-tips" id="mqtt-in-datatype-depreciated-tip"><span data-i18n="mqtt.label.auto-mode-depreciated"></span></div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/html" data-template-name="mqtt out">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
</div>
<div class="form-row mqtt-form-row-cols2">
<label for="node-input-qos" class="mqtt-form-row-col1"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-input-qos" class="mqtt-form-row-col1">
<option value=""></option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<label for="node-input-retain" class="mqtt-form-row-col2"><i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span></label>
<select id="node-input-retain" class="mqtt-form-row-col2" >
<option value=""></option>
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
<input type="text" id="node-input-userProps" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-input-respTopic" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-input-correl" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-input-contentType"><span data-i18n="mqtt.label.contentType"></span></label>
<input type="text" id="node-input-contentType" style="width: calc(100% - 166px);">
</div>
<div class="form-row mqtt-form-row-cols2 mqtt5 mqtt5-out">
<label for="node-input-expiry" class="mqtt-form-row-col1"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-input-expiry" style="width: calc(100% - 166px);" class="mqtt-form-row-col1" >
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips"><span data-i18n="mqtt.tip"></span></div>
</script>
<script type="text/html" data-template-name="mqtt-broker">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<ul style="min-width: 600px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul>
</div>
<div id="node-config-mqtt-broker-tabs-content" style="min-height:150px;">
<div id="mqtt-broker-tab-connection" style="display:none">
<div class="form-row node-input-broker">
<label for="node-config-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-config-input-broker" style="width: calc(100% - 300px);" data-i18n="[placeholder]mqtt.label.example">
<label for="node-config-input-port" style="margin-left:20px; width:43px; "> <span data-i18n="mqtt.label.port"></span></label>
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px">
</div>
<div class="form-row" style="margin-bottom:0">
<input type="checkbox" id="node-config-input-autoConnect" style="margin: 0 5px 0 104px; display: inline-block; width: auto;">
<label for="node-config-input-autoConnect" style="width: auto"><span data-i18n="mqtt.label.auto-connect"></span></label>
</div>
<div class="form-row" style="height: 34px;">
<input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 5px 0 104px; display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-usetls" style="width: 100px; line-height: 34px;"><span data-i18n="mqtt.label.use-tls"></span></label>
<span id="node-config-row-tls" class="hide"><input style="width: 320px;" type="text" id="node-config-input-tls"></span>
</div>
<div class="form-row">
<label for="node-config-input-protocolVersion"><i class="fa fa-cog"></i> <span data-i18n="mqtt.label.protocolVersion"></span></label>
<select id="node-config-input-protocolVersion" style="width:70%;">
<option value="3" data-i18n="mqtt.label.protocolVersion3"></option>
<option value="4" data-i18n="mqtt.label.protocolVersion4"></option>
<option value="5" data-i18n="mqtt.label.protocolVersion5"></option>
</select>
</div>
<div class="form-row">
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
<input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
</div>
<div class="form-row">
<label for="node-config-input-keepalive"><i class="fa fa-heartbeat"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
<input type="number" min="0" id="node-config-input-keepalive" style="width: 100px">
</div>
<div class="form-row" style="margin-bottom:0">
<label style="vertical-align:top;"><i class="fa fa-info"></i> <span data-i18n="mqtt.label.session"></span></label>
<div style="display: inline-block; width:calc(100% - 110px)">
<div class="form-row">
<label for="node-config-input-cleansession" style="width: auto;">
<input type="checkbox" id="node-config-input-cleansession" style="position: relative;vertical-align: bottom; top: -2px; width: 15px;height: 15px;">
<span id="node-config-input-cleansession-label" data-i18n="mqtt.label.cleansession"></span>
</label>
</div>
<div class="form-row mqtt5">
<label style="width:auto" for="node-config-input-sessionExpiry"><span data-i18n="mqtt.label.sessionExpiry"></span></label>
<input type="number" min="0" id="node-config-input-sessionExpiry" style="width: 100px" >
</div>
</div>
</div>
<div class="form-row mqtt5">
<label style="width: 125px;" for="node-config-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
<input type="text" id="node-config-input-userProps" style="width: calc(100% - 166px);">
</div>
<br>
</div>
<div id="mqtt-broker-tab-security" style="display:none">
<div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
<input type="text" id="node-config-input-user">
</div>
<div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
<input type="password" id="node-config-input-password">
</div>
</div>
<div id="mqtt-broker-tab-messages" style="display:none">
<div id="mqtt-broker-section-birth">
<div class="red-ui-palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.birth-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-birthRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-birthQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-contentType" data-i18n="mqtt.label.contentType"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-birth-contentType">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-props" data-i18n="mqtt.label.userProperties"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-birth-props">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-config-input-birth-respTopic" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-config-input-birth-correl" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-birth-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-config-input-birth-expiry" style="width: calc(100% - 200px);">
</div>
</div>
</div>
<div id="mqtt-broker-section-close">
<div class="red-ui-palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.close-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-closeTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closeTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.close-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-closeRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-closePayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closePayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-closeQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-contentType" data-i18n="mqtt.label.contentType"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-close-contentType">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-props" data-i18n="mqtt.label.userProperties"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-close-props">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-config-input-close-respTopic" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-config-input-close-correl" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-close-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-config-input-close-expiry" style="width: calc(100% - 200px);">
</div>
</div>
</div>
<div id="mqtt-broker-section-will">
<div class="red-ui-palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.will-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.will-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-willRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-willQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-row mqtt5">
<label><span data-i18n="mqtt.label.delay"></span></label>
<input type="number" min="0" id="node-config-input-will-delay" style="width: 100px" >
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-contentType" data-i18n="mqtt.label.contentType"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-will-contentType">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-props" data-i18n="mqtt.label.userProperties"></label>
<input type="text" style="width:calc(100% - 200px);" id="node-config-input-will-props">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
<input type="text" id="node-config-input-will-respTopic" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
<input type="text" id="node-config-input-will-correl" style="width: calc(100% - 200px);">
</div>
<div class="form-row mqtt5 mqtt5-out">
<label for="node-config-input-will-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
<input id="node-config-input-will-expiry" style="width: calc(100% - 200px);">
</div>
</div>
</div>
</div>
</div>
</script>
<script type="text/javascript">
(function() {
var typedInputNoneOpt = { value: 'none', label: '', hasValue: false };
var makeTypedInputOpt = function(value){
return {
value: value,
label:value,
hasValue: false
}
}
var contentTypeOpts = [
typedInputNoneOpt,
makeTypedInputOpt("application/json"),
makeTypedInputOpt("application/octet-stream"),
makeTypedInputOpt("text/csv"),
makeTypedInputOpt("text/html"),
makeTypedInputOpt("text/plain"),
{value:"other", label:""}
];
function getDefaultContentType(value) {
var defaultContentType;
var matchedContentType = contentTypeOpts.filter(function(v) {
return v.value === value;
})
if (matchedContentType.length > 0) {
defaultContentType = matchedContentType[0].value;
}
if (value && !defaultContentType) {
defaultContentType = 'other';
}
return defaultContentType || 'none'
}
/**
* Test a topic string is valid for publishing
* @param {string} topic
* @returns `true` if it is a valid topic
*/
function validateMQTTPublishTopic(topic, opts) {
if(!topic || topic == "" || !/[\+#\b\f\n\r\t\v\0]/.test(topic)) {
return true;
}
return RED._("node-red:mqtt.errors.invalid-topic");
}
RED.nodes.registerType('mqtt-broker',{
category: 'config',
defaults: {
name: {value:""},
broker: {value:"",required:true},
port: {
value:1883,required:false,
label: RED._("node-red:mqtt.label.port"),
validate:RED.validators.number(true)},
tls: {type:"tls-config",required: false,
label:RED._("node-red:mqtt.label.use-tls") },
clientid: {value:"", validate: function(v, opt) {
var ok = false;
if ($("#node-config-input-clientid").length) {
// Currently editing the node
ok = $("#node-config-input-cleansession").is(":checked") || (v||"").length > 0;
} else {
ok = (this.cleansession===undefined || this.cleansession) || (v||"").length > 0;
}
if (ok) {
return ok;
}
return RED._("node-red:mqtt.errors.invalid-client-id");
}},
autoConnect: {value: true},
usetls: {value: false},
verifyservercert: { value: false},
compatmode: { value: false},
protocolVersion: { value: 4},
keepalive: {
value:60,
label: RED._("node-red:mqtt.label.keepalive"),
validate:RED.validators.number(false)},
cleansession: {value: true},
birthTopic: {value:"", validate:validateMQTTPublishTopic},
birthQos: {value:"0"},
birthRetain: {value:false},
birthPayload: {value:""},
birthMsg: { value: {}},
closeTopic: {value:"", validate:validateMQTTPublishTopic},
closeQos: {value:"0"},
closeRetain: {value:false},
closePayload: {value:""},
closeMsg: { value: {}},
willTopic: {value:"", validate:validateMQTTPublishTopic},
willQos: {value:"0"},
willRetain: {value:false},
willPayload: {value:""},
willMsg: { value: {}},
userProps: { value: ""},
sessionExpiry: {value:0}
},
credentials: {
user: {type:"text"},
password: {type: "password"}
},
label: function() {
if (this.name) {
return this.name;
}
var b = this.broker;
if (!b) { b = "undefined"; }
var lab = "";
lab = (this.clientid?this.clientid+"@":"")+b;
if (b.indexOf("://") === -1){
if (!this.port){ lab = lab + ":1883"; }
else { lab = lab + ":" + this.port; }
}
return lab;
},
oneditprepare: function () {
var tabs = RED.tabs.create({
id: "node-config-mqtt-broker-tabs",
onchange: function(tab) {
$("#node-config-mqtt-broker-tabs-content").children().hide();
$("#" + tab.id).show();
}
});
tabs.addTab({
id: "mqtt-broker-tab-connection",
label: this._("mqtt.tabs-label.connection")
});
tabs.addTab({
id: "mqtt-broker-tab-security",
label: this._("mqtt.tabs-label.security")
});
tabs.addTab({
id: "mqtt-broker-tab-messages",
label: this._("mqtt.tabs-label.messages")
});
function setUpSection(sectionId, v5Opts, isExpanded) {
var birthMessageSection = $("#mqtt-broker-section-"+sectionId);
var paletteHeader = birthMessageSection.find('.red-ui-palette-header');
var twistie = paletteHeader.find('i');
var sectionContent = birthMessageSection.find('.section-content');
function toggleSection(expanded) {
twistie.toggleClass('expanded', expanded);
sectionContent.toggle(expanded);
}
paletteHeader.on("click", function(e) {
e.preventDefault();
var isExpanded = twistie.hasClass('expanded');
toggleSection(!isExpanded);
});
toggleSection(isExpanded);
$("#node-config-input-"+sectionId+"-contentType").val(v5Opts?v5Opts.contentType:"").typedInput({
default: getDefaultContentType(v5Opts?v5Opts.contentType:""),
types: contentTypeOpts,
});
$("#node-config-input-"+sectionId+"-props").val(v5Opts?v5Opts.userProps:"").typedInput({
default: !(v5Opts?v5Opts.userProps:null)? 'none':'json',
types: [typedInputNoneOpt, 'json'],
});
$("#node-config-input-"+sectionId+"-respTopic").val(v5Opts?v5Opts.respTopic:"").typedInput({
default: !(v5Opts?v5Opts.respTopic:null)? 'none':'str',
types: [typedInputNoneOpt, 'str'],
});
$("#node-config-input-"+sectionId+"-correl").val(v5Opts?v5Opts.correl:"").typedInput({
default: !(v5Opts?v5Opts.correl:null)? 'none':'str',
types: [typedInputNoneOpt, 'str'],
});
$("#node-config-input-"+sectionId+"-expiry").val(v5Opts?v5Opts.expiry:"").typedInput({
default: !(v5Opts?v5Opts.expiry:null)? 'none':'num',
types: [typedInputNoneOpt, 'num'],
});
}
// show first section if none are set so the user gets the idea
var showBirthSection = this.birthTopic !== ""
|| this.willTopic === ""
&& this.birthTopic === ""
&& this.closeTopic == "";
setUpSection('birth', this.birthMsg, showBirthSection);
setUpSection('close', this.closeMsg, this.closeTopic !== "");
setUpSection('will', this.willMsg, this.willTopic !== "");
if (this.willMsg) {
$("#node-config-input-will-delay").val(this.willMsg.delay);
}
setTimeout(function() { tabs.resize(); },0);
if (typeof this.cleansession === 'undefined') {
this.cleansession = true;
$("#node-config-input-cleansession").prop("checked",true);
}
if (typeof this.usetls === 'undefined') {
this.usetls = false;
$("#node-config-input-usetls").prop("checked",false);
}
if (typeof this.autoConnect === 'undefined') {
this.autoConnect = true;
$("#node-config-input-autoConnect").prop("checked",true);
}
if (this.compatmode === 'true' || this.compatmode === true) {
delete this.compatmode;
this.protocolVersion = 4;
}
if (typeof this.protocolVersion === 'undefined') {
this.protocolVersion = 4;
}
$("#node-config-input-protocolVersion").on("change", function() {
var v5 = $("#node-config-input-protocolVersion").val() == "5";
if(v5) {
$("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleanstart"))
$("div.form-row.mqtt5").show();
} else {
$("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleansession"))
$("div.form-row.mqtt5").hide();
}
});
$("#node-config-input-protocolVersion").val(this.protocolVersion);
$("#node-config-input-userProps").typedInput({
default: !this.userProps ? 'none':'json',
types: [typedInputNoneOpt, 'json']
});
$("#node-config-input-userProps").typedInput('value',this.userProps);
if (typeof this.keepalive === 'undefined') {
this.keepalive = 15;
$("#node-config-input-keepalive").val(this.keepalive);
}
if (typeof this.birthQos === 'undefined') {
this.birthQos = "0";
$("#node-config-input-birthQos").val("0");
}
if (typeof this.closeQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
if (typeof this.willQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
function updateTLSOptions() {
if ($("#node-config-input-usetls").is(':checked')) {
$("#node-config-row-tls").show();
} else {
$("#node-config-row-tls").hide();
}
}
updateTLSOptions();
$("#node-config-input-usetls").on("click",function() {
updateTLSOptions();
});
var node = this;
function updateClientId() {
if ($("#node-config-input-cleansession").is(":checked")) {
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid"));
} else {
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid-nonclean"));
}
$("#node-config-input-clientid").trigger("change");
}
setTimeout(updateClientId,0);
$("#node-config-input-cleansession").on("click",function() {
updateClientId();
});
function updatePortEntry(){
var disabled = $("#node-config-input-port").prop("disabled");
if ($("#node-config-input-broker").val().indexOf("://") === -1){
if (disabled){
$("#node-config-input-port").prop("disabled", false);
}
}
else {
if (!disabled){
$("#node-config-input-port").prop("disabled", true);
}
}
}
$("#node-config-input-broker").on("change", function() {
updatePortEntry();
});
$("#node-config-input-broker").on( "keyup", function() {
updatePortEntry();
});
setTimeout(updatePortEntry,50);
setTimeout(function() {
$("#node-config-input-protocolVersion").trigger("change");
},50);
},
oneditsave: function() {
if (!$("#node-config-input-usetls").is(':checked')) {
$("#node-config-input-tls").val("");
}
var v5 = $("#node-config-input-protocolVersion").val() == "5";
function saveV5Message(section) {
var msg = {};
if ($("#node-config-input-"+section+"Topic").val().trim().length > 0) {
var contentType = $("#node-config-input-"+section+"-contentType").val().trim();
if (contentType === '') {
contentType = $("#node-config-input-"+section+"-contentType").typedInput('type');
if (contentType === 'none' || contentType === 'other') {
contentType = "";
}
}
if (contentType) {
msg.contentType = contentType;
}
var props = $("#node-config-input-"+section+"-props").val().trim();
if (props) {
msg.userProps = props;
}
var resp = $("#node-config-input-"+section+"-respTopic").val().trim();
if (props) {
msg.respTopic = resp;
}
var correl = $("#node-config-input-"+section+"-correl").val().trim();
if (correl) {
msg.correl = correl;
}
var expiry = $("#node-config-input-"+section+"-expiry").val().trim();
if (expiry) {
msg.expiry = expiry;
}
}
return msg;
}
if (v5) {
this.userProps = "";
const userPropsType = $("#node-config-input-userProps").typedInput("type");
if(userPropsType == "json") {
const userProps = $("#node-config-input-userProps").val();
if (userProps && typeof userProps === "string") {
this.userProps = userProps.trim();
}
}
this.birthMsg = saveV5Message("birth");
this.closeMsg = saveV5Message("close");
this.willMsg = saveV5Message("will");
var willDelay = $("#node-config-input-will-delay").val();
if (willDelay) {
this.willMsg.delay = willDelay;
}
} else {
this.willMsg = {};
this.birthMsg = {};
this.closeMsg = {};
}
}
});
RED.nodes.registerType('mqtt in',{
category: 'network',
defaults: {
name: {value:""},
topic: {
value:"",
validate: function(v, opt) {
var isDynamic = this.inputs === 1;
var topicTypeSelect = $("#node-input-topicType");
if (topicTypeSelect.length) {
isDynamic = topicTypeSelect.val()==='dynamic'
}
if (isDynamic || ((!!v) && RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)(v))) {
return true;
}
return RED._("node-red:mqtt.errors.invalid-topic");
}
},
qos: {value: "2"},
datatype: {value:"auto-detect",required:true},
broker: {type:"mqtt-broker", required:true, label:RED._("node-red:mqtt.label.broker")},
// subscriptionIdentifier: {value:0},
nl: {value:false},
rap: {value:true},
rh: {value:0},
inputs: {value:0},
},
color:"#d8bfd8",
inputs:0,
outputs:1,
icon: "bridge.svg",
label: function() {
var label = "mqtt";
if(this.topicType !== "dynamic" && this.topic) {
label = this.topic;
}
return this.name || label;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
const node = this;
const isV5Broker = function() {
var confNode = RED.nodes.node($("#node-input-broker").val());
return confNode && confNode.protocolVersion === "5";
}
const isDynamic = function() {
return $('#node-input-topicType').val() === "dynamic";
}
const updateVisibility = function() {
var v5 = isV5Broker();
var dynamic = isDynamic();
$("div.form-row-mqtt5").toggleClass("form-row-mqtt5-active",!!v5);
$("div.form-row.form-row-mqtt-static").toggleClass("form-row-mqtt-static-disabled", !!dynamic)
}
$("#node-input-datatype").on("change", function() {
if($(this).val() === "auto") {
$(".form-row.form-row-mqtt-datatype-tip").show();
} else {
$(".form-row.form-row-mqtt-datatype-tip").hide();
}
})
$("#node-input-datatype").trigger("change");
$("#node-input-broker").on("change",function(d){
updateVisibility();
});
$('#node-input-topicType').on("change", function () {
$("#node-input-inputs").val(isDynamic() ? 1 : 0);
updateVisibility();
});
if (this.inputs === 1) {
$('#node-input-topicType').val('dynamic')
} else {
$('#node-input-topicType').val('topic')
}
$('#node-input-topicType').trigger("change");
if (this.qos === undefined) {
$("#node-input-qos").val("2");
}
if (this.datatype === undefined) {
$("#node-input-datatype").val("auto-detect");
}
},
oneditsave: function() {
if ($('#node-input-topicType').val() === "dynamic") {
$('#node-input-topic').val("");
}
}
});
RED.nodes.registerType('mqtt out',{
category: 'network',
defaults: {
name: {value:""},
topic: {value:"", validate:validateMQTTPublishTopic},
qos: {value:""},
retain: {value:""},
respTopic: {value:""},
contentType: {value:""},
userProps: {value:''},
correl: {value:''},
expiry: {value:''},
broker: {type:"mqtt-broker", required:true,
label:RED._("node-red:mqtt.label.broker") }
},
color:"#d8bfd8",
inputs:1,
outputs:0,
icon: "bridge.svg",
align: "right",
label: function() {
return this.name||this.topic||"mqtt";
},
oneditprepare: function() {
var that = this;
function showHideDynamicFields() {
var confNode = RED.nodes.node($("#node-input-broker").val());
var v5 = confNode && confNode.protocolVersion == "5";
if(v5) {
$("div.form-row.mqtt5").show();
var t = $("#node-input-respTopic").typedInput("type");
if (t == 'none') {
$("#node-input-correl").parent().hide();
} else {
$("#node-input-correl").parent().show();
}
} else {
$("div.form-row.mqtt5").hide();
}
}
$("#node-input-broker").on("change",function(d){
showHideDynamicFields();
});
var respTopicTI = $("#node-input-respTopic").typedInput({
default: !this.respTopic ? 'none':'str',
types: [typedInputNoneOpt, 'str'],
});
var correlTI = $("#node-input-correl").typedInput({
default: !this.correl ? 'none':'str',
types: [typedInputNoneOpt, 'str']
});
//show / hide correlation data depending on respTopic
respTopicTI.on("change", showHideDynamicFields);
respTopicTI.triggerHandler("change");
$("#node-input-userProps").typedInput({
default: !this.userProps ? 'none':'json',
types: [typedInputNoneOpt, 'json'],
});
$("#node-input-expiry").typedInput({
default: !this.expiry ? 'none':'num',
types: [typedInputNoneOpt, 'num']
});
$("#node-input-contentType").typedInput({
default: getDefaultContentType(this.contentType),
types: contentTypeOpts
})
},
oneditsave: function() {
var contentType = $("#node-input-contentType").val().trim();
if (contentType === '') {
contentType = $("#node-input-contentType").typedInput('type');
if (contentType === 'none' || contentType === 'other') {
contentType = "";
}
}
$("#node-input-contentType").val(contentType)
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="mqtt in">
<p>Verbindungsherstellung zu einem MQTT-Broker und Abonnement von Topic-Nachrichten.</p>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string | buffer</span></dt>
<dd>Zeichenfolge, sofern sie nicht als binärer Puffer (buffer) erkannt wurde.</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd>MQTT-Topic mit / (Schrägstrich) als Hierarchie-Trennzeichen.</dd>
<dt>qos <span class="property-type">number</span></dt>
<dd>QoS (Quality of Service)<br/>
0: Einmal gesendet ohne Empfangsgarantie (fire und forget)<br/>
1: Garantiert mindestens einmal empfangen (at least once)<br/>
2: Garantiert exakt einmal empfangen (once and once only).</dd>
<dt>retain <span class="property-type">boolean</span></dt>
<dd>Bei <code>true</code> kann es eine aufbewahrte ältere Nachricht sein.</dd>
<dt class="optional">responseTopic <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: MQTT-Antwort-Topic der Nachricht.</dd>
<dt class="optional">correlationData <span class="property-type">buffer</span></dt>
<dd><b>MQTTv5</b>: Korrelationsdaten der Nachricht.</dd>
<dt class="optional">contentType <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: Inhaltstyp der Nutzdaten (Payload).</dd>
<dt class="optional">userProperties <span class="property-type">object</span></dt>
<dd><b>MQTTv5</b>: Alle Benutzer-Eigenschaften der Nachricht.</dd>
<dt class="optional">messageExpiryInterval <span class="property-type">number</span></dt>
<dd><b>MQTTv5</b>: Ablaufzeit der Nachricht in Sekunden.</dd>
</dl>
<h3>Details</h3>
<p>Das abonnierte Topic darf MQTT-Platzhalterzeichen (wildcards) enthalten (+ für eine Ebene und # für mehrere Ebenen).</p>
<p>Dieser Node erfordert eine Verbindung zu einem MQTT-Broker, der über die Auswahlliste selektiert werden kann.
Eine neue Verbindung wird durch Klicken auf das Stiftsymbol erstellt.</p>
<p>Mehrere MQTT-Nodes (in oder out) können bei Bedarf dieselbe Broker-Verbindung nutzen.</p>
</script>
<script type="text/html" data-help-name="mqtt out">
<p>Verbindungsherstellung zu einem MQTT-Broker und publizieren von Topic-Nachrichten.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string | buffer</span></dt>
<dd>Zu publiziernde Nutzdaten.<br/>
Wenn nicht gesetzt wird keine Nachricht gesendet.
Um eine leere Nachricht zu senden, muss eine leere Zeichenfolge (string) übergeben werden.</dd>
<dt class="optional">topic <span class="property-type">string</span></dt>
<dd>MQTT-Topic mit / (Schrägstrich) als Hierarchie-Trennzeichen.</dd>
<dt class="optional">qos <span class="property-type">number</span></dt>
<dd>QoS (Quality of Service)<br/>
0: Einmal gesendet ohne Empfangsgarantie (fire und forget)<br/>
1: Garantiert mindestens einmal empfangen (at least once)<br/>
2: Garantiert exakt einmal empfangen (once and once only).</dd>
<dt class="optional">retain <span class="property-type">boolean</span></dt>
<dd>Bei <code>true</code> wird die Nachricht beim Broker aufbewahrt.
Standard (default) ist <code>false</code>.</dd>
<dt class="optional">responseTopic <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: MQTT-Antwort-Topic für die Nachricht.</dd>
<dt class="optional">correlationData <span class="property-type">buffer</span></dt>
<dd><b>MQTTv5</b>: Korrelationsdaten für die Nachricht.</dd>
<dt class="optional">contentType <span class="property-type">string</span></dt>
<dd><b>MQTTv5</b>: Inhaltstyp der Nutzdaten (Payload).</dd>
<dt class="optional">userProperties <span class="property-type">object</span></dt>
<dd><b>MQTTv5</b>: Alle Benutzer-Eigenschaften der Nachricht.</dd>
<dt class="optional">messageExpiryInterval <span class="property-type">number</span></dt>
<dd><b>MQTTv5</b>: Ablaufzeit der Nachricht in Sekunden.</dd>
<dt class="optional">topicAlias <span class="property-type">number</span></dt>
<dd><b>MQTTv5</b>: Der zu benutzende MQTT-Topic-Alias.</dd>
</dl>
<h3>Details</h3>
<p><code>msg.payload</code> wird als Nutzdaten (Payload) der zu publizierenden Nachricht verwendet.
Wenn es ein Objekt enthält, wird es vorm Senden in eine JSON-Zeichenfolge (string) konvertiert.
Wenn es einen binären Puffer (buffer) enthält, wird die Nachricht unverändert gesendet.</p>
<p>Das Topic kann im Node eingestellt werden oder, falls leer gelassen,
durch <code>msg.topic</code> vorgegeben werden.</p>
<p>Ebenso können die QoS- und Retain-Werte im Node eingestellt werden oder, falls leer gelassen,
durch <code>msg.qos</code> bzw. <code>msg.retain</code> vorgegeben werden.
Um ein beim Broker vorgehaltenes Topic zu löschen,
kann eine leere Nachricht mit dem Topic und Retain gleich <code>true</code> gesendet werden.</p>
<p>Dieser Node erfordert eine Verbindung zu einem MQTT-Broker, der über die Auswahlliste selektiert werden kann.
Eine neue Verbindung wird durch Klicken auf das Stiftsymbol erstellt.</p>
<p>Mehrere MQTT-Nodes (in oder out) können bei Bedarf dieselbe Broker-Verbindung nutzen.</p>
</script>
<script type="text/html" data-help-name="mqtt-broker">
<p>Konfiguration der Verbindung zu einem MQTT-Broker.</p>
<p>Diese Konfiguration erstellt eine einzelne Verbindung zu einem Broker,
welche anschließend von den mqtt&nbsp;in- und
mqtt out-Nodes verwendet werden.</p>
<p>Der Node generiert eine beliebige Client-ID, falls sie nicht vorgegeben ist und der
Node eine bereinigte Sitzung (clean session) verwenden soll.
Wenn eine Client-ID vorgegeben wird, muss sie für den Broker eindeutig sein, zu dem die Verbindung hergestellt werden soll.</p>
<h3>Nachricht bei Verbindungsaufbau</h3>
<p>Diese Nachricht wird vom Broker mit dem eingestellten Topic publiziert, wenn die Verbindung hergestellt wurde.</p>
<h3>Nachricht vor Verbindungsabbau</h3>
<p>Diese Nachricht wird vom Broker mit dem eingestellten Topic publiziert, bevor die Verbindung normal abgebaut wird,
egal ob durch erneute Übernahme (deploy) des Nodes oder durch Herunterfahren von Node-RED.</p>
<h3>Nachricht bei unerwarteten Verbindungsabbruch</h3>
<p>Diese Nachricht wird vom Broker mit dem eingestellten Topic veröffentlicht,
wenn die Verbindung unerwartet abgebrochen ist.</p>
<h3>WebSockets</h3>
<p>Der Node kann für die Verwendung einer WebSocket-Verbindung eingestellt werden.
Dazu ist im Server-Feld die vollständige URI für die Verbindung vorzugeben. Beispiel:</p>
<pre>ws://example.com:4000/mqtt</pre>
</script>
</div><div><!-- --- [red-module:node-red/httpin] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="http in">
<div class="form-row">
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
<select type="text" id="node-input-method" style="width:70%;">
<option value="get">GET</option>
<option value="post">POST</option>
<option value="put">PUT</option>
<option value="delete">DELETE</option>
<option value="patch">PATCH</option>
</select>
</div>
<div class="form-row form-row-http-in-upload hide">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-upload" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-upload" style="width: 70%;" data-i18n="httpin.label.upload"></label>
</div>
<div class="form-row">
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
<input id="node-input-url" type="text" placeholder="/url">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row row-swagger-doc">
<label for="node-input-swaggerDoc"><i class="fa fa-file-text-o"></i> <span data-i18n="httpin.label.doc"></span></label>
<input type="text" id="node-input-swaggerDoc">
</div>
<div id="node-input-tip" class="form-tips"><span data-i18n="httpin.tip.in"></span><code><span id="node-input-path"></span></code>.</div>
</script>
<script type="text/html" data-template-name="http response">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-statusCode"><i class="fa fa-long-arrow-left"></i> <span data-i18n="httpin.label.status"></span></label>
<input type="text" id="node-input-statusCode" placeholder="msg.statusCode">
</div>
<div class="form-row" style="margin-bottom:0;">
<label><i class="fa fa-list"></i> <span data-i18n="httpin.label.headers"></span></label>
</div>
<div class="form-row node-input-headers-container-row">
<ol id="node-input-headers-container"></ol>
</div>
<div class="form-tips"><span data-i18n="[html]httpin.tip.res"></span></div>
</script>
<script type="text/javascript">
(function() {
RED.nodes.registerType('http in',{
category: 'network',
color:"rgb(231, 231, 174)",
defaults: {
name: {value:""},
url: {value:"", required:true,
label:RED._("node-red:httpin.label.url")},
method: {value:"get",required:true},
upload: {value:false},
swaggerDoc: {type:"swagger-doc", required:false}
},
inputs:0,
outputs:1,
icon: "white-globe.svg",
label: function() {
if (this.name) {
return this.name;
} else if (this.url) {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) != "/") {
root = root+"/";
}
if (this.url.charAt(0) == "/") {
root += this.url.slice(1);
} else {
root += this.url;
}
return "["+this.method+"] "+root;
} else {
return "http";
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) == "/") {
root = root.slice(0,-1);
}
if (root == "") {
$("#node-input-tip").hide();
} else {
$("#node-input-path").html(root);
$("#node-input-tip").show();
}
if(!RED.nodes.getType("swagger-doc")){
$('.row-swagger-doc').hide();
}
$("#node-input-method").on("change", function() {
if ($(this).val() === "post") {
$(".form-row-http-in-upload").show();
} else {
$(".form-row-http-in-upload").hide();
}
}).change();
}
});
var headerTypes = [
{value:"content-type",label:"Content-Type",hasValue: false},
{value:"location",label:"Location",hasValue: false},
{value:"other",label:RED._("node-red:httpin.label.other"),icon:"red/images/typedInput/az.svg"}
]
var contentTypes = [
{value:"application/json",label:"application/json",hasValue: false},
{value:"application/xml",label:"application/xml",hasValue: false},
{value:"text/css",label:"text/css",hasValue: false},
{value:"text/html",label:"text/html",hasValue: false},
{value:"text/plain",label:"text/plain",hasValue: false},
{value:"image/gif",label:"image/gif",hasValue: false},
{value:"image/png",label:"image/png",hasValue: false},
{value:"other",label:RED._("node-red:httpin.label.other"),icon:"red/images/typedInput/az.svg"}
];
RED.nodes.registerType('http response',{
category: 'network',
color:"rgb(231, 231, 174)",
defaults: {
name: {value:""},
statusCode: {
value:"",
label: RED._("node-red:httpin.label.status"),
validate: RED.validators.number(true)},
headers: {value:{}}
},
inputs:1,
outputs:0,
align: "right",
icon: "white-globe.svg",
label: function() {
return this.name||("http"+(this.statusCode?" ("+this.statusCode+")":""));
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var headerList = $("#node-input-headers-container").css('min-height','150px').css('min-width','450px').editableList({
addItem: function(container,i,header) {
var row = $('<div/>').css({
overflow: 'hidden',
whiteSpace: 'nowrap',
display: 'flex'
}).appendTo(container);
var propertNameCell = $('<div/>').css({'flex-grow':1}).appendTo(row);
var propertyName = $('<input/>',{class:"node-input-header-name",type:"text", style:"width: 100%"})
.appendTo(propertNameCell)
.typedInput({types:headerTypes});
var propertyValueCell = $('<div/>').css({'flex-grow':1,'margin-left':'10px'}).appendTo(row);
var propertyValue = $('<input/>',{class:"node-input-header-value",type:"text",style:"width: 100%"})
.appendTo(propertyValueCell)
.typedInput({types:
header.h === 'content-type'?contentTypes:[{value:"other",label:"other",icon:"red/images/typedInput/az.svg"}]
});
var matchedType = headerTypes.filter(function(ht) {
return ht.value === header.h
});
if (matchedType.length === 0) {
propertyName.typedInput('type','other');
propertyName.typedInput('value',header.h);
propertyValue.typedInput('value',header.v);
} else {
propertyName.typedInput('type',header.h);
if (header.h === "content-type") {
matchedType = contentTypes.filter(function(ct) {
return ct.value === header.v;
});
if (matchedType.length === 0) {
propertyValue.typedInput('type','other');
propertyValue.typedInput('value',header.v);
} else {
propertyValue.typedInput('type',header.v);
}
} else {
propertyValue.typedInput('value',header.v);
}
}
matchedType = headerTypes.filter(function(ht) {
return ht.value === header.h
});
if (matchedType.length === 0) {
propertyName.typedInput('type','other');
propertyName.typedInput('value',header.h);
} else {
propertyName.typedInput('type',header.h);
}
propertyName.on('change',function(event) {
var type = propertyName.typedInput('type');
if (type === 'content-type') {
propertyValue.typedInput('types',contentTypes);
} else {
propertyValue.typedInput('types',[{value:"other",label:"other",icon:"red/images/typedInput/az.svg"}]);
}
});
},
removable: true
});
if (this.headers) {
for (var key in this.headers) {
if (this.headers.hasOwnProperty(key)) {
headerList.editableList('addItem',{h:key,v:this.headers[key]});
}
}
}
},
oneditsave: function() {
var headers = $("#node-input-headers-container").editableList('items');
var node = this;
node.headers = {};
headers.each(function(i) {
var header = $(this);
var keyType = header.find(".node-input-header-name").typedInput('type');
var keyValue = header.find(".node-input-header-name").typedInput('value');
var valueType = header.find(".node-input-header-value").typedInput('type');
var valueValue = header.find(".node-input-header-value").typedInput('value');
var key = keyType;
var value = valueType;
if (keyType === 'other') {
key = keyValue;
}
if (valueType === 'other') {
value = valueValue;
}
if (key !== '') {
node.headers[key] = value;
}
});
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-headers-container-row)");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-headers-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("#node-input-headers-container").editableList('height',height);
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="http in">
<p>Erstellung eines HTTP-Endpunktes zur Erzeugung von Web-Diensten.</p>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload</dt>
<dd>Für eine GET-Anforderung enthält es ein Objekt aller Abfrage-Parameter (query string parameters).
Ansonsten enthält es den Hauptteil (Body) der HTTP-Anforderung.</dd>
<dt>req <span class="property-type">object</span></dt>
<dd>HTTP Anforderungsobjekt.<br/>
Es enthält mehrere Eigenschaften, die Informationen zu der Anforderung bereitstellen.
<ul>
<li><code>body</code>: Hauptteil der eingehenden Anforderung. Das Format hängt von der Anforderung ab.</li>
<li><code>headers</code>: Objekt mit HTTP-Request-Header</li>
<li><code>query</code>: Objekt mit Anfrage-Parametern (query string parameters)</li>
<li><code>params</code>: Objekt mit den Routing-Parametern</li>
<li><code>cookies</code>: Objekt mit den Cookies der Anfrage</li>
<li><code>files</code>: Objekt mit allen Dateien, die mit der POST-Anforderung gesendet wurden, sofern im Node aktiviert</li>
</ul>
</dd>
<dt>res <span class="property-type">object</span></dt>
<dd>HTTP-Antwortobjekt.<br/>
Diese Eigenschaft sollte nicht direkt verwendet werden.
Im http&nbsp;response-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
Diese Eigenschaft muss an der Nachricht angehängt bleiben, die an den Antwort-Node übergeben wird.</dd>
</dl>
<h3>Details</h3>
<p>Der Node ist auf dem eingestellten Pfad für Anforderungen eines bestimmten Typs empfangsbereit.
Der Pfad kann vollständig angegeben werden, z.B. <code>/user</code> oder benannte Parameter beinhalten,
die einen beliebigen Wert akzeptieren, z.B. <code>/user/:name</code>.
Wenn benannte Parameter verwendet werden, kann auf ihren aktuellen Wert über <code>msg.req.params</code>
zugegriffen werden.</p>
<p>Für Anforderungen, die einen Hauptteil (Body) enthalten, wie z.B. POST oder PUT, wird der Inhalt der
Anforderung über <code>msg.payload</code> verfügbar gemacht.</p>
<p>Wenn der Inhaltstyp der Anforderung ermittelt werden kann, wird der Hauptteil als passender Typ analysiert.
Z.B. <code>application/json</code> wird zu einem JavaScript-Objekt analysiert.</p>
<p><b>Hinweis</b>: Dieser Node sendet keine Antwort an die Anforderung.
Der Flow muss einen http&nbsp;response-Node enthalten,
um die Anforderung zu vervollständigen.</p>
</script>
<script type="text/html" data-help-name="http response">
<p>Senden von Antworten auf Anforderungen, die von einem http&nbsp;in-Node empfangen wurden.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string</span></dt>
<dd>Hauptteil (Body) der Antwort.</dd>
<dt class="optional">statusCode <span class="property-type">number</span></dt>
<dd>Wenn gesetzt, wird diese als Antwort-Statuscode verwendet. Standardwert: 200.</dd>
<dt class="optional">headers <span class="property-type">object</span></dt>
<dd>Wenn gesetzt, enthält es die HTTP-Header für die Antwort.</dd>
<dt class="optional">cookies <span class="property-type">object</span></dt>
<dd>Wenn gesetzt, kann es zum Setzen oder Löschen von Cookies verwendet werden.</dd>
</dl>
<h3>Details</h3>
<p>Der <code>statusCode</code> und die <code>headers</code> können auch innerhalb des Node angegeben werden.
Wenn eine Eigenschaft innerhalb des Nodes angegeben ist,
kann sie nicht durch die entsprechende Nachrichteneigenschaft überschrieben werden.</p>
<h4><b>Cookie-Behandlung</b></h4>
<p>Die <code>cookies</code>-Eigenschaft muss ein Objekt mit Name/Wert-Paaren sein.
Bei dem Wert kann es sich entweder um eine Zeichenfolge (string) zur Festlegung des Cookies mit Standardwerten handeln
oder es kann ein Objekt mit Optionen sein.</p>
<p>Im folgenden Beispiel werden zwei Cookies festgelegt - einer mit dem Namen <code>name</code> und dem
Wert <code>nick</code> und der andere <code>session</code> mit dem Wert
<code>1234</code> und einer festgelegten Ablaufzeit von 15 Minuten.</p>
<pre>
msg.cookies = {
name: 'nick',
session: {
value: '1234',
maxAge: 900000
}
}</pre>
<p>Die gültigen Optionen sind:</p>
<ul>
<li><code>domain</code>: Domänenname für das Cookie, angegeben als Zeichenfolge (string)</li>
<li><code>expires</code>: Ablaufzeit in GMT. Wenn nicht vorgeben oder Null (0), wird ein Sitzungscookie erstellt.</li>
<li><code>maxAge</code>: Ablaufzeit in Bezug auf die aktuelle Zeit in Millisekunden, angegeben als Zeichenfolge (string)</li>
<li><code>path</code>: Pfad für das Cookie. Standardwert: / (Schrägstrich), angegeben als Zeichenfolge (string)</li>
<li><code>value</code>: Wert, der für das Cookie verwendet werden soll, angegeben als Zeichenfolge (string)</li>
</ul>
<p>Um ein Cookie zu löschen, ist sein <code>value</code> auf <code>null</code> zu setzen.</p>
</script>
</div><div><!-- --- [red-module:node-red/httprequest] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="http request">
<div class="form-row">
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
<select type="text" id="node-input-method" style="width:70%;">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="HEAD">HEAD</option>
<option value="use" data-i18n="httpin.setby"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
<input id="node-input-url" type="text" placeholder="http://">
</div>
<div class="form-row node-input-paytoqs-row">
<label for="node-input-paytoqs"><span data-i18n="common.label.payload"></span></label>
<select id="node-input-paytoqs" style="width: 70%;">
<option value="ignore" data-i18n="httpin.label.paytoqs.ignore"></option>
<option value="query" data-i18n="httpin.label.paytoqs.query"></option>
<option value="body" data-i18n="httpin.label.paytoqs.body"></option>
</select>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
<div id="node-row-tls" class="hide">
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
</div>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-useAuth" style="width: 70%;"><span data-i18n="httpin.basicauth"></span></label>
<div style="margin-left: 20px" class="node-input-useAuth-row hide">
<div class="form-row">
<label for="node-input-authType-select"><i class="fa fa-user-secret "></i> <span data-i18n="httpin.label.authType"></span></label>
<select type="text" id="node-input-authType-select" style="width:70%;">
<option value="basic" data-i18n="httpin.basic"></option>
<option value="digest" data-i18n="httpin.digest"></option>
<option value="bearer" data-i18n="httpin.bearer"></option>
</select>
<input type="hidden" id="node-input-authType">
</div>
<div class="form-row node-input-basic-row">
<label for="node-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
<input type="text" id="node-input-user">
</div>
<div class="form-row">
<label for="node-input-password"> <i class="fa fa-lock"></i> <span data-i18n="common.label.password" id="node-span-password"></span><span data-i18n="httpin.label.bearerToken" id="node-span-token" style="display:none"></span></label>
<input type="password" id="node-input-password">
</div>
</div>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-persist" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-persist" style="width: auto" data-i18n="httpin.persist"></label>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-useProxy" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-useProxy" style="width: auto;"><span data-i18n="httpin.use-proxy"></span></label>
<div id="node-input-useProxy-row" class="hide">
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-proxy"><i class="fa fa-globe"></i> <span data-i18n="httpin.proxy-config"></span></label><input type="text" style="width: 270px" id="node-input-proxy">
</div>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-senderr" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-senderr" style="width: auto" data-i18n="httpin.senderr"></label>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-insecureHTTPParser" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-insecureHTTPParser", style="width: auto;" data-i18n="httpin.insecureHTTPParser"></label>
</div>
<div class="form-row">
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
<select type="text" id="node-input-ret" style="width:70%;">
<option value="txt" data-i18n="httpin.utf8"></option>
<option value="bin" data-i18n="httpin.binary"></option>
<option value="obj" data-i18n="httpin.json"></option>
</select>
</div>
<div class="form-row form-tips" id="tip-json" hidden><span data-i18n="httpin.tip.req"></span></div>
<div class="form-row" style="margin-bottom:0;">
<label><i class="fa fa-list"></i> <span data-i18n="httpin.label.headers"></span></label>
</div>
<div class="form-row node-input-headers-container-row">
<ol id="node-input-headers-container"></ol>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
(function() {
const headerTypes = [
{ value: "Accept", label: "Accept", hasValue: false },
{ value: "Accept-Encoding", label: "Accept-Encoding", hasValue: false },
{ value: "Accept-Language", label: "Accept-Language", hasValue: false },
{ value: "Authorization", label: "Authorization", hasValue: false },
{ value: "Content-Type", label: "Content-Type", hasValue: false },
{ value: "Cache-Control", label: "Cache-Control", hasValue: false },
{ value: "User-Agent", label: "User-Agent", hasValue: false },
{ value: "Location", label: "Location", hasValue: false },
{ value: "other", label: RED._("node-red:httpin.label.other"),
hasValue: true, icon: "red/images/typedInput/az.svg" },
{ value: "msg", label: "msg.", hasValue: true },
]
const headerOptions = {};
const defaultOptions = [
{ value: "other", label: RED._("node-red:httpin.label.other"),
hasValue: true, icon: "red/images/typedInput/az.svg" },
{ value: "msg", label: "msg.", hasValue: true },
];
headerOptions["accept"] = [
{ value: "text/plain", label: "text/plain", hasValue: false },
{ value: "text/html", label: "text/html", hasValue: false },
{ value: "application/json", label: "application/json", hasValue: false },
{ value: "application/xml", label: "application/xml", hasValue: false },
...defaultOptions,
];
headerOptions["accept-encoding"] = [
{ value: "gzip", label: "gzip", hasValue: false },
{ value: "deflate", label: "deflate", hasValue: false },
{ value: "compress", label: "compress", hasValue: false },
{ value: "br", label: "br", hasValue: false },
{ value: "gzip, deflate", label: "gzip, deflate", hasValue: false },
{ value: "gzip, deflate, br", label: "gzip, deflate, br", hasValue: false },
...defaultOptions,
];
headerOptions["accept-language"] = [
{ value: "*", label: "*", hasValue: false },
{ value: "en-GB, en-US, en;q=0.9", label: "en-GB, en-US, en;q=0.9", hasValue: false },
{ value: "de-AT, de-DE;q=0.9, en;q=0.5", label: "de-AT, de-DE;q=0.9, en;q=0.5", hasValue: false },
{ value: "es-mx,es,en;q=0.5", label: "es-mx,es,en;q=0.5", hasValue: false },
{ value: "fr-CH, fr;q=0.9, en;q=0.8", label: "fr-CH, fr;q=0.9, en;q=0.8", hasValue: false },
{ value: "zh-CN, zh-TW; q = 0.9, zh-HK; q = 0.8, zh; q = 0.7, en; q = 0.6", label: "zh-CN, zh-TW; q = 0.9, zh-HK; q = 0.8, zh; q = 0.7, en; q = 0.6", hasValue: false },
{ value: "ja-JP, jp", label: "ja-JP, jp", hasValue: false },
...defaultOptions,
];
headerOptions["content-type"] = [
{ value: "text/css", label: "text/css", hasValue: false },
{ value: "text/plain", label: "text/plain", hasValue: false },
{ value: "text/html", label: "text/html", hasValue: false },
{ value: "application/json", label: "application/json", hasValue: false },
{ value: "application/octet-stream", label: "application/octet-stream", hasValue: false },
{ value: "application/pdf", label: "application/pdf", hasValue: false },
{ value: "application/xml", label: "application/xml", hasValue: false },
{ value: "application/zip", label: "application/zip", hasValue: false },
{ value: "multipart/form-data", label: "multipart/form-data", hasValue: false },
{ value: "audio/aac", label: "audio/aac", hasValue: false },
{ value: "audio/ac3", label: "audio/ac3", hasValue: false },
{ value: "audio/basic", label: "audio/basic", hasValue: false },
{ value: "audio/mp4", label: "audio/mp4", hasValue: false },
{ value: "audio/ogg", label: "audio/ogg", hasValue: false },
{ value: "image/bmp", label: "image/bmp", hasValue: false },
{ value: "image/gif", label: "image/gif", hasValue: false },
{ value: "image/jpeg", label: "image/jpeg", hasValue: false },
{ value: "image/png", label: "image/png", hasValue: false },
{ value: "image/tiff", label: "image/tiff", hasValue: false },
...defaultOptions,
];
headerOptions["cache-control"] = [
{ value: "max-age=0", label: "max-age=0", hasValue: false },
{ value: "max-age=86400", label: "max-age=86400", hasValue: false },
{ value: "no-cache", label: "no-cache", hasValue: false },
...defaultOptions,
];
headerOptions["user-agent"] = [
{ value: "Mozilla/5.0", label: "Mozilla/5.0", hasValue: false },
...defaultOptions,
];
function getHeaderOptions(headerName) {
const lc = (headerName || "").toLowerCase();
let opts = headerOptions[lc];
return opts || defaultOptions;
}
RED.nodes.registerType('http request',{
category: 'network',
color:"rgb(231, 231, 174)",
defaults: {
name: {value:""},
method:{value:"GET"},
ret: {value:"txt"},
paytoqs: {value: false},
url:{
value:"",
validate: function(v, opt) {
if ((v.trim().length === 0) ||
(v.indexOf("://") === -1) ||
(v.trim().indexOf("http") === 0)) {
return true;
}
return RED._("node-red:httpin.errors.invalid-url");
}
},
tls: {type:"tls-config",required: false,
label:RED._("node-red:httpin.tls-config") },
persist: {value:false},
proxy: {type:"http proxy",required: false,
label:RED._("node-red:httpin.proxy-config") },
insecureHTTPParser: {value: false},
authType: {value: ""},
senderr: {value: false},
headers: { value: [] }
},
credentials: {
user: {type:"text"},
password: {type: "password"}
},
inputs:1,
outputs:1,
outputLabels: function(i) {
return ({
txt: this._("httpin.label.utf8String"),
bin: this._("httpin.label.binaryBuffer"),
obj: this._("httpin.label.jsonObject")
}[this.ret]);
},
icon: "white-globe.svg",
label: function() {
return this.name||this._("httpin.httpreq");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
const node = this;
$("#node-input-useAuth").on("change", function() {
if ($(this).is(":checked")) {
$(".node-input-useAuth-row").show();
// Nodes (< version 0.20.x) with credentials but without authentication type, need type 'basic'
if (!$('#node-input-authType').val()) {
$("#node-input-authType-select").val('basic').trigger("change");
}
} else {
$(".node-input-useAuth-row").hide();
$('#node-input-authType').val('');
$('#node-input-user').val('');
$('#node-input-password').val('');
}
RED.tray.resize();
});
$("#node-input-authType-select").on("change", function() {
const val = $(this).val();
$("#node-input-authType").val(val);
if (val === "basic" || val === "digest") {
$(".node-input-basic-row").show();
$('#node-span-password').show();
$('#node-span-token').hide();
} else if (val === "bearer") {
$(".node-input-basic-row").hide();
$('#node-span-password').hide();
$('#node-span-token').show();
$('#node-input-user').val('');
}
RED.tray.resize();
});
$("#node-input-method").on("change", function() {
if ($(this).val() == "GET") {
$(".node-input-paytoqs-row").show();
} else {
$(".node-input-paytoqs-row").hide();
}
RED.tray.resize();
});
if (node.paytoqs === true || node.paytoqs == "query") {
$("#node-input-paytoqs").val("query");
} else if (node.paytoqs === "body") {
$("#node-input-paytoqs").val("body");
} else {
$("#node-input-paytoqs").val("ignore");
}
if (node.authType) {
$('#node-input-useAuth').prop('checked', true);
$("#node-input-authType-select").val(node.authType);
$("#node-input-authType-select").change();
} else {
$('#node-input-useAuth').prop('checked', false);
}
$("#node-input-useAuth").change();
function updateTLSOptions() {
if ($("#node-input-usetls").is(':checked')) {
$("#node-row-tls").show();
} else {
$("#node-row-tls").hide();
}
RED.tray.resize();
}
if (node.tls) {
$('#node-input-usetls').prop('checked', true);
} else {
$('#node-input-usetls').prop('checked', false);
}
updateTLSOptions();
$("#node-input-usetls").on("click",function() {
updateTLSOptions();
});
function updateProxyOptions() {
if ($("#node-input-useProxy").is(":checked")) {
$("#node-input-useProxy-row").show();
} else {
$("#node-input-useProxy-row").hide();
}
RED.tray.resize();
}
if (node.proxy) {
$("#node-input-useProxy").prop("checked", true);
} else {
$("#node-input-useProxy").prop("checked", false);
}
if (node.insecureHTTPParser) {
$("node-intput-insecureHTTPParser").prop("checked", true)
} else {
$("node-intput-insecureHTTPParser").prop("checked", false)
}
updateProxyOptions();
$("#node-input-useProxy").on("click", function() {
updateProxyOptions();
});
$("#node-input-ret").on("change", function() {
if ($("#node-input-ret").val() === "obj") {
$("#tip-json").show();
} else {
$("#tip-json").hide();
}
RED.tray.resize();
});
const hasMatch = function (arr, value) {
return arr.some(function (ht) {
return ht.value === value
});
}
const headerList = $("#node-input-headers-container").css('min-height', '150px').css('min-width', '450px').editableList({
addItem: function (container, i, header) {
const row = $('<div/>').css({
overflow: 'hidden',
whiteSpace: 'nowrap',
display: 'flex'
}).appendTo(container);
const propertNameCell = $('<div/>').css({ 'flex-grow': 1 }).appendTo(row);
const propertyName = $('<input/>', { class: "node-input-header-name", type: "text", style: "width: 100%" })
.appendTo(propertNameCell)
.typedInput({ types: headerTypes });
const propertyValueCell = $('<div/>').css({ 'flex-grow': 1, 'margin-left': '10px' }).appendTo(row);
const propertyValue = $('<input/>', { class: "node-input-header-value", type: "text", style: "width: 100%" })
.appendTo(propertyValueCell)
.typedInput({
types: getHeaderOptions(header.keyType)
});
const setup = function(_header) {
const headerTypeIsAPreset = function(h) {return hasMatch(headerTypes, h) };
const headerValueIsAPreset = function(h, v) {return hasMatch(getHeaderOptions(h), v) };
const {keyType, keyValue, valueType, valueValue} = header;
if(keyType == "msg" || keyType == "other") {
propertyName.typedInput('type', keyType);
propertyName.typedInput('value', keyValue);
} else if (headerTypeIsAPreset(keyType)) {
propertyName.typedInput('type', keyType);
} else {
propertyName.typedInput('type', "other");
propertyName.typedInput('value', keyValue);
}
if(valueType == "msg" || valueType == "other") {
propertyValue.typedInput('type', valueType);
propertyValue.typedInput('value', valueValue);
} else if (headerValueIsAPreset(propertyName.typedInput('type'), valueType)) {
propertyValue.typedInput('type', valueType);
} else {
propertyValue.typedInput('type', "other");
propertyValue.typedInput('value', valueValue);
}
}
setup(header);
propertyName.on('change', function (event) {
propertyValue.typedInput('types', getHeaderOptions(propertyName.typedInput('type')));
});
},
removable: true
});
if (node.headers) {
for (let index = 0; index < node.headers.length; index++) {
const element = node.headers[index];
headerList.editableList('addItem', node.headers[index]);
}
}
},
oneditsave: function() {
if (!$("#node-input-usetls").is(':checked')) {
$("#node-input-tls").val("_ADD_");
}
if (!$("#node-input-useProxy").is(":checked")) {
$("#node-input-proxy").val("_ADD_");
}
const headers = $("#node-input-headers-container").editableList('items');
const node = this;
node.headers = [];
headers.each(function(i) {
const header = $(this);
const keyType = header.find(".node-input-header-name").typedInput('type');
const keyValue = header.find(".node-input-header-name").typedInput('value');
const valueType = header.find(".node-input-header-value").typedInput('type');
const valueValue = header.find(".node-input-header-value").typedInput('value');
if (keyType !== '' || keyType === 'other' || keyType === 'msg') {
node.headers.push({
keyType, keyValue, valueType, valueValue
})
}
});
},
oneditresize: function(size) {
const dlg = $("#dialog-form");
const expandRow = dlg.find('.node-input-headers-container-row');
let height = dlg.height() - 5;
if(expandRow && expandRow.length){
const siblingRows = dlg.find('> .form-row:not(.node-input-headers-container-row)');
for (let i = 0; i < siblingRows.size(); i++) {
const cr = $(siblingRows[i]);
if(cr.is(":visible"))
height -= cr.outerHeight(true);
}
$("#node-input-headers-container").editableList('height',height);
}
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="http request">
<p>Senden von HTTP-Anforderungen und Rückgabe der Antwort.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">url <span class="property-type">string</span></dt>
<dd>Wenn nicht im Node eingestellt, setzt diese optionale Eigenschaft die URL der Anforderung.</dd>
<dt class="optional">method <span class="property-type">string</span></dt>
<dd>Wenn nicht im Node eingestellt, setzt diese optionale Eigenschaft die HTTP-Methode der Anforderung
(<code>GET</code>, <code>PUT</code>, <code>POST</code>, <code>PATCH</code> oder <code>DELETE</code>).</dd>
<dt class="optional">headers <span class="property-type">object</span></dt>
<dd>HTTP-Header der Anforderung.</dd>
<dt class="optional">cookies <span class="property-type">object</span></dt>
<dd>Wenn gesetzt, kann es verwendet werden, um Cookies mit der Anforderung zu senden.</dd>
<dt class="optional">payload</dt>
<dd>Hauptteil der Anforderung.</dd>
<dt class="optional">rejectUnauthorized</dt>
<dd>Wenn auf <code>false</code> gesetzt, können Anforderungen an https-Sites gesendet werden, die selbst signierte Zertifikate verwenden.</dd>
<dt class="optional">followRedirects</dt>
<dd>Wenn auf <code>false</code> gesetzt, wird ein nachfolgendes Redirect (HTTP 301) verhindert.
Standard ist <code>true</code>.</dd>
<dt class="optional">requestTimeout</dt>
<dd>Wenn dieser Wert auf eine positive Zahl eingestellt ist,
wird damit der global eingestellte Parameter <code>httpRequestTimeout</code> überschrieben.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string | object | buffer</span></dt>
<dd>Hauptteil der Antwort.<br/>
Der Node kann eingestellt werden, um den Hauptteil als String zurückzugeben,
zu versuchen, ihn als JSON-String zu analysieren oder ihn als binären Puffer (buffer) zu belassen.</dd>
<dt>statusCode <span class="property-type">number</span></dt>
<dd>Statuscode der Antwort oder der Fehlercode, wenn die Anforderung nicht abgeschlossen werden konnte.</dd>
<dt>headers <span class="property-type">object</span></dt>
<dd>Objekt mit dem HTTP-Header der Antwort.</dd>
<dt>responseUrl <span class="property-type">string</span></dt>
<dd>Falls während der Bearbeitung der Anforderung Umleitungen aufgetreten sind, ist diese Eigenschaft die letzte umgelenkte URL.
Andernfalls die URL der ursprünglichen Anforderung.</dd>
<dt>responseCookies <span class="property-type">object</span></dt>
<dd>Wenn die Antwort Cookies enthält, ist dieses Element ein Objekt von Name/Wert-Paaren für jedes Cookie.</dd>
</dl>
<h3>Details</h3>
<p>Wenn innerhalb des Nodes eingestellt, kann die URL-Eigenschaft
<a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache-style</a>-Tags enthalten.
Diese ermöglichen es, die URL aus den Werten der eingehenden Nachricht aufzubauen.
Wenn die URL beispielsweise <code>example.com/{{{topic}}}</code> lautet,
wird der Wert von <code>msg.topic</code> automatisch eingefügt.
Die Verwendung von {{{...}} hindert Mustache am Escaping von Zeichen wie z.B. / & usw.</p>
<p><b>Hinweis</b>: Wenn Node-RED hinter einem Proxy läuft, sollte die Umgebungsvariable <code>http_proxy=...</code>
gesetzt und Node-RED neu gestartet werden.
Alternativ kann eine Proxy-Konfiguration verwendet werden, die dann Vorrang vor der Umgebungsvariable hat.</p>
<h4><b>Verwendung mehrerer HTTP-Anforderungs-Nodes</b></h4>
<p>Um mehr als einen dieser Nodes im gleichen Flow verwenden zu können,
ist Aufmerksamkeit bei der Verwendung der <code>msg.headers</code>-Eigenschaft gefordert.
Der erste Node setzt diese Eigenschaft mit dem Antwort-Header.
Der nächste Node verwendet dann diesen Header für seine Anfrage, was aber nicht die richtige Art und Weise ist.
Wenn die <code>msg.headers</code>-Eigenschaft zwischen den Nodes unverändert bleibt, wird sie vom zweiten Node ignoriert.
Um benutzerdefinierte Header festzulegen, sollte <code>msg.headers</code> zuerst gelöscht oder
auf ein leeres Objekt gesetzt werden: <code>{}</code></p>
<h4><b>Behandlung von Cookies</b></h4>
<p>Die an den Node übergebene <code>cookies</code>-Eigenschaft muss ein Objekt von Name/Wert-Paaren sein.
Der Wert kann entweder ein String sein, um den Wert des Cookies zu setzen,
oder es kann ein Objekt mit einer einzigen <code>value</code>-Eigenschaft sein.<p>
<p>Alle auf Anforderung zurückgegebene Cookies werden über die <code>responseCookies</code>-Eigenschaft zurückgegeben.</p>
<h4><b>Behandlung von Content-Typen</b></h4>
<p>Wenn <code>msg.payload</code> ein Objekt ist, setzt der Node automatisch den Inhaltstyp der Anforderung
auf <code>application/json</code> und kodiert den Hauptteil als solchen.</p>
<p>Um die Anforderung als Formulardaten zu kodieren, sollte <code>msg.headers["content-type"]</code> auf
<code>application/x-wwww-form-urlencoded</code> gesetzt werden.</p>
<h4><b>Datei-Upload</b></h4>
<p>Um einen Datei-Upload umzusetzen, sollte <code>msg.headers["content-type"]</code> auf <code>multipart/form-data</code>
gesetzt werden und das an den Node zu sendende <code>msg.payload</code> muss ein Objekt mit folgender Struktur sein:</p>
<pre><code>{
"KEY": {
"value": FILE_CONTENTS,
"options": {
"filename": "FILENAME"
}
}
}</code></pre>
<p>Die Inhalte von <code>KEY</code>, <code>FILE_CONTENTS</code> und <code>FILENAME</code>
sollten auf passende Werte gesetzt sein.</p>
</script>
</div><div><!-- --- [red-module:node-red/websocket] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- WebSocket Input Node -->
<script type="text/html" data-template-name="websocket in">
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> <span data-i18n="websocket.label.type"></span></label>
<select id="node-input-mode">
<option value="server" data-i18n="websocket.listenon"></option>
<option value="client" data-i18n="websocket.connectto"></option>
</select>
</div>
<div class="form-row" id="websocket-server-row">
<label for="node-input-server"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
<input type="text" id="node-input-server">
</div>
<div class="form-row" id="websocket-client-row">
<label for="node-input-client"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input type="text" id="node-input-client">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
(function() {
function ws_oneditprepare() {
$("#websocket-client-row").hide();
$("#node-input-mode").on("change", function() {
if ( $("#node-input-mode").val() === 'client') {
$("#websocket-server-row").hide();
$("#websocket-client-row").show();
}
else {
$("#websocket-server-row").show();
$("#websocket-client-row").hide();
}
});
if (this.client) {
$("#node-input-mode").val('client').change();
}
else {
$("#node-input-mode").val('server').change();
}
}
function ws_oneditsave() {
if ($("#node-input-mode").val() === 'client') {
$("#node-input-server").append('<option value="">Dummy</option>');
$("#node-input-server").val('');
}
else {
$("#node-input-client").append('<option value="">Dummy</option>');
$("#node-input-client").val('');
}
}
function ws_label() {
var nodeid = (this.client)?this.client:this.server;
var wsNode = RED.nodes.node(nodeid);
return this.name||(wsNode?"[ws] "+wsNode.label():"websocket");
}
function ws_validateserver() {
if ($("#node-input-mode").val() === 'client' || (this.client && !this.server)) {
return true;
}
else {
if (RED.nodes.node(this.server) != null) {
return true;
}
return RED._("node-red:websocket.errors.missing-server");
}
}
function ws_validateclient() {
if ($("#node-input-mode").val() === 'client' || (this.client && !this.server)) {
if (RED.nodes.node(this.client) != null) {
return true;
}
return RED._("node-red:websocket.errors.missing-client");
}
else {
return true;
}
}
RED.nodes.registerType('websocket in',{
category: 'network',
defaults: {
name: {value:""},
server: {type:"websocket-listener", validate: ws_validateserver},
client: {type:"websocket-client", validate: ws_validateclient}
},
color:"rgb(215, 215, 160)",
inputs:0,
outputs:1,
icon: "white-globe.svg",
labelStyle: function() {
return this.name?"node_label_italic":"";
},
label: ws_label,
oneditsave: ws_oneditsave,
oneditprepare: ws_oneditprepare
});
RED.nodes.registerType('websocket out',{
category: 'network',
defaults: {
name: {value:""},
server: {type:"websocket-listener", validate: ws_validateserver},
client: {type:"websocket-client", validate: ws_validateclient}
},
color:"rgb(215, 215, 160)",
inputs:1,
outputs:0,
icon: "white-globe.svg",
align: "right",
labelStyle: function() {
return this.name?"node_label_italic":"";
},
label: ws_label,
oneditsave: ws_oneditsave,
oneditprepare: ws_oneditprepare
});
RED.nodes.registerType('websocket-listener',{
category: 'config',
defaults: {
path: {value:"",required:true,
label:RED._("node-red:websocket.label.path"),
validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/)},
wholemsg: {value:"false"}
},
inputs:0,
outputs:0,
label: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) != "/") {
root = root+"/";
}
if (this.path) {
if (this.path.charAt(0) == "/") {
root += this.path.slice(1);
} else {
root += this.path;
}
}
return root;
},
oneditprepare: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) == "/") {
root = root.slice(0,-1);
}
if (root === "") {
$("#node-config-ws-tip").hide();
} else {
$("#node-config-ws-path").html(RED._("node-red:websocket.tip.path2", { path: root }));
$("#node-config-ws-tip").show();
}
}
});
RED.nodes.registerType('websocket-client',{
category: 'config',
defaults: {
path: {
value:"",required:true,
label:RED._("node-red:websocket.label.path"),
validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/)},
tls: {type:"tls-config",required: false},
wholemsg: {value:"false"},
hb: {
value: "",
label:RED._("node-red:websocket.sendheartbeat"),
validate: RED.validators.number(/*blank allowed*/true) },
subprotocol: {value:"",required: false}
},
inputs:0,
outputs:0,
label: function() {
return this.path;
},
oneditprepare: function() {
$("#node-config-input-path").on("change keyup paste",function() {
$(".node-config-row-tls").toggle(/^wss:/i.test($(this).val()))
});
$("#node-config-input-path").change();
var heartbeatActive = (this.hb && this.hb != "0");
$("#node-config-input-hb-cb").prop("checked",heartbeatActive);
$("#node-config-input-hb-cb").on("change", function(evt) {
$("#node-config-input-hb-row").toggle(this.checked);
})
$("#node-config-input-hb-cb").trigger("change");
if (!heartbeatActive) {
$("#node-config-input-hb").val("");
}
},
oneditsave: function() {
if (!/^wss:/i.test($("#node-config-input-path").val())) {
$("#node-config-input-tls").val("_ADD_");
}
if (!$("#node-config-input-hb-cb").prop("checked")) {
$("#node-config-input-hb").val("0");
}
}
});
})();
</script>
<!-- WebSocket out Node -->
<script type="text/html" data-template-name="websocket out">
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> <span data-i18n="websocket.label.type"></span></label>
<select id="node-input-mode">
<option value="server" data-i18n="websocket.listenon"></option>
<option value="client" data-i18n="websocket.connectto"></option>
</select>
</div>
<div class="form-row" id="websocket-server-row">
<label for="node-input-server"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
<input type="text" id="node-input-server">
</div>
<div class="form-row" id="websocket-client-row">
<label for="node-input-client"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input type="text" id="node-input-client">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<!-- WebSocket Server configuration node -->
<script type="text/html" data-template-name="websocket-listener">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
<input id="node-config-input-path" type="text" placeholder="/ws/example">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg" data-i18n="websocket.sendrec"></label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false" data-i18n="websocket.payload"></option>
<option value="true" data-i18n="websocket.message"></option>
</select>
</div>
<div class="form-tips">
<span data-i18n="[html]websocket.tip.path1"></span>
<p id="node-config-ws-tip"><span id="node-config-ws-path"></span></p>
</div>
</script>
<!-- WebSocket Client configuration node -->
<script type="text/html" data-template-name="websocket-client">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input id="node-config-input-path" type="text" placeholder="ws://example.com/ws">
</div>
<div class="form-row node-config-row-tls hide">
<label for="node-config-input-tls" data-i18n="httpin.tls-config"></label>
<input type="text" id="node-config-input-tls">
</div>
<div class="form-row">
<label for="node-config-input-subprotocol"><i class="fa fa-tag"></i> <span data-i18n="websocket.label.subprotocol"></span></label>
<input type="text" id="node-config-input-subprotocol">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg" data-i18n="websocket.sendrec"></label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false" data-i18n="websocket.payload"></option>
<option value="true" data-i18n="websocket.message"></option>
</select>
</div>
<div class="form-row" style="display: flex; align-items: center; min-height: 34px">
<label for="node-config-input-hb-cb" data-i18n="websocket.sendheartbeat"></label>
<input type="checkbox" style="margin: 0 8px; width:auto" id="node-config-input-hb-cb">
<span id="node-config-input-hb-row" class="hide" >
<input type="text" style="width: 70px; margin-right: 3px" id="node-config-input-hb">
<span data-i18n="inject.seconds"></span>
</span>
</div>
<div class="form-tips">
<p><span data-i18n="[html]websocket.tip.url1"></span></p>
<span data-i18n="[html]websocket.tip.url2"></span>
</div>
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="websocket in">
<p>WebSocket-Eingangs-Node.</p>
<p>Standardmäßig befinden sich die vom WebSocket empfangenen Daten in <code>msg.payload</code>.
Der Socket kann eingestellt werden, einen korrekt gebildeten JSON-Zeichenfolge (string) zu erwarten.
In diesem Fall wird das JSON analysiert (parse) und das resultierende Objekt als gesamte Nachricht gesendet.</p>
</script>
<script type="text/html" data-help-name="websocket out">
<p>WebSocket-Ausgang-Node.</p>
<p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet.
Der Socket kann eingestellt werden, das gesamte <code>msg</code>-Objekt als JSON-Zeichenfolge (string) zu kodieren und
über den WebSocket zu senden.</p>
<p>Wenn die an diesem Node ankommende Nachricht von einem WebSocket-Eingangs-Node ausgeht,
wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat.
Andernfalls wird die Nachricht an alle verbundenen Clients gesendet.</p>
<p>Wenn eine von einem WebSocket-Eingangs-Node ausgehende Nachricht an alle verbundenen Clients gesendet werden soll,
muss die <code>msg._session</code>-Eigenschaft im Flow gelöscht werden.</p>
</script>
<script type="text/html" data-help-name="websocket-listener">
<p>Konfigurations-Node zur Erstellung eines WebSocket-Server-Endpunktes mit vorgegebenen Pfad.</p>
</script>
<script type="text/html" data-help-name="websocket-client">
<p>Konfigurations-Node zur Verbindung eines WebSocket-Clients mit vorgegebener URL.</p>
</script>
</div><div><!-- --- [red-module:node-red/tcpin] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="tcp in">
<div class="form-row">
<label for="node-input-server"><i class="fa fa-dot-circle-o"></i> <span data-i18n="tcpin.label.type"></span></label>
<select id="node-input-server" style="width:120px; margin-right:5px;">
<option value="server" data-i18n="tcpin.type.listen"></option>
<option value="client" data-i18n="tcpin.type.connect"></option>
</select>
<span data-i18n="tcpin.label.port"></span> <input type="text" id="node-input-port" style="width:65px">
</div>
<div class="form-row hidden" id="node-input-host-row" style="padding-left:110px;">
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
</div>
<div class="form-row" id="node-input-tls-enable">
<label> </label>
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width:auto; vertical-align:top;">
<label for="node-input-usetls" style="width:auto" data-i18n="httpin.use-tls"></label>
<div id="node-row-tls" class="hide">
<label style="width:auto; margin-left:20px; margin-right:10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
</div>
</div>
<div class="form-row">
<label><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.output"></span></label>
<select id="node-input-datamode" style="width:110px;">
<option value="stream" data-i18n="tcpin.output.stream"></option>
<option value="single" data-i18n="tcpin.output.single"></option>
</select>
<select id="node-input-datatype" style="width:140px;">
<option value="buffer" data-i18n="tcpin.output.buffer"></option>
<option value="utf8" data-i18n="tcpin.output.string"></option>
<option value="base64" data-i18n="tcpin.output.base64"></option>
</select>
<span data-i18n="tcpin.label.payload"></span>
</div>
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br/>
<input type="checkbox" id="node-input-trim" style="display:inline-block; width:auto; vertical-align:top;"> <span data-i18n="tcpin.label.reattach"></span>
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('tcp in',{
category: 'network',
color: "Silver",
defaults: {
name: {value:""},
server: {value:"server", required:true},
host: {
value:"",
validate:function(v, opt) {
if ((this.server == "server")||v.length > 0) {
return true;
}
return RED._("node-red:tcpin.errors.invalid-host");
}
},
port: {
value:"", required:true,
label:RED._("node-red:tcpin.label.port"),
validate:RED.validators.number(false)},
datamode:{value:"stream"},
datatype:{value:"buffer"},
newline:{value:""},
topic: {value:""},
trim: {value:false},
base64: {/*deprecated*/ value:false, required:true},
tls: {type:"tls-config", value:'', required:false,
label:RED._("node-red:httpin.tls-config") }
},
inputs:0,
outputs:1,
icon: "bridge-dash.svg",
label: function() {
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
var updateOptions = function() {
var sockettype = $("#node-input-server").val();
if (sockettype == "client") {
$("#node-input-host-row").show();
} else {
$("#node-input-host-row").hide();
}
var datamode = $("#node-input-datamode").val();
var datatype = $("#node-input-datatype").val();
if (datamode == "stream") {
if (datatype == "utf8") {
$("#node-row-newline").show();
} else {
$("#node-row-newline").hide();
}
} else {
$("#node-row-newline").hide();
}
};
updateOptions();
$("#node-input-server").change(updateOptions);
$("#node-input-datatype").change(updateOptions);
$("#node-input-datamode").change(updateOptions);
function updateTLSOptions() {
if ($("#node-input-usetls").is(':checked')) {
$("#node-row-tls").show();
} else {
$("#node-row-tls").hide();
}
}
if (this.tls) {
$('#node-input-usetls').prop('checked', true);
} else {
$('#node-input-usetls').prop('checked', false);
}
updateTLSOptions();
$("#node-input-usetls").on("click",function() {
updateTLSOptions();
});
},
oneditsave: function() {
if (!$("#node-input-usetls").is(':checked')) {
$("#node-input-tls").val("_ADD_");
}
}
});
</script>
<script type="text/html" data-template-name="tcp out">
<div class="form-row">
<label for="node-input-beserver"><i class="fa fa-dot-circle-o"></i> <span data-i18n="tcpin.label.type"></span></label>
<select id="node-input-beserver" style="width:150px; margin-right:5px;">
<option value="server" data-i18n="tcpin.type.listen"></option>
<option value="client" data-i18n="tcpin.type.connect"></option>
<option value="reply" data-i18n="tcpin.type.reply"></option>
</select>
<span id="node-input-port-row"><span data-i18n="tcpin.label.port"></span> <input type="text" id="node-input-port" style="width: 65px"></span>
</div>
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" style="width: 60%;">
</div>
<div class="form-row" id="node-input-tls-enable">
<label> </label>
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
<div id="node-row-tls" class="hide">
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
</div>
</div>
<div class="form-row hidden" id="node-input-end-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-end" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-end" style="width: 70%;"><span data-i18n="tcpin.label.close-connection"></span></label>
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-base64" style="width: 70%;"><span data-i18n="tcpin.label.decode-base64"></span></label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('tcp out',{
category: 'network',
color: "Silver",
defaults: {
name: {value:""},
host: {
value:"",
validate:function(v, opt) {
if ((this.beserver != "client")||v.length > 0) {
return true;
}
return RED._("node-red:tcpin.errors.invalid-host");
}
},
port: {
value:"",
validate:function(v) {
if ((this.beserver == "reply")||RED.validators.number()(v)) {
return true;
}
return RED._("node-red:tcpin.errors.invalid-port");
}
},
beserver: {value:"client", required:true},
base64: {value:false, required:true},
end: {value:false, required:true},
tls: {type:"tls-config", value:'', required:false,
label:RED._("node-red:httpin.tls-config") }
},
inputs:1,
outputs:0,
icon: "bridge-dash.svg",
align: "right",
label: function() {
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
},
labelStyle: function() {
return (this.name)?"node_label_italic":"";
},
oneditprepare: function() {
var updateOptions = function() {
var sockettype = $("#node-input-beserver").val();
if (sockettype == "reply") {
$("#node-input-port-row").hide();
$("#node-input-host-row").hide();
$("#node-input-end-row").hide();
$("#node-input-tls-enable").hide();
} else if (sockettype == "client"){
$("#node-input-port-row").show();
$("#node-input-host-row").show();
$("#node-input-end-row").show();
$("#node-input-tls-enable").show();
} else {
$("#node-input-port-row").show();
$("#node-input-host-row").hide();
$("#node-input-end-row").show();
$("#node-input-tls-enable").show();
}
};
updateOptions();
$("#node-input-beserver").change(updateOptions);
function updateTLSOptions() {
if ($("#node-input-usetls").is(':checked')) {
$("#node-row-tls").show();
} else {
$("#node-row-tls").hide();
}
}
if (this.tls) {
$('#node-input-usetls').prop('checked', true);
} else {
$('#node-input-usetls').prop('checked', false);
}
updateTLSOptions();
$("#node-input-usetls").on("click",function() {
updateTLSOptions();
});
},
oneditsave: function() {
if (!$("#node-input-usetls").is(':checked')) {
$("#node-input-tls").val("_ADD_");
}
}
});
</script>
<script type="text/html" data-template-name="tcp request">
<div class="form-row">
<label for="node-input-server"><i class="fa fa-globe"></i> <span data-i18n="tcpin.label.server"></span></label>
<input type="text" id="node-input-server" placeholder="ip.address" style="width:45%">
<span data-i18n="tcpin.label.port"></span>
<input type="text" id="node-input-port" style="width:60px">
</div>
<div class="form-row" id="node-input-tls-enable">
<label> </label>
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
<div id="node-row-tls" class="hide">
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
</div>
</div>
<div class="form-row">
<label for="node-input-ret"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
<select type="text" id="node-input-ret" style="width:54%;">
<option value="buffer" data-i18n="tcpin.output.buffer"></option>
<option value="string" data-i18n="tcpin.output.string"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-out"><i class="fa fa-sign-out fa-rotate-90"></i> <span data-i18n="tcpin.label.close"></span></label>
<select type="text" id="node-input-out" style="width:54%;">
<option value="time" data-i18n="tcpin.return.timeout"></option>
<option value="char" data-i18n="tcpin.return.character"></option>
<option value="count" data-i18n="tcpin.return.number"></option>
<option value="sit" data-i18n="tcpin.return.never"></option>
<option value="immed" data-i18n="tcpin.return.immed"></option>
</select>
<input type="text" id="node-input-splitc" style="width:50px;">
<span id="node-units"></span>
</div>
<div id="node-row-newline" class="form-row hidden" style="padding-left:162px;">
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br/>
<input type="checkbox" id="node-input-trim" style="display:inline-block; width:auto; vertical-align:top;"> <span data-i18n="tcpin.label.reattach"></span>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('tcp request',{
category: 'network',
color: "Silver",
defaults: {
name: {value:""},
server: {value:""},
port: {
value:"",
label: RED._("node-red:tcpin.label.port"),
validate:RED.validators.regex(/^(\d*|)$/)
},
out: {value:"time", required:true},
ret: {value:"buffer"},
splitc: {value:"0", required:true},
newline: {value:""},
trim: {value:false},
tls: {type:"tls-config", value:'', required:false, label:RED._("node-red:httpin.tls-config")}
},
inputs:1,
outputs:1,
icon: "bridge-dash.svg",
label: function() {
return this.name || "tcp:"+(this.server?this.server+":":"")+this.port;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var previous = null;
if ($("#node-input-ret").val() == undefined) {
$("#node-input-ret").val("buffer");
this.ret = "buffer";
}
$("#node-input-ret").on("change", function() {
if ($("#node-input-ret").val() === "string" && $("#node-input-out").val() === "sit") { $("#node-row-newline").show(); }
else { $("#node-row-newline").hide(); }
});
$("#node-input-out").on("change", function() {
if ($("#node-input-ret").val() === "string" && $("#node-input-out").val() === "sit") { $("#node-row-newline").show(); }
else { $("#node-row-newline").hide(); }
});
$("#node-input-out").on('focus', function () { previous = this.value; }).on("change", function() {
$("#node-input-splitc").show();
if (previous === null) { previous = $("#node-input-out").val(); }
if ($("#node-input-out").val() == "char") {
if (previous != "char") { $("#node-input-splitc").val("\\n"); }
$("#node-units").text("");
}
else if ($("#node-input-out").val() == "time") {
if (previous != "time") { $("#node-input-splitc").val("0"); }
$("#node-units").text(RED._("node-red:tcpin.label.ms"));
}
else if ($("#node-input-out").val() == "immed") {
if (previous != "immed") { $("#node-input-splitc").val(" "); }
$("#node-units").text("");
$("#node-input-splitc").hide();
}
else if ($("#node-input-out").val() == "count") {
if (previous != "count") { $("#node-input-splitc").val("12"); }
$("#node-units").text(RED._("node-red:tcpin.label.chars"));
}
else {
if (previous != "sit") { $("#node-input-splitc").val(" "); }
$("#node-units").text("");
$("#node-input-splitc").hide();
}
});
function updateTLSOptions() {
if ($("#node-input-usetls").is(':checked')) {
$("#node-row-tls").show();
} else {
$("#node-row-tls").hide();
}
}
if (this.tls) {
$('#node-input-usetls').prop('checked', true);
} else {
$('#node-input-usetls').prop('checked', false);
}
updateTLSOptions();
$("#node-input-usetls").on("click",function() {
updateTLSOptions();
});
},
oneditsave: function() {
if (!$("#node-input-usetls").is(':checked')) {
$("#node-input-tls").val("_ADD_");
}
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="tcp in">
<p>TCP-Eingang zur Verbindung mit einem entfernten TCP-Port oder Akzeptanz eingehender Verbindungen.</p>
<p><b>Hinweis</b>: Auf einigen Systemen benötigen Sie möglicherweise Root- oder Administrator-Zugriffsrechte,
um Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
</script>
<script type="text/html" data-help-name="tcp out">
<p>TCP-Ausgang zur Verbindung mit einem entfernten TCP-Port, Akzeptanz eingehender Verbindungen oder
Antwort auf Nachrichten, die von einem <b>tcp&nbsp;in</b>-Node empfangen werden.</p>
<p>Nur der <code>msg.payload</code>-Inhalt wird gesendet.</p>
<p>Wenn <code>msg.payload</code> einen String mit Base64-Kodierung von binären Daten beinhaltet,
bewirkt die Option <i>Base64-Nachricht dekodieren</i>,
dass sie vorm Senden wieder in Binärdaten umgewandelt wird.</p>
<p>Wenn <code>msg._session</code> nicht vorhanden ist,
werden die Nutzdaten (Payload) an <b>alle</b> verbundenen Clients gesendet.</p>
<p><b>Hinweis</b>: Auf einigen Systemen benötigen Sie möglicherweise Root- oder Administrator-Zugriffsrechte,
um Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
</script>
<script type="text/html" data-help-name="tcp request">
<p>Einfacher TCP-Anforderungs-Node zum
Senden von <code>msg.payload</code> an einen Server-TCP-Port und erwarten einer Antwort.</p>
<p>Der Node verbindet sich, sendet einen <i>request</i> (Anfrage) und liest den <i>response</i> (Antwort).
Er kann entweder eine vorgegebene Zeichenanzahl in einem festen Puffer abzählen,
auf ein passendes Zeichen zur Rückkehr reagieren, ein festes Zeitlimit ab der ersten Antwort abwarten und dann rückkehren,
endlos auf Daten warten oder sofort die Verbindug schliessen, ohne auf Antwort zu warten.</p>
<p>Die Antwort wird in <code>msg.payload</code> als binärer Puffer (buffer) ausgegeben,
sodass sie ggf. mit der <code>.toString()</code>-Funktion umgewandelt werden kann.</p>
<p>Wenn <i>Server</i> oder <i>Port</code> nicht vorgegeben werden,
müssen diese mit den <code>msg.host</code>- und <code>msg.port</code>-Eigenschaften übergeben werden.</p>
</script>
</div><div><!-- --- [red-module:node-red/udp] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- The Input Node -->
<script type="text/html" data-template-name="udp in">
<div class="form-row">
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.listen"></span></label>
<select id="node-input-multicast" style='width:70%'>
<option value="false" data-i18n="udp.udpmsgs"></option>
<option value="true" data-i18n="udp.mcmsgs"></option>
</select>
</div>
<div class="form-row node-input-group">
<label for="node-input-group"><i class="fa fa-list"></i> <span data-i18n="udp.label.group"></span></label>
<input type="text" id="node-input-group" placeholder="225.0.18.83">
</div>
<div class="form-row node-input-iface">
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.placeholder.interfaceprompt">
</div>
<div class="form-row">
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>
<input type="text" id="node-input-port" style="width:80px">
&nbsp;&nbsp;<span data-i18n="udp.label.using"></span> <select id="node-input-ipv" style="width:80px">
<option value="udp4">ipv4</option>
<option value="udp6">ipv6</option>
</select>
</div>
<div class="form-row">
<label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="udp.label.output"></span></label>
<select id="node-input-datatype" style="width:70%;">
<option value="buffer" data-i18n="udp.output.buffer"></option>
<option value="utf8" data-i18n="udp.output.string"></option>
<option value="base64" data-i18n="udp.output.base64"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips"><span data-i18n="udp.tip.in"></span></div>
<div class="form-tips" id="udpporttip"><span data-i18n="[html]udp.tip.port"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('udp in',{
category: 'network',
color:"Silver",
defaults: {
name: {value:""},
iface: {value:""},
port: {
value:"", required:true,
label:RED._("node-red:udp.label.port"),
validate:RED.validators.number(false)
},
ipv: {value:"udp4"},
multicast: {value:"false"},
group: {
value:"",
validate:function(v,opt) {
if ((this.multicast !== "true")||v.length > 0) {
return true;
}
return RED._("node-red:udp.errors.invalid-group");
}
},
datatype: {value:"buffer",required:true}
},
inputs:0,
outputs:1,
icon: "bridge-dash.svg",
label: function() {
if (this.multicast=="false") {
return this.name||"udp "+this.port;
}
else {
return this.name||"udp "+(this.group+":"+this.port);
}
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-multicast").on("change", function() {
var id = $("#node-input-multicast").val();
if (id == "false") {
$(".node-input-group").hide();
$(".node-input-iface").hide();
}
else {
$(".node-input-group").show();
$(".node-input-iface").show();
}
});
$("#node-input-multicast").change();
var porttip = this._("udp.tip.port");
var alreadyused = this._("udp.errors.alreadyused");
var portsInUse = {};
$.getJSON('udp-ports/'+this.id,function(data) {
portsInUse = data || {};
$('#udpporttip').html(porttip + data);
});
$("#node-input-port").on("change", function() {
var portnew = $("#node-input-port").val();
if (portsInUse.hasOwnProperty($("#node-input-port").val())) {
RED.notify(alreadyused+" "+$("#node-input-port").val(),"warn");
}
});
}
});
</script>
<!-- The Output Node -->
<script type="text/html" data-template-name="udp out">
<div class="form-row">
<label for="node-input-port"><i class="fa fa-envelope"></i> <span data-i18n="udp.label.send"></span></label>
<select id="node-input-multicast" style="width:40%">
<option value="false" data-i18n="udp.udpmsg"></option>
<option value="broad" data-i18n="udp.bcmsg"></option>
<option value="multi" data-i18n="udp.mcmsg"></option>
</select>
<span data-i18n="udp.label.toport"></span> <input type="text" id="node-input-port" style="width:70px">
</div>
<div class="form-row node-input-addr">
<label for="node-input-addr" id="node-input-addr-label"><i class="fa fa-list"></i> <span data-i18n="udp.label.address"></span></label>
<input type="text" id="node-input-addr" data-i18n="[placeholder]udp.placeholder.address" style="width:50%;">
<select id="node-input-ipv" style="width:70px">
<option value="udp4">ipv4</option>
<option value="udp6">ipv6</option>
</select>
</div>
<div class="form-row node-input-iface">
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.placeholder.interface">
</div>
<div class="form-row">
<label for="node-input-outport-type">&nbsp;</label>
<select id="node-input-outport-type">
<option id="node-input-outport-type-random" value="random" data-i18n="udp.bind.random"></option>
<option value="fixed" data-i18n="udp.bind.local"></option>
</select>
<input type="text" id="node-input-outport" style="width:70px;">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-base64" style="display:inline-block; width:auto; vertical-align:top;">
<label for="node-input-base64" style="width:70%;"><span data-i18n="udp.label.decode-base64"></span></label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips"><span data-i18n="[html]udp.tip.out"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('udp out',{
category: 'network',
color:"Silver",
defaults: {
name: {value:""},
addr: {value:""},
iface: {value:""},
port: {value:""},
ipv: {value:"udp4"},
outport: {value:""},
base64: {value:false,required:true},
multicast: {value:"false"}
},
inputs:1,
outputs:0,
icon: "bridge-dash.svg",
align: "right",
label: function() {
return this.name||"udp "+(this.addr+":"+this.port);
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var addresslabel = this._("udp.label.address");
var addressph = this._("udp.placeholder.address");
var grouplabel = this._("udp.label.group");
var bindrandom = this._("udp.bind.random");
var bindtarget = this._("udp.bind.target");
var type = this.outport===""?"random":"fixed";
$("#node-input-outport-type").val(type);
$("#node-input-outport-type").on("change", function() {
var type = $(this).val();
if (type == "random") {
$("#node-input-outport").val("").hide();
} else {
$("#node-input-outport").show();
}
});
$("#node-input-outport-type").change();
$("#node-input-multicast").on("change", function() {
var id = $("#node-input-multicast").val();
if (id === "multi") {
$(".node-input-iface").show();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> ' + grouplabel);
$("#node-input-addr")[0].placeholder = '225.0.18.83';
}
else if (id === "broad") {
$(".node-input-iface").hide();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> ' + addresslabel);
$("#node-input-addr")[0].placeholder = '255.255.255.255';
}
else {
$(".node-input-iface").hide();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> ' + addresslabel);
$("#node-input-addr")[0].placeholder = addressph;
}
var type = $(this).val();
if (type == "false") {
$("#node-input-outport-type-random").html(bindrandom);
} else {
$("#node-input-outport-type-random").html(bindtarget);
}
});
$("#node-input-multicast").change();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="udp in">
<p>UDP-Eingangs-Node zur Erzeugung einer <code>msg.payload</code> mit Buffer, String oder base64-kodierten String.
Multicast wird unterstützt.</p>
<p>Über die Eigenschaften <code>msg.ip</code> und <code>msg.port</code> können IP-Addresse und Port vorgeben werden,
von dem die Nachtrichten empfangen werden.</p>
<p><b>Hinweis</b>: Auf einigen Systemen benötigen Sie möglicherweise Root- oder Administrator-Zugriffsrechte,
um Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
</script>
<script type="text/html" data-help-name="udp out">
<p>UDP-Ausgangs-Node zum Senden von <code>msg.payload</code> an vorgegebenen UDP-Host und -Port.
Multicast wird unterstützt.</p>
<p>Über die Eigenschaften <code>msg.ip</code> und <code>msg.port</code> können IP-Addresse und Port vorgeben werden,
an den die Nachtrichten gesendet werden. Statisch im Node vorgebene Werte haben aber Vorrang.</p>
<p>Bei Verwendung von Broadcast sollte die Adresse auf die lokale Broadcast-IP-Adresse oder
auf 255.255.255.255 (globale Broadcast-Adresse) eingestellt werden.</p>
<p><b>Hinweis</b>: Auf einigen Systemen benötigen Sie möglicherweise Root- oder Administrator-Zugriffsrechte,
um Ports unter 1024 und/oder Broadcast nutzen zu können.</p>
</script>
</div><div><!-- --- [red-module:node-red/CSV] --- -->
<script type="text/html" data-template-name="csv">
<div class="form-row">
<label for="node-input-temp"><i class="fa fa-list"></i> <span data-i18n="csv.label.columns"></span></label>
<input type="text" id="node-input-temp" data-i18n="[placeholder]csv.placeholder.columns">
</div>
<div class="form-row">
<label for="node-input-select-sep"><i class="fa fa-text-width"></i> <span data-i18n="csv.label.separator"></span></label>
<select style="width:150px" id="node-input-select-sep">
<option value="," data-i18n="csv.separator.comma"></option>
<option value="\t" data-i18n="csv.separator.tab"></option>
<option value=" " data-i18n="csv.separator.space"></option>
<option value=";" data-i18n="csv.separator.semicolon"></option>
<option value=":" data-i18n="csv.separator.colon"></option>
<option value="#" data-i18n="csv.separator.hashtag"></option>
<option value="" data-i18n="csv.separator.other"></option>
</select>
<input style="width:40px;" type="text" id="node-input-sep" pattern=".">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<hr align="middle"/>
<div class="form-row">
<label style="width:100%;"><span data-i18n="csv.label.c2o"></span></label>
</div>
<div class="form-row" style="padding-left:20px;">
<label><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.input"></span></label>
<span data-i18n="csv.label.skip-s"></span>&nbsp;<input type="text" id="node-input-skip" style="width:40px; height:25px;"/>&nbsp;<span data-i18n="csv.label.skip-e"></span><br/>
<label>&nbsp;</label>
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-hdrin"><label style="width:auto; margin-top:7px;" for="node-input-hdrin"><span data-i18n="csv.label.firstrow"></span></label><br/>
<label>&nbsp;</label>
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-strings"><label style="width:auto; margin-top:7px;" for="node-input-strings"><span data-i18n="csv.label.usestrings"></span></label><br/>
<label>&nbsp;</label>
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_empty_strings"><label style="width:auto; margin-top:7px;" for="node-input-include_empty_strings"><span data-i18n="csv.label.include_empty_strings"></span></label><br/>
<label>&nbsp;</label>
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_null_values"><label style="width:auto; margin-top:7px;" for="node-input-include_null_values"><span data-i18n="csv.label.include_null_values"></span></label><br/>
</div>
<div class="form-row" style="padding-left:20px;">
<label><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
<select type="text" id="node-input-multi" style="width:250px;">
<option value="one" data-i18n="csv.output.row"></option>
<option value="mult" data-i18n="csv.output.array"></option>
</select>
</div>
<div class="form-row" style="margin-top:20px">
<label style="width:100%;"><span data-i18n="csv.label.o2c"></span></label>
</div>
<div class="form-row" style="padding-left:20px;">
<label><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
<!-- <input style="width:20px; vertical-align:top; margin-right:5px;" type="checkbox" id="node-input-hdrout"><label style="width:auto;" for="node-input-hdrout"><span data-i18n="csv.label.includerow"></span></span> -->
<select style="width:60%" id="node-input-hdrout">
<option value="none" data-i18n="csv.hdrout.none"></option>
<option value="all" data-i18n="csv.hdrout.all"></option>
<option value="once" data-i18n="csv.hdrout.once"></option>
</select>
</div>
<div class="form-row" style="padding-left:20px;">
<label></label>
<label style="width:auto; margin-right:10px;" for="node-input-ret"><span data-i18n="csv.label.newline"></span></label>
<select style="width:150px;" id="node-input-ret">
<option value='\n' data-i18n="csv.newline.linux"></option>
<option value='\r' data-i18n="csv.newline.mac"></option>
<option value='\r\n' data-i18n="csv.newline.windows"></option>
</select>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('csv',{
category: 'parser',
color:"#DEBD5C",
defaults: {
name: {value:""},
sep: {
value:',', required:true,
label:RED._("node-red:csv.label.separator"),
validate:RED.validators.regex(/^.{1,2}$/)},
//quo: {value:'"',required:true},
hdrin: {value:""},
hdrout: {value:"none"},
multi: {value:"one",required:true},
ret: {value:'\\n'},
temp: {value:""},
skip: {value:"0"},
strings: {value:true},
include_empty_strings: {value:""},
include_null_values: {value:""}
},
inputs:1,
outputs:1,
icon: "parser-csv.svg",
label: function() {
return this.name||"csv";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.hdrout === false) { this.hdrout = "none"; $("#node-input-hdrout").val("none"); }
if (this.hdrout === true) { this.hdrout = "all"; $("#node-input-hdrout").val("all");}
if (this.strings === undefined) { this.strings = true; $("#node-input-strings").prop('checked', true); }
if (this.skip === undefined) { this.skip = 0; $("#node-input-skip").val("0");}
$("#node-input-skip").spinner({ min:0 });
if (this.sep == "," || this.sep == "\\t" || this.sep == ";" || this.sep == ":" || this.sep == " " || this.sep == "#") {
$("#node-input-select-sep").val(this.sep);
$("#node-input-sep").hide();
} else {
$("#node-input-select-sep").val("");
$("#node-input-sep").val(this.sep);
$("#node-input-sep").show();
}
$("#node-input-select-sep").on("change", function() {
var v = $("#node-input-select-sep").val();
$("#node-input-sep").val(v);
if (v == "") {
$("#node-input-sep").val("");
$("#node-input-sep").show().focus();
} else {
$("#node-input-sep").hide();
}
});
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="csv">
<p>Konvertierung zwischen einer CSV-formatierten Zeichenfolge (string) und ihrer JavaScript-Objektdarstellung in beide Richtungen.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | array | string</span></dt>
<dd>JavaScript-Objekt, Array oder CSV-Zeichenfolge.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | array | string</span></dt>
<dd>
<ul>
<li>Wenn die Eingangsdaten ein Zeichenfolge (string) sind, wird versucht, sie als CSV zu analysieren (parse),
und es wird für jede Zeile ein JavaScript-Objekt mit Schlüssel/Wert-Paaren erstellt.
Der Node sendet dann entweder eine Nachricht für jede CSV-Zeile oder
eine einzige Nachricht mit einem Array von Objekten.</li>
<li>Wenn die Eingangsdaten ein JavaScript-Objekt sind, wird versucht, eine CSV-Zeichenfolge zu erzeugen</li>
<li>Wenn die Eingangsdaten ein Array mit einfachen Werten sind, wird eine einzeilige CSV-Zeichenfolge erstellt</li>
<li>Wenn die Eingangsdaten ein Array von Arrays oder Objekten sind, wird ein mehrzeiliger CSV-Zeichenfolge erstellt</li>
</ul>
</dd>
</dl>
<h3>Details</h3>
<p>Die Spaltenvorlage besteht aus der geordneten und durch Komma getrennten Liste der Spaltennamen.
Bei der Konvertierung von CSV nach Objekt werden die Spaltennamen als Eigenschaftsnamen verwendet.
Alternativ können die Spaltennamen auch aus der ersten Zeile des CSV übernommen werden.</p>
<p>Bei der Konvertierung nach CSV wird die Spaltenvorlage verwendet, um festzustellen,
welche Eigenschaften aus dem Objekt in welcher Reihenfolge extrahiert werden sollen.</p>
<p>Wenn die Spaltenvorlage nicht vorgegeben ist, kann eine einfache, Komma getrennte Liste über
die <code>msg.columns</code>-Eigenschaft übergeben werden, um vorzugeben, was der Node extrahieren soll,
und wie es sortiert sein soll.
Wenn das nicht vorgegeben ist, werden alle Objekt-Eigenschaften in der Reihenfolge ausgegeben,
wie die Eigenschaften in der ersten Zeile gefunden wurden.</p>
<p>Wenn die Eingangsdaten ein Array sind, wird die Spaltenvorlage nur verwendet,
um optional eine Reihe von Spaltentiteln zu erzeugen.</p>
<p>Mit der Option <i>Zahlenwerte ermitteln</i> werden Zeichenfolgen als Zahlenwerte ausgewertet, z.B. der mittlere Wert der CSV-Zeile <code>1,"1.5",2</code></p>
<p>Mit der Option <i>Leere Zeichenfolgen (string) einbeziehen</i> werden auch leere Zeichenfolgen übergeben, z.B. der mittlere Wert der CSV-Zeile <code>"1","",3</code></p>
<p>Mit der Option <i>Nullwerte einbeziehen</i> werden auch Nullwerte rückgegeben, z.B. der mittlere Wert der CSV-Zeile <code>"1",,3</code></p>
<p>Der Node kann mehrteilige Eingangsdaten akzeptieren, solange die <code>parts</code>-Eigenschaft korrekt gesetzt ist.</p>
<p>Wenn mehrere Nachrichten ausgegeben werden, sind ihre <code>parts</code>-Eigenschaften gesetzt und sie bilden eine vollständige Nachrichtensequenz.</p>
<p><b>Hinweis</b>:Die Spaltenvorlage muss Komma-getrennt sein, auch wenn für die Daten ein anderes Trennzeichen gewählt wird.</p>
</script>
</div><div><!-- --- [red-module:node-red/HTML] --- -->
<script type="text/html" data-template-name="html">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%">
</div>
<div class="form-row">
<label for="node-input-tag"><i class="fa fa-filter"></i> <span data-i18n="html.label.select"></span></label>
<input type="text" id="node-input-tag" placeholder="h1">
</div>
<div class="form-row">
<label for="node-input-ret"><i class="fa fa-sign-out"></i> <span data-i18n="html.label.output"></span></label>
<select id="node-input-ret" style="width:70%">
<option value="html" data-i18n="html.output.html"></option>
<option value="text" data-i18n="html.output.text"></option>
<option value="attr" data-i18n="html.output.attr"></option>
<!-- <option value="val">return the value from a form element</option> -->
</select>
</div>
<div class="form-row">
<label for="node-input-as">&nbsp;</label>
<select id="node-input-as" style="width:70%">
<option value="single" data-i18n="html.format.single"></option>
<option value="multi" data-i18n="html.format.multi"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-outproperty">&nbsp;</label>
<span data-i18n="html.label.in" style="padding-left:8px; padding-right:2px; vertical-align:-1px;"></span> <input type="text" id="node-input-outproperty" style="width:64%">
</div>
<br/>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" style="width:70%" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('html',{
category: 'parser',
color:"#DEBD5C",
defaults: {
name: {value:""},
property: {value:"payload"},
outproperty: {value:"payload"},
tag: {value:""},
ret: {value:"html"},
as: {value:"single"}
},
inputs:1,
outputs:1,
icon: "parser-html.svg",
label: function() {
return this.name||this.tag||"html";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-property").typedInput({default:'msg',types:['msg']});
$("#node-input-outproperty").typedInput({default:'msg',types:['msg']});
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="html">
<p>Extraktion von Elementen unter Verwendung eines CSS-Selektors aus einem HTML-Dokument, das sich in <code>msg.payload</code> befindet.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string</span></dt>
<dd>HTML-Zeichenfolge (string), aus dem Elemente extrahiert werden sollen.</dd>
<dt class="optional">select <span class="property-type">string</span></dt>
<dd>Sofern nicht im Node vorgegeben, kann der Selektor auch als <code>msg.select</code>-Eigenschaft übergeben werden.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">array | string</span></dt>
<dd>Das Ergebnis kann entweder eine einzelne Nachricht mit dem Array der passendes Elemente oder
mehrere Nachrichten mit je einem passenden Element sein.
Wenn mehrere Nachrichten gesendet werden, enthalten sie auch die <code>parts</code>-Eigenschaft.</dd>
</dl>
<h3>Details</h3>
<p>Dieser Node unterstützt eine Kombination aus CSS- und jQuery-Selektoren.
Siehe die <a href="https://github.com/fb55/CSSselect#user-content-supported-selectors" target="_blank">css-select Dokumentation</a>
für weitere Informationen über die unterstützte Syntax.</p>
</script>
</div><div><!-- --- [red-module:node-red/JSON] --- -->
<script type="text/html" data-template-name="json">
<div class="form-row">
<label for="node-input-action"><i class="fa fa-dot-circle-o"></i> <span data-i18n="json.label.action"></span></label>
<select style="width:70%" id="node-input-action">
<option value="" data-i18n="json.label.actions.toggle"></option>
<option value="str" data-i18n="json.label.actions.str"></option>
<option value="obj" data-i18n="json.label.actions.obj"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="json.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<hr align="middle"/>
<div class="form-row node-json-to-json-options">
<label style="width:100%;"><span data-i18n="json.label.o2j"></span></label>
</div>
<div class="form-row node-json-to-json-options" style="padding-left: 20px;">
<input style="width:20px; vertical-align:top; margin-right: 5px;" type="checkbox" id="node-input-pretty"><label style="width: auto;" for="node-input-pretty" data-i18n="json.label.pretty"></label>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('json',{
category: 'parser',
color:"#DEBD5C",
defaults: {
name: {value:""},
property: {value:"payload",required:true,
label:RED._("node-red:json.label.property")},
action: {value:""},
pretty: {value:false}
},
inputs:1,
outputs:1,
icon: "parser-json.svg",
label: function() {
return this.name||"json";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
$("#node-input-action").on("change", function() {
if (this.value === "" || this.value === "str") {
$(".node-json-to-json-options").show();
} else {
$(".node-json-to-json-options").hide();
}
});
$("#node-input-action").change();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="json">
<p>Konvertierung zwischen JSON-Zeichenfolge (string) und JavaScript-Objektdarstellung in beide Richtungen.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string</span></dt>
<dd>JavaScript-Objekt oder JSON-Zeichenfolge (string).</dd>
<dt>schema <span class="property-type">object</span></dt>
<dd>Optionales JSON-Schema-Objekt, gegen das das JSON-Objekt validiert wird.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string</span></dt>
<dd>
<ul>
<li>Wenn die Eingangsdaten eine JSON-Zeichenfolge (string) darstellen, wird versucht sie in ein JavaScript-Objekt zu analysieren (parsen).</li>
<li>Wenn die Eingangsdaten ein JavaScript-Objekt darstellen, wird eine JSON-Zeichenfolge (string) erstellt.
Die Zeichenfolge (string) kann optional gut leserlich formatiert werden.</li>
</ul>
</dd>
<dt>schemaError <span class="property-type">array</span></dt>
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den catch-Node eine <code>schemaError</code>-Eigenschaft erstellt,
die ein Array von Fehlern enthält.</dd>
</dl>
<h3>Details</h3>
<p>Standardmäßig verarbeitet der Node <code>msg.payload</code>,
kann aber auch eine beliebige Nachrichteneigenschaft konvertieren.</p>
<p>Die Konvertierungsrichtung kann im Node auch vorgegeben werden, um eine bestimmte Ziel-Kodierung sicherzustellen.
Dies kann z.B. zusammen mit dem http&nbsp;in-Node benutzt werden, um sicherzustellen,
dass die Nutzdaten (Payload) ein analysiertes (parsed) Objekt ist,
auch wenn eine eingehende Anfrage seinen Inhaltstyp nicht korrekt eingestellt hat,
damit der http&nbsp;in-Node die Konvertierung durchführen kann.</p>
<p>Wenn der Node auf Zeichenfolgen-Eingang (string) eingestellt ist und es einen String empfängt,
werden keine weiteren Prüfungen der Eigenschaft durchgeführt.
Der Node prüft weder, ob die Zeichenfolge (string) ein gültiges JSON enthält, noch wird er ihn neu formatieren,
wenn die Format-Option ausgewählt ist.</p>
<p>Für weitere Details über das JSON-Schema siehe die
<a href="http://json-schema.org/latest/json-schema-validation.html">JSON-Schema-Spezifikation</a>.</p>
</script>
</div><div><!-- --- [red-module:node-red/XML] --- -->
<script type="text/html" data-template-name="xml">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<hr align="middle"/>
<div class="form-row">
<label style="width:100%;"><span data-i18n="xml.label.x2o"></span></label>
</div>
<div class="form-row" style="padding-left: 20px;">
<label style="width:250px;" for="node-input-attr" data-i18n="xml.label.represent"></label> <input type="text" id="node-input-attr" style="text-align:center; width:40px" placeholder="$">
</div>
<div class="form-row" style="padding-left: 20px;">
<label style="width:250px;" for="node-input-chr" data-i18n="xml.label.prefix"></label> <input type="text" id="node-input-chr" style="text-align:center; width:40px" placeholder="_">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('xml',{
category: 'parser',
color:"#DEBD5C",
defaults: {
name: {value:""},
property: {value:"payload",required:true,
label:RED._("node-red:common.label.property")},
attr: {value:""},
chr: {value:""}
},
inputs:1,
outputs:1,
icon: "parser-xml.svg",
label: function() {
return this.name||"xml";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="xml">
<p>Konvertierung zwischen XML-Zeichenfolge (string) und JavaScript-Objekt in beiden Richtungen.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string</span></dt>
<dd>JavaScript-Objekt oder XML-Zeichenfolge (string).</dd>
<dt class="optional">options <span class="property-type">object</span></dt>
<dd>Optionale Eigenschaft zur Übergabe von Optionen an die Konvertier-Bibliothek von und zu XML.
Siehe <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">xml2js Dokumente</a>
für weitere Informationen.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string</span></dt>
<dd>
<ul>
<li>Wenn die Eingangsdaten eine Zeichenfolge (string) sind,
wird versucht sie als XML zu analysieren (parse) und daraus ein JavaScript-Objekt zu erstellen.</li>
<li>Wenn die Eingangsdaten ein JavaScript-Objekt darstellen,
wird versucht daraus ein XML-Zeichenfolge (string) zu erstellen.</li>
</ul>
</dd>
</dl>
<h3>Details</h3>
<p>Bei der Konvertierung zwischen XML und einem Objekt werden standardmäßig alle XML-Attribute als Eigenschaft mit Namen <code>$</code> hinzugefügt.
Jeder Textinhalt wird als Eigenschaft mit Namen <code>_</code> hinzugefügt.
Diese Eigenschaftsnamen können in der Node-Konfiguration angegeben werden.</p>
<p>Zum Beispiel wird das folgende XML wie dargestellt konvertiert:</p>
<pre>&lt;p class="tag"&gt;Hello World&lt;/p&gt;</pre>
<pre>{
"p": {
"$": {
"class": "tag"
},
"_": "Hello World"
}
}</pre>
</script>
</div><div><!-- --- [red-module:node-red/YAML] --- -->
<script type="text/html" data-template-name="yaml">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('yaml',{
category: 'parser',
color:"#DEBD5C",
defaults: {
property: {value:"payload",required:true,
label:RED._("node-red:common.label.property")},
name: {value:""}
},
inputs:1,
outputs:1,
icon: "parser-yaml.svg",
label: function() {
return this.name||"yaml";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="yaml">
<p>Konvertierung zwischen YAML-formatierter Zeichenfolge (string) und JavaScript-Objekt-Darstellung in beide Richtungen.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string</span></dt>
<dd>JavaScript-Objekt oder YAML-Zeichenfolge (string).</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string</span></dt>
<dd>
<ul>
<li>Wenn die Eingangsdaten eine YAML-Zeichenfolge (string) sind, wird versucht daraus ein JavaScript-Objekt zu erzeugen.</li>
<li>Wenn die Eingangsdaten ein JavaScript-Objekt darstellt, wird daraus eine YAML-Zeichenfolge (string) erstellt.</li>
</ul>
</dd>
</dl>
</script>
</div><div><!-- --- [red-module:node-red/split] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="split">
<div class="form-row"><span data-i18n="[html]split.intro"></span></div>
<div class="form-row"><span data-i18n="[html]split.strBuff"></span></div>
<div class="form-row">
<label for="node-input-splt" style="padding-left:10px; margin-right:-10px;" data-i18n="split.splitUsing"></label>
<input type="text" id="node-input-splt" style="width:70%">
<input type="hidden" id="node-input-spltType">
</div>
<div class="form-row">
<input type="checkbox" id="node-input-stream" style="margin-left:10px; vertical-align:top; width:auto;">
<label for="node-input-stream" style="width:auto;" data-i18n="split.stream"></label>
</div>
<div class="form-row"><span data-i18n="[html]split.array"></span></div>
<div class="form-row">
<label for="node-input-arraySplt" style="padding-left:10px; margin-right:-10px;" data-i18n="split.splitUsing"></label>
<input type="text" id="node-input-arraySplt" style="width:70%">
<input type="hidden" id="node-input-arraySpltType">
</div>
<div class="form-row"><span data-i18n="[html]split.object"></span></div>
<div class="form-row" style="padding-left: 10px"><span data-i18n="[html]split.objectSend"></span></div>
<div class="form-row">
<input type="checkbox" id="node-input-addname-cb" style="margin-left:10px; vertical-align:baseline; width:auto;">
<label for="node-input-addname-cb" style="width:auto;" data-i18n="split.addname"></label>
<input type="text" id="node-input-addname" style="width:70%">
</div>
<hr/>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('split',{
category: 'sequence',
color:"#E2D96E",
defaults: {
name: {value:""},
splt: {value:"\\n"},
spltType: {value:"str"},
arraySplt: {value:1},
arraySpltType: {value:"len"},
stream: {value:false},
addname: {value:""}
},
inputs:1,
outputs:1,
icon: "split.svg",
label: function() {
return this.name||this._("split.split");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-splt").typedInput({
default: 'str',
typeField: $("#node-input-spltType"),
types:[
'str',
'bin',
{value:"len", label:RED._("node-red:split.splitLength"),validate:/^\d+$/}
]
});
if (this.arraySplt === undefined) {
$("#node-input-arraySplt").val(1);
}
$("#node-input-arraySplt").typedInput({
default: 'len',
typeField: $("#node-input-arraySpltType"),
types:[
{value:"len", label:RED._("node-red:split.splitLength"),validate:/^\d+$/}
]
});
$("#node-input-addname").typedInput({
typeField: $("#node-input-fnameType"),
types:['msg']
});
$("#node-input-addname-cb").on("change", function() {
$("#node-input-addname").prop('disabled',!this.checked);
})
if (this.addname === "") {
$("#node-input-addname-cb").prop('checked',false);
$("#node-input-addname").val('topic');
} else {
$("#node-input-addname-cb").prop('checked',true);
}
$("#node-input-addname-cb").change();
},
oneditsave: function() {
if (!$("#node-input-addname-cb").prop('checked')) {
$("#node-input-addname").val('');
}
}
});
</script>
<script type="text/html" data-template-name="join">
<div class="form-row">
<label data-i18n="join.mode.mode"></label>
<select id="node-input-mode" style="width:200px;">
<option value="auto" data-i18n="join.mode.auto"></option>
<option value="custom" data-i18n="join.mode.custom"></option>
<option value="reduce" data-i18n="join.mode.reduce"></option>
</select>
</div>
<div class="node-row-custom">
<div class="form-row node-row-property">
<label data-i18n="join.combine"> </label>
<input type="text" id="node-input-property" style="width:70%;">
<input type="hidden" id="node-input-propertyType">
</div>
<div class="form-row">
<label data-i18n="join.create"></label>
<select id="node-input-build" style="width:70%;">
<option value="string" data-i18n="join.type.string"></option>
<option value="buffer" data-i18n="join.type.buffer"></option>
<option value="array" data-i18n="join.type.array"></option>
<option value="object" data-i18n="join.type.object"></option>
<option value="merged" data-i18n="join.type.merged"></option>
</select>
</div>
<div class="form-row node-row-key">
<label style="vertical-align:top; margin-top:7px; width:auto; margin-right: 5px;" data-i18n="join.using"></label>
<div style="display:inline-block">
<input type="text" id="node-input-key" style="width:220px;"> <span data-i18n="join.key"></span>
</div>
</div>
<div class="form-row node-row-joiner">
<label for="node-input-joiner" data-i18n="join.joinedUsing"></label>
<input type="text" id="node-input-joiner" style="width:70%">
<input type="hidden" id="node-input-joinerType">
</div>
<div class="form-row node-row-trigger" id="trigger-row">
<label style="width:auto;" data-i18n="join.send"></label>
<ul>
<li>
<label style="width:280px;" for="node-input-count" data-i18n="join.afterCount"></label> <input id="node-input-count" data-i18n="[placeholder]join.count" type="text" style="width:75px;">
</li>
<li class="node-row-accumulate" style="list-style-type:none;">
<input type="checkbox" id="node-input-accumulate" style="display:inline-block; width:20px; margin-left:20px; vertical-align:top;"> <label style="width: auto" for="node-input-accumulate" data-i18n="join.subsequent"></label>
</li>
<li>
<label style="width:280px;" for="node-input-timeout" data-i18n="join.afterTimeout"></label> <input id="node-input-timeout" data-i18n="[placeholder]join.seconds" type="text" style="width:75px;">
</li>
<li>
<label style="width:auto; padding-top:6px;" data-i18n="[html]join.complete"></label>
</li>
</ul>
</div>
</div>
<div class="node-row-reduce">
<div class="form-row">
<label for="node-input-reduceExp" data-i18n="join.reduce.exp" style="margin-left:10px;"></label>
<input type="text" id="node-input-reduceExp" data-i18n="[placeholder]join.reduce.exp-value" style="width:65%">
</div>
<div class="form-row">
<label for="node-input-reduceInit" data-i18n="join.reduce.init" style="margin-left:10px;"></label>
<input type="text" id="node-input-reduceInit" data-i18n="[placeholder]join.reduce.init" style="width:65%">
<input type="hidden" id="node-input-reduceInitType">
</div>
<div class="form-row">
<label for="node-input-reduceFixup" data-i18n="join.reduce.fixup" style="margin-left:10px;"></label>
<input type="text" id="node-input-reduceFixup" data-i18n="[placeholder]join.reduce.exp-value" style="width:65%">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-reduceRight" style="display:inline-block; width:auto; vertical-align:top; margin-left:10px;">
<label for="node-input-reduceRight" style="width:70%;" data-i18n="join.reduce.right" style="margin-left:10px;"/>
</div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips form-tips-auto hide" data-i18n="[html]join.tip"></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('join',{
category: 'sequence',
color:"#E2D96E",
defaults: {
name: {value:""},
mode: {value:"auto"},
build: { value:"object"},
property: {
value:"payload",
label: RED._("node-red:join.message-prop"),
validate:RED.validators.typedInput("propertyType", false)
},
propertyType: { value:"msg"},
key: {value:"topic"},
joiner: { value:"\\n"},
joinerType: { value:"str"},
accumulate: { value:"false" },
timeout: {value:""},
count: {value:""},
reduceRight: {value:false},
reduceExp: {value:undefined},
reduceInit: {value:undefined},
reduceInitType: {value:undefined},
reduceFixup: {value:undefined}
},
inputs:1,
outputs:1,
icon: "join.svg",
label: function() {
return this.name||this._("join.join");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
$("#node-input-mode").on("change", function(e) {
var val = $(this).val();
$(".node-row-custom").toggle(val==='custom');
$(".node-row-reduce").toggle(val==='reduce');
$(".form-tips-auto").toggle((val==='auto') || (val==='reduce'));
if (val === "auto") {
$("#node-input-accumulate").attr('checked', false);
}
else if (val === "custom") {
$("#node-input-build").change();
}
else if (val === "reduce") {
var jsonata_or_empty = {
value: "jsonata",
label: "expression",
icon: "red/images/typedInput/expr.svg",
validate: function(v) {
try{
if(v !== "") {
jsonata(v);
}
return true;
}
catch(e){
return false;
}
},
expand:function() {
var that = this;
RED.editor.editExpression({
value: this.value().replace(/\t/g,"\n"),
complete: function(v) {
that.value(v.replace(/\n/g,"\t"));
}
})
}
};
$("#node-input-reduceExp").typedInput({types:[jsonata_or_empty]});
$("#node-input-reduceInit").typedInput({
default: 'num',
types:['flow','global','str','num','bool','json','bin','date','jsonata','env'],
typeField: $("#node-input-reduceInitType")
});
$("#node-input-reduceFixup").typedInput({types:[jsonata_or_empty]});
}
});
$("#node-input-build").on("change", function(e) {
var val = $(this).val();
$(".node-row-key").toggle(val==='object');
$(".node-row-accumulate").toggle(val==='object' || val==='merged');
$(".node-row-joiner").toggle(val==='string' || val==='buffer');
$(".node-row-trigger").toggle(val!=='auto');
if (val === 'string' || val==='buffer') {
$("#node-input-property").typedInput('types',['msg']);
$("#node-input-joiner").typedInput("show");
} else {
$("#node-input-property").typedInput('types', ['msg', {
value: "full",
label: RED._("node-red:join.completeMessage"),
hasValue: false
}]);
}
});
$("#node-input-joiner").typedInput({
default: 'str',
typeField: $("#node-input-joinerType"),
types:['str', 'bin']
});
$("#node-input-property").typedInput({
typeField: $("#node-input-propertyType"),
types: ['msg', {
value: "full",
label: RED._("node-red:join.completeMessage"),
hasValue: false
}]
});
$("#node-input-key").typedInput({
types:['msg']
});
$("#node-input-build").change();
$("#node-input-mode").change();
},
oneditsave: function() {
var build = $("#node-input-build").val();
if (build !== 'object' && build !== 'merged') {
$("#node-input-accumulate").prop("checked",false);
}
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="split">
<p>Aufteilung einer Nachricht in Nachrichtensequenzen.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object | string | array | buffer</span></dt>
<dd>Das Node-Verhalten wird durch den <code>msg.payload</code>-Typ bestimmt:
<ul>
<li><b>Zeichenfolge (string) / Binärer Puffer (buffer)</b>: Die Nachricht wird anhand des vorgegebenen Zeichens (Standard: <code>\n</code>),
der Buffer-Sequenz oder in feste Längen aufgeteilt</li>
<li><b>Datenfeld (array)</b>: Die Nachricht wird entweder in einzelne Array-Elemente oder Arrays mit fester Länge aufgeteilt</li>
<li><b>Objekt (object)</b>: Jedes Schlüssel/Wert-Paar wird einzeln als Nachricht gesendet</li>
</ul>
</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>parts <span class="property-type">object</span></dt>
<dd>Diese Eigenschaft enthält Informationen darüber, wie die Nachricht von der ursprünglichen Nachricht abgeteilt wurde.
Bei Übergabe an ein join-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
Diese Eigenschaft hat die folgenden Eigenschaften:
<ul>
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
<li><code>index</code>: Position innerhalb der Gruppe</li>
<li><code>count</code>: Gesamtzahl der Nachrichten in der Gruppe (sofern bekannt). Siehe dazu unten <i>Streaming-Modus</i>.</li>
<li><code>type</code>: Nachrichtentyp string/array/object/buffer</li>
<li><code>ch</code>: Die für das Aufteilen der String- oder Buffer-Nachricht verwendeten Daten, entweder als String oder als Byte-Array.</li>
<li><code>key</code>: Schlüssel der Eigenschaft, aus der diese Nachricht erstellt wurde (nur bei einem Objekt).
Optional kann dieser Wert auch in andere Nachrichteneigenschaft kopiert werden, wie z.B. <code>msg.topic</code>.</li>
<li><code>len</code>: Nachrichtenlänge bei Aufteilung in feste Längen</li>
</ul>
</dd>
</dl>
<h3>Details</h3>
<p>Dieser Node macht es einfach, einen Flow zu erstellen, der gemeinsame Aktionen über eine Sequenz von Nachrichten ausführt,
bevor die Sequenz mittels join-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
<p>Der Node verwendet die <code>msg.parts</code>-Eigenschaft, um die einzelnen Sequenzteile nachzuverfolgen.</p>
<h4><b>Streaming-Modus</b></h4>
<p>Der Node kann auch zum Aufbereiten eines Nachrichtenstroms verwendet werden.
So kann beispielsweise ein serielles Gerät, das <code>newline</code>-terminierte Befehle sendet,
eine Nachricht mit einem noch unvollständigen Befehl am Ende liefern.
Im Streaming-Modus teilt der Node die Nachricht in komplette Befehlsegmente auf.
Befindet sich am Nachrichtenende ein unvollständiges Befehlsegment,
so wird es im Node aufbewahrt und der nächsten empfangenen Nachricht vorangestellt.</p>
<p>In diesem Modus wird die <code>msg.parts.count</code>-Eigenschaft nicht gesetzt,
da die Anzahl der zu erwartenden Nachrichten im Stream unbekannt ist.
Das bedeutet, dass ein nachfolgender join-Node nicht im Automatikmodus verwendet werden kann.</p>
</script>
<script type="text/html" data-help-name="join">
<p>Verbindung von Nachrichtensequenzen zu einer einzigen Nachricht.</p>
<p>Es sind drei Modi verfügbar:</p>
<dl>
<dt>Automatisch</dt>
<dd>In Kombination mit dem split-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
<dt>Manuell</dt>
<dd>Die Nachrichtensequenzen können auf verschiedene Weisen verbunden werden.</dd>
<dt>Sequenz reduzieren</dt>
<dd>Einen Ausdruck auf alle Nachrichten einer Sequenz anwenden, um sie auf eine einzige Nachricht zu reduzieren.</dd>
</dl>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">parts <span class="property-type">object</span></dt>
<dd>Zur automatischen Verbindung einer Nachrichtensequenz sollten alle über diese Eigenschaft verfügen.
Der split-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
Sie hat die folgenden Eigenschaften:
<ul>
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
<li><code>index</code>: Position innerhalb der Gruppe</li>
<li><code>count</code>: Gesamtzahl der Nachrichten in der Gruppe (sofern bekannt). Siehe dazu unten "Streaming-Modus".</li>
<li><code>type</code>: Nachrichtentyp string/array/object/buffer</li>
<li><code>ch</code>: Die für das Aufteilen der String- oder Buffer-Nachricht verwendeten Daten, entweder als String oder als Byte-Array.</li>
<li><code>key</code>: Schlüssel der Eigenschaft, aus der diese Nachricht erstellt wurde (nur bei einem Objekt).
Optional kann dieser Wert auch in andere Nachrichteneigenschaft kopiert werden, wie z.B. <code>msg.topic</code>.</li>
<li><code>len</code>: Nachrichtenlänge bei Aufteilung in feste Längen</li>
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>Wenn gesetzt, werden die Nutzdaten (Payload) hinzugefügt und die Ausgangsnachricht im aktuellen Zustand gesendet.</dd>
</dl>
<h3>Details</h3>
<h4><b>Automatischer Modus</b></h4>
<p>Der automatische Modus verwendet die <code>parts</code>-Eigenschaften der eingehenden Nachrichten,
um die Sequenz in richtiger Reihenfolge zu verknüpften.
Dies ermöglicht die Aufteilung des split-Nodes automatisch rückgängig zu machen.</p>
<h4><b>Manueller Modus</b></h4>
<p>Im manuellen Modus werden Nachrichtensequenzen auf verschiedenen Arten zusammengefügt:</p>
<ul>
<li><b>String</b> oder <b>Buffer</b>: Verbinden der ausgewählten Eigenschaft jeder Nachricht
mit den vorgegebenen Join-Zeichen oder -Buffer</li>
<li><b>Array</b>: Erstellung eines Ausgangsarrays durch Hinzufügen jeder ausgewählten Eigenschaft oder ganzer Nachrichten</li>
<li><b>Schlüssel/Wert-Objekt</b>: Erzeugung von Schlüssel und Wert aus Eigenschaft jeder Nachricht</li>
<li><b>Zusammengeführtes Objekt</b>: Erzeugung durch Zusammenführen der Eigenschaften jeder Nachricht als ein einziges Objekt</li>
</ul>
<p>Die anderen Eigenschaften der Ausgangsnachricht werden von der zuletzt empfangenen Nachricht übernommen,
bevor das Ergebnis gesendet wird.</p>
<p>Mit <i>Anzahl</i> kann vorgegeben werden, wie viele Nachrichten vor dem Erzeugen der Ausgangsnadchricht empfangen werden sollen.
Bei Objektausgaben kann der Node nach Erreichen dieser Anzahl so eingestellt werden,
dass er bei jeder nachfolgenden empfangenen Nachricht eine weitere Nachricht sendet.</p>
<p>Mittels <i>Zeitablauf</i> kann das Senden einer neuen Nachricht mit dem Inhalt ausgelöst werden, was bisher empfangen wurde.</p>
<p>Wenn eine Nachricht mit der <code>msg.complete</code>-Eigenschaft empfangen wird,
wird die Ausgangsnachricht finalisiert und gesendet.
Dadurch wird die Zählung aller Teile zurückgesetzt.</p>
<p>Wenn eine Nachricht mit der <code>msg.reset</code>-Eigenschaft empfangen wird,
wird die unvollständige Nachricht gelöscht und nicht gesendet.
Dadurch wird die Zählung aller Teile zurückgesetzt.</p>
<h4><b>Modus Sequenz reduzieren</b></h4>
<p>In diesem Modus wird auf jede Nachricht einer Sequenz ein Ausdruck angewendet und
das Ergebnis zu einer einzigen Nachricht akkumuliert.</p>
<dl class="message-properties">
<dt>Anfangswert</dt>
<dd>Anfangswert des akkumulierten Wertes (<code>$A</code>).</dd>
<dt>Reduktions-Ausdruck</dt>
<dd>JSONata-Ausdruck, der für jede Nachricht in der Sequenz aufgerufen wird.
Das Ergebnis wird als akkumulierter Wert an den nächsten Aufruf des Ausdrucks übergeben.
Im Ausdruck können folgende spezielle Variablen verwendet werden:
<ul>
<li><code>$A</code>: Akkumulierter Wert</li>
<li><code>$I</code>: Index der Nachricht innerhalb der Sequenz</li>
<li><code>$N</code>: Anzahl der Nachrichten der Sequenz</li>
</ul>
</dd>
<dt>Fix-up-Ausdruck</dt>
<dd>Optionaler JSONata-Ausdruck, der nach Anwendung des Reduktions-Ausdrucks auf alle Nachrichten in der Sequenz angewendet wird.
Im Ausdruck können folgende spezielle Variablen verwendet werden:
<ul>
<li><code>$A</code>: Akkumulierter Wert</li>
<li><code>$N</code>: Anzahl der Nachrichten der Sequenz</li>
</ul>
</dd>
<p>Standardmäßig wird der Reduktions-Ausdruck in Reihenfolge von der ersten bis zur letzten Nachricht der Sequenz angewendet.
Er kann optional in umgekehrter Reihenfolge angewendet werden.</p>
</dl>
<p><b>Beispiel</b>: Die folgenden Einstellungen berechnen bei einer Sequenz von Zahlenwerten den Mittelwert:
<ul>
<li><b>Reduktions-Ausdruck</b>: <code>$A+payload</code></li>
<li><b>Anfangswert</b>: <code>0</code></li>
<li><b>Fix-up-Ausdruck</b>: <code>$A/$N</code></li>
</ul>
</p>
<h4><b>Speichern von Nachrichten</b></h4>
<p>Dieser Node puffert Nachrichten intern, um sequenzübergreifend zu arbeiten.
Mit der Laufzeiteinstellung <code>nodeMessageBufferMaxLength</code> kann begrenzt werden,
wie viele Nachrichten im Node zwischengespeichert werden sollen.</p>
</script>
</div><div><!-- --- [red-module:node-red/sort] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="sort">
<div class="form-row">
<label for="node-input-target"><i class="fa fa-dot-circle-o"></i> <span data-i18n="sort.target"></span></label>
<input type="text" id="node-input-target" style="width:70%;">
<input type="hidden" id="node-input-targetType">
</div>
<div class="node-row-sort-msg-key">
<div class="form-row">
<label for="node-input-msgKey"><i class="fa fa-filter"></i> <span data-i18n="sort.key"></span></label>
<input type="text" id="node-input-msgKey" style="width:70%;">
<input type="hidden" id="node-input-msgKeyType">
</div>
</div>
<div class="node-row-sort-seq-key">
<div class="form-row">
<label for="node-input-seqKey"><i class="fa fa-filter"></i> <span data-i18n="sort.key"></span></label>
<input type="text" id="node-input-seqKey" style="width:70%;">
<input type="hidden" id="node-input-seqKeyType">
</div>
</div>
<div class="form-row">
<label><i class="fa fa-random"></i> <span data-i18n="sort.order"></span></label>
<select id="node-input-order" style="width:200px;">
<option value="ascending" data-i18n="sort.ascending"></option>
<option value="descending" data-i18n="sort.descending"></option>
</select>
</div>
<div class="form-row" id="node-as_num">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-as_num" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-as_num" style="width: 70%;" data-i18n="sort.as-number"></label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('sort',{
category: 'sequence',
color:"#E2D96E",
defaults: {
name: { value:"" },
order: { value:"ascending" },
as_num: { value:false },
target: { value:"payload" },
targetType: { value:"msg" },
msgKey: { value:"payload" },
msgKeyType: { value:"elem" },
seqKey: { value:"payload" },
seqKeyType: { value:"msg" }
},
inputs:1,
outputs:1,
icon: "sort.svg",
label: function() {
return this.name||this._("sort.sort");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
var seq = {
value: "seq",
label: RED._("node-red:sort.seq"),
hasValue: false
};
var elem = {
value: "elem",
label: RED._("node-red:sort.elem"),
hasValue: false
};
$("#node-input-target").typedInput({
default:'msg',
typeField: $("#node-input-targetType"),
types:['msg', seq]
});
$("#node-input-msgKey").typedInput({
default:'elem',
typeField: $("#node-input-msgKeyType"),
types:[elem, 'jsonata']
});
$("#node-input-seqKey").typedInput({
default:'msg',
typeField: $("#node-input-seqKeyType"),
types:['msg', 'jsonata']
});
$("#node-input-target").on("change", function(e) {
var val = $("#node-input-target").typedInput('type');
$(".node-row-sort-msg-key").toggle(val === "msg");
$(".node-row-sort-seq-key").toggle(val === "seq");
});
$("#node-input-target").change();
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="sort">
<p>Sortierung einer Nachrichteneigenschaft oder einer Nachrichtensequenz.</p>
<p>Der Node sortiert entweder das Array der vorgegebenen Nachrichteneigenschaft oder
die Reihenfolge einer Nachrichtensequenz neu.</p>
<p>Die Sortierreihenfolge kann sein:</p>
<ul>
<li><b>aufsteigend</b> oder</li>
<li><b>absteigend</b></li>
</ul>
<p>Für Zahlenwerte kann die numerische Sortierreihenfolge festgelegt werden.</p>
<p>Der Sortierschlüssel kann ein Elementwert oder ein JSONata-Ausdruck beim Sortieren einer Nachrichteneigenschaft
bzw. eine Nachrichteneigenschaft oder ein JSONata-Ausdruck beim Sortieren einer Nachrichtensequenz sein.<p>
<p>Zum Sortieren einer Nachrichtensequenz benötigt der sort-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
Diese Eigenschaft wird vom split-Node erzeugt und kann aber auch manuell erzeugt werden.
Sie hat die folgenden Eigenschaften:</p>
<p>
<ul>
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
<li><code>index</code>: Position innerhalb der Gruppe</li>
<li><code>count</code>: Gesamtzahl der Nachrichten in der Gruppe</li>
</ul>
</p>
<p><b>Hinweis</b>: Dieser Node speichert intern Nachrichten um seine Aufgabe erfüllen zu können.
Um einen unerwarteten Speicherverbrauch zu vermeiden, kann die Anzahl der gespeicherten Nachrichten begrenzt werden.
Standardmäßig ist die Nachrichtenanzahl nicht begrenzt.
Mit der Laufzeiteinstellung <code>nodeMessageBufferMaxLength</code> kann begrenzt werden,
wie viele Nachrichten im Node zwischengespeichert werden sollen.</p>
</p>
</script>
</div><div><!-- --- [red-module:node-red/batch] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="batch">
<div class="form-row">
<label for="node-input-mode"><span data-i18n="batch.mode.label"></span></label>
<select type="text" id="node-input-mode" style="width: 300px;">
<option value="count" data-i18n="batch.mode.num-msgs"></option>
<option value="interval" data-i18n="batch.mode.interval"></option>
<option value="concat" data-i18n="batch.mode.concat"></option>
</select>
</div>
<div class="node-row-msg-count">
<div class="form-row node-row-count">
<label style="margin-left: 10px; width: 175px;" for="node-input-count" data-i18n="batch.count.label"></label>
<input type="text" id="node-input-count" style="width: 50px;">
</div>
</div>
<div class="node-row-msg-overlap">
<div class="form-row node-row-overlap">
<label style="margin-left: 10px; width: 175px;" for="node-input-overlap" data-i18n="batch.count.overlap"></label>
<input type="text" id="node-input-overlap" style="width: 50px;">
</div>
</div>
<div class="node-row-msg-interval">
<div class="form-row node-row-interval">
<label style="margin-left: 10px; width: 175px;" for="node-input-interval"> <span data-i18n="batch.interval.label"></span></label>
<input type="text" id="node-input-interval" style="width: 50px;">
<span data-i18n="batch.interval.seconds"></span>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-allowEmptySequence" style="margin-left:20px; margin-right: 10px; vertical-align:top; width:auto;">
<label for="node-input-allowEmptySequence" style="width:auto;" data-i18n="batch.interval.empty"></label>
</div>
</div>
<div class="node-row-msg-concat">
<div class="form-row">
<label data-i18n="batch.concat.topics-label"></label>
<div class="form-row node-input-topics-container-row">
<ol id="node-input-topics-container"></ol>
</div>
</div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType("batch",{
category: "sequence",
color:"#E2D96E",
defaults: {
name: {value:""},
mode: {value:"count"},
count: {
value:10,
validate:function(v, opt) {
if (RED.validators.number(v) && (v >= 1)) {
return true;
}
return RED._("node-red:batch.error.invalid-count");
}
},
overlap: {
value:0,
validate:function(v, opt) {
if (RED.validators.number(v) && (v >= 0)) {
return true;
}
return RED._("node-red:batch.error.invalid-overlap");
}
},
interval: {
value:10,
validate:function(v, opt) {
if (RED.validators.number(v) && (v >= 1)) {
return true;
}
return RED._("node-red:batch.error.invalid-interval");
}
},
allowEmptySequence: {value:false},
topics: {value:[{topic:""}]}
},
inputs:1,
outputs:1,
icon: "batch.svg",
label: function() {
return this.name||this._("batch.batch");;
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
var node = this;
var topic_str = node._("batch.concat.topic");
function resizeTopics(topic) {
var newWidth = topic.width();
topic.find('.red-ui-typedInput')
.typedInput("width",newWidth-15);
}
$("#node-input-topics-container")
.css('min-height','150px').css('min-width','430px')
.editableList({
addItem: function(container, i, opt) {
if (!opt.hasOwnProperty('topic')) {
opt.topic = "";
}
var row = $('<div/>').appendTo(container);
var valueField = $('<input/>',{
class:"node-input-topic-value",
type:"text",
style:"margin-left: 5px;"
}).appendTo(row)
.typedInput({default:'str', types:['str']});
valueField.typedInput('value', opt.topic);
valueField.typedInput('type', 'str');
valueField.attr('placeholder', topic_str);
resizeTopics(container);
},
resizeItem: resizeTopics,
sortable: true,
removable: true
});
$("#node-input-count").spinner({min:1});
$("#node-input-overlap").spinner({min:0});
$("#node-input-interval").spinner({min:1});
$("#node-input-mode").on("change", function(e) {
var val = $(this).val();
$(".node-row-msg-count").toggle(val==="count");
$(".node-row-msg-overlap").toggle(val==="count");
$(".node-row-msg-interval").toggle(val==="interval");
$(".node-row-msg-concat").toggle(val==="concat");
if (val==="concat") {
var topics = node.topics;
var container = $("#node-input-topics-container");
container.editableList('empty');
for (var i = 0; i < topics.length; i++) {
var topic = topics[i];
container.editableList('addItem', topic);
}
}
});
},
oneditsave: function() {
var topics = $("#node-input-topics-container").editableList('items');
var node = this;
node.topics = [];
topics.each(function(i) {
var topicData = $(this).data('data');
var topic = $(this);
var vf = topic.find(".node-input-topic-value");
var value = vf.typedInput('value');
var type = vf.typedInput('type');
var r = {topic:value};
node.topics.push(r);
});
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-topics-container-row)");
var height = size.height;
for (var i = 0; i < rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-topics-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("#node-input-topics-container").editableList('height',height);
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="batch">
<p>Erstellung von Nachrichtensequenzen nach verschiedenen Regeln.</p>
<h3>Details</h3>
<p>Es gibt drei Modi für die Erstellung von Nachrichtensequenzen:</p>
<dl>
<dt>Gruppierung anhand Nachrichtenanzahl</dt>
<dd>Die Nachrichten werden zu Sequenzen einer vorgegebenen Länge gruppiert.
Die Option <i>Überlappung</i> gibt an, wie viele Nachrichten vom Ende einer Sequenz
am Anfang der nächsten Sequenz wiederholt werden sollen.</dd>
<dt>Gruppierung anhand Zeitintervall</dt>
<dd>Gruppierung von Nachrichten, die innerhalb des vorgegebenen Intervalls eingehen.
Wenn keine Nachrichten innerhalb des Intervalls eingehen, kann der Node optional eine leere Nachricht senden.</dd>
<dt>Verknüpfung von Sequenzen</dt>
<dd>Erzeugt eine Nachrichtensequenz durch die Verkettung eingehender Sequenzen.
Jede Nachricht muss eine <code>msg.topic</code>- und eine <code>msg.parts</code>-Eigenschaft haben,
damit die Sequenz identifiziert werden kann.
Der Node wird mit einer Liste von <code>topic</code>-Werten eingestellt,
mit der die Verknüpfungs-Reihenfolge der Sequenzen definiert wird.</dd>
</dl>
<h4><b>Speichern der Nachrichten</b></h4>
<p>Dieser Node puffert Nachrichten intern, um sequenzübergreifend arbeiten zu können.
Mit der Laufzeiteinstellung <code>nodeMessageBufferMaxLength</code> kann begrenzt werden,
wie viele Nachrichten im Node zwischengespeichert werden sollen.</p>
<p>Wenn eine Nachricht mit gesetzter <code>msg.reset</code>-Eigenschaft empfangen wurde, wird die zwischengespeicherte Nachricht gelöscht und nicht gesendet.</p>
</script>
</div><div><!-- --- [red-module:node-red/file] --- -->
<script type="text/html" data-template-name="file">
<div class="form-row node-input-filename">
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
<input id="node-input-filename" type="text">
<input type="hidden" id="node-input-filenameType">
</div>
<div class="form-row">
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
<select type="text" id="node-input-overwriteFile" style="width: 250px;">
<option value="false" data-i18n="file.action.append"></option>
<option value="true" data-i18n="file.action.overwrite"></option>
<option value="delete" data-i18n="file.action.delete"></option>
</select>
</div>
<div class="form-row form-row-file-write-options">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-appendNewline" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-appendNewline" style="width: 70%;"><span data-i18n="file.label.addnewline"></span></label>
</div>
<div class="form-row form-row-file-write-options">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-createDir" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-createDir" style="width: 70%;"><span data-i18n="file.label.createdir"></span></label>
</div>
<div class="form-row form-row-file-encoding">
<label for="node-input-encoding"><i class="fa fa-flag"></i> <span data-i18n="file.label.encoding"></span></label>
<select type="text" id="node-input-encoding" style="width: 250px;">
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name">
</div>
<div class="form-tips"><span data-i18n="file.tip"></span></div>
</script>
<script type="text/html" data-template-name="file in">
<div class="form-row">
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
<input id="node-input-filename" type="text">
<input type="hidden" id="node-input-filenameType">
</div>
<div class="form-row">
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
<select id="node-input-format" style="width: 250px;">
<option value="utf8" data-i18n="file.output.utf8"></option>
<option value="lines" data-i18n="file.output.lines"></option>
<option value="" data-i18n="file.output.buffer"></option>
<option value="stream" data-i18n="file.output.stream"></option>
</select>
</div>
<div class="form-row" id="file-allprops">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-allProps" style="display:inline-block; width:auto; vertical-align:top;">
<label for="node-input-allProps" style="width: 70%;"><span data-i18n="file.label.allProps"></span></label>
</div>
<div class="form-row" id="encoding-spec">
<label for="node-input-encoding"><i class="fa fa-flag"></i> <span data-i18n="file.label.encoding"></span></label>
<select type="text" id="node-input-encoding" style="width:250px;">
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name">
</div>
<div class="form-tips"><span data-i18n="file.tip"></span></div>
</script>
<script type="text/javascript">
(function(){
var encodings = [
[ "file.encoding.native",
"utf8",
"ucs2",
"utf-16le",
"ascii",
"binary",
"base64",
"hex"
],
[ "file.encoding.unicode",
"utf-16be",
],
[ "file.encoding.japanese",
"Shift_JIS",
"Windows-31j",
"Windows932",
"EUC-JP"
],
[ "file.encoding.chinese",
"GB2312",
"GBK",
"GB18030",
"Windows936",
"EUC-CN"
],
[ "file.encoding.korean",
"KS_C_5601",
"Windows949",
"EUC-KR"
],
[ "file.encoding.taiwan",
"Big5",
"Big5-HKSCS",
"Windows950"
],
[ "file.encoding.windows",
"cp874",
"cp1250",
"cp1251",
"cp1252",
"cp1253",
"cp1254",
"cp1255",
"cp1256",
"cp1257",
"cp1258"
],
[ "file.encoding.iso",
"ISO-8859-1",
"ISO-8859-2",
"ISO-8859-3",
"ISO-8859-4",
"ISO-8859-5",
"ISO-8859-6",
"ISO-8859-7",
"ISO-8859-8",
"ISO-8859-9",
"ISO-8859-10",
"ISO-8859-11",
"ISO-8859-12",
"ISO-8859-13",
"ISO-8859-14",
"ISO-8859-15",
"ISO-8859-16"
],
[ "file.encoding.ibm",
"cp437",
"cp737",
"cp775",
"cp808",
"cp850",
"cp852",
"cp855",
"cp856",
"cp857",
"cp858",
"cp860",
"cp861",
"cp866",
"cp869",
"cp922",
"cp1046",
"cp1124",
"cp1125",
"cp1129",
"cp1133",
"cp1161",
"cp1162",
"cp1163"
],
[ "file.encoding.mac",
"maccroatian",
"maccyrillic",
"macgreek",
"maciceland",
"macroman",
"macromania",
"macthai",
"macturkish",
"macukraine",
"maccenteuro",
"macintosh"
],
[ "file.encoding.koi8",
"koi8-r",
"koi8-u",
"koi8-ru",
"koi8-t"
],
[ "file.encoding.misc",
"armscii8",
"rk1048",
"tcvn",
"georgianacademy",
"georgianps",
"pt154",
"viscii",
"iso646cn",
"iso646jp",
"hproman8",
"tis620"
]
];
RED.nodes.registerType('file',{
category: 'storage',
defaults: {
name: {value:""},
filename: {value:""},
filenameType: {value:"str"},
appendNewline: {value:true},
createDir: {value:false},
overwriteFile: {value:"false"},
encoding: {value:"none"}
},
color:"BurlyWood",
inputs:1,
outputs:1,
icon: "file-out.svg",
label: function() {
var fn = this.filename;
if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; }
if(this.filenameType === "env") { fn = "env."+fn; }
if (this.overwriteFile === "delete") {
return this.name||this._("file.label.deletelabel",{file:fn});
} else {
return this.name||fn||this._("file.label.write");
}
},
paletteLabel: RED._("node-red:file.label.write"),
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
var encSel = $("#node-input-encoding");
var label = node._("file.encoding.none");
$("<option/>", {
value: "none",
label: label
}).text(label).appendTo(encSel);
$("<option/>", {
value: "setbymsg",
label: node._("file.encoding.setbymsg")
}).text(label).appendTo(encSel);
$("#node-input-filename").typedInput({
default: "str",
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
typeField: $("#node-input-filenameType")
});
if(typeof node.filenameType == 'undefined') {
//existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput
if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match
node.filename = "filename";
node.filenameType = "msg";
$("#node-input-filename").typedInput("type", node.filenameType);
$("#node-input-filename").typedInput("value", node.filename);
} else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR}
node.filenameType = "env";
node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) {
return (name === undefined)?"":name;
});
$("#node-input-filename").typedInput("type", node.filenameType);
$("#node-input-filename").typedInput("value", node.filename);
} else { //was using a static filename - set typedInput type to str
node.filenameType = "str";
$("#node-input-filename").typedInput("type", node.filenameType);
$("#node-input-filename").typedInput("value", node.filename);
}
}
encodings.forEach(function(item) {
if(Array.isArray(item)) {
var group = $("<optgroup/>", {
label: node._(item[0])
}).appendTo(encSel);
for (var i = 1; i < item.length; i++) {
var enc = item[i];
$("<option/>", {
value: enc,
label: enc
}).text(enc).appendTo(group);
}
}
else {
$("<option/>", {
value: item,
label: item
}).text(item).appendTo(encSel);
}
});
encSel.val(node.encoding);
$("#node-input-overwriteFile").on("change",function() {
if (this.value === "delete") {
$(".form-row-file-write-options").hide();
$(".form-row-file-encoding").hide();
} else {
$(".form-row-file-write-options").show();
$(".form-row-file-encoding").show();
}
});
}
});
RED.nodes.registerType('file in',{
category: 'storage',
defaults: {
name: {value:""},
filename: {value:""},
filenameType: {value:"str"},
format: {value:"utf8"},
chunk: {value:false},
sendError: {value: false},
encoding: {value: "none"},
allProps: {value: false}
},
color:"BurlyWood",
inputs:1,
outputs:1,
outputLabels: function(i) {
var l;
if (this.format === "utf8") {
l = "file.label.utf8String";
} else if (this.format === "lines") {
l = "file.label.utf8String_plural";
} else if (this.format === "stream") {
l = "file.label.binaryBuffer_plural";
} else {
l = "file.label.binaryBuffer";
}
return this._(l);
},
icon: "file-in.svg",
label: function() {
var fn = this.filename;
if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; }
if(this.filenameType === "env") { fn = "env."+fn; }
return this.name||fn||this._("file.label.read");
},
paletteLabel: RED._("node-red:file.label.read"),
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var node = this;
var encSel = $("#node-input-encoding");
var label = node._("file.encoding.none");
$("<option/>", {
value: "none",
label: label
}).text(label).appendTo(encSel);
$("#node-input-filename").typedInput({
default: "str",
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
typeField: $("#node-input-filenameType")
});
if(typeof node.filenameType == 'undefined') {
//existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput
if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match
node.filename = "filename";
node.filenameType = "msg";
$("#node-input-filename").typedInput("type", node.filenameType);
$("#node-input-filename").typedInput("value", node.filename);
} else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR}
node.filenameType = "env";
node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) {
return (name === undefined)?"":name;
});
$("#node-input-filename").typedInput("type", node.filenameType);
$("#node-input-filename").typedInput("value", node.filename);
} else { //was using a static filename - set typedInput type to str
node.filenameType = "str";
$("#node-input-filename").typedInput("type", node.filenameType);
$("#node-input-filename").typedInput("value", node.filename);
}
}
encodings.forEach(function(item) {
if(Array.isArray(item)) {
var group = $("<optgroup/>", {
label: node._(item[0])
}).appendTo(encSel);
for (var i = 1; i < item.length; i++) {
var enc = item[i];
$("<option/>", {
value: enc,
label: enc
}).text(enc).appendTo(group);
}
}
else {
$("<option/>", {
value: item,
label: item
}).text(item).appendTo(encSel);
}
});
encSel.val(node.encoding);
$("#node-input-format").on("change",function() {
var format = $("#node-input-format").val();
if ((format === "utf8") || (format === "lines")) {
$("#encoding-spec").show();
}
else {
$("#encoding-spec").hide();
}
if ((format === "lines") || (format === "stream")) {
$("#file-allprops").show();
}
else {
$("#file-allprops").hide();
}
});
}
});
})();
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="file">
<p>Schreiben von <code>msg.payload</code> in eine Datei entweder hinzufügend oder ersetzend.
Alternativ Löschen der Datei.</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">string</span></dt>
<dd>Sofern nicht im Node eingestellt, legt diese optionale Eigenschaft den Namen der zu aktualisierenden Datei fest.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<p>Nach Abschluss des Schreibvorgangs wird die Eingangsnachricht an den Ausgang gesendet.</p>
<h3>Details</h3>
<p>Jede Nachrichten-Nutzdaten (Payload) werden standardmäßig am Ende der Datei hinzugefügt,
optional mit Zeilenumbruchzeichen (\n) nach jeder Nachricht.</p>
<p>Wenn <code>msg.filename</code> verwendet wird, wird die Datei nach jedem Schreiben geschlossen.
Für eine optimale Leistung sollten feste Dateinamen verwendet werden.</p>
<p>Alternativ kann angegeben werden, dass die gesamte Datei überschrieben wird.
Zum Beispiel wird diese Option beim Schreiben von Binärdaten in eine Datei verwendet,
wo dann auch die Zeilenumbruch-Hinzufüge-Option deaktiviert sein sollte.</p>
<p>Alternativ kann dieser Node so eingestellt werden, dass er die Datei löscht.</p>
</script>
<script type="text/html" data-help-name="file in">
<p>Lesen von Dateiinhalt als Zeichenfolge (string) oder binären Puffer (buffer).</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">string</span></dt>
<dd>Sofern nicht im Node eingestellt, legt diese optionale Eigenschaft den Namen der zu lesenden Datei fest.</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string | buffer</span></dt>
<dd>Dateiinhalt entweder als Zeichenfolge (string) oder binärer Puffer (buffer).</dd>
<dt class="optional">filename <span class="property-type">string</span></dt>
<dd>Sofern nicht im Node eingestellt, enthält diese optionale Eigenschaft den Namen der zu lesenden Datei.</dd>
</dl>
<h3>Details</h3>
<p>Der Dateiname sollte ein absoluter Pfad sein.
Andernfalls wird er relativ zum Arbeitsverzeichnis des Node-RED-Prozesses angewandt.</p>
<p>Unter Windows müssen die Pfadtrenner (\) in Escape-Codes umgewandelt werden, z.B.: <code>\\Users\\myUser</code></p>
<p>Optional kann eine Textdatei in einzelne Zeilen mit jeweils eine Nachricht pro Zeile aufgeteilt werden.
Eine Binärdatei wird in kleine Teile in Größe abhängig vom Betriebssystem aufgeteilt,
aber typischerweise 64k (Linux/Mac) oder 41k (Windows).</p>
<p>Bei Aufteilung in mehrere Nachrichten besitzt jede eine <code>parts</code>-Eigenschaft,
welche eine komplette Nachrichten-Sequenz bildet.</p>
<p>Fehler sollten mittels catch-Nodes abgefangen und behandelt werden.</p>
</script>
</div><div><!-- --- [red-module:node-red/watch] --- -->
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-template-name="watch">
<div class="form-row node-input-filename">
<label for="node-input-files"><i class="fa fa-file"></i> <span data-i18n="watch.label.files"></span></label>
<input id="node-input-files" type="text" tabindex="1" data-i18n="[placeholder]watch.placeholder.files">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-recursive" style="display:inline-block; width:auto; vertical-align:top;">
<label for="node-input-recursive" style="width:70%;"> <span data-i18n="watch.label.recursive"></span></label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div id="node-input-tip" class="form-tips"><span data-i18n="watch.tip"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('watch',{
category: 'storage',
defaults: {
name: {value:""},
files: {value:"",required:true,
label:RED._("node-red:watch.label.files")},
recursive: {value:""}
},
color:"BurlyWood",
inputs:0,
outputs:1,
icon: "watch.svg",
label: function() {
return this.name||this.files||this._("watch.watch");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="watch">
<p>Überwachung eines Verzeichnisses oder einer Datei auf Änderungen.</p>
<p>Es kann eine kommagetrennte Liste von Verzeichnissen und/oder Dateien angegeben werden.
Es müssen Anführungszeichen "..." um alle Leerzeichen enthaltenden Einträge gesetzt werden.</p>
<p>Unter Windows müssen in allen Verzeichnisnamen doppelte Schrägstriche \\ verwendet werden.</p>
<p>Der vollständige Dateiname der geänderten Datei wird in <code>msg.payload</code> und <code>msg.filename</code> gemeldet,
während die Überwachungsliste in <code>msg.topic</code> zurückgegeben wird.</p>
<p><code>msg.file</code> enthält nur den kurzen Dateinamen der geänderten Datei.
<code>msg.type</code> enthält den Typ des geänderten Elements, normalerweise <i>file</i> oder <i>directory</i>,
während <code>msg.size</code> die Dateigröße in Bytes enthält.</p>
<p>Natürlich ist unter Linux <i>alles</i> eine Datei und kann somit beobachtet werden ...</p>
<p><b>Hinweis</b>: Das Verzeichnis oder die Datei muss vorhanden sein, um beobachtet werden zu können.
Wenn die Datei oder das Verzeichnis gelöscht wird, kann es nicht weiter überwacht werden,
auch wenn sie/es wieder neu erstellt wird.</p>
</script>
</div><div><!-- --- [red-module:node-red-contrib-influxdb/influxdb] --- -->
<script type="text/html" data-template-name="influxdb">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-config-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-row">
<label for="node-config-input-influxdbVersion"><i class="fa fa-code-fork"></i> <span data-i18n="influxdb.label.version"></span></label>
<select type="text" style="width: 100px" id="node-config-input-influxdbVersion">
<option value="1.x">1.x</option>
<option value="1.8-flux">1.8-flux</option>
<option value="2.0">2.0</option>
</select>
</div>
<div class="form-row" id="node-config-row-hostname-port">
<label for="node-config-input-hostname"><i class="fa fa-server"></i> <span data-i18n="influxdb.label.host"></span></label>
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="influxdb.label.port"></span></label>
<input type="text" id="node-config-input-port" style="width:45px">
</div>
<div class="form-row" id="node-config-row-url">
<label for="node-config-input-url"><i class="fa fa-server"></i> <span data-i18n="influxdb.label.url"></span></label>
<input class="input-append-left" type="text" id="node-config-input-url" placeholder="http://localhost:8086">
</div>
<div class="form-row" id="node-config-row-database">
<label for="node-config-input-database"><i class="fa fa-database"></i> <span data-i18n="influxdb.label.database"></span></label>
<input type="text" id="node-config-input-database">
</div>
<div class="form-row" id="node-config-row-username">
<label for="node-config-input-username"><i class="fa fa-user"></i> <span data-i18n="node-red:common.label.username"></span></label>
<input type="text" id="node-config-input-username">
</div>
<div class="form-row" id="node-config-row-password">
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="node-red:common.label.password"></span></label>
<input type="password" id="node-config-input-password">
</div>
<div class="form-row" id="node-config-row-token">
<label for="node-config-input-token"><i class="fa fa-lock"></i> <span data-i18n="influxdb.label.token"></span></label>
<input type="password" id="node-config-input-token">
</div>
<div class="form-row" id="node-config-row-rejectUnauthorized">
<input type="checkbox" id="node-config-input-rejectUnauthorized" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-rejectUnauthorized" style="width: auto" data-i18n="influxdb.label.reject-unauthorized"></label>
</div>
<div class="form-row" id="node-config-row-enableSecureConnection">
<input type="checkbox" id="node-config-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-usetls" style="width: auto" data-i18n="influxdb.label.use-tls"></label>
<div id="node-config-row-tls" class="hide">
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-config-input-tls"><span data-i18n="influxdb.label.tls-config"></span></label>
<input style="width: 300px;" type="text" id="node-config-input-tls">
</div>
</div>
</script>
<script type="text/javascript">
function getVersion() {
return $("#node-config-input-influxdbVersion option:selected").val();
}
RED.nodes.registerType('influxdb', {
category: 'config',
color: "rgb(218, 196, 180)",
defaults: {
hostname: {value: "127.0.0.1", required: true},
port: {value: 8086, required: true},
protocol: {value: "http", required: true},
database: {value: "database",
validate:function(db) {
let version = getVersion();
if (!version || version === '1.x') {
return db.length > 0;
}
return true;
}
},
name: {value: ""},
usetls: {value: false},
tls: {type:"tls-config",required: false},
influxdbVersion: {value: "1.x", required: false},
url: {value: "http://localhost:8086",
validate:function(url) {
let version = getVersion();
if (version === '1.8-flux' || version === '2.0') {
return url.length > 0;
}
return true;
}
},
rejectUnauthorized: {value: true}
},
credentials: {
username: {type: "text"},
password: { type: "password" },
token: {type: "password"}
},
label: function () {
this.influxdbVersion = this.influxdbVersion || '1.x'; // for compatibility
var version = "[v"+this.influxdbVersion+"] ";
if (this.influxdbVersion === '1.8-flux' || this.influxdbVersion === '2.0') {
return this.name ? version + this.name : version + this.url;
} else {
return this.name ? version + this.name : version + this.hostname + ":" + this.port + "/" + this.database;
}
},
oneditprepare: function () {
function updateTLSOptions() {
if ($("#node-config-input-usetls").is(':checked')) {
$("#node-config-row-tls").show();
} else {
$("#node-config-row-tls").hide();
}
}
function update18Options() {
$("#node-config-row-hostname-port").show();
$("#node-config-row-url").hide();
$("#node-config-row-database").show();
$("#node-config-row-username").show();
$("#node-config-row-password").show();
$("#node-config-row-token").hide();
$("#node-config-row-rejectUnauthorized").hide();
$("#node-config-row-enableSecureConnection").show();
}
function update18FluxOptions() {
$("#node-config-row-hostname-port").hide();
$("#node-config-row-url").show();
$("#node-config-row-database").hide();
$("#node-config-row-username").show();
$("#node-config-row-password").show();
$("#node-config-row-token").hide();
$("#node-config-row-rejectUnauthorized").show();
$("#node-config-row-enableSecureConnection").hide();
}
function update20Options() {
$("#node-config-row-hostname-port").hide();
$("#node-config-row-url").show();
$("#node-config-row-database").hide();
$("#node-config-row-username").hide();
$("#node-config-row-password").hide();
$("#node-config-row-token").show();
$("#node-config-row-rejectUnauthorized").show();
$("#node-config-row-enableSecureConnection").hide();
}
$("#node-config-input-influxdbVersion").change(function () {
let selected = $("#node-config-input-influxdbVersion option:selected").val();
switch (selected) {
case '1.8-flux':
update18FluxOptions();
break;
case '2.0':
update20Options();
break;
default: // 1.x
update18Options();
updateTLSOptions();
$("#node-config-input-usetls").on("click", function () {
updateTLSOptions();
});
}
});
// if version not set assume 1.x to support older flows
let selected = $("#node-config-input-influxdbVersion option:selected").val();
selected = selected || '1.x';
$("#node-config-input-influxdbVersion").val(selected)
}
});
</script>
<script type="text/html" data-template-name="influxdb out">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-row">
<label for="node-input-influxdb"><i class="fa fa-server"></i> <span data-i18n="influxdb.label.server"></span></label>
<input type="text" id="node-input-influxdb">
</div>
<div class="form-row" id="node-input-row-org">
<label for="node-input-org"><i class="fa fa-sitemap"></i> <span data-i18n="influxdb.label.org"></span></label>
<input type="text" id="node-input-org">
</div>
<div class="form-row" id="node-input-row-bucket">
<label for="node-input-bucket"><i class="fa fa-database"></i> <span data-i18n="influxdb.label.bucket"></span></label>
<input type="text" id="node-input-bucket">
</div>
<div class="form-row" id="node-input-row-database">
<label for="node-input-database"><i class="fa fa-database"></i> <span data-i18n="influxdb.label.database"></span></label>
<input type="text" id="node-input-database">
</div>
<div class="form-row">
<label for="node-input-measurement"><i style="width: 10px;" class="fa fa-rss"></i> <span data-i18n="influxdb.label.measurement"></span></label>
<input type="text" id="node-input-measurement">
</div>
<div class="form-row" id="node-input-row-enableAdvancedOptions">
<input type="checkbox" id="advanced-options-checkbox" style="display: inline-block; width: auto; vertical-align: top;">
<label for="advanced-options-checkbox" style="width: 70%;"><span data-i18n="influxdb.label.use-advanced-query"></span></label>
<div id="advanced-options-div" class="hide" style="margin-left: 20px; margin-top: 10px;">
<div class="form-row">
<label for="node-input-precision" style="width:35%"><i class="fa fa-clock-o"></i> <span data-i18n="influxdb.label.time-precision"></span></label>
<select type="text" id="node-input-precision" style="width:55%">
<option value="">Default</option>
<option value="n">Nanoseconds (n)</option>
<option value="u">Microseconds (u)</option>
<option value="ms">Milliseconds (ms)</option>
<option value="s">Seconds (s)</option>
<option value="m">Minute (m)</option>
<option value="h">Hour (h)</option>
<option value="d">Day (d)</option>
<option value="w">Week (w)</option>
</select>
</div>
<div class="form-row">
<label for="node-input-retentionPolicy" style="width:35%"><i class="fa fa-gavel"></i> <span data-i18n="influxdb.label.retention-policy"></span></label>
<input type="text" style="width:55%" id="node-input-retentionPolicy">
</div>
</div>
</div>
<div class="form-row" id="node-input-row-precisionV18FluxV20">
<label for="node-input-precisionV18FluxV20" style="width:35%"><i class="fa fa-clock-o"></i> <span data-i18n="influxdb.label.time-precision"></span></label>
<select type="text" id="node-input-precisionV18FluxV20" style="width:55%">
<option value="ns">Nanoseconds (ns)</option>
<option value="us">Microseconds (us)</option>
<option value="ms">Milliseconds (ms)</option>
<option value="s">Seconds (s)</option>
</select>
</div>
<div class="form-row" id="node-input-row-retentionPolicyV18Flux">
<label for="node-input-retentionPolicyV18Flux" style="width:35%"><i class="fa fa-gavel"></i> <span data-i18n="influxdb.label.retention-policy"></span></label>
<input type="text" id="node-input-retentionPolicyV18Flux" style="width:55%">
</div>
<div class="form-tips" id="node-warning-measurement"><span data-i18n="[html]influxdb.tip.measurement"></span></div>
<div class="form-tips" id="node-warning-retention-policy"><span data-i18n="[html]influxdb.tip.retention-policy"></span></div>
</script>
<script type="text/javascript">
function selectedVersion() {
// use prefix to update UI when version of config node changes
var optionSelected = $("#node-input-influxdb option:selected").text();
var influxDBVersionMatches = optionSelected.match(/\[(.*?)\]/);
var influxDBVersion = '';
if (influxDBVersionMatches) {
influxDBVersion = influxDBVersionMatches[1];
}
return influxDBVersion;
}
RED.nodes.registerType('influxdb out', {
category: 'storage-output',
color: "rgb(218, 196, 180)",
defaults: {
influxdb: {type: "influxdb", required: true},
name: {value: ""},
measurement: {value: ""},
precision: {value: ""},
retentionPolicy: {value: ""},
database: {value: "database",
validate:function(db) {
if (selectedVersion() === 'v1.8-flux') {
return db.length > 0;
}
return true;
}
},
precisionV18FluxV20: {value: "ms"},
retentionPolicyV18Flux: {value: ""},
org: {value: "organisation",
validate:function(org) {
if (selectedVersion() === 'v2.0') {
return org.length > 0;
}
return true;
}
},
bucket: {value: "bucket",
validate:function(bucket) {
let version = selectedVersion()
if (version === 'v2.0') {
return bucket.length > 0;
}
return true;
}
}
},
inputs: 1,
outputs: 0,
icon: "influxdb.png",
align: "right",
label: function() {
var influxNode = RED.nodes.node(this.influxdb);
return this.name || (influxNode ? influxNode.label() + " " + this.measurement : "influxdb");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
$("#advanced-options-checkbox").change( function () {
if ($('#advanced-options-checkbox').is(":checked")) {
$("#advanced-options-div").show();
} else {
$("#advanced-options-div").hide();
}
});
// show advanced options if a query option is set on startup
if (($('#node-input-precision').val() === "")
&& ($('#node-input-retentionPolicy').val() === "")) {
$("#advanced-options-div").hide();
} else {
$('#advanced-options-checkbox').prop('checked', true);
$("#advanced-options-div").show();
}
function update18Options() {
$("#node-input-row-org").hide();
$("#node-input-row-bucket").hide();
$("#node-input-row-database").hide();
$("#node-input-row-enableAdvancedOptions").show();
$("#node-input-row-precisionV18FluxV20").hide();
$("#node-input-row-retentionPolicyV18Flux").hide();
$("#node-warning-retention-policy").show();
}
function update18FluxOptions() {
$("#node-input-row-org").hide();
$("#node-input-row-bucket").hide();
$("#node-input-row-database").show();
$("#node-input-row-enableAdvancedOptions").hide();
$("#node-input-row-precisionV18FluxV20").show();
$("#node-input-row-retentionPolicyV18Flux").show();
$("#node-warning-retention-policy").show();
}
function update20Options() {
$("#node-input-row-org").show();
$("#node-input-row-bucket").show();
$("#node-input-row-database").hide();
$("#node-input-row-enableAdvancedOptions").hide();
$("#node-input-row-precisionV18FluxV20").show();
$("#node-input-row-retentionPolicyV18Flux").hide();
$("#node-warning-retention-policy").hide();
}
$("#node-input-influxdb").change(function () {
switch (selectedVersion()) {
case 'v1.8-flux':
update18FluxOptions();
break;
case 'v2.0':
update20Options();
break;
default:
update18Options();
}
});
$("#node-input-measurement").change(function () {
if($("#node-input-measurement").val() === "") {
$("#node-warning-measurement").show();
} else {
$("#node-warning-measurement").hide();
}
});
},
oneditsave: function() {
// reset inputs if we are not using advanced options
if (!$("#advanced-options-checkbox").is(':checked')) {
$("#node-input-precision").val("");
$("#node-input-retentionPolicy").val("");
}
}
});
</script>
<script type="text/html" data-template-name="influxdb batch">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-row">
<label for="node-input-influxdb"><i class="fa fa-server"></i> <span data-i18n="influxdb.label.server"></span></label>
<input type="text" id="node-input-influxdb">
</div>
<div class="form-row" id="node-input-row-org">
<label for="node-input-org"><i class="fa fa-sitemap"></i> <span data-i18n="influxdb.label.org"></span></label>
<input type="text" id="node-input-org">
</div>
<div class="form-row" id="node-input-row-bucket">
<label for="node-input-bucket"><i class="fa fa-database"></i> <span data-i18n="influxdb.label.bucket"></span></label>
<input type="text" id="node-input-bucket">
</div>
<div class="form-row" id="node-input-row-database">
<label for="node-input-database"><i class="fa fa-database"></i> <span data-i18n="influxdb.label.database"></span></label>
<input type="text" id="node-input-database">
</div>
<div class="form-row" id="node-input-row-enableAdvancedOptions">
<input type="checkbox" id="advanced-options-checkbox" style="display: inline-block; width: auto; vertical-align: top;">
<label for="advanced-options-checkbox" style="width: 70%;"><span data-i18n="influxdb.label.use-advanced-query"></span></label>
<div id="advanced-options-div" class="hide" style="margin-left: 20px; margin-top: 10px;">
<div class="form-row">
<label for="node-input-precision" style="width:35%"><i class="fa fa-clock-o"></i> <span data-i18n="influxdb.label.time-precision"></span></label>
<select type="text" id="node-input-precision" style="width:55%">
<option value="">Default</option>
<option value="n">Nanoseconds (n)</option>
<option value="u">Microseconds (u)</option>
<option value="ms">Milliseconds (ms)</option>
<option value="s">Seconds (s)</option>
<option value="m">Minute (m)</option>
<option value="h">Hour (h)</option>
<option value="d">Day (d)</option>
<option value="w">Week (w)</option>
</select>
</div>
<div class="form-row">
<label for="node-input-retentionPolicy" style="width:35%"><i class="fa fa-gavel"></i> <span data-i18n="influxdb.label.retention-policy"></span></label>
<input type="text" style="width:55%" id="node-input-retentionPolicy">
</div>
</div>
</div>
<div class="form-row" id="node-input-row-precisionV18FluxV20">
<label for="node-input-precisionV18FluxV20" style="width:35%"><i class="fa fa-clock-o"></i> <span data-i18n="influxdb.label.time-precision"></span></label>
<select type="text" id="node-input-precisionV18FluxV20" style="width:55%">
<option value="ns">Nanoseconds (ns)</option>
<option value="us">Microseconds (us)</option>
<option value="ms">Milliseconds (ms)</option>
<option value="s">Seconds (s)</option>
</select>
</div>
<div class="form-row" id="node-input-row-retentionPolicyV18Flux">
<label for="node-input-retentionPolicyV18Flux" style="width:35%"><i class="fa fa-gavel"></i> <span data-i18n="influxdb.label.retention-policy"></span></label>
<input type="text" id="node-input-retentionPolicyV18Flux" style="width:55%">
</div>
<div class="form-tips" id="node-warning-retention-policy"><span data-i18n="[html]influxdb.tip.retention-policy"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('influxdb batch', {
category: 'storage-output',
color: "rgb(218, 196, 180)",
paletteLabel: 'influx batch',
defaults: {
influxdb: {type: "influxdb", required: true},
precision: {value: ""},
retentionPolicy: {value: ""},
name: {value: ""},
database: {value: "database",
validate:function(db) {
if (selectedVersion() === 'v1.8-flux') {
return db.length > 0;
}
return true;
}
},
precisionV18FluxV20: {value: "ms"},
retentionPolicyV18Flux: {value: ""},
org: {value: "organisation",
validate:function(org) {
if (selectedVersion() === 'v2.0') {
return org.length > 0;
}
return true;
}
},
bucket: {value: "bucket",
validate:function(bucket) {
let version = selectedVersion()
if (version === 'v2.0') {
return bucket.length > 0;
}
return true;
}
}
},
inputs: 1,
outputs: 0,
icon: "influxdb.png",
align: "right",
label: function() {
var influxNode = RED.nodes.node(this.influxdb);
return this.name || (influxNode ? influxNode.label() : "influxdb batch");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
function update18Options() {
$("#node-input-row-org").hide();
$("#node-input-row-bucket").hide();
$("#node-input-row-database").hide();
$("#node-input-row-enableAdvancedOptions").show();
$("#node-input-row-precisionV18FluxV20").hide();
$("#node-input-row-retentionPolicyV18Flux").hide();
$("#node-warning-retention-policy").show();
}
function update18FluxOptions() {
$("#node-input-row-org").hide();
$("#node-input-row-bucket").hide();
$("#node-input-row-database").show();
$("#node-input-row-enableAdvancedOptions").hide();
$("#node-input-row-precisionV18FluxV20").show();
$("#node-input-row-retentionPolicyV18Flux").show();
$("#node-warning-retention-policy").show();
}
function update20Options() {
$("#node-input-row-org").show();
$("#node-input-row-bucket").show();
$("#node-input-row-database").hide();
$("#node-input-row-enableAdvancedOptions").hide();
$("#node-input-row-precisionV18FluxV20").show();
$("#node-input-row-retentionPolicyV18Flux").hide();
$("#node-warning-retention-policy").hide();
}
$("#node-input-influxdb").change(function () {
switch (selectedVersion()) {
case 'v1.8-flux':
update18FluxOptions();
break;
case 'v2.0':
update20Options();
break;
default:
update18Options();
}
});
$("#advanced-options-checkbox").change( function () {
if ($('#advanced-options-checkbox').is(":checked")) {
$("#advanced-options-div").show();
} else {
$("#advanced-options-div").hide();
}
});
// show advanced options if a query option is set on startup
if (($('#node-input-precision').val() === "")
&& ($('#node-input-retentionPolicy').val() === "")) {
$("#advanced-options-div").hide();
} else {
$('#advanced-options-checkbox').prop('checked', true);
$("#advanced-options-div").show();
}
},
oneditsave: function() {
// reset inputs if we are not using advanced options
if (!$("#advanced-options-checkbox").is(':checked')) {
$("#node-input-precision").val("");
$("#node-input-retentionPolicy").val("");
}
}
});
</script>
<script type="text/html" data-template-name="influxdb in">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-row">
<label for="node-input-influxdb"><i class="fa fa-server"></i> <span data-i18n="influxdb.label.server"></span></label>
<input type="text" id="node-input-influxdb">
</div>
<div class="form-row" id="node-input-row-org">
<label for="node-input-org"><i class="fa fa-sitemap"></i> <span data-i18n="influxdb.label.org"></span></label>
<input type="text" id="node-input-org">
</div>
<div class="form-row" id="node-input-row-extras">
<input type="checkbox" id="node-input-rawOutput" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-rawOutput"><span data-i18n="influxdb.label.use-raw-output"></span></label>
<input type="checkbox" id="advanced-options-checkbox" style="display: inline-block; width: auto; vertical-align: top;">
<label for="advanced-options-checkbox" style="width: 60%;"><span data-i18n="influxdb.label.use-advanced-query"></span></label>
<div id="advanced-options-div" class="hide" style="margin-left: 20px; margin-top: 10px;">
<div class="form-row">
<label for="node-input-precision" style="width:35%"><i class="fa fa-clock-o"></i> <span data-i18n="influxdb.label.time-precision"></span></label>
<select type="text" id="node-input-precision" style="width:55%">
<option value="">Default</option>
<option value="n">Nanoseconds (n)</option>
<option value="u">Microseconds (u)</option>
<option value="ms">Milliseconds (ms)</option>
<option value="s">Seconds (s)</option>
<option value="m">Minute (m)</option>
<option value="h">Hour (h)</option>
<option value="d">Day (d)</option>
<option value="w">Week (w)</option>
</select>
</div>
<div class="form-row">
<label for="node-input-retentionPolicy" style="width:35%"><i class="fa fa-gavel"></i> <span data-i18n="influxdb.label.retention-policy"></span></label>
<input type="text" style="width:55%" id="node-input-retentionPolicy">
</div>
</div>
</div>
<div>
<input type="hidden" id="node-input-query">
</div>
<div class="form-row" style="margin-bottom: 0px;">
<label for="" style="width: unset;" id="node-input-query-label"><i class="fa fa-code"></i> <span data-i18n="influxdb.label.query"></label>
</div>
<div class="form-row node-text-editor-row">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-query-editor" ></div>
</div>
<div class="form-tips" id="node-warning" style="display: none"><span data-i18n="[html]influxdb.tip.querytip"></span></div>
</script>
<script type="text/javascript">
RED.nodes.registerType('influxdb in', {
category: 'storage-input',
color: "rgb(218, 196, 180)",
defaults: {
influxdb: {type: "influxdb", required: true},
name: {value: ""},
query: {value: ""},
rawOutput: {value: false},
precision: {value: ""},
retentionPolicy: {value: ""},
org: { value: "organisation",
validate:function(org) {
if (selectedVersion() === 'v2.0') {
return org.length > 0;
}
return true;
}
}
},
inputs: 1,
outputs: 1,
icon: "influxdb.png",
label: function() {
var influxNode = RED.nodes.node(this.influxdb);
return this.name || (influxNode ? influxNode.label() : "influxdb");
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
this.editor = RED.editor.createEditor({
id: 'node-input-query-editor',
mode: 'ace/mode/text',
value: $("#node-input-query").val()
});
$("#node-input-query").change();
$("#node-input-query").change(function () {
if($("#node-input-query").val() === "") {
$("#node-warning").show();
} else {
$("#node-warning").hide();
}
});
$("#advanced-options-checkbox").change( function () {
if ($('#advanced-options-checkbox').is(":checked")) {
$("#advanced-options-div").show();
} else {
$("#advanced-options-div").hide();
}
});
// show advanced options if a query option is set on startup
if (($('#node-input-precision').val() === "")
&& ($('#node-input-retentionPolicy').val() === "")) {
$("#advanced-options-div").hide();
} else {
$('#advanced-options-checkbox').prop('checked', true);
$("#advanced-options-div").show();
}
function update18Options() {
$("#node-input-row-org").hide();
$("#node-input-row-extras").show();
}
function update18FluxOptions() {
$("#node-input-row-org").hide();
$("#node-input-row-extras").hide();
}
function update20Options() {
$("#node-input-row-org").show();
$("#node-input-row-extras").hide();
}
$("#node-input-influxdb").change(function () {
switch (selectedVersion()) {
case 'v1.8-flux':
update18FluxOptions();
break;
case 'v2.0':
update20Options();
break;
default:
update18Options();
}
});
},
oneditsave: function() {
$("#node-input-query").val(this.editor.getValue());
this.editor.destroy();
delete this.editor;
// reset inputs if we are not using advanced options
if (!$("#advanced-options-checkbox").is(':checked')) {
$("#node-input-precision").val("");
$("#node-input-retentionPolicy").val("");
}
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
}
});
</script>
<script type="text/html" data-help-name="influxdb out">
<p>A simple influxdb output node to write values and tags to an influxdb measurement.</p>
<p>The fields and tags to write are in <b>msg.payload</b>. If <b>msg.payload</b> is a string, number, or boolean,
it will be written as a single value to the specified measurement (called <i>value</i>).</p>
<p>If <b>msg.payload</b> is an object containing multiple properties, the fields will be written to the measurement.</p>
<p>If <b>msg.payload</b> is an array containing two objects, the first object will be written as the set of named fields,
the second is the set of named tags.</p>
<p>Finally, if <b>msg.payload</b> is an array of arrays, it will be written as a series of points containing fields and tags.</p>
<p>If the <i>measurement</i> field is not set in the node configuration, the user can send in data with a specified measurement
name in <b>msg.measurement</b> to overwrite the <i>measurement</i> field in the configuration of the node.</p>
<p><b>InfluxDB 1.x Mode</b></p>
<p>Check <i>Advanced Query Options</i> to specify a time precision and retention policy for the insertion.<p>
<p>The advanced query options <i>Time Precision</i> and <i>Retention Policy</i> can be overwritten using
message properties <b>msg.precision</b> and <b>msg.retentionPolicy</b>.</p>
<p><b>InfluxDB 1.8 Flux and InfluxDB 2.0 Mode</b></p>
<p>If no retention policy is specified, <i>autogen</i> will be assumed.</p>
</script><script type="text/html" data-help-name="influxdb batch">
<p><b>InfluxDB 1.8</b></p>
<p>A influxdb output node to write multiple points (fields and tags) to multiple influxdb measurements.</p>
<p>The <b>msg.payload</b> needs to be an array of <i>point</i> objects.</p>
<p>The <b>measurement</b> property of a point contains the name of the measurement for the point. The <b>fields</b> property will contain the
fields of the point. If supplied, the <b>tags</b> property will contain the tags for the point. To set the time
for the point, supply a <b>timestamp</b> property.</p>
<p>Check <i>Advanced Query Options</i> to specify a time precision and retention policy for the insertion.<p>
<p>The advanced query options <i>Time Precision</i> and <i>Retention Policy</i> can be overwritten using
message properties <b>msg.precision</b> and <b>msg.retentionPolicy</b>.</p>
</script><script type="text/html" data-help-name="influxdb in">
<p>Allows basic queries to be made to an influxdb time series database.</p>
<p>The query can be specified in the configuration property or using the property
<b>msg.query</b>. The results will be returned in <b>msg.payload</b>.</p>
<p><b>InfluxDB 1.x</b></p>
<p>To output the results of the query in the raw output format returned by InfluxDb,
check the <i>Raw Output</i> checkbox.</p>
<p>Check <i>Advanced Query Options</i> to specify a time precision and retention policy for the query.<p>
<p>The raw output configuration can be overwritten by the message property <b>msg.rawOutput</b>.</p>
<p>The advanced query options <i>Time Precision</i> and <i>Retention Policy</i> can be overwritten using
message properties <b>msg.precision</b> and <b>msg.retentionPolicy</b>.</p>
<p>&nbsp;</p><p><b>InfluxDB 1.8 Flux and InfluxDB 2.0</b></p>
<p>Uses a flux query in the configuration property or using the property
<b>msg.query</b>. The results will be returned in <b>msg.payload</b>.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_base] --- -->
<style>
:root {
--nr-db-dark-text: #444;
--nr-db-light-text: #eee;
--nr-db-disabled-text: #999;
--nr-db-mid-grey: #7f7f7f;
}
.nr-db-sb {
position: absolute;
top: 1px;
bottom: 2px;
left: 1px;
right: 1px;
overflow-y: auto;
padding: 10px;
}
.nr-db-sb .form-row label {
display: block;
width: auto;
}
.nr-db-sb .form-row input,
.nr-db-sb .form-row select {
width: calc(100% - 100px);
margin-bottom:0;
}
.nr-db-sb .compact {
margin-bottom: 8px !important;
}
.nr-db-sb .red-ui-editableList-container {
padding: 0;
min-height: 250px;
height: auto;
}
.nr-db-sb-tab-list {
min-height: 250px;
height: auto;
}
.nr-db-sb-tab-list li {
padding: 0;
}
.nr-db-sb-tab-list-item {
border-radius: 4px;
color: var(--red-ui-primary-text-color, var(--nr-db-dark-text));
}
.nr-db-sb-list-header {
cursor: pointer;
position:relative;
color: var(--red-ui-header-text-color, var(--nr-db-dark-text));
padding:3px;
white-space: nowrap;
}
.nr-db-sb-list-header:hover {
color: var(--red-ui-secondary-text-color-hover, var(--nr-db-dark-text));
}
.nr-db-sb-title-hidden {
text-decoration: line-through;
}
.nr-db-sb-title-disabled {
color: var(--red-ui-secondary-text-color-disabled, var(--nr-db-disabled-text));
}
.nr-db-sb-tab-list-header {
background: var(--red-ui-secondary-background-selected, var(--nr-db-light-text));
padding:5px;
}
.nr-db-sb-group-list-header:hover,
.nr-db-sb-widget-list-header:hover {
background: var(--red-ui-secondary-background-hover, var(--nr-db-light-text));
}
.nr-db-sb-list-chevron {
width: 15px;
text-align: center;
margin: 3px 5px 3px 5px;
}
.nr-db-sb-tab-list-item .red-ui-editableList-container {
border-radius: 0;
border: none;
height: auto !important;
min-height: unset;
}
.nr-db-sb-list-handle {
vertical-align: top;
opacity: 0;
cursor: move;
}
.nr-db-sb-list-header:hover>.nr-db-sb-list-handle,
.nr-db-sb-list-header:hover>.nr-db-sb-list-header-button-group {
opacity: 1;
}
.nr-db-sb-list-header-button-group {
opacity: 0;
}
.nr-db-sb-list-handle {
color: var(--red-ui-tertiary-text-color, var(--nr-db-light-text));
padding:5px;
}
.nr-db-sb-tab-list-header>.nr-db-sb-list-chevron {
margin-left: 0px;
transition: transform 0.2s ease-in-out;
}
.nr-db-sb-group-list-header>.nr-db-sb-list-chevron {
margin-left: 20px;
transition: transform 0.2s ease-in-out;
}
.nr-db-sb-group-list {
min-height: 10px;
}
.nr-db-sb-group-list li {
border-bottom-color: var(--red-ui-secondary-border-color, var(--nr-db-light-text));
}
.nr-db-sb-group-list>li.ui-sortable-helper {
border-top: 1px solid var(--red-ui-secondary-border-color, var(--nr-db-light-text));
}
.nr-db-sb-group-list>li:last-child {
border-bottom: none;
}
.nr-db-sb-widget-list>li {
border: none !important;
}
.nr-db-sb-group-list>li>.red-ui-editableList-item-handle {
left: 10px;
}
.nr-db-sb-list-button-group {
position: absolute;
right: 3px;
top: 0px;
z-index: 2;
}
.nr-db-sb-list-header-button-group {
position: absolute;
right: 3px;
top: 4px;
}
.nr-db-sb-list-header-button {
margin-left: 5px;
}
.nr-db-sb li.ui-sortable-helper {
opacity: 0.9;
}
.nr-db-sb-widget-icon {
margin-left: 56px;
}
.nr-db-sb-icon {
margin-right: 10px;
}
.nr-db-sb-link {
display: inline-block;
padding-left: 20px;
}
.nr-db-sb-link-name-container .fa-external-link {
margin-right: 10px;
}
.nr-db-sb-link-url {
font-size: 0.8em;
color: var(--red-ui-secondary-text-color, var(--nr-db-mid-grey));
}
span.nr-db-color-pick-container {
max-width: 50px;
border-radius: 3px;
margin-left: 15px;
}
input.nr-db-field-themeColor[type="color"] {
width: 60px !important;
padding: 0px;
height: 20px;
box-shadow: none;
position: absolute;
right: 36px;
border-radius: 3px !important;
border: solid 1px #ccc;
-webkit-appearance: none;
font-size: smaller;
text-align: center;
}
input.nr-db-field-themeColor::-webkit-color-swatch {
border: none;
}
.red-ui-tabs {
margin-bottom: 15px;
}
.red-ui-tab.hidden {
display: none;
}
#dashboard-tabs-list li a:hover {
cursor: pointer;
}
#dash-link-button {
background: none;
border: none;
margin-top: 3px;
display: inline-block;
margin: 3px 0px 0px 3px;
height: 32px;
line-height: 29px;
max-width: 200px;
overflow: hidden;
white-space: nowrap;
position: relative;
padding: 0px 7px 0px 7px;
}
ul.red-ui-dashboard-theme-styles {
list-style: none;
}
ul.red-ui-dashboard-theme-styles li {
margin-bottom: 6px;
}
.nr-db-resetIcon {
margin: 3px 6px 0px 6px;
float: right;
color: var(--red-ui-secondary-text-color, var(--nr-db-mid-grey));
opacity: 0.8;
display: block;
}
.nr-db-resetIcon:hover {
cursor: pointer;
}
#nr-db-field-font {
margin-left: 2em;
width: calc(100% - 81px);
}
.nr-db-theme-label {
font-weight: bold;
}
#custom-theme-library-container .btn-group {
margin-bottom: 10px;
}
</style>
<!-- Dashboard layout tool -->
<link rel="stylesheet" href="./Node-RED_files/gridstack.min.css">
<link rel="stylesheet" href="./Node-RED_files/gridstack-extra.min.css">
<style>
.grid-stack {
background-color: #f8f8f8;
border: solid 2px #C0C0C0;
margin: auto;
min-height: 42px;
display: table-cell;
background-image: linear-gradient(#C0C0C0 1px, transparent 0),
linear-gradient(90deg, #C0C0C0 1px, transparent 0);
background-size: 40px 43px;
}
.grid-stack>.grid-stack-item>.grid-stack-item-content {
top: 3px;
left: 5px;
right: 5px;
bottom: 3px;
}
.grid-stack-item-content {
color: #2c3e50;
text-align: center;
background-color: #b0dfe3;
border-radius: 2px;
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
white-space: nowrap;
font-size: 12px;
opacity: 0.7;
}
.grid-stack-item {
cursor: move;
}
.nr-dashboard-layout-container-fluid {
width: 100%;
padding-right: 0px;
padding-left: 0px;
margin-right: 0px;
margin-left: 0px;
}
.nr-dashboard-layout-row {
width: 100%;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: 0px;
margin-left: 0px;
}
.nr-dashboard-layout-span12 {
width: 98.4%;
padding: 2px;
margin-left: 2px;
}
.nr-dashboard-layout-span6 {
width: 49.2%;
padding: 2px;
margin-left: 2px;
}
.nr-dashboard-layout-span4 {
width: 32.7%;
padding: 2px;
margin-left: 2px;
}
.nr-dashboard-layout-span3 {
width: 24.3%;
padding: 2px;
margin-left: 2px;
}
.nr-dashboard-layout-span2 {
width: 16.0%;
padding: 2px;
margin-left: 2px;
}
.nr-dashboard-layout-resize-disable {
cursor: pointer;
float: right;
position: relative;
z-index: 90;
margin-right: 4px;
}
.nr-dashboard-layout-resize-enable {
cursor: pointer;
float: right;
position: relative;
z-index: 90;
margin-right: 1px;
}
.grid-stack>.ui-state-disabled {
opacity: 1;
background-image: none;
}
.grid-stack>.grid-stack-item>.ui-resizable-handle {
z-index: 90;
margin-right: -7px;
}
</style>
<script type="text/javascript">
(function($) {
var editSaveEventHandler;
var nodesAddEventHandler;
var nodesRemoveEventHandler;
var layoutUpdateEventHandler; // Dashboard layout tool
var uip = 'ui';
var attemptedVendorLoad = false;
var ensureDashboardNode;
var loadTinyColor = function(path) {
$.ajax({ url: path,
success: function (data) {
var jsScript = document.createElement("script");
jsScript.type = "application/javascript";
jsScript.src = path;
document.body.appendChild(jsScript);
//console.log('Tiny Color Loaded:',path);
},
error: function (xhr, ajaxOptions, thrownError) {
if (xhr.status === 404 && !attemptedVendorLoad) {
loadTinyColor('/'+uip+'/vendor/tinycolor2/dist/tinycolor-min.js');
attemptedVendorLoad = true;
}
//console.log('Tiny Color Failed to load:',path);
}
});
}
// convert to i18 text
function c_(x) {
return RED._("node-red-dashboard/ui_base:ui_base."+x);
}
// Try to load dist version first
// then if fails, load non dist version
loadTinyColor('ui_base/js/tinycolor-min.js');
//loadTinyColor('ui_base/tinycolor2/dist/tinycolor-min.js');
// Dashboard layout tool
// Load gridstack library
var loadGsLib = function(path, callback) {
$.ajax({ url: path,
success: function (data) {
var jsScript = document.createElement("script");
jsScript.type = "application/javascript";
jsScript.src = path;
document.body.appendChild(jsScript);
if (callback) { callback(); }
},
error: function (xhr, ajaxOptions, thrownError) {
// TODO
}
});
};
loadGsLib('ui_base/gs/gridstack.min.js', function() {
loadGsLib('ui_base/gs/gridstack.jQueryUI.min.js', null)
});
var tabDatas; // Layout editing tab data
var oldSpacer; // Spacer not needed after editing
var widthChange; // Group width change
var widgetResize; // Change widget event
var widgetDrag; // Drag wiget event
var MAX_GROUP_WIDTH = 50; // The maximum width is 30
/////////////////////////////////////////////////////////
// Get widget under specified tab from node information
/////////////////////////////////////////////////////////
function getTabDataFromNodes(tabID) {
var nodes = RED.nodes.createCompleteNodeSet(false);
var tab = {};
// Tab information
for (var cnt = 0; cnt < nodes.length; cnt++) {
if (nodes[cnt].type == "ui_tab" && nodes[cnt].id == tabID) {
tab = {
id: nodes[cnt].id,
name: nodes[cnt].name,
type: nodes[cnt].type,
order: nodes[cnt].order,
groups: []
};
break;
}
}
// Group information
for (var cnt = 0; cnt < nodes.length; cnt++) {
if (nodes[cnt].type == "ui_group" && nodes[cnt].tab == tabID) {
var group = {
id: nodes[cnt].id,
name: nodes[cnt].name,
type: nodes[cnt].type,
order: nodes[cnt].order,
width: nodes[cnt].width,
widgets: []
};
tab.groups.push(group);
}
}
// Widget information
var groupsIdx = {};
for (var cnt = 0; cnt < tab.groups.length; cnt++) {
groupsIdx[tab.groups[cnt].id] = tab.groups[cnt];
}
for (var cnt = 0; cnt < nodes.length; cnt++) {
var group = groupsIdx[nodes[cnt].group];
if (group != null && (/^ui_/.test(nodes[cnt].type) && nodes[cnt].type !== 'ui_link' && nodes[cnt].type !== 'ui_toast' && nodes[cnt].type !== 'ui_ui_control' && nodes[cnt].type !== 'ui_audio' && nodes[cnt].type !== 'ui_base' && nodes[cnt].type !== 'ui_group' && nodes[cnt].type !== 'ui_tab')) {
var widget = {
id: nodes[cnt].id,
type: nodes[cnt].type,
order: nodes[cnt].order,
width: nodes[cnt].width,
height: nodes[cnt].height,
auto: nodes[cnt].width == 0 ? true : false
};
group.widgets.push(widget);
if (!isLayoutToolSupported(nodes[cnt].type)) {
console.log("LayoutTool warning: Unsupported widget. Widget="+JSON.stringify(widget));
}
}
}
return tab;
}
//////////////////////////////////////////////////
// Update node information in the edited widget
////////////////////////////////////////////////////
function putTabDataToNodes() {
// Delete old flow spacer node
for (var cnt = 0; cnt < oldSpacer.length; cnt++) {
RED.nodes.remove(oldSpacer[cnt]);
RED.nodes.dirty(true);
RED.view.redraw(true);
}
var t_groups = tabDatas.groups;
for (var cnt1 = 0; cnt1 < t_groups.length; cnt1++) {
var n_group = RED.nodes.node(t_groups[cnt1].id);
n_group.width = t_groups[cnt1].width;
var t_widgets = t_groups[cnt1].widgets;
for (var cnt2 = 0; cnt2 < t_widgets.length; cnt2++) {
var n_widget = RED.nodes.node(t_widgets[cnt2].id);
if (n_widget != null) {
if (n_widget.group !== n_group.id) {
var oldGroupNode = RED.nodes.node(n_widget.group);
if (oldGroupNode) {
var index = oldGroupNode.users.indexOf(n_widget);
oldGroupNode.users.splice(index,1);
}
n_widget.group = n_group.id;
n_group.users.push(n_widget);
}
n_widget.order = t_widgets[cnt2].order;
if (t_widgets[cnt2].auto === true ) {
n_widget.width = 0;
n_widget.height = 0;
} else {
n_widget.width = t_widgets[cnt2].width;
n_widget.height = t_widgets[cnt2].height;
}
n_widget.changed = true;
n_widget.dirty = true;
RED.editor.validateNode(n_widget);
RED.events.emit("layout:update",n_widget);
RED.nodes.dirty(true);
RED.view.redraw(true);
}
else {
// Add a spacer node
if (t_widgets[cnt2].type === 'ui_spacer') {
var spaceNode = {
_def: RED.nodes.getType("ui_spacer"),
type: "ui_spacer",
hasUsers: false,
users: [],
id: RED.nodes.id(),
tab: tabDatas.id,
group: n_group.id,
order: t_widgets[cnt2].order,
name: "spacer",
width: t_widgets[cnt2].width,
height: t_widgets[cnt2].height,
z: RED.workspaces.active(),
label: function() { return this.name + " " + this.width + "x" + this.height; }
};
RED.nodes.add(spaceNode);
RED.editor.validateNode(spaceNode);
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
};
}
RED.sidebar.info.refresh();
}
////////////////////////////////////////
// Sort by order
////////////////////////////////////////
function compareOrder(a, b) {
var r = 0;
if (a.order < b.order) { r = -1; }
else if (a.order > b.order) { r = 1; }
return r;
}
////////////////////////////////////////
// Sort by XY
////////////////////////////////////////
function compareXY(a, b) {
var r = 0;
if (a.y < b.y) { r = -1; }
else if (a.y > b.y) { r = 1; }
else if (a.x < b.x) { r = -1; }
else if (a.x > b.x) { r = 1; }
return r;
}
///////////////////////////////////////////////////////
// Placeable location search (placed in the upper left)
///////////////////////////////////////////////////////
function search_point(width, height, maxWidth, maxHeight, tbl) {
for (var y=0; y < maxHeight; y++) {
for (var x=0; x < maxWidth; x++) {
if (check_matrix(x, y, width, height, maxWidth, tbl)) {
fill_matrix(x, y, width, height, maxWidth, tbl);
return {x:x, y:y};
}
}
}
return false;
}
// Check placement position
function check_matrix(px, py, width, height, maxWidth, tbl) {
if (px+width > maxWidth) return false;
for (var y=py; y < py+height; y++) {
for (var x=px; x<px+width; x++) {
if (tbl[maxWidth*y+x]) return false;
}
}
return true;
}
// Mark the placement position
function fill_matrix(px, py, width, height, maxWidth, tbl) {
for (var y=py; y < py+height; y++) {
for (var x=px; x < px+width; x++) {
tbl[maxWidth*y+x] = 1;
}
}
}
////////////////////////////////////////////////////
// Apply edit result to tab information for editing
////////////////////////////////////////////////////
function saveGridDatas() {
var groups = tabDatas.groups;
for (var cnt = 0; cnt < groups.length; cnt++) {
// Get layout editing results
var gridID = '#grid'+cnt;
var serializedData = [];
$(gridID+'.grid-stack > .grid-stack-item:visible').each( function (index) {
el = $(this);
var node = el.data('_gridstack_node');
serializedData.push({
id: el[0].dataset.noderedid,
type: el[0].dataset.noderedtype,
group: groups[cnt].id,
width: Number(node.width),
height: Number(node.height),
x: node.x,
y: node.y,
auto: (el[0].dataset.noderedsizeauto == 'true') ? true : false
});
});
var width = Number(groups[cnt].width);
var height = 0;
// Search group height
for (var i=0; i < serializedData.length; i++) {
var wd = serializedData[i];
if (height < wd.y + wd.height) {
height = wd.y + wd.height;
}
}
// Place widget on table
var tbl = new Array(width * height);
for (var i = 0; i< tbl.length; i++) {
tbl[i]=0;
}
for (var i = 0; i < serializedData.length; i++) {
var wd = serializedData[i];
for (var y = wd.y; y < wd.y+wd.height; y++) {
for (var x = wd.x; x < wd.x+wd.width; x++) {
tbl[width*y+x]=1;
}
}
}
// Add Spacer to Blank
for (var y = 0; y < height; y++) {
var spacerAdded = false;
for (var x = 0; x < width; x++) {
if (tbl[width*y+x]===0) {
if (!spacerAdded) {
// Add 1x1 spacer
serializedData.push({
x: x,
y: y,
z: RED.workspaces.active(),
width: 1,
height: 1,
name: 'spacer',
type: 'ui_spacer'
});
spacerAdded = true;
} else {
// Extend the spacer width by 1
serializedData[serializedData.length-1].width += 1;
}
} else {
spacerAdded = false;
}
}
}
// Sort Gridstack objects by x, y information
serializedData.sort(compareXY);
// Delete x and y elements as information for sorting, and give order
var order = 0;
for (i in serializedData) {
order++;
delete serializedData[i].x;
delete serializedData[i].y;
serializedData[i].order = order;
}
// Update widget information in group with edited data
var group = groups[cnt];
delete group.widgets;
group.widgets = serializedData;
}
// Save process call
putTabDataToNodes();
};
////////////////////////////////////////////////////
// Get default height for automatic settings
////////////////////////////////////////////////////
function getDefaultHeight(nodeID, groupWidth) {
var redNode = RED.nodes.node(nodeID);
var height = 1;
if (redNode.type === 'ui_gauge') {
if (redNode.gtype === 'gage') {
height = Math.round(groupWidth/2)+1;
} else if (redNode.gtype === 'wave') {
if (groupWidth < 3) {
height = 1;
} else {
height = Math.round(groupWidth*0.75);
}
} else { // donut or compass
if (groupWidth < 3) {
height = 1;
} else if (groupWidth < 11) {
height = groupWidth - 1;
} else {
height = Math.round(groupWidth*0.95);
}
}
} else if (redNode.type === 'ui_chart') {
height = Math.floor(groupWidth/2)+1;
} else if (redNode.type === 'ui_form') {
// var optNum = redNode.options.length; // Sub widget number
// if (redNode.label) {
// height = optNum + 2; // Label and Button
// } else {
// height = optNum + 1; // Button only
// }
height = redNode.rowCount
} else if (redNode.type === 'ui_lineargauge') {
if (redNode.unit && redNode.name) {
height = 5;
} else {
height = 4;
}
} else if (redNode.type === 'ui_list') {
height = 5;
} else if (redNode.type === 'ui_vega') {
height = 5;
}
return height;
}
/////////////////////////////
// Grid width change
////////////////////////////
var changeGroupWidth = function(id) {
var widthID = '#change-width'+id;
var gridID = '#grid'+id;
$(widthID).spinner( {
min: 1,
max: MAX_GROUP_WIDTH,
spin: function(event, ui) {
// Search current maximum width
var serializedData = [];
$(gridID+'.grid-stack > .grid-stack-item:visible').each( function (index) {
el = $(this);
var node = el.data('_gridstack_node');
serializedData.push({
width: Number(node.width),
x: node.x,
auto: (el[0].dataset.noderedsizeauto == 'true') ? true : false
});
});
var maxWidth = 0;
for (var i=0; i < serializedData.length; i++) {
var wd = serializedData[i];
if (wd.auto == false) {
if (maxWidth < wd.x + wd.width) {
maxWidth = wd.x + wd.width;
}
}
}
var width = ui.value;
if (width < maxWidth) {
width = maxWidth;
}
var grid = $(gridID+'.grid-stack').data('gridstack');
$(gridID+'.grid-stack').css("width", width * 40);
$(gridID+'.grid-stack').css("background-size", 100/width+"% 43px");
grid.setColumn(tabDatas.groups[id].width, true);
grid.setColumn(width, true);
tabDatas.groups[id].width = width;
$(gridID+'.grid-stack > .grid-stack-item:visible').each( function(idx, el) {
el = $(el);
var node = el.data('_gridstack_node');
var auto = (el[0].dataset.noderedsizeauto == 'true') ? true : false;
var type = el[0].dataset.noderedtype;
grid.resizable(el, !auto);
if (auto === true) {
grid.resize(el, width, getDefaultHeight(node.id, width));
}
});
if (width !== ui.value) {
event.stopPropagation();
event.preventDefault();
}
}
});
};
//////////////////////////////////
// Move between groups of widgets
//////////////////////////////////
function handleMove(grid) {
return function(ev, prevWidget, newWidget) {
var elem = newWidget.el[0];
if (elem.getAttribute("data-noderedsizeauto") === "true") {
var id = elem.getAttribute("data-noderedid");
var width = grid.grid.column;
var height = getDefaultHeight(id, width);
grid.move(elem, 0, newWidget.y);
grid.resize(elem, width, height);
var en = $(elem).find('.nr-dashboard-layout-resize-enable');
en.off('click');
en.on('click',layoutResizeEnable);
en[0].setAttribute("title",c_("layout.auto"));
}
else {
var ds = $(elem).find('.nr-dashboard-layout-resize-disable');
ds.off('click');
ds.on('click',layoutResizeDisable);
ds[0].setAttribute("title",c_("layout.manual"));
}
};
}
//////////////////////////////////////////
// Widget size change (start event)
//////////////////////////////////////////
var resizeGroupWidget = function(id) {
var gridID = '#grid'+id;
var grid = $(gridID+'.grid-stack').data('gridstack');
$(gridID+'.grid-stack').on('resizestart', function(event, ui) {
// Reset group width
grid.setColumn(tabDatas.groups[id].width, true);
});
}
//////////////////////////////////////////
// Widget drag (start event)
//////////////////////////////////////////
var dragGroupWidget = function(id) {
var gridID = '#grid'+id;
var grid = $(gridID+'.grid-stack').data('gridstack');
$(gridID+'.grid-stack').on('dragstart', function(event, ui) {
// Reset group width
grid.setColumn(tabDatas.groups[id].width, true);
});
}
//////////////////////////////////////////
// Layout resize Disable (Auto:false)
//////////////////////////////////////////
var layoutResizeDisable = function(e) {
var target = $(e.target);
var el = target.parents('.grid-stack-item:visible');
var grid = target.parents('.grid-stack').data('gridstack');
var node = el.data('_gridstack_node');
var id = Number(target.parents('.grid-stack').attr('id').slice(4));
var width = Number(tabDatas.groups[id].width);
var nodeID = el[0].dataset.noderedid;
var height = getDefaultHeight(nodeID, width);
grid.move(el, 0, node.y);
grid.resize(el, width, height);
grid.resizable(el, false);
el.find('.nr-dashboard-layout-resize-disable').off('click');
el.attr({'data-noderedsizeauto':'true'});
target.removeClass().addClass('fa fa-unlock nr-dashboard-layout-resize-enable');
el.find('.nr-dashboard-layout-resize-enable')[0].setAttribute("title",c_("layout.auto"));
el.find('.nr-dashboard-layout-resize-enable').on('click',layoutResizeEnable);
}
//////////////////////////////////////////
// Layout resize Enable (Auto:true)
//////////////////////////////////////////
var layoutResizeEnable = function(e) {
var target = $(e.target);
var el = target.parents('.grid-stack-item:visible');
var grid = target.parents('.grid-stack').data('gridstack');
grid.resizable(el, true);
el.find('.nr-dashboard-layout-resize-enable').off('click');
el.attr({'data-noderedsizeauto':'false'});
target.removeClass().addClass('fa fa-lock nr-dashboard-layout-resize-disable');
el.find('.nr-dashboard-layout-resize-disable')[0].setAttribute("title",c_("layout.manual"));
el.find('.nr-dashboard-layout-resize-disable').on('click',layoutResizeDisable);
}
//////////////////////////////////////////
// Check dashboard layout tool supported
//////////////////////////////////////////
function isLayoutToolSupported(nodeType) {
if (nodeType.indexOf("ui_") !== 0) {
return false;
}
else {
return true;
}
}
RED.nodes.registerType('ui_base', {
category: 'config',
defaults: {
name: {},
theme: {},
site: {}
},
hasUsers: false,
paletteLabel: 'Dashboard',
label: function() { return this.name || 'Node-RED Dashboard'; },
labelStyle: function() { return this.name ? "node_label_italic" : ""; },
onpaletteremove: function() {
RED.sidebar.removeTab("dashboard");
RED.events.off("editor:save",editSaveEventHandler);
RED.events.off("nodes:add",nodesAddEventHandler);
RED.events.off("nodes:remove",nodesRemoveEventHandler);
RED.events.off("layout:update",layoutUpdateEventHandler); // Dashboard layout tool
},
onpaletteadd: function() {
var globalDashboardNode = null;
var editor;
var baseStyles = ['base-color'];
var configurableStyles = ['page-titlebar-backgroundColor', 'page-backgroundColor', 'page-sidebar-backgroundColor',
'group-textColor', 'group-borderColor', 'group-backgroundColor',
'widget-textColor', 'widget-backgroundColor','widget-borderColor'];
var baseFontName = "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif";
var aTheme = {primary:"indigo", accents:"blue", warn:"red", background:"grey", palette:"light"};
// tiny colour implementation
var colours = {
leastReadable: function(base, colours) {
var least = tinycolor.readability(base, colours[0]);
var leastColor = colours[0];
for (var i=1; i<colours.length; i++) {
var readability = tinycolor.readability(base, colours[i]);
if (readability < least) {
least = readability;
leastColor = colours[i];
}
}
return leastColor;
},
whiteGreyMostReadable: function (base) {
var rgb = tinycolor(base).toRgb();
var level = ((rgb.r*299) + (rgb.g*587) + (rgb.b*114))/1000;
var readable = (level >= 128) ? '#111111' : '#eeeeee';
return readable;
},
whiteBlackLeastReadable: function(base) {
return this.leastReadable(base, ["#000000", "#ffffff"]);
},
calculate_page_backgroundColor: function(base) {
var pageBackground = "#fafafa";
var theme = "light";
if (globalDashboardNode && globalDashboardNode.hasOwnProperty("theme") && globalDashboardNode.theme.hasOwnProperty("name")) {
theme = globalDashboardNode.theme.name.split('-')[1];
}
if (theme === "dark") {
pageBackground = "#111111";
}
else if (theme === "custom") {
var whiteOrBlack = this.whiteBlackLeastReadable(base);
if (whiteOrBlack === "#000000") { pageBackground = "#111111"; }
}
return pageBackground;
},
calculate_page_sidebar_backgroundColor: function(base) {
if (this.whiteBlackLeastReadable(base) === "#000000") { return "#333333"; }
else { return "#ffffff"; }
},
calculate_page_titlebar_backgroundColor: function(base) {
return base;
},
calculate_group_textColor: function(base) {
var groupTextColour = tinycolor(base).lighten(15).toHexString();
//if (this.whiteBlackLeastReadable(base) === "#ffffff") { groupTextColour = "#000000"; }
return groupTextColour;
},
calculate_group_backgroundColor: function(base) {
var groupBackground = "#ffffff";
var theme = "light";
if (globalDashboardNode && globalDashboardNode.hasOwnProperty("theme") && globalDashboardNode.theme.hasOwnProperty("name")) {
theme = globalDashboardNode.theme.name.split('-')[1];
}
if (theme === "dark") {
groupBackground = "#333333";
}
else if (theme === "custom") {
var whiteOrBlack = this.whiteBlackLeastReadable(base);
if (whiteOrBlack === "#000000") { groupBackground = "#333333"; }
}
return groupBackground;
},
calculate_group_borderColor: function(base) {
var groupBackground = this.calculate_group_backgroundColor(base);
return this.leastReadable(groupBackground, ["#ffffff", "#555555"]);
},
calculate_widget_textColor: function(base) {
//most readable against group background
var groupBackground = this.calculate_group_backgroundColor(base);
return tinycolor.mostReadable(groupBackground, ["#111111", "#eeeeee"]).toHexString();
},
calculate_widget_backgroundColor: function(base) {
//return tinycolor(base).darken(5).toHexString()
return tinycolor(base).toHexString();
},
calculate_widget_borderColor: function(base) {
var widgetBorder = "#ffffff";
var theme = "light";
if (globalDashboardNode && globalDashboardNode.hasOwnProperty("theme") && globalDashboardNode.theme.hasOwnProperty("name")) {
theme = globalDashboardNode.theme.name.split('-')[1];
}
if (theme === "dark") {
widgetBorder = "#333333";
}
else if (theme === "custom") {
var whiteOrBlack = this.whiteBlackLeastReadable(base);
if (whiteOrBlack === "#000000") { widgetBorder = "#333333"; }
}
return widgetBorder;
},
calculate_base_font: function(base) {
return baseFontName;
}
}
var sizes = {
sx: 48, // width of <1> grid square
sy: 48, // height of <1> grid square
gx: 6, // gap between groups
gy: 6, // gap between groups
cx: 6, // gap between components
cy: 6, // gap between components
px: 0, // padding of group's cards
py: 0 // padding of group's cards
};
ensureDashboardNode = function(createMissing) {
if (globalDashboardNode !== null) {
// Check if it has been deleted beneath us
var n = RED.nodes.node(globalDashboardNode.id);
if (n === null) { globalDashboardNode = null; }
}
// Find the old dashboard node
if (globalDashboardNode === null) {
var bases = [];
RED.nodes.eachConfig(function(n) {
if (n.type === 'ui_base') { bases.push(n); }
});
// make sure we only have one ui_base node
// at the moment this will just use our existing one - deleting any new base node and theme
// at some point we may want to make this an option to select one or the other.
while (bases.length > 1) {
var n = bases.pop();
console.log("Removing ui_base node "+n.id);
RED.nodes.remove(n.id);
RED.nodes.dirty(true);
}
if (bases.length === 1) { globalDashboardNode = bases[0]; }
// If there is no dashboard node, ensure we create it after
// initialising
var noDashboardNode = (globalDashboardNode === null);
// set up theme state
var themeState = {};
var baseColor = "#0094CE"
for (var i=0; i<baseStyles.length; i++) {
themeState[baseStyles[i]] = { default:baseColor, value:baseColor, edited:false };
}
for (var j = 0; j < configurableStyles.length; j++) {
var underscore = configurableStyles[j].split("-").join("_");
var colour = colours['calculate_'+underscore](baseColor);
themeState[configurableStyles[j]] = {value:colour, edited:false};
}
themeState["base-font"] = {value:baseFontName};
var missingFields = (!globalDashboardNode || !globalDashboardNode.theme || !globalDashboardNode.site || !globalDashboardNode.site.sizes );
if (missingFields && createMissing) {
var lightTheme = {
default: baseColor,
baseColor: baseColor,
baseFont: baseFontName,
edited: false
}
var darkTheme = {
default: "#097479",
baseColor: "#097479",
baseFont: baseFontName,
edited: false
}
var customTheme = {
name: 'Untitled Theme 1',
default: "#4B7930",
baseColor: "#4B7930",
baseFont: baseFontName
}
var oldThemeName;
if (globalDashboardNode && typeof(globalDashboardNode.theme === 'string')) { oldThemeName = globalDashboardNode.theme; }
var theme = {
name: oldThemeName || "theme-light",
lightTheme: lightTheme,
darkTheme: darkTheme,
customTheme: customTheme,
themeState: themeState,
angularTheme: aTheme
}
var site_name = c_("site.title");
var site_date_format = c_("site.date-format");
var site = { name:site_name, hideToolbar:"false", allowSwipe:"false", lockMenu:"false", allowTempTheme:"true", dateFormat:site_date_format, sizes:sizes };
if (globalDashboardNode !== null) {
if (typeof globalDashboardNode.site !== "undefined") {
site = {
name: globalDashboardNode.site.name || globalDashboardNode.name,
hideToolbar: globalDashboardNode.site.hideToolbar,
lockMenu: globalDashboardNode.site.lockMenu,
allowSwipe: globalDashboardNode.site.allowSwipe,
allowTempTheme: globalDashboardNode.site.allowTempTheme,
dateFormat: globalDashboardNode.site.dateFormat,
sizes: globalDashboardNode.site.sizes
}
}
if (globalDashboardNode.theme.hasOwnProperty("angularTheme")) {
aTheme = globalDashboardNode.theme.angularTheme;
}
else { globalDashboardNode.theme.angularTheme = aTheme; }
}
if (noDashboardNode) {
globalDashboardNode = {
id: RED.nodes.id(),
_def: RED.nodes.getType("ui_base"),
type: "ui_base",
site: site,
theme: theme,
users: []
}
RED.nodes.add(globalDashboardNode);
RED.editor.validateNode(globalDashboardNode);
}
else {
globalDashboardNode["_def"] = RED.nodes.getType("ui_base");
globalDashboardNode.site = site;
globalDashboardNode.theme = theme;
delete globalDashboardNode.name;
}
$("#nr-db-field-font").val(baseFontName);
RED.nodes.dirty(true);
}
}
}
var content = $("<div>").css({"position":"relative","height":"100%"});
var mainContent = $("<div>",{class:"nr-db-sb"}).appendTo(content);
var form = $('<form class="dialog-form">').appendTo(mainContent);
// Dashboard Tabs markup
var divTab = $('<div class="red-ui-tabs">').appendTo(form);
var ulDashboardTabs = $('<ul id="dashboard-tabs-list"></ul>').appendTo(divTab);
var layout_label = c_("label.layout");
var site_label = c_("label.site");
var theme_label = c_("label.theme");
var angular_label = c_("label.angular");
var liLayoutTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Layout"><span>'+layout_label+'</span></a></li>').appendTo(ulDashboardTabs);
var liSiteTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Site" style="width:60px;"><span>'+site_label+'</span></a></li>').appendTo(ulDashboardTabs);
var liThemeTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Theme" style="width:80px;"><span>'+theme_label+'</span></a></li>').appendTo(ulDashboardTabs);
var liAngularTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Angular" style="width:80px;"><span>'+angular_label+'</span></a></li>').appendTo(ulDashboardTabs);
// Link out to dashboard
$.getJSON('uisettings',function(data) {
if (data.hasOwnProperty("path")) { uip = data.path; }
var lnk = document.location.host+RED.settings.httpNodeRoot+"/"+uip;
var re = new RegExp('\/{1,}','g');
lnk = lnk.replace(re,'/');
if (!RED.hasOwnProperty("actions")) {
RED.keyboard.add("*",/* d */ 68,{ctrl:true, shift:true},function() { window.open(document.location.protocol+"//"+lnk, "nr-dashboard") });
}
else {
RED.actions.add("dashboard:show-dashboard",function() { window.open(document.location.protocol+"//"+lnk, "nr-dashboard") });
RED.keyboard.add("*","ctrl-shift-d","dashboard:show-dashboard");
}
$('<span id="dash-link-button" class="editor-button" style="position:absolute; right:0px;"><i class="fa fa-external-link"></i></span>')
.click(function(evt) {
window.open(document.location.protocol+"//"+lnk);
evt.preventDefault();
})
.appendTo(ulDashboardTabs);
});
// Dashboard Tab containers
var layoutTab = $('<div id="dashboard-layout" style="height:calc(100% - 48px)">').appendTo(form);
var siteTab = $('<div id="dashboard-site" style="display:none;">').appendTo(form);
var themeTab = $('<div id="dashboard-theme" style="display:none;">').appendTo(form);
var angularTab = $('<div id="dashboard-angular" style="display:none;">').appendTo(form);
ulDashboardTabs.children().first().addClass("active");
// Tab logic
var onTabClick = function() {
//Toggle tabs
ulDashboardTabs.children().removeClass("active");
ulDashboardTabs.children().css({"transition": "width 100ms"});
$(this).parent().addClass("active");
var selectedTab = $(this)[0].title;
if (selectedTab === 'Layout') {
themeTab.hide();
siteTab.hide();
angularTab.hide();
layoutTab.show();
}
else if (selectedTab === 'Angular') {
themeTab.hide();
siteTab.hide();
angularTab.show();
layoutTab.hide();
}
else if (selectedTab === 'Theme') {
layoutTab.hide();
siteTab.hide();
angularTab.hide();
themeTab.show();
if ($("#nr-db-field-theme option:selected").val() === 'theme-custom') { themeSettingsContainer.show(); }
else { themeSettingsContainer.hide(); }
}
else {
layoutTab.hide();
themeTab.hide();
angularTab.hide();
siteTab.show();
}
}
ulDashboardTabs.find("li.red-ui-tab a").on("click",onTabClick)
// Site Tab
var divTitle = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
$('<div>').html('<b>'+c_("label.title")+'</b>').appendTo(divTitle);
$('<input type="text" id="nr-db-field-title">').val(site_name).css("width","100%")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.site.name !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.site.name = $(this).val();
}
RED.nodes.dirty(true);
})
.appendTo(divTitle);
var divHideToolbar = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
$('<div>').html('<b>'+c_("label.options")+'</b>').appendTo(divHideToolbar);
$('<select id="nr-db-field-hideToolbar">')
.css("width","100%")
.append($('<option>', { value:"false", text:c_("title-bar.show"), selected:true }))
.append($('<option>', { value:"true", text:c_("title-bar.hide") }))
.val("false")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.site.hideToolbar !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.site.hideToolbar = $(this).val();
}
RED.nodes.dirty(true);
})
.appendTo(divHideToolbar);
var divLockMenu = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
$('<select id="nr-db-field-lockMenu">')
.css("width","100%")
.append($('<option>', { value:"false", text:c_("lock.clicked"), selected:true }))
.append($('<option>', { value:"true", text:c_("lock.locked") }))
.append($('<option>', { value:"icon", text:c_("lock.locked-icon") }))
.val("false")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.site.lockMenu !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.site.lockMenu = $(this).val();
}
RED.nodes.dirty(true);
})
.appendTo(divLockMenu);
var divAllowSwipe = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
$('<select id="nr-db-field-allowSwipe">')
.css("width","100%")
.append($('<option>', { value:"false", text:c_("swipe.no-swipe"), selected:true }))
.append($('<option>', { value:"true", text:c_("swipe.allow-swipe") }))
.append($('<option>', { value:"mouse", text:c_("swipe.allow-swipe-mouse") }))
.append($('<option>', { value:"menu", text:c_("swipe.show-menu") }))
.val("false")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.site.allowSwipe !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.site.allowSwipe = $(this).val();
RED.nodes.dirty(true);
}
})
.appendTo(divAllowSwipe);
var divAllowTempTheme = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
$('<select id="nr-db-field-allowTempTheme">')
.css("width","100%")
.append($('<option>', { value:"true", text:c_("temp.allow-theme"), selected:true }))
.append($('<option>', { value:"false", text:c_("temp.no-theme") }))
.append($('<option>', { value:"none", text:c_("temp.none") }))
.val("true")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.site.allowTempTheme !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.site.allowTempTheme = $(this).val();
}
if ($('#nr-db-field-allowTempTheme').val() === "none") {
ulDashboardTabs.children().eq(2).addClass("hidden");
ulDashboardTabs.children().eq(3).removeClass("hidden");
}
else {
ulDashboardTabs.children().eq(2).removeClass("hidden");
ulDashboardTabs.children().eq(3).addClass("hidden");
}
RED.nodes.dirty(true);
})
.appendTo(divAllowTempTheme);
var site_name = c_("site.title");
var site_date_format = c_("site.date-format");
var divDateFormat = $('<div>',{class:"form-row"}).appendTo(siteTab);
$('<div>').html('<b>'+c_("label.date-format")+'</b>')
.css("width","80%")
.css("display","inline-block")
.appendTo(divDateFormat);
$('<div>').html("<a href='https://momentjs.com/docs/#/displaying/format/' target='_new'><i class='fa fa-info-circle' style='color:grey;'></i></a>")
.css("display","inline-block")
.css("margin-right","6px")
.css("float","right")
.appendTo(divDateFormat);
$('<input type="text" id="nr-db-field-dateFormat">').val(site_date_format).css("width","100%")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.site.dateFormat !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.site.dateFormat = $(this).val();
}
RED.nodes.dirty(true);
})
.appendTo(divDateFormat);
var divSetSizes = $('<div>',{class:"form-row"}).appendTo(siteTab);
$('<span style="width:45%; display:inline-block">').html('<b>'+c_("label.sizes")+'</b>').appendTo(divSetSizes);
$('<span style="width:25%; display:inline-block; font-size:smaller">').text(c_("label.horizontal")).appendTo(divSetSizes);
$('<span style="width:20%; display:inline-block; font-size:smaller">').text(c_("label.vertical")).appendTo(divSetSizes);
$('<i id="sizes-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:1.0})
.click(function(e) {
$("#nr-db-field-sx").val(sizes.sx); globalDashboardNode.site.sizes.sx = sizes.sx;
$("#nr-db-field-sy").val(sizes.sy); globalDashboardNode.site.sizes.sy = sizes.sy;
$("#nr-db-field-px").val(sizes.px); globalDashboardNode.site.sizes.px = sizes.px;
$("#nr-db-field-py").val(sizes.py); globalDashboardNode.site.sizes.py = sizes.py;
$("#nr-db-field-gx").val(sizes.gx); globalDashboardNode.site.sizes.gx = sizes.gx;
$("#nr-db-field-gy").val(sizes.gy); globalDashboardNode.site.sizes.gy = sizes.gy;
$("#nr-db-field-cx").val(sizes.cx); globalDashboardNode.site.sizes.cx = sizes.cx;
$("#nr-db-field-cy").val(sizes.cy); globalDashboardNode.site.sizes.cy = sizes.cy;
RED.nodes.dirty(true);
})
.appendTo(divSetSizes);
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.widget-size")).appendTo(divSetSizes);
$('<input type="number" name="sx" min="24" id="nr-db-field-sx">').val(48).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.sx=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
$('<input type="number" name="sy" min="24" id="nr-db-field-sy">').val(48).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.sy=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.widget-spacing")).appendTo(divSetSizes);
$('<input type="number" name="cx" min="0" id="nr-db-field-cx">').val(6).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.cx=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
$('<input type="number" name="cy" min="0" id="nr-db-field-cy">').val(6).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.cy=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.group-padding")).appendTo(divSetSizes);
$('<input type="number" name="px" min="0" id="nr-db-field-px">').val(0).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.px=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
$('<input type="number" name="py" min="0" id="nr-db-field-py">').val(0).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.py=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.group-spacing")).appendTo(divSetSizes);
$('<input type="number" name="gx" min="0" id="nr-db-field-gx">').val(6).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.gx=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
$('<input type="number" name="gy" min="0" id="nr-db-field-gy">').val(6).css("width","20%")
.on("change", function() {
//ensureDashboardNode(true);
globalDashboardNode.site.sizes.gy=Number($(this).val()); RED.nodes.dirty(true); } )
.appendTo(divSetSizes);
// Angular Theme Tab
var changed = function() {
ensureDashboardNode(true);
globalDashboardNode.theme.angularTheme = aTheme;
RED.nodes.dirty(true);
}
var angColorList = ["red", "pink", "purple", "deep-purple", "indigo", "blue", "light-blue", "cyan", "teal", "green", "light-green", "lime", "yellow", "amber", "orange", "deep-orange", "brown", "grey", "blue-grey"];
var angColors = "";
angColorList.forEach(function(c) { angColors += '<option value="' + c + '">' + c + '</option>'; });
var divPrimStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
$('<span style="width:45%; display:inline-block">')
.html('<b>'+c_("style.primary")+'</b>')
.appendTo(divPrimStyle);
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:1.0})
.click(function(e) {
$("#nr-db-field-angPrimary").val("indigo");
globalDashboardNode.theme.angularTheme.primary = "indigo";
RED.nodes.dirty(true);
})
.appendTo(divPrimStyle);
$('<select id="nr-db-field-angPrimary">'+angColors+'</select>')
.css("width","100%")
.val(aTheme.primary)
.on("change", function() { aTheme.primary = $(this).val(); changed(); })
.appendTo(divPrimStyle);
var divAccStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
$('<span style="width:45%; display:inline-block">')
.html('<b>'+c_("style.accents")+'</b>')
.appendTo(divAccStyle);
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:1.0})
.click(function(e) {
$("#nr-db-field-angAccents").val("blue");
globalDashboardNode.theme.angularTheme.accents = "blue";
RED.nodes.dirty(true);
})
.appendTo(divAccStyle);
$('<select id="nr-db-field-angAccents">'+angColors+'</select>')
.css("width","100%")
.val(aTheme.accents)
.on("change", function() { aTheme.accents = $(this).val(); changed(); })
.appendTo(divAccStyle);
var divWarnStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
$('<span style="width:45%; display:inline-block">')
.html('<b>'+c_("style.warnings")+'</b>')
.appendTo(divWarnStyle);
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:1.0})
.click(function(e) {
$("#nr-db-field-angWarn").val("red");
globalDashboardNode.theme.angularTheme.warn = "red";
RED.nodes.dirty(true);
})
.appendTo(divWarnStyle);
$('<select id="nr-db-field-angWarn">'+angColors+'</select>')
.css("width","100%")
.val(aTheme.warn)
.on("change", function() { aTheme.warn = $(this).val(); changed(); })
.appendTo(divWarnStyle);
var divBackStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
$('<span style="width:45%; display:inline-block">')
.html('<b>'+c_("style.background")+'</b>')
.appendTo(divBackStyle);
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:1.0})
.click(function(e) {
$("#nr-db-field-angBackground").val("grey");
globalDashboardNode.theme.angularTheme.background = "grey";
RED.nodes.dirty(true);
})
.appendTo(divBackStyle);
$('<select id="nr-db-field-angBackground">'+angColors+'</select>')
.css("width","100%")
.val(aTheme.background)
.on("change", function() { aTheme.background = $(this).val(); changed(); })
.appendTo(divBackStyle);
var divPalStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
$('<span style="width:45%; display:inline-block">')
.html('<b>'+c_("style.palette")+'</b>')
.appendTo(divPalStyle);
var lightdark = '<option value="light">' +c_("style.light")+ '</option>';
lightdark += '<option value="dark">' +c_("style.dark")+ '</option>';
$('<select id="nr-db-field-angLook">'+lightdark+'</select>')
.css("width","100%")
.val(aTheme.palette)
.on("change", function() { aTheme.palette = $(this).val(); changed(); })
.appendTo(divPalStyle);
// Theme Tab
// For all customisable styles, generate and apply the css
var generateColours = function(base) {
var theme = globalDashboardNode.theme.name.split('-')[1];
if (!globalDashboardNode.theme.themeState.hasOwnProperty["base-font"]) {
if (globalDashboardNode.theme[theme+"Theme"].baseFont === "Helvetica Neue") {
globalDashboardNode.theme[theme+"Theme"].baseFont = baseFontName;
}
globalDashboardNode.theme.themeState["base-font"] = {value:globalDashboardNode.theme[theme+"Theme"].baseFont};
$("#nr-db-field-font").val(globalDashboardNode.theme[theme+"Theme"].baseFont);
}
for (var i=0; i<configurableStyles.length; i++) {
var styleID = configurableStyles[i];
var underscore = styleID.split("-").join("_");
if (!globalDashboardNode.theme.themeState.hasOwnProperty(styleID)) {
globalDashboardNode.theme.themeState[styleID] = {value:"#fff",edited:false};
}
if (!globalDashboardNode.theme.themeState[styleID].edited || globalDashboardNode.theme[theme+'Theme'].reset) {
var colour = colours['calculate_'+underscore](base);
globalDashboardNode.theme.themeState[styleID].value = colour;
}
setColourPickerColour(styleID, globalDashboardNode.theme.themeState[styleID].value, globalDashboardNode.theme.themeState[styleID].edited);
}
globalDashboardNode.theme[theme+'Theme'].reset = false;
}
var divThemeStyle = $('<div>',{class:"form-row"}).appendTo(themeTab);
$('<label class="nr-db-theme-label">').text(c_("theme.style")).appendTo(divThemeStyle);
var themeSelection = $('<select id="nr-db-field-theme">'+
'<option value="theme-light">'+c_("style.light")+'</option>'+
'<option value="theme-dark">'+c_("style.dark")+'</option>'+
'<option value="theme-custom">'+c_("style.custom")+'</option>'+
'</select>')
.css("width","100%")
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.theme.name !== $(this).val()) {
//ensureDashboardNode(true);
var theme = globalDashboardNode.theme.name.split('-')[1];
var baseColour = globalDashboardNode.theme[theme+'Theme'].baseColor;
var baseFont = globalDashboardNode.theme[theme+'Theme'].baseFont;
globalDashboardNode.theme.name = $(this).val();
theme = globalDashboardNode.theme.name.split('-')[1];
if (theme !== "custom") {
baseColour = globalDashboardNode.theme[theme+'Theme'].default;
}
else { baseColour = globalDashboardNode.theme[theme+'Theme'].baseColor; }
setColourPickerColour("base-color", baseColour);
globalDashboardNode.theme.themeState['base-color'].value = baseColour;
globalDashboardNode.theme.themeState['base-color'].default = baseColour;
globalDashboardNode.theme.themeState['base-font'] = {value:baseFont};
$("#nr-db-field-font").val(baseFont);
globalDashboardNode.theme[theme+'Theme'].reset = true;
//generate colours for all colour settings from base colour
generateColours(baseColour);
RED.nodes.dirty(true);
}
$('#base-color-reset').remove();
if ($(this).val() === 'theme-custom') {
$("#custom-theme-library-container").show(); //TODO undo this at some point
$("#custom-theme-settings").show();
//addResetButton('base-color', baseSettingsUl.children());
}
else {
$("#custom-theme-library-container").hide();
$("#custom-theme-settings").hide();
addLightAndDarkResetButton('base-color', baseSettingsUl.children().first());
}
})
.appendTo(divThemeStyle);
var customThemeLibraryContainer = $('<div id="custom-theme-library-container">').appendTo(themeTab);
$('<label class="nr-db-theme-label">').text(c_("theme.custom-profile")).appendTo(customThemeLibraryContainer);
$('<input type="text" id="ui-sidebar-name" style="vertical-align:top;" placeholder="profile name (not blank)">')
.val(c_("theme.custom-profile-name"))
.on("change", function() {
if (!globalDashboardNode || globalDashboardNode.theme.customTheme.name !== $(this).val()) {
//ensureDashboardNode(true);
globalDashboardNode.theme.customTheme.name = $(this).val();
if (editor) {
editor.setValue(JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site}),1);
RED.nodes.dirty(true);
}
}
})
.keyup(function() {
if ($(this).val().length === 0) {
$("#custom-theme-library-container div").css("pointer-events","none");
}
else { $("#custom-theme-library-container div").css("pointer-events","inherit"); }
})
.appendTo(customThemeLibraryContainer);
$('<input type="hidden" id="nr-db-field-format">').appendTo(customThemeLibraryContainer);
$('<div style="display:none;" class="node-text-editor" id="nr-db-field-format-editor"></div>').appendTo(customThemeLibraryContainer);
var baseThemeSettingsContainer = $('<div id="base-theme-settings">').appendTo(themeTab);
var baseSettings = $('<div>',{class:"form-row"}).appendTo(baseThemeSettingsContainer);
$('<label class="nr-db-theme-label">').text(c_("theme.base-settings")).appendTo(baseSettings);
var baseSettingsUl = $('<ul id="base-settings-ul" class="red-ui-dashboard-theme-styles"></ul>').appendTo(baseSettings);
var baseColourItem = $('<li class="red-ui-dashboard-theme-item"><span>'+c_("base.colour")+'</span></li>').appendTo(baseSettingsUl);
var spanColorContainer = $('<span class="nr-db-color-pick-container"></span>').appendTo(baseColourItem);
$('<input id="base-color" class="nr-db-field-themeColor" type="color" value="#ffffff"/>')
.on("change", function() {
//ensureDashboardNode(true);
var value = $(this).val();
var lightThemeMatch = globalDashboardNode.theme.lightTheme.baseColor === value;
var darkThemeMatch = globalDashboardNode.theme.darkTheme.baseColor === value;
var customThemeMatch = globalDashboardNode.theme.customTheme.baseColor === value;
if (!globalDashboardNode || !lightThemeMatch || !darkThemeMatch || !customThemeMatch) {
var theme = globalDashboardNode.theme.name.split('-')[1];
globalDashboardNode.theme[theme+'Theme'].baseColor = value;
if (globalDashboardNode.theme.name === 'theme-light' || globalDashboardNode.theme.name === 'theme-dark') {
//for light and dark themes, reset the colours
globalDashboardNode.theme[theme+'Theme'].reset = true;
}
generateColours(value);
editor.setValue(JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site}),1);
colourPickerChangeHandler($(this).attr('id'), value);
}
})
.appendTo(spanColorContainer);
var baseFontItem = $('<li class="red-ui-dashboard-theme-item"><span>'+c_("base.font")+'</span></li>').appendTo(baseSettingsUl);
var fontSelector = $('<select id="nr-db-field-font">'+
'<option value="'+baseFontName+'" style="font-family:'+baseFontName+'">'+c_("font.system")+'</option>'+
'<option value="Arial,Arial,Helvetica,sans-serif" style="font-family:Arial,Arial,Helvetica,sans-serif">Arial</option>'+
'<option value="Arial Black,Arial Black,Gadget,sans-serif" style="font-family:Arial Black,Arial Black,Gadget,sans-serif">Arial Black</option>'+
'<option value="Arial Narrow,Nimbus Sans L,sans-serif" style="font-family:Arial Narrow,Nimbus Sans L,sans-serif">Arial Narrow</option>'+
'<option value="Century Gothic,CenturyGothic,AppleGothic,sans-serif" style="font-family:Century Gothic,CenturyGothic,AppleGothic,sans-serif">Century Gothic</option>'+
'<option value="Copperplate,Copperplate Gothic Light,fantasy" style="font-family:Copperplate,Copperplate Gothic Light,fantasy;">Copperplate</option>'+
'<option value="Courier,monospace" style="font-family:Courier,monospace;">Courier</option>'+
'<option value="Georgia,Georgia,serif" style="font-family:Georgia,Georgia,serif">Georgia</option>'+
'<option value="Gill Sans,Geneva,sans-serif" style="font-family:Gill Sans,Geneva,sans-serif;">Gill Sans</option>'+
//'<option value="Helvetica Neue,Helvetica,sans-serif" style="font-family:Helvetica Neue,Helvetica,sans-serif">Helvetica Neue</option>'+
'<option value="Impact,Impact,Charcoal,sans-serif" style="font-family:Impact,Impact,Charcoal,sans-serif">Impact</option>'+
'<option value="Lucida Sans Typewriter,Lucida Console,Monaco,monospace" style="font-family:Lucida Console,Monaco,monospace">Lucida Console</option>'+
'<option value="Lucida Sans Unicode,Lucida Grande,sans-serif" style="font-family:Lucida Sans Unicode,Lucida Grande,sans-serif">Lucida Sans</option>'+
'<option value="Palatino Linotype,Palatino,Book Antiqua,serif" style="font-family:Palatino Linotype,Palatino,Book Antiqua,serif">Palatino Linotype</option>'+
'<option value="Tahoma,Geneva,sans-serif" style="font-family:Tahoma,Geneva,sans-serif">Tahoma</optionstyle="font-family:>'+
'<option value="Times New Roman,Times,serif" style="font-family:Times New Roman,Times,serif">Times New Roman</option>'+
'<option value="Trebuchet MS,Helvetica,sans-serif" style="font-family:Trebuchet MS,Helvetica,sans-serif">Trebuchet MS</option>'+
'<option value="Verdana,Verdana,Geneva,sans-serif" style="font-family:Verdana,Verdana,Geneva,sans-serif">Verdana</option>'+
'</select>')
.on("change", function() {
//ensureDashboardNode(true);
var theme = globalDashboardNode.theme.name.split('-')[1];
globalDashboardNode.theme[theme+'Theme'].baseFont = $(this).val();
globalDashboardNode.theme.themeState['base-font'] = {value:$(this).val()};
RED.nodes.dirty(true);
})
.appendTo(baseFontItem);
var themeSettingsContainer = $('<div id="custom-theme-settings">').appendTo(themeTab);
// Markup
// Page styles
var divPageStyle = $('<div>',{class:"form-row"}).appendTo(themeSettingsContainer);
$('<label class="nr-db-theme-label">').text(c_("theme.page-settings")).appendTo(divPageStyle);
var pageStyles = $('<ul class="red-ui-dashboard-theme-styles"></ul>').appendTo(themeSettingsContainer);
addCustomisableStyle('page-titlebar-backgroundColor', c_("theme.page.title"), pageStyles);
addCustomisableStyle('page-backgroundColor', c_("theme.page.page"), pageStyles);
addCustomisableStyle('page-sidebar-backgroundColor', c_("theme.page.side"), pageStyles);
// Group styles
var divGroupStyle = $('<div>',{class:"form-row"}).appendTo(themeSettingsContainer);
$('<label class="nr-db-theme-label">').text(c_("theme.group-settings")).appendTo(divGroupStyle);
var groupStyles = $('<ul class="red-ui-dashboard-theme-styles"></ul>').appendTo(themeSettingsContainer);
addCustomisableStyle('group-textColor', c_("theme.group.text"), groupStyles);
addCustomisableStyle('group-borderColor', c_("theme.group.border"), groupStyles);
addCustomisableStyle('group-backgroundColor', c_("theme.group.background"), groupStyles);
// Widget styles
var divWidgetStyle = $('<div>',{class:"form-row"}).appendTo(themeSettingsContainer);
$('<label class="nr-db-theme-label">').text(c_("theme.widget-settings")).appendTo(divWidgetStyle);
var widgetStyles = $('<ul class="red-ui-dashboard-theme-styles"></ul>').appendTo(themeSettingsContainer);
addCustomisableStyle('widget-textColor', c_("theme.widget.text"), widgetStyles);
addCustomisableStyle('widget-backgroundColor', c_("theme.widget.colour"), widgetStyles);
addCustomisableStyle('widget-borderColor', c_("theme.widget.background"), widgetStyles);
function addCustomisableStyle(id, name, parentUl) {
var styleLi = $('<li class="red-ui-dashboard-theme-item"><span>'+name+'</span></li>').appendTo(parentUl);
var spanColorContainer = $('<span class="nr-db-color-pick-container"></span>').appendTo(styleLi);
$('<input id="'+id+'" class="nr-db-field-themeColor" type="color" value="#ffffff"/>')
.on("change", function() {
colourPickerChangeHandler($(this).attr('id'), $(this).val());
})
.appendTo(spanColorContainer);
addResetButton(id, styleLi);
}
function colourPickerChangeHandler(id, value) {
$("#"+id).css("background-color", value);
$("#"+id+"-reset").css({opacity:1});
globalDashboardNode.theme.themeState[id].edited = true;
globalDashboardNode.theme.themeState[id].value = value;
if (editor) {
editor.setValue(JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site}),1);
}
RED.nodes.dirty(true);
}
function addResetButton(id, parent) {
var resetToDefault = $('<i id="'+id+'-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:0.2})
.click(function(e) { resetClick(e); })
.appendTo(parent);
}
function addLightAndDarkResetButton(id, parent) {
if ($("#" + id + "-reset").length === 0) {
var resetToDefault = $('<i id="'+id+'-reset" class="fa fa-undo nr-db-resetIcon"></i>')
.css({opacity:1})
.click(function(e) { lightAndDarkResetClick(e); })
.appendTo(parent);
globalDashboardNode.theme[globalDashboardNode.theme.name.split('-')[1] + 'Theme'].edited = true;
}
}
function lightAndDarkResetClick(e) {
var elementID = e.target.id.split('-reset')[0];
var key = globalDashboardNode.theme.name.split('-')[1] + 'Theme';
//sanity check - light and dark only allow base-color-reset
if (elementID === 'base-color') { // && globalDashboardNode.theme[key].edited) {
var defaultColor = globalDashboardNode.theme[key].default;
globalDashboardNode.theme[key].reset = true;
generateColours(defaultColor);
setColourPickerColour(elementID, defaultColor);
$("#"+elementID+"-reset").css({opacity:0.2});
globalDashboardNode.theme.themeState[elementID].value = defaultColor;
globalDashboardNode.theme[key].baseColor = defaultColor;
globalDashboardNode.theme[key].edited = false;
RED.nodes.dirty(true);
}
}
function resetClick(e) {
//take off -reset
var elementID = e.target.id.split('-reset')[0];
if (globalDashboardNode.theme.themeState[elementID].edited) {
var defaultColor = globalDashboardNode.theme.themeState['base-color'].value;
var colour;
//set colour
if (elementID === 'base-color') {
colour = defaultColor;
generateColours(colour);
}
else {
var underscore = elementID.split('-').join('_');
colour = colours['calculate_'+underscore](defaultColor);
}
setColourPickerColour(elementID, colour);
$("#"+elementID+"-reset").css({opacity:0.2});
globalDashboardNode.theme.themeState[elementID].edited = false;
globalDashboardNode.theme.themeState[elementID].value = colour;
RED.nodes.dirty(true);
}
}
function setColourPickerColour(id, val, ed) {
$("#"+id).val(val);
$("#"+id).css("background-color", val);
//call mostReadableGreyWhite to set text colour
var textColor = colours.whiteGreyMostReadable(val);
$("#"+id).css("color", textColor);
if (ed === true) { $("#"+id+"-reset").css({opacity:1}); }
else { $("#"+id+"-reset").css({opacity:0.2}); }
}
//Layout Tab
var divTabs = $('<div>',{class:"form-row",style:"position:relative"}).appendTo(layoutTab);
$('<label>').html('<b>'+c_("layout.tab-and-link")+'</b>').appendTo(divTabs);
var buttonGroup = $('<div>',{class:"nr-db-sb-list-button-group"}).appendTo(divTabs);
//Toggle expand buttons
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-angle-double-up"></i></a>')
.click(function(evt) {
tabContainer.find(".nr-db-sb-group-list-container").slideUp().addClass('nr-db-sb-collapsed');
tabContainer.find(".nr-db-sb-tab-list-header>.nr-db-sb-list-chevron").css({"transform":"rotate(-90deg)"});
evt.preventDefault();
})
.appendTo(buttonGroup);
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-angle-double-down"></i></a>')
.click(function(evt) {
tabContainer.find(".nr-db-sb-group-list-container").slideDown().removeClass('nr-db-sb-collapsed');
tabContainer.find(".nr-db-sb-tab-list-header>.nr-db-sb-list-chevron").css({"transform":""});
evt.preventDefault();
})
.appendTo(buttonGroup);
//Add item button
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.tab")+'</a>')
.click(function(evt) {
tabContainer.editableList('addItem',{type: 'ui_tab'});
evt.preventDefault();
})
.appendTo(buttonGroup);
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.link")+'</a>')
.click(function(evt) {
tabContainer.editableList('addItem',{type: 'ui_link'});
evt.preventDefault();
})
.appendTo(buttonGroup);
var tabLists = {};
var groupLists = {};
// toggle slide tab group content
var titleToggle = function (id,content,chevron) {
return function(evt) {
if (content.is(":visible")) {
content.slideUp();
chevron.css({"transform":"rotate(-90deg)"});
content.addClass('nr-db-sb-collapsed');
listStates[id] = false;
}
else {
content.slideDown();
chevron.css({"transform":""});
content.removeClass('nr-db-sb-collapsed');
listStates[id] = true;
}
};
}
var addTabOrLinkItem = function(container,i,item) {
ensureDashboardNode(true);
// create node if needed
if (!item.node) {
var defaultItem = {
'ui_tab': {
_def: RED.nodes.getType('ui_tab'),
type: 'ui_tab',
users: [],
icon: 'dashboard',
name: 'Tab'
},
'ui_link': {
_def: RED.nodes.getType('ui_link'),
type: 'ui_link',
users: [],
icon: 'open_in_browser',
name: 'Link',
target: 'newtab'
}
}
item.node = defaultItem[item.type]
item.node.id = RED.nodes.id()
item.node.order = i+1
item.node.name += ' '+item.node.order
listElements[item.node.id] = container;
if (item.type === 'ui_tab') {
item.groups = [];
}
RED.nodes.add(item.node);
RED.editor.validateNode(item.node);
RED.history.push({
t:'add',
nodes:[item.node.id],
dirty:RED.nodes.dirty()
});
RED.nodes.dirty(true);
}
else if (item.type === undefined) {
item.type = item.node.type
}
listElements[item.node.id] = container;
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
RED.nodes.updateConfigNodeUsers(item.node);
}
// title
var titleRow = $('<div>',{class:"nr-db-sb-list-header nr-db-sb-tab-list-header"}).appendTo(container);
switch (item.type) {
case 'ui_tab': {
container.addClass("nr-db-sb-tab-list-item");
$('<i class="nr-db-sb-list-handle nr-db-sb-tab-list-handle fa fa-bars"></i>').appendTo(titleRow);
var chevron = $('<i class="fa fa-angle-down nr-db-sb-list-chevron">',{style:"width:10px;"}).appendTo(titleRow);
var tabicon = "fa-object-group";
//var tabicon = item.node.disabled ? "fa-window-close-o" : item.node.hidden ? "fa-eye-slash" : "fa-object-group";
$('<i>',{class:"nr-db-sb-icon nr-db-sb-tab-icon fa "+tabicon}).appendTo(titleRow);
var tabhide = item.node.hidden ? " nr-db-sb-title-hidden" : "";
var tabable = item.node.disabled ? " nr-db-sb-title-disabled" : "";
$('<span>',{class:"nr-db-sb-title"+tabhide+tabable}).text(item.node.name||"").appendTo(titleRow);
break;
}
case 'ui_link': {
$('<i class="nr-db-sb-list-handle fa fa-bars"></i>').appendTo(titleRow);
var title = $('<div class="nr-db-sb-link">').appendTo(titleRow);
var nameContainer = $('<div class="nr-db-sb-link-name-container">').appendTo(title);
$('<i class="fa fa-external-link"></i>').appendTo(nameContainer);
$('<span class="nr-db-sb-link-name">').text(item.node.name||"untitled").appendTo(nameContainer);
$('<div class="nr-db-sb-link-url">').text(item.node.link||"http://").appendTo(title);
break;
}
}
// buttons
var buttonGroup = $('<div>',{class:"nr-db-sb-list-header-button-group",id: item.node.id}).appendTo(titleRow);
if (item.type === 'ui_tab') {
var addGroupButton = $('<a href="#" class="nr-db-sb-tab-add-group-button editor-button editor-button-small nr-db-sb-list-header-button" ><i class="fa fa-plus"></i> '+c_("layout.group")+'</a>').appendTo(buttonGroup);
}
var editButton = $('<a href="#" class="nr-db-sb-tab-edit-button editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.edit")+'</a>').appendTo(buttonGroup);
editButton.on('click',function(evt) {
RED.editor.editConfig("", item.type, item.node.id);
evt.stopPropagation();
evt.preventDefault();
});
// Dashboard layout tool
if (item.type === 'ui_tab') {
var layoutButton = $('<a href="#" class="nr-db-sb-tab-edit-layout-button editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.layout")+'</a>').appendTo(buttonGroup);
layoutButton.on('click',function(evt) {
var editTabName = item.node.name ? item.node.name : item.node.id;
var trayOptions = {
title: c_("layout.layout-editor") + " : " + editTabName,
width: Infinity,
buttons: [
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
// clean editor
RED.tray.close();
}
},
{
id: "node-dialog-ok",
text: RED._("common.label.done"),
class: "primary",
click: function() {
// Save data after editing
saveGridDatas();
RED.tray.close();
}
}
],
resize: function(dimensions) {},
open: function(tray) {
// Get widget of specified tab from node information
tabDatas = getTabDataFromNodes(item.node.id);
// The width that can be handled by Layout is up to MAX_GROUP_WIDTH
// Groups exceeding the maximum width are not supported.
var tmpGroups = tabDatas.groups;
tmpGroups.sort(compareOrder);
var groups = [];
for (var cnt = 0; cnt < tmpGroups.length; cnt++) {
if (tmpGroups[cnt].width <= MAX_GROUP_WIDTH) {
groups.push(tmpGroups[cnt]);
}
}
tabDatas.groups = groups;
var editor = $('<div></div>',{addClass: 'nr-dashboard-layout-container-fluid'});
var row = $('<div></div>',{addClass: 'nr-dashboard-layout-row'});
var span_num = Math.floor(12 / groups.length); // bootstrap grid 12 splits
span_num = span_num < 2 ? 2 : span_num; // max 6 groups per row
for (var cnt = 0; cnt < groups.length; cnt++) {
if (cnt !=0 && (cnt % 6) == 0) {
editor.append(row);
editor.append('<div><br></div>');
row = $('<div></div>',{addClass: 'nr-dashboard-layout-row'});
}
var span = $('<div></div>',{addClass: 'nr-dashboard-layout-span' + span_num});
var groupName = groups[cnt].name ? groups[cnt].name : groups[cnt].id;
var title = $('<div></div>', {
style: "margin-top:2px; margin-bottom:2px;"
});
var title_group = $('<div></div>', {
title: groupName,
style: "margin-left:4px; margin-right:8px; overflow:hidden;"
}).appendTo(title);
$("<b/>").text(groupName).appendTo(title_group);
var title_width = $('<div></div>', {
style: "text-align:right; margin-right:8px;"
}).appendTo(title);
$("<span/>", {
style: "margin_right: 8px;"
}).text(c_("layout.width")+': ').appendTo(title_width);
var changeWidth = $('<input>', {
id: 'change-width' + cnt,
value: groups[cnt].width,
style: 'width:30px;',
readonly: true,
'node-id': groups[cnt].id,
});
title_width.append(changeWidth);
title.css('white-space','nowrap');
title.css('overflow','hidden');
var gridstack = $('<div></div>', {
id: 'grid'+cnt,
addClass: 'grid-stack'
});
span.append(title);
span.append(gridstack);
row.append(span);
}
if (groups.length != 0) {
editor.append(row);
}
// Show layout editor in tray
var trayBody = tray.find('.red-ui-tray-body, .editor-tray-body');
trayBody.css('overflow','auto');
trayBody.append(editor);
/////////////////////////////////////////
// Editor screen generation
/////////////////////////////////////////
oldSpacer = [];
widthChange = [];
widgetResize = [];
widgetDrag = [];
for (var cnt=0; cnt < groups.length; cnt++) {
// Gridstack.js option
var options = {
acceptWidgets: true,
alwaysShowResizeHandle: true,
cellHeight: 42,
disableOneColumnMode : true,
float: true,
verticalMargin: 1
};
var gridID='#grid' + cnt;
// gridstack generation
$(gridID).gridstack(options);
// Clear the contents of Grid
var grid = $(gridID+'.grid-stack').data('gridstack');
grid.removeAll();
$(gridID).on("dropped", handleMove(grid));
// Set the width of the display area of gridstack
var groupWidth = Number(groups[cnt].width);
$(gridID+'.grid-stack').css("width", groupWidth * 40);
$(gridID+'.grid-stack').css("background-size", 100/groupWidth+"% 43px");
$(gridID+'.grid-stack').attr("node-id", groups[cnt].id);
$(gridID+'.grid-stack').attr("grid-column", groups[cnt].width);
grid.setColumn(groupWidth, true);
// Determination of placement position of widget of Grid
var widgets = groups[cnt].widgets;
widgets.sort(compareOrder);
var tbl = {};
for (var cnt2 = 0; cnt2 < widgets.length; cnt2++) {
// Set default value when there is auto width
if (widgets[cnt2].auto == true) {
widgets[cnt2].width = groupWidth;
// Adjust to the group width
} else if (widgets[cnt2].width > groupWidth) {
widgets[cnt2].width = groupWidth;
}
// Auto support
if (widgets[cnt2].auto === true || widgets[cnt2].type === 'ui_form') {
widgets[cnt2].height = getDefaultHeight(widgets[cnt2].id, groupWidth);
}
// Calculate coordinates to be placed
var point = search_point(Number(widgets[cnt2].width), Number(widgets[cnt2].height), groupWidth, 256, tbl);
if (point) {
widgets[cnt2].x = point.x;
widgets[cnt2].y = point.y;
}
}
var items = GridStackUI.Utils.sort(widgets);
items.forEach(function (node) {
var minHeight = null;
var maxHeight = null;
// ui_form is fixed to height 2
if (node.type === 'ui_form') {
minHeight = node.height;
maxHeight = node.height;
}
if (node.type !== 'ui_spacer') {
var dispNode = RED.nodes.node(node.id);
var dispType = dispNode._def.paletteLabel;
var dispLabel = dispNode._def.label;
try {
dispLabel = (typeof dispLabel === "function" ? dispLabel.call(dispNode) : dispLabel)||"";
}
catch(err) {
console.log("Definition error: " + node.type + ".label",err);
dispLabel = dispType;
}
var item = $('<div></div>', {
'data-noderedtype': node.type,
'data-noderedid': node.id,
'data-nodereddisptype': dispType,
'data-nodereddisplabel': dispLabel,
'data-noderedsizeauto': node.auto
});
var itemContent = $('<div></div>', {
addClass: 'grid-stack-item-content',
title: dispLabel + ':' + dispType
});
if (node.auto === true) {
itemContent.append('<i class="fa fa-unlock nr-dashboard-layout-resize-enable" title="'+c_("layout.auto")+'"></i>');
} else {
itemContent.append('<i class="fa fa-lock nr-dashboard-layout-resize-disable" title="'+c_("layout.manual")+'"></i>');
}
itemContent.append('<b>'+ dispLabel +'</b><br/>'+ dispType);
item.append(itemContent);
grid.addWidget(
item,
node.x, node.y, node.width, node.height, false, null, null,
minHeight, maxHeight, node.id);
} else {
// Record the spacer node ID to be deleted
oldSpacer.push(node.id);
}
});
$(gridID+'.grid-stack > .grid-stack-item:visible').each( function(idx, el) {
el = $(el);
var node = el.data('_gridstack_node');
var auto = (el[0].dataset.noderedsizeauto == 'true') ? true : false;
grid.resizable(el, !auto);
});
// Group width change
widthChange.push(new changeGroupWidth(cnt));
// Resize widget in group (start event)
widgetResize.push(new resizeGroupWidget(cnt));
// Dragging widgets in a group (start event)
widgetDrag.push(new dragGroupWidget(cnt));
}
$('.grid-stack>.grid-stack-item>.grid-stack-item-content>.nr-dashboard-layout-resize-disable').on('click',layoutResizeDisable);
$('.grid-stack>.grid-stack-item>.grid-stack-item-content>.nr-dashboard-layout-resize-enable').on('click',layoutResizeEnable);
},
close: function() {},
show: function() {}
}
RED.tray.show(trayOptions);
evt.stopPropagation();
evt.preventDefault();
});
}
if (item.type === 'ui_tab') {
var content = $('<div>',{class:"nr-db-sb-group-list-container"}).appendTo(container);
// ui_tab group chevron
if (listStates.hasOwnProperty(item.node.id) && !listStates[item.node.id]) {
content.hide();
chevron.css({"transform":"rotate(-90deg)"});
content.addClass('nr-db-sb-collapsed');
listStates[item.node.id] = false;
}
else {
listStates[item.node.id] = true;
}
titleRow.click(titleToggle(item.node.id,content,chevron));
// ui_tab group list
var ol = $('<ol>',{class:"nr-db-sb-group-list"}).appendTo(content).editableList({
sortable:".nr-db-sb-group-list-header",
addButton: false,
height: 'auto',
connectWith: ".nr-db-sb-group-list",
addItem: function(container,i,group) {
if (!group.node) {
group.node = {
id: RED.nodes.id(),
_def: RED.nodes.getType("ui_group"),
type: "ui_group",
users: [],
tab: item.node.id,
order: i+1,
name: "Group "+(i+1),
width: 6,
disp: true
};
listElements[group.node.id] = container;
RED.nodes.add(group.node);
RED.editor.validateNode(group.node);
group.widgets = [];
RED.history.push({
t:'add',
nodes:[group.node.id],
dirty:RED.nodes.dirty()
});
RED.nodes.dirty(true);
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
RED.nodes.updateConfigNodeUsers(group.node);
}
}
else {
if (group.node.order === undefined) {
group.node.order = i+1;
}
}
var groupNode = group.node;
elementParents[groupNode] = item.node.id;
var titleRow = $('<div>',{class:"nr-db-sb-list-header nr-db-sb-group-list-header"}).appendTo(container);
$('<i class="nr-db-sb-list-handle nr-db-sb-group-list-handle fa fa-bars"></i>').appendTo(titleRow);
var chevron = $('<i class="fa fa-angle-down nr-db-sb-list-chevron">',{style:"width:10px;"}).appendTo(titleRow);
$('<i class="nr-db-sb-icon nr-db-sb-group-icon fa fa-table"></i>').appendTo(titleRow);
var title = $('<span class="nr-db-sb-title">').text(groupNode.name||groupNode.id||"").appendTo(titleRow);
listElements[groupNode.id] = container;
var buttonGroup = $('<div>',{class:"nr-db-sb-list-header-button-group",id:groupNode.id}).appendTo(titleRow);
var spacerButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.spacer")+'</a>').appendTo(buttonGroup);
spacerButton.on('click',function(evt) {
var spaceNode = {
_def: RED.nodes.getType("ui_spacer"),
type: "ui_spacer",
hasUsers: false,
users: [],
id: RED.nodes.id(),
tab: item.node.name,
group: group.node.id,
order: i+1,
name: "spacer",
width: 1,
height:1,
z: RED.workspaces.active(),
label: function() { return "spacer " + this.width + "x" + this.height; }
};
RED.nodes.add(spaceNode);
RED.editor.validateNode(spaceNode);
RED.history.push({
t:'add',
nodes:[spaceNode.id],
dirty:RED.nodes.dirty()
});
RED.nodes.dirty(true);
RED.view.redraw();
evt.stopPropagation();
evt.preventDefault();
});
var editButton = $('<a href="#" class="nr-db-sb-edit-group-button editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.edit")+'</a>').appendTo(buttonGroup);
var content = $('<div>',{class:"nr-db-sb-widget-list-container"}).appendTo(container);
if (!listStates.hasOwnProperty(groupNode.id) || !listStates[groupNode.id]) {
content.hide();
chevron.css({"transform":"rotate(-90deg)"});
content.addClass('nr-db-sb-collapsed');
listStates[groupNode.id] = false;
}
else {
listStates[groupNode.id] = true;
}
var ol = $('<ol>',{class:"nr-db-sb-widget-list"}).appendTo(content).editableList({
sortable:".nr-db-sb-widget-list-header",
addButton: false,
height: 'auto',
connectWith: ".nr-db-sb-widget-list",
addItem: function(container,i,widgetNode) {
elementParents[widgetNode.id] = groupNode.id;
var titleRow = $('<div>',{class:"nr-db-sb-list-header nr-db-sb-widget-list-header"}).appendTo(container);
$('<i class="nr-db-sb-list-handle nr-db-sb-widget-list-handle fa fa-bars"></i>').appendTo(titleRow);
$('<i class="nr-db-sb-icon nr-db-sb-widget-icon fa fa-picture-o"></i>').click(function(e) { e.preventDefault(); RED.search.show(widgetNode.id); }).appendTo(titleRow);
var l = widgetNode._def.label;
try {
l = (typeof l === "function" ? l.call(widgetNode) : l)||"";
}
catch(err) {
console.log("Definition error: "+d.type+".label",err);
l = d.type;
}
var title = $('<span class="nr-db-sb-title">').text(l).appendTo(titleRow);
listElements[widgetNode.id] = container;
var buttonGroup = $('<div>',{class:"nr-db-sb-list-header-button-group"}).appendTo(titleRow);
var editButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.edit")+'</a>').appendTo(buttonGroup);
container.on('mouseover',function() {
widgetNode.highlighted = true;
widgetNode.dirty = true;
RED.view.redraw();
});
container.on('mouseout',function() {
widgetNode.highlighted = false;
widgetNode.dirty = true;
RED.view.redraw();
});
editButton.on('click',function(evt) {
RED.editor.edit(widgetNode);
evt.stopPropagation();
evt.preventDefault();
});
},
sortItems: function(items) {
var historyEvents = [];
items.each(function(i,el) {
var node = el.data('data');
var hev = {
t:'edit',
node:node,
changes:{
order:node.order,
group:node.group
},
dirty:node.dirty,
changed:node.changed
};
historyEvents.push(hev);
var changed = false;
if (node.order !== i+1) {
node.order = i+1;
changed = true;
}
if (node.group !== group.node.id) {
var oldGroupNode = RED.nodes.node(node.group);
if (oldGroupNode) {
var index = oldGroupNode.users.indexOf(node);
oldGroupNode.users.splice(index,1);
}
node.group = group.node.id;
group.node.users.push(node);
changed = true;
}
if (changed) {
node.dirty = true;
node.changed = true;
}
})
RED.history.push({
t:'multi',
events: historyEvents
});
RED.nodes.dirty(true);
RED.view.redraw();
}
});
ol.css("min-height","5px");
if (groupNode.id) {
groupLists[groupNode.id] = ol;
}
titleRow.click(titleToggle(groupNode.id,content,chevron));
editButton.on('click',function(evt) {
RED.editor.editConfig("", groupNode.type, groupNode.id);
evt.stopPropagation();
evt.preventDefault();
});
group.widgets.forEach(function(widget) {
ol.editableList('addItem',widget);
})
},
sortItems: function(items) {
var historyEvents = [];
items.each(function(i,el) {
var groupData = el.data('data');
var node = groupData.node;
var hev = {
t:'edit',
node:node,
changes:{
order:node.order,
tab:node.tab
},
dirty:node.dirty,
changed:node.changed
};
historyEvents.push(hev);
var changed = false;
if (node.order !== i+1) {
node.order = i+1;
changed = true;
}
if (changed) {
node.dirty = true;
node.changed = true;
}
if (node.tab !== item.node.id) {
var oldTabNode = RED.nodes.node(node.tab);
if (oldTabNode) {
var index = oldTabNode.users.indexOf(node);
oldTabNode.users.splice(index,1);
}
node.tab = item.node.id;
item.node.users.push(node);
changed = true;
}
})
RED.history.push({
t:'multi',
events: historyEvents
});
RED.nodes.dirty(true);
RED.view.redraw();
}
})
tabLists[item.node.id] = ol;
addGroupButton.click(function(evt) {
ol.editableList('addItem',{});
evt.stopPropagation();
evt.preventDefault();
});
item.groups.forEach(function(group) {
ol.editableList('addItem',group);
});
}
}
var tabContainer = $('<ol>',{class:"nr-db-sb-tab-list"}).appendTo(divTabs).editableList({
sortable:".nr-db-sb-tab-list-header",
addButton: false,
addItem: addTabOrLinkItem,
sortItems: function(items) {
var historyEvents = [];
items.each(function(i,el) {
var itemData = el.data('data');
var node = itemData.node;
var hev = {
t:'edit',
node:node,
changes:{
order:node.order
},
dirty:node.dirty,
changed:node.changed
}
historyEvents.push(hev);
var changed = false;
if (node.order !== i+1) {
node.order = i+1;
changed = true;
}
if (changed) {
node.dirty = true;
node.changed = true;
}
})
RED.history.push({
t:'multi',
events: historyEvents
});
RED.nodes.dirty(true);
RED.view.redraw();
}
});
var orphanedWidgets = $('<div>',{class:"form-row"}).appendTo(layoutTab);
$('<span><i class="fa fa-info-circle"></i> There <span id="nr-db-missing-group-count"></span> not in a group. Click <a id="nr-db-add-missing-groups" href="#">here</a> to create the missing groups</span>').appendTo(orphanedWidgets);
orphanedWidgets.find('a').click(function(event) {
var unknownGroups = {};
RED.nodes.eachNode(function(node) {
if (/^ui_/.test(node.type) && node.type !== 'ui_link' && node.type !== 'ui_toast' && node.type !== 'ui_ui_control') {
if (!RED.nodes.node(node.group)) {
var g = node.group || "_BLANK_";
unknownGroups[g] = unknownGroups[g] || [];
unknownGroups[g].push(node);
}
}
});
var tab = null;
var tabs = tabContainer.editableList('items');
tabs.first().each(function(i,el) {
var tabData = el.data('data');
tab = tabData.node;
});
var hev = [];
if (tab === null) {
tab = {
id: RED.nodes.id(),
_def: RED.nodes.getType("ui_tab"),
type: "ui_tab",
users: [],
order: 0,
name: "Tab",
icon: "dashboard"
};
RED.nodes.add(tab);
RED.editor.validateNode(tab);
hev.push(tab.id);
}
for (var groupId in unknownGroups) {
if (unknownGroups.hasOwnProperty(groupId)) {
var groupNode = {
id: RED.nodes.id(),
_def: RED.nodes.getType("ui_group"),
type: "ui_group",
users: [],
tab: tab.id,
order: i+1,
name: (groupId==="_BLANK_"?"Group":groupId),
width: 6,
disp: true
};
hev.push(groupNode.id);
RED.nodes.add(groupNode);
RED.editor.validateNode(groupNode);
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
RED.nodes.updateConfigNodeUsers(groupNode);
}
var widgets = unknownGroups[groupId];
for (var i=0; i<widgets.length; i++) {
widgets[i].group = groupNode.id;
widgets[i].changed = true;
widgets[i].dirty = true;
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
RED.nodes.updateConfigNodeUsers(widgets[i]);
}
RED.editor.validateNode(widgets[i]);
}
}
}
RED.history.push({
t:'add',
nodes: hev,
dirty:RED.nodes.dirty()
});
RED.nodes.dirty(true);
refresh();
refreshOrphanedWidgets();
RED.view.redraw();
event.preventDefault();
});
var listElements = {};
var dashboard = [];
var listStates = {};
var elementParents = {};
var awaitingGroups = {};
var awaitingTabs = {};
function getCurrentList() {
var currentList = [];
var tabs = tabContainer.editableList('items');
var open = false;
tabs.each(function(i,el) {
var tabData = el.data('data');
var tab = [];
var groups = el.find('.nr-db-sb-group-list').editableList('items');
groups.each(function(j,el) {
var group = [];
var groupData = el.data('data');
var widgets = el.find('.nr-db-sb-widget-list').editableList('items');
widgets.each(function(k,el) {
var widgetData = el.data('data');
group.push(widgetData.id);
})
tab.push({id:groupData.node.id, widgets:group});
});
currentList.push({id:tabData.node.id,groups:tab});
});
return currentList;
}
function refreshOrphanedWidgets() {
var unknownGroups = {};
var count = 0;
RED.nodes.eachNode(function(node) {
if (/^ui_/.test(node.type) && node.type !== 'ui_link' && node.type !== 'ui_toast' && node.type !== 'ui_ui_control' && (node.type === 'ui_template' && node.templateScope !== 'global')) {
if (!RED.nodes.node(node.group)) {
var g = node.group || "_BLANK_";
unknownGroups[g] = unknownGroups[g] || [];
unknownGroups[g].push(node);
count++;
}
}
});
if (count > 0) {
orphanedWidgets.show();
$("#nr-db-missing-group-count").text((count===1?"is ":"are ")+count+" widget"+(count === 1?"":"s"))
}
else {
orphanedWidgets.hide();
}
}
function refresh() {
var currentList = getCurrentList();
dashboard = [];
var tabs = {};
var groups = {};
var elements = [];
var groupElements = {};
var tabGroups = {};
var groupId;
var group;
var tabId;
var tab;
var unknownGroups = 0;
// Find all the tabs and groups
RED.nodes.eachConfig(function(node) {
switch (node.type) {
case 'ui_tab':
case 'ui_link': {
tabs[node.id] = node;
//tabContainer.editableList('addItem',node);
break;
}
case 'ui_group': {
groups[node.id] = node;
break;
}
case 'ui_spacer': {
if (groups.hasOwnProperty(node.group)) {
groupElements[node.group] = groupElements[node.group]||[];
groupElements[node.group].push(node);
}
break;
}
}
});
for (groupId in groups) {
if (groups.hasOwnProperty(groupId)) {
group = groups[groupId];
if (tabs.hasOwnProperty(group.tab)) {
// This group belongs to a tab
tabGroups[group.tab] = tabGroups[group.tab]||[];
tabGroups[group.tab].push(group);
}
else {
unknownGroups++;
}
}
}
// Find all ui widgets - list them by their group id
RED.nodes.eachNode(function(node) {
if (/^ui_/.test(node.type)) {
if (groups.hasOwnProperty(node.group)) {
groupElements[node.group] = groupElements[node.group]||[];
groupElements[node.group].push(node);
}
else if ((node.type !== 'ui_toast')&&(node.type !== 'ui_ui_control')&&(node.type === 'ui_template' && node.templateScope !== 'global')) {
unknownGroups++;
}
}
});
if (unknownGroups > 0) {
$("#nr-db-missing-group-count").text((unknownGroups===1?"is ":"are ")+unknownGroups+" widget"+(unknownGroups === 1?"":"s"))
orphanedWidgets.show();
}
else {
orphanedWidgets.hide();
}
// Sort each group's array of widgets
for (groupId in groupElements) {
if (groupElements.hasOwnProperty(groupId)) {
group = groupElements[groupId];
groupElements[groupId] = group.map(function(v,i) { return {n:v,i:i} }).sort(function(A,B) {
if (A.n.order < B.n.order) { return A.n.order!==0?-1:1;}
if (A.n.order > B.n.order) { return B.n.order!==0?1:-1;}
return A.i - B.i;
}).map(function(v) { return v.n})
}
}
// Sort each tabs's array of groups
for (tabId in tabGroups) {
if (tabGroups.hasOwnProperty(tabId)) {
tab = tabGroups[tabId];
tabGroups[tabId] = tab.map(function(v,i) { return {n:v,i:i} }).sort(function(A,B) {
if (A.n.order < B.n.order) { return -1;}
if (A.n.order > B.n.order) { return 1;}
return A.i - B.i;
}).map(function(v) { return v.n})
}
}
var tabIds = Object.keys(tabs).map(function(v,i) { return {n:tabs[v],i:i} }).sort(function(A,B) {
if (A.n.order < B.n.order) { return -1;}
if (A.n.order > B.n.order) { return 1;}
return A.i - B.i;
}).map(function(v) { return v.n.id});
tabIds.forEach(function(tabId) {
var tab = {node:tabs[tabId],groups:[]};
if (tabGroups[tabId]) {
tabGroups[tabId].forEach(function(groupNode) {
var group = {node:groupNode,widgets:[]};
if (groupElements[groupNode.id]) {
group.widgets = groupElements[groupNode.id];
}
tab.groups.push(group);
});
}
dashboard.push(tab);
});
var newList = dashboard.map(function(t) {
return {
id: t.node.id,
groups: t.groups.map(function(g) {
return {
id: g.node.id,
widgets: g.widgets.map(function(w) {
return w.id;
})
}
})
}
});
if (JSON.stringify(newList)!=JSON.stringify(currentList)) {
listElements = {};
groupLists = {};
tabLists = {};
tabs = {};
groups = {};
elementParents = {};
tabContainer.empty();
dashboard.forEach(function(tab) {
tabContainer.editableList('addItem',tab);
});
}
//ensureDashboardNode(true);
if (globalDashboardNode) {
$("#nr-db-field-title").val(globalDashboardNode.site.name);
$("#nr-db-field-allowSwipe").val(globalDashboardNode.site.allowSwipe || "false");
$("#nr-db-field-allowTempTheme").val(globalDashboardNode.site.allowTempTheme || "true");
$("#nr-db-field-hideToolbar").val(globalDashboardNode.site.hideToolbar || "false");
$("#nr-db-field-dateFormat").val(globalDashboardNode.site.dateFormat);
if (typeof globalDashboardNode.site.sizes !== "object") {
globalDashboardNode.site.sizes = sizes;
}
$("#nr-db-field-sx").val(globalDashboardNode.site.sizes.sx);
$("#nr-db-field-sy").val(globalDashboardNode.site.sizes.sy);
$("#nr-db-field-px").val(globalDashboardNode.site.sizes.px);
$("#nr-db-field-py").val(globalDashboardNode.site.sizes.py);
$("#nr-db-field-cx").val(globalDashboardNode.site.sizes.cx);
$("#nr-db-field-cy").val(globalDashboardNode.site.sizes.cy);
$("#nr-db-field-gx").val(globalDashboardNode.site.sizes.gx);
$("#nr-db-field-gy").val(globalDashboardNode.site.sizes.gy);
if (typeof globalDashboardNode.theme.angularTheme !== "object") {
globalDashboardNode.theme.angularTheme = aTheme;
}
$("#nr-db-field-angPrimary").val(globalDashboardNode.theme.angularTheme.primary || "indigo");
$("#nr-db-field-angAccents").val(globalDashboardNode.theme.angularTheme.accents || "blue");
$("#nr-db-field-angWarn").val(globalDashboardNode.theme.angularTheme.warn || "red");
$("#nr-db-field-angBackground").val(globalDashboardNode.theme.angularTheme.background || "grey");
$("#nr-db-field-angLook").val(globalDashboardNode.theme.angularTheme.palette || "light");
$("#nr-db-field-theme").val(globalDashboardNode.theme.name);
$("#ui-sidebar-name").val(globalDashboardNode.theme.customTheme.name);
if (globalDashboardNode.theme.name === 'theme-custom') {
$("#custom-theme-library-container").show();
$("#custom-theme-settings").show();
}
else {
$("#custom-theme-library-container").hide();
$("#custom-theme-settings").hide();
}
if ($('#nr-db-field-allowTempTheme').val() === "none") {
ulDashboardTabs.children().eq(2).addClass("hidden");
ulDashboardTabs.children().eq(3).removeClass("hidden");
}
else {
ulDashboardTabs.children().eq(2).removeClass("hidden");
ulDashboardTabs.children().eq(3).addClass("hidden");
}
//set colour start
if (typeof globalDashboardNode.theme.name !== "string") {
globalDashboardNode.theme.name = "theme-light";
}
var currentTheme = globalDashboardNode.theme.name.split("-")[1];
var startingValue = globalDashboardNode.theme[currentTheme+"Theme"].baseColor;
setColourPickerColour("base-color", startingValue);
$("#nr-db-field-font").val(globalDashboardNode.theme[currentTheme+"Theme"].baseFont);
generateColours(startingValue);
if (globalDashboardNode.theme.name === 'theme-light' || globalDashboardNode.theme.name === 'theme-dark') {
addLightAndDarkResetButton('base-color', $('#base-settings-ul').children().first());
}
if (editor === undefined) {
editor = RED.editor.createEditor({
id: 'nr-db-field-format-editor',
mode: 'ace/mode/javascript',
value: JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site})
});
RED.library.create({
url:"themes", // where to get the data from
type:"theme", // the type of object the library is for
editor: editor, // the field name the main text body goes to
mode:"ace/mode/javascript",
fields:['name'],
elementPrefix:"ui-sidebar-"
});
}
editor.on('input', function() {
// Check for any changes on the editor object
// i.e. has the theme been customised compared
// to what is stored
var editorObject = JSON.parse(editor.getValue());
//Update theme object if necessary
if (JSON.stringify(editorObject.theme) !== JSON.stringify(globalDashboardNode.theme.themeState)) {
globalDashboardNode.theme.themeState = editorObject.theme;
if ($("#ui-sidebar-name").val() !== globalDashboardNode.theme.customTheme.name) {
globalDashboardNode.theme.customTheme.name = $("#ui-sidebar-name").val();
globalDashboardNode.theme.customTheme.baseColor = globalDashboardNode.theme.themeState["base-color"].value;
setColourPickerColour("base-color", globalDashboardNode.theme.customTheme.baseColor);
generateColours(globalDashboardNode.theme.themeState["base-color"].value);
RED.nodes.dirty(true);
}
}
if (JSON.stringify(aTheme) !== JSON.stringify(globalDashboardNode.theme.angularTheme)) {
globalDashboardNode.theme.angularTheme = aTheme;
}
//Update site object if necessary
if (JSON.stringify(editorObject.site) !== JSON.stringify(globalDashboardNode.site)) {
globalDashboardNode.site = editorObject.site;
$("#nr-db-field-title").val(globalDashboardNode.site.name);
$("#nr-db-field-hideToolbar").val(globalDashboardNode.site.hideToolbar);
$("#nr-db-field-allowSwipe").val(globalDashboardNode.site.allowSwipe);
$("#nr-db-field-allowTempTheme").val(globalDashboardNode.site.allowTempTheme);
$("#nr-db-field-dateFormat").val(globalDashboardNode.site.dateFormat);
$("#nr-db-field-sx").val(globalDashboardNode.site.sizes.sx);
$("#nr-db-field-sy").val(globalDashboardNode.site.sizes.sy);
$("#nr-db-field-px").val(globalDashboardNode.site.sizes.px);
$("#nr-db-field-py").val(globalDashboardNode.site.sizes.py);
$("#nr-db-field-gx").val(globalDashboardNode.site.sizes.gx);
$("#nr-db-field-gy").val(globalDashboardNode.site.sizes.gy);
$("#nr-db-field-cx").val(globalDashboardNode.site.sizes.cx);
$("#nr-db-field-cy").val(globalDashboardNode.site.sizes.cy);
RED.nodes.dirty(true);
}
});
}
awaitingGroups = {};
awaitingTabs = {};
}
RED.sidebar.addTab({
id: "dashboard",
label: c_("label.dashboard"),
name: "Dashboard",
content: content,
closeable: true,
pinned: true,
iconClass: "fa fa-bar-chart",
disableOnEdit: true,
onchange: function() { refresh(); }
});
editSaveEventHandler = function(node) {
if (/^ui_/.test(node.type)) {
if (node.type === "ui_tab" || node.type === "ui_group") {
if (listElements[node.id]) {
// Existing element
listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").text(node.name||node.id);
if (node.type === "ui_group") {
refresh();
}
else {
if (node.hidden === true) { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").addClass('nr-db-sb-title-hidden'); }
else { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").removeClass('nr-db-sb-title-hidden'); }
if (node.disabled === true) { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").addClass('nr-db-sb-title-disabled'); }
else { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").removeClass('nr-db-sb-title-disabled'); }
}
}
else if (node.type === "ui_tab") {
// Adding a tab
tabContainer.editableList('addItem',{node:node,groups:[]})
}
else {
// Adding a group
if (tabLists[node.tab]) {
tabLists[node.tab].editableList('addItem',{node:node,widgets:[]})
}
}
}
else if (node.type === "ui_link") {
if (listElements[node.id]) {
var container = listElements[node.id];
container.find(".nr-db-sb-link-name").text(node.name||"untitled");
container.find(".nr-db-sb-link-url").text(node.link);
}
}
else {
refreshOrphanedWidgets();
if (listElements[node.id]) {
if (node.group != elementParents[node.id]) {
// Moved to a different group
if (groupLists[elementParents[node.id]]) {
groupLists[elementParents[node.id]].editableList('removeItem',listElements[node.id].data('data'))
}
if (groupLists[node.group]) {
groupLists[node.group].editableList('removeItem',node)
groupLists[node.group].editableList('addItem',node);
}
}
else {
var l = node._def.label;
try {
l = (typeof l === "function" ? l.call(node) : l)||"";
}
catch(err) {
console.log("Definition error: "+d.type+".label",err);
l = d.type;
}
listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").text(l);
}
}
else {
if (groupLists[node.group]) {
if (node.order === 0) { node.order = groupLists[node.group].editableList('length'); }
groupLists[node.group].editableList('addItem',node);
}
}
}
}
};
RED.events.on("editor:save",editSaveEventHandler);
// Dashboard layout tool
layoutUpdateEventHandler = function(node) {
if (/^ui_/.test(node.type) && node.type !== 'ui_link' && node.type !== 'ui_toast' && node.type !== 'ui_ui_control' && node.type !== 'ui_audio' && node.type !== 'ui_base' && node.type !== 'ui_group' && node.type !== 'ui_tab') {
if (listElements[node.id]) {
if (node.group != elementParents[node.id]) {
// Moved to a different group
if (groupLists[elementParents[node.id]]) {
groupLists[elementParents[node.id]].editableList('removeItem',listElements[node.id].data('data'))
}
if (groupLists[node.group]) {
groupLists[node.group].editableList('removeItem',node)
groupLists[node.group].editableList('addItem',node);
groupLists[node.group].editableList('sort',function(a,b) {return a.order-b.order;});
}
}
else {
groupLists[node.group].editableList('sort',function(a,b) {return a.order-b.order;});
}
}
}
};
RED.events.on("layout:update",layoutUpdateEventHandler);
var pendingAdd = [];
var pendingAddTimer = null;
function handlePendingAdds() {
var hasTabs = false;
var hasGroups = false;
pendingAdd.sort(function(A,B) {
hasTabs = hasTabs || A.type === "ui_tab" || B.type === "ui_tab";
hasGroups = hasGroups || A.type === "ui_group" || B.type === "ui_group";
if (A.type === B.type) {
return 0;
}
if (A.type === "ui_tab") {
return -1;
}
else if (B.type === "ui_tab") {
return 1;
}
else if (A.type === "ui_group") {
return -1;
}
else if (B.type === "ui_group") {
return 1;
}
return 0
});
var updateList = {};
for (var i=0; i<pendingAdd.length; i++) {
var node = pendingAdd[i];
if (listElements[node.id]) {
continue;
}
if (node.type === "ui_tab") {
tabContainer.editableList('addItem',{node:node,groups:[]});
}
else {
if (hasTabs) {
// We've added some tabs, need to give jquery time to add the lists
pendingAdd = pendingAdd.slice(i);
pendingAddTimer = setTimeout(handlePendingAdds,50);
return;
}
if (node.type === "ui_group") {
if (tabLists[node.tab]) {
tabLists[node.tab].editableList('addItem',{node:node,widgets:[]});
}
}
else {
if (hasGroups) {
// We've added some tabs, need to give jquery time to add the lists
pendingAdd = pendingAdd.slice(i);
pendingAddTimer = setTimeout(handlePendingAdds,50);
return;
}
if (groupLists[node.group]) {
groupLists[node.group].editableList('addItem',node)
if (node.order >= 0) {
updateList[node.group] = true;
}
}
else {
refreshOrphanedWidgets();
}
}
}
}
Object.keys(updateList).forEach(function (group) {
var list = groupLists[group];
if (list) {
list.editableList("sort", function(a,b) {return a.order-b.order;});
}
});
pendingAdd = [];
}
nodesAddEventHandler = function(node) {
if (/^ui_/.test(node.type) && !listElements[node.id]) {
pendingAdd.push(node);
clearTimeout(pendingAddTimer);
pendingAddTimer = setTimeout(handlePendingAdds,100);
}
};
RED.events.on("nodes:add", nodesAddEventHandler);
nodesRemoveEventHandler = function(node) {
if (/^ui_/.test(node.type)) {
if (node.type === "ui_tab" || node.type === "ui_link") {
if (listElements[node.id]) {
tabContainer.editableList('removeItem',listElements[node.id].data('data'));
delete tabLists[node.id];
}
}
else if (node.type === "ui_group") {
if (tabLists[node.tab] && listElements[node.id]) {
tabLists[node.tab].editableList('removeItem',listElements[node.id].data('data'));
}
delete groupLists[node.id];
}
else {
if (groupLists[node.group]) {
groupLists[node.group].editableList('removeItem',node)
}
}
refreshOrphanedWidgets();
delete listElements[node.id];
}
};
RED.events.on("nodes:remove", nodesRemoveEventHandler);
}
});
$.widget("nodereddashboard.elementSizerByNum", {
_create: function() {
var that = this;
var has_height = this.options.has_height;
var pos = this.options.pos;
var c_width = has_height ? '15%' : '6%';
var container = $('<div>').css({
position: 'absolute',
background: 'white',
padding: '10px 10px 10px 10px',
border: '1px solid grey',
zIndex: '20',
borderRadius: "4px",
display:"none",
width: c_width
}).appendTo(document.body);
var box0 = $("<div>").css({
fontSize: '13px',
color: '#aaa',
float: 'left',
paddingTop: '1px'
}).appendTo(container);
var width = $(this.options.width).val();
var height = has_height ? $(this.options.height).val() : undefined;
var max_w = '';
var groupNode = this.options.groupNode;
if(groupNode) {
max_w = 'max="'+groupNode.width+'"';
}
width = (width > 0) ? width : 1;
height = (height > 0) ? height : 1;
var in0 = $('<input type="number" min="1" '+max_w+'>')
.css("width", has_height ? "40%" : "100%")
.val(width)
.appendTo(box0);
if(has_height) {
var pad = $('<span>')
.text(" x ")
.appendTo(box0);
var in1 = $('<input type="number" min="1">')
.css("width", "40%")
.val(height)
.appendTo(box0);
}
var closeTimer;
var closeFunc = function() {
var w = in0.val();
var h = has_height ? in1.val() : undefined;
var label = that.options.label;
label.text(w+(has_height ? (' x '+h) : ''));
$(that.options.width).val(w).change();
if(has_height) {
$(that.options.height).val(h).change();
}
that.destroy();
};
container.keypress(function(e) {
if(e.which === 13) { // pressed ENTER
container.fadeOut(100, closeFunc);
}
});
container.on('mouseleave', function(e) {
closeTimer = setTimeout(function() {
container.fadeOut(200, closeFunc);
}, 100);
});
container.on('mouseenter', function(e) {
clearTimeout(closeTimer);
});
container.css({
top: (pos.top -10)+"px",
left: (pos.left +10)+"px"
});
container.fadeIn(200);
}
});
$.widget( "nodereddashboard.elementSizer", {
_create: function() {
var that = this;
var gridWidth = 6;
var width = parseInt($(this.options.width).val()||0);
var height = parseInt(this.options.hasOwnProperty('height')?$(this.options.height).val():"1")||0;
var hasAuto = (!this.options.hasOwnProperty('auto') || this.options.auto);
this.element.css({
minWidth: this.element.height()+4
});
var auto_text = c_("auto");
var sizeLabel = (width === 0 && height === 0)?auto_text:width+(this.options.hasOwnProperty('height')?" x "+height:"");
this.element.text(sizeLabel).on('mousedown',function(evt) {
evt.stopPropagation();
evt.preventDefault();
var width = parseInt($(that.options.width).val()||0);
var height = parseInt(that.options.hasOwnProperty('height')?$(that.options.height).val():"1")||0;
var maxWidth = 0;
var maxHeight;
var fixedWidth = false;
var fixedHeight = false;
var group = $(that.options.group).val();
if (group) {
var groupNode = RED.nodes.node(group);
if (groupNode) {
gridWidth = Math.max(6,groupNode.width,+width);
maxWidth = groupNode.width || gridWidth;
fixedWidth = true;
}
maxHeight = Math.max(6,+height+1);
}
else {
gridWidth = Math.max(12,+width);
maxWidth = gridWidth;
maxHeight = 1;
fixedHeight = true;
}
var pos = $(this).offset();
var container = $('<div>').css({
position: 'absolute',
background: 'white',
padding: '5px 10px 10px 10px',
border: '1px solid grey',
zIndex: '20',
borderRadius: "4px",
display:"none"
}).appendTo(document.body);
var closeTimer;
container.on('mouseleave',function(evt) {
closeTimer = setTimeout(function() {
container.fadeOut(200, function() { $(this).remove(); });
},100)
});
container.on('mouseenter',function() {
clearTimeout(closeTimer);
})
var label = $("<div>").css({
fontSize: '13px',
color: '#aaa',
float: 'left',
paddingTop: '1px'
}).appendTo(container).text((width === 0 && height === 0)?auto_text:(width+(that.options.hasOwnProperty('height')?" x "+height:"")));
label.hover(function() {
$(this).css('text-decoration', 'underline');
}, function() {
$(this).css('text-decoration', 'none');
});
label.click(function(e) {
var group = $(that.options.group).val();
var groupNode = null;
if(group) {
groupNode = RED.nodes.node(group);
if(groupNode === null) {
return;
}
}
$(that).elementSizerByNum({
width: that.options.width,
height: that.options.height,
groupNode: groupNode,
pos: pos,
label: that.element,
has_height: that.options.hasOwnProperty('height')
});
closeTimer = setTimeout(function() {
container.fadeOut(200, function() {
$(this).remove();
});
},100)
});
var buttonRow = $('<div>',{style:"text-align:right; height:25px;"}).appendTo(container);
if (hasAuto) {
var button = $('<a>',{href:"#",class:"editor-button editor-button-small",style:"margin-bottom:5px"})
.text(auto_text)
.appendTo(buttonRow)
.on('mouseup',function(evt) {
that.element.text(auto_text)
$(that.options.width).val(0).change();
$(that.options.height).val(0).change();
evt.preventDefault();
container.fadeOut(200, function() { $(this).remove(); });
});
}
var cellBorder = "1px dashed lightGray";
var cellBorderExisting = "1px solid gray";
var cellBorderHighlight = "1px dashed black";
var rows = [];
function addRow(i) {
var row = $('<div>').css({padding:0,margin:0,height:"25px","box-sizing":"border-box"}).appendTo(container);
rows.push(row);
cells.push([])
for (var j=0; j<gridWidth; j++) {
addCell(i,j);
}
}
function addCell(i,j) {
var row = rows[i];
var cell = $('<div>').css({
display:"inline-block",
width: "25px",
height: "25px",
borderRight: (j===(width-1)&&i<height)?cellBorderExisting:cellBorder,
borderBottom: (i===(height-1)&&j<width)?cellBorderExisting:cellBorder,
boxSizing: "border-box",
cursor:"pointer",
background: (j<maxWidth)?"#fff":"#eee"
}).appendTo(row);
cells[i].push(cell);
if (j===0) {
cell.css({borderLeft:((i<=height-1)?cellBorderExisting:cellBorder)});
}
if (i===0) {
cell.css({borderTop:((j<=width-1)?cellBorderExisting:cellBorder)});
}
if (j<maxWidth) {
cell.data("w",j);
cell.data("h",i);
cell.on("mouseup",function() {
that.element.text(($(this).data("w")+1)+(that.options.hasOwnProperty('height')?" x "+($(this).data("h")+1):""))
$(that.options.width).val($(this).data("w")+1).change();
$(that.options.height).val($(this).data("h")+1).change();
container.fadeOut(200, function() { $(this).remove(); });
});
cell.on("mouseover",function() {
var w = $(this).data("w");
var h = $(this).data("h");
label.text((w+1)+(that.options.hasOwnProperty('height')?" x "+(h+1):""));
for (var y = 0; y<maxHeight; y++) {
for (var x = 0; x<maxWidth; x++) {
cells[y][x].css({
background: (y<=h && x<=w)?'#ddd':'#fff',
borderLeft: (x===0&&y<=h)?cellBorderHighlight:(x===0)?((y<=height-1)?cellBorderExisting:cellBorder):'',
borderTop: (y===0&&x<=w)?cellBorderHighlight:(y===0)?((x<=width-1)?cellBorderExisting:cellBorder):'',
borderRight: (x===w&&y<=h)?cellBorderHighlight:((x===width-1&&y<=height-1)?cellBorderExisting:cellBorder),
borderBottom: (y===h&&x<=w)?cellBorderHighlight:((y===height-1&&x<=width-1)?cellBorderExisting:cellBorder)
})
}
}
if (!fixedHeight && h === maxHeight-1) {
addRow(maxHeight++)
}
if (!fixedWidth && w === maxWidth-1) {
maxWidth++;
gridWidth++;
for (var r=0; r<maxHeight; r++) {
addCell(r,maxWidth-1);
}
}
})
}
}
var cells = [];
for (var i=0; i<maxHeight; i++) {
addRow(i);
}
container.css({
top:(pos.top)+"px",
left:(pos.left)+"px"
});
container.fadeIn(200);
})
}
});
})(jQuery);
</script>
<script type="text/html" data-template-name="ui_base">
<div class='form-row'>
This <i>ui_base</i> node is the main node that all<br/>other dashboard widget nodes communicate to.<br/>
<br/>One instance is required to support the dashboard.<br/>
<br/>If you have no dashboard you can delete this node.<br/>
It will be re-created automatically if required.<br/>
</div>
</script>
<script type="text/html" data-help-name="ui_base">
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_button] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_button',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: false},
label: {value: 'button'},
tooltip: {value: ''},
color: {value: ''},
bgcolor: {value: ''},
className: {value: ''},
icon: {value: ''},
payload: {value: '',validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('payloadType'):function(v) { return true})},
payloadType: { value: 'str'},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'}
},
inputs:1,
outputs:1,
outputLabels: function() { if (this.payloadType === "str") {
return this.payload;
} else {return this.payloadType; } },
icon: "ui_button.png",
paletteLabel: 'button',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'button'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$('#node-input-payload').typedInput({
default: 'str',
typeField: $("#node-input-payloadType"),
types: ['str','num','bool','json','bin','date','flow','global']
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
}
});
</script>
<script type="text/html" data-template-name="ui_button">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui_button.label.group"></label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> <span data-i18n="ui_button.label.size"></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-icon"><i class="fa fa-picture-o"></i> <span data-i18n="ui_button.label.icon"></label>
<input type="text" id="node-input-icon" data-i18n="[placeholder]ui_button.label.optionalIcon">
</div>
<div class="form-row">
<label for="node-input-label"><i class="fa fa-i-cursor"></i> <span data-i18n="ui_button.label.label"></label>
<input type="text" id="node-input-label" data-i18n="[placeholder]ui_button.label.optionalLabel">
</div>
<div class="form-row">
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> <span data-i18n="ui_button.label.tooltip"></label>
<input type="text" id="node-input-tooltip" data-i18n="[placeholder]ui_button.label.optionalTooltip">
</div>
<div class="form-row">
<label for="node-input-color"><i class="fa fa-tint"></i> <span data-i18n="ui_button.label.color"></label>
<input type="text" id="node-input-color" data-i18n="[placeholder]ui_button.label.optionalColor">
</div>
<div class="form-row">
<label for="node-input-bgcolor"><i class="fa fa-tint"></i> <span data-i18n="ui_button.label.background"></label>
<input type="text" id="node-input-bgcolor" data-i18n="[placeholder]ui_button.label.optionalBackgroundColor">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> <span data-i18n="ui_button.label.whenClicked"></label>
</div>
<div class="form-row">
<label for="node-input-payload" style="padding-left: 25px; margin-right: -25px"><span data-i18n="ui_button.label.payload"></label>
<input type="text" id="node-input-payload" style="width:70%">
<input type="hidden" id="node-input-payloadType">
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left: 25px; margin-right: -25px"><span data-i18n="ui_button.label.topic"></label>
<input type="text" id="node-input-topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> <span data-i18n="ui_button.label.emulateClick"></label>
<input type="checkbox" id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="ui_button.label.className"></label>
<input type="text" id="node-input-className" data-i18n="[placeholder]ui_button.label.classNamePlaceholder"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
</script>
<script type="text/html" data-help-name="ui_button">
<p>Adds a button to the user interface.</p>
<p>Clicking the button generates a message with <code>msg.payload</code> set to the <b>Payload</b> field.
If no payload is specified, the node id is used.</p>
<p>The <b>Size</b> defaults to 3 by 1.</p>
<p>The <b>Icon</b> can be defined, as either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
<p>The colours of the text and background may be set. They can also be set by a message property by setting
the field to the name of the property, for example <code>{{background}}</code>.
You don't need to prepend the <i>msg.</i> part of the property name.</p>
<p>The label and icon can also be set by a message property by setting
the field to the name of the property, for example <code>{{topic}}</code> or <code>{{myicon}}</code>.</p>
<p>If set to pass through mode a message arriving on the input will act like pressing the button.
The output payload will be as defined in the node configuration.</p>
<p>The incoming <b>topic</b> field can be used to set the <code>msg.topic</code> property that is output.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the button.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_dropdown] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_dropdown',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: ''},
tooltip: {value: ''},
place: {value: 'Select option'},
group: {type: 'ui_group', required:true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: true},
multiple: {value: false},
options: {value:[{value: '', label : ''}],
validate:function(v) {
var unique = new Set(v.map(function(o) {return o.value;}));
return v.length == unique.size;
}},
payload: {value: ''},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
className: {value: ''}
},
inputs:1,
outputs:1,
icon: "ui_dropdown.png",
paletteLabel: 'dropdown',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'dropdown'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
if (this.multiple === undefined) {
$("#node-input-multiple").prop('checked', false);;
}
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
var un = new Set(this.options.map(function(o) {return o.value}));
if (this.options.length == un.size) { $("#valWarning").hide(); }
else { $("#valWarning").show(); }
function generateOption(i, option) {
var container = $('<li/>',{style:"background: #fff; margin:0; padding:8px 0px 0px; border-bottom: 1px solid #ccc;"});
var row = $('<div/>').appendTo(container);
var row2 = $('<div/>',{style:"padding-top:5px; padding-left:175px;"}).appendTo(container);
var row3 = $('<div/>',{style:"padding-top:5px; padding-left:120px;"}).appendTo(container);
$('<i style="color:#eee; cursor:move; margin-left:3px;" class="node-input-option-handle fa fa-bars"></i>').appendTo(row);
var valueField = $('<input/>',{class:"node-input-option-value",type:"text",style:"margin-left:7px; width:calc(50% - 32px);", placeholder: 'Value',value:option.value}).appendTo(row).typedInput({default:option.type||'str',types:['str','num','bool']});
var labelField = $('<input/>',{class:"node-input-option-label",type:"text",style:"margin-left:7px; width:calc(50% - 32px);", placeholder: 'Label', value:option.label}).appendTo(row);
var finalspan = $('<span/>',{style:"float:right; margin-right:8px;"}).appendTo(row);
var deleteButton = $('<a/>',{href:"#",class:"editor-button editor-button-small", style:"margin-top:7px; margin-left:5px;"}).appendTo(finalspan);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
deleteButton.click(function() {
container.css({"background":"#fee"});
container.fadeOut(300, function() {
$(this).remove();
});
});
$("#node-input-option-container").append(container);
}
$("#node-input-add-option").click(function() {
generateOption($("#node-input-option-container").children().length+1, {});
$("#node-input-option-container-div").scrollTop($("#node-input-option-container-div").get(0).scrollHeight);
});
for (var i=0; i<this.options.length; i++) {
var option = this.options[i];
generateOption(i+1,option);
}
$( "#node-input-option-container" ).sortable({
axis: "y",
handle:".node-input-option-handle",
cursor: "move"
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
},
oneditsave: function() {
var options = $("#node-input-option-container").children();
var node = this;
node.options = [];
options.each(function(i) {
var option = $(this);
var o = {
label: option.find(".node-input-option-label").val(),
value: option.find(".node-input-option-value").typedInput('value'),
type: option.find(".node-input-option-value").typedInput('type')
};
if (option.find(".node-input-option-value").typedInput('type') === "num") {
o.value = Number(o.value);
}
if (option.find(".node-input-option-value").typedInput('type') === "bool") {
o.value = (o.value == "true");
}
node.options.push(o);
});
},
oneditresize: function() {
}
});
</script>
<script type="text/html" data-template-name="ui_dropdown">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-tag"></i> Label</label>
<input type="text" id="node-input-label" placeholder="optional label">
</div>
<div class="form-row">
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
</div>
<div class="form-row">
<label for="node-input-place"><i class="fa fa-tag"></i> Placeholder</label>
<input type="text" id="node-input-place" placeholder="optional placeholder">
</div>
<div class="form-row node-input-option-container-row" style="margin-bottom: 0px;width: 100%">
<label for="node-input-width" style="vertical-align:top"><i class="fa fa-list-alt"></i> Options</label>
<div id="node-input-option-container-div" style="box-sizing:border-box; border-radius:5px; height:257px; padding:5px; border:1px solid #ccc; overflow-y:scroll; display:inline-block; width:calc(70% + 15px);">
<span id="valWarning" style="color:#910000"><b>All Values must be unique.</b></span>
<ol id="node-input-option-container" style="list-style-type:none; margin:0;"></ol>
</div>
</div>
<div class="form-row">
<a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top:4px; margin-left:103px;"><i class="fa fa-plus"></i> <span>option</span></a>
</div>
<div class="form-row">
<label style="width:auto" for="node-input-multiple"><i class="fa fa-th-list"></i> Allow multiple selections from list: </label>
<input type="checkbox" checked id="node-input-multiple" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="optional msg.topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/html" data-help-name="ui_dropdown">
<p>Adds a dropdown select box to the user interface.</p>
<p>Multiple value / label pairs can be added as required. If the label is not specified the
value will be used for both.</p>
<p>The configured value of the selected item will be returned as <code>msg.payload</code>.</p>
<p>Setting <code>msg.payload</code> to one of the item values will preset the choice in the dropdown.
If using the multi-select option then the payload should be an array of values.</p>
<p>Optionally the <b>Topic</b> field can be used to set the <code>msg.topic</code> property.</p>
<p>The Options may be configured by inputting <code>msg.options</code> containing an array.
If just text then the value will be the same as the label, otherwise you can specify both by
using an object of <code>"label":"value"</code> pairs :</p>
<code>[ "Choice 1", "Choice 2", {"Choice 3":"3"} ]</code>
<p></p>
<p>If the "Allow multiple selections" output option is enabled - the result will be returned as an array instead of a string.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_switch] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_switch',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: 'switch'},
tooltip: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: true},
decouple: {value: "false"},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
style: {value: ''},
onvalue: {value: true, required:true, validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('onvalueType'):function(v) { return true})},
onvalueType: {value: 'bool'},
onicon: {value: '' },
oncolor: {value: ''},
offvalue: {value: false, required:true, validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('offvalueType'):function(v) { return true})},
offvalueType: {value: 'bool'},
officon: {value: ''},
offcolor: {value: ''},
animate: {value: false},
className: {value: ''}
},
inputs:1,
outputs:1,
icon: "ui_switch.png",
paletteLabel: 'switch',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'switch'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$('#node-input-custom-icons').on("change", function() {
if ($('#node-input-custom-icons').val() === "default") {
$(".form-row-custom-icons").hide();
}
else {
$(".form-row-custom-icons").show();
}
});
if (this.onicon !== "" || this.oncolor !== "" || this.officon !=="" || this.offcolor !== "") {
$('#node-input-custom-icons').val('custom');
}
else {
$(".form-row-custom-icons").hide();
$('#node-input-custom-icons').change();
}
$('#node-input-onvalue').typedInput({
default: 'str',
typeField: $("#node-input-onvalueType"),
types: ['str','num','bool','json','bin','date','flow','global']
});
$('#node-input-offvalue').typedInput({
default: 'str',
typeField: $("#node-input-offvalueType"),
types: ['str','num','bool','json','bin','date','flow','global']
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
$('#node-input-passthru').on("change", function() {
if (this.checked) {
$('.form-row-decouple').hide();
$('#node-input-decouple').val("false");
}
else {
$('.form-row-decouple').show();
}
});
},
oneditsave: function() {
if ($('#node-input-custom-icons').val() === 'default') {
$('#node-input-onicon').val('');
$('#node-input-officon').val('');
$('#node-input-oncolor').val('');
$('#node-input-offcolor').val('');
}
}
});
</script>
<script type="text/html" data-template-name="ui_switch">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
</div>
<div class="form-row">
<label for="node-input-custom-icons"><i class="fa fa-picture-o"></i> Icon</label>
<select id="node-input-custom-icons" style="width:35%">
<option value="default">Default</option>
<option value="custom">Custom</option>
</select>
<span style="width:auto; padding-left:20px" class="form-row-custom-icons" for="node-input-animate"> Animate
<input type="checkbox" checked id="node-input-animate" style="display:inline-block; width:auto; vertical-align:baseline;"></span>
</div>
<div class="form-row form-row-custom-icons">
<label for="node-input-onicon" style="text-align:right;"><i class="fa fa-toggle-on"></i> On Icon</label>
<input type="text" id="node-input-onicon" style="width:120px">
<label for="node-input-oncolor" style="width:50px; text-align:right;">Colour</label>
<input type="text" id="node-input-oncolor" style="width:120px">
</div>
<div class="form-row form-row-custom-icons">
<label for="node-input-officon" style="text-align:right;"><i class="fa fa-toggle-off"></i> Off Icon</label>
<input type="text" id="node-input-officon" style="width:120px">
<label for="node-input-offcolor" style="width:50px; text-align:right;">Colour</label>
<input type="text" id="node-input-offcolor" style="width:120px">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> Pass through <code>msg</code> if payload matches valid state: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row form-row-decouple">
<label for="node-input-decouple"><i class="fa fa-toggle-on"></i> Indicator</label>
<select id="node-input-decouple" style="display: inline-block; vertical-align: middle; width:70%;">
<option value="false">Switch icon shows state of the output</option>
<option value="true">Switch icon shows state of the input</option>
</select>
</div>
<div class="form-row">
<label style="width:auto" for="node-input-onvalue"><i class="fa fa-envelope-o"></i> When clicked, send:</label>
</div>
<div class="form-row">
<label for="node-input-onvalue" style="padding-left:25px; margin-right:-25px">On Payload</label>
<input type="text" id="node-input-onvalue" style="width:70%">
<input type="hidden" id="node-input-onvalueType">
</div>
<div class="form-row">
<label for="node-input-offvalue" style="padding-left:25px; margin-right:-25px">Off Payload</label>
<input type="text" id="node-input-offvalue" style="width:70%">
<input type="hidden" id="node-input-offvalueType">
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
<input type="text" id="node-input-topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/html" data-help-name="ui_switch">
<p>Adds a switch to the user interface.</p>
<p>Each change in the state of the switch will generate
a <code>msg.payload</code> with the specified <b>On</b> and <b>Off</b> values.</p>
<p>The <b>On/Off Color</b> and <b>On/Off Icon</b> are optional fields. If they are all present, the default
toggle switch will be replaced with the relevant icons and their respective colors.</p>
<p>The <b>On/Off Icon</b> field can be either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
<p>In pass through mode the switch state can be updated by an incoming <code>msg.payload</code> with the specified values,
that must also match the specified type (number, string, etc). When not in passthrough mode then the icon can either
track the state of the output - or the input msg.payload, in order to provide a closed loop feedback.</p>
<p>The label can also be set by a message property by setting
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
<p>If a <b>Topic</b> is specified, it will be added to the output as <code>msg.topic</code>.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the switch widget.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_slider] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_slider',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: 'slider'},
tooltip: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: true},
outs: {value: 'all'},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
min: {value: 0, required:true, validate:RED.validators.number()},
max: {value: 10, required:true, validate:RED.validators.number()},
step: {value: 1},
className: {value: ''}
},
inputs:1,
outputs:1,
outputLabels: function() { return this.min+" - "+this.max; },
icon: "ui_slider.png",
paletteLabel: 'slider',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'slider'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
if (!$("#node-input-outs").val()) { $("#node-input-outs").val("all") }
}
});
</script>
<script type="text/html" data-template-name="ui_slider">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
</div>
<div class="form-row">
<label for="node-input-min"><i class="fa fa-arrows-h"></i> Range</label>
<span for="node-input-min">min</span>
<input type="text" id="node-input-min" style="width:60px">
<span for="not-input-max" style="margin-left:22px;">max</span>
<input type="text" id="node-input-max" style="width:60px">
<span for="not-input-step" style="margin-left:22px;">step</span>
<input type="text" id="node-input-step" style="width:60px">
</div>
<div class="form-row">
<label for="node-input-outs"><i class="fa fa-sign-out"></i> Output</label>
<select id="node-input-outs" style="width:204px">
<option value="all">continuously while sliding</option>
<option value="end">only on release</option>
</select>
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
</div>
<div class="form-row">
<label style="padding-left:25px; margin-right:-25px">Payload</label>
<label style="width:auto">Current value</label>
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
<input type="text" id="node-input-topic">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
<input type="hidden" id="node-input-topicType">
</div>
</script>
<script type="text/html" data-help-name="ui_slider">
<p>Adds a slider widget to the user interface.</p>
<p>The user can change its value between the limits (<b>min</b> and <b>max</b>). Each value change
will generate a message with the value set as <b>payload</b>.</p>
<p>A vertical slider can be created by setting the size so that the height is greater than the width.</p>
<p>The slider can be reversed by setting the min value larger than the max value. e.g. min 100, max 0.</p>
<p>If a <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.</p>
<p>An input <code>msg.payload</code> will be converted to a number, and used to preset a value.
The <b>min</b> value will be used if conversion fails,
and it will update the user interface. If the value changes, it will also be passed to the output.</p>
<p>The label can also be set by a message property by setting
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the slider output.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_numeric] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_numeric',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: 'numeric'},
tooltip: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
wrap: {value: false},
passthru: {value: true},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
format: {value: '{{value}}'},
min: {value: 0, required: true, validate: RED.validators.number()},
max: {value: 10, required: true, validate: RED.validators.number()},
step: {value: 1},
className: {value: ''}
},
inputs:1,
outputs:1,
outputLabels: function() { return this.min+" - "+this.max; },
icon: "ui_numeric.png",
paletteLabel: 'numeric',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'numeric'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
}
});
</script>
<script type="text/html" data-template-name="ui_numeric">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
</div>
<div class="form-row">
<label for="node-input-format"><i class="fa fa-i-cursor"></i> Value Format</label>
<input type="text" id="node-input-format" placeholder="{{value}}">
</div>
<div class="form-row">
<label for="node-input-min"><i class="fa fa-arrows-h"></i> Range</label>
<span for="node-input-min">min</span>
<input type="text" id="node-input-min" style="width:60px">
<span for="not-input-max" style="margin-left:22px;">max</span>
<input type="text" id="node-input-max" style="width:60px">
<span for="not-input-step" style="margin-left:22px;">step</span>
<input type="text" id="node-input-step" style="width:60px">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-wrap"><i class="fa fa-refresh"></i> Wrap value from max to min and min to max.</label>
<input type="checkbox" id="node-input-wrap" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
</div>
<div class="form-row">
<label style="padding-left:25px; margin-right:-25px">Payload</label>
<label style="width:auto">Current value</label>
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
<input type="text" id="node-input-topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/html" data-help-name="ui_numeric">
<p>Adds a numeric input widget to the user interface.</p>
<p>The user can set the value between
the limits (<b>min</b> and <b>max</b>). Each value change will generate a <code>msg.payload</code>.</p>
<p>If <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.<p>
<p>Any input <code>msg.payload</code> will be converted to a number, the <b>min</b> value will be used if conversion fails,
and it will update the user interface. If the value changes, it will also be passed to the output.</p>
<p>The <b>Value Format</b> field can be used to change the displayed format. For example, a <b>Value Format</b>
of <code>{{value}} %</code>
with a value of <b>23</b> will show <b>23 %</b> on the user interface. The <b>Value Format</b> field can contain
HTML or Angular filters to format the output (eg: <code>&amp;deg;</code> will show the degree symbol).</p>
<p>Setting the Value Format field to <code>{{msg.payload}}</code> will make the input field editable so you can type in a number.</p>
<p>The label can also be set by a message property by setting
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the widget output.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_text_input] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_text_input',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: ''},
tooltip: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: true},
mode: {value: 'text', required: true},
delay: {value: 300, validate: RED.validators.number()},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
sendOnBlur: {value: true},
className: {value: ''},
topicType: {value: 'msg'}
},
inputs:1,
outputs:1,
outputLabels: function() { return this.mode; },
icon: "ui_text.png",
paletteLabel: 'text input',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || this.mode+' input'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
}
});
</script>
<script type="text/html" data-template-name="ui_text_input">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
</div>
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-keyboard-o"></i> Mode</label>
<select style="width:128px" id="node-input-mode">
<option value="text">text input</option>
<option value="email">email address</option>
<option value="password">password</option>
<option value="number">number</option>
<option value="tel">telephone input</option>
<option value="color">color picker</option>
<option value="time">time picker</option>
<option value="datetime-local">datetime picker</option>
<option value="week">week picker</option>
<option value="month">month picker</option>
<!-- <option value="date">date picker</option> -->
</select>
<label for="node-input-delay" style="text-align:right; width:100px"><i class="fa fa-clock-o"></i> Delay (ms)</label>
<input type="text" style="width:58px" id="node-input-delay">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-sendOnBlur">Send value on focus leave: </label>
<input type="checkbox" checked id="node-input-sendOnBlur" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
</div>
<div class="form-row">
<label style="padding-left: 25px; margin-right: -25px">Payload</label>
<label style="width:auto">Current value</label>
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left: 25px; margin-right: -25px">Topic</label>
<input type="text" id="node-input-topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
<div class="form-tips">Setting <b>Delay</b> to 0 waits for Enter or Tab key, to send input.</span></div>
</script>
<script type="text/html" data-help-name="ui_text_input">
<p>Adds a text input field to the user interface. Mode can be regular text, email or color picker.</p>
<p>Any input is sent as <code>msg.payload</code>. If set to pass through mode an arriving <code>msg.payload</code>
will be used if it is different from the existing text in the input field. This allows you to preset
the text of the input field.</p>
<p>The <b>Delay</b> <i>(default : 300ms)</i> sets the amount of time in milliseconds before the output is sent.
Setting to <code>0</code> waits for "Enter" or "Tab" key to send. Enter will send payload but remain in focus.
Tab will send payload and move to next field. Clicking elsewhere will also send the payload.</p>
<p>The email mode will color in red if it is not a valid address and will return undefined.</p>
<p>The time input type returns a number of milliseconds from midnight.</p>
<p>Not all browsers support the <i>week</i> and <i>month</i> input types, and may return <i>undefined</i>.
Please test your target browser(s) before use.</p>
<p>If a <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the input.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_date_picker] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_date_picker',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: 'date'},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: true},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
className: {value: ''}
},
inputs:1,
outputs:1,
outputLabels: ["epoch mS"],
icon: "ui_date_picker.png",
paletteLabel: 'date picker',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'date picker'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
}
});
</script>
<script type="text/html" data-template-name="ui_date_picker">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
</div>
<div class="form-row">
<label style="padding-left:25px; margin-right:-25px">Payload</label>
<label style="width:auto">Current value</label>
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
<input type="text" id="node-input-topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/html" data-help-name="ui_date_picker">
<p>Adds a date picker widget to the user interface.</p>
<p>The date display can be formatted in the Dashboard - Site tab using <a href="https://momentjs.com/docs/#/displaying/">
moment.js</a> formatting. For example <code>MM/DD/YYYY</code>, <code>Do MMM YYYY</code> or <code>YYYY-MM-DD</code>.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the input.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_colour_picker] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_colour_picker',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: ''},
group: {type: 'ui_group', required: true},
format: {value: 'hex'},
outformat: {value: 'string'},
showSwatch: {value: true},
showPicker: {value: false},
showValue: {value: false},
showHue: {value: false},
showAlpha: {value: false},
showLightness: {value: true},
square: {value: "false"},
dynOutput: {value: "false"},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
passthru: {value: true},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
className: {value: ''}
},
inputs:1,
outputs:1,
outputLabels: function() { return this.format; },
icon: "ui_colour_picker.png",
paletteLabel: 'colour picker',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'colour picker'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
if (this.square === undefined) {
this.square = "false";
$("#node-input-square").val("false");
}
$("#node-input-square").on("change", function() {
if ($("#node-input-square").val() === "false") {
$("#node-input-showLightness").prop('checked', true);
$("#node-input-showHue").prop('checked', false);
}
else {
$("#node-input-showLightness").prop('checked', false);
$("#node-input-showHue").prop('checked', true);
}
});
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$("#node-input-format").on("change", function() {
if ($(this).val() === "hex") {
$("#node-alpha-control").hide();
}
else {
$("#node-alpha-control").show();
}
});
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
},
oneditsave: function() {
if (!$("#node-input-showPicker").is(':checked') && !$("#node-input-showValue").is(':checked')) {
$("#node-input-showSwatch").prop('checked', true);
this.showSwatch = true;
}
}
});
</script>
<script type="text/html" data-template-name="ui_colour_picker">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label for="node-input-format"><i class="fa fa-keyboard-o"></i> Format</label>
<select id="node-input-format" style="width:156px;">
<option value="hex">hex</option>
<option value="hex8">hex8</option>
<option value="hsl">hsl</option>
<option value="hsv">hsv</option>
<option value="rgb">rgb</option>
</select>
<select id="node-input-square" style="width:130px; margin-left:30px">
<option value="false">round</option>
<option value="true">square</option>
</select>
</div>
<div class="form-row">
<label>&nbsp;</label> Show hue slider : <input type="checkbox" id="node-input-showHue" style="display:inline-block; width:auto; vertical-align:baseline;">
<br/>
<label>&nbsp;</label> Show lightness slider : <input type="checkbox" id="node-input-showLightness" style="display:inline-block; width:auto; vertical-align:baseline;">
<br/>
<span id="node-alpha-control"><label>&nbsp;</label> Show transparency slider : <input type="checkbox" id="node-input-showAlpha" style="display:inline-block; width:auto; vertical-align:baseline;"></span>
</div>
<div class="form-row">
If width is 4 or greater:<br/>
<label>&nbsp;</label>
Always show swatch : <input type="checkbox" checked id="node-input-showSwatch" style="display:inline-block; width:auto; vertical-align:top;">
<br/>
<label>&nbsp;</label>
Always show picker : <input type="checkbox" checked id="node-input-showPicker" style="display:inline-block; width:auto; vertical-align:top;">
<br/>
<label>&nbsp;</label>
Always show value field : <input type="checkbox" checked id="node-input-showValue" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label for="node-input-dynOutput"><i class="fa fa-envelope-o"></i> Send</label>
<select id="node-input-dynOutput" style="width:60%">
<option value="false">one value when released/closed</option>
<option value="true">multiple values during editing</option>
</select>
</div>
<div class="form-row">
<label for="node-input-outformat" style="padding-left: 25px; margin-right: -25px">Payload</label>
<select id="node-input-outformat" style="width:60%">
<option value="string">current value as a string</option>
<option value="object">current value as an object</option>
</select>
</div>
<div class="form-row">
<label for="node-input-topic" style="padding-left: 25px; margin-right: -25px">Topic</label>
<input type="text" id="node-input-topic" placeholder="optional topic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/html" data-help-name="ui_colour_picker">
<p>Adds a colour picker to the dashboard.</p>
<p>If the group width is 4 or greater then the picker can be set to be visible at all times.</p>
<p><b>Format</b> can be rgb, hex, hex8, hsv, or hsl. Transparency is supported for all except hex.</p>
<p>If a <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.</p>
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the input.</p>
<p>If set to pass through mode a message arriving on the input will be evaluated for any colour format available
as Format. If the conversion fails #000000 will be used.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_form] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_form',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(176, 223, 227)',
defaults: {
name: {value: ''},
label: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
options: {value:[{value:'', label :'', type:'', required:true}], validate:function(value) {
if (value.length ) {
for (var i = 0; i < value.length; i++) {
if (!value[i].value) {
return false;
}
}
}
else {
return false;
}
return true;
}, required:true},
formValue:{value:{}},
payload: {value: ''},
submit: {value: "submit"},
cancel: {value: "cancel"},
topic: {value: 'topic', validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('topicType'):function(v) { return true})},
topicType: {value: 'msg'},
splitLayout: {value:''},
className: {value: ''}
},
inputs:1,
outputs:1,
icon: "ui_form.png",
paletteLabel: 'form',
label: function() { return this.name || this.label || 'form'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
if ($("#node-input-submit").val() === null) { $("#node-input-submit").val("submit"); }
if ($("#node-input-cancel").val() === null) { $("#node-input-cancel").val("cancel"); }
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
this.resizeRule = function(option,newWidth) {
//option.find(".node-input-option-type").width(newWidth);
// option.find(".node-input-option-label").width(newWidth);
// option.find(".node-input-option-value").width(newWidth);
}
function generateOption(i, option) {
var container = $('<li/>',{style:"margin:0; padding:8px 0px 0px; border-bottom:1px solid #ccc;"});
var row = $('<div/>').appendTo(container);
var row2 = $('<div/>',{style:"padding-top:5px; padding-left:175px;"}).appendTo(container);
var row3 = $('<div/>',{style:"padding-top:5px; padding-left:120px;"}).appendTo(container);
$('<i style="cursor:move; margin-left:3px;" class="node-input-option-handle fa fa-bars"></i>').appendTo(row);
var labelField = $('<input/>',{class:"node-input-option-label", type:"text", style:"margin-left:7px; width:20%;", placeholder: RED._("node-red-dashboard/ui_form:ui_form.label.egName"), value:option.label}).appendTo(row);//.typedInput({default:'str',types:['str', 'num']});
var valueClass ="node-input-option-value"
if (!option.value) { valueClass ="node-input-option-value input-error"; }
var valueField = $('<input/>',{class:valueClass, type:"text", style:"margin-left:7px; width:20%;", placeholder: RED._("node-red-dashboard/ui_form:ui_form.label.egName2"), value:option.value}).appendTo(row);//.typedInput({default:'str',types:['str','num','bool']});
valueField.keyup(function() {
if ($(this).val() && $(this).hasClass('input-error')) {
$(this).removeClass('input-error')
}
else {
if (!$(this).val()) {
$(this).addClass('input-error')
}
}
});
// var typeField = $('<input/>',{class:"node-input-option-type",type:"text",style:"margin-left: 7px; width: 135px;", placeholder: 'Type', value:option.type}).appendTo(row).typedInput({default:'str',types:['str', 'num']});
var typeField = $('<select/>',{class:"node-input-option-type",type:"text",style:"margin-left:7px; width:16%"}).appendTo(row);//.typedInput({default:'str',types:['str', 'num']});
var arr = [
{val : "text", text: RED._("node-red-dashboard/ui_form:ui_form.label.text")},
{val : "multiline", text: RED._("node-red-dashboard/ui_form:ui_form.label.multiline")},
{val : "number", text: RED._("node-red-dashboard/ui_form:ui_form.label.number")},
{val : "email", text: RED._("node-red-dashboard/ui_form:ui_form.label.email")},
{val : "password", text: RED._("node-red-dashboard/ui_form:ui_form.label.password")},
{val : "checkbox", text: RED._("node-red-dashboard/ui_form:ui_form.label.checkbox")},
{val : "switch", text: RED._("node-red-dashboard/ui_form:ui_form.label.switch")},
{val : "date", text: RED._("node-red-dashboard/ui_form:ui_form.label.date")},
{val : "time", text: RED._("node-red-dashboard/ui_form:ui_form.label.time")}
];
//var sel = $('<select>').appendTo('body');
$(arr).each(function() {
var isSelected= false;
if (option.type == this.val) {
isSelected = true;
}
typeField.append($("<option>").attr('value',this.val).text(this.text).prop('selected',isSelected));
});
//var labelForRequried = $('<span/>',{style:"margin: 10px;"}).text('Required').appendTo(row);
var requiredContainer= $('<div/>',{style:"display:inline-block; height:34px; width:13%; vertical-align: middle"}).appendTo(row);
var requiredInnerContainer= $('<div/>',{style:"left:35%; position:relative; width:30px"}).appendTo(requiredContainer);
var reqRow=$("<label />",{class:"switch",style:"top:10px; width:30px;"}).appendTo(requiredInnerContainer);
//var required = $('<input/>',{class:"node-input-option-required",style:"margin: 5px;width:19%",type:"checkbox", checked:option.required}).appendTo(row);//labelForRequried);//.typedInput({default:'str',types:['str', 'num']});
var required = $('<input/>',{class:"node-input-option-required", type:"checkbox", checked:option.required, style:"vertical-align:top;"}).appendTo(reqRow);//labelForRequried);//.typedInput({default:'str',types:['str', 'num']});
var reqDiv=$("<div />",{class:"slider round"}).appendTo(reqRow);
var vis = option.rows ? 'visible' : 'hidden';
var rowsField = $('<input/>',{class:"node-input-option-rows", type:"number", style:"width:10%;", placeholder:'Rows', value:option.rows }).css('visibility',vis).appendTo(row);
var finalspan = $('<div/>',{style:"display:inline-block; width:5%;"}).appendTo(row);
var deleteButton = $('<a/>',{href:"#",class:"editor-button", style:"font-size:1.3em; left:45%; position:relative;"}).appendTo(finalspan);
$('<i/>',{class:"fa fa-trash-o"}).appendTo(deleteButton);
typeField.change(function(e){
if (e.target.value != 'multiline') {
rowsField.val(undefined)
option.rows = null;
rowsField.css('visibility','hidden')
} else {
rowsField.css('visibility','visible')
if (!rowsField[0].value) rowsField[0].value = 3;
}
})
deleteButton.click(function() {
container.find(".node-input-option-value").removeAttr('required')
container.css({"background":"#fee"});
container.fadeOut(300, function() {
$(this).remove();
});
});
$("#node-input-option-container").append(container);
}
$("#node-input-add-option").click(function() {
generateOption($("#node-input-option-container").children().length+1, {});
$("#node-input-option-container-div").scrollTop($("#node-input-option-container-div").get(0).scrollHeight);
});
for (var i=0; i<this.options.length; i++) {
var option = this.options[i];
generateOption(i+1,option);
}
$('#node-input-topic').typedInput({
default: 'str',
typeField: $("#node-input-topicType"),
types: ['str','msg','flow','global']
});
$( "#node-input-option-container" ).sortable({
axis: "y",
handle:".node-input-option-handle",
cursor: "move"
});
},
oneditsave: function() {
var options = $("#node-input-option-container").children();
var node = this;
node.options = [];
node.formValue = {};
options.each(function(i) {
var option = $(this);
var o = {
label: option.find(".node-input-option-label").val(),//typedInput('value'),
value: option.find(".node-input-option-value").val(),//typedInput('value'),
type: option.find(".node-input-option-type").val(),//typedInput('value')
required: option.find(".node-input-option-required").is(':checked'),
rows: parseInt(option.find(".node-input-option-rows").val())
};
// o.value= o.value||o.label||(o.type+"_"+i);
node.formValue[o.value]= o.type == "checkbox" || o.type == "switch" ? false : "";
node.options.push(o);
});
},
oneditresize: function() {
var options = $("#node-input-option-container").children();
var newWidth = ($("#node-input-option-container").width() - 175)/2;
var node = this;
options.each(function(i) {
node.resizeRule($(this),newWidth);
});
}
});
</script>
<script type="text/html" data-template-name="ui_form">
<style>
.switch {
position: relative;
display: inline-block;
width: 30px;
height: 18px;
}
.switch input {display:none;}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 15px;
width: 15px;
left: 2px;
bottom: 2px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #910000;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(11px);
-ms-transform: translateX(11px);
transform: translateX(11px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
</style>
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui_form.label.group"></label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> <span data-i18n="ui_form.label.size"></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-label"><i class="fa fa-tag"></i> <span data-i18n="ui_form.label.label"></label>
<input type="text" id="node-input-label" data-i18n="[placeholder]ui_form.label.optionalLabel">
</div>
<div class="form-row node-input-option-container-row" style="margin-bottom:0px; width:100%; min-width:520px">
<label style="vertical-align:top;"><i class="fa fa-list-alt"></i> <span data-i18n="ui_form.label.formElements"></label>
<div style="display:inline-block; width:78%; border:1px solid #ccc; border-radius:5px; box-sizing:border-box;">
<div class="red-ui-tray-header" style="width:100%; display: inline-block; padding-top:10px; padding-buttom:10px; border-top:0px solid; border-radius:5px 5px 0 0; border-bottom:1px solid #ccc;">
<div style="width:94%; display:inline-block; margin-left:27px">
<div style="width:20%; text-align:center; float:left;" data-i18n="ui_form.label.label"></span></div>
<div style="width:20%; text-align:center; float:left; margin-left:9px" data-i18n="node-red:common.label.name"></div>
<div style="margin-left:7px; width:16%; text-align:center; float:left; margin-left:9px" data-i18n="ui_form.label.type"></div>
<div style="width:16%; text-align:center; float:left;" data-i18n="ui_form.label.required"></div>
<div style="width:10%; text-align:center; float:left;" data-i18n="ui_form.label.rows"></div>
<div style="width:12%; text-align:center; float:left;" data-i18n="ui_form.label.remove"></div>
</div>
</div>
<div id="node-input-option-container-div" style=" height: 257px; padding: 5px; overflow-y:scroll;">
<ol id="node-input-option-container" style=" list-style-type:none; margin: 0;"></ol>
</div>
</div>
</div>
<div class="form-row">
<a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top: 4px; margin-left: 103px;"><i class="fa fa-plus"></i> <span data-i18n="ui_form.label.element"></span></a>
</div>
<div class="form-row">
<label for="node-input-submit"><i class="fa fa-square"></i> <span data-i18n="ui_form.label.buttons"></label>
<i class="fa fa-thumbs-o-up"></i> <input type="text" id="node-input-submit" data-i18n="[placeholder]ui_form.label.submitButtonText" style="width:35%;">
<span style="margin-left:16px"><i class="fa fa-thumbs-o-down"></i></span>
<input type="text" id="node-input-cancel" data-i18n="[placeholder]ui_form.label.cancelButtonText" style="width:35%;">
</div>
<div class="form-row">
<label for="node-input-splitLayout"></label>
<input type="checkbox" id="node-input-splitLayout" style="display:inline-block; width:auto; vertical-align:top;">
<span data-i18n="ui_form.label.splitLayout">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="ui_form.label.topic"></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]ui_form.label.optionalMsgTopic">
<input type="hidden" id="node-input-topicType">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="ui_form.label.className"></label>
<input type="text" id="node-input-className" data-i18n="[placeholder]ui_form.label.classNamePlaceholder"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
</script>
<script type="text/html" data-help-name="ui_form">
<p>Fügt dem Dashboard ein Eingabeformular hinzu.</p>
<p>Der <code>ui_form</code>-Node ermöglicht die Eingabe mehrerer Werte durch den Benutzer.
Beim Klicken auf die Schaltfläche <b>Senden</b> wird ein Objekt als <code>msg.payload</code> versendet.</p>
<p>Über die Schaltfläche <b>+Element</b> können Eingabeelemente hinzugefügt werden.</p>
<p>Jedes Element enthält folgende Einstellmöglichkeiten:</p>
<ul>
<li><b>Beschriftung:</b> Beschriftung des Elements in der Benutzeroberfläche</li>
<li><b>Name:</b> Schlüssel (Variablennamen), mit dem der Eingabewert in <code>msg.payload</code> abgelegt wird</li>
<li><b>Typ:</b> Typ des Eingabeelements</li>
<li><b>Erforderlich:</b> Markierund des Eingabefeldes als erfolderliche Benutzereingabe</li>
<li><b>Zeilen:</b> Zeilenanzahl bei mehrzeiligen Texteingabefeldern</li>
<li><b>Entfernen:</b> Entfernung des Elements aus dem Formular</li>
</ul>
<p>Über <b>Topic</b> kann die Eigenschaft <code>msg.topic</code> optional festgelegt werden.</p>
<p>Die Schaltfläche <b>Abbrechen</b> kann ausgeblendet werden, indem sein Feld leer gelassen wird.</p>
<p>Wenn eine <b>Klasse</b> angegeben ist, wird sie der übergeordneten Karte hinzugefügt. Auf diese Weise können Sie CSS-Stile auf die ui-card und ihre untergeordneten Elemente anwenden. Die Klasse kann zur Laufzeit festgelegt werden, indem eine Zeichenfolgeneigenschaft <code>msg.className</code> festgelegt wird.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_text] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_text',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(119, 198, 204)',
defaults: {
group: {type: 'ui_group', required:true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
name: {value: ''},
label: {value: 'text'},
format: {value: '{{msg.payload}}'},
layout: {value:'row-spread'},
className: {value: ''}
},
inputs:1,
outputs:0,
align: "right",
icon: "ui_text.png",
paletteLabel: 'text',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'text'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$(".nr-db-text-layout-"+(this.layout||'row-spread')).addClass('selected');
[ ".nr-db-text-layout-row-left",".nr-db-text-layout-row-center",".nr-db-text-layout-row-right",
".nr-db-text-layout-row-spread",".nr-db-text-layout-col-center"].forEach(function(id) {
$(id).click(function(e) {
$(".nr-db-text-layout").removeClass('selected');
$(this).addClass('selected');
$('#node-input-layout').val(id.substring(".nr-db-text-layout-".length));
e.preventDefault();
})
})
}
});
</script>
<script type="text/html" data-template-name="ui_text">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-label"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-label">
</div>
<div class="form-row">
<label for="node-input-format"><i class="fa fa-i-cursor"></i> Value format</label>
<input type="text" id="node-input-format" placeholder="{{msg.payload}}">
</div>
<div class="form-row">
<label style="vertical-align: top"><i class="fa fa-th-large"></i> Layout</label>
<div style="display:inline-block">
<input type="hidden" id="node-input-layout"><input type="hidden" id="node-input-layoutAlign">
<div>
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-left">
<span class="nr-db-text-layout-label">label</span>
<span class="nr-db-text-layout-value">value</span>
<div class="nr-db-text-layout-checkbox"></div>
</a>
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-center">
<span class="nr-db-text-layout-label">label</span>
<span class="nr-db-text-layout-value">value</span>
<div class="nr-db-text-layout-checkbox"></div>
</a>
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-right">
<span class="nr-db-text-layout-label">label</span>
<span class="nr-db-text-layout-value">value</span>
<div class="nr-db-text-layout-checkbox"></div>
</a>
</div>
<div>
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-spread">
<span class="nr-db-text-layout-label">label</span>
<span class="nr-db-text-layout-value">value</span>
<div class="nr-db-text-layout-checkbox"></div>
</a>
<a href="#" class="nr-db-text-layout nr-db-text-layout-col nr-db-text-layout-col-center">
<span class="nr-db-text-layout-label">label</span>
<span class="nr-db-text-layout-value">value</span>
<div class="nr-db-text-layout-checkbox"></div>
</a>
</div>
</div>
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<style>
.nr-db-text-layout {
position:relative;
display: inline-block;
width: 90px;
height: 60px;
border-radius:3px;
border:1px solid #bbb;
cursor:pointer;
color: #666;
margin-right: 10px;
margin-bottom: 10px;
}
.nr-db-text-layout.selected, .nr-db-text-layout:hover {
border-color: #333;
color: #333;
}
.nr-db-text-layout span {
position: absolute;
}
.nr-db-text-layout-value {
font-weight: bold;
}
.nr-db-text-layout-row span { top: 20px; }
.nr-db-text-layout-row-left .nr-db-text-layout-label { left: 2px; }
.nr-db-text-layout-row-left .nr-db-text-layout-value { left: 34px; }
.nr-db-text-layout-row-spread .nr-db-text-layout-label { left: 2px; }
.nr-db-text-layout-row-spread .nr-db-text-layout-value { right: 2px; }
.nr-db-text-layout-row-center .nr-db-text-layout-label { left: 11px; }
.nr-db-text-layout-row-center .nr-db-text-layout-value { right: 11px; }
.nr-db-text-layout-row-right .nr-db-text-layout-label { right: 40px; }
.nr-db-text-layout-row-right .nr-db-text-layout-value { right: 2px; }
.nr-db-text-layout-col span { width: 90px; text-align: center; left: 0px;}
.nr-db-text-layout-col-center .nr-db-text-layout-label { top: 12px; }
.nr-db-text-layout-col-center .nr-db-text-layout-value { top: 26px; }
.nr-db-text-layout-checkbox {
display: none;
width: 10px;
height: 10px;
border-radius: 10px;
border: 1px solid #bbb;
position: absolute;
right: -5px;
top: -5px;
background: #fff;
}
.nr-db-text-layout.selected .nr-db-text-layout-checkbox {
display:inline-block;
box-shadow: inset 0px 0px 0px 2px #fff;
background: #333;
border-color: #333;
}
</style>
<script type="text/html" data-help-name="ui_text">
<p>Will display a non-editable text field on the user interface.</p>
<p>Each received <code>msg.payload</code> will update the text based on the provided <b>Value Format</b>.</p>
<p>The <b>Value Format</b> field can be used to change the displayed format and can contain valid HTML and
<a href="https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters" target="_blank">Angular filters</a>.</p>
<p>For example: <code>{{value | uppercase}} &amp;deg;</code> will uppercase the payload text and add the degree symbol.</p>
<p>The label can also be set by a message property by setting
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
<p>The following icon fonts are also available: <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
<p>The widget also has a class of <code>nr-dashboard-widget-{the_widget_label_with_underscores}</code> which can be used for additional
styling if required. You may need to use the <i>!important</i> flag to override the theme.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_gauge] --- -->
<style>
input.gauge-color {
width: 100px;
text-align: center;
}
input.gauge-color::-webkit-color-swatch {
border: none;
}
</style>
<script type="text/javascript">
RED.nodes.registerType('ui_gauge',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(119, 198, 204)',
defaults: {
name: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v || 0;
var currentGroup = $('#node-input-group').val() || this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
gtype: {value: 'gage'},
title: {value: 'gauge'},
label: {value: 'units'},
format: {value: '{{value}}'},
min: {value: 0, required: true, validate: RED.validators.number()},
max: {value: 10, required: true, validate: RED.validators.number()},
colors: {value: ["#00B500","#E6E600","#CA3838"]},
seg1: {value: ""},
seg2: {value: ""},
diff: {value: false},
className: {value: ''}
},
inputs:1,
outputs:0,
inputLabels: function() { return this.min+" - "+this.max; },
align: "right",
icon: "ui_gauge.png",
paletteLabel: 'gauge',
label: function() { return this.name || (~this.title.indexOf("{{") ? null : this.title) || ((this.gtype === "gage") ? "gauge" : this.gtype) || 'gauge'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
var setColour = function(id, value) {
$(id).val(value);
$(id).css("background-color", value);
var rgb = tinycolor(value).toRgb();
var level = ((rgb.r*299) + (rgb.g*587) + (rgb.b*114))/1000;
var textColor = (level >= 128) ? '#111111' : '#eeeeee';
$(id).css("color", textColor);
}
$(".gauge-color").on("change", function() {
setColour("#"+$(this).attr("id"), $(this).val());
});
var defaultColors = ['#00B500', '#E6E600', '#CA3838'];
if (this.colors) {
for (var i=0; i<this.colors.length; i++) {
var value = this.colors[i] || defaultColors[i];
setColour("#node-input-color"+(i+1), value);
}
}
else {
for (var j=0; j<defaultColors.length; j++) {
setColour("#node-input-color"+(j+1), defaultColors[j]);
}
}
if (this.gtype === undefined) {
this.gtype = "gage";
$("#node-input-gtype").val("gage");
}
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$("#node-input-gtype").on("change", function() {
if (($(this).val() === "compass") || ($(this).val() === "wave")) {
$("#ui-gauge-colours").hide();
$("#ui-gauge-segments").hide();
}
else {
$("#ui-gauge-colours").show();
$("#ui-gauge-segments").show();
}
if ($(this).val() === "gage") {
$("#ui-gauge-diff").show();
}
else { $("#ui-gauge-diff").hide(); }
});
$("#node-input-min").on("change", function() {
$("#seg-min").text($(this).val());
});
$("#node-input-max").on("change", function() {
$("#seg-max").text($(this).val());
});
},
oneditsave: function() {
this.colors = [$("#node-input-color1").val(),$("#node-input-color2").val(),$("#node-input-color3").val()];
}
});
</script>
<script type="text/html" data-template-name="ui_gauge">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-gtype"><i class="fa fa-list"></i> Type</label>
<select id="node-input-gtype" style="width:150px">
<option value="gage">Gauge</option>
<option value="donut">Donut</option>
<option value="compass">Compass</option>
<option value="wave">Level</option>
</select>
</div>
<div id="ui-gauge-labels">
<div class="form-row">
<label for="node-input-title"><i class="fa fa-i-cursor"></i> Label</label>
<input type="text" id="node-input-title">
</div>
<div class="form-row" id="ui-gauge-format">
<label for="node-input-format"><i class="fa fa-i-cursor"></i> Value format</label>
<input type="text" id="node-input-format" placeholder="{{value}}">
</div>
<div class="form-row" id="ui-gauge-units">
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Units</label>
<input type="text" id="node-input-label" placeholder="optional sub-label">
</div>
</div>
<div class="form-row">
<label for="node-input-min">Range</label>
<span for="node-input-min">min</span>
<input type="text" id="node-input-min" style="width:80px">
<span for="node-input-max" style="margin-left:20px;">max</span>
<input type="text" id="node-input-max" style="width:80px">
</div>
<div class="form-row" id="ui-gauge-colours">
<label for="node-input-color1">Colour gradient</label>
<input type="color" id="node-input-color1" class="gauge-color" style="width:100px;"/>
<input type="color" id="node-input-color2" class="gauge-color" style="width:100px;"/>
<input type="color" id="node-input-color3" class="gauge-color" style="width:100px;"/>
</div>
<div class="form-row" id="ui-gauge-segments">
<label>Sectors</label>
<span id="seg-min" style="display:inline-block; width:40px;">0</span>...
<input type="text" id="node-input-seg1" style="text-align:center; width:87px;" placeholder="optional"> ...
<input type="text" id="node-input-seg2" style="text-align:center; width:87px;" placeholder="optional"> ...
<span id="seg-max" style="display:inline-block; width:40px; text-align:right">10</span>
</div>
<div class="form-row" id="ui-gauge-diff">
<label></label> Fill gauge from centre.
<input type="checkbox" id="node-input-diff" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name">
</div>
</script>
<script type="text/html" data-help-name="ui_gauge">
<p>Adds a gauge type widget to the user interface.</p>
<p>The <code>msg.payload</code> is searched for a numeric <i>value</i> and is formatted in accordance with
the defined <b>Value Format</b>, which can then be formatted using
<a href="https://docs.angularjs.org/api/ng/filter" target="_blank">Angular filters</a>.</p>
<p>For example : <code>{{value | number:1}}%</code> will round the value to one decimal place and append a % sign.</p>
<p>The colours of each of 3 sectors can be specified and the gauge will blend between them.
The colours should be specified in hex (#rrggbb) format.</p>
<p>If you specify numbers for the sectors then the colours changes per sector.
If not specified the colours are blended across the total range.</p>
<p>The gauge has several modes. Regular gauge, donut, compass and wave.</p>
<p>The label can also be set by a message property by setting
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_chart] --- -->
<style>
input.series-color {
width: 100px;
text-align: center;
}
input.series-color::-webkit-color-swatch {
border: none;
}
</style>
<script type="text/javascript">
RED.nodes.registerType('ui_chart',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(119, 198, 204)',
defaults: {
name: {value: ''},
group: {type: 'ui_group', required: true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}},
height: {value: 0},
label: {value: 'chart'},
chartType: {value: 'line'},
legend: {value: 'false'},
xformat: {value: 'HH:mm:ss'},
interpolate: {value: 'linear', required:true},
nodata: {value: ''},
dot: {value: false},
ymin: {value: '', validate:function(value) { return value === '' || RED.validators.number(); }},
ymax: {value: '', validate:function(value) { return value === '' || RED.validators.number(); }},
removeOlder: {value: 1, validate:RED.validators.number(), required:true},
removeOlderPoints: {value: '', validate:function(value) { return value === '' || RED.validators.number(); }},
removeOlderUnit: {value: '3600', required:true},
cutout: {value: 0},
useOneColor: {value: false},
useUTC: {value: false},
colors: {value: ['#1F77B4', '#AEC7E8', '#FF7F0E', '#2CA02C', '#98DF8A', '#D62728', '#FF9896', '#9467BD', '#C5B0D5']},
outputs: {value: 1},
useDifferentColor: {value: false},
className: {value: ''}
},
inputs:1,
outputs:1,
inputLabels: function() { return this.chartType; },
outputLabels: ["chart state"],
align: "right",
icon: "ui_chart.png",
paletteLabel: 'chart',
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'chart'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
var oldouts = this.outputs;
if (RED.nodes.filterLinks({source:{id:this.id},sourcePort:1}).length > 0) { this.outputs = 2; }
else { this.outputs = 1; }
if (this.outputs !== oldouts) { this.changed = true; }
if (!$("#node-input-chartType").val()) {
$("#node-input-chartType").val("line");
}
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
$("#node-input-chartType").on("change", function() {
$("#legend-show").hide();
$("#show-useDifferentColor").hide();
if ($(this).val() === "horizontalBar") {
$("#y-label-show").hide();
$("#x-label-show").show();
}
else {
$("#y-label-show").show();
$("#x-label-show").hide();
}
if ($(this).val() === "line") {
$("#x-axis-show").show();
$("#x-axis-label-show").show();
$("#interpolate-show").show();
$("#legend-show").show();
$("#y-axis-show").show();
$("#hole-size-show").hide();
$("#show-dot-field").show();
$("#show-useOneColor").hide();
}
else {
$("#x-axis-show").hide();
$("#x-axis-label-show").hide();
$("#interpolate-show").hide();
$("#show-dot-field").hide();
if (($(this).val() === "bar")||($(this).val() === "horizontalBar")) {
$("#show-useOneColor").show();
$("#legend-show").show();
}
else {
$("#show-useOneColor").hide();
}
if ($(this).val() === "pie") {
$("#y-axis-show").hide();
$("#legend-show").show();
$("#hole-size-show").show();
}
else if ($(this).val() === "polar-area") {
$("#y-axis-show").show();
$("#legend-show").show();
$("#hole-size-show").hide();
$("#show-useDifferentColor").show();
}
else if ($(this).val() === "radar") {
$("#y-axis-show").show();
$("#legend-show").show();
$("#hole-size-show").hide();
}
else {
$("#y-axis-show").show();
$("#hole-size-show").hide();
}
}
});
var setColour = function(id, value) {
$(id).val(value);
$(id).css("background-color", value);
var rgb = tinycolor(value).toRgb();
var level = ((rgb.r*299) + (rgb.g*587) + (rgb.b*114))/1000;
var textColor = (level >= 128) ? '#111111' : '#eeeeee';
$(id).css("color", textColor);
}
$(".series-color").on("change", function() {
setColour("#"+$(this).attr("id"), $(this).val());
});
var oval = $("#node-input-xformat").val();
if (!oval) { $("#node-input-xformat").val("HH:mm:ss"); }
var odef = 'custom';
if (oval === "HH:mm:ss") { odef = oval; }
if (oval === "HH:mm") { odef = oval; }
if (oval === "Y-M-D") { odef = oval; }
if (oval === "D/M") { odef = oval; }
if (oval === "dd HH:mm") { odef = oval; }
if (oval === "auto") { odef = oval; }
var ohms = {value: "HH:mm:ss", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.HHmmss"), hasValue: false};
var ohm = {value: "HH:mm", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.HHmm"), hasValue: false};
var oymd = {value: "Y-M-D", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.yearMonthDate"), hasValue: false};
var odm = {value: "D/M", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.dateMonth"), hasValue: false};
var oahm = {value: "dd HH:mm", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.dayHHmm"), hasValue: false};
var ocus = {value: "custom", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.custom"), icon: "red/images/typedInput/az.png"};
var oaut = {value: "auto", label: RED._("node-red-dashboard/ui_chart:ui_chart.label.automatic"), hasValue: false};
$("#node-input-xformat").typedInput({
default: odef,
types:[ ohms, ohm, oahm, odm, oymd, ocus, oaut ]
});
var defaultColors = ['#1F77B4', '#AEC7E8', '#FF7F0E', '#2CA02C', '#98DF8A', '#D62728', '#FF9896', '#9467BD', '#C5B0D5'];
if (this.colors) {
for (var i=0; i<this.colors.length; i++) {
var value = this.colors[i] || defaultColors[i];
setColour("#node-input-color"+(i+1), value);
}
}
else {
for (var c=0; c<defaultColors.length; c++) {
setColour("#node-input-color"+(c+1), defaultColors[c]);
}
}
},
oneditsave: function() {
if ($("#node-input-xformat").typedInput('type') !== 'custom') {
$("#node-input-xformat").val($("#node-input-xformat").typedInput('type'));
}
this.colors = [$("#node-input-color1").val(),$("#node-input-color2").val(),$("#node-input-color3").val(),
$("#node-input-color4").val(),$("#node-input-color5").val(),$("#node-input-color6").val(),
$("#node-input-color7").val(),$("#node-input-color8").val(),$("#node-input-color9").val()];
}
});
</script>
<script type="text/html" data-template-name="ui_chart">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui_chart.label.group"></label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> <span data-i18n="ui_chart.label.size"></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-label"><i class="fa fa-i-cursor"></i> <span data-i18n="ui_chart.label.label"></label>
<input type="text" id="node-input-label" data-i18n="[placeholder]ui_chart.label.optionalChartTitle">
</div>
<div class="form-row">
<label for="node-input-removeOlder"><i class="fa fa-line-chart"></i> <span data-i18n="ui_chart.label.type"></label>
<select id="node-input-chartType" style="width:159px; font-family:'FontAwesome','Helvetica Neue', Helvetica, Arial, sans-serif">
<option value="line" data-i18n="[html]ui_chart.label.lineChart"></option>
<option value="bar" data-i18n="[html]ui_chart.label.barChart"></option>
<option value="horizontalBar" data-i18n="[html]ui_chart.label.barChartH"></option>
<option value="pie" data-i18n="[html]ui_chart.label.pieChart"></option>
<option value="polar-area" data-i18n="[html]ui_chart.label.polarAreaChart"></option>
<option value="radar" data-i18n="[html]ui_chart.label.radarChart"></option>
</select>
<div id="show-dot-field" style="display:inline-block;">
<input type="checkbox" id="node-input-dot" style="display:inline-block; width:auto; vertical-align:baseline; margin-left:40px; margin-right:5px;"><span data-i18n="ui_chart.label.enlargePoints">
</div>
</div>
<div class="form-row" id="x-axis-show">
<label for="node-input-removeOlder" data-i18n="ui_chart.label.xAxis"></label>
<label for="node-input-removeOlder" style="width:auto" data-i18n="ui_chart.label.last"></label>
<input type="text" id="node-input-removeOlder" style="width:50px;">
<select id="node-input-removeOlderUnit" style="width:80px;">
<option value="1" data-i18n="ui_chart.label.seconds"></option>
<option value="60" data-i18n="ui_chart.label.minutes"></option>
<option value="3600" data-i18n="ui_chart.label.hours"></option>
<option value="86400" data-i18n="ui_chart.label.days"></option>
<option value="604800" data-i18n="ui_chart.label.weeks"></option>
</select>
<label for="node-input-removeOlderPoints" style="width:auto; margin-left:10px; margin-right:10px;" data-i18n="ui_chart.label.or"></label>
<input type="text" id="node-input-removeOlderPoints" style="width:60px;" placeholder="1000">
<span style="margin-left:5px;" data-i18n="ui_chart.label.points"></span>
</div>
<div class="form-row" id="x-axis-label-show">
<label for="node-input-xformat" data-i18n="ui_chart.label.xAxisLabel"></label>
<input type="text" id="node-input-xformat" style="width:250px;">
<input type="checkbox" id="node-input-useUTC" style="display:inline-block; width:auto; vertical-align:baseline; margin-left:8px; margin-right:4px;"> <span data-i18n="ui_chart.label.asUTC"></span>
</div>
<div class="form-row" id="y-axis-show">
<label id="y-label-show" for="node-input-ymin" data-i18n="ui_chart.label.yAxis"></label>
<label id="x-label-show" for="node-input-ymin" data-i18n="ui_chart.label.xAxis"></label>
<label for="node-input-ymin" style="width:auto" data-i18n="ui_chart.label.min"></label>
<input type="text" id="node-input-ymin" style="width:92px">
<label for="node-input-ymax" style="width:auto; margin-left:20px;" data-i18n="ui_chart.label.max"></label>
<input type="text" id="node-input-ymax" style="width:92px">
</div>
<div class="form-row" id="legend-show">
<label for="node-input-legend" data-i18n="ui_chart.label.legend"></label>
<select id="node-input-legend" style="width:120px;">
<option value="false" data-i18n="ui_chart.label.none"></option>
<option value="true" data-i18n="ui_chart.label.show"></option>
</select>
<span id="interpolate-show">&nbsp;&nbsp;&nbsp;&nbsp;<span data-i18n="ui_chart.label.interpolate"></span>
<select id="node-input-interpolate" style="width:120px;">
<option value="linear" data-i18n="ui_chart.label.linear"></option>
<option value="step" data-i18n="ui_chart.label.step"></option>
<option value="bezier" data-i18n="ui_chart.label.bezier"></option>
<option value="cubic" data-i18n="ui_chart.label.cubic"></option>
<option value="monotone" data-i18n="ui_chart.label.cubicMono"></option>
</select>
</span>
<span id="hole-size-show">&nbsp;&nbsp;&nbsp;&nbsp;<span data-i18n="ui_chart.label.cutout"></span>
<input type="text" id="node-input-cutout" style="width:35px"> %
</span>
</div>
<div id="show-useOneColor" style="display:none; height:24px;">
<input type="checkbox" id="node-input-useOneColor" style="display:inline-block; width:auto; vertical-align:baseline; margin-left:105px; margin-right:5px;"><span data-i18n="ui_chart.label.useFirstColourForAllBars"></span>
</div>
<div class="form-row" id="ui-chart-colours">
<label for="node-input-color1" data-i18n="ui_chart.label.seriesColours"></label>
<input type="color" id="node-input-color1" class="series-color" style="width:100px;"/>
<input type="color" id="node-input-color2" class="series-color" style="width:100px;"/>
<input type="color" id="node-input-color3" class="series-color" style="width:100px;"/>
<div style="margin-top:5px; margin-left:104px;">
<input type="color" id="node-input-color4" class="series-color" style="width:100px;"/>
<input type="color" id="node-input-color5" class="series-color" style="width:100px;"/>
<input type="color" id="node-input-color6" class="series-color" style="width:100px;"/>
</div>
<div style="margin-top:5px; margin-left:104px;">
<input type="color" id="node-input-color7" class="series-color" style="width:100px;"/>
<input type="color" id="node-input-color8" class="series-color" style="width:100px;"/>
<input type="color" id="node-input-color9" class="series-color" style="width:100px;"/>
</div>
</div>
<div id="show-useDifferentColor" class="form-row">
<label></label>
<input type="checkbox" id="node-input-useDifferentColor" style="display:inline-block; width:auto; vertical-align:top;">
<span data-i18n="ui_chart.label.useDifferentColor"></span>
</input>
</div>
<div class="form-row">
<label for="node-input-nodata" data-i18n="ui_chart.label.blankLabel"></label>
<input type="text" id="node-input-nodata" data-i18n="[placeholder]ui_chart.label.displayThisTextBeforeValidDataArrives">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="ui_chart.label.className"></span></label>
<input type="text" id="node-input-className" data-i18n="[placeholder]ui_chart.label.classNamePlaceholder"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
</script>
<script type="text/html" data-help-name="ui_chart">
<p>Zeichnet Eingangswerte in ein Diagramm, welches entweder ein zeitbasiertes Liniendiagramm,
ein Balkendiagramm (vertikal oder horizontal) oder ein Kreisdiagramm sein kann.</p>
<p>Jede eingehende <code>msg.payload</code>-Nachricht wird in einen Zahlenwert konvertiert.
Wenn die Konvertierung fehlschlägt, wird die Nachricht ignoriert.</p>
<p>Die Minimum- und Maximum-Werte für die <b>Y-Achse</b> sind optional.
Ohne diese wird das Diagramm automatisch anhand aller empfangenen Werte skaliert.</p>
<p>Mehrere Serien können im gleichen Diagramm angezeigt werden,
indem für jede Eingangsnachricht andere <code>msg.topic</code>-Werte verwendet werden.
Mit der Eigenschaft <code>msg.label</code> können mehrere Balken der selben Serie angezeigt werden.</p>
<p>Der Wertebereich der <b>X-Achse</b> wird durch ein Zeitfenster oder eine maximale Anzahl anzuzeigender Punkte vorgegeben.
Ältere Daten werden automatisch aus dem Diagramm entfernt.
Die Achsenbeschriftung kann mittels einer <a href="https://momentjs.com/docs/#/displaying/format/" target="_blank">
Moment.js-zeitformatierten</a> Zeichenfolge benutzerdefiniert werden (z.B. D.M.Y für 21.3.2021).</p>
<p>Wird eine <code>msg.payload</code>-Nachricht mit einem leeren Array <code>[]</code> an den Eingang gesendet,
so wird das Diagramm gelöscht.</p>
<p><b><a href="https://github.com/node-red/node-red-dashboard/blob/master/Charts.md" target="_new">Hier</a></b>
sind weitere Informationen zum Vorformatieren von Daten verfügbar, um sie als vollständiges Diagramm zu übergeben.</p>
<p>Das <b>Leer-Text</b>-Feld kann verwendet werden, um den Text im Diagramm anzuzeigen, bevor gültige Daten empfangen wurden.
<p>Der <b>Beschriftung</b> kann auch durch eine Nachrichteneigenschaft festgelegt werden.
Dazu muss der Name der Eigenschaft in das Feld eingetragen werden, zum Beispiel <code>{{msg.topic}}</code>.</p>
<p>Der Node-Ausgang enthält ein Array des Diagrammstatus, das bei Bedarf gespeichert werden kann.
Wird dieses zum <code>ui_chart</code>-Node gesendet, so werden die gespeicherten Daten erneut angezeigt.</p>
<p>Wenn eine <b>Klasse</b> angegeben ist, wird sie der übergeordneten Karte hinzugefügt. Auf diese Weise können Sie CSS-Stile auf die ui-card und ihre untergeordneten Elemente anwenden. Die Klasse kann zur Laufzeit festgelegt werden, indem eine Zeichenfolgeneigenschaft <code>msg.className</code> festgelegt wird.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_audio] --- -->
<script type="text/javascript">
(function() {
var myvoice = 0;
var voices;
RED.nodes.registerType('ui_audio',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
paletteLabel: 'audio out',
color: 'rgb(119, 198, 204)',
defaults: {
name: {value:""},
group: {type: 'ui_group', required: true},
voice: {value:""},
always: {value:""}
},
inputs:1,
outputs:0,
icon: "feed.png",
align: "right",
label: function() { return this.name||"audio out"; },
labelStyle: function() { return this.name?"node_label_italic":""; },
onpaletteadd: function() {
if ('speechSynthesis' in window) { voices = window.speechSynthesis.getVoices(); }
},
oneditprepare: function() {
if ('speechSynthesis' in window) {
voices = window.speechSynthesis.getVoices();
for (i = 0; i < voices.length ; i++) {
//console.log(i,voices[i].name,voices[i].lang,voices[i].voiceURI,voices[i].default);
var option = document.createElement('option');
option.textContent = i + " : " + voices[i].name + ' (' + voices[i].lang + ')';
if (voices[i].default) { option.textContent += ' -- DEFAULT'; }
option.setAttribute('value', voices[i].voiceURI);
document.getElementById("node-input-voice").appendChild(option);
}
$('#node-input-voice').val(this.voice || 0);
}
else {
$('#voice-input-row').hide();
}
$("#node-input-voice").on("change", function() {
myvoice = this.voice = $("#node-input-voice").val();
});
}
});
})();
</script>
<script type="text/html" data-template-name="ui_audio">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row" id="voice-input-row">
<label for="node-input-voice"><i class="fa fa-language"></i> TTS Voice</label>
<select id="node-input-voice" style="width:70%"></select>
</div>
<div class="form-row">
<label for="node-input-always"></label>
<input type="checkbox" checked id="node-input-always" style="display:inline-block; width:auto; vertical-align:top;">
Play audio when window not in focus.
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/html" data-help-name="ui_audio">
<p>Plays audio or text to speech (TTS) in the dashboard.</p>
<p>To work the dashboard web page must be open.</p>
<p>Expects <code>msg.payload</code> to contain a buffer of a <b>wav</b> or <b>mp3</b> file.</p>
<p>If your browser has native support for Text-to-Speech then a <code>msg.payload</code>
can also be a <b>string</b> to be read aloud.</p>
<p>Optionally setting <code>msg.level</code> from 0 to 100 will change the volume from 0 to 100%. Default is 100%.
In audio mode you can go up to 300, but you may get distortion.</p>
<p>When a <code>msg.reset</code> is available with value <code>true</code>, then playback of the current audio fragment will be stopped.</p>
<p>The <b>node status</b> reflects the current playback status:
<ul>
<li><b>started:</b> the audio fragment playback has been started.</li>
<li><b>reset:</b> the audio fragment playback has been reset (i.e. stopped before completed).</li>
</ul>
As soon as the audio fragment playback is completed, the node status will be cleared automatically.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_toast] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_toast', {
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb(119, 198, 204)',
defaults: {
position: {value: 'top right'},
displayTime: {value: '3'},
highlight: {value: ''},
sendall: {value: true},
outputs: {value: 0},
ok: {value: 'OK', required: true},
cancel: {value: ''},
raw: {value: false},
className: {value: ''},
topic: {value: ''},
name: {value: ''}
},
inputs:1,
outputs:0,
align: "right",
icon: "ui_toast.png",
paletteLabel: 'notification',
label: function() { return this.name || (this.position==="prompt" ? "show dialog" : (this.position==="dialog" ? "show dialog" : "show notification")); },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-position").on("change", function() {
if ($("#node-input-position option:selected").val() === 'dialog') {
$("#node-toast-displaytime").hide();
$("#node-toast-highlightcolor").hide();
$("#node-toast-sendall").hide();
$("#node-dialog-displayok").show();
$("#node-dialog-displaycancel").show();
$("#node-dialog-topic").show();
}
else if ($("#node-input-position option:selected").val() === 'prompt') {
$("#node-toast-displaytime").hide();
$("#node-toast-highlightcolor").hide();
$("#node-toast-sendall").hide();
$("#node-dialog-displayok").show();
$("#node-dialog-displaycancel").show();
$("#node-dialog-topic").show();
if (typeof $("#node-input-cancel").val() !== "string" || $("#node-input-cancel").val() === "" ) {
$("#node-input-cancel").val("Cancel");
}
}
else {
$("#node-toast-displaytime").show();
$("#node-toast-highlightcolor").show();
$("#node-toast-sendall").show();
$("#node-dialog-displayok").hide();
$("#node-dialog-displaycancel").hide();
$("#node-dialog-topic").show();
}
});
},
oneditsave: function() {
if ($("#node-input-position option:selected").val() === 'dialog') { this.outputs = 1; }
else if ($("#node-input-position option:selected").val() === 'prompt') { this.outputs = 1; }
else { this.outputs = 0; }
}
});
</script>
<script type="text/html" data-template-name="ui_toast">
<div class="form-row">
<label for="node-input-position"><i class="fa fa-th-large"></i> Layout</label>
<select type="text" id="node-input-position" style="display:inline-block; width:70%; vertical-align:baseline;">
<option value="top right">Top Right</option>
<option value="bottom right">Bottom Right</option>
<option value="top left">Top Left</option>
<option value="bottom left">Bottom Left</option>
<option value="dialog">OK / Cancel Dialog</option>
<option value="prompt">OK / Cancel Dialog with Input</option>
</select>
</div>
<div class="form-row" id="node-toast-displaytime">
<label for="node-input-displayTime"><i class="fa fa-clock-o"></i> Timeout (S)</label>
<input type="text" id="node-input-displayTime" placeholder="[msg.timeout]">
</div>
<div class="form-row" id="node-toast-highlightcolor">
<label for="node-input-highlight"><i class="fa fa-square-o"></i> Border</label>
<input type="text" id="node-input-highlight" placeholder="(optional) border highlight colour">
</div>
<div class="form-row" id="node-toast-sendtoall">
<label style="width:auto" for="node-input-sendall"><i class="fa fa-arrow-right"></i> Send to all browser sessions. </label>
<input type="checkbox" checked id="node-input-sendall" style="display:inline-block; width:auto; vertical-align:baseline;">
</div>
<div class="form-row" id="node-dialog-displayok">
<label for="node-input-ok"><i class="fa fa-check"></i> Default action label</label>
<input type="text" id="node-input-ok" placeholder="label for OK button">
</div>
<div class="form-row" id="node-dialog-displaycancel">
<label for="node-input-cancel"><i class="fa fa-times"></i> Secondary action label</label>
<input type="text" id="node-input-cancel" placeholder="(optional label for Cancel button)">
</div>
<div class="form-row" id="node-toast-raw">
<label style="width:auto" for="node-input-raw"><i class="fa fa-exclamation-triangle"></i> Accept raw HTML/JavaScript input in msg.payload to format popup.</label>
<input type="checkbox" id="node-input-raw" style="display:inline-block; width:auto; vertical-align:baseline;">
</div>
<div class="form-row" id="node-dialog-className">
<label for="node-input-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="[msg.className]">
</div>
<div class="form-row" id="node-dialog-topic">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="[msg.topic]">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips"><b>Note</b>: checking <i>Accept raw HTML/JavaScript</i> can allow injection of code.
Ensure the input comes from trusted sources.</span></div>
</script>
<script type="text/html" data-help-name="ui_toast">
<p>Shows <code>msg.payload</code> as a popup notification or OK / Cancel dialog
message on the user interface.</p>
<p>If a <code>msg.topic</code> is available it will be used as the title.</p>
<p>If you do not set an optional border highlight colour, then it can be set dynamically by <code>msg.highlight</code>.</p>
<p>You may also configure the position and duration of the toast notifications. If you leave the timeout blank
it can be set by <code>msg.timeout</code>. This does not apply to OK/Cancel dialogs.
<p>The dialog returns a <code>msg.payload</code> string of whatever you configure
the button label(s) to be. The second (cancel) button is optional, as is the return
value of <code>msg.topic</code>.</p>
<p>If you select 'OK, Cancel and Input' mode then <code>msg.payload</code> will contain
any text input by the user, rather than the OK button text.</p>
<p>Sending a blank payload will remove any active dialog without sending any data.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent element. This way you can style the card and the elements inside it with custom CSS.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_ui_control] --- -->
<script type="text/javascript">
// convert to i18 text
function c_(x) {
return RED._("node-red-dashboard/ui_ui_control:ui_ui_control."+x);
}
RED.nodes.registerType('ui_ui_control', {
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb( 63, 173, 181)',
defaults: {
name: {value:""},
events: {value:"all"}
},
inputs:1,
outputs:1,
align: "right",
icon: "ui_link.png",
paletteLabel: 'ui control',
label: function() { return this.name || "ui control"; },
labelStyle: function() { return this.name?"node_label_italic":""; },
outputLabels: function() { return this.events; },
});
</script>
<script type="text/html" data-template-name="ui_ui_control">
<div class="form-row">
<label for="node-input-events"><i class="fa fa-sign-out"></i> Output</label>
<select id="node-input-events" style="width:70%;">
<option value="all">Connect, lost, change tab or group events</option>
<option value="change">Change tab or group events only</option>
<option value="connect">Connect event only</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_ui_control.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]ui_ui_control.placeholder.name">
</div>
</script>
<script type="text/html" data-help-name="ui_ui_control">
<p>Ermöglicht die dynamische Steuerung des Dashboards.</p>
<p>Die Standardfunktion besteht darin, den aktuell angezeigten Tab zu ändern.
<code>msg.payload</code> sollte entweder ein Objekt der Form <code>{"tab":"my_tab_name"}</code> sein,
oder einfach der <b>Tab-Name</b> oder ein <b>numerischer Index</b> (ab 0) vom Tab oder Link, der angezeigt werden soll.</p>
<p>Das Senden eines leeren Namens "" aktualisiert die aktuell angezeigte Seite.
Es kann auch "+1" für den nächsten und "-1" für den vorherigen Tab gesendet werden.</p>
<p>Dashboard Seiten (also Tabs) können durch Senden eines <code>msg.payload</code>-Objektes im Format
<pre>{"tabs": {"hide": "tab_name_to_hide", "disable": ["secret_tab", "unused_stuff"]}}</pre> gesteuert werden.
Es sind zwei Zustände verfügbar: <b>show</b>/<b>hide</b> und <b>enable</b>/<b>disable</b></p>
<p>Die Sichtbarkeit von individuellen Widget-Gruppen können durch folgenden Payload gesteuert werden:
<pre>{"group": {"hide": ["tab_name_group_name_with_underscores"], "show": ["reveal_another_group"], "focus": true}}</pre>
<b>focus</b> ist optional und sorgt dafür, dass zu der richtigen Gruppe gescrollt wird.
Es können auch folgende Eigenschafen wie `open` und `close` verwendet werden, um den Status einer Gruppe zu setzen.
Die Gruppennamen sind die IDs der Gruppen und setzen sich aus <i>tab name</i> plus <i>group name</i> zusammen,
zusammengeschrieben mittels Leerzeichen-ersetzender Unterstriche.</p>
<p>Wenn ein Browser die Verbindung aufbaut oder verliert, den Tab wechselt oder eine Gruppe auf- bzw. zuklappt,
sendet dieser Node eine <code>msg</code> mit folgendem Inhalt:</p>
<ul>
<li><code>payload</code> - <i>connect</i>, <i>lost</i>, <i>change</i> oder <i>group</i>
<li><code>socketid</code> - die ID des Sockets (dies ändert sich jedes Mal, wenn der Browser die Seite neu lädt)
<li><code>socketip</code> - die IP-Adresse, von der die Verbindung stammt
<li><code>tab</code> - die Nummer des Tabs (nur für 'change' Ereignisse)
<li><code>name</code> - der Name des Tabs (nur für 'change' Ereignisse)
<li><code>group</code> - der Name der Gruppe (nur für 'group' Ereignisse)
<li><code>open</code> - der Status der Gruppe (nur für 'group' Ereignisse)
</ul>
<p>Optional - Nur neue Verbindungen melden - nützlich, um ein erneutes Senden von Daten an einen neuen Client auszulösen, ohne dass andere Ereignisse herausgefiltert werden müssen.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_template] --- -->
<script type="text/javascript">
// convert to i18 text
function c_(x) {
return RED._("node-red-dashboard/ui_template:ui_template."+x);
}
RED.nodes.registerType('ui_template',{
category: RED._("node-red-dashboard/ui_base:ui_base.label.category"),
color: 'rgb( 63, 173, 181)',
defaults: {
group: {type: 'ui_group', required:false},
name: {value: ''},
order: {value: 0},
width: {value: 0, validate: function(v) {
var valid = true
if (this.templateScope !== 'global') {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
}
return valid;
}},
height: {value: 0},
format: {value: '<div ng-bind-html="msg.payload"></div>'},
storeOutMessages: {value: true},
fwdInMessages: {value: true},
resendOnRefresh: {value: true},
templateScope: {value: 'local'},
className: {value: ''}
},
inputs:1,
outputs:1,
icon: "ui_template.png",
paletteLabel: 'template',
label: function() { return this.name || 'template'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
if (RED.editor.hasOwnProperty("editText") && typeof RED.editor.editText === "function") {
$("#node-template-expand-editor").show();
}
else {
$("#node-template-expand-editor").hide();
}
var that = this;
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
if (typeof this.storeOutMessages === 'undefined') {
this.storeOutMessages = true;
$('#node-input-storeOutMessages').prop('checked', true);
}
if (typeof this.fwdInMessages === 'undefined') {
this.fwdInMessages = true;
$('#node-input-fwdInMessages').prop('checked', true);
}
if (typeof this.templateScope === 'undefined') {
this.templateScope = 'local';
$('#node-input-templateScope').val(this.templateScope);
}
$('#node-input-templateScope').on('change', function() {
if ($('#node-input-templateScope').val() === 'global') {
$('#template-row-group, #template-row-size, #template-pass-store, #template-row-class').hide();
that._def.defaults.group.required = false;
}
else {
$('#template-row-group, #template-row-size, #template-pass-store, #template-row-class').show();
that._def.defaults.group.required = true;
}
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.size(); i++) {
height = height - $(rows[i]).outerHeight(true);
}
if ($('#node-input-templateScope').val() === "global") { height += 240; }
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
if (this.editor) { this.editor.resize(); }
})
this.editor = RED.editor.createEditor({
id: 'node-input-format-editor',
mode: 'ace/mode/html',
value: $("#node-input-format").val()
});
RED.library.create({
url:"uitemplates", // where to get the data from
type:"ui_template", // the type of object the library is for
editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/html",
fields:['name']
});
this.editor.focus();
RED.popover.tooltip($("#node-template-expand-editor"),c_("label.expand"));
$("#node-template-expand-editor").on("click", function(e) {
e.preventDefault();
var value = that.editor.getValue();
RED.editor.editText({
mode: 'html',
value: value,
width: "Infinity",
cursor: that.editor.getCursorPosition(),
complete: function(v,cursor) {
that.editor.setValue(v, -1);
that.editor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() { that.editor.focus(); },300);
}
})
})
},
oneditsave: function() {
var annot = this.editor.getSession().getAnnotations();
this.noerr = 0;
$("#node-input-noerr").val(0);
for (var k=0; k < annot.length; k++) {
if (annot[k].type === "error") {
$("#node-input-noerr").val(annot.length);
this.noerr = annot.length;
}
}
$("#node-input-format").val(this.editor.getValue());
this.editor.destroy();
delete this.editor;
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.size(); i++) {
height = height - $(rows[i]).outerHeight(true);
}
if ($('#node-input-templateScope').val() === "global") { height += 232; }
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
this.editor.resize();
}
});
</script>
<script type="text/html" data-template-name="ui_template">
<div class="form-row">
<label for="node-input-format"><span data-i18n="ui_template.label.type"></span></label>
<select style="width:76%" id="node-input-templateScope">
<option value="local" data-i18n="ui_template.label.local"></option>
<option value="global" data-i18n="ui_template.label.global"></option>
</select>
</div>
<div class="form-row" id="template-row-group">
<label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui_template.label.group"></span></label>
<input type="text" id="node-input-group">
</div>
<div class="form-row" id="template-row-size">
<label><i class="fa fa-object-group"></i> <span data-i18n="ui_template.label.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" id="template-row-class">
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="ui_template.label.className"></label>
<input type="text" id="node-input-className" data-i18n="[placeholder]ui_template.label.classNamePlaceholder"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<div style="display:inline-block; width:calc(100% - 105px)">
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
</div>
<div class="form-row" style="margin-bottom:0px;">
<label for="node-input-format"><i class="fa fa-copy"></i> <span data-i18n="ui_template.label.template"></span></label>
<input type="hidden" id="node-input-format">
<button id="node-template-expand-editor" class="red-ui-button red-ui-button-small" style="float:right"><i class="fa fa-expand"></i></button>
</div>
<div class="form-row node-text-editor-row">
<div style="height:250px; min-height:100px" class="node-text-editor" id="node-input-format-editor" ></div>
</div>
<div id="template-pass-store">
<div class="form-row" style="margin-bottom:0px;">
<input type="checkbox" id="node-input-fwdInMessages" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
<label for="node-input-fwdInMessages" style="width:70%;"> <span data-i18n="ui_template.label.pass-through"></span></label>
</div>
<div class="form-row" style="margin-bottom:0px;">
<input type="checkbox" id="node-input-storeOutMessages" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
<label for="node-input-storeOutMessages" style="width:70%;"> <span data-i18n="ui_template.label.store-state"></span></label>
</div>
<div class="form-row" style="margin-bottom:0px;">
<input type="checkbox" id="node-input-resendOnRefresh" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
<label for="node-input-resendOnRefresh" style="width:70%;"> <span data-i18n="ui_template.label.resend"></span></label>
</div>
</div>
</script>
<script type="text/html" data-help-name="ui_template">
<p>Das template-Widget kann alle gültigen HTML- und Angular/Angular-Material-Anweisungen enthalten.</p>
<p>Dieser Node kann verwendet werden, um ein dynamisches Benutzeroberflächenelement zu erstellen, dessen Erscheinungsbild
basierend auf der Eingangsnachricht geändert wird, und kann Nachrichten an Node-RED zurücksenden.</p>
<p><b>Zum Beispiel:</b><br>
<pre style="font-size:smaller;">
&lt;div layout=&quot;row&quot; layout-align=&quot;space-between&quot;&gt;
&lt;p&gt;The number is&lt;/p&gt;
&lt;font color=&quot;{{((msg.payload || 0) % 2 === 0) ? 'green' : 'red'}}&quot;&gt;
{{(msg.payload || 0) % 2 === 0 ? 'even' : 'odd'}}
&lt;/font&gt;
&lt;/div&gt;</pre>
Wird angezeigt, wenn die als <code>msg.payload</code> empfangene Zahl gerade oder ungerade ist.
Es wird auch die Farbe des Textes zu grün geändert, wenn die Zahl gerade ist, oder rot, wenn ungerade.</p>
<p>Das nächste Beispiel zeigt, wie eine eindeutige ID für Ihre Vorlage erstellt werden kann,
die Standardfarbe fürs Erscheinungsbild ausgewählt wird und wie auf eingehende Nachrichten geprüft werden kann.
<pre style="font-size:smaller;">
&lt;div id="{{'my_'+$id}}" style="{{'color:'+theme.base_color}}"&gt;Some text&lt;/div&gt;
&lt;script&gt;
(function(scope) {
scope.$watch('msg', function(msg) {
if (msg) {
// Do something when msg arrives
$("#my_"+scope.$id).html(msg.payload);
}
});
})(scope);
&lt;/script&gt;</pre>
Auf diese Weise erstellte Vorlagen können kopiert werden und bleiben unabhängig voneinander.</p>
<p><b>Senden einer Nachricht:</b><br>
<pre style="font-size:smaller;">
&lt;script&gt;
var value = "hello world";
// or overwrite value in your callback function ...
this.scope.action = function() { return value; }
&lt;/script&gt;
&lt;md-button ng-click=&quot;send({payload:action()})&quot;&gt;
Click me to send a hello world
&lt;/md-button&gt;</pre>
Zeigt einen Button an, welcher beim Klicken eine Nachricht mit Payload <code>'Hello world'</code> sendet.</p>
<p><b>Verwenden von <code>msg.template</code>:</b><br>
Der Vorlageninhalt kann auch über <code>msg.template</code> definiert werden.
So können beispielsweise externe Dateien verwendet werden.<br>
Die Vorlage wird bei eingehenden Nachrichten neu geladen, wenn sie verändert wurde.<br>
In das Vorlagefeld geschriebener Code wird ignoriert, wenn <code>msg.template</code> vorhanden ist.</p>
<p>Die folgenden Icon-Schriftarten sind verfügbar: <a href=\"https://klarsys.github.io/angular-material-icons/\" target=\"_blank\">Material-Design-Icon</a> (z.B. <code>check</code> oder <code>close</code>), ein <a href=\"https://fontawesome.com/v4.7.0/icons/\" target=\"_blank\">Font-Awesome-Icon</a> (z.B. <code>fa-fire</code>) oder ein <a href=\"https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md\" target=\"_blank\">Wetter-Icon</a> (z.B. <code>wi-wu-sunny</code>) sein.</p><p>Des Weiteren können alle Google-Material-Icons verwendet werden, indem dem Icon-Namen <code>mi-</code> vorangestellt wird (z.B. <code>mi-videogame_asset</code>).</p>
<p>Wenn eine <b>Klasse</b> angegeben ist, wird sie der übergeordneten Karte hinzugefügt. Auf diese Weise können Sie CSS-Stile auf die ui-card und ihre untergeordneten Elemente anwenden. Die Klasse kann zur Laufzeit festgelegt werden, indem eine Zeichenfolgeneigenschaft <code>msg.className</code> festgelegt wird.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_link] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_link',{
category: 'config',
color: 'rgb( 63, 173, 181)',
defaults: {
name: {value: 'Google'},
link: {value: 'https://www.google.com'},
icon: {value: 'open_in_browser'},
target: {value: 'newtab', validate :function() { return true; }},
order: {value: 0},
className: {value: ''}
},
inputs:0,
outputs:0,
hasUsers: false,
align: "right",
icon: "ui_link.png",
paletteLabel: 'link',
label: function() { return this.name || 'link'; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
document.getElementById('node-config-input-target-opentab').checked = (this.target === 'newtab');
document.getElementById('node-config-input-target-openiframe').checked = (this.target === 'iframe');
document.getElementById('node-config-input-target-openthis').checked = (this.target === 'thistab');
},
oneditsave : function () {
var t = 'iframe';
if (document.getElementById('node-config-input-target-opentab').checked) { t = 'newtab'; }
if (document.getElementById('node-config-input-target-openthis').checked) { t = 'thistab'; }
this.target = t;
},
onadd: function() {
//console.log("PING");
}
});
</script>
<script type="text/html" data-template-name="ui_link">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_link.label.name"></span></label>
<input type="text" id="node-config-input-name">
</div>
<div class="form-row">
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="ui_link.label.className"></label>
<input type="text" id="node-input-className" data-i18n="[placeholder]ui_link.label.classNamePlaceholder"/>
</div>
<div class="form-row">
<label for="node-config-input-link"><i class="fa fa-link"></i> <span data-i18n="ui_link.label.link"></span></label>
<input type="text" id="node-config-input-link">
</div>
<div class="form-row">
<label for="node-config-input-icon"><i class="fa fa-image"></i> <span data-i18n="ui_link.label.icon"></span></label>
<input type="text" id="node-config-input-icon">
</div>
<div class="form-row">
<label><i class="fa fa-link"></i> <span data-i18n="ui_link.label.open-in"></span></label>
<input type="radio" id="node-config-input-target-opentab" name="open-link-method" style="width:20px; margin-top:0px; margin-bottom:5px" checked>
<label for="node-config-input-target-opentab" data-i18n="ui_link.label.new-tab"></label><br/>
<input type="radio" id="node-config-input-target-openthis" name="open-link-method" style="width:20px; margin-left:104px; margin-top:0px; margin-bottom:5px">
<label for="node-config-input-target-openthis" data-i18n="ui_link.label.this-tab"></label><br/>
<input type="radio" id="node-config-input-target-openiframe" name="open-link-method" style="width:20px; margin-left:104px; margin-top:0px; margin-bottom:5px">
<label for="node-config-input-target-openiframe" data-i18n="ui_link.label.iframe"></label>
</div>
<div class="form-tips" data-i18n="[html]ui_link.tip"></div>
</script>
<script type="text/html" data-help-name="ui_link">
<p>The <b>Icon</b> can be defined, as either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
<p>The <b>Open in</b> field controls whether the link opens in a <i>New Tab</i>, or if the link is opened within an <i>iframe</i> on the same page. Some sites, including Google, do not allow the rendering of their page inside an iframe. If you select the <i>iframe</i> option and the site does not show, this is simply because that site forbids the use of it inside an iframe.</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_tab] --- -->
<script type="text/javascript">
// convert to i18 text
function c_ui_tab(x) {
return RED._("node-red-dashboard/ui_tab:ui_tab."+x);
}
RED.nodes.registerType('ui_tab',{
category: 'config',
defaults: {
name: {value: c_ui_tab("label.home")},
icon: {value: 'dashboard'},
order: {value: 0},
disabled: {value: false},
hidden: {value: false}
},
paletteLabel: 'dashboard tab',
label: function() { return this.name || c_ui_tab("label.tab"); },
sort: function(A,B) {
return A.order - B.order;
},
oneditprepare: function() {
$("#node-config-input-disabled-btn").on("click", function(e) {
var i = $(this).find("i");
var active = i.hasClass("fa-toggle-on");
var newCls = "fa fa-toggle-" + (active ? "off" : "on");
i.attr("class", newCls);
$("#node-config-input-disabled").prop('checked',active);
var newTxt = c_ui_tab(active ? "label.disabled" : "label.enabled");
$("#node-config-input-disabled-label").text(newTxt);
var info = $("#node-config-input-disabled-info");
var done = active ? info.show() : info.hide();
});
if (this.disabled) {
$("#node-config-input-disabled-btn").click();
}
else {
$("#node-config-input-disabled-label").text(c_ui_tab("label.enabled"));
}
$("#node-config-input-hidden-btn").on("click", function(e) {
var i = $(this).find("i");
var active = i.hasClass("fa-toggle-on");
var newCls = "fa fa-toggle-" + (active ? "off" : "on");
i.attr("class", newCls);
$("#node-config-input-hidden").prop('checked',active);
var newTxt = c_ui_tab(active ? "label.hidden" : "label.visible");
$("#node-config-input-hidden-label").text(newTxt);
var info = $("#node-config-input-hidden-info");
var done = active ? info.show() : info.hide();
});
if (this.hidden) {
$("#node-config-input-hidden-btn").click();
}
else {
$("#node-config-input-hidden-label").text(c_ui_tab("label.visible"));
}
},
oneditsave: function() {
this.disabled = $("#node-config-input-disabled").prop("checked");
this.hidden = $("#node-config-input-hidden").prop("checked");
}
});
</script>
<script type="text/html" data-template-name="ui_tab">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_tab.label.name"></span></label>
<input type="text" id="node-config-input-name">
</div>
<div class="form-row">
<label for="node-config-input-icon"><i class="fa fa-file-image-o"></i> <span data-i18n="ui_tab.label.icon"></span></label>
<input type="text" id="node-config-input-icon">
</div>
<div class="form-row">
<label for="node-config-input-disabled-btn"><i class="fa fa-ban"></i> <span data-i18n="ui_tab.label.state"></span></label>
<button id="node-config-input-disabled-btn" class="editor-button" style="width:100px; margin-right:6px;"><i class="fa fa-toggle-on"></i> <span id="node-config-input-disabled-label"></span></button>
<input type="checkbox" id="node-config-input-disabled" style="display:none;"/>
<span id="node-config-input-disabled-info" data-i18n="[html]ui_tab.info.disabled" style="display:none;"></span>
</div>
<div class="form-row">
<label for="node-config-input-hidden-btn"><i class="fa fa-eye-slash"></i> <span data-i18n="ui_tab.label.navmenu"></span></label>
<button id="node-config-input-hidden-btn" class="editor-button" style="width:100px; margin-right:6px;"><i class="fa fa-toggle-on"></i> <span id="node-config-input-hidden-label"></span></button>
<input type="checkbox" id="node-config-input-hidden" style="display:none;"/>
<span id="node-config-input-hidden-info" data-i18n="[html]ui_tab.info.hidden" style="display:none;"></span>
</div>
<div class="form-tips" data-i18n="[html]ui_tab.tip"></div>
</script>
<script type="text/html" data-help-name="ui_tab">
<p>Tab configuration for Dashboard</p>
<p><b>Disabled</b> pages are not included in the Dashboard app, and are therefore not functional.
The tab name still appears in the Navigation Menu (unless it is also hidden).
</p>
<p><b>Hidden</b> pages are not listed in the Left-hand Navigation Menu.
However, they are still active in the Dashboard, and can be shown by using a `ui_control` msg.
</p>
<p>The <b>Icon</b> field can be either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_group] --- -->
<script type="text/javascript">
// convert to i18 text
function c_ui_group(x) {
return RED._("node-red-dashboard/ui_group:ui_group."+x);
}
RED.nodes.registerType('ui_group',{
category: 'config',
defaults: {
name: {value: c_ui_group("label.default")},
tab: {type:"ui_tab", required: true },
order: {value: 0},
disp: {value: true},
width: {value: 6},
collapse: {value: false},
disabled: {value: false},
hidden: {value: false},
className: {value: ''},
},
sort: function(A,B) {
if (A.tab !== B.tab) {
var tabA = RED.nodes.node(A.tab);
var tabB = RED.nodes.node(B.tab);
if (!tabA && tabB) {
return -1;
}
else if (tabA && !tabB) {
return 1;
}
else {
return tabA.order - tabB.order;
}
}
return A.order - B.order;
},
paletteLabel: 'dashboard group',
label: function() {
var tabNode = RED.nodes.node(this.tab);
if (tabNode) {
return "["+(tabNode.name||c_ui_group("label.tab"))+"] " + (this.name || c_ui_group("label.group"));
}
return "["+c_ui_group("label.unassigned")+"] " + (this.name || c_ui_group("label.group"));
},
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-config-input-width",
auto: false
});
$("#node-config-input-disp").on("change", function() {
if ($("#node-config-input-disp").is(":checked")) {
$("#group-collapse-flag").show();
}
else {
$("#group-collapse-flag").hide();
$("#node-config-input-collapse").prop("checked",false);
}
});
}
});
</script>
<script type="text/html" data-template-name="ui_group">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_group.label.name"></span></label>
<input type="text" id="node-config-input-name">
</div>
<div class="form-row">
<label for="node-config-input-tab"><i class="fa fa-table"></i> <span data-i18n="ui_group.label.tab"></span></label>
<input type="text" id="node-config-input-tab">
</div>
<div class="form-row">
<label for="node-config-input-className"><i class="fa fa-code"></i> <span data-i18n="ui_group.label.className"></label>
<input type="text" id="node-config-input-className" data-i18n="[placeholder]ui_group.label.classNamePlaceholder"/>
</div>
<div class="form-row">
<label for="node-config-input-width"><i class="fa fa-arrows-h"></i> <span data-i18n="ui_group.label.width"></span></label>
<input type="hidden" id="node-config-input-width">
<button class="editor-button" id="node-input-size"></button>
</div>
<div class="form-row">
<input style="margin:8px 0 10px 102px; width:20px;" type="checkbox" checked id="node-config-input-disp"> <label style="width:auto" for="node-config-input-disp"><span data-i18n="ui_group.display-name"></span></label>
</div>
<div class="form-row" id="group-collapse-flag">
<input style="margin:8px 0 10px 102px; width:20px;" type="checkbox" id="node-config-input-collapse"> <label style="width:auto" for="node-config-input-collapse"><span data-i18n="ui_group.collapse-name"></span></label>
</div>
</script>
<script type="text/html" data-help-name="ui_group">
<p>Group</p>
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script>
</div><div><!-- --- [red-module:node-red-dashboard/ui_spacer] --- -->
<script type="text/javascript">
RED.nodes.registerType('ui_spacer', {
category: 'config',
color: '#D4F0F8',
defaults: {
name: {value: "spacer"},
group: {type: 'ui_group', required:true},
order: {value: 0},
width: {value: 0, validate: function(v) {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
var valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
return valid;
}
},
height: {value: 0},
className: {value: ''}
},
z: RED.workspaces.active(),
inputs:0,
outputs:0,
hasUsers: false,
icon: "ui_spacer.png",
paletteLabel: 'spacer',
label: function() { return this.name + " " + this.width + "x" + this.height; },
labelStyle: function() { return this.name?"node_label_italic":""; },
oneditprepare: function() {
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
},
oneditsave: function() {
this.width = $("#node-input-width").val();
this.height = $("#node-input-height").val();
}
});
</script>
<script type="text/html" data-template-name="ui_spacer">
<div class="form-row">
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
<input type="text" id="node-input-group">
</div>
<div class="form-row">
<label><i class="fa fa-object-group"></i> Size</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-className"><i class="fa fa-code"></i> Class</label>
<input type="text" id="node-input-className" placeholder="Optional CSS class name(s) for widget"/>
</div>
</script>
<script type="text/html" data-help-name="ui_spacer">
<p>If a <b>Class</b> is specified, it will be added to the parent card. This way you can style the card and the elements inside it with custom CSS. The Class can be set at runtime by setting a <code>msg.className</code> string property.</p>
</script></div><script type="text/x-red" data-template-name="_js"><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-js"></div></div></script></div><div id="red-ui-full-shade" class="hide"></div><div id="red-ui-notifications"></div><div id="red-ui-drop-target"><div data-i18n="[append]workspace.dropFlowHere"><i class="fa fa-download"></i><br>Hier kann der Flow eingefügt werden</div></div><span class="red-ui-palette-label" style="position: absolute; top: -1000px;">ui control</span><span class="red-ui-flow-node-label" style="position: absolute; top: -1000px;">shelly2Influx</span></div>
<script src="./Node-RED_files/vendor.js"></script>
<script src="./Node-RED_files/monaco-bootstrap.js"></script><script src="./Node-RED_files/editor.js"></script>
<script src="./Node-RED_files/red.min.js"></script>
<script src="./Node-RED_files/main.min.js"></script>
<div tabindex="-1" role="dialog" class="ui-dialog red-ui-editor-dialog ui-widget ui-widget-content ui-front ui-dialog-buttons ui-draggable" aria-describedby="red-ui-library-dialog-save" style="display: none;" aria-labelledby="ui-id-1"><div class="ui-dialog-titlebar ui-corner-all ui-widget-header ui-helper-clearfix ui-draggable-handle"><span id="ui-id-1" class="ui-dialog-title">In Bibliothek speichern ...</span><button type="button" class="ui-button ui-corner-all ui-widget ui-button-icon-only ui-dialog-titlebar-close hide" title="Close"><span class="ui-button-icon ui-icon ui-icon-closethick"></span><span class="ui-button-icon-space"> </span>Close</button></div><div id="red-ui-library-dialog-save" class="hide ui-dialog-content ui-widget-content" style="display: block;"><form class="form-horizontal"><div class="red-ui-library-dialog-box" style="height: 400px; position:relative; "><div id="red-ui-library-dialog-save-browser"><div class="red-ui-library-browser"><div class="red-ui-treeList" tabindex="0" style="width: 100%; height: 100%;"><div class="red-ui-treeList-container"><div class="red-ui-editableList" style="inset: 0px; position: absolute;"><div style="inset: 0px; position: absolute; max-height: none; overflow-y: auto;" class="red-ui-editableList-border red-ui-editableList-container"><ol class="red-ui-treeList-list red-ui-editableList-list" style="position: static; inset: auto; height: auto;"></ol></div></div></div></div></div></div><div class="form-row"><label data-i18n="clipboard.export.exportAs">Exportiere als</label><input id="red-ui-library-dialog-save-filename" type="text"></div></div></form></div><div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"><div class="ui-dialog-buttonset"><button type="button" class="ui-button ui-corner-all ui-widget">Abbrechen</button><button type="button" id="red-ui-library-dialog-save-button" class="primary ui-button ui-corner-all ui-widget">Speichern</button></div></div></div><div tabindex="-1" role="dialog" class="ui-dialog red-ui-editor-dialog ui-widget ui-widget-content ui-front ui-dialog-buttons ui-draggable" aria-describedby="red-ui-library-dialog-load" style="display: none;" aria-labelledby="ui-id-2"><div class="ui-dialog-titlebar ui-corner-all ui-widget-header ui-helper-clearfix ui-draggable-handle"><span id="ui-id-2" class="ui-dialog-title">&nbsp;</span><button type="button" class="ui-button ui-corner-all ui-widget ui-button-icon-only ui-dialog-titlebar-close hide" title="Close"><span class="ui-button-icon ui-icon ui-icon-closethick"></span><span class="ui-button-icon-space"> </span>Close</button></div><div id="red-ui-library-dialog-load" class="hide ui-dialog-content ui-widget-content" style="display: block;"><form class="form-horizontal"><div class="red-ui-library-dialog-box" style="height: 400px; position:relative; "><div id="red-ui-library-dialog-load-panes" class="red-ui-panels red-ui-panels-horizontal"><div class="red-ui-panel" id="red-ui-library-dialog-load-browser"><div class="red-ui-library-browser"><div class="red-ui-treeList" tabindex="0" style="width: 100%; height: 100%;"><div class="red-ui-treeList-container"><div class="red-ui-editableList" style="inset: 0px; position: absolute;"><div style="inset: 0px; position: absolute; max-height: none; overflow-y: auto;" class="red-ui-editableList-border red-ui-editableList-container"><ol class="red-ui-treeList-list red-ui-editableList-list" style="position: static; inset: auto; height: auto;"></ol></div></div></div></div></div></div><div class="red-ui-panels-separator ui-draggable ui-draggable-handle" style="position: relative;"></div><div class="red-ui-panel"><div id="red-ui-library-dialog-load-preview" class="red-ui-panels"><div class="red-ui-panel" id="red-ui-library-dialog-load-preview-text" style="position:relative; height: 50%; overflow-y: hidden;"></div><div class="red-ui-panels-separator ui-draggable ui-draggable-handle" style="position: relative;"></div><div class="red-ui-panel" id="red-ui-library-dialog-load-preview-details"><table id="red-ui-library-dialog-load-preview-details-table" class="re
border: 0 !important;
box-shadow: 0px 0px transparent;
color-scheme: light !important;
right: 0 !important;
padding: 0 !important;
pointer-events: none !important;
position: fixed !important;
opacity: 0 !important;
top: 10px !important;
transition: opacity 0.2s ease !important;
user-select: none !important;
height: 500px !important;
width: 470px !important;
z-index: 9007199254740991 !important;
}
#matter-popup-app[data-matter-active] {
display: block !important;
}
#matter-popup-app[data-matter-hidden] {
visibility: hidden !important;
z-index: -1 !important;
}
#matter-popup-app[data-matter-active="true"] {
pointer-events: auto !important;
opacity: 1 !important;
transition: opacity 0.2s ease !important;
}
@media print {
#matter-popup-app, #matter-floating-iframe, #matter-modal-iframe {
display: none !important;
}
}
#matter-floating-iframe {
border: 0 !important;
box-shadow: 0px 0px transparent;
color-scheme: light !important;
height: 187px !important;
position: absolute !important;
z-index: 9007199254740991 !important;
width: 350px !important;
pointer-events: none !important;
opacity: 0 !important;
visibility: hidden;
}
#matter-floating-iframe[data-matter-active] {
display: block !important;
}
#matter-floating-iframe[data-matter-active="true"] {
pointer-events: auto !important;
opacity: 1 !important;
visibility: visible;
}
#matter-modal-iframe {
border: 0 !important;
display: none !important;
z-index: 9007199254740991 !important;
}
#matter-modal-iframe[data-matter-active="true"] {
display: block !important;
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
}
mark[data-annotation-id][data-open-web-highlight] {
background: #fff8c6 !important;
box-shadow: 0 0.195em 0 0 #fff8c6,0 calc(0.195em * -1) 0 0 #fff8c6 !important;
font-weight: inherit;
font-style: inherit;
}
mark[data-annotation-id][data-open-web-highlight][data-line-height-normal] {
box-shadow: none !important;
}
mark[data-open-web-highlight][data-annotation-has-note] {
text-decoration: underline;
text-decoration-color: #ffd02a;
text-decoration-thickness: 2.5px;
text-decoration-skip-ink: none;
text-underline-offset: 1px;
}
mark[data-open-web-highlight][data-annotation-has-note][data-line-height-normal] {
text-decoration-thickness: 1px;
}</style><iframe id="matter-popup-app" src="./Node-RED_files/index.html" data-matter-active="false" aria-hidden="true" style="display: none;"></iframe><iframe id="matter-floating-iframe" src="./Node-RED_files/popover.html" style="display: none;"></iframe><iframe id="matter-modal-iframe" src="./Node-RED_files/modal.html" style="display: none;"></iframe></html>