chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2024-10-19 14:44:55 +02:00
parent c9ce29f206
commit 40e894df8b
294 changed files with 14209 additions and 4192 deletions

View file

@ -45,7 +45,6 @@ export class OsmConnectionFeatureSwitches {
}
export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
public readonly featureSwitchEnableLogin: UIEventSource<boolean>
public readonly featureSwitchSearch: UIEventSource<boolean>
public readonly featureSwitchBackgroundSelection: UIEventSource<boolean>

View file

@ -11,8 +11,8 @@ import FilterConfig from "../../Models/ThemeConfig/FilterConfig"
import Constants from "../../Models/Constants"
export type ActiveFilter = {
layer: LayerConfig,
filter: FilterConfig,
layer: LayerConfig
filter: FilterConfig
control: UIEventSource<string | number | undefined>
}
/**
@ -36,9 +36,13 @@ export default class LayerState {
private readonly _activeFilters: UIEventSource<ActiveFilter[]> = new UIEventSource([])
public readonly activeFilters: Store<ActiveFilter[]> = this._activeFilters
private readonly _activeLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>(undefined)
private readonly _activeLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<
FilteredLayer[]
>(undefined)
public readonly activeLayers: Store<FilteredLayer[]> = this._activeLayers
private readonly _nonactiveLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>(undefined)
private readonly _nonactiveLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<
FilteredLayer[]
>(undefined)
public readonly nonactiveLayers: Store<FilteredLayer[]> = this._nonactiveLayers
private readonly osmConnection: OsmConnection
@ -71,7 +75,7 @@ export default class LayerState {
this.filteredLayers = filteredLayers
layers.forEach((l) => LayerState.linkFilterStates(l, filteredLayers))
this.filteredLayers.forEach(fl => {
this.filteredLayers.forEach((fl) => {
fl.isDisplayed.addCallback(() => this.updateActiveFilters())
for (const [_, appliedFilter] of fl.appliedFilters) {
appliedFilter.addCallback(() => this.updateActiveFilters())
@ -80,27 +84,27 @@ export default class LayerState {
this.updateActiveFilters()
}
private updateActiveFilters(){
private updateActiveFilters() {
const filters: ActiveFilter[] = []
const activeLayers: FilteredLayer[] = []
const nonactiveLayers: FilteredLayer[] = []
this.filteredLayers.forEach(fl => {
if(!fl.isDisplayed.data){
const nonactiveLayers: FilteredLayer[] = []
this.filteredLayers.forEach((fl) => {
if (!fl.isDisplayed.data) {
nonactiveLayers.push(fl)
return
}
activeLayers.push(fl)
if(fl.layerDef.filterIsSameAs){
if (fl.layerDef.filterIsSameAs) {
return
}
for (const [filtername, appliedFilter] of fl.appliedFilters) {
if (appliedFilter.data === undefined) {
continue
}
const filter = fl.layerDef.filters.find(f => f.id === filtername)
if(typeof appliedFilter.data === "number"){
if(filter.options[appliedFilter.data].osmTags === undefined){
const filter = fl.layerDef.filters.find((f) => f.id === filtername)
if (typeof appliedFilter.data === "number") {
if (filter.options[appliedFilter.data].osmTags === undefined) {
// This is probably the first, generic option which doesn't _actually_ filter
continue
}

View file

@ -17,7 +17,6 @@ import { FeatureSource } from "../FeatureSource/FeatureSource"
import { Feature } from "geojson"
export default class SearchState {
public readonly feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined)
public readonly searchTerm: UIEventSource<string> = new UIEventSource<string>("")
public readonly searchIsFocused = new UIEventSource(false)
@ -39,57 +38,66 @@ export default class SearchState {
new LocalElementSearch(state, 5),
new CoordinateSearch(),
new OpenStreetMapIdSearch(state),
new PhotonSearch() // new NominatimGeocoding(),
new PhotonSearch(), // new NominatimGeocoding(),
]
const bounds = state.mapProperties.bounds
const suggestionsList = this.searchTerm.stabilized(250).mapD(search => {
const suggestionsList = this.searchTerm.stabilized(250).mapD(
(search) => {
if (search.length === 0) {
return undefined
}
return this.locationSearchers.map(ls => ls.suggest(search, { bbox: bounds.data }))
}, [bounds]
return this.locationSearchers.map((ls) => ls.suggest(search, { bbox: bounds.data }))
},
[bounds]
)
this.suggestionsSearchRunning = suggestionsList.bind(suggestions => {
this.suggestionsSearchRunning = suggestionsList.bind((suggestions) => {
if (suggestions === undefined) {
return new ImmutableStore(true)
}
return Stores.concat(suggestions).map(suggestions => suggestions.some(list => list === undefined))
return Stores.concat(suggestions).map((suggestions) =>
suggestions.some((list) => list === undefined)
)
})
this.suggestions = suggestionsList.bindD(suggestions =>
Stores.concat(suggestions).map(suggestions => CombinedSearcher.merge(suggestions))
this.suggestions = suggestionsList.bindD((suggestions) =>
Stores.concat(suggestions).map((suggestions) => CombinedSearcher.merge(suggestions))
)
const themeSearch = new ThemeSearch(state)
this.themeSuggestions = this.searchTerm.mapD(query => themeSearch.search(query, 3))
this.themeSuggestions = this.searchTerm.mapD((query) => themeSearch.search(query, 3))
const layerSearch = new LayerSearch(state.theme)
this.layerSuggestions = this.searchTerm.mapD(query => layerSearch.search(query, 5))
this.layerSuggestions = this.searchTerm.mapD((query) => layerSearch.search(query, 5))
const filterSearch = new FilterSearch(state)
this.filterSuggestions = this.searchTerm.stabilized(50)
.mapD(query => filterSearch.search(query))
.mapD(filterResult => {
const active = state.layerState.activeFilters.data
return filterResult.filter(({ filter, index, layer }) => {
const foundMatch = active.some(active =>
active.filter.id === filter.id && layer.id === active.layer.id && active.control.data === index)
this.filterSuggestions = this.searchTerm
.stabilized(50)
.mapD((query) => filterSearch.search(query))
.mapD(
(filterResult) => {
const active = state.layerState.activeFilters.data
return filterResult.filter(({ filter, index, layer }) => {
const foundMatch = active.some(
(active) =>
active.filter.id === filter.id &&
layer.id === active.layer.id &&
active.control.data === index
)
return !foundMatch
})
}, [state.layerState.activeFilters])
return !foundMatch
})
},
[state.layerState.activeFilters]
)
this.locationResults = new GeocodingFeatureSource(this.suggestions.stabilized(250))
this.showSearchDrawer = new UIEventSource(false)
this.searchIsFocused.addCallbackAndRunD(sugg => {
this.searchIsFocused.addCallbackAndRunD((sugg) => {
if (sugg) {
this.showSearchDrawer.set(true)
}
})
}
public async apply(result: FilterSearchResult[] | LayerConfig) {
@ -108,7 +116,7 @@ export default class SearchState {
private async applyFilter(payload: FilterSearchResult[]) {
const state = this.state
const layersToShow = payload.map(fsr => fsr.layer.id)
const layersToShow = payload.map((fsr) => fsr.layer.id)
console.log("Layers to show are", layersToShow)
for (const [name, otherLayer] of state.layerState.filteredLayers) {
const layer = otherLayer.layerDef
@ -144,7 +152,7 @@ export default class SearchState {
}
// This feature might not be loaded because we zoomed out
const object = await this.state.osmObjectDownloader.DownloadObjectAsync(osmid)
if(object === "deleted"){
if (object === "deleted") {
return
}
const f = object.asGeoJson()

View file

@ -22,9 +22,7 @@ import Showdown from "showdown"
import { LocalStorageSource } from "../Web/LocalStorageSource"
import { GeocodeResult } from "../Search/GeocodingProvider"
export class OptionallySyncedHistory<T> {
public readonly syncPreference: UIEventSource<"sync" | "local" | "no">
public readonly value: Store<T[]>
private readonly synced: UIEventSource<T[]>
@ -34,18 +32,26 @@ export class OptionallySyncedHistory<T> {
private readonly _isSame: (a: T, b: T) => boolean
private osmconnection: OsmConnection
constructor(key: string, osmconnection: OsmConnection, maxHistory: number = 20, isSame?: (a: T, b: T) => boolean) {
constructor(
key: string,
osmconnection: OsmConnection,
maxHistory: number = 20,
isSame?: (a: T, b: T) => boolean
) {
this.osmconnection = osmconnection
this._maxHistory = maxHistory
this._isSame = isSame
this.syncPreference = osmconnection.getPreference(
"preference-" + key + "-history",
"sync",
)
const synced = this.synced = UIEventSource.asObject<T[]>(osmconnection.getPreference(key + "-history"), [])
const local = this.local = LocalStorageSource.getParsed<T[]>(key + "-history", [])
const thisSession = this.thisSession = new UIEventSource<T[]>([], "optionally-synced:" + key + "(session only)")
this.syncPreference.addCallback(syncmode => {
this.syncPreference = osmconnection.getPreference("preference-" + key + "-history", "sync")
const synced = (this.synced = UIEventSource.asObject<T[]>(
osmconnection.getPreference(key + "-history"),
[]
))
const local = (this.local = LocalStorageSource.getParsed<T[]>(key + "-history", []))
const thisSession = (this.thisSession = new UIEventSource<T[]>(
[],
"optionally-synced:" + key + "(session only)"
))
this.syncPreference.addCallback((syncmode) => {
if (syncmode === "sync") {
let list = [...thisSession.data, ...synced.data].slice(0, maxHistory)
if (this._isSame) {
@ -67,9 +73,7 @@ export class OptionallySyncedHistory<T> {
}
})
this.value = this.syncPreference.bind(syncPref => this.getAppropriateStore(syncPref))
this.value = this.syncPreference.bind((syncPref) => this.getAppropriateStore(syncPref))
}
private getAppropriateStore(syncPref?: string) {
@ -87,7 +91,7 @@ export class OptionallySyncedHistory<T> {
const store = this.getAppropriateStore()
let oldList = store.data ?? []
if (this._isSame) {
oldList = oldList.filter(x => !this._isSame(t, x))
oldList = oldList.filter((x) => !this._isSame(t, x))
}
store.set([t, ...oldList].slice(0, this._maxHistory))
}
@ -100,14 +104,13 @@ export class OptionallySyncedHistory<T> {
if (t === undefined) {
return
}
this.osmconnection.isLoggedIn.addCallbackAndRun(loggedIn => {
this.osmconnection.isLoggedIn.addCallbackAndRun((loggedIn) => {
if (!loggedIn) {
return
}
this.add(t)
return true
})
}
clear() {
@ -157,7 +160,7 @@ export default class UserRelatedState {
*/
public readonly gpsLocationHistoryRetentionTime = new UIEventSource(
7 * 24 * 60 * 60,
"gps_location_retention",
"gps_location_retention"
)
public readonly addNewFeatureMode = new UIEventSource<
@ -180,18 +183,17 @@ export default class UserRelatedState {
public readonly recentlyVisitedThemes: OptionallySyncedHistory<string>
public readonly recentlyVisitedSearch: OptionallySyncedHistory<GeocodeResult>
constructor(
osmConnection: OsmConnection,
layout?: ThemeConfig,
featureSwitches?: FeatureSwitchState,
mapProperties?: MapProperties,
mapProperties?: MapProperties
) {
this.osmConnection = osmConnection
this._mapProperties = mapProperties
this.showAllQuestionsAtOnce = UIEventSource.asBoolean(
this.osmConnection.getPreference("show-all-questions", "false"),
this.osmConnection.getPreference("show-all-questions", "false")
)
this.language = this.osmConnection.getPreference("language")
this.showTags = this.osmConnection.getPreference("show_tags")
@ -203,15 +205,19 @@ export default class UserRelatedState {
this.mangroveIdentity = new MangroveIdentity(
this.osmConnection.getPreference("identity", undefined, "mangrove"),
this.osmConnection.getPreference("identity-creation-date", undefined, "mangrove"),
this.osmConnection.getPreference("identity-creation-date", undefined, "mangrove")
)
this.preferredBackgroundLayer = this.osmConnection.getPreference(
"preferred-background-layer"
)
this.preferredBackgroundLayer = this.osmConnection.getPreference("preferred-background-layer")
this.addNewFeatureMode = this.osmConnection.getPreference(
"preferences-add-new-mode",
"button_click_right",
"button_click_right"
)
this.showScale = UIEventSource.asBoolean(
this.osmConnection.GetPreference("preference-show-scale", "false")
)
this.showScale = UIEventSource.asBoolean(this.osmConnection.GetPreference("preference-show-scale", "false"))
this.imageLicense = this.osmConnection.getPreference("pictures-license", "CC0")
this.installedUserThemes = UserRelatedState.initInstalledUserThemes(osmConnection)
@ -224,12 +230,13 @@ export default class UserRelatedState {
"theme",
this.osmConnection,
10,
(a, b) => a === b,
(a, b) => a === b
)
this.recentlyVisitedSearch = new OptionallySyncedHistory<GeocodeResult>("places",
this.recentlyVisitedSearch = new OptionallySyncedHistory<GeocodeResult>(
"places",
this.osmConnection,
15,
(a, b) => a.osm_id === b.osm_id && a.osm_type === b.osm_type,
(a, b) => a.osm_id === b.osm_id && a.osm_type === b.osm_type
)
this.syncLanguage()
this.recentlyVisitedThemes.addDefferred(layout?.id)
@ -279,9 +286,7 @@ export default class UserRelatedState {
*/
public addUnofficialTheme(themeInfo: MinimalThemeInformation) {
const pref = this.osmConnection.getPreference("unofficial-theme-" + themeInfo.id)
this.osmConnection.isLoggedIn.when(
() => pref.set(JSON.stringify(themeInfo))
)
this.osmConnection.isLoggedIn.when(() => pref.set(JSON.stringify(themeInfo)))
}
public getUnofficialTheme(id: string): MinimalThemeInformation | undefined {
@ -298,9 +303,9 @@ export default class UserRelatedState {
} catch (e) {
console.warn(
"Removing theme " +
id +
" as it could not be parsed from the preferences; the content is:",
str,
id +
" as it could not be parsed from the preferences; the content is:",
str
)
pref.setData(null)
return undefined
@ -330,7 +335,7 @@ export default class UserRelatedState {
title: layout.title.translations,
shortDescription: layout.shortDescription.translations,
definition: layout["definition"],
}),
})
)
}
}
@ -340,7 +345,7 @@ export default class UserRelatedState {
return osmConnection.preferencesHandler.allPreferences.map((prefs) =>
Object.keys(prefs)
.filter((k) => k.startsWith(prefix))
.map((k) => k.substring(prefix.length)),
.map((k) => k.substring(prefix.length))
)
}
@ -354,7 +359,7 @@ export default class UserRelatedState {
return userPreferences.map((preferences) =>
Object.keys(preferences)
.filter((key) => key.startsWith(prefix))
.map((key) => key.substring(prefix.length, key.length - "-enabled".length)),
.map((key) => key.substring(prefix.length, key.length - "-enabled".length))
)
}
@ -370,7 +375,7 @@ export default class UserRelatedState {
return undefined
}
return [home.lon, home.lat]
}),
})
).map((homeLonLat) => {
if (homeLonLat === undefined) {
return empty
@ -400,7 +405,7 @@ export default class UserRelatedState {
* */
private initAmendedPrefs(
layout?: ThemeConfig,
featureSwitches?: FeatureSwitchState,
featureSwitches?: FeatureSwitchState
): UIEventSource<Record<string, string>> {
const amendedPrefs = new UIEventSource<Record<string, string>>({
_theme: layout?.id,
@ -446,19 +451,19 @@ export default class UserRelatedState {
const missingLayers = Utils.Dedup(
untranslated
.filter((k) => k.startsWith("layers:"))
.map((k) => k.slice("layers:".length).split(".")[0]),
.map((k) => k.slice("layers:".length).split(".")[0])
)
const zenLinks: { link: string; id: string }[] = Utils.NoNull([
hasMissingTheme
? {
id: "theme:" + layout.id,
link: LinkToWeblate.hrefToWeblateZen(
language,
"themes",
layout.id,
),
}
id: "theme:" + layout.id,
link: LinkToWeblate.hrefToWeblateZen(
language,
"themes",
layout.id
),
}
: undefined,
...missingLayers.map((id) => ({
id: "layer:" + id,
@ -475,7 +480,7 @@ export default class UserRelatedState {
}
amendedPrefs.ping()
},
[this.translationMode],
[this.translationMode]
)
this.mangroveIdentity.getKeyId().addCallbackAndRun((kid) => {
@ -494,7 +499,7 @@ export default class UserRelatedState {
.makeHtml(userDetails.description)
?.replace(/&gt;/g, ">")
?.replace(/&lt;/g, "<")
?.replace(/\n/g, ""),
?.replace(/\n/g, "")
)
}
@ -505,7 +510,7 @@ export default class UserRelatedState {
(c: { contributor: string; commits: number }) => {
const replaced = c.contributor.toLowerCase().replace(/\s+/g, "")
return replaced === simplifiedName
},
}
)
if (isTranslator) {
amendedPrefs.data["_translation_contributions"] = "" + isTranslator.commits
@ -514,7 +519,7 @@ export default class UserRelatedState {
(c: { contributor: string; commits: number }) => {
const replaced = c.contributor.toLowerCase().replace(/\s+/g, "")
return replaced === simplifiedName
},
}
)
if (isCodeContributor) {
amendedPrefs.data["_code_contributions"] = "" + isCodeContributor.commits

View file

@ -1,14 +1,42 @@
import { Utils } from "../../Utils"
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
export class ThemeMetaTagging {
public static readonly themeName = "usersettings"
public static readonly themeName = "usersettings"
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) {
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/&lt;/g,'<')?.replace(/&gt;/g,'>') ?? '' )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
feat.properties['__current_backgroun'] = 'initial_value'
}
}
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
feat.properties._description
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
?.at(1)
)
Utils.AddLazyProperty(
feat.properties,
"_d",
() => feat.properties._description?.replace(/&lt;/g, "<")?.replace(/&gt;/g, ">") ?? ""
)
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.href.match(/mastodon|en.osm.town/) !== null
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(
feat.properties,
"_mastodon_candidate",
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
)
feat.properties["__current_backgroun"] = "initial_value"
}
}