2024-07-07 18:32:30 +03:00
import { stripTags } from '../utils.ts' ;
import { hideElem , queryElemChildren , showElem } from '../utils/dom.ts' ;
import { POST } from '../modules/fetch.ts' ;
import { showErrorToast } from '../modules/toast.ts' ;
2024-11-14 21:48:41 +03:00
import { fomanticQuery } from '../modules/fomantic/base.ts' ;
2021-10-16 20:28:04 +03:00
2024-03-02 12:29:04 +03:00
const { appSubUrl } = window . config ;
2021-10-16 20:28:04 +03:00
export function initRepoTopicBar() {
2024-12-06 17:29:04 +03:00
const mgrBtn = document . querySelector < HTMLButtonElement > ( '#manage_topic' ) ;
2024-03-25 02:44:05 +03:00
if ( ! mgrBtn ) return ;
2024-03-31 18:39:50 +03:00
2024-06-10 23:49:33 +03:00
const editDiv = document . querySelector ( '#topic_edit' ) ;
const viewDiv = document . querySelector ( '#repo-topics' ) ;
2024-03-31 18:39:50 +03:00
const topicDropdown = editDiv . querySelector ( '.ui.dropdown' ) ;
let lastErrorToast ;
2021-10-16 20:28:04 +03:00
2024-03-25 02:44:05 +03:00
mgrBtn . addEventListener ( 'click' , ( ) = > {
hideElem ( viewDiv ) ;
showElem ( editDiv ) ;
2024-12-06 17:29:04 +03:00
topicDropdown . querySelector < HTMLInputElement > ( 'input.search' ) . focus ( ) ;
2021-10-16 20:28:04 +03:00
} ) ;
2024-03-31 18:39:50 +03:00
document . querySelector ( '#cancel_topic_edit' ) . addEventListener ( 'click' , ( ) = > {
lastErrorToast ? . hideToast ( ) ;
2024-03-25 02:44:05 +03:00
hideElem ( editDiv ) ;
showElem ( viewDiv ) ;
mgrBtn . focus ( ) ;
Fine tune more downdrop settings, use SVG for labels, improve Repo Topic Edit form (#23626)
Although it seems that some different purposes are mixed in this PR,
however, they are all related, and can be tested together, so I put them
together to save everyone's time.
Diff: `+79 −84`, everything becomes much better.
### Improve the dropdown settings.
Move all fomantic-init related code into our `fomantic.js`
Fine-tune some dropdown global settings, see the comments.
Also help to fix the first problem in #23625 , cc: @yp05327
The "language" menu has been simplified, and it works with small-height
window better.
### Use SVG instead of `<i class="delete icon">`
It's also done by `$.fn.dropdown.settings.templates.label` , cc:
@silverwind
### Remove incorrect `tabable` CSS class
It doesn't have CSS styles, and it was only in Vue. So it's totally
unnecessary, remove it by the way.
### Improve the Repo Topic Edit form
* Simplify the code
* Add a "Cancel" button
* Align elements
Before:
<details>
![image](https://user-images.githubusercontent.com/2114189/223325782-f09532de-0c38-4742-ba86-ed35cc9a858d.png)
</details>
After:
![image](https://user-images.githubusercontent.com/2114189/226796347-207feb0a-b3cd-4820-8a3e-01930bab1069.png)
2023-03-26 14:31:26 +03:00
} ) ;
2021-10-16 20:28:04 +03:00
2024-12-06 17:29:04 +03:00
document . querySelector ( '#save_topic' ) . addEventListener ( 'click' , async ( e : MouseEvent & { target : HTMLButtonElement } ) = > {
2024-03-31 18:39:50 +03:00
lastErrorToast ? . hideToast ( ) ;
2024-12-06 17:29:04 +03:00
const topics = editDiv . querySelector < HTMLInputElement > ( 'input[name=topics]' ) . value ;
2021-10-16 20:28:04 +03:00
2024-03-02 12:29:04 +03:00
const data = new FormData ( ) ;
data . append ( 'topics' , topics ) ;
2024-03-31 18:39:50 +03:00
const response = await POST ( e . target . getAttribute ( 'data-link' ) , { data } ) ;
2024-03-02 12:29:04 +03:00
if ( response . ok ) {
const responseData = await response . json ( ) ;
if ( responseData . status === 'ok' ) {
2024-03-31 18:39:50 +03:00
queryElemChildren ( viewDiv , '.repo-topic' , ( el ) = > el . remove ( ) ) ;
2021-10-16 20:28:04 +03:00
if ( topics . length ) {
const topicArray = topics . split ( ',' ) ;
2023-04-14 22:29:05 +03:00
topicArray . sort ( ) ;
2024-03-02 12:29:04 +03:00
for ( const topic of topicArray ) {
2024-12-06 17:29:04 +03:00
// TODO: sort items in topicDropdown, or items in edit div will have different order to the items in view div
// !!!! it SHOULD and MUST match the code in "home_sidebar_top.tmpl" !!!!
2024-03-25 02:44:05 +03:00
const link = document . createElement ( 'a' ) ;
2024-12-06 17:29:04 +03:00
link . classList . add ( 'repo-topic' , 'ui' , 'large' , 'label' , 'gt-ellipsis' ) ;
2024-03-25 02:44:05 +03:00
link . href = ` ${ appSubUrl } /explore/repos?q= ${ encodeURIComponent ( topic ) } &topic=1 ` ;
link . textContent = topic ;
2024-12-06 17:29:04 +03:00
viewDiv . append ( link ) ;
2021-10-16 20:28:04 +03:00
}
}
2024-03-25 02:44:05 +03:00
hideElem ( editDiv ) ;
showElem ( viewDiv ) ;
2021-10-16 20:28:04 +03:00
}
2024-03-02 12:29:04 +03:00
} else if ( response . status === 422 ) {
2024-03-31 18:39:50 +03:00
// how to test: input topic like " invalid topic " (with spaces), and select it from the list, then "Save"
2024-03-02 12:29:04 +03:00
const responseData = await response . json ( ) ;
2024-03-31 18:39:50 +03:00
lastErrorToast = showErrorToast ( responseData . message , { duration : 5000 } ) ;
2024-10-08 20:27:05 +03:00
if ( responseData . invalidTopics && responseData . invalidTopics . length > 0 ) {
2024-03-02 12:29:04 +03:00
const { invalidTopics } = responseData ;
2024-03-31 18:39:50 +03:00
const topicLabels = queryElemChildren ( topicDropdown , 'a.ui.label' ) ;
2024-03-02 12:29:04 +03:00
for ( const [ index , value ] of topics . split ( ',' ) . entries ( ) ) {
if ( invalidTopics . includes ( value ) ) {
2024-03-31 18:39:50 +03:00
topicLabels [ index ] . classList . remove ( 'green' ) ;
topicLabels [ index ] . classList . add ( 'red' ) ;
2021-11-22 11:19:01 +03:00
}
2021-10-16 20:28:04 +03:00
}
}
2024-03-02 12:29:04 +03:00
}
2021-10-16 20:28:04 +03:00
} ) ;
2024-11-14 21:48:41 +03:00
fomanticQuery ( topicDropdown ) . dropdown ( {
2021-10-16 20:28:04 +03:00
allowAdditions : true ,
forceSelection : false ,
fullTextSearch : 'exact' ,
fields : { name : 'description' , value : 'data-value' } ,
saveRemoteData : false ,
label : {
transition : 'horizontal flip' ,
duration : 200 ,
variation : false ,
} ,
apiSettings : {
2022-04-07 21:59:56 +03:00
url : ` ${ appSubUrl } /explore/topics/search?q={query} ` ,
2021-10-16 20:28:04 +03:00
throttle : 500 ,
cache : false ,
onResponse ( res ) {
const formattedResponse = {
success : false ,
results : [ ] ,
} ;
const query = stripTags ( this . urlData . query . trim ( ) ) ;
let found_query = false ;
const current_topics = [ ] ;
2024-03-31 18:39:50 +03:00
for ( const el of queryElemChildren ( topicDropdown , 'a.ui.label.visible' ) ) {
2021-11-22 11:19:01 +03:00
current_topics . push ( el . getAttribute ( 'data-value' ) ) ;
2024-03-31 18:39:50 +03:00
}
2021-10-16 20:28:04 +03:00
if ( res . topics ) {
let found = false ;
2024-07-03 18:48:14 +03:00
for ( const { topic_name } of res . topics ) {
2021-10-16 20:28:04 +03:00
// skip currently added tags
2024-07-03 18:48:14 +03:00
if ( current_topics . includes ( topic_name ) ) {
2021-10-16 20:28:04 +03:00
continue ;
}
2024-07-03 18:48:14 +03:00
if ( topic_name . toLowerCase ( ) === query . toLowerCase ( ) ) {
2021-10-16 20:28:04 +03:00
found_query = true ;
}
2024-07-03 18:48:14 +03:00
formattedResponse . results . push ( { description : topic_name , 'data-value' : topic_name } ) ;
2021-10-16 20:28:04 +03:00
found = true ;
}
formattedResponse . success = found ;
}
if ( query . length > 0 && ! found_query ) {
formattedResponse . success = true ;
formattedResponse . results . unshift ( { description : query , 'data-value' : query } ) ;
} else if ( query . length > 0 && found_query ) {
formattedResponse . results . sort ( ( a , b ) = > {
if ( a . description . toLowerCase ( ) === query . toLowerCase ( ) ) return - 1 ;
if ( b . description . toLowerCase ( ) === query . toLowerCase ( ) ) return 1 ;
if ( a . description > b . description ) return - 1 ;
if ( a . description < b . description ) return 1 ;
return 0 ;
} ) ;
}
return formattedResponse ;
} ,
} ,
onLabelCreate ( value ) {
value = value . toLowerCase ( ) . trim ( ) ;
this . attr ( 'data-value' , value ) . contents ( ) . first ( ) . replaceWith ( value ) ;
2024-11-14 21:48:41 +03:00
return fomanticQuery ( this ) ;
2021-10-16 20:28:04 +03:00
} ,
onAdd ( addedValue , _addedText , $addedChoice ) {
addedValue = addedValue . toLowerCase ( ) . trim ( ) ;
2024-03-31 18:39:50 +03:00
$addedChoice [ 0 ] . setAttribute ( 'data-value' , addedValue ) ;
$addedChoice [ 0 ] . setAttribute ( 'data-text' , addedValue ) ;
2024-03-22 17:06:53 +03:00
} ,
2021-10-16 20:28:04 +03:00
} ) ;
}