forked from MapComplete/MapComplete
		
	Improvements to index search functionality
This commit is contained in:
		
							parent
							
								
									1da799bb5f
								
							
						
					
					
						commit
						14ce4c1846
					
				
					 4 changed files with 89 additions and 80 deletions
				
			
		|  | @ -36,28 +36,39 @@ export default class MoreScreen extends Combine { | |||
|         } | ||||
| 
 | ||||
|         const search = new TextField({ | ||||
|             placeholder:  tr.searchForATheme, | ||||
|             placeholder: tr.searchForATheme, | ||||
|         }) | ||||
|         search.GetValue().addCallbackAndRun(d => console.log("Search is ", d)) | ||||
| 
 | ||||
|         if (onMainScreen) { | ||||
|             search.focus() | ||||
|         } | ||||
|         document.addEventListener("keydown", function (event) { | ||||
|             console.log("Got a key event: ", event) | ||||
|             if (event.ctrlKey && event.code === "KeyF") { | ||||
|                 search.focus() | ||||
|                 event.preventDefault(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         const searchBar = new Combine([Svg.search_svg().SetClass("w-8"), search.SetClass("mr-4 w-full")]) | ||||
|             .SetClass("flex rounded-full border-2 border-black w-max items-center my-2 w-1/2") | ||||
|             .SetClass("flex rounded-full border-2 border-black items-center my-2 w-1/2") | ||||
| 
 | ||||
| 
 | ||||
|             super([ | ||||
|                 new Combine([searchBar]).SetClass("flex justify-center"),   | ||||
|         super([ | ||||
|             new Combine([searchBar]).SetClass("flex justify-center"), | ||||
|             MoreScreen.createOfficialThemesList(state, themeButtonStyle, themeListStyle, search.GetValue()), | ||||
|             MoreScreen.createPreviouslyVistedHiddenList(state, themeButtonStyle, themeListStyle, search.GetValue()), | ||||
|             MoreScreen.createUnofficialThemeList(themeButtonStyle, state, themeListStyle, search.GetValue()), | ||||
|             tr.streetcomplete.Clone().SetClass("block text-base mx-10 my-3 mb-10") | ||||
|         ]); | ||||
|     } | ||||
|      | ||||
|     private static NothingFound(search: UIEventSource<string>): BaseUIElement{ | ||||
|         const t  = Translations.t.general.morescreen; | ||||
| 
 | ||||
|     private static NothingFound(search: UIEventSource<string>): BaseUIElement { | ||||
|         const t = Translations.t.general.morescreen; | ||||
|         return new Combine([ | ||||
|             new Title(t.noMatchingThemes, 5).SetClass("w-max font-bold"), | ||||
|          new SubtleButton(Svg.search_disable_ui(), t.noSearch,{imgSize: "h-8"}).SetClass("h-12 w-max") | ||||
|              .onClick( () => search.setData("")) | ||||
|             new SubtleButton(Svg.search_disable_ui(), t.noSearch, {imgSize: "h-6"}).SetClass("h-12 w-max") | ||||
|                 .onClick(() => search.setData("")) | ||||
|         ]).SetClass("flex flex-col items-center w-full") | ||||
|     } | ||||
| 
 | ||||
|  | @ -173,7 +184,7 @@ export default class MoreScreen extends Combine { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static createUnofficialThemeList(buttonClass: string, state: UserRelatedState, themeListClasses: string, search : UIEventSource<string>): BaseUIElement { | ||||
|     private static createUnofficialThemeList(buttonClass: string, state: UserRelatedState, themeListClasses: string, search: UIEventSource<string>): BaseUIElement { | ||||
|         const prefix = "mapcomplete-unofficial-theme-"; | ||||
| 
 | ||||
|         var currentIds: UIEventSource<string[]> = state.osmConnection.preferencesHandler.preferences | ||||
|  | @ -192,11 +203,14 @@ export default class MoreScreen extends Combine { | |||
|         var stableIds = UIEventSource.ListStabilized<string>(currentIds) | ||||
|         return new VariableUiElement( | ||||
|             stableIds.map(ids => { | ||||
|                 const allThemes: { element: BaseUIElement, predicate?: (s:string) => boolean }[] = [] | ||||
|                 const allThemes: { element: BaseUIElement, predicate?: (s: string) => boolean }[] = [] | ||||
|                 for (const id of ids) { | ||||
|                     const link = this.createUnofficialButtonFor(state, id) | ||||
|                     if (link !== undefined) { | ||||
|                         allThemes.push({element: link.SetClass(buttonClass), predicate : s => id.toLowerCase().indexOf(s) >= 0}) | ||||
|                         allThemes.push({ | ||||
|                             element: link.SetClass(buttonClass), | ||||
|                             predicate: s => id.toLowerCase().indexOf(s) >= 0 | ||||
|                         }) | ||||
|                     } | ||||
|                 } | ||||
|                 if (allThemes.length <= 0) { | ||||
|  | @ -212,7 +226,7 @@ export default class MoreScreen extends Combine { | |||
|             })); | ||||
|     } | ||||
| 
 | ||||
|     private static createPreviouslyVistedHiddenList(state: UserRelatedState, buttonClass: string, themeListStyle: string, search: UIEventSource<string>) : BaseUIElement{ | ||||
|     private static createPreviouslyVistedHiddenList(state: UserRelatedState, buttonClass: string, themeListStyle: string, search: UIEventSource<string>): BaseUIElement { | ||||
|         const t = Translations.t.general.morescreen | ||||
|         const prefix = "mapcomplete-hidden-theme-" | ||||
|         const hiddenThemes = themeOverview["default"].filter(layout => layout.hideFromOverview) | ||||
|  | @ -230,15 +244,18 @@ export default class MoreScreen extends Combine { | |||
|                     } | ||||
| 
 | ||||
|                     const knownThemeDescriptions = hiddenThemes.filter(theme => knownThemes.has(theme.id)) | ||||
|                         .map(theme => ({element: MoreScreen.createLinkButton(state, theme)?.SetClass(buttonClass), | ||||
|                         predicate: MoreScreen.MatchesLayoutFunc(theme) | ||||
|                         .map(theme => ({ | ||||
|                             element: MoreScreen.createLinkButton(state, theme)?.SetClass(buttonClass), | ||||
|                             predicate: MoreScreen.MatchesLayoutFunc(theme) | ||||
|                         })); | ||||
| 
 | ||||
|                     const knownLayouts = new FilteredCombine(knownThemeDescriptions, | ||||
|                         search, | ||||
|                         {innerClasses: themeListStyle, | ||||
|                             onEmpty: MoreScreen.NothingFound(search)} | ||||
|                         ) | ||||
|                         { | ||||
|                             innerClasses: themeListStyle, | ||||
|                             onEmpty: MoreScreen.NothingFound(search) | ||||
|                         } | ||||
|                     ) | ||||
| 
 | ||||
|                     return new Combine([ | ||||
|                         new Title(t.previouslyHiddenTitle), | ||||
|  | @ -261,36 +278,28 @@ export default class MoreScreen extends Combine { | |||
|     private static MatchesLayoutFunc(layout: { | ||||
|         id: string, | ||||
|         title: any, | ||||
|         shortDescription: any | ||||
|         shortDescription: any, | ||||
|         keywords?: any[] | ||||
|     }) { | ||||
|         return (search: string) => { | ||||
|             search = search.toLocaleLowerCase() | ||||
|             if (layout.id.toLowerCase().indexOf(search) >= 0) { | ||||
|                 return true; | ||||
|             } | ||||
|             for (const lang in layout.shortDescription) { | ||||
|                 if (Locale.language.data !== lang) { | ||||
|                     continue | ||||
|                 } | ||||
|                 if (layout.shortDescription[lang].toLowerCase()?.indexOf(search) >= 0) { | ||||
|             const entitiesToSearch = [layout.shortDescription, layout.title, ...layout.keywords] | ||||
|             for (const entity of entitiesToSearch) { | ||||
|                 const term = entity["*"] ?? entity[Locale.language.data] | ||||
|                 if (term?.toLowerCase()?.indexOf(search) >= 0) { | ||||
|                     return true | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             for (const lang in layout.title) { | ||||
|                 if (Locale.language.data !== lang) { | ||||
|                     continue | ||||
|                 } | ||||
|                 if (layout.title[lang].toLowerCase()?.indexOf(search) >= 0) { | ||||
|                     return true | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static createOfficialThemesList(state: { osmConnection: OsmConnection, locationControl?: UIEventSource<Loc> }, buttonClass: string, themeListStyle: string, search: UIEventSource<string>):BaseUIElement { | ||||
|     private static createOfficialThemesList(state: { osmConnection: OsmConnection, locationControl?: UIEventSource<Loc> }, buttonClass: string, themeListStyle: string, search: UIEventSource<string>): BaseUIElement { | ||||
|         let officialThemes: { | ||||
|             id: string, | ||||
|             icon: string, | ||||
|  |  | |||
|  | @ -7,8 +7,10 @@ export class TextField extends InputElement<string> { | |||
|     public readonly enterPressed = new UIEventSource<string>(undefined); | ||||
|     private readonly value: UIEventSource<string>; | ||||
|     private _element: HTMLElement; | ||||
|     private _actualField : HTMLElement | ||||
|     private readonly _isValid: (s: string) => boolean; | ||||
|     private _rawValue: UIEventSource<string>  | ||||
|     private _isFocused = false; | ||||
|      | ||||
|     constructor(options?: { | ||||
|         placeholder?: string | BaseUIElement, | ||||
|  | @ -60,7 +62,6 @@ export class TextField extends InputElement<string> { | |||
| 
 | ||||
|         const field = inputEl; | ||||
| 
 | ||||
| 
 | ||||
|         this.value.addCallbackAndRunD(value => { | ||||
|             // We leave the textfield as is in the case of undefined or null (handled by addCallbackAndRunD) - make sure we do not erase it!
 | ||||
|             field["value"] = value; | ||||
|  | @ -99,7 +100,6 @@ export class TextField extends InputElement<string> { | |||
|                 ) { | ||||
|                 newCursorPos--; | ||||
|             } | ||||
|             // @ts-ignore
 | ||||
|             TextField.SetCursorPosition(field, newCursorPos); | ||||
|         }; | ||||
| 
 | ||||
|  | @ -110,6 +110,12 @@ export class TextField extends InputElement<string> { | |||
|                 self.enterPressed.setData(field.value); | ||||
|             } | ||||
|         }); | ||||
|          | ||||
|         if(this._isFocused){ | ||||
|             field.focus() | ||||
|         } | ||||
|          | ||||
|         this._actualField = field; | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
|  | @ -147,4 +153,11 @@ export class TextField extends InputElement<string> { | |||
|         return this._element; | ||||
|     } | ||||
| 
 | ||||
|     public focus() { | ||||
|         if(this._actualField === undefined){ | ||||
|             this._isFocused = true | ||||
|         }else{ | ||||
|             this._actualField.focus() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,19 +1,13 @@ | |||
| { | ||||
|   "id": "mapcomplete-changes", | ||||
|   "title": { | ||||
|     "en": "Changes made with MapComplete", | ||||
|     "de": "Änderungen mit MapComplete", | ||||
|     "es": "Cambios hechos con MapComplete" | ||||
|     "en": "Changes made with MapComplete" | ||||
|   }, | ||||
|   "shortDescription": { | ||||
|     "en": "Shows changes made by MapComplete", | ||||
|     "de": "Zeigt Änderungen von MapComplete", | ||||
|     "es": "Muestra los cambios hechos por MapComplete" | ||||
|     "en": "Shows changes made by MapComplete" | ||||
|   }, | ||||
|   "description": { | ||||
|     "en": "This maps shows all the changes made with MapComplete", | ||||
|     "de": "Diese Karte zeigt alle Änderungen die mit MapComplete gemacht wurden", | ||||
|     "es": "Este mapa muestra todos los cambios hechos con MapComplete" | ||||
|     "en": "This maps shows all the changes made with MapComplete" | ||||
|   }, | ||||
|   "maintainer": "", | ||||
|   "icon": "./assets/svg/logo.svg", | ||||
|  | @ -28,9 +22,7 @@ | |||
|     { | ||||
|       "id": "mapcomplete-changes", | ||||
|       "name": { | ||||
|         "en": "Changeset centers", | ||||
|         "de": "Schwerpunkte von Änderungssätzen", | ||||
|         "es": "Centros de conjuntos de cambios" | ||||
|         "en": "Changeset centers" | ||||
|       }, | ||||
|       "minzoom": 0, | ||||
|       "source": { | ||||
|  | @ -44,45 +36,35 @@ | |||
|       ], | ||||
|       "title": { | ||||
|         "render": { | ||||
|           "en": "Changeset for {theme}", | ||||
|           "de": "Änderungen für {theme}", | ||||
|           "es": "Conjunto de cambios para {theme}" | ||||
|           "en": "Changeset for {theme}" | ||||
|         } | ||||
|       }, | ||||
|       "description": { | ||||
|         "en": "Shows all MapComplete changes", | ||||
|         "de": "Zeigt alle MapComplete Änderungen", | ||||
|         "es": "Muestra todos los cambios de MapComplete" | ||||
|         "en": "Shows all MapComplete changes" | ||||
|       }, | ||||
|       "tagRenderings": [ | ||||
|         { | ||||
|           "id": "render_id", | ||||
|           "render": { | ||||
|             "en": "Changeset <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>", | ||||
|             "de": "Änderung <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>", | ||||
|             "es": "Conjunto de cambios <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>" | ||||
|             "en": "Changeset <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>" | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": "contributor", | ||||
|           "render": { | ||||
|             "en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>", | ||||
|             "de": "Änderung wurde von <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a> gemacht", | ||||
|             "es": "Cambio hecho por <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>" | ||||
|             "en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>" | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": "theme", | ||||
|           "render": { | ||||
|             "en": "Change with theme <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>", | ||||
|             "de": "Änderung mit Thema <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>" | ||||
|             "en": "Change with theme <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>" | ||||
|           }, | ||||
|           "mappings": [ | ||||
|             { | ||||
|               "if": "theme~http.*", | ||||
|               "then": { | ||||
|                 "en": "Change with <b>unofficial</b> theme <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>", | ||||
|                 "de": "Änderung mit <b>inoffiziellem</b> Thema <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>" | ||||
|                 "en": "Change with <b>unofficial</b> theme <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>" | ||||
|               } | ||||
|             } | ||||
|           ] | ||||
|  | @ -346,8 +328,7 @@ | |||
|                 } | ||||
|               ], | ||||
|               "question": { | ||||
|                 "en": "Themename contains {search}", | ||||
|                 "de": "Themenname enthält {search}" | ||||
|                 "en": "Themename contains {search}" | ||||
|               } | ||||
|             } | ||||
|           ] | ||||
|  | @ -363,9 +344,7 @@ | |||
|                 } | ||||
|               ], | ||||
|               "question": { | ||||
|                 "en": "Made by contributor {search}", | ||||
|                 "de": "Erstellt von {search}", | ||||
|                 "es": "Hecho por contributor/a {search}" | ||||
|                 "en": "Made by contributor {search}" | ||||
|               } | ||||
|             } | ||||
|           ] | ||||
|  | @ -381,9 +360,7 @@ | |||
|                 } | ||||
|               ], | ||||
|               "question": { | ||||
|                 "en": "<b>Not</b> made by contributor {search}", | ||||
|                 "de": "<b>Nicht</b> erstellt von {search}", | ||||
|                 "es": "<b>No</b> hecho por contributor/a {search}" | ||||
|                 "en": "<b>Not</b> made by contributor {search}" | ||||
|               } | ||||
|             } | ||||
|           ] | ||||
|  | @ -398,9 +375,7 @@ | |||
|           { | ||||
|             "id": "link_to_more", | ||||
|             "render": { | ||||
|               "en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>", | ||||
|               "de": "Weitere Statistiken finden Sie <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>hier</a>", | ||||
|               "es": "Se pueden encontrar más estadísticas <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>aquí</a>" | ||||
|               "en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|  |  | |||
|  | @ -13,22 +13,35 @@ import PointRenderingConfigJson from "../Models/ThemeConfig/Json/PointRenderingC | |||
| import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer"; | ||||
| import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme"; | ||||
| import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion"; | ||||
| import LayerConfig from "../Models/ThemeConfig/LayerConfig"; | ||||
| import LayerConfigJsonJSC from "../Docs/Schemas/LayerConfigJsonJSC"; | ||||
| import {Utils} from "../Utils"; | ||||
| 
 | ||||
| // This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
 | ||||
| // It spits out an overview of those to be used to load them
 | ||||
| 
 | ||||
| class LayerOverviewUtils { | ||||
| 
 | ||||
|     writeSmallOverview(themes: { id: string, title: any, shortDescription: any, icon: string, hideFromOverview: boolean, mustHaveLanguage: boolean }[]) { | ||||
|     writeSmallOverview(themes: { id: string, title: any, shortDescription: any, icon: string, hideFromOverview: boolean, mustHaveLanguage: boolean, layers: (LayerConfigJson | string | {builtin})[] }[]) { | ||||
|         const perId = new Map<string, any>(); | ||||
|         for (const theme of themes) { | ||||
|              | ||||
|             const keywords : {}[] = [] | ||||
|             for (const layer of (theme.layers ?? [])) { | ||||
|                 const l = <LayerConfigJson> layer; | ||||
|                 keywords.push({"*": l.id}) | ||||
|                 keywords.push(l.title) | ||||
|                 keywords.push(l.description) | ||||
|             } | ||||
|              | ||||
|             const data = { | ||||
|                 id: theme.id, | ||||
|                 title: theme.title, | ||||
|                 shortDescription: theme.shortDescription, | ||||
|                 icon: theme.icon, | ||||
|                 hideFromOverview: theme.hideFromOverview, | ||||
|                 mustHaveLanguage: theme.mustHaveLanguage | ||||
|                 mustHaveLanguage: theme.mustHaveLanguage, | ||||
|                 keywords: Utils.NoNull(keywords) | ||||
|             } | ||||
|             perId.set(theme.id, data); | ||||
|         } | ||||
|  | @ -215,13 +228,12 @@ class LayerOverviewUtils { | |||
|             fixed.set(themeFile.id, themeFile) | ||||
|         } | ||||
| 
 | ||||
|         this.writeSmallOverview(themeFiles.map(tf => { | ||||
|             const t = tf.parsed; | ||||
|         this.writeSmallOverview(Array.from(fixed.values()).map(t => { | ||||
|             return { | ||||
|                 ...t, | ||||
|                 hideFromOverview: t.hideFromOverview ?? false, | ||||
|                 shortDescription: t.shortDescription ?? new Translation(t.description).FirstSentence().translations, | ||||
|                 mustHaveLanguage: t.mustHaveLanguage?.length > 0 | ||||
|                 mustHaveLanguage: t.mustHaveLanguage?.length > 0, | ||||
|             } | ||||
|         })); | ||||
|         return fixed; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue