max80.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Get an element by id or an Element object
  2. function getelem(id) {
  3. return (id instanceof Element) ? id : document.getElementById(id);
  4. }
  5. // Read a key=value text file and return it as a Promise of a Map
  6. function fetchconfig(url) {
  7. return fetch(url, {redirect: "follow"})
  8. .then(res => {
  9. if (!res.ok) {
  10. throw new Error("HTTP error "+response.status);
  11. } else {
  12. return res.text();
  13. }
  14. })
  15. .then(text => {
  16. var map = new Map();
  17. for (const c of text.split(/[\r\n]+/)) {
  18. var m = c.match(/^\s*([\;\/]?)((?:"[^"]*"|[^"])*?)\s*=(.*)$/);
  19. if (m && m[1] == "") {
  20. var k = m[2].replaceAll(/(^"|"$|(")")/g, "$2");
  21. map.set(k, m[3]);
  22. }
  23. }
  24. return map;
  25. });
  26. }
  27. // Initialize a form from a map
  28. function initform(form,map) {
  29. var button = null;
  30. var clearers = new Map;
  31. form = getelem(form);
  32. for (var field of form.elements) {
  33. if (((field instanceof HTMLInputElement) ||
  34. (field instanceof HTMLSelectElement)) &&
  35. !field.classList.contains("noload")) {
  36. const val = map.get(field.name);
  37. if (val == null) {
  38. } else if (field.type == 'checkbox') {
  39. const checked = !val.match(/^(0*|[fnd].*|of.*)$/i);
  40. field.checked = checked;
  41. field.value = '1';
  42. } else if (field.type == 'radio') {
  43. field.checked = (val == field.name);
  44. } else if (field.type == 'hidden' &&
  45. field.classList.contains('_clr')) {
  46. field.remove();
  47. } else {
  48. field.value = val;
  49. }
  50. } else if (field instanceof HTMLButtonElement &&
  51. field.type == 'submit') {
  52. button = field;
  53. }
  54. }
  55. for (const what of clearers.keys()) {
  56. var clearer = document.createElement('INPUT');
  57. clearer.type = 'hidden';
  58. clearer.name = what;
  59. clearer.value = '0';
  60. clearer.classList.add('_clr');
  61. form.prepend(clearer);
  62. }
  63. if (button) {
  64. button.disabled = false; // All loaded, enable the submit button
  65. }
  66. }
  67. // Load form initialization data
  68. function loadform(form, url) {
  69. fetchconfig(url)
  70. .then(map => { initform(form, map) })
  71. .catch(() => {});
  72. }
  73. // Replace the contents of selected HTML elements based on a map with selectors
  74. function fillin(map,html)
  75. {
  76. for (const [key,val] of map) {
  77. try {
  78. for (var e of document.querySelectorAll(key))
  79. if (html) e.innerHTML = val; else e.innerText = val;
  80. } catch (error) { }
  81. }
  82. }
  83. // Load status or HTML data
  84. function load(url,html = false)
  85. {
  86. fetchconfig(url)
  87. .then(map => { fillin(map,html) })
  88. .catch(() => {});
  89. }
  90. // POST file upload with progress and response text
  91. function uploadfile(event) {
  92. event.preventDefault();
  93. var form = event.currentTarget;
  94. var elem = form.elements;
  95. var files = elem["file"].files;
  96. if (files.length != 1) {
  97. /* Show error */
  98. return;
  99. }
  100. var file = files[0];
  101. var xhr = new XMLHttpRequest();
  102. var progress = form.querySelector("progress");
  103. if (progress != undefined) {
  104. progress.value = 0;
  105. xhr.upload.addEventListener("progress", (event) => {
  106. if (event.lengthComputable) {
  107. progress.max = event.total * 1.05;
  108. progress.value = event.loaded;
  109. }
  110. });
  111. }
  112. var result = form.querySelector("pre.result");
  113. if (result != undefined) {
  114. result.className = "result hide";
  115. }
  116. xhr.addEventListener("loadend", (event) => {
  117. const ok = xhr.status >= 200 && xhr.status <= 299;
  118. if (progress != undefined) {
  119. progress.value = ok ? progress.max : 0;
  120. }
  121. if (result != undefined) {
  122. result.className = "result " + (ok ? "ok" : "err");
  123. result.innerText = xhr.responseText;
  124. }
  125. });
  126. xhr.open("POST", form.action);
  127. xhr.responseType = 'text';
  128. xhr.send(file);
  129. }
  130. // Enable a button (this ensures that the necessary scripts have been
  131. // run before one can submit)
  132. function enablebutton(id,on) {
  133. getelem(id).disabled = !on;
  134. }
  135. // Flip the status of an INPUT element between text and password
  136. function showpwd(id,me) {
  137. var pwd = getelem(id);
  138. const now_visible = me.classList.toggle('hide');
  139. me.classList.toggle('show',!now_visible);
  140. const new_type = now_visible ? 'text' : 'password';
  141. pwd.setAttribute('type', new_type);
  142. }
  143. // Hack to include an HTML files. Sadly, does not support
  144. // including files with <script> tags.
  145. function inc(url) {
  146. var me = document.currentScript;
  147. fetch(url, {redirect: "follow"})
  148. .then((response) => response.text())
  149. .then((text) => { me.outerHTML = text; });
  150. }
  151. // Insert translations
  152. function translate() {
  153. load('/sys/lang', true);
  154. }