@@ -96,9 +96,25 @@ document.addEventListener('DOMContentLoaded', function() {
9696 }
9797 }
9898
99+ // Relevance rank: 0 exact name, 1 name starts with, 2 name contains, 3 description only.
100+ var RANK_LABELS = [ 'Exact match' , 'Name match' , 'Name match' , 'Description match' ] ;
101+
102+ function matchRank ( k , terms ) {
103+ var name = cache [ k ] . name ;
104+ if ( terms . length === 1 && name === terms [ 0 ] ) return 0 ;
105+ var nameHit = terms . every ( function ( t ) { return name . indexOf ( t ) !== - 1 ; } ) ;
106+ if ( ! nameHit ) return 3 ;
107+ return name . indexOf ( terms [ 0 ] ) === 0 ? 1 : 2 ;
108+ }
109+
99110 function applyFilters ( ) {
100111 var terms = input ? input . value . toLowerCase ( ) . split ( / \s + / ) . filter ( Boolean ) : [ ] ;
101112 var selectedArch = arch ? arch . value : '' ;
113+ var list = document . getElementById ( 'app-list' ) . querySelector ( '.app-list' ) ;
114+ var matched = [ ] ;
115+
116+ var oldHeadings = list . querySelectorAll ( '.app-group-heading' ) ;
117+ for ( var h = 0 ; h < oldHeadings . length ; h ++ ) oldHeadings [ h ] . remove ( ) ;
102118
103119 for ( var k = 0 ; k < appNodes . length ; k ++ ) {
104120 var matchesSearch = ! terms . length ||
@@ -108,7 +124,31 @@ document.addEventListener('DOMContentLoaded', function() {
108124 } ) ;
109125 var matchesArch = ! selectedArch ||
110126 cache [ k ] . archs . some ( function ( a ) { return a === selectedArch ; } ) ;
111- appNodes [ k ] . style . display = ( matchesSearch && matchesArch ) ? '' : 'none' ;
127+ var visible = matchesSearch && matchesArch ;
128+ appNodes [ k ] . style . display = visible ? '' : 'none' ;
129+ if ( visible ) matched . push ( { index : k , rank : terms . length ? matchRank ( k , terms ) : 0 } ) ;
130+ }
131+
132+ if ( terms . length ) {
133+ matched . sort ( function ( a , b ) {
134+ return a . rank !== b . rank ? a . rank - b . rank : cache [ a . index ] . name . localeCompare ( cache [ b . index ] . name ) ;
135+ } ) ;
136+ }
137+
138+ var lastLabel = null ;
139+ for ( var m = 0 ; m < matched . length ; m ++ ) {
140+ var entry = matched [ m ] ;
141+ if ( terms . length ) {
142+ var label = RANK_LABELS [ entry . rank ] ;
143+ if ( label !== lastLabel ) {
144+ var heading = document . createElement ( 'div' ) ;
145+ heading . className = 'app-group-heading' ;
146+ heading . textContent = label ;
147+ list . appendChild ( heading ) ;
148+ lastLabel = label ;
149+ }
150+ }
151+ list . appendChild ( appNodes [ entry . index ] ) ;
112152 }
113153 }
114154
0 commit comments