@markus.hardardt/js_hmi 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -0
- package/.vscode/launch.json +17 -0
- package/README.md +2 -0
- package/config/db_access.json +8 -0
- package/config/db_config.json +44 -0
- package/config/icons/export.gif +0 -0
- package/config/icons/folder.gif +0 -0
- package/config/icons/htm.gif +0 -0
- package/config/icons/jso.gif +0 -0
- package/config/icons/lab.gif +0 -0
- package/config/icons/refresh.gif +0 -0
- package/config/icons/txt.gif +0 -0
- package/config/js_hmi_config_create.sql +91 -0
- package/config.json +19 -0
- package/ext/jquery/ajaxblob.js +80 -0
- package/ext/jquery/dataTables.pageResize.min.js +8 -0
- package/ext/jquery/dataTables.scrollResize.min.js +8 -0
- package/ext/jquery/jquery.layout-latest.js +5126 -0
- package/ext/jquery/jquery.transform2d.js +551 -0
- package/ext/jquery/jquery.ui.touch-punch.js +160 -0
- package/ext/jquery/layout-default-latest.css +228 -0
- package/images/arrows/arrow-down.png +0 -0
- package/images/arrows/arrow-left-right.png +0 -0
- package/images/arrows/arrow-left.png +0 -0
- package/images/arrows/arrow-right.png +0 -0
- package/images/arrows/arrow-up-down.png +0 -0
- package/images/arrows/arrow-up.png +0 -0
- package/images/favicon.ico +0 -0
- package/images/question/question-balloon.png +0 -0
- package/images/question/question-button.png +0 -0
- package/images/question/question-frame.png +0 -0
- package/images/question/question.png +0 -0
- package/main.js +307 -0
- package/package.json +21 -0
- package/src/BrowserMain.js +132 -0
- package/ui/arrow-down.png +0 -0
- package/ui/arrow-left-right.png +0 -0
- package/ui/arrow-left.png +0 -0
- package/ui/arrow-right.png +0 -0
- package/ui/arrow-up-down.png +0 -0
- package/ui/arrow-up.png +0 -0
- package/ui/hmi_styles.css +333 -0
- package/ui/scrollbar-desktop.css +117 -0
- package/ui/scrollbar-touch.css +117 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Default Layout Theme
|
|
3
|
+
*
|
|
4
|
+
* Created for jquery.layout
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2010
|
|
7
|
+
* Fabrizio Balliano (http://www.fabrizioballiano.net)
|
|
8
|
+
* Kevin Dalman (http://allpro.net)
|
|
9
|
+
*
|
|
10
|
+
* Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)
|
|
11
|
+
* and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
|
|
12
|
+
*
|
|
13
|
+
* Last Updated: 2010-02-10
|
|
14
|
+
* NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* DEFAULT FONT
|
|
19
|
+
* Just to make demo-pages look better - not actually relevant to Layout!
|
|
20
|
+
*/
|
|
21
|
+
/*
|
|
22
|
+
body {
|
|
23
|
+
font-family: Geneva, Arial, Helvetica, sans-serif;
|
|
24
|
+
font-size: 100%;
|
|
25
|
+
*font-size: 80%;
|
|
26
|
+
}
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* PANES & CONTENT-DIVs
|
|
31
|
+
*/
|
|
32
|
+
.ui-layout-pane { /* all 'panes' */
|
|
33
|
+
/* background: #FFF; TODO Hm 2014-05-21 */
|
|
34
|
+
border: 1px solid #BBB;
|
|
35
|
+
/* padding: 10px; TODO Hm 2014-05-21 */
|
|
36
|
+
/* overflow: auto; TODO Hm 2014-05-23 */
|
|
37
|
+
overflow: hidden !important;
|
|
38
|
+
|
|
39
|
+
/* DO NOT add scrolling (or padding) to 'panes' that have a content-div,
|
|
40
|
+
otherwise you may get double-scrollbars - on the pane AND on the content-div
|
|
41
|
+
- use ui-layout-wrapper class if pane has a content-div
|
|
42
|
+
- use ui-layout-container if pane has an inner-layout
|
|
43
|
+
*/
|
|
44
|
+
}
|
|
45
|
+
/* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */
|
|
46
|
+
.ui-layout-content {
|
|
47
|
+
/* padding: 10px; TODO Hm 2014-05-21 */
|
|
48
|
+
position: relative; /* contain floated or positioned elements */
|
|
49
|
+
overflow: auto; /* add scrolling to content-div */
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
* UTILITY CLASSES
|
|
54
|
+
* Must come AFTER pane-class above so will override
|
|
55
|
+
* These classes are NOT auto-generated and are NOT used by Layout
|
|
56
|
+
*/
|
|
57
|
+
.layout-child-container,
|
|
58
|
+
.layout-content-container {
|
|
59
|
+
padding: 0;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
}
|
|
62
|
+
.layout-child-container {
|
|
63
|
+
border: 0; /* remove border because inner-layout-panes probably have borders */
|
|
64
|
+
}
|
|
65
|
+
.layout-scroll {
|
|
66
|
+
overflow: auto;
|
|
67
|
+
}
|
|
68
|
+
.layout-hide {
|
|
69
|
+
display: none;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* RESIZER-BARS
|
|
74
|
+
*/
|
|
75
|
+
.ui-layout-resizer { /* all 'resizer-bars' */
|
|
76
|
+
/* background: #DDD; TODO Hm 2014-05-21 */
|
|
77
|
+
border: 1px solid #BBB;
|
|
78
|
+
border-width: 0;
|
|
79
|
+
}
|
|
80
|
+
.ui-layout-resizer-drag { /* REAL resizer while resize in progress */
|
|
81
|
+
}
|
|
82
|
+
.ui-layout-resizer-hover { /* affects both open and closed states */
|
|
83
|
+
}
|
|
84
|
+
/* NOTE: It looks best when 'hover' and 'dragging' are set to the same color,
|
|
85
|
+
otherwise color shifts while dragging when bar can't keep up with mouse */
|
|
86
|
+
.ui-layout-resizer-open-hover , /* hover-color to 'resize' */
|
|
87
|
+
.ui-layout-resizer-dragging { /* resizer beging 'dragging' */
|
|
88
|
+
background: #C4E1A4;
|
|
89
|
+
}
|
|
90
|
+
.ui-layout-resizer-dragging { /* CLONED resizer being dragged */
|
|
91
|
+
border: 1px solid #BBB;
|
|
92
|
+
}
|
|
93
|
+
.ui-layout-resizer-north-dragging,
|
|
94
|
+
.ui-layout-resizer-south-dragging {
|
|
95
|
+
border-width: 1px 0;
|
|
96
|
+
}
|
|
97
|
+
.ui-layout-resizer-west-dragging,
|
|
98
|
+
.ui-layout-resizer-east-dragging {
|
|
99
|
+
border-width: 0 1px;
|
|
100
|
+
}
|
|
101
|
+
/* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */
|
|
102
|
+
.ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */
|
|
103
|
+
background: #E1A4A4; /* red */
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.ui-layout-resizer-closed-hover { /* hover-color to 'slide open' */
|
|
107
|
+
background: #EBD5AA;
|
|
108
|
+
}
|
|
109
|
+
.ui-layout-resizer-sliding { /* resizer when pane is 'slid open' */
|
|
110
|
+
opacity: .10; /* show only a slight shadow */
|
|
111
|
+
filter: alpha(opacity=10);
|
|
112
|
+
}
|
|
113
|
+
.ui-layout-resizer-sliding-hover { /* sliding resizer - hover */
|
|
114
|
+
opacity: 1.00; /* on-hover, show the resizer-bar normally */
|
|
115
|
+
filter: alpha(opacity=100);
|
|
116
|
+
}
|
|
117
|
+
/* sliding resizer - add 'outside-border' to resizer on-hover
|
|
118
|
+
* this sample illustrates how to target specific panes and states */
|
|
119
|
+
.ui-layout-resizer-north-sliding-hover { border-bottom-width: 1px; }
|
|
120
|
+
.ui-layout-resizer-south-sliding-hover { border-top-width: 1px; }
|
|
121
|
+
.ui-layout-resizer-west-sliding-hover { border-right-width: 1px; }
|
|
122
|
+
.ui-layout-resizer-east-sliding-hover { border-left-width: 1px; }
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
* TOGGLER-BUTTONS
|
|
126
|
+
*/
|
|
127
|
+
.ui-layout-toggler {
|
|
128
|
+
border: 1px solid #BBB; /* match pane-border */
|
|
129
|
+
background-color: #BBB;
|
|
130
|
+
}
|
|
131
|
+
.ui-layout-resizer-hover .ui-layout-toggler {
|
|
132
|
+
opacity: .60;
|
|
133
|
+
filter: alpha(opacity=60);
|
|
134
|
+
}
|
|
135
|
+
.ui-layout-toggler-hover , /* need when NOT resizable */
|
|
136
|
+
.ui-layout-resizer-hover .ui-layout-toggler-hover { /* need specificity when IS resizable */
|
|
137
|
+
background-color: #FC6;
|
|
138
|
+
opacity: 1.00;
|
|
139
|
+
filter: alpha(opacity=100);
|
|
140
|
+
}
|
|
141
|
+
.ui-layout-toggler-north ,
|
|
142
|
+
.ui-layout-toggler-south {
|
|
143
|
+
border-width: 0 1px; /* left/right borders */
|
|
144
|
+
}
|
|
145
|
+
.ui-layout-toggler-west ,
|
|
146
|
+
.ui-layout-toggler-east {
|
|
147
|
+
border-width: 1px 0; /* top/bottom borders */
|
|
148
|
+
}
|
|
149
|
+
/* hide the toggler-button when the pane is 'slid open' */
|
|
150
|
+
.ui-layout-resizer-sliding .ui-layout-toggler {
|
|
151
|
+
display: none;
|
|
152
|
+
}
|
|
153
|
+
/*
|
|
154
|
+
* style the text we put INSIDE the togglers
|
|
155
|
+
*/
|
|
156
|
+
.ui-layout-toggler .content {
|
|
157
|
+
color: #666;
|
|
158
|
+
font-size: 12px;
|
|
159
|
+
font-weight: bold;
|
|
160
|
+
width: 100%;
|
|
161
|
+
padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
* PANE-MASKS
|
|
166
|
+
* these styles are hard-coded on mask elems, but are also
|
|
167
|
+
* included here as !important to ensure will overrides any generic styles
|
|
168
|
+
*/
|
|
169
|
+
.ui-layout-mask {
|
|
170
|
+
border: none !important;
|
|
171
|
+
padding: 0 !important;
|
|
172
|
+
margin: 0 !important;
|
|
173
|
+
overflow: hidden !important;
|
|
174
|
+
position: absolute !important;
|
|
175
|
+
opacity: 0 !important;
|
|
176
|
+
filter: Alpha(Opacity="0") !important;
|
|
177
|
+
}
|
|
178
|
+
.ui-layout-mask-inside-pane { /* masks always inside pane EXCEPT when pane is an iframe */
|
|
179
|
+
top: 0 !important;
|
|
180
|
+
left: 0 !important;
|
|
181
|
+
width: 100% !important;
|
|
182
|
+
height: 100% !important;
|
|
183
|
+
}
|
|
184
|
+
div.ui-layout-mask {} /* standard mask for iframes */
|
|
185
|
+
iframe.ui-layout-mask {} /* extra mask for objects/applets */
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* Default printing styles
|
|
189
|
+
*/
|
|
190
|
+
@media print {
|
|
191
|
+
/*
|
|
192
|
+
* Unless you want to print the layout as it appears onscreen,
|
|
193
|
+
* these html/body styles are needed to allow the content to 'flow'
|
|
194
|
+
*/
|
|
195
|
+
html {
|
|
196
|
+
height: auto !important;
|
|
197
|
+
overflow: visible !important;
|
|
198
|
+
}
|
|
199
|
+
body.ui-layout-container {
|
|
200
|
+
position: static !important;
|
|
201
|
+
top: auto !important;
|
|
202
|
+
bottom: auto !important;
|
|
203
|
+
left: auto !important;
|
|
204
|
+
right: auto !important;
|
|
205
|
+
/* only IE6 has container width & height set by Layout */
|
|
206
|
+
_width: auto !important;
|
|
207
|
+
_height: auto !important;
|
|
208
|
+
}
|
|
209
|
+
.ui-layout-resizer, .ui-layout-toggler {
|
|
210
|
+
display: none !important;
|
|
211
|
+
}
|
|
212
|
+
/*
|
|
213
|
+
* Default pane print styles disables positioning, borders and backgrounds.
|
|
214
|
+
* You can modify these styles however it suit your needs.
|
|
215
|
+
*/
|
|
216
|
+
.ui-layout-pane {
|
|
217
|
+
border: none !important;
|
|
218
|
+
background: transparent !important;
|
|
219
|
+
position: relative !important;
|
|
220
|
+
top: auto !important;
|
|
221
|
+
bottom: auto !important;
|
|
222
|
+
left: auto !important;
|
|
223
|
+
right: auto !important;
|
|
224
|
+
width: auto !important;
|
|
225
|
+
height: auto !important;
|
|
226
|
+
overflow: visible !important;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/main.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
"use strict";
|
|
3
|
+
const {
|
|
4
|
+
Client, // direct access: const Client = require('@markus.hardardt/js_utils/src/Client.js');
|
|
5
|
+
Executor, // direct access: const Executor = require('@markus.hardardt/js_utils/src/Executor.js');
|
|
6
|
+
HashLists, // direct access: const HashLists = require('@markus.hardardt/js_utils/src/HashLists.js');
|
|
7
|
+
JsonFX, // direct access: const JsonFX = require('@markus.hardardt/js_utils/src/JsonFX.js');
|
|
8
|
+
Mathematics, // direct access: const Mathematics = require('@markus.hardardt/js_utils/src/Mathematics.js');
|
|
9
|
+
ObjectPositionSystem, // direct access: const ObjectPositionSystem = require('@markus.hardardt/js_utils/src/ObjectPositionSystem.js');
|
|
10
|
+
Regex, // direct access: const Regex = require('@markus.hardardt/js_utils/src/Regex.js');
|
|
11
|
+
Server, // direct access: const Server = require('@markus.hardardt/js_utils/src/Server.js');
|
|
12
|
+
Sorting, // direct access: const Sorting = require('@markus.hardardt/js_utils/src/Sorting.js');
|
|
13
|
+
SqlHelper, // direct access: const SqlHelper = require('@markus.hardardt/js_utils/src/SqlHelper.js');
|
|
14
|
+
Utilities, // direct access: const Utilities = require('@markus.hardardt/js_utils/src/Utilities.js');
|
|
15
|
+
Core, // direct access: const Core = require('@markus.hardardt/js_utils/src/Core.js');
|
|
16
|
+
WebServer, // direct access: const WebServer = require('@markus.hardardt/js_utils/src/WebServer.js');
|
|
17
|
+
ContentManager, // direct access: const ContentManager = require('@markus.hardardt/js_utils/src/ContentManager.js');
|
|
18
|
+
Common, // direct access: const Common = require('@markus.hardardt/js_utils/src/Common.js');
|
|
19
|
+
ObjectLifecycleManager, // direct access: const ObjectLifecycleManager = require('@markus.hardardt/js_utils/src/ObjectLifecycleManager.js');
|
|
20
|
+
DataPoint, // direct access: const DataPoint = require('@markus.hardardt/js_utils/src/DataPoint.js');
|
|
21
|
+
TargetSystem, // direct access: const TargetSystem = require('@markus.hardardt/js_utils/src/TargetSystem.js');
|
|
22
|
+
WebSocketConnection, // direct access: const WebSocketConnection = require('@markus.hardardt/js_utils/src/WebSocketConnection.js');
|
|
23
|
+
DataConnector, // direct access: const DataConnector = require('@markus.hardardt/js_utils/src/DataConnector.js');
|
|
24
|
+
md5, // direct access: const md5 = require('@markus.hardardt/js_utils/ext/md5.js'); // external
|
|
25
|
+
addStaticWebServerJsUtilsFiles
|
|
26
|
+
} = require('@markus.hardardt/js_utils/js_utils.js');
|
|
27
|
+
|
|
28
|
+
// debug
|
|
29
|
+
const s_verbose_sql_queries = !true;
|
|
30
|
+
|
|
31
|
+
// load configurations
|
|
32
|
+
const db_access = require('./config/db_access.json');
|
|
33
|
+
const db_config = require('./config/db_config.json');
|
|
34
|
+
|
|
35
|
+
// Determine config file
|
|
36
|
+
var configFile = './config.json';
|
|
37
|
+
if (process.argv.length > 2 && /\.json$/.test(process.argv[2])) {
|
|
38
|
+
configFile = /^\.\//.test(process.argv[2]) ? process.argv[2] : './' + process.argv[2];
|
|
39
|
+
}
|
|
40
|
+
const config = require(configFile);
|
|
41
|
+
|
|
42
|
+
// create 'hmi' environment object
|
|
43
|
+
const hmi = {}; // TODO: -> "sys"
|
|
44
|
+
// here we add our libraries
|
|
45
|
+
hmi.lib = {};
|
|
46
|
+
// load Mathematics
|
|
47
|
+
hmi.lib.Mathematics = Mathematics;
|
|
48
|
+
hmi.lib.JsonFX = JsonFX;
|
|
49
|
+
hmi.lib.exec = Executor;
|
|
50
|
+
hmi.lib.regex = Regex;
|
|
51
|
+
hmi.lib.sql = SqlHelper;
|
|
52
|
+
// add hmi-object-framweork
|
|
53
|
+
hmi.create = (object, element, onSuccess, onError, initData) => ObjectLifecycleManager.create(object, element, onSuccess, onError, hmi, initData);
|
|
54
|
+
hmi.destroy = ObjectLifecycleManager.destroy;
|
|
55
|
+
hmi.env = {
|
|
56
|
+
isInstance: instance => false, // TODO: Implement isInstance(instance)
|
|
57
|
+
isSimulationEnabled: () => false // TODO: Implement isSimulationEnabled()
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Prepare web server
|
|
61
|
+
const minimized = true;
|
|
62
|
+
const webServer = new WebServer.Server({ secureKeyFile: config.secureKeyFile, secureCertFile: config.secureCertFile });
|
|
63
|
+
webServer.RandomFileIdEnabled = false;
|
|
64
|
+
webServer.SetTitle('js hmi');
|
|
65
|
+
webServer.AddStaticDir('./images', 'images');
|
|
66
|
+
webServer.PrepareFavicon('images/favicon.ico');
|
|
67
|
+
webServer.AddStaticFile('./ui/hmi_styles.css');
|
|
68
|
+
webServer.AddStaticFile('./node_modules/jquery/dist/' + (minimized ? 'jquery.min.js' : 'jquery.js'));
|
|
69
|
+
webServer.AddStaticFile('./node_modules/jquery-ui-dist/' + (minimized ? 'jquery-ui.min.css' : 'jquery-ui.css'));
|
|
70
|
+
webServer.AddStaticFile('./node_modules/jquery-ui-dist/' + (minimized ? 'jquery-ui.min.js' : 'jquery-ui.js'));
|
|
71
|
+
// Note: The next css file references png files by relative paths. Because 'media' is the common root, we must not scramble deeper folders.
|
|
72
|
+
webServer.AddStaticFile('./node_modules/datatables/media', minimized ? 'css/jquery.dataTables.min.css' : 'css/jquery.dataTables.css');
|
|
73
|
+
webServer.AddStaticFile('./node_modules/datatables/media', minimized ? 'js/jquery.dataTables.min.js' : 'js/jquery.dataTables.js');
|
|
74
|
+
// Note: Don't use this extension! Shows paging even if not configured and every second page is empty.
|
|
75
|
+
// webServer.AddStaticFile('./node_modules/datatables.net-scroller/js/dataTables.scroller.js');
|
|
76
|
+
// Note: The next css file references png files by relative paths. Because 'dist' is the common root, we must not scramble deeper folders.
|
|
77
|
+
webServer.AddStaticFile('./node_modules/jquery.fancytree/dist', minimized ? 'skin-lion/ui.fancytree.min.css' : 'skin-lion/ui.fancytree.css');
|
|
78
|
+
webServer.AddStaticFile('./node_modules/jquery.fancytree/dist/' + (minimized ? 'jquery.fancytree-all.min.js' : 'jquery.fancytree-all.js'));
|
|
79
|
+
webServer.AddStaticFile('./ext/jquery/jquery.ui.touch-punch.js');
|
|
80
|
+
webServer.AddStaticFile('./ext/jquery/jquery.transform2d.js');
|
|
81
|
+
webServer.AddStaticFile('./ext/jquery/ajaxblob.js');
|
|
82
|
+
webServer.AddStaticFile('./ext/jquery/layout-default-latest.css');
|
|
83
|
+
webServer.AddStaticFile('./ext/jquery/jquery.layout-latest.js');
|
|
84
|
+
webServer.AddStaticFile('./ext/jquery/dataTables.pageResize.min.js');
|
|
85
|
+
webServer.AddStaticFile('./ext/jquery/dataTables.scrollResize.min.js');
|
|
86
|
+
/*
|
|
87
|
+
webServer.AddStaticFile('./ext/jquery/jquery.transform2d.js');
|
|
88
|
+
webServer.AddStaticFile('./ext/jquery/ajaxblob.js');
|
|
89
|
+
webServer.AddStaticFile('./ext/jquery/layout-default-latest.css');
|
|
90
|
+
webServer.AddStaticFile('./ext/jquery/jquery.layout-latest.js');
|
|
91
|
+
webServer.AddStaticFile('./ext/jquery/dataTables.pageResize.min.js');
|
|
92
|
+
webServer.AddStaticFile('./ext/jquery/dataTables.scrollResize.min.js');
|
|
93
|
+
*/
|
|
94
|
+
// TODO: https://codemirror.net/docs/migration/ --> CodeMirror.fromTextArea
|
|
95
|
+
webServer.AddStaticFile('./node_modules/codemirror/lib/codemirror.css');
|
|
96
|
+
webServer.AddStaticFile('./node_modules/codemirror/lib/codemirror.js');
|
|
97
|
+
webServer.AddStaticFile('./node_modules/codemirror/mode/javascript/javascript.js');
|
|
98
|
+
webServer.AddStaticFile('./node_modules/codemirror/mode/xml/xml.js');
|
|
99
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/edit/matchbrackets.js');
|
|
100
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/edit/closebrackets.js');
|
|
101
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/search/search.js');
|
|
102
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/dialog/dialog.css');
|
|
103
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/dialog/dialog.js');
|
|
104
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/search/searchcursor.js');
|
|
105
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/search/match-highlighter.js');
|
|
106
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/hint/show-hint.css');
|
|
107
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/hint/show-hint.js');
|
|
108
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/hint/javascript-hint.js');
|
|
109
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/scroll/annotatescrollbar.js');
|
|
110
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/search/matchesonscrollbar.js');
|
|
111
|
+
webServer.AddStaticFile('./node_modules/codemirror/addon/search/matchesonscrollbar.css');
|
|
112
|
+
|
|
113
|
+
webServer.AddStaticFile('./node_modules/file-saver/dist/' + (minimized ? 'FileSaver.min.js' : 'FileSaver.js'));
|
|
114
|
+
webServer.AddStaticFile('./node_modules/js-beautify/js/lib/beautify.js');
|
|
115
|
+
webServer.AddStaticFile('./node_modules/js-beautify/js/lib/beautify-html.js');
|
|
116
|
+
webServer.AddStaticFile('./node_modules/js-beautify/js/lib/beautify-css.js');
|
|
117
|
+
addStaticWebServerJsUtilsFiles(webServer);
|
|
118
|
+
// add the final static file: our hmi main loader
|
|
119
|
+
webServer.AddStaticFile('./src/BrowserMain.js');
|
|
120
|
+
// No content - will be generated at runtime inside browser
|
|
121
|
+
webServer.SetBody('');
|
|
122
|
+
|
|
123
|
+
/* let body = ''; // TODO Handle CodeMirror v5 -> v6 issues
|
|
124
|
+
body += '<script type="module">\n';
|
|
125
|
+
body += 'import { attachBrowserFeatures } from "./src/Client.js";\n';
|
|
126
|
+
body += 'import "./src/ObjectLifecycleManager.js";\n';
|
|
127
|
+
body += 'attachBrowserFeatures(window.ObjectLifecycleManager);\n';
|
|
128
|
+
//body += 'const olm = new ObjectLifecycleManager();\n';
|
|
129
|
+
body += '</script>\n';
|
|
130
|
+
webServer.SetBody(body); */
|
|
131
|
+
// deliver main config to client
|
|
132
|
+
webServer.Post('/get_client_config', (request, response) => response.send(JSON.stringify({
|
|
133
|
+
requestAnimationFrameCycle: config.clientRequestAnimationFrameCycle
|
|
134
|
+
})));
|
|
135
|
+
|
|
136
|
+
// prepare content management system
|
|
137
|
+
// we need the handler for database access
|
|
138
|
+
// TODO: reuse or remove const sqlHelper = new SqlHelper.Connector(db_access, s_verbose_sql_queries);
|
|
139
|
+
const sqlAdapterFactory = SqlHelper.getAdapterFactory(db_access, s_verbose_sql_queries);
|
|
140
|
+
// we directly replace our icon directory to make sure on server and client
|
|
141
|
+
// (with debug proxy too) our icons will be available
|
|
142
|
+
db_config.icon_dir = '/' + webServer.AddStaticDir(db_config.icon_dir) + '/';
|
|
143
|
+
db_config.jsonfx_pretty = config.jsonfx_pretty === true;
|
|
144
|
+
// TODO: reuse or remove hmi.cms = new ContentManager(sqlHelper.createAdapter, db_config);
|
|
145
|
+
hmi.cms = new ContentManager.Instance(sqlAdapterFactory, db_config);
|
|
146
|
+
// we need access via ajax from clients
|
|
147
|
+
webServer.Post(ContentManager.GET_CONTENT_DATA_URL, (request, response) => {
|
|
148
|
+
hmi.cms.HandleRequest(request.body,
|
|
149
|
+
result => response.send(JSON.stringify(result)),
|
|
150
|
+
error => response.send(JSON.stringify(error.toString()))
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
// the tree control requests da via 'GET' so we handle those request
|
|
154
|
+
// separately
|
|
155
|
+
webServer.Get(ContentManager.GET_CONTENT_TREE_NODES_URL, (request, response) => {
|
|
156
|
+
hmi.cms.HandleFancyTreeRequest(request.query.request, request.query.path,
|
|
157
|
+
result => response.send(JSON.stringify(result)),
|
|
158
|
+
error => response.send(JSON.stringify(error.toString()))
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
function addStaticFiles(file) {
|
|
162
|
+
if (Array.isArray(file)) {
|
|
163
|
+
for (var i = 0, l = file.length; i < l; i++) {
|
|
164
|
+
addStaticFiles(file[i]);
|
|
165
|
+
}
|
|
166
|
+
} else if (typeof file === 'string' && file.length > 0) {
|
|
167
|
+
webServer.AddStaticFile(file);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
addStaticFiles(config.staticClientFiles);
|
|
171
|
+
webServer.AddStaticFile(config.touch ? config.scrollbar_hmi : config.scrollbar_config);
|
|
172
|
+
|
|
173
|
+
// debug stuff start
|
|
174
|
+
const DataIds = Object.freeze({ b: 'test:b', i: 'test:i', f: 'test:f', t: 'test:t' });
|
|
175
|
+
const test_subscriptions = {};
|
|
176
|
+
test_subscriptions[DataIds.b] = { value: false, onRefresh: null };
|
|
177
|
+
test_subscriptions[DataIds.i] = { value: 0, onRefresh: null };
|
|
178
|
+
test_subscriptions[DataIds.f] = { value: 1.618, onRefresh: null };
|
|
179
|
+
test_subscriptions[DataIds.t] = { value: 'hello world', onRefresh: null };
|
|
180
|
+
const test_dataPoints = {
|
|
181
|
+
onOperationalStateChanged: null,
|
|
182
|
+
IsOperational: true,
|
|
183
|
+
SubscribeOperationalState: onOperationalStateChanged => {
|
|
184
|
+
test_dataPoints.onOperationalStateChanged = onOperationalStateChanged;
|
|
185
|
+
onOperationalStateChanged(true);
|
|
186
|
+
},
|
|
187
|
+
UnsubscribeOperationalState: onOperationalStateChanged => test_dataPoints.onOperationalStateChanged = null,
|
|
188
|
+
GetType: dataId => { },
|
|
189
|
+
SubscribeData: (dataId, onRefresh) => {
|
|
190
|
+
test_subscriptions[dataId].onRefresh = onRefresh;
|
|
191
|
+
onRefresh(test_subscriptions[dataId].value);
|
|
192
|
+
},
|
|
193
|
+
UnsubscribeData: (dataId, onRefresh) => test_subscriptions[dataId].onRefresh = null,
|
|
194
|
+
Read: (dataId, onResponse, onError) => test_subscriptions[dataId].value,
|
|
195
|
+
Write: (dataId, value) => setTestValue(dataId, value)
|
|
196
|
+
};
|
|
197
|
+
function setTestValue(dataId, value) {
|
|
198
|
+
test_subscriptions[dataId].value = value;
|
|
199
|
+
if (test_subscriptions[dataId].onRefresh) {
|
|
200
|
+
test_subscriptions[dataId].onRefresh(value);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
setInterval(() => {
|
|
204
|
+
setTestValue(DataIds.b, Math.random() >= 0.5);
|
|
205
|
+
setTestValue(DataIds.i, test_subscriptions[DataIds.i].value + 1);
|
|
206
|
+
setTestValue(DataIds.f, Math.random());
|
|
207
|
+
setTestValue(DataIds.t, `Hello world! ${Math.random()}`);
|
|
208
|
+
}, 500);
|
|
209
|
+
const test_dataPointsCollection = new DataPoint.Collection();
|
|
210
|
+
test_dataPointsCollection.Parent = test_dataPoints;
|
|
211
|
+
setTimeout(() => { // TODO: Renove when tested and running
|
|
212
|
+
test_dataPointsCollection.Parent = null;
|
|
213
|
+
test_dataPointsCollection.Parent = test_dataPoints;
|
|
214
|
+
}, 5000)
|
|
215
|
+
// debug stuff end
|
|
216
|
+
|
|
217
|
+
const router = new DataPoint.Router();
|
|
218
|
+
router.GetDataAccessObject = dataId => {
|
|
219
|
+
const match = /^([a-z0-9_]+):.+$/i.exec(dataId);
|
|
220
|
+
if (!match) {
|
|
221
|
+
throw new Error(`Invalid id: '${dataId}'`);
|
|
222
|
+
} else {
|
|
223
|
+
switch (match[1]) {
|
|
224
|
+
case 'test':
|
|
225
|
+
return test_dataPointsCollection; // test_dataPoints;
|
|
226
|
+
default:
|
|
227
|
+
throw new Error(`Invalid prefix '${match[1]}' id: '${dataId}'`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
router.IsOperational = true; // TODO: Handle this (but when and how?)
|
|
232
|
+
hmi.env.data = router;
|
|
233
|
+
|
|
234
|
+
const dataConnectors = {};
|
|
235
|
+
|
|
236
|
+
const tasks = [];
|
|
237
|
+
|
|
238
|
+
// Prepare web socket server
|
|
239
|
+
let webSocketServer = undefined;
|
|
240
|
+
webServer.Post('/get_web_socket_session_config',
|
|
241
|
+
(request, response) => response.send(JSON.stringify(webSocketServer.CreateSessionConfig()))
|
|
242
|
+
);
|
|
243
|
+
tasks.push((onSuccess, onError) => {
|
|
244
|
+
try {
|
|
245
|
+
webSocketServer = new WebSocketConnection.Server(config.webSocketPort, {
|
|
246
|
+
secure: webServer.IsSecure,
|
|
247
|
+
autoConnect: config.autoConnect,
|
|
248
|
+
closedConnectionDisposeTimeout: config.closedConnectionDisposeTimeout,
|
|
249
|
+
OnOpen: connection => {
|
|
250
|
+
console.log(`web socket client opened (sessionId: '${WebSocketConnection.formatSesionId(connection.SessionId)}')`);
|
|
251
|
+
const dataConnector = new DataConnector.ServerConnector();
|
|
252
|
+
dataConnector.Parent = router;
|
|
253
|
+
dataConnector.Connection = connection;
|
|
254
|
+
dataConnector.SendDelay = config.sendDelay;
|
|
255
|
+
dataConnector.SubscribeDelay = config.subscribeDelay;
|
|
256
|
+
dataConnector.UnsubscribeDelay = config.unsubscribeDelay;
|
|
257
|
+
dataConnector.SetDataPoints([
|
|
258
|
+
{ id: DataIds.b, type: Core.DataType.Boolean },
|
|
259
|
+
{ id: DataIds.i, type: Core.DataType.Int64 },
|
|
260
|
+
{ id: DataIds.f, type: Core.DataType.Double },
|
|
261
|
+
{ id: DataIds.t, type: Core.DataType.String }
|
|
262
|
+
]);
|
|
263
|
+
dataConnectors[connection.SessionId] = dataConnector;
|
|
264
|
+
dataConnector.OnOpen();
|
|
265
|
+
},
|
|
266
|
+
OnReopen: connection => {
|
|
267
|
+
console.log(`web socket client reopened (sessionId: '${WebSocketConnection.formatSesionId(connection.SessionId)}')`);
|
|
268
|
+
const dataConnector = dataConnectors[connection.SessionId];
|
|
269
|
+
dataConnector.OnReopen();
|
|
270
|
+
},
|
|
271
|
+
OnClose: connection => {
|
|
272
|
+
console.log(`web socket client closed (sessionId: '${WebSocketConnection.formatSesionId(connection.SessionId)}')`);
|
|
273
|
+
const dataConnector = dataConnectors[connection.SessionId];
|
|
274
|
+
dataConnector.OnClose();
|
|
275
|
+
},
|
|
276
|
+
OnDispose: connection => {
|
|
277
|
+
console.log(`web socket client disposed (sessionId: '${WebSocketConnection.formatSesionId(connection.SessionId)}')`);
|
|
278
|
+
const dataConnector = dataConnectors[connection.SessionId];
|
|
279
|
+
dataConnector.OnDispose();
|
|
280
|
+
delete dataConnectors[connection.SessionId];
|
|
281
|
+
dataConnector.Connection = null;
|
|
282
|
+
dataConnector.Parent = null;
|
|
283
|
+
},
|
|
284
|
+
OnError: (connection, error) => {
|
|
285
|
+
console.error(`error in connection (sessionId: '${WebSocketConnection.formatSesionId(connection.SessionId)}') to server: ${error}`);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
onSuccess();
|
|
289
|
+
} catch (error) {
|
|
290
|
+
onError(error);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
tasks.push((onSuccess, onError) => {
|
|
295
|
+
Server.startRefreshCycle(config.serverCycleMillis, () => ObjectLifecycleManager.refresh(new Date()));
|
|
296
|
+
onSuccess();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
tasks.push((onSuccess, onError) => {
|
|
300
|
+
webServer.Listen(config.webServerPort, () => {
|
|
301
|
+
console.log(`js hmi web server listening on port: ${config.webServerPort}`);
|
|
302
|
+
onSuccess();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
Executor.run(tasks, () => Object.seal(hmi), error => console.error(error));
|
|
307
|
+
}());
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@markus.hardardt/js_hmi",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "main.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"codemirror": "^5.52.2",
|
|
14
|
+
"datatables": "^1.10.18",
|
|
15
|
+
"file-saver": "^2.0.5",
|
|
16
|
+
"jquery": "^3.7.1",
|
|
17
|
+
"jquery-ui-dist": "^1.13.3",
|
|
18
|
+
"jquery.fancytree": "^2.38.5",
|
|
19
|
+
"js-beautify": "^1.15.4"
|
|
20
|
+
}
|
|
21
|
+
}
|