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…
Reference in a new issue