1
1
/**
2
- * Copyright (c) 2024, The Linux Foundation.
2
+ * Copyright (c) 2024-2025 , The Linux Foundation.
3
3
* SPDX-License-Identifier: Apache-2.0
4
4
*/
5
5
@@ -29,6 +29,29 @@ function populateFormFromURL() {
29
29
}
30
30
} ) ;
31
31
32
+ // Restore supported features from URL
33
+ if ( hashParams . has ( "features" ) ) {
34
+ const features = hashParams . get ( "features" ) . split ( "," ) ;
35
+ setTimeout ( ( ) => {
36
+ features . forEach ( feature => {
37
+ const tagContainer = document . getElementById ( 'tag-container' ) ;
38
+ const tagInput = document . getElementById ( 'tag-input' ) ;
39
+
40
+ const tagElement = document . createElement ( 'span' ) ;
41
+ tagElement . classList . add ( 'tag' ) ;
42
+ tagElement . textContent = feature ;
43
+ tagElement . onclick = ( ) => {
44
+ const selectedTags = [ ...document . querySelectorAll ( '.tag' ) ] . map ( tag => tag . textContent ) ;
45
+ selectedTags . splice ( selectedTags . indexOf ( feature ) , 1 ) ;
46
+ tagElement . remove ( ) ;
47
+ filterBoards ( ) ;
48
+ } ;
49
+ tagContainer . insertBefore ( tagElement , tagInput ) ;
50
+ } ) ;
51
+ filterBoards ( ) ;
52
+ } , 0 ) ;
53
+ }
54
+
32
55
filterBoards ( ) ;
33
56
}
34
57
@@ -47,6 +70,10 @@ function updateURL() {
47
70
}
48
71
} ) ;
49
72
73
+ // Add supported features to URL
74
+ const selectedTags = [ ...document . querySelectorAll ( '.tag' ) ] . map ( tag => tag . textContent ) ;
75
+ selectedTags . length ? hashParams . set ( "features" , selectedTags . join ( "," ) ) : hashParams . delete ( "features" ) ;
76
+
50
77
window . history . replaceState ( { } , "" , `#${ hashParams . toString ( ) } ` ) ;
51
78
}
52
79
@@ -84,6 +111,81 @@ function fillSocSocSelect(families, series = undefined, selectOnFill = false) {
84
111
} ) ;
85
112
}
86
113
114
+ function setupHWCapabilitiesField ( ) {
115
+ let selectedTags = [ ] ;
116
+
117
+ const tagContainer = document . getElementById ( 'tag-container' ) ;
118
+ const tagInput = document . getElementById ( 'tag-input' ) ;
119
+ const datalist = document . getElementById ( 'tag-list' ) ;
120
+
121
+ const tagCounts = Array . from ( document . querySelectorAll ( '.board-card' ) ) . reduce ( ( acc , board ) => {
122
+ board . getAttribute ( 'data-supported-features' ) . split ( ' ' ) . forEach ( tag => {
123
+ acc [ tag ] = ( acc [ tag ] || 0 ) + 1 ;
124
+ } ) ;
125
+ return acc ;
126
+ } , { } ) ;
127
+
128
+ const allTags = Object . keys ( tagCounts ) . sort ( ) ;
129
+
130
+ function addTag ( tag ) {
131
+ if ( selectedTags . includes ( tag ) || tag === "" || ! allTags . includes ( tag ) ) return ;
132
+ selectedTags . push ( tag ) ;
133
+
134
+ const tagElement = document . createElement ( 'span' ) ;
135
+ tagElement . classList . add ( 'tag' ) ;
136
+ tagElement . textContent = tag ;
137
+ tagElement . onclick = ( ) => removeTag ( tag ) ;
138
+ tagContainer . insertBefore ( tagElement , tagInput ) ;
139
+
140
+ tagInput . value = '' ;
141
+ updateDatalist ( ) ;
142
+ }
143
+
144
+ function removeTag ( tag ) {
145
+ selectedTags = selectedTags . filter ( t => t !== tag ) ;
146
+ document . querySelectorAll ( '.tag' ) . forEach ( el => {
147
+ if ( el . textContent . includes ( tag ) ) el . remove ( ) ;
148
+ } ) ;
149
+ updateDatalist ( ) ;
150
+ }
151
+
152
+ function updateDatalist ( ) {
153
+ datalist . innerHTML = '' ;
154
+ const filteredTags = allTags . filter ( tag => ! selectedTags . includes ( tag ) ) ;
155
+
156
+ filteredTags . forEach ( tag => {
157
+ const option = document . createElement ( 'option' ) ;
158
+ option . value = tag ;
159
+ datalist . appendChild ( option ) ;
160
+ } ) ;
161
+
162
+ filterBoards ( ) ;
163
+ }
164
+
165
+ tagInput . addEventListener ( 'input' , ( ) => {
166
+ if ( allTags . includes ( tagInput . value ) ) {
167
+ addTag ( tagInput . value ) ;
168
+ }
169
+ } ) ;
170
+
171
+ // Add tag when pressing the Enter key
172
+ tagInput . addEventListener ( 'keydown' , ( e ) => {
173
+ if ( e . key === 'Enter' && allTags . includes ( tagInput . value ) ) {
174
+ addTag ( tagInput . value ) ;
175
+ e . preventDefault ( ) ;
176
+ }
177
+ } ) ;
178
+
179
+ // Delete tag when pressing the Backspace key
180
+ tagInput . addEventListener ( 'keydown' , ( e ) => {
181
+ if ( e . key === 'Backspace' && tagInput . value === '' && selectedTags . length > 0 ) {
182
+ removeTag ( selectedTags [ selectedTags . length - 1 ] ) ;
183
+ }
184
+ } ) ;
185
+
186
+ updateDatalist ( ) ;
187
+ }
188
+
87
189
document . addEventListener ( "DOMContentLoaded" , function ( ) {
88
190
const form = document . querySelector ( ".filter-form" ) ;
89
191
@@ -101,9 +203,10 @@ document.addEventListener("DOMContentLoaded", function () {
101
203
fillSocFamilySelect ( ) ;
102
204
fillSocSeriesSelect ( ) ;
103
205
fillSocSocSelect ( ) ;
104
-
105
206
populateFormFromURL ( ) ;
106
207
208
+ setupHWCapabilitiesField ( ) ;
209
+
107
210
socFamilySelect = document . getElementById ( "family" ) ;
108
211
socFamilySelect . addEventListener ( "change" , ( ) => {
109
212
const selectedFamilies = [ ...socFamilySelect . selectedOptions ] . map ( ( { value } ) => value ) ;
@@ -142,6 +245,11 @@ function resetForm() {
142
245
fillSocFamilySelect ( ) ;
143
246
fillSocSeriesSelect ( ) ;
144
247
fillSocSocSelect ( ) ;
248
+
249
+ // Clear supported features
250
+ document . querySelectorAll ( '.tag' ) . forEach ( tag => tag . remove ( ) ) ;
251
+ document . getElementById ( 'tag-input' ) . value = '' ;
252
+
145
253
filterBoards ( ) ;
146
254
}
147
255
@@ -160,8 +268,10 @@ function filterBoards() {
160
268
const vendorSelect = document . getElementById ( "vendor" ) . value ;
161
269
const socSocSelect = document . getElementById ( "soc" ) ;
162
270
271
+ const selectedTags = [ ...document . querySelectorAll ( '.tag' ) ] . map ( tag => tag . textContent ) ;
272
+
163
273
const resetFiltersBtn = document . getElementById ( "reset-filters" ) ;
164
- if ( nameInput || archSelect || vendorSelect || socSocSelect . selectedOptions . length ) {
274
+ if ( nameInput || archSelect || vendorSelect || socSocSelect . selectedOptions . length || selectedTags . length ) {
165
275
resetFiltersBtn . classList . remove ( "btn-disabled" ) ;
166
276
} else {
167
277
resetFiltersBtn . classList . add ( "btn-disabled" ) ;
@@ -174,6 +284,7 @@ function filterBoards() {
174
284
const boardArchs = board . getAttribute ( "data-arch" ) . split ( " " ) ;
175
285
const boardVendor = board . getAttribute ( "data-vendor" ) ;
176
286
const boardSocs = board . getAttribute ( "data-socs" ) . split ( " " ) ;
287
+ const boardSupportedFeatures = board . getAttribute ( "data-supported-features" ) . split ( " " ) ;
177
288
178
289
let matches = true ;
179
290
@@ -183,7 +294,8 @@ function filterBoards() {
183
294
! ( nameInput && ! boardName . includes ( nameInput ) ) &&
184
295
! ( archSelect && ! boardArchs . includes ( archSelect ) ) &&
185
296
! ( vendorSelect && boardVendor !== vendorSelect ) &&
186
- ( selectedSocs . length === 0 || selectedSocs . some ( ( soc ) => boardSocs . includes ( soc ) ) ) ;
297
+ ( selectedSocs . length === 0 || selectedSocs . some ( ( soc ) => boardSocs . includes ( soc ) ) ) &&
298
+ ( selectedTags . length === 0 || selectedTags . every ( ( tag ) => boardSupportedFeatures . includes ( tag ) ) ) ;
187
299
188
300
board . classList . toggle ( "hidden" , ! matches ) ;
189
301
} ) ;
0 commit comments