| 
1 |  | -import $ from 'jquery';  | 
 | 1 | +import {toggleElem} from '../../utils/dom.ts';  | 
 | 2 | +import {fomanticQuery} from '../../modules/fomantic/base.ts';  | 
2 | 3 | 
 
  | 
3 |  | -function isExclusiveScopeName(name) {  | 
 | 4 | +function nameHasScope(name: string): boolean {  | 
4 | 5 |   return /.*[^/]\/[^/].*/.test(name);  | 
5 | 6 | }  | 
6 | 7 | 
 
  | 
7 |  | -function updateExclusiveLabelEdit(form) {  | 
8 |  | -  const nameInput = document.querySelector(`${form} .label-name-input`);  | 
9 |  | -  const exclusiveField = document.querySelector(`${form} .label-exclusive-input-field`);  | 
10 |  | -  const exclusiveCheckbox = document.querySelector(`${form} .label-exclusive-input`);  | 
11 |  | -  const exclusiveWarning = document.querySelector(`${form} .label-exclusive-warning`);  | 
 | 8 | +export function initCompLabelEdit(pageSelector: string) {  | 
 | 9 | +  const pageContent = document.querySelector<HTMLElement>(pageSelector);  | 
 | 10 | +  if (!pageContent) return;  | 
12 | 11 | 
 
  | 
13 |  | -  if (isExclusiveScopeName(nameInput.value)) {  | 
14 |  | -    exclusiveField?.classList.remove('muted');  | 
15 |  | -    exclusiveField?.removeAttribute('aria-disabled');  | 
16 |  | -    if (exclusiveCheckbox.checked && exclusiveCheckbox.getAttribute('data-exclusive-warn')) {  | 
17 |  | -      exclusiveWarning?.classList.remove('tw-hidden');  | 
18 |  | -    } else {  | 
19 |  | -      exclusiveWarning?.classList.add('tw-hidden');  | 
20 |  | -    }  | 
21 |  | -  } else {  | 
22 |  | -    exclusiveField?.classList.add('muted');  | 
23 |  | -    exclusiveField?.setAttribute('aria-disabled', 'true');  | 
24 |  | -    exclusiveWarning?.classList.add('tw-hidden');  | 
25 |  | -  }  | 
26 |  | -}  | 
 | 12 | +  // for guest view, the modal is not available, the "labels" are read-only  | 
 | 13 | +  const elModal = pageContent.querySelector<HTMLElement>('#issue-label-edit-modal');  | 
 | 14 | +  if (!elModal) return;  | 
27 | 15 | 
 
  | 
28 |  | -export function initCompLabelEdit(selector) {  | 
29 |  | -  if (!$(selector).length) return;  | 
 | 16 | +  const elLabelId = elModal.querySelector<HTMLInputElement>('input[name="id"]');  | 
 | 17 | +  const elNameInput = elModal.querySelector<HTMLInputElement>('.label-name-input');  | 
 | 18 | +  const elExclusiveField = elModal.querySelector('.label-exclusive-input-field');  | 
 | 19 | +  const elExclusiveInput = elModal.querySelector<HTMLInputElement>('.label-exclusive-input');  | 
 | 20 | +  const elExclusiveWarning = elModal.querySelector('.label-exclusive-warning');  | 
 | 21 | +  const elIsArchivedField = elModal.querySelector('.label-is-archived-input-field');  | 
 | 22 | +  const elIsArchivedInput = elModal.querySelector<HTMLInputElement>('.label-is-archived-input');  | 
 | 23 | +  const elDescInput = elModal.querySelector<HTMLInputElement>('.label-desc-input');  | 
 | 24 | +  const elColorInput = elModal.querySelector<HTMLInputElement>('.js-color-picker-input input');  | 
30 | 25 | 
 
  | 
31 |  | -  // Create label  | 
32 |  | -  $('.new-label.button').on('click', () => {  | 
33 |  | -    updateExclusiveLabelEdit('.new-label');  | 
34 |  | -    $('.new-label.modal').modal({  | 
35 |  | -      onApprove() {  | 
36 |  | -        const form = document.querySelector('.new-label.form');  | 
37 |  | -        if (!form.checkValidity()) {  | 
38 |  | -          form.reportValidity();  | 
39 |  | -          return false;  | 
40 |  | -        }  | 
41 |  | -        $('.new-label.form').trigger('submit');  | 
42 |  | -      },  | 
43 |  | -    }).modal('show');  | 
44 |  | -    return false;  | 
45 |  | -  });  | 
46 |  | - | 
47 |  | -  // Edit label  | 
48 |  | -  $('.edit-label-button').on('click', function () {  | 
49 |  | -    $('#label-modal-id').val($(this).data('id'));  | 
50 |  | - | 
51 |  | -    const $nameInput = $('.edit-label .label-name-input');  | 
52 |  | -    $nameInput.val($(this).data('title'));  | 
53 |  | - | 
54 |  | -    const $isArchivedCheckbox = $('.edit-label .label-is-archived-input');  | 
55 |  | -    $isArchivedCheckbox[0].checked = this.hasAttribute('data-is-archived');  | 
 | 26 | +  const syncModalUi = () => {  | 
 | 27 | +    const hasScope = nameHasScope(elNameInput.value);  | 
 | 28 | +    elExclusiveField.classList.toggle('disabled', !hasScope);  | 
 | 29 | +    const showExclusiveWarning = hasScope && elExclusiveInput.checked && elModal.hasAttribute('data-need-warn-exclusive');  | 
 | 30 | +    toggleElem(elExclusiveWarning, showExclusiveWarning);  | 
 | 31 | +    if (!hasScope) elExclusiveInput.checked = false;  | 
 | 32 | +  };  | 
56 | 33 | 
 
  | 
57 |  | -    const $exclusiveCheckbox = $('.edit-label .label-exclusive-input');  | 
58 |  | -    $exclusiveCheckbox[0].checked = this.hasAttribute('data-exclusive');  | 
59 |  | -    // Warn when label was previously not exclusive and used in issues  | 
60 |  | -    $exclusiveCheckbox.data('exclusive-warn',  | 
61 |  | -      $(this).data('num-issues') > 0 &&  | 
62 |  | -      (!this.hasAttribute('data-exclusive') || !isExclusiveScopeName($nameInput.val())));  | 
63 |  | -    updateExclusiveLabelEdit('.edit-label');  | 
 | 34 | +  const showLabelEditModal = (btn:HTMLElement) => {  | 
 | 35 | +    // the "btn" should contain the label's attributes by its `data-label-xxx` attributes  | 
 | 36 | +    const form = elModal.querySelector<HTMLFormElement>('form');  | 
 | 37 | +    elLabelId.value = btn.getAttribute('data-label-id') || '';  | 
 | 38 | +    elNameInput.value = btn.getAttribute('data-label-name') || '';  | 
 | 39 | +    elIsArchivedInput.checked = btn.getAttribute('data-label-is-archived') === 'true';  | 
 | 40 | +    elExclusiveInput.checked = btn.getAttribute('data-label-exclusive') === 'true';  | 
 | 41 | +    elDescInput.value = btn.getAttribute('data-label-description') || '';  | 
 | 42 | +    elColorInput.value = btn.getAttribute('data-label-color') || '';  | 
 | 43 | +    elColorInput.dispatchEvent(new Event('input', {bubbles: true})); // trigger the color picker  | 
64 | 44 | 
 
  | 
65 |  | -    $('.edit-label .label-desc-input').val(this.getAttribute('data-description'));  | 
 | 45 | +    // if label id exists: "edit label" mode; otherwise: "new label" mode  | 
 | 46 | +    const isEdit = Boolean(elLabelId.value);  | 
66 | 47 | 
 
  | 
67 |  | -    const colorInput = document.querySelector('.edit-label .js-color-picker-input input');  | 
68 |  | -    colorInput.value = this.getAttribute('data-color');  | 
69 |  | -    colorInput.dispatchEvent(new Event('input', {bubbles: true}));  | 
 | 48 | +    // if a label was not exclusive but has issues, then it should warn user if it will become exclusive  | 
 | 49 | +    const numIssues = parseInt(btn.getAttribute('data-label-num-issues') || '0');  | 
 | 50 | +    elModal.toggleAttribute('data-need-warn-exclusive', !elExclusiveInput.checked && numIssues > 0);  | 
 | 51 | +    elModal.querySelector('.header').textContent = isEdit ? elModal.getAttribute('data-text-edit-label') : elModal.getAttribute('data-text-new-label');  | 
70 | 52 | 
 
  | 
71 |  | -    $('.edit-label.modal').modal({  | 
 | 53 | +    const curPageLink = elModal.getAttribute('data-current-page-link');  | 
 | 54 | +    form.action = isEdit ? `${curPageLink}/edit` : `${curPageLink}/new`;  | 
 | 55 | +    toggleElem(elIsArchivedField, isEdit);  | 
 | 56 | +    syncModalUi();  | 
 | 57 | +    fomanticQuery(elModal).modal({  | 
72 | 58 |       onApprove() {  | 
73 |  | -        const form = document.querySelector('.edit-label.form');  | 
74 | 59 |         if (!form.checkValidity()) {  | 
75 | 60 |           form.reportValidity();  | 
76 | 61 |           return false;  | 
77 | 62 |         }  | 
78 |  | -        $('.edit-label.form').trigger('submit');  | 
 | 63 | +        form.submit();  | 
79 | 64 |       },  | 
80 | 65 |     }).modal('show');  | 
81 |  | -    return false;  | 
82 |  | -  });  | 
 | 66 | +  };  | 
83 | 67 | 
 
  | 
84 |  | -  $('.new-label .label-name-input').on('input', () => {  | 
85 |  | -    updateExclusiveLabelEdit('.new-label');  | 
86 |  | -  });  | 
87 |  | -  $('.new-label .label-exclusive-input').on('change', () => {  | 
88 |  | -    updateExclusiveLabelEdit('.new-label');  | 
89 |  | -  });  | 
90 |  | -  $('.edit-label .label-name-input').on('input', () => {  | 
91 |  | -    updateExclusiveLabelEdit('.edit-label');  | 
92 |  | -  });  | 
93 |  | -  $('.edit-label .label-exclusive-input').on('change', () => {  | 
94 |  | -    updateExclusiveLabelEdit('.edit-label');  | 
95 |  | -  });  | 
 | 68 | +  elModal.addEventListener('input', () => syncModalUi());  | 
 | 69 | + | 
 | 70 | +  // theoretically, if the modal exists, the "new label" button should also exist, just in case it doesn't, use "?."  | 
 | 71 | +  const elNewLabel = pageContent.querySelector<HTMLElement>('.ui.button.new-label');  | 
 | 72 | +  elNewLabel?.addEventListener('click', () => showLabelEditModal(elNewLabel));  | 
 | 73 | + | 
 | 74 | +  const elEditLabelButtons = pageContent.querySelectorAll<HTMLElement>('.edit-label-button');  | 
 | 75 | +  for (const btn of elEditLabelButtons) {  | 
 | 76 | +    btn.addEventListener('click', (e) => {  | 
 | 77 | +      e.preventDefault();  | 
 | 78 | +      showLabelEditModal(btn);  | 
 | 79 | +    });  | 
 | 80 | +  }  | 
96 | 81 | }  | 
0 commit comments