You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tasklist.js 2.6KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /**
  2. * Attaches `input` handlers to markdown rendered tasklist checkboxes in comments.
  3. *
  4. * When a checkbox value changes, the corresponding [ ] or [x] in the markdown string
  5. * is set accordingly and sent to the server. On success it updates the raw-content on
  6. * error it resets the checkbox to its original value.
  7. */
  8. const preventListener = (e) => e.preventDefault();
  9. export function initMarkupTasklist() {
  10. for (const el of document.querySelectorAll(`.markup[data-can-edit=true]`) || []) {
  11. const container = el.parentNode;
  12. const checkboxes = el.querySelectorAll(`.task-list-item input[type=checkbox]`);
  13. for (const checkbox of checkboxes) {
  14. if (checkbox.hasAttribute('data-editable')) {
  15. return;
  16. }
  17. checkbox.setAttribute('data-editable', 'true');
  18. checkbox.addEventListener('input', async () => {
  19. const checkboxCharacter = checkbox.checked ? 'x' : ' ';
  20. const position = parseInt(checkbox.getAttribute('data-source-position')) + 1;
  21. const rawContent = container.querySelector('.raw-content');
  22. const oldContent = rawContent.textContent;
  23. const encoder = new TextEncoder();
  24. const buffer = encoder.encode(oldContent);
  25. buffer.set(encoder.encode(checkboxCharacter), position);
  26. const newContent = new TextDecoder().decode(buffer);
  27. if (newContent === oldContent) {
  28. return;
  29. }
  30. // Prevent further inputs until the request is done. This does not use the
  31. // `disabled` attribute because it causes the border to flash on click.
  32. for (const checkbox of checkboxes) {
  33. checkbox.addEventListener('click', preventListener);
  34. }
  35. try {
  36. const editContentZone = container.querySelector('.edit-content-zone');
  37. const updateUrl = editContentZone.getAttribute('data-update-url');
  38. const context = editContentZone.getAttribute('data-context');
  39. await $.post(updateUrl, {
  40. ignore_attachments: true,
  41. _csrf: window.config.csrfToken,
  42. content: newContent,
  43. context
  44. });
  45. rawContent.textContent = newContent;
  46. } catch (err) {
  47. checkbox.checked = !checkbox.checked;
  48. console.error(err);
  49. }
  50. // Enable input on checkboxes again
  51. for (const checkbox of checkboxes) {
  52. checkbox.removeEventListener('click', preventListener);
  53. }
  54. });
  55. }
  56. // Enable the checkboxes as they are initially disabled by the markdown renderer
  57. for (const checkbox of checkboxes) {
  58. checkbox.disabled = false;
  59. }
  60. }
  61. }