guindilla_gui 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,614 @@
1
+ #------------------------------------------------------------------------------#
2
+ # Copyleft 2022
3
+ # This file is part of GuindillaGUI.
4
+ # GuindillaGUI is free software: you can redistribute it and/or modify it under
5
+ # the terms of the GNU General Public License as published by the Free Software
6
+ # Foundation, either version 3 of the License, or (at your option) any later
7
+ # version.
8
+ # GuindillaGUI is distributed in the hope that it will be useful, but WITHOUT
9
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11
+ # You should have received a copy of the GNU General Public License along with
12
+ # GuindillaGUI. If not, see <https://www.gnu.org/licenses/>.
13
+ #------------------------------------------------------------------------------#
14
+
15
+ module GuindillaGUI
16
+ class Guindilla
17
+ ##
18
+ # JavaScript `setTimeout` Timer
19
+ def after(seconds, &block)
20
+ Timer.new("timeout", seconds, &block)
21
+ end
22
+
23
+ def alert(message)
24
+ send_js(%Q~ alert("#{message}") ~)
25
+ end
26
+
27
+ def append(element)
28
+ id = caller_id(self)
29
+ send_js(%Q~ $("##{self.id}").append($("##{element.id}")); ~)
30
+ end
31
+
32
+ ##
33
+ # attributes may include `controls: true`
34
+ def audio_out(attributes={})
35
+ AudioVideo.new("audio", attributes)
36
+ end
37
+
38
+ def bullet_list(list_array, attributes={})
39
+ ul = Element.new("ul")
40
+ list_array.each do |li|
41
+ send_js(%Q~ $("##{ul.id}").append($("<li>").html("#{li}")); ~)
42
+ end
43
+ return ul
44
+ end
45
+
46
+ ##
47
+ # `button(text="", attributes={}, &block)`
48
+ def button(*args, &block)
49
+ args.unshift("") unless args[0].is_a?(String)
50
+ txt = args[0]
51
+ args[1] ? attributes = args[1] : attributes = {}
52
+ btn = Element.new("button", attributes)
53
+ send_js(%Q~ #{btn.id}.innerHTML = "#{txt}"; ~)
54
+ send_js(%Q~
55
+ #{btn.id}.onclick = function(event){
56
+ socket.send("#{btn.id}:!!:");
57
+ event.stopPropagation();
58
+ };
59
+ ~)
60
+ @@gui.blocks[:"#{btn.id}"] = block if block_given?
61
+ return btn
62
+ end
63
+
64
+ def canvas(attributes={}, &block)
65
+ attributes[:width] = "50%" unless attributes[:width]
66
+ attributes[:height] = "33%" unless attributes[:height]
67
+ Canvas.new(attributes, &block)
68
+ end
69
+
70
+ ##
71
+ # `chart(type: 'scatter', title: "", attributes={}, &block)`
72
+ def chart(attributes={}, &block)
73
+ # OPTIMIZE: use Hash#merge!
74
+ Chart.new(attributes, &block)
75
+ end
76
+
77
+ ##
78
+ # `checkbox(label="", attributes={}, &block |boolean|)`
79
+ def checkbox(*args, &block)
80
+ args.unshift("") unless args[0].is_a?(String)
81
+ label = args[0]
82
+ args[1] ? attributes = args[1] : attributes = {}
83
+ Input.new("checkbox", label, attributes, &block)
84
+ end
85
+
86
+ def circle(radius, attributes={})
87
+ attributes[:cx] = radius
88
+ attributes[:cy] = radius
89
+ attributes[:r] = radius
90
+ Svg.new("circle", attributes)
91
+ end
92
+
93
+ ##
94
+ # `color_input(label="", attributes={}, &block |color|)`
95
+ def color_input(*args, &block)
96
+ args.unshift("") unless args[0].is_a?(String)
97
+ label = args[0]
98
+ args[1] ? attributes = args[1] : attributes = {}
99
+ Input.new("color", label, attributes, &block)
100
+ end
101
+
102
+ def container(attributes={}, &block)
103
+ Box.new(nil, attributes, &block)
104
+ end
105
+
106
+ ##
107
+ # JavaScript `setInterval` Timer
108
+ def every(seconds, &block)
109
+ Timer.new("interval", seconds, &block)
110
+ end
111
+
112
+ ##
113
+ # `file_input(label="", attributes={}, &block |file|)`
114
+ def file_input(*args, &block)
115
+ args.unshift("") unless args[0].is_a?(String)
116
+ label = args[0]
117
+ args[1] ? attributes = args[1] : attributes = {}
118
+ Input.new("file", label, attributes, &block)
119
+ end
120
+
121
+ def h_box(attributes={}, &block)
122
+ Box.new("row", attributes, &block)
123
+ end
124
+
125
+ def h_rule(attributes={})
126
+ attributes[:width] = "100%" unless attributes[:width]
127
+ Element.new("hr", attributes)
128
+ end
129
+
130
+ ##
131
+ # `heading(level=1, string, attributes={})`
132
+ def heading(*args)
133
+ args.unshift(1) unless args[0].is_a?(Integer)
134
+ level = args[0]
135
+ string = args[1]
136
+ args[2] ? attributes = args[2] : attributes = {}
137
+ h = Element.new("#{'h' + level.to_s}", attributes)
138
+ send_js(%Q~ #{h.id}.innerHTML = "#{string}"; ~)
139
+ return h
140
+ end
141
+
142
+ def hide
143
+ id = caller_id(self)
144
+ send_js(%Q~ $("##{id}").hide(); ~)
145
+ end
146
+
147
+ def image(source, attributes={})
148
+ img = Element.new("img", attributes)
149
+ send_js(%Q~ #{img.id}.src = "#{source}"; ~)
150
+ send_js(%Q~ #{img.id}.onerror = function(){
151
+ #{img.id}.src = "resources/guindilla_gui.png"
152
+ };
153
+ ~)
154
+ return img
155
+ end
156
+
157
+ def line_break
158
+ para("")
159
+ end
160
+
161
+ def link(url, attributes={})
162
+ lnk = Element.new("a", attributes)
163
+ if self.is_a?(GuindillaGUI::Element)
164
+ lnk.append(self)
165
+ else
166
+ attributes[:text] ? txt = attributes[:text] : txt = url
167
+ send_js(%Q~ #{lnk.id}.textContent = "#{txt}"; ~)
168
+ end
169
+ send_js(%Q~ #{lnk.id}.href = "#{url}"; ~)
170
+ send_js(%Q~ #{lnk.id}.target = "_blank"; ~)
171
+ return lnk
172
+ end
173
+
174
+ ##
175
+ # `number_input(label="", attributes={}, &block |input|)`
176
+ def number_input(*args, &block)
177
+ args.unshift("") unless args[0].is_a?(String)
178
+ label = args[0]
179
+ args[1] ? attributes = args[1] : attributes = {}
180
+ Input.new("number", label, attributes, &block)
181
+ end
182
+
183
+ def on_click(&block)
184
+ id = caller_id(self)
185
+ send_js(%Q~
186
+ #{id}.onclick = function(event){
187
+ socket.send("#{id}_click:!!:");
188
+ event.stopPropagation();
189
+ };
190
+ ~)
191
+ @@gui.blocks[:"#{id}_click"] = block if block_given?
192
+ return @@gui.elements[:"#{id}"]
193
+ end
194
+
195
+ def on_hover(&block)
196
+ id = caller_id(self)
197
+ send_js(%Q~
198
+ #{id}.onmouseover = function(event){
199
+ socket.send("#{id}_hover:!!:");
200
+ event.stopPropagation();
201
+ };
202
+ ~)
203
+ @@gui.blocks[:"#{id}_hover"] = block if block_given?
204
+ return @@gui.elements[:"#{id}"]
205
+ end
206
+
207
+ def on_leave(&block)
208
+ id = caller_id(self)
209
+ send_js(%Q~
210
+ #{id}.onmouseout = function(event){
211
+ socket.send("#{id}_leave:!!:");
212
+ event.stopPropagation();
213
+ };
214
+ ~)
215
+ @@gui.blocks[:"#{id}_leave"] = block if block_given?
216
+ return @@gui.elements[:"#{id}"]
217
+ end
218
+
219
+ def on_mouse_move(&block)
220
+ id = caller_id(self)
221
+ send_js(%Q~
222
+ #{id}.onmousemove = function(event){
223
+ socket.send("#{id}:!!:mousemove:!!:" + event.pageX + ',' + event.pageY);
224
+ event.stopPropagation();
225
+ };
226
+ ~)
227
+ @@gui.blocks[:"#{id}_move"] = block if block_given?
228
+ return @@gui.elements[:"#{id}"]
229
+ end
230
+
231
+ def ordered_list(list_array, attributes={})
232
+ ol = Element.new("ol")
233
+ list_array.each do |li|
234
+ send_js(%Q~ $("##{ol.id}").append($("<li>").html("#{li}")); ~)
235
+ end
236
+ return ol
237
+ end
238
+
239
+ def para(string, attributes={})
240
+ p = Element.new("p", attributes)
241
+ send_js(%Q~ #{p.id}.innerHTML = "#{string}"; ~)
242
+ return p
243
+ end
244
+
245
+ ##
246
+ # `polygon` takes a nested array of x, y coordinates, e.g.:
247
+ # `polygon([[2, 0], [0, 3], [3, 3], [2, 0]])`
248
+ def polygon(points_array, attributes={})
249
+ points = ""
250
+ points_array.each do |arr|
251
+ points += arr.join(",")
252
+ points += " "
253
+ end
254
+ attributes[:points] = points
255
+ width = 0
256
+ height = 0
257
+ points.split(" ").each do |xy|
258
+ pair = xy.split(",")
259
+ width = pair[0].to_i if pair[0].to_i > width
260
+ height = pair[1].to_i if pair[1].to_i > height
261
+ end
262
+ attributes[:width] = width unless attributes[:width]
263
+ attributes[:height] = height unless attributes[:height]
264
+ Svg.new("polygon", attributes)
265
+ end
266
+
267
+ ##
268
+ # `radio_button(label="", attributes={}, &block |boolean|)`
269
+ # attributes may include a +group:+ key to group buttons
270
+ def radio_button(*args, &block)
271
+ args.unshift("") unless args[0].is_a?(String)
272
+ label = args[0]
273
+ args[1] ? attributes = args[1] : attributes = {}
274
+ attributes[:group] = "no_group" unless attributes[:group]
275
+ Input.new("radio", label, attributes, &block)
276
+ end
277
+
278
+ ##
279
+ # `range_slider(label="", {min: 0, max: 1.0, step: 0.05, value: 0.5}, &block |value|)`
280
+ def range_slider(*args, &block)
281
+ args.unshift("") unless args[0].is_a?(String)
282
+ label = args[0]
283
+ args[1] ? attributes = args[1] : attributes = {}
284
+ attributes[:min] = 0 unless attributes[:min]
285
+ attributes[:max] = 1.0 unless attributes[:max]
286
+ attributes[:step] = 0.05 unless attributes[:step]
287
+ attributes[:value] = (attributes[:max] - attributes[:min]) / 2 unless attributes[:value]
288
+ Input.new("range", label, attributes, &block)
289
+ end
290
+
291
+ def rectangle(width_integer, height_integer, attributes={})
292
+ attributes[:width] = width_integer
293
+ attributes[:height] = height_integer
294
+ Svg.new("rect", attributes)
295
+ end
296
+
297
+ def show
298
+ id = caller_id(self)
299
+ send_js(%Q~ $("##{id}").show(); ~)
300
+ end
301
+
302
+ def source(path_string)
303
+ id = caller_id(self)
304
+ send_js(%Q~ #{id}.src = "#{path_string}"; ~)
305
+ end
306
+ alias_method :source=, :source
307
+
308
+ def square(size_integer, attributes={})
309
+ rectangle(size_integer, size_integer, attributes)
310
+ end
311
+
312
+ def sub_script(string, attributes={})
313
+ ## FIXME: displays superscript, huh???
314
+ sub = Element.new("p", attributes)
315
+ send_js(%Q~ #{sub.id}.innerHTML = "#{string}"; ~)
316
+ sub.style(vertical_align: "sub", font_size: "small")
317
+ return sub
318
+ end
319
+
320
+ def sup_script(string, attributes={})
321
+ sup = Element.new("p", attributes)
322
+ send_js(%Q~ #{sup.id}.innerHTML = "#{string}"; ~)
323
+ sup.style(vertical_align: "super", font_size: "small")
324
+ return sup
325
+ end
326
+
327
+ ##
328
+ # set element text
329
+ def text(string)
330
+ id = caller_id(self)
331
+ send_js(%Q~ #{id}.innerHTML = "#{string}"; ~)
332
+ end
333
+ alias_method :text=, :text
334
+
335
+ ##
336
+ # `text_input(label="", attributes={}, &block |input|)`
337
+ def text_input(*args, &block)
338
+ args.unshift("") unless args[0].is_a?(String)
339
+ label = args[0]
340
+ args[1] ? attributes = args[1] : attributes = {}
341
+ Input.new("text", label, attributes, &block)
342
+ end
343
+
344
+ ##
345
+ # show/hide element
346
+ def toggle
347
+ id = caller_id(self)
348
+ send_js(%Q~ $("##{id}").toggle(); ~)
349
+ end
350
+
351
+ def triangle(size_integer, attributes={})
352
+ polygon(
353
+ [
354
+ [0, size_integer * 0.866],
355
+ [size_integer / 2, 0],
356
+ [size_integer, size_integer * 0.866]
357
+ ],
358
+ attributes
359
+ )
360
+ end
361
+
362
+ ##
363
+ # `url_input(label="", attributes={}, &block |input|)`
364
+ def url_input(*args, &block)
365
+ args.unshift("") unless args[0].is_a?(String)
366
+ label = args[0]
367
+ args[1] ? attributes = args[1] : attributes = {}
368
+ Input.new("url", label, attributes, &block)
369
+ end
370
+
371
+ def v_box(attributes={}, &block)
372
+ Box.new("column", attributes, &block)
373
+ end
374
+
375
+ ##
376
+ # attributes may include `controls: true`
377
+ def video_out(attributes={})
378
+ attributes[:width] = 500 unless attributes[:width]
379
+ attributes[:height] = 300 unless attributes[:height]
380
+ AudioVideo.new("video", attributes)
381
+ end
382
+
383
+ def web_frame(attributes={})
384
+ attributes[:height] = "500px" unless attributes[:height]
385
+ Element.new("iframe", attributes)
386
+ end
387
+
388
+
389
+ ##############################################################################
390
+ #----------------------------------------------------------------------------#
391
+ # style methods #
392
+ #----------------------------------------------------------------------------#
393
+ ##############################################################################
394
+ ##
395
+ # CSS properties key/value pairs with underscores `_` rather than dashes `-`
396
+ # e.g. `style(color: 'blue', text_align: 'center')`
397
+ ##
398
+
399
+ def style(hash)
400
+ id = caller_id(self)
401
+ hash.each do |key, value|
402
+ send_js(%Q~
403
+ $("##{id}").css("#{key.to_s.gsub("_","-")}", "#{value}");
404
+ ~)
405
+ @@gui.elements[:"#{id}"].attributes[:"#{key}"] = "#{value}"
406
+ end
407
+ return self
408
+ end
409
+ alias_method :style=, :style
410
+
411
+ ##
412
+ # Vertical alignment within a box.
413
+ # Position may be `'stretch'`(default), `'center'`, `'start'`, `'end'`, or `'baseline'`.
414
+ # See 'align-items': https://css-tricks.com/snippets/css/a-guide-to-flexbox/
415
+ def align(position) # vertical
416
+ position = "flex-start" if position == "start"
417
+ position = "flex-end" if position == "end"
418
+ self.style(align_items: "#{position}")
419
+ return self
420
+ end
421
+ alias_method :align=, :align
422
+
423
+ ##
424
+ # `color_string` may be rgb, rgba, hex, or CSS color
425
+ def background(color_string)
426
+ self.style(background: "#{color_string}")
427
+ return self
428
+ end
429
+ alias_method :background=, :background
430
+
431
+ ##
432
+ # https://www.w3schools.com/css/css_border.asp
433
+ # e.g. `border('2px solid blue')`
434
+ def border(border_string)
435
+ self.style(border: "#{border_string}")
436
+ return self
437
+ end
438
+ alias_method :border=, :border
439
+
440
+ ##
441
+ # `color_string` may be rgb, rgba, hex, or CSS color
442
+ def border_color(color_string)
443
+ if self.class.to_s == "GuindillaGUI::Svg"
444
+ self.style(stroke: "#{color_string}")
445
+ else
446
+ self.style(border_color: "#{color_string}")
447
+ end
448
+ return self
449
+ end
450
+ alias_method :border_color=, :border_color
451
+
452
+ ##
453
+ # https://www.w3schools.com/cssref/css3_pr_border-radius.asp
454
+ def border_radius(pixels)
455
+ self.style(border_radius: "#{pixels}")
456
+ return self
457
+ end
458
+ alias_method :border_radius=, :border_radius
459
+
460
+ def border_width(width)
461
+ self.style(border_width: "#{width_integer}")
462
+ return self
463
+
464
+ end
465
+ alias_method :border_width=, :border_width
466
+
467
+ ##
468
+ # `color_string` may be rgb, rgba, hex, or CSS color
469
+ def color(color_string)
470
+ if self.class.to_s == "GuindillaGUI::Svg"
471
+ self.style(fill: "#{color_string}")
472
+ else
473
+ self.style(color: "#{color_string}")
474
+ end
475
+ return self
476
+ end
477
+ alias_method :color=, :color
478
+
479
+ ##
480
+ # CSS display property.
481
+ # https://www.w3schools.com/CSSref/pr_class_display.asp
482
+ def display(property)
483
+ self.style(display: "#{property}")
484
+ return self
485
+ end
486
+ alias_method :display=, :display
487
+
488
+ ##
489
+ # https://www.w3schools.com/css/css_font.asp
490
+ def font(family_string, size_integer)
491
+ id = caller_id(self)
492
+ self.style(font_family: "#{family_string}", font_size: "#{size_integer}")
493
+ return self
494
+ end
495
+ alias_method :font=, :font
496
+
497
+ ##
498
+ # https://www.w3schools.com/Css/css_font.asp
499
+ def font_family(family_string)
500
+ self.style(font_family: "#{family_string}")
501
+ return self
502
+ end
503
+ alias_method :font_family=, :font_family
504
+
505
+ ##
506
+ # https://www.w3schools.com/cssref/pr_font_font-size.asp
507
+ def font_size(size)
508
+ self.style(font_size: "#{size}")
509
+ return self
510
+ end
511
+ alias_method :font_size=, :font_size
512
+
513
+ ##
514
+ # https://www.w3schools.com/cssref/pr_dim_height.asp
515
+ def height(h)
516
+ self.style(height: "#{h}")
517
+ return self
518
+ end
519
+ alias_method :height=, :height
520
+
521
+ ##
522
+ # Horizontal justification within a box.
523
+ # https://www.w3schools.com/csSref/css3_pr_justify-content.asp
524
+ def justify(position)
525
+ position = "flex-start" if position == "start"
526
+ position = "flex-end" if position == "end"
527
+ self.style(justify_content: "#{position}")
528
+ return self
529
+ end
530
+ alias_method :justify=, :justify
531
+
532
+ ##
533
+ # margin in pixels, or `'auto'` to center
534
+ def margin(size)
535
+ self.style(margin: "#{size}")
536
+ return self
537
+ end
538
+ alias_method :margin=, :margin
539
+
540
+ ##
541
+ # 0.0 to 1.0
542
+ def opacity(value)
543
+ if self.class.to_s == "GuindillaGUI::Svg"
544
+ self.style(fill_opacity: "#{value}")
545
+ else
546
+ self.style(opacity: "#{value}")
547
+ end
548
+ return self
549
+ end
550
+ alias_method :opacity=, :opacity
551
+
552
+ ##
553
+ # padding in pixels
554
+ def padding(size)
555
+ self.style(padding: "#{size}")
556
+ return self
557
+ end
558
+ alias_method :padding=, :padding
559
+
560
+ ##
561
+ # position by x and y pixel coordinates
562
+ def position(x, y)
563
+ self.style(position: 'absolute')
564
+ self.style(left: "#{x}px", top: "#{y}px")
565
+ end
566
+ alias_method :position=, :position
567
+
568
+ def rotate(degrees)
569
+ rotation = self.attributes[:rotate].to_i + degrees
570
+ self.style(rotate: "#{rotation}deg")
571
+ return self
572
+ end
573
+
574
+ def size(width, height)
575
+ self.style(width: "#{width}", height: "#{height}")
576
+ return self
577
+ end
578
+ alias_method :size=, :size
579
+
580
+ ##
581
+ # position may be `'left'`, `'right'`, `'center'`, or `'justify'`
582
+ def text_align(position)
583
+ self.style(text_align: "#{position}")
584
+ return self
585
+ end
586
+ alias_method :text_align=, :text_align
587
+
588
+ ##
589
+ # `transition(property, duration, delay=0, type="ease")`
590
+ # https://www.w3schools.com/css/css3_transitions.asp
591
+ def transition(property, duration, *args)
592
+ self.style(transition: "#{property} #{duration}s")
593
+ unless args.empty?
594
+ args.each do |arg|
595
+ if arg.is_a?(String)
596
+ self.style(transition_timing_function: "#{arg}")
597
+ elsif arg.is_a?(Integer)
598
+ self.style(transition_delay: "#{arg}s")
599
+ end
600
+ end
601
+ end
602
+ end
603
+ alias_method :transition=, :transition
604
+
605
+ ##
606
+ # https://www.w3schools.com/cssref/pr_dim_width.asp
607
+ def width(w)
608
+ self.style(width: "#{w}")
609
+ return self
610
+ end
611
+ alias_method :width=, :width
612
+
613
+ end #class Guindilla
614
+ end #module
@@ -0,0 +1,35 @@
1
+ <!--
2
+ #------------------------------------------------------------------------------#
3
+ # Copyleft 2022
4
+ # This file is part of GuindillaGUI.
5
+ # GuindillaGUI is free software: you can redistribute it and/or modify it under
6
+ # the terms of the GNU General Public License as published by the Free Software
7
+ # Foundation, either version 3 of the License, or (at your option) any later
8
+ # version.
9
+ # GuindillaGUI is distributed in the hope that it will be useful, but WITHOUT
10
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ # You should have received a copy of the GNU General Public License along with
13
+ # GuindillaGUI. If not, see <https://www.gnu.org/licenses/>.
14
+ #------------------------------------------------------------------------------#
15
+ -->
16
+
17
+ <!doctype html>
18
+
19
+ <html lang="en">
20
+ <head>
21
+ <meta charset="utf-8">
22
+ <meta name="viewport" content="width=device-width, initial-scale=1">
23
+ <title>GuindillaGUI</title>
24
+ <meta name="description" content="GuindillaGUI generated html">
25
+ <meta name="author" content="lljk">
26
+ <link rel="icon" href="guindilla_gui.png">
27
+
28
+ <script src="jquery/jquery-3.6.0.min.js"></script>
29
+ <script src="plotly/plotly-2.9.0.min.js"></script>
30
+ <script src="guindilla.js"></script>
31
+ </head>
32
+
33
+ <body id="body">
34
+ </body>
35
+ </html>
@@ -0,0 +1,46 @@
1
+ /*
2
+ #------------------------------------------------------------------------------#
3
+ # Copyleft 2022
4
+ # This file is part of GuindillaGUI.
5
+ # GuindillaGUI is free software: you can redistribute it and/or modify it under
6
+ # the terms of the GNU General Public License as published by the Free Software
7
+ # Foundation, either version 3 of the License, or (at your option) any later
8
+ # version.
9
+ # GuindillaGUI is distributed in the hope that it will be useful, but WITHOUT
10
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ # You should have received a copy of the GNU General Public License along with
13
+ # GuindillaGUI. If not, see <https://www.gnu.org/licenses/>.
14
+ #------------------------------------------------------------------------------#
15
+ */
16
+
17
+ let socket = null
18
+
19
+ $(document).ready(function(){
20
+
21
+ socket = new WebSocket('ws://localhost:8181/');
22
+
23
+ socket.onopen = function(event) {
24
+ console.log("[open] Connection with GuindillaGUI established");
25
+ };
26
+ socket.onmessage = function(event) {
27
+ console.log(`[message] Data received from server: ${event.data}`);
28
+ $(document.body).append(event.data);
29
+ };
30
+ socket.onclose = function(event) {
31
+ if (event.wasClean) {
32
+ console.log(`[close] Connection with GuindillaGUI closed, code=${event.code} reason=${event.reason}`);
33
+ } else {
34
+ alert('[close] Connection with GuindillaGUI died');
35
+ }
36
+ };
37
+ socket.onerror = function(error) {
38
+ alert(`[error] ${error.message}`);
39
+ };
40
+
41
+ window.addEventListener('beforeunload', function (e) {
42
+ socket.send("UI closed.")
43
+ socket.close();
44
+ });
45
+
46
+ });