11document . addEventListener ( 'DOMContentLoaded' , function ( ) {
22 // only load on open issues page for now
3- var issueSelect = document . querySelector ( ".open-issues select " ) ;
3+ var issueSelect = document . querySelector ( ".open-issues #label-filter " ) ;
44 if ( ! issueSelect ) {
55 return ;
66 }
77
8- issueSelect . onchange = issueSelectHandler ;
8+ issueSelect . onchange = function ( event ) {
9+ issueSelectHandler ( event ) ;
10+ applySorting ( ) ;
11+ } ;
12+
13+ var sortSelect = document . querySelector ( ".open-issues #sort-order" ) ;
14+ if ( sortSelect ) {
15+ sortSelect . onchange = function ( ) {
16+ applySorting ( ) ;
17+ } ;
18+ }
919
1020 // load issues label when using back button
1121 window . addEventListener ( 'popstate' , loadIssues . bind ( null , true ) ) ;
@@ -17,27 +27,35 @@ document.addEventListener('DOMContentLoaded', function() {
1727function loadIssues ( isPopState ) {
1828 var params = new URLSearchParams ( window . location . search ) ;
1929 var label = params . get ( 'label' ) ;
30+ var sort = params . get ( 'sort' ) ;
2031
21- if ( ! label ) {
22- return ;
32+ if ( sort ) {
33+ var sortSelect = document . querySelector ( '.open-issues #sort-order' ) ;
34+ if ( sortSelect ) {
35+ sortSelect . value = sort ;
36+ }
37+ }
38+
39+ if ( label ) {
40+ issueSelectHandler ( label , isPopState ) ;
41+ var issuesList = document . querySelector ( '.open-issues #label-filter' ) ;
42+ issuesList . value = label ;
2343 }
2444
25- issueSelectHandler ( label , isPopState ) ;
26- var issuesList = document . querySelector ( '.open-issues select' ) ;
27- issuesList . value = label ;
45+ applySorting ( ) ;
2846}
2947
3048function issueSelectHandler ( event , isPopState ) {
3149 if ( event . target ) {
32- var selectedOption = this . options [ this . selectedIndex ] . value ;
50+ var selectedOption = event . target . options [ event . target . selectedIndex ] . value ;
3351 } else {
3452 // page loads will set the event as just the selected label from params
3553 var selectedOption = event ;
3654 }
3755
3856 // don't set params on the back button
3957 if ( ! isPopState ) {
40- setIssueParams ( selectedOption ) ;
58+ setParams ( ) ;
4159 }
4260
4361 // hide all elements first
@@ -47,17 +65,150 @@ function issueSelectHandler(event, isPopState) {
4765 } ) ;
4866
4967 // show the selected options
50- var selectedOption = selectedOption === 'all' ? 'li' : `. ${ selectedOption } ` ;
51- var items = document . querySelectorAll ( ` .issues-list ${ selectedOption } ` ) ;
68+ var selector = selectedOption === 'all' ? 'li' : '.' + selectedOption ;
69+ var items = document . querySelectorAll ( ' .issues-list ' + selector ) ;
5270 items . forEach ( function ( item ) {
53- item . style . display = 'block'
71+ item . style . display = 'block' ;
5472 item . parentElement . closest ( 'li' ) . style . display = 'block' ;
5573 } ) ;
5674}
5775
58- function setIssueParams ( label ) {
76+ function getIssueDays ( element ) {
77+ return parseInt ( element . dataset . daysOpen , 10 ) || 0 ;
78+ }
79+
80+ function applySorting ( ) {
81+ var sortSelect = document . querySelector ( '.open-issues #sort-order' ) ;
82+ if ( ! sortSelect ) return ;
83+
84+ var sortOrder = sortSelect . value ;
85+ if ( sortOrder === 'default' ) {
86+ // Restore original order by reloading — but simpler to just not sort
87+ // We store original order on first run
88+ restoreOriginalOrder ( ) ;
89+ setParams ( ) ;
90+ return ;
91+ }
92+
93+ // Sort issues within each library's issues-list
94+ var issuesLists = document . querySelectorAll ( '.issues-list' ) ;
95+ issuesLists . forEach ( function ( list ) {
96+ var items = Array . from ( list . querySelectorAll ( ':scope > li' ) ) ;
97+
98+ // Store original order if not already stored
99+ if ( ! list . dataset . originalOrder ) {
100+ list . dataset . originalOrder = 'stored' ;
101+ items . forEach ( function ( item , index ) {
102+ item . dataset . originalIndex = index ;
103+ } ) ;
104+ }
105+
106+ items . sort ( function ( a , b ) {
107+ var daysA = getIssueDays ( a ) ;
108+ var daysB = getIssueDays ( b ) ;
109+ if ( sortOrder === 'newest' ) {
110+ return daysA - daysB ; // fewer days = newer = first
111+ } else {
112+ return daysB - daysA ; // more days = older = first
113+ }
114+ } ) ;
115+
116+ // Re-append in sorted order
117+ items . forEach ( function ( item ) {
118+ list . appendChild ( item ) ;
119+ } ) ;
120+ } ) ;
121+
122+ // Sort the library groups by their best matching issue
123+ var topList = document . getElementById ( 'libraries-list' ) ;
124+ if ( topList ) {
125+ var libraryItems = Array . from ( topList . querySelectorAll ( ':scope > li' ) ) ;
126+
127+ if ( ! topList . dataset . originalOrder ) {
128+ topList . dataset . originalOrder = 'stored' ;
129+ libraryItems . forEach ( function ( item , index ) {
130+ item . dataset . originalIndex = index ;
131+ } ) ;
132+ }
133+
134+ libraryItems . sort ( function ( a , b ) {
135+ var bestA = getBestDays ( a . querySelectorAll ( '.issues-list > li' ) , sortOrder ) ;
136+ var bestB = getBestDays ( b . querySelectorAll ( '.issues-list > li' ) , sortOrder ) ;
137+ if ( sortOrder === 'newest' ) {
138+ return bestA - bestB ;
139+ } else {
140+ return bestB - bestA ;
141+ }
142+ } ) ;
143+
144+ libraryItems . forEach ( function ( item ) {
145+ topList . appendChild ( item ) ;
146+ } ) ;
147+ }
148+
149+ setParams ( ) ;
150+ }
151+
152+ function getBestDays ( issues , sortOrder ) {
153+ var result = sortOrder === 'newest' ? Infinity : 0 ;
154+ issues . forEach ( function ( issue ) {
155+ var days = getIssueDays ( issue ) ;
156+ if ( sortOrder === 'newest' ) {
157+ result = Math . min ( result , days ) ;
158+ } else {
159+ result = Math . max ( result , days ) ;
160+ }
161+ } ) ;
162+ return result === Infinity ? 0 : result ;
163+ }
164+
165+ function restoreOriginalOrder ( ) {
166+ // Restore library-level order
167+ var topList = document . getElementById ( 'libraries-list' ) ;
168+ if ( topList && topList . dataset . originalOrder ) {
169+ var libraryItems = Array . from ( topList . querySelectorAll ( ':scope > li' ) ) ;
170+ libraryItems . sort ( function ( a , b ) {
171+ return ( parseInt ( a . dataset . originalIndex ) || 0 ) - ( parseInt ( b . dataset . originalIndex ) || 0 ) ;
172+ } ) ;
173+ libraryItems . forEach ( function ( item ) {
174+ topList . appendChild ( item ) ;
175+ } ) ;
176+ }
177+
178+ // Restore issue-level order within each list
179+ var issuesLists = document . querySelectorAll ( '.issues-list' ) ;
180+ issuesLists . forEach ( function ( list ) {
181+ var items = Array . from ( list . querySelectorAll ( ':scope > li' ) ) ;
182+ items . sort ( function ( a , b ) {
183+ return ( parseInt ( a . dataset . originalIndex ) || 0 ) - ( parseInt ( b . dataset . originalIndex ) || 0 ) ;
184+ } ) ;
185+ items . forEach ( function ( item ) {
186+ list . appendChild ( item ) ;
187+ } ) ;
188+ } ) ;
189+ }
190+
191+ function setParams ( ) {
59192 var params = new URLSearchParams ( window . location . search ) ;
60- params . set ( "label" , label ) ;
61- var newUrl = `${ window . location . protocol } //${ window . location . host } ${ window . location . pathname } ?${ params . toString ( ) } ` ;
62- window . history . pushState ( { path :newUrl } , '' , newUrl ) ;
193+
194+ var labelSelect = document . querySelector ( '.open-issues #label-filter' ) ;
195+ if ( labelSelect && labelSelect . value && labelSelect . value !== 'all' ) {
196+ params . set ( "label" , labelSelect . value ) ;
197+ } else {
198+ params . delete ( "label" ) ;
199+ }
200+
201+ var sortSelect = document . querySelector ( '.open-issues #sort-order' ) ;
202+ if ( sortSelect && sortSelect . value && sortSelect . value !== 'default' ) {
203+ params . set ( "sort" , sortSelect . value ) ;
204+ } else {
205+ params . delete ( "sort" ) ;
206+ }
207+
208+ var query = params . toString ( ) ;
209+ var newUrl = window . location . protocol + '//' + window . location . host + window . location . pathname ;
210+ if ( query ) {
211+ newUrl += '?' + query ;
212+ }
213+ window . history . pushState ( { path : newUrl } , '' , newUrl ) ;
63214}
0 commit comments