@@ -7,142 +7,144 @@ import {showErrorToast} from '../modules/toast.ts';
77const { appSubUrl} = window . config ;
88
99export function initRepoTopicBar ( ) {
10- const mgrBtn = document . querySelector ( '#manage_topic' ) ;
11- if ( ! mgrBtn ) return ;
10+ const mgrBtns = document . querySelectorAll ( '#manage_topic' ) ;
11+ if ( mgrBtns . length === 0 ) return ;
1212
13- const editDiv = document . querySelector ( '#topic_edit' ) ;
14- const viewDiv = document . querySelector ( '#repo-topics' ) ;
15- const topicDropdown = editDiv . querySelector ( '.ui.dropdown' ) ;
16- let lastErrorToast ;
13+ for ( const mgrBtn of mgrBtns ) {
14+ const editDiv = mgrBtn . parentNode . querySelector ( '#topic_edit' ) ;
15+ const viewDiv = mgrBtn . parentNode . querySelector ( '#repo-topics' ) ;
16+ const topicDropdown = editDiv . querySelector ( '.ui.dropdown' ) ;
17+ let lastErrorToast ;
1718
18- mgrBtn . addEventListener ( 'click' , ( ) => {
19- hideElem ( viewDiv ) ;
20- showElem ( editDiv ) ;
21- topicDropdown . querySelector ( 'input.search' ) . focus ( ) ;
22- } ) ;
19+ mgrBtn . addEventListener ( 'click' , ( ) => {
20+ hideElem ( viewDiv ) ;
21+ showElem ( editDiv ) ;
22+ topicDropdown . querySelector ( 'input.search' ) . focus ( ) ;
23+ } ) ;
2324
24- document . querySelector ( '#cancel_topic_edit' ) . addEventListener ( 'click' , ( ) => {
25- lastErrorToast ?. hideToast ( ) ;
26- hideElem ( editDiv ) ;
27- showElem ( viewDiv ) ;
28- mgrBtn . focus ( ) ;
29- } ) ;
25+ mgrBtn . parentNode . querySelector ( '#cancel_topic_edit' ) . addEventListener ( 'click' , ( ) => {
26+ lastErrorToast ?. hideToast ( ) ;
27+ hideElem ( editDiv ) ;
28+ showElem ( viewDiv ) ;
29+ mgrBtn . focus ( ) ;
30+ } ) ;
3031
31- document . querySelector ( '#save_topic' ) . addEventListener ( 'click' , async ( e ) => {
32- lastErrorToast ?. hideToast ( ) ;
33- const topics = editDiv . querySelector ( 'input[name=topics]' ) . value ;
32+ mgrBtn . parentNode . querySelector ( '#save_topic' ) . addEventListener ( 'click' , async ( e ) => {
33+ lastErrorToast ?. hideToast ( ) ;
34+ const topics = editDiv . querySelector ( 'input[name=topics]' ) . value ;
3435
35- const data = new FormData ( ) ;
36- data . append ( 'topics' , topics ) ;
36+ const data = new FormData ( ) ;
37+ data . append ( 'topics' , topics ) ;
3738
38- const response = await POST ( e . target . getAttribute ( 'data-link' ) , { data} ) ;
39+ const response = await POST ( e . target . getAttribute ( 'data-link' ) , { data} ) ;
3940
40- if ( response . ok ) {
41- const responseData = await response . json ( ) ;
42- if ( responseData . status === 'ok' ) {
43- queryElemChildren ( viewDiv , '.repo-topic' , ( el ) => el . remove ( ) ) ;
44- if ( topics . length ) {
45- const topicArray = topics . split ( ',' ) ;
46- topicArray . sort ( ) ;
47- for ( const topic of topicArray ) {
48- // it should match the code in repo/home.tmpl
49- // TODO: sort items in topicDropdown, or items in edit div will have different order to the items in view div
50- const link = document . createElement ( 'a' ) ;
51- link . classList . add ( 'repo-topic' , 'ui' , 'large' , 'label' ) ;
52- link . href = `${ appSubUrl } /explore/repos?q=${ encodeURIComponent ( topic ) } &topic=1` ;
53- link . textContent = topic ;
54- viewDiv . append ( link ) ;
41+ if ( response . ok ) {
42+ const responseData = await response . json ( ) ;
43+ if ( responseData . status === 'ok' ) {
44+ queryElemChildren ( viewDiv , '.repo-topic' , ( el ) => el . remove ( ) ) ;
45+ if ( topics . length ) {
46+ const topicArray = topics . split ( ',' ) ;
47+ topicArray . sort ( ) ;
48+ for ( const topic of topicArray ) {
49+ // it should match the code in repo/home.tmpl
50+ // TODO: sort items in topicDropdown, or items in edit div will have different order to the items in view div
51+ const link = document . createElement ( 'a' ) ;
52+ link . classList . add ( 'repo-topic' , 'ui' , 'large' , 'label' ) ;
53+ link . href = `${ appSubUrl } /explore/repos?q=${ encodeURIComponent ( topic ) } &topic=1` ;
54+ link . textContent = topic ;
55+ viewDiv . append ( link ) ;
56+ }
5557 }
58+ hideElem ( editDiv ) ;
59+ showElem ( viewDiv ) ;
5660 }
57- hideElem ( editDiv ) ;
58- showElem ( viewDiv ) ;
59- }
60- } else if ( response . status === 422 ) {
61- // how to test: input topic like " invalid topic " (with spaces), and select it from the list, then "Save"
62- const responseData = await response . json ( ) ;
63- lastErrorToast = showErrorToast ( responseData . message , { duration : 5000 } ) ;
64- if ( responseData . invalidTopics && responseData . invalidTopics . length > 0 ) {
65- const { invalidTopics} = responseData ;
66- const topicLabels = queryElemChildren ( topicDropdown , 'a.ui.label' ) ;
67- for ( const [ index , value ] of topics . split ( ',' ) . entries ( ) ) {
68- if ( invalidTopics . includes ( value ) ) {
69- topicLabels [ index ] . classList . remove ( 'green' ) ;
70- topicLabels [ index ] . classList . add ( 'red' ) ;
61+ } else if ( response . status === 422 ) {
62+ // how to test: input topic like " invalid topic " (with spaces), and select it from the list, then "Save"
63+ const responseData = await response . json ( ) ;
64+ lastErrorToast = showErrorToast ( responseData . message , { duration : 5000 } ) ;
65+ if ( responseData . invalidTopics && responseData . invalidTopics . length > 0 ) {
66+ const { invalidTopics} = responseData ;
67+ const topicLabels = queryElemChildren ( topicDropdown , 'a.ui.label' ) ;
68+ for ( const [ index , value ] of topics . split ( ',' ) . entries ( ) ) {
69+ if ( invalidTopics . includes ( value ) ) {
70+ topicLabels [ index ] . classList . remove ( 'green' ) ;
71+ topicLabels [ index ] . classList . add ( 'red' ) ;
72+ }
7173 }
7274 }
7375 }
74- }
75- } ) ;
76+ } ) ;
7677
77- $ ( topicDropdown ) . dropdown ( {
78- allowAdditions : true ,
79- forceSelection : false ,
80- fullTextSearch : 'exact' ,
81- fields : { name : 'description' , value : 'data-value' } ,
82- saveRemoteData : false ,
83- label : {
84- transition : 'horizontal flip' ,
85- duration : 200 ,
86- variation : false ,
87- } ,
88- apiSettings : {
89- url : `${ appSubUrl } /explore/topics/search?q={query}` ,
90- throttle : 500 ,
91- cache : false ,
92- onResponse ( res ) {
93- const formattedResponse = {
94- success : false ,
95- results : [ ] ,
96- } ;
97- const query = stripTags ( this . urlData . query . trim ( ) ) ;
98- let found_query = false ;
99- const current_topics = [ ] ;
100- for ( const el of queryElemChildren ( topicDropdown , 'a.ui.label.visible' ) ) {
101- current_topics . push ( el . getAttribute ( 'data-value' ) ) ;
102- }
78+ $ ( topicDropdown ) . dropdown ( {
79+ allowAdditions : true ,
80+ forceSelection : false ,
81+ fullTextSearch : 'exact' ,
82+ fields : { name : 'description' , value : 'data-value' } ,
83+ saveRemoteData : false ,
84+ label : {
85+ transition : 'horizontal flip' ,
86+ duration : 200 ,
87+ variation : false ,
88+ } ,
89+ apiSettings : {
90+ url : `${ appSubUrl } /explore/topics/search?q={query}` ,
91+ throttle : 500 ,
92+ cache : false ,
93+ onResponse ( res ) {
94+ const formattedResponse = {
95+ success : false ,
96+ results : [ ] ,
97+ } ;
98+ const query = stripTags ( this . urlData . query . trim ( ) ) ;
99+ let found_query = false ;
100+ const current_topics = [ ] ;
101+ for ( const el of queryElemChildren ( topicDropdown , 'a.ui.label.visible' ) ) {
102+ current_topics . push ( el . getAttribute ( 'data-value' ) ) ;
103+ }
103104
104- if ( res . topics ) {
105- let found = false ;
106- for ( const { topic_name} of res . topics ) {
107- // skip currently added tags
108- if ( current_topics . includes ( topic_name ) ) {
109- continue ;
110- }
105+ if ( res . topics ) {
106+ let found = false ;
107+ for ( const { topic_name} of res . topics ) {
108+ // skip currently added tags
109+ if ( current_topics . includes ( topic_name ) ) {
110+ continue ;
111+ }
111112
112- if ( topic_name . toLowerCase ( ) === query . toLowerCase ( ) ) {
113- found_query = true ;
113+ if ( topic_name . toLowerCase ( ) === query . toLowerCase ( ) ) {
114+ found_query = true ;
115+ }
116+ formattedResponse . results . push ( { description : topic_name , 'data-value' : topic_name } ) ;
117+ found = true ;
114118 }
115- formattedResponse . results . push ( { description : topic_name , 'data-value' : topic_name } ) ;
116- found = true ;
119+ formattedResponse . success = found ;
117120 }
118- formattedResponse . success = found ;
119- }
120121
121- if ( query . length > 0 && ! found_query ) {
122- formattedResponse . success = true ;
123- formattedResponse . results . unshift ( { description : query , 'data-value' : query } ) ;
124- } else if ( query . length > 0 && found_query ) {
125- formattedResponse . results . sort ( ( a , b ) => {
126- if ( a . description . toLowerCase ( ) === query . toLowerCase ( ) ) return - 1 ;
127- if ( b . description . toLowerCase ( ) === query . toLowerCase ( ) ) return 1 ;
128- if ( a . description > b . description ) return - 1 ;
129- if ( a . description < b . description ) return 1 ;
130- return 0 ;
131- } ) ;
132- }
122+ if ( query . length > 0 && ! found_query ) {
123+ formattedResponse . success = true ;
124+ formattedResponse . results . unshift ( { description : query , 'data-value' : query } ) ;
125+ } else if ( query . length > 0 && found_query ) {
126+ formattedResponse . results . sort ( ( a , b ) => {
127+ if ( a . description . toLowerCase ( ) === query . toLowerCase ( ) ) return - 1 ;
128+ if ( b . description . toLowerCase ( ) === query . toLowerCase ( ) ) return 1 ;
129+ if ( a . description > b . description ) return - 1 ;
130+ if ( a . description < b . description ) return 1 ;
131+ return 0 ;
132+ } ) ;
133+ }
133134
134- return formattedResponse ;
135+ return formattedResponse ;
136+ } ,
137+ } ,
138+ onLabelCreate ( value ) {
139+ value = value . toLowerCase ( ) . trim ( ) ;
140+ this . attr ( 'data-value' , value ) . contents ( ) . first ( ) . replaceWith ( value ) ;
141+ return $ ( this ) ;
142+ } ,
143+ onAdd ( addedValue , _addedText , $addedChoice ) {
144+ addedValue = addedValue . toLowerCase ( ) . trim ( ) ;
145+ $addedChoice [ 0 ] . setAttribute ( 'data-value' , addedValue ) ;
146+ $addedChoice [ 0 ] . setAttribute ( 'data-text' , addedValue ) ;
135147 } ,
136- } ,
137- onLabelCreate ( value ) {
138- value = value . toLowerCase ( ) . trim ( ) ;
139- this . attr ( 'data-value' , value ) . contents ( ) . first ( ) . replaceWith ( value ) ;
140- return $ ( this ) ;
141- } ,
142- onAdd ( addedValue , _addedText , $addedChoice ) {
143- addedValue = addedValue . toLowerCase ( ) . trim ( ) ;
144- $addedChoice [ 0 ] . setAttribute ( 'data-value' , addedValue ) ;
145- $addedChoice [ 0 ] . setAttribute ( 'data-text' , addedValue ) ;
146- } ,
147- } ) ;
148+ } ) ;
149+ }
148150}
0 commit comments