max80.js 4.3 KB

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