mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Remove most jQuery function calls from the repository topic box (#30191)
Remove most jQuery function calls --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -1,55 +1,53 @@ | ||||
| import $ from 'jquery'; | ||||
| import {stripTags} from '../utils.js'; | ||||
| import {hideElem, showElem} from '../utils/dom.js'; | ||||
| import {hideElem, queryElemChildren, showElem} from '../utils/dom.js'; | ||||
| import {POST} from '../modules/fetch.js'; | ||||
| import {showErrorToast} from '../modules/toast.js'; | ||||
|  | ||||
| const {appSubUrl} = window.config; | ||||
|  | ||||
| export function initRepoTopicBar() { | ||||
|   const mgrBtn = document.getElementById('manage_topic'); | ||||
|   if (!mgrBtn) return; | ||||
|  | ||||
|   const editDiv = document.getElementById('topic_edit'); | ||||
|   const viewDiv = document.getElementById('repo-topics'); | ||||
|   const saveBtn = document.getElementById('save_topic'); | ||||
|   const topicDropdown = editDiv.querySelector('.dropdown'); | ||||
|   const $topicDropdown = $(topicDropdown); | ||||
|   const $topicForm = $(editDiv); | ||||
|   const $topicDropdownSearch = $topicDropdown.find('input.search'); | ||||
|   const topicPrompts = { | ||||
|     countPrompt: topicDropdown.getAttribute('data-text-count-prompt') ?? undefined, | ||||
|     formatPrompt: topicDropdown.getAttribute('data-text-format-prompt') ?? undefined, | ||||
|   }; | ||||
|   const topicDropdown = editDiv.querySelector('.ui.dropdown'); | ||||
|   let lastErrorToast; | ||||
|  | ||||
|   mgrBtn.addEventListener('click', () => { | ||||
|     hideElem(viewDiv); | ||||
|     showElem(editDiv); | ||||
|     $topicDropdownSearch.trigger('focus'); | ||||
|     topicDropdown.querySelector('input.search').focus(); | ||||
|   }); | ||||
|  | ||||
|   $('#cancel_topic_edit').on('click', () => { | ||||
|   document.querySelector('#cancel_topic_edit').addEventListener('click', () => { | ||||
|     lastErrorToast?.hideToast(); | ||||
|     hideElem(editDiv); | ||||
|     showElem(viewDiv); | ||||
|     mgrBtn.focus(); | ||||
|   }); | ||||
|  | ||||
|   saveBtn.addEventListener('click', async () => { | ||||
|     const topics = $('input[name=topics]').val(); | ||||
|   document.getElementById('save_topic').addEventListener('click', async (e) => { | ||||
|     lastErrorToast?.hideToast(); | ||||
|     const topics = editDiv.querySelector('input[name=topics]').value; | ||||
|  | ||||
|     const data = new FormData(); | ||||
|     data.append('topics', topics); | ||||
|  | ||||
|     const response = await POST(saveBtn.getAttribute('data-link'), {data}); | ||||
|     const response = await POST(e.target.getAttribute('data-link'), {data}); | ||||
|  | ||||
|     if (response.ok) { | ||||
|       const responseData = await response.json(); | ||||
|       if (responseData.status === 'ok') { | ||||
|         $(viewDiv).children('.topic').remove(); | ||||
|         queryElemChildren(viewDiv, '.repo-topic', (el) => el.remove()); | ||||
|         if (topics.length) { | ||||
|           const topicArray = topics.split(','); | ||||
|           topicArray.sort(); | ||||
|           for (const topic of topicArray) { | ||||
|             // it should match the code in repo/home.tmpl | ||||
|             const link = document.createElement('a'); | ||||
|             link.classList.add('ui', 'repo-topic', 'large', 'label', 'topic', 'tw-m-0'); | ||||
|             link.classList.add('repo-topic', 'ui', 'large', 'label'); | ||||
|             link.href = `${appSubUrl}/explore/repos?q=${encodeURIComponent(topic)}&topic=1`; | ||||
|             link.textContent = topic; | ||||
|             mgrBtn.parentNode.insertBefore(link, mgrBtn); // insert all new topics before manage button | ||||
| @@ -59,27 +57,23 @@ export function initRepoTopicBar() { | ||||
|         showElem(viewDiv); | ||||
|       } | ||||
|     } else if (response.status === 422) { | ||||
|       // how to test: input topic like " invalid topic " (with spaces), and select it from the list, then "Save" | ||||
|       const responseData = await response.json(); | ||||
|       lastErrorToast = showErrorToast(responseData.message, {duration: 5000}); | ||||
|       if (responseData.invalidTopics.length > 0) { | ||||
|         topicPrompts.formatPrompt = responseData.message; | ||||
|  | ||||
|         const {invalidTopics} = responseData; | ||||
|         const $topicLabels = $topicDropdown.children('a.ui.label'); | ||||
|         const topicLabels = queryElemChildren(topicDropdown, 'a.ui.label'); | ||||
|         for (const [index, value] of topics.split(',').entries()) { | ||||
|           if (invalidTopics.includes(value)) { | ||||
|             $topicLabels.eq(index).removeClass('green').addClass('red'); | ||||
|             topicLabels[index].classList.remove('green'); | ||||
|             topicLabels[index].classList.add('red'); | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         topicPrompts.countPrompt = responseData.message; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Always validate the form | ||||
|     $topicForm.form('validate form'); | ||||
|   }); | ||||
|  | ||||
|   $topicDropdown.dropdown({ | ||||
|   $(topicDropdown).dropdown({ | ||||
|     allowAdditions: true, | ||||
|     forceSelection: false, | ||||
|     fullTextSearch: 'exact', | ||||
| @@ -102,9 +96,9 @@ export function initRepoTopicBar() { | ||||
|         const query = stripTags(this.urlData.query.trim()); | ||||
|         let found_query = false; | ||||
|         const current_topics = []; | ||||
|         $topicDropdown.find('a.label.visible').each((_, el) => { | ||||
|         for (const el of queryElemChildren(topicDropdown, 'a.ui.label.visible')) { | ||||
|           current_topics.push(el.getAttribute('data-value')); | ||||
|         }); | ||||
|         } | ||||
|  | ||||
|         if (res.topics) { | ||||
|           let found = false; | ||||
| @@ -146,38 +140,8 @@ export function initRepoTopicBar() { | ||||
|     }, | ||||
|     onAdd(addedValue, _addedText, $addedChoice) { | ||||
|       addedValue = addedValue.toLowerCase().trim(); | ||||
|       $($addedChoice)[0].setAttribute('data-value', addedValue); | ||||
|       $($addedChoice)[0].setAttribute('data-text', addedValue); | ||||
|     }, | ||||
|   }); | ||||
|  | ||||
|   $.fn.form.settings.rules.validateTopic = function (_values, regExp) { | ||||
|     const $topics = $topicDropdown.children('a.ui.label'); | ||||
|     const status = !$topics.length || $topics.last()[0].getAttribute('data-value').match(regExp); | ||||
|     if (!status) { | ||||
|       $topics.last().removeClass('green').addClass('red'); | ||||
|     } | ||||
|     return status && !$topicDropdown.children('a.ui.label.red').length; | ||||
|   }; | ||||
|  | ||||
|   $topicForm.form({ | ||||
|     on: 'change', | ||||
|     inline: true, | ||||
|     fields: { | ||||
|       topics: { | ||||
|         identifier: 'topics', | ||||
|         rules: [ | ||||
|           { | ||||
|             type: 'validateTopic', | ||||
|             value: /^\s*[a-z0-9][-.a-z0-9]{0,35}\s*$/, | ||||
|             prompt: topicPrompts.formatPrompt, | ||||
|           }, | ||||
|           { | ||||
|             type: 'maxCount[25]', | ||||
|             prompt: topicPrompts.countPrompt, | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       $addedChoice[0].setAttribute('data-value', addedValue); | ||||
|       $addedChoice[0].setAttribute('data-text', addedValue); | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
|   | ||||
| @@ -39,6 +39,7 @@ function showToast(message, level, {gravity, position, duration, useHtmlBody, .. | ||||
|  | ||||
|   toast.showToast(); | ||||
|   toast.toastElement.querySelector('.toast-close').addEventListener('click', () => toast.hideToast()); | ||||
|   return toast; | ||||
| } | ||||
|  | ||||
| export function showInfoToast(message, opts) { | ||||
|   | ||||
| @@ -51,8 +51,22 @@ export function isElemHidden(el) { | ||||
|   return res[0]; | ||||
| } | ||||
|  | ||||
| export function queryElemSiblings(el, selector = '*') { | ||||
|   return Array.from(el.parentNode.children).filter((child) => child !== el && child.matches(selector)); | ||||
| function applyElemsCallback(elems, fn) { | ||||
|   if (fn) { | ||||
|     for (const el of elems) { | ||||
|       fn(el); | ||||
|     } | ||||
|   } | ||||
|   return elems; | ||||
| } | ||||
|  | ||||
| export function queryElemSiblings(el, selector = '*', fn) { | ||||
|   return applyElemsCallback(Array.from(el.parentNode.children).filter((child) => child !== el && child.matches(selector)), fn); | ||||
| } | ||||
|  | ||||
| // it works like jQuery.children: only the direct children are selected | ||||
| export function queryElemChildren(parent, selector = '*', fn) { | ||||
|   return applyElemsCallback(parent.querySelectorAll(`:scope > ${selector}`), fn); | ||||
| } | ||||
|  | ||||
| export function onDomReady(cb) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user