main.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // log htmx on dev
  2. // htmx.logAll();
  3. // add text/html accept header to receive html instead of json for the requests
  4. document.body.addEventListener('htmx:configRequest', function(evt) {
  5. evt.detail.headers["Accept"] = "text/html,*/*";
  6. });
  7. // redirect to homepage
  8. document.body.addEventListener("redirectToHomepage", function() {
  9. setTimeout(() => {
  10. window.location.replace("/");
  11. }, 1500);
  12. });
  13. // reset form if event is sent from the backend
  14. function resetForm(id) {
  15. return function() {
  16. const form = document.getElementById(id);
  17. if (!form) return;
  18. form.reset();
  19. }
  20. }
  21. document.body.addEventListener('resetChangePasswordForm', resetForm("change-password"));
  22. document.body.addEventListener('resetChangeEmailForm', resetForm("change-email"));
  23. // an htmx extension to use the specifed params in the path instead of the query or body
  24. htmx.defineExtension("path-params", {
  25. onEvent: function(name, evt) {
  26. if (name === "htmx:configRequest") {
  27. evt.detail.path = evt.detail.path.replace(/{([^}]+)}/g, function(_, param) {
  28. var val = evt.detail.parameters[param]
  29. delete evt.detail.parameters[param]
  30. return val === undefined ? '{' + param + '}' : encodeURIComponent(val)
  31. })
  32. }
  33. }
  34. })
  35. // find closest element
  36. function closest(selector, elm) {
  37. let element = elm || this;
  38. while (element && element.nodeType === 1) {
  39. if (element.matches(selector)) {
  40. return element;
  41. }
  42. element = element.parentNode;
  43. }
  44. return null;
  45. };
  46. // show QR code
  47. function handleQRCode(element) {
  48. const dialog = document.querySelector("#link-dialog");
  49. const dialogContent = dialog.querySelector(".content-wrapper");
  50. if (!dialogContent) return;
  51. openDialog("link-dialog", "qrcode");
  52. dialogContent.textContent = "";
  53. const qrcode = new QRCode(dialogContent, {
  54. text: element.dataset.url,
  55. width: 200,
  56. height: 200,
  57. colorDark : "#000000",
  58. colorLight : "#ffffff",
  59. correctLevel : QRCode.CorrectLevel.H
  60. });
  61. }
  62. // copy the link to clipboard
  63. function handleCopyLink(element) {
  64. navigator.clipboard.writeText(element.dataset.url);
  65. }
  66. // copy the link and toggle copy button style
  67. function handleShortURLCopyLink(element) {
  68. handleCopyLink(element);
  69. const clipboard = element.parentNode.querySelector(".clipboard") || closest(".clipboard", element);
  70. if (!clipboard || clipboard.classList.contains("copied")) return;
  71. clipboard.classList.add("copied");
  72. setTimeout(function() {
  73. clipboard.classList.remove("copied");
  74. }, 1000);
  75. }
  76. // TODO: make it an extension
  77. // open and close dialog
  78. function openDialog(id, name) {
  79. const dialog = document.getElementById(id);
  80. if (!dialog) return;
  81. dialog.classList.add("open");
  82. if (name) {
  83. dialog.classList.add(name);
  84. }
  85. }
  86. function closeDialog() {
  87. const dialog = document.querySelector(".dialog");
  88. if (!dialog) return;
  89. while (dialog.classList.length > 0) {
  90. dialog.classList.remove(dialog.classList[0]);
  91. }
  92. dialog.classList.add("dialog");
  93. }
  94. window.addEventListener("click", function(event) {
  95. const dialog = document.querySelector(".dialog");
  96. if (dialog && event.target === dialog) {
  97. closeDialog();
  98. }
  99. });
  100. // handle navigation in the table of links
  101. function setLinksLimit(event) {
  102. const buttons = Array.from(document.querySelectorAll('table .nav .limit button'));
  103. const limitInput = document.querySelector('#limit');
  104. if (!limitInput || !buttons || !buttons.length) return;
  105. limitInput.value = event.target.textContent;
  106. buttons.forEach(b => {
  107. b.disabled = b.textContent === event.target.textContent;
  108. });
  109. }
  110. function setLinksSkip(event, action) {
  111. const buttons = Array.from(document.querySelectorAll('table .nav .pagination button'));
  112. const limitElm = document.querySelector('#limit');
  113. const totalElm = document.querySelector('#total');
  114. const skipElm = document.querySelector('#skip');
  115. if (!buttons || !limitElm || !totalElm || !skipElm) return;
  116. const skip = parseInt(skipElm.value);
  117. const limit = parseInt(limitElm.value);
  118. const total = parseInt(totalElm.value);
  119. skipElm.value = action === "next" ? skip + limit : Math.max(skip - limit, 0);
  120. document.querySelectorAll('.pagination .next').forEach(elm => {
  121. elm.disabled = total <= parseInt(skipElm.value) + limit;
  122. });
  123. document.querySelectorAll('.pagination .prev').forEach(elm => {
  124. elm.disabled = parseInt(skipElm.value) <= 0;
  125. });
  126. }
  127. function updateLinksNav() {
  128. const totalElm = document.querySelector('#total');
  129. const skipElm = document.querySelector('#skip');
  130. const limitElm = document.querySelector('#limit');
  131. if (!totalElm || !skipElm || !limitElm) return;
  132. const total = parseInt(totalElm.value);
  133. const skip = parseInt(skipElm.value);
  134. const limit = parseInt(limitElm.value);
  135. document.querySelectorAll('.pagination .next').forEach(elm => {
  136. elm.disabled = total <= skip + limit;
  137. });
  138. document.querySelectorAll('.pagination .prev').forEach(elm => {
  139. elm.disabled = skip <= 0;
  140. });
  141. }
  142. function resetLinkNav() {
  143. const totalElm = document.querySelector('#total');
  144. const skipElm = document.querySelector('#skip');
  145. const limitElm = document.querySelector('#limit');
  146. if (!totalElm || !skipElm || !limitElm) return;
  147. skipElm.value = 0;
  148. limitElm.value = 10;
  149. const skip = parseInt(skipElm.value);
  150. const limit = parseInt(limitElm.value);
  151. document.querySelectorAll('.pagination .next').forEach(elm => {
  152. elm.disabled = total <= skip + limit;
  153. });
  154. document.querySelectorAll('.pagination .prev').forEach(elm => {
  155. elm.disabled = skip <= 0;
  156. });
  157. document.querySelectorAll('table .nav .limit button').forEach(b => {
  158. b.disabled = b.textContent === limit.toString();
  159. });
  160. }