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' ;
45import { getTemplatesSearchInput } from './selectors' ;
56
7+ let searchIndex : Promise < any > | undefined ;
8+
69export const createTemplatesContainer = ( eventsManager : EventsManager ) => {
710 const div = document . createElement ( 'div' ) ;
811 div . innerHTML = templatesScreen ;
@@ -28,11 +31,12 @@ export const createTemplatesContainer = (eventsManager: EventsManager) => {
2831} ;
2932
3033export const createStarterTemplateLink = (
31- template : Template ,
34+ template : Template & { id : string } ,
3235 starterTemplatesList : HTMLElement | null ,
3336 baseUrl : string ,
3437) => {
3538 const li = document . createElement ( 'li' ) ;
39+ li . dataset . id = template . id ;
3640 const link = document . createElement ( 'a' ) ;
3741 link . href = '?template=' + template . name ;
3842 link . innerHTML = `
@@ -59,26 +63,68 @@ export const noUserTemplates = () => `
5963</div>
6064` ;
6165
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+
6299export const setupTemplatesSearch = ( container : HTMLElement ) => {
63100 const input = getTemplatesSearchInput ( container ) ;
64101 if ( ! input ) return ;
65102
66103 const filterTemplates = ( query : string ) => {
67- const mainItems = container . querySelectorAll ( '#templates-starter li' ) ;
68- const userItems = container . querySelectorAll ( '#templates-user li' ) ;
69- const items = Array . from ( mainItems ) . concat ( Array . from ( userItems ) ) ;
70- items . forEach ( ( item ) => {
71- const text = item . textContent ?. toLowerCase ( ) || '' ;
72- const matches = text . includes ( query . toLowerCase ( ) ) ;
73- ( 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+ } ) ;
74120 } ) ;
75121 } ;
76122
77123 const debouncedFilter = debounce ( ( val : string ) => {
78124 filterTemplates ( val . trim ( ) ) ;
79125 } , 150 ) ;
80126
81- input . addEventListener ( 'input ' , ( e : Event ) => {
127+ input . addEventListener ( 'keyup ' , ( e : Event ) => {
82128 const val = ( e . target as HTMLInputElement ) . value || '' ;
83129 debouncedFilter ( val ) ;
84130 } ) ;
0 commit comments