11import { templatesScreen } from '../html' ;
22import type { EventsManager , Template } from '../models' ;
3- import { debounce } from '../utils/utils' ;
3+ import { debounce , loadScript } from '../utils/utils' ;
4+ import { flexSearchUrl } from '../vendors' ;
5+ import { getTemplatesSearchInput } from './selectors' ;
46
5- export const createTemplatesContainer = (
6- eventsManager : EventsManager ,
7- loadUserTemplates : ( ) => void ,
8- ) => {
7+ let searchIndex : Promise < any > | undefined ;
8+
9+ export const createTemplatesContainer = ( eventsManager : EventsManager ) => {
910 const div = document . createElement ( 'div' ) ;
1011 div . innerHTML = templatesScreen ;
1112 const templatesContainer = div . firstChild as HTMLElement ;
@@ -23,21 +24,19 @@ export const createTemplatesContainer = (
2324 } ) ;
2425 const target = templatesContainer . querySelector ( '#' + link . dataset . target ) ;
2526 target ?. classList . add ( 'active' ) ;
26- if ( link . dataset . target === 'templates-user' ) {
27- loadUserTemplates ( ) ;
28- }
2927 } ) ;
3028 } ) ;
3129 setupTemplatesSearch ( templatesContainer ) ;
3230 return templatesContainer ;
3331} ;
3432
3533export const createStarterTemplateLink = (
36- template : Template ,
34+ template : Template & { id : string } ,
3735 starterTemplatesList : HTMLElement | null ,
3836 baseUrl : string ,
3937) => {
4038 const li = document . createElement ( 'li' ) ;
39+ li . dataset . id = template . id ;
4140 const link = document . createElement ( 'a' ) ;
4241 link . href = '?template=' + template . name ;
4342 link . innerHTML = `
@@ -54,36 +53,78 @@ export const noUserTemplates = () => `
5453 <div class="description alert">${ window . deps . translateString ( 'templates.noUserTemplates.heading' , 'You have no saved templates.' ) } </div>
5554 <div class="description help">
5655 ${ window . deps . translateString (
57- 'templates.noUserTemplates.desc' ,
58- 'You can save a project as a template from <wbr />(App menu > Save as > Template).' ,
59- {
60- isHTML : true ,
61- } ,
62- ) }
56+ 'templates.noUserTemplates.desc' ,
57+ 'You can save a project as a template from <wbr />(App menu > Save as > Template).' ,
58+ {
59+ isHTML : true ,
60+ } ,
61+ ) }
6362 </div>
6463</div>
6564` ;
6665
66+ export const initTemplatesSearchIndex = ( ) => {
67+ searchIndex = loadScript ( flexSearchUrl , 'FlexSearch' ) . then (
68+ async ( FlexSearch : any ) =>
69+ new FlexSearch . Document ( {
70+ index : [ 'name' , 'title' , 'description' , 'aliases' , 'tags' , 'languages' ] ,
71+ tokenize : 'full' ,
72+ worker : true ,
73+ } ) ,
74+ ) ;
75+ } ;
76+
77+ export const addTemplateToIndex = ( {
78+ id,
79+ title,
80+ name = '' ,
81+ description = '' ,
82+ aliases = [ ] ,
83+ tags = [ ] ,
84+ languages = [ ] ,
85+ } : {
86+ id : string ;
87+ title : string ;
88+ name ?: string ;
89+ description ?: string ;
90+ aliases ?: string [ ] ;
91+ tags ?: string [ ] ;
92+ languages ?: string [ ] ;
93+ } ) => {
94+ searchIndex ?. then ( ( index ) => {
95+ index . add ( { id, name, title, description, aliases, tags, languages } ) ;
96+ } ) ;
97+ } ;
98+
6799export const setupTemplatesSearch = ( container : HTMLElement ) => {
68- const input = container . querySelector ( '#templates-search-input' ) ;
100+ const input = getTemplatesSearchInput ( container ) ;
69101 if ( ! input ) return ;
70102
71103 const filterTemplates = ( query : string ) => {
72- const mainItems = container . querySelectorAll ( '#templates-starter li' ) ;
73- const userItems = container . querySelectorAll ( '#templates-user li' ) ;
74- const items = Array . from ( mainItems ) . concat ( Array . from ( userItems ) ) ;
75- items . forEach ( ( item ) => {
76- const text = item . textContent ?. toLowerCase ( ) || '' ;
77- const matches = text . includes ( query . toLowerCase ( ) ) ;
78- ( item as HTMLElement ) . style . display = matches ? '' : 'none' ;
104+ searchIndex ?. then ( async ( index ) => {
105+ const mainItems = container . querySelectorAll (
106+ '#templates-starter li' ,
107+ ) as NodeListOf < HTMLElement > ;
108+ const userItems = container . querySelectorAll ( '#templates-user li' ) as NodeListOf < HTMLElement > ;
109+ const items = Array . from ( mainItems ) . concat ( Array . from ( userItems ) ) ;
110+
111+ const result =
112+ query === ''
113+ ? null
114+ : ( await index . searchAsync ( query ) ) . map ( ( field : any ) => field . result ) . flat ( ) ;
115+
116+ items . forEach ( ( item ) => {
117+ ( item as HTMLElement ) . style . display =
118+ query === '' || result . includes ( item . dataset . id as string ) ? '' : 'none' ;
119+ } ) ;
79120 } ) ;
80121 } ;
81122
82123 const debouncedFilter = debounce ( ( val : string ) => {
83124 filterTemplates ( val . trim ( ) ) ;
84125 } , 150 ) ;
85126
86- input . addEventListener ( 'input ' , ( e : Event ) => {
127+ input . addEventListener ( 'keyup ' , ( e : Event ) => {
87128 const val = ( e . target as HTMLInputElement ) . value || '' ;
88129 debouncedFilter ( val ) ;
89130 } ) ;
0 commit comments