5// Created by Stefan Ritt on 5/8/15.
16 Dialog boxes consists of normal HTML code defined on the current web page. By
17 using the class "dlgFrame" they are automatically hidden until the
18 dlgShow() function is called. The dialog has a title bar and can be moved
19 around by dragging the title bar. The dlgHide() function should be called
20 to close (hide) the dialog.
22 Following button shows the dialog dlgXXX:
24 <button type="button" onClick="dlgShow('dlgXXX')">XXX</button>
26 Following HTML code defines the dialog dlgXXX:
28 <div id="dlgXXX" class="dlgFrame">
29 <div class="dlgTitlebar">Title</div>
30 <div class="dlgPanel">
31 <div>Dialog Contents</div>
32 <button class="dlgButton" onClick="dlgHide('dlgXXX')">Close</button>
41 Replacement for alert() function showing a standard notification
43 dlgConfirm(message, callback, param)
44 Replacement of confirm() dialog. Shows a message dialog with a 'Cancel'
45 and 'Ok' button. The callback is called with the first parameter either
46 true (if Ok has been clicked) or false (if Cancel has been clicked) and
47 the second parameter a copy of 'param' passed to dlgConfirm().
49 dlgQuery(message, value, callback, param)
50 Replacement of prompt() dialog. Shows a dialog box ith a 'Cancel', 'Ok'
51 button and a field to enter a value. 'message' is shown before the
52 input filed and can contain a string like 'Please enter value:'. If
53 'cancel' is pressed, the 'callback' function is called with the first
54 parameter equal 'false'. If 'Ok' is pressed, 'callback' is called with
55 the first parameter being the value of the input field. 'param' is just
56 passed to the callback function as an optional second parameter. So a
57 typical callback function can look like
59 function cb(value, param) {
61 alert('Value is '+value+', param is '+param);
64 where 'param' can also be ommitted.
66 dlgMessage(title, message, modal, error, callback, param)
67 Similar to dlgAlert, but with the option to set a custom title which
68 gets a red background if error is true. After the 'Ok' button is pressed,
69 the callback function is called with an optional parameter passed to
70 dlgMessage. If modal equals true, the whole screen is greyed out and all
71 mouse events are captured until the 'Ok' button is pressed.
74 Shows a model dialog with a progress bar for 'time' seconds and 'string'
75 in the first line. After 'time' seconds the dialog closes automatically.
80 <button name="ctrlHSlider" type="button" class="ctrlHSlider" data-update="xxx()" id="yyy"></button>
82 <button name="ctrlVSlider" type="button" class="ctrlVSlider" data-update="xxx()" id="yyy"></button>
84 On each change of the slider, the function xxx(value, final) is called with
85 value ranging from 0 to 1. Dragging the slider will cause many updates with
86 final = false, and once the mouse button got released, the funciton is called
87 once with final = true.
89 To set the slider programmatically call
91 document.getElementById('yyy').set(0.5);
93 Valid range is again 0 to 1.
99 <div name="ctrlProgress" style="width:xxxpx;color:yyy;" id="zzz"></div>
101 document.getElementById('yyy').set(v); // v = 0...1
108 <button name="ctrlButton" data-draw="xxx" type="button" id="yyy" onClick="zzz()"></button>
112 // example for an up-arrow with 36x36 pixels
115 let ctx = cvs.getContext("2d");
116 ctx.fillStyle = "#E0E0E0";
117 ctx.fillRect(0, 0, 36, 36);
124 ctx.fillStyle = "#808080";
130// default styles for dialog boxes
131let controls_css = `<style>
133 font-family: verdana,tahoma,sans-serif;
134 border: 1px solid black;
135 box-shadow: 6px 6px 10px 4px rgba(0,0,0,0.2);
141 display: none; /* pre-hidden */
146 background-color: #C0C0C0;
147 border-top-left-radius: 6px;
148 border-top-right-radius: 6px;
159 background-color: #F8F8F8;
160 border: 1px solid #808080;
167 background-color: #4187F7;
169 border: 1px solid #808080;
175 background-color: #F0F0F0;
178 background-color: #F0F0F0;
181 border-bottom-left-radius: 6px;
182 border-bottom-right-radius: 6px;
185 background: rgba(0,0,0,.5);
206 border: 1px solid #A0A0A0;
210 background-color: #E0E0E0;
218 background-color: #419bf9;
223(function (window) { // anonymous global function
224 window.addEventListener("load", ctlInit, false);
228 let CTL = new Controls();
232function Controls() // constructor
236Controls.prototype.init = function () // scan DOM
239 document.head.insertAdjacentHTML("beforeend", controls_css);
241 // scan DOM for controls
242 this.ctrlButton = document.getElementsByName("ctrlButton");
243 this.ctrlVSlider = document.getElementsByName("ctrlVSlider");
244 this.ctrlHSlider = document.getElementsByName("ctrlHSlider");
245 this.ctrlProgress = document.getElementsByName("ctrlProgress");
248 for (let i = 0; i < this.ctrlButton.length; i++) {
249 let cvs = document.createElement("canvas");
250 this.ctrlButton[i].appendChild(cvs);
252 if (this.ctrlButton[i].dataset.draw !== undefined)
253 eval(this.ctrlButton[i].dataset.draw + "(cvs)");
257 for (let i = 0; i < this.ctrlVSlider.length; i++) {
258 let cvs = document.createElement("canvas");
259 let sl = this.ctrlVSlider[i];
260 cvs.width = sl.clientWidth;
261 cvs.height = sl.clientHeight;
265 sl.position = 0.5; // slider position 0...1
266 sl.addEventListener("click", this.ctrlVSliderHandler.bind(this));
267 sl.addEventListener("contextmenu", this.ctrlVSliderHandler.bind(this));
268 sl.addEventListener("mousemove", this.ctrlVSliderHandler.bind(this));
269 sl.addEventListener("touchmove", this.ctrlVSliderHandler.bind(this));
270 sl.draw = this.ctrlVSliderDraw;
272 sl.set = this.ctrlVSliderSet;
276 for (let i = 0; i < this.ctrlHSlider.length; i++) {
277 let cvs = document.createElement("canvas");
278 let sl = this.ctrlHSlider[i];
279 cvs.width = sl.clientWidth;
280 cvs.height = sl.clientHeight;
284 sl.position = 0.5; // slider position 0...1
285 sl.addEventListener("click", this.ctrlHSliderHandler.bind(this));
286 sl.addEventListener("contextmenu", this.ctrlHSliderHandler.bind(this));
287 sl.addEventListener("mousemove", this.ctrlHSliderHandler.bind(this));
288 sl.addEventListener("touchmove", this.ctrlHSliderHandler.bind(this));
289 sl.addEventListener("mouseup", this.ctrlHSliderHandler.bind(this));
290 sl.draw = this.ctrlHSliderDraw;
292 sl.set = this.ctrlHSliderSet;
296 for (let i = 0; i < this.ctrlProgress.length; i++) {
297 let p = this.ctrlProgress[i];
298 p.className = "ctrlProgress";
299 let ind = document.createElement("div");
300 ind.className = "ctrlProgressInd";
301 ind.style.height = p.style.height;
302 ind.style.backgroundColor = p.style.color;
304 p.set = this.ctrlProgressSet;
309Controls.prototype.ctrlVSliderDraw = function (b) {
312 let w = b.canvas.width;
313 let h = b.canvas.height;
316 let ctx = b.canvas.getContext("2d");
317 ctx.fillStyle = "#E0E0E0";
318 ctx.fillRect(0, 0, b.canvas.width, b.canvas.height);
320 let knob = b.sliderOfs + (1 - b.position) * (h - 2 * b.sliderOfs);
322 ctx.strokeStyle = "#A0A0A0";
325 ctx.moveTo(w / 2, b.sliderOfs);
326 ctx.lineTo(w / 2, knob);
329 ctx.strokeStyle = "#00A0FF";
331 ctx.moveTo(w / 2, knob);
332 ctx.lineTo(w / 2, h - b.sliderOfs);
335 ctx.fillStyle = "#E0E0E0";
336 ctx.strokeStyle = "#C0C0C0";
338 ctx.arc(w / 2, knob, 10, 0, 2 * Math.PI);
343Controls.prototype.ctrlVSliderSet = function (pos) {
352Controls.prototype.ctrlVSliderHandler = function (e) {
355 let b = e.currentTarget;
357 if (b.canvas === undefined) // we can get events from parent node
360 if ((e.buttons === 1 && e.type === "mousemove") || e.type === "click")
362 if (e.type === "touchmove")
363 y = e.changedTouches[e.changedTouches.length - 1].clientY - b.getBoundingClientRect().top;
365 if (e.type === "contextmenu") {
367 this.ctrlVSliderDraw(b);
368 let f = b.dataset.update;
370 f = f.substr(0, f.indexOf("("));
371 window[f](b.position);
373 if (y !== undefined) {
374 b.position = 1 - (y - b.sliderOfs) / (b.clientHeight - 2 * b.sliderOfs);
379 this.ctrlVSliderDraw(b);
380 let f = b.dataset.update;
382 f = f.substr(0, f.indexOf("("));
383 window[f](b.position);
388Controls.prototype.ctrlHSliderDraw = function (b) {
391 let w = b.canvas.width;
392 let h = b.canvas.height;
395 let ctx = b.canvas.getContext("2d");
396 ctx.fillStyle = "#E0E0E0";
397 ctx.fillRect(0, 0, b.canvas.width, b.canvas.height);
399 let knob = b.sliderOfs + (b.position) * (w - 2 * b.sliderOfs);
401 ctx.strokeStyle = "#A0A0A0";
404 ctx.moveTo(w - b.sliderOfs, h / 2);
405 ctx.lineTo(knob, h / 2);
408 ctx.strokeStyle = "#00A0FF";
410 ctx.moveTo(knob, h / 2);
411 ctx.lineTo(b.sliderOfs, h / 2);
414 ctx.fillStyle = "#E0E0E0";
415 ctx.strokeStyle = "#C0C0C0";
417 ctx.arc(knob, h / 2, 10, 0, 2 * Math.PI);
422Controls.prototype.ctrlHSliderSet = function (pos) {
431Controls.prototype.ctrlHSliderHandler = function (e) {
434 let b = e.currentTarget;
436 if (b.canvas === undefined) // we can get events from parent node
439 if ((e.buttons === 1 && e.type === "mousemove") || e.type === "click")
441 if (e.type === "touchmove")
442 x = e.changedTouches[e.changedTouches.length - 1].clientX - b.getBoundingClientRect().left;
444 if (e.type === "contextmenu") {
446 b.contextMenu = true;
447 this.ctrlHSliderDraw(b);
448 let f = b.dataset.update;
450 f = f.substr(0, f.indexOf("("));
451 window[f](b.position, true);
454 if (x !== undefined) {
455 b.contextMenu = false;
456 b.position = (x - b.sliderOfs) / (b.clientWidth - 2 * b.sliderOfs);
461 this.ctrlHSliderDraw(b);
462 let f = b.dataset.update;
464 f = f.substr(0, f.indexOf("("));
465 window[f](b.position, false);
468 if (e.type === "mouseup" && !b.contextMenu) {
469 console.log(e.buttons);
470 let f = b.dataset.update;
472 f = f.substr(0, f.indexOf("("));
473 window[f](b.position, true);
477Controls.prototype.ctrlProgressSet = function (value) {
482 this.firstChild.style.width = Math.round(parseInt(this.style.width) * value) + "px";
485//-------------------------------------------------------------------------------------------------
486var dlgLoadedDialogs = [];
488function dlgLoad(url) {
489 // check if dialog already laoded
490 if (dlgLoadedDialogs.includes(url))
493 dlgLoadedDialogs.push(url);
495 // load dialog via AJAX
496 return new Promise(function (resolve, reject) {
497 let xhr = new XMLHttpRequest();
498 xhr.onreadystatechange = function () {
499 if (xhr.readyState === 4) {
500 if (xhr.status === 200) {
501 let d = document.createElement("div");
502 d.innerHTML = xhr.responseText;
503 document.body.appendChild(d);
504 resolve(xhr.responseText);
506 dlgAlert("network error: see javascript console: dlgLoad() cannot load " + url + ", HTTP status: " + xhr.status);
507 reject(xhr.responseURL);
512 xhr.open("GET", url, true);
513 xhr.setRequestHeader('Content-type', 'text/html');
518function drawCloseButton(c, mark) {
521 let ctx = c.getContext("2d");
522 ctx.clearRect(0, 0, c.width, c.height);
525 ctx.arc(c.width/2, c.height/2, c.width/2-1, 0, 2*Math.PI);
526 ctx.fillStyle = '#FD5E59';
528 ctx.strokeStyle = '#DF2020';
531 ctx.strokeStyle = '#000000';
534 ctx.moveTo(c.width/2-3, c.height/2-3);
535 ctx.lineTo(c.width/2+3, c.height/2+3);
536 ctx.moveTo(c.width/2+3, c.height/2-3);
537 ctx.lineTo(c.width/2-3, c.height/2+3);
542function dlgCenter(dlg) {
544 if (typeof dlg === "string")
545 d = document.getElementById(dlg);
550 dlgAlert("Dialog '" + dlg + "' does not exist");
554 d.style.left = Math.round(document.documentElement.clientWidth / 2 - d.offsetWidth / 2) + "px";
555 if (document.documentElement.clientHeight / 2 - d.offsetHeight / 2 < 0)
558 d.style.top = Math.round(document.documentElement.clientHeight / 2 - d.offsetHeight / 2) + "px";
560 // allow for scrolling of very high dialog boxes
561 if (d.offsetHeight > document.documentElement.clientHeight)
562 d.style.position = "absolute";
565function dlgShow(dlg, modal, param) {
567 if (typeof dlg === "string")
568 d = document.getElementById(dlg);
573 dlgAlert("Dialog '" + dlg + "' does not exist");
577 if (d.childNodes === undefined) {
578 dlgAlert("Dialog '" + dlg + "' has no title bar");
582 // add optional parameter to dialog
585 // put "close" icon into title bar
587 if (d.childNodes[0].className === "dlgTitlebar")
589 if (d.childNodes[1] && d.childNodes[1].className === "dlgTitlebar")
591 if (t !== undefined) {
592 let ttext = t.innerHTML;
593 if (ttext.search('dlgHide') === -1) {
594 t.innerHTML = "<div style=\"position: absolute;left: 6px;top: 3px;\" " +
595 "onclick=\"dlgClose(this);\">" +
596 "<canvas id=\"cvsClose\" width=\"14px\" height=\"14px\"></canvas>" +
599 d.canvas = t.childNodes[0].childNodes[0];
600 drawCloseButton(d.canvas, false);
607 d.modal = (modal === true);
609 d.style.display = "block";
612 // put dialog on top of all other dialogs
613 let dlgs = document.getElementsByClassName("dlgFrame");
614 for (let i = 0; i < dlgs.length; i++)
615 dlgs[i].style.zIndex = "30"; // on top of blackout (20)
616 d.style.zIndex = "31";
618 // move dialog right-down if on top of previous one
619 if (dlgs.length > 1) {
620 d.style.left = (parseInt(dlgs[dlgs.length - 2].style.left) + 30).toString() + "px";
621 d.style.top = (parseInt(dlgs[dlgs.length - 2].style.top) + 30).toString() + "px";
624 // enable scrolling if dialog box goes beyond screen
625 d.oldScroll = window.getComputedStyle(document.body).overflow;
626 document.body.style.overflow = "scroll";
629 let b = document.getElementById("dlgBlackout");
630 if (b === undefined || b === null) {
631 b = document.createElement("div");
632 b.id = "dlgBlackout";
633 b.className = "dlgBlackout";
634 document.body.appendChild(b);
637 b.style.display = "block";
641 d.dlgMouseDown = function (e) {
642 if (d.style.display === "none")
645 // ignore right mouse clicks
649 if ((e.target === this || e.target.parentNode === this) &&
650 e.target.className === "dlgTitlebar") {
654 this.Dx = parseInt(this.style.left);
655 this.Dy = parseInt(this.style.top);
658 if (d.modal && e.target !== d && !d.contains(e.target)) {
659 // catch all mouse events outside the dialog
662 if (e.target === this || d.contains(e.target)) {
663 let dlgs = document.getElementsByClassName("dlgFrame");
664 for (let i = 0; i < dlgs.length; i++)
665 dlgs[i].style.zIndex = "30";
666 d.style.zIndex = "31";
671 d.dlgMouseMove = function (e) {
672 if (d.style.display === "none")
675 // draw close button with "x" if mouse cursor is inside
676 drawCloseButton(d.canvas, e.target === d.canvas);
678 if (this.Ax > 0 && this.Ay > 0) {
682 // stop dragging if leaving window
683 if (x < 0 || y < 0 ||
684 x > document.documentElement.clientWidth ||
685 y > document.documentElement.clientHeight ||
686 (this.Dy + (y - this.Ay)) < 0) {
690 this.style.left = (this.Dx + (x - this.Ax)) + "px";
691 this.style.top = (this.Dy + (y - this.Ay)) + "px";
696 d.dlgMouseUp = function () {
701 d.dlgTouchStart = function (e) {
702 if (d.style.display === "none")
705 if ((e.target === this || e.target.parentNode === this) &&
706 e.target.className === "dlgTitlebar") {
708 this.Ax = e.targetTouches[0].clientX;
709 this.Ay = e.targetTouches[0].clientY;
710 this.Dx = parseInt(this.style.left);
711 this.Dy = parseInt(this.style.top);
714 if (d.modal && e.target !== d && !d.contains(e.target)) {
715 // catch all mouse events
718 if (e.target === this || d.contains(e.target)) {
719 let dlgs = document.getElementsByClassName("dlgFrame");
720 for (let i = 0; i < dlgs.length; i++)
721 dlgs[i].style.zIndex = "30";
722 d.style.zIndex = "31";
727 d.dlgTouchMove = function (e) {
728 if (d.style.display === "none")
731 if (this.Ax > 0 && this.Ay > 0) {
733 let x = e.changedTouches[e.changedTouches.length - 1].clientX;
734 let y = e.changedTouches[e.changedTouches.length - 1].clientY;
735 this.style.left = (this.Dx + (x - this.Ax)) + "px";
736 this.style.top = (this.Dy + (y - this.Ay)) + "px";
740 d.dlgTouchEnd = function (e) {
741 if (d.style.display === "none")
744 if (this.Ax > 0 && this.Ay > 0) {
751 d.dlgTouchCancel = function (e) {
752 if (d.style.display === "none")
755 if (this.Ax > 0 && this.Ay > 0) {
762 d.dlgKeyDown = function (e) {
763 if (d.style.display === "none")
766 if (e.key === 'Escape') {
768 dlgClose(d.childNodes[1].childNodes[0]);
771 window.addEventListener("keydown", d.dlgKeyDown.bind(d), true);
773 window.addEventListener("mousedown", d.dlgMouseDown.bind(d), true);
774 window.addEventListener("mousemove", d.dlgMouseMove.bind(d), true);
775 window.addEventListener("mouseup", d.dlgMouseUp.bind(d), true);
776 window.addEventListener("touchstart", d.dlgTouchStart.bind(d), true);
777 window.addEventListener("touchmove", d.dlgTouchMove.bind(d), true);
778 window.addEventListener("touchend", d.dlgTouchEnd.bind(d), true);
779 window.addEventListener("touchcancel", d.dlgTouchCancel.bind(d), true);
782function dlgMove(d, x, y) {
783 d.style.left = x + "px";
784 d.style.top = y + "px";
787function dlgClose(div) {
789 while (!dlg.className.includes("dlgFrame"))
790 dlg = dlg.parentElement;
791 if (dlg.shouldDestroy)
792 dlgMessageDestroy(dlg);
793 else if (dlg.id !== undefined)
797function dlgHide(dlg) {
798 if (typeof dlg === "string")
799 dlg = document.getElementById(dlg);
800 else if (dlg.type === "button") {
802 dlg = dlg.parentElement;
803 } while (dlg.className !== 'dlgFrame');
807 // only remove blackout if we are the only modal dialog left
808 let dlgs = document.getElementsByClassName("dlgFrame");
810 for (let i = 0; i < dlgs.length; i++)
811 if (dlgs[i].style.display === "block" && dlgs[i].modal)
814 let d = document.getElementById("dlgBlackout");
815 if (d !== undefined && d !== null)
816 d.style.display = "none";
819 dlg.style.display = "none";
820 if (dlg.oldScroll !== "")
821 document.body.style.overflow = dlg.oldScroll;
824function dlgMessageDestroy(b) {
826 while (!dlg.className.includes("dlgFrame"))
827 dlg = dlg.parentElement;
829 // only remove blackout if we are the only modal dialog left
830 let dlgs = document.getElementsByClassName("dlgFrame");
832 for (let i = 0; i < dlgs.length; i++)
833 if (dlgs[i].style.display === "block" && dlgs[i].modal)
836 let d = document.getElementById("dlgBlackout");
837 if (d !== undefined && d !== null)
838 d.style.display = "none";
841 // dialog is not really removed from memory, event listerner is still active and
842 // grabs mousdown events, so mark its display "none" to prevent eating mouse events
843 // above in dlgMouseDown routine
844 dlg.style.display = "none";
845 document.body.removeChild(dlg);
848function dlgMessage(title, string, modal, error, callback, param) {
849 let d = document.createElement("div");
850 d.className = "dlgFrame";
851 d.style.zIndex = modal ? "31" : "30";
852 d.callback = callback;
853 d.callbackParam = param;
854 d.shouldDestroy = true;
856 d.innerHTML = "<div class=\"dlgTitlebar\" id=\"dlgMessageTitle\">" + title + "</div>" +
857 "<div class=\"dlgPanel\" style=\"padding: 30px;\">" +
858 "<div id=\"dlgMessageString\">" + string + "</div>" +
859 "<br /><br /><button class=\"dlgButton\" id=\"dlgMessageButton\" type=\"button\" " +
860 " onClick=\"let d=this.parentElement.parentElement;if(d.callback!==undefined)d.callback(d.callbackParam);dlgMessageDestroy(this)\">Close</button>" +
863 document.body.appendChild(d);
865 if (error === true) {
866 let t = document.getElementById("dlgMessageTitle");
867 t.style.backgroundColor = "#9E2A2A";
868 t.style.color = "white";
875function dlgAlert(s, callback) {
876 dlgMessage('Message', s, true, false, callback);
879function dlgConfirm(string, confirmCallback, param) {
880 let d = document.createElement("div");
881 d.className = "dlgFrame";
882 d.style.zIndex = "31";
883 d.callback = confirmCallback;
884 d.callbackParam = param;
885 d.shouldDestroy = true;
887 d.innerHTML = "<div class=\"dlgTitlebar\" id=\"dlgMessageTitle\">Please confirm</div>" +
888 "<div class=\"dlgPanel\" style=\"padding: 30px;\">" +
889 "<div id=\"dlgMessageString\">" + string + "</div>" +
891 "<button class=\"dlgButtonDefault\" id=\"dlgMessageButtonOk\" type=\"button\" " +
892 " onClick=\"let d=this.parentElement.parentElement;d.callback(true,d.callbackParam);dlgMessageDestroy(this);\">OK</button>" +
893 "<button class=\"dlgButton\" id=\"dlgMessageButtonCancel\" type=\"button\" " +
894 " onClick=\"let d=this.parentElement.parentElement;d.callback(false,d.callbackParam);dlgMessageDestroy(this);\">Cancel</button>" +
897 document.body.appendChild(d);
900 document.getElementById('dlgMessageButtonOk').focus();
904// Populate a modal with a general html
905function dlgGeneral(p) {
906 /* general dialog containing p.html code and other optional parameters
907 p.iddiv - the name of the dialog div (optional)
908 p.width/p.height - minimal width/height of dialog (optional)
909 p.minWidth/p.minHeight - minimal width/height of dialog (optional)
910 p.x/p.y - initial position of dialog (optional)
911 p.title - title of the dialog (optional)
914 // First make sure you removed existing iddiv
915 if (document.getElementById(p.iddiv)) document.getElementById(p.iddiv).remove();
916 let d = document.createElement("div");
917 d.className = "dlgFrame";
918 if (p.iddiv) d.id = p.iddiv;
919 d.style.zIndex = "30";
920 d.style.overflow = "hidden";
921 d.style.resize = "both";
922 d.style.width = p.width? p.width + "px" : "400px";
923 d.style.height = p.height ? p.height + "px" : "200px";
924 d.style.minWidth = p.minWidth ? p.minWidth + "px" : d.style.width;
925 d.style.minHeight = p.minHeight ? p.minHeight + "px" : d.style.height;
926 d.style.maxHeight = "90vh";
927 d.style.maxWidth = "60vw";
928 d.shouldDestroy = true;
930 const dlgTitle = document.createElement("div");
931 dlgTitle.className = "dlgTitlebar";
932 //dlgTitle.id = "dlgMessageTitle";
933 dlgTitle.innerText = p.title || (p.iddiv ? p.iddiv + " dialog" : "General dialog");
934 d.appendChild(dlgTitle);
936 const dlgPanel = document.createElement("div");
937 dlgPanel.className = "dlgPanel";
938 //dlgPanel.id = "dlgPanel";
939 d.appendChild(dlgPanel);
941 const content = document.createElement("div");
942 //content.id = "dlgHTML";
943 content.style.overflow = "auto";
944 content.innerHTML = p.html;
945 dlgPanel.appendChild(content);
947 document.body.appendChild(d);
950 if (p.x !== undefined && p.y !== undefined)
951 dlgMove(d, p.x, p.y);
953 // Initial size based on content
954 d.style.height = (content.scrollHeight + dlgTitle.offsetHeight + 5 ) + "px";
955 d.style.width = (content.scrollWidth + 5 ) + "px";
957 // Function to handle resize events
958 function handleResize() {
959 content.style.height = (d.offsetHeight - dlgTitle.offsetHeight - 5 ) + "px";
962 // Resize observer to watch for dialog resizing
963 const resizeObs = new ResizeObserver(handleResize);
964 resizeObs.observe(d);
969function dlgQueryKeyDown(event, inp) {
970 let keyCode = ('which' in event) ? event.which : event.keyCode;
972 if (keyCode === 27) {
974 let d = inp.parentElement.parentElement.parentElement;
975 d.callback(false, d.callbackParam);
976 dlgMessageDestroy(inp.parentElement);
980 if (keyCode === 13) {
982 let d = inp.parentElement.parentElement.parentElement;
983 d.callback(inp.value, d.callbackParam);
984 dlgMessageDestroy(inp.parentElement);
991function dlgQuery(string, value, queryCallback, param, size) {
992 let d = document.createElement("div");
993 d.className = "dlgFrame";
994 d.style.zIndex = "31";
995 d.callback = queryCallback;
996 d.callbackParam = param;
997 d.shouldDestroy = true;
999 if (size === undefined)
1002 d.innerHTML = "<div class=\"dlgTitlebar\" id=\"dlgMessageTitle\"> </div>" +
1003 "<div class=\"dlgPanel\" style=\"padding: 20px;\">" +
1004 "<div id=\"dlgMessageString\">" + string + " <input type='text' size='"+size+"' id='dlgQueryInput' onkeydown='return dlgQueryKeyDown(event, this);' value='" + value + "'></input></div>" +
1006 "<button class=\"dlgButtonDefault\" id=\"dlgMessageButton\" type=\"button\" " +
1007 " onClick=\"let d=this.parentElement.parentElement;d.callback(document.getElementById('dlgQueryInput').value,d.callbackParam);dlgMessageDestroy(this);\">OK</button>" +
1008 "<button class=\"dlgButton\" id=\"dlgMessageButton\" type=\"button\" " +
1009 " onClick=\"let d=this.parentElement.parentElement;d.callback(false,d.callbackParam);dlgMessageDestroy(this);\">Cancel</button>" +
1012 document.body.appendChild(d);
1015 document.getElementById('dlgQueryInput').focus();
1016 document.getElementById('dlgQueryInput').select();
1025let dlgWaitFuncParam;
1027function dlgWait(time, string, func, param) {
1029 let d = document.createElement("div");
1030 d.className = "dlgFrame";
1031 d.style.zIndex = "31";
1032 d.shouldDestroy = true;
1034 <!-- wait dialog -->
1035 d.innerHTML = "<div class=\"dlgTitlebar\" id=\"dlgMessageTitle\">Please wait...</div>" +
1036 "<div class=\"dlgPanel\" style=\"padding: 20px;\">" +
1037 "<div id=\"dlgMessageString\">" + string + "</div>" +
1039 "<div name=\"ctrlProgress\" style=\"width:250px;\" id=\"dlgWaitProgress\"></div>" +
1042 document.body.appendChild(d);
1044 // init progress bar
1045 let p = document.getElementById('dlgWaitProgress');
1046 p.className = "ctrlProgress";
1047 let ind = document.createElement("div");
1048 ind.className = "ctrlProgressInd";
1049 ind.style.height = p.style.height;
1050 ind.style.backgroundColor = p.style.color;
1052 p.set = function (value) {
1053 this.firstChild.style.width = Math.round(parseInt(this.style.width) * value) + "px";
1059 dlgWaitProgress = 0;
1062 dlgWaitFuncParam = param;
1063 window.setTimeout(updateDlgWaitProgress, 100);
1066function updateDlgWaitProgress() {
1067 dlgWaitProgress += 0.1;
1068 let d = document.getElementById("dlgWaitProgress");
1069 d.set(dlgWaitProgress / dlgWaitTime);
1070 if (dlgWaitProgress >= dlgWaitTime) {
1071 dlgWaitDialog.style.display = "none";
1072 document.body.removeChild(dlgWaitDialog);
1073 let d = document.getElementById("dlgBlackout");
1074 if (d !== undefined && d !== null)
1075 d.style.display = "none";
1076 if (dlgWaitFunc !== undefined)
1077 dlgWaitFunc(dlgWaitFuncParam);
1079 window.setTimeout(updateDlgWaitProgress, 100);