|
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