@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.
Files changed (44) hide show
  1. package/.gitattributes +2 -0
  2. package/.vscode/launch.json +17 -0
  3. package/README.md +2 -0
  4. package/config/db_access.json +8 -0
  5. package/config/db_config.json +44 -0
  6. package/config/icons/export.gif +0 -0
  7. package/config/icons/folder.gif +0 -0
  8. package/config/icons/htm.gif +0 -0
  9. package/config/icons/jso.gif +0 -0
  10. package/config/icons/lab.gif +0 -0
  11. package/config/icons/refresh.gif +0 -0
  12. package/config/icons/txt.gif +0 -0
  13. package/config/js_hmi_config_create.sql +91 -0
  14. package/config.json +19 -0
  15. package/ext/jquery/ajaxblob.js +80 -0
  16. package/ext/jquery/dataTables.pageResize.min.js +8 -0
  17. package/ext/jquery/dataTables.scrollResize.min.js +8 -0
  18. package/ext/jquery/jquery.layout-latest.js +5126 -0
  19. package/ext/jquery/jquery.transform2d.js +551 -0
  20. package/ext/jquery/jquery.ui.touch-punch.js +160 -0
  21. package/ext/jquery/layout-default-latest.css +228 -0
  22. package/images/arrows/arrow-down.png +0 -0
  23. package/images/arrows/arrow-left-right.png +0 -0
  24. package/images/arrows/arrow-left.png +0 -0
  25. package/images/arrows/arrow-right.png +0 -0
  26. package/images/arrows/arrow-up-down.png +0 -0
  27. package/images/arrows/arrow-up.png +0 -0
  28. package/images/favicon.ico +0 -0
  29. package/images/question/question-balloon.png +0 -0
  30. package/images/question/question-button.png +0 -0
  31. package/images/question/question-frame.png +0 -0
  32. package/images/question/question.png +0 -0
  33. package/main.js +307 -0
  34. package/package.json +21 -0
  35. package/src/BrowserMain.js +132 -0
  36. package/ui/arrow-down.png +0 -0
  37. package/ui/arrow-left-right.png +0 -0
  38. package/ui/arrow-left.png +0 -0
  39. package/ui/arrow-right.png +0 -0
  40. package/ui/arrow-up-down.png +0 -0
  41. package/ui/arrow-up.png +0 -0
  42. package/ui/hmi_styles.css +333 -0
  43. package/ui/scrollbar-desktop.css +117 -0
  44. 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
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
+ }