forked from MapComplete/MapComplete
Merge master
This commit is contained in:
commit
c939d8ea8e
352 changed files with 976 additions and 212534 deletions
|
@ -8,11 +8,13 @@ import { FeatureSource, WritableFeatureSource } from "../FeatureSource/FeatureSo
|
|||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
import { OsmTags } from "../../Models/OsmFeature"
|
||||
import StaticFeatureSource, { WritableStaticFeatureSource } from "../FeatureSource/Sources/StaticFeatureSource"
|
||||
import StaticFeatureSource, {
|
||||
WritableStaticFeatureSource,
|
||||
} from "../FeatureSource/Sources/StaticFeatureSource"
|
||||
import { MapProperties } from "../../Models/MapProperties"
|
||||
import { Orientation } from "../../Sensors/Orientation"
|
||||
|
||||
("use strict")
|
||||
;("use strict")
|
||||
/**
|
||||
* The geolocation-handler takes a map-location and a geolocation state.
|
||||
* It'll move the map as appropriate given the state of the geolocation-API
|
||||
|
|
|
@ -32,7 +32,6 @@ export default class NoElementsInViewDetector {
|
|||
return "zoom-to-low"
|
||||
}
|
||||
|
||||
|
||||
for (const [layerName, source] of themeViewState.perLayerFiltered) {
|
||||
if (priviliged.has(layerName)) {
|
||||
continue
|
||||
|
|
|
@ -34,11 +34,15 @@ export default class SelectedElementTagsUpdater {
|
|||
})
|
||||
}
|
||||
|
||||
public static applyUpdate(latestTags: OsmTags, id: string, state: {
|
||||
theme: ThemeConfig,
|
||||
changes: Changes,
|
||||
featureProperties: FeaturePropertiesStore
|
||||
}) {
|
||||
public static applyUpdate(
|
||||
latestTags: OsmTags,
|
||||
id: string,
|
||||
state: {
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
featureProperties: FeaturePropertiesStore
|
||||
}
|
||||
) {
|
||||
try {
|
||||
const leftRightSensitive = state.theme.isLeftRightSensitive()
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class DetermineTheme {
|
|||
tagRenderings: DetermineTheme.getSharedTagRenderings(),
|
||||
tagRenderingOrder: DetermineTheme.getSharedTagRenderingOrder(),
|
||||
sharedLayers: knownLayersDict,
|
||||
publicLayers: new Set<string>()
|
||||
publicLayers: new Set<string>(),
|
||||
}
|
||||
return convertState
|
||||
}
|
||||
|
|
|
@ -84,10 +84,10 @@ export default class FavouritesFeatureSource extends StaticFeatureSource {
|
|||
private async updateFeature(
|
||||
feature: Feature,
|
||||
state: {
|
||||
theme: ThemeConfig,
|
||||
changes: Changes,
|
||||
featureProperties: FeaturePropertiesStore,
|
||||
osmObjectDownloader: OsmObjectDownloader,
|
||||
theme: ThemeConfig
|
||||
changes: Changes
|
||||
featureProperties: FeaturePropertiesStore
|
||||
osmObjectDownloader: OsmObjectDownloader
|
||||
}
|
||||
) {
|
||||
const id = feature.properties.id
|
||||
|
|
|
@ -32,7 +32,6 @@ export default class ThemeSource implements IndexedFeatureSource {
|
|||
public readonly featuresById: Store<Map<string, Feature>>
|
||||
private readonly core: Store<ThemeSourceCore>
|
||||
|
||||
|
||||
private readonly addedSources: FeatureSource[] = []
|
||||
private readonly addedItems: OsmFeature[] = []
|
||||
|
||||
|
@ -48,14 +47,23 @@ export default class ThemeSource implements IndexedFeatureSource {
|
|||
const isLoading = new UIEventSource(true)
|
||||
this.isLoading = isLoading
|
||||
|
||||
const features = this.features = new UIEventSource<Feature[]>([])
|
||||
const featuresById = this.featuresById = new UIEventSource(new Map())
|
||||
this.core = mvtAvailableLayers.mapD(mvtAvailableLayers => {
|
||||
const core = new ThemeSourceCore(layers, featureSwitches, mapProperties, backend, isDisplayed, mvtAvailableLayers, isLoading, fullNodeDatabaseSource)
|
||||
this.addedSources.forEach(src => core.addSource(src))
|
||||
this.addedItems.forEach(item => core.addItem(item))
|
||||
core.features.addCallbackAndRun(data => features.set(data))
|
||||
core.featuresById.addCallbackAndRun(data => featuresById.set(data))
|
||||
const features = (this.features = new UIEventSource<Feature[]>([]))
|
||||
const featuresById = (this.featuresById = new UIEventSource(new Map()))
|
||||
this.core = mvtAvailableLayers.mapD((mvtAvailableLayers) => {
|
||||
const core = new ThemeSourceCore(
|
||||
layers,
|
||||
featureSwitches,
|
||||
mapProperties,
|
||||
backend,
|
||||
isDisplayed,
|
||||
mvtAvailableLayers,
|
||||
isLoading,
|
||||
fullNodeDatabaseSource
|
||||
)
|
||||
this.addedSources.forEach((src) => core.addSource(src))
|
||||
this.addedItems.forEach((item) => core.addItem(item))
|
||||
core.features.addCallbackAndRun((data) => features.set(data))
|
||||
core.featuresById.addCallbackAndRun((data) => featuresById.set(data))
|
||||
return core
|
||||
})
|
||||
}
|
||||
|
@ -69,7 +77,6 @@ export default class ThemeSource implements IndexedFeatureSource {
|
|||
this.addedSources.push(source)
|
||||
}
|
||||
|
||||
|
||||
public addItem(obj: OsmFeature) {
|
||||
this.core.data?.addItem(obj)
|
||||
this.addedItems.push(obj)
|
||||
|
@ -82,7 +89,6 @@ export default class ThemeSource implements IndexedFeatureSource {
|
|||
* Note that special layers (with `source=null` will be ignored)
|
||||
*/
|
||||
class ThemeSourceCore extends FeatureSourceMerger {
|
||||
|
||||
/**
|
||||
* This source is _only_ triggered when the data is downloaded for CSV export
|
||||
* @private
|
||||
|
@ -116,7 +122,7 @@ class ThemeSourceCore extends FeatureSourceMerger {
|
|||
mapProperties,
|
||||
{
|
||||
isActive: isDisplayed(layer.id),
|
||||
maxAge: layer.maxAgeOfCache
|
||||
maxAge: layer.maxAgeOfCache,
|
||||
}
|
||||
)
|
||||
fromCache.set(layer.id, src)
|
||||
|
@ -169,11 +175,11 @@ class ThemeSourceCore extends FeatureSourceMerger {
|
|||
overpassUrl: featureSwitches.overpassUrl,
|
||||
overpassTimeout: featureSwitches.overpassTimeout,
|
||||
overpassMaxZoom: new ImmutableStore(99),
|
||||
widenFactor: 0
|
||||
widenFactor: 0,
|
||||
},
|
||||
{
|
||||
ignoreZoom: true,
|
||||
isActive: new ImmutableStore(false)
|
||||
isActive: new ImmutableStore(false),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -247,7 +253,7 @@ class ThemeSourceCore extends FeatureSourceMerger {
|
|||
backend,
|
||||
isActive,
|
||||
patchRelations: true,
|
||||
fullNodeDatabase
|
||||
fullNodeDatabase,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -279,11 +285,11 @@ class ThemeSourceCore extends FeatureSourceMerger {
|
|||
widenFactor: 1.5,
|
||||
overpassUrl: featureSwitches.overpassUrl,
|
||||
overpassTimeout: featureSwitches.overpassTimeout,
|
||||
overpassMaxZoom: featureSwitches.overpassMaxZoom
|
||||
overpassMaxZoom: featureSwitches.overpassMaxZoom,
|
||||
},
|
||||
{
|
||||
padToTiles: zoom.map((zoom) => Math.min(15, zoom + 1)),
|
||||
isActive
|
||||
isActive,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export default class AllImageProviders {
|
|||
...WikimediaImageProvider.commonsPrefixes,
|
||||
...Mapillary.valuePrefixes,
|
||||
...AllImageProviders.dontLoadFromPrefixes,
|
||||
"Category:"
|
||||
"Category:",
|
||||
])
|
||||
|
||||
private static imageAttributionSources: ImageProvider[] = [
|
||||
|
@ -31,7 +31,7 @@ export default class AllImageProviders {
|
|||
WikidataImageProvider.singleton,
|
||||
WikimediaImageProvider.singleton,
|
||||
Panoramax.singleton,
|
||||
AllImageProviders.genericImageProvider
|
||||
AllImageProviders.genericImageProvider,
|
||||
]
|
||||
public static apiUrls: string[] = [].concat(
|
||||
...AllImageProviders.imageAttributionSources.map((src) => src.apiUrls())
|
||||
|
@ -44,7 +44,7 @@ export default class AllImageProviders {
|
|||
mapillary: Mapillary.singleton,
|
||||
wikidata: WikidataImageProvider.singleton,
|
||||
wikimedia: WikimediaImageProvider.singleton,
|
||||
panoramax: Panoramax.singleton
|
||||
panoramax: Panoramax.singleton,
|
||||
}
|
||||
|
||||
public static byName(name: string) {
|
||||
|
@ -77,7 +77,10 @@ export default class AllImageProviders {
|
|||
*
|
||||
*
|
||||
*/
|
||||
public static estimateNumberOfImages(tags: Record<string, string>, prefixes: string[] = undefined): number {
|
||||
public static estimateNumberOfImages(
|
||||
tags: Record<string, string>,
|
||||
prefixes: string[] = undefined
|
||||
): number {
|
||||
let count = 0
|
||||
|
||||
const sources = [Imgur.singleton,
|
||||
|
@ -137,7 +140,7 @@ export default class AllImageProviders {
|
|||
*/
|
||||
public static loadImagesFrom(urls: string[]): Store<ProvidedImage[]> {
|
||||
const tags = {
|
||||
id: urls.join(";")
|
||||
id: urls.join(";"),
|
||||
}
|
||||
for (let i = 0; i < urls.length; i++) {
|
||||
tags["image:" + i] = urls[i]
|
||||
|
|
|
@ -604,14 +604,16 @@ export class OsmConnection {
|
|||
if (this.fakeUser) {
|
||||
return
|
||||
}
|
||||
this.FetchCapabilities().then(({ api, gpx }) => {
|
||||
this.apiIsOnline.setData(api)
|
||||
this.gpxServiceIsOnline.setData(gpx)
|
||||
}).catch(err => {
|
||||
console.log("Could not reach the api:", err)
|
||||
this.apiIsOnline.set("unreachable")
|
||||
this.gpxServiceIsOnline.set("unreachable")
|
||||
})
|
||||
this.FetchCapabilities()
|
||||
.then(({ api, gpx }) => {
|
||||
this.apiIsOnline.setData(api)
|
||||
this.gpxServiceIsOnline.setData(gpx)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Could not reach the api:", err)
|
||||
this.apiIsOnline.set("unreachable")
|
||||
this.gpxServiceIsOnline.set("unreachable")
|
||||
})
|
||||
}
|
||||
|
||||
private readonly _userInfoCache: Record<number, OsmUserInfo> = {}
|
||||
|
|
|
@ -210,7 +210,7 @@ export class OsmPreferences {
|
|||
* @private
|
||||
*/
|
||||
private async getPreferencesDictDirectly(): Promise<Record<string, string>> {
|
||||
if(!this.osmConnection.isLoggedIn.data){
|
||||
if (!this.osmConnection.isLoggedIn.data) {
|
||||
return {}
|
||||
}
|
||||
return new Promise<Record<string, string>>((resolve, reject) => {
|
||||
|
@ -260,7 +260,7 @@ export class OsmPreferences {
|
|||
*
|
||||
*/
|
||||
private async uploadKvSplit(k: string, v: string) {
|
||||
if(!this.osmConnection.isLoggedIn.data){
|
||||
if (!this.osmConnection.isLoggedIn.data) {
|
||||
return
|
||||
}
|
||||
if (v === null || v === undefined || v === "" || v === "undefined" || v === "null") {
|
||||
|
|
|
@ -15,7 +15,6 @@ export default class OpenStreetMapIdSearch implements GeocodingProvider {
|
|||
}
|
||||
private readonly _osmObjectDownloader: OsmObjectDownloader
|
||||
|
||||
|
||||
constructor(osmObjectDownloader: OsmObjectDownloader) {
|
||||
this._osmObjectDownloader = osmObjectDownloader
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export default class SearchState {
|
|||
new OpenLocationCodeSearch(),
|
||||
new OpenStreetMapIdSearch(state.osmObjectDownloader),
|
||||
new PhotonSearch(true, 2),
|
||||
new PhotonSearch()
|
||||
new PhotonSearch(),
|
||||
// new NominatimGeocoding(),
|
||||
]
|
||||
|
||||
|
|
|
@ -414,7 +414,7 @@ export default class UserRelatedState {
|
|||
typeof window === "undefined" ? "no" : window.navigator.share ? "yes" : "no",
|
||||
_iframe: Utils.isIframe ? "yes" : "no",
|
||||
})
|
||||
if(!Utils.runningFromConsole){
|
||||
if (!Utils.runningFromConsole) {
|
||||
amendedPrefs.data["_host"] = window.location.host
|
||||
amendedPrefs.data["_path"] = window.location.pathname
|
||||
amendedPrefs.data["_userAgent"] = navigator.userAgent
|
||||
|
@ -492,7 +492,7 @@ export default class UserRelatedState {
|
|||
})
|
||||
|
||||
const usersettingMetaTagging = new ThemeMetaTagging()
|
||||
osmConnection.isLoggedIn.addCallbackAndRun(loggedIn => {
|
||||
osmConnection.isLoggedIn.addCallbackAndRun((loggedIn) => {
|
||||
amendedPrefs.data["_loggedIn"] = "" + loggedIn
|
||||
amendedPrefs.ping()
|
||||
})
|
||||
|
|
|
@ -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(/</g,'<')?.replace(/>/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(/</g, "<")?.replace(/>/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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ export interface NSIItem {
|
|||
}
|
||||
readonly tags: Readonly<Record<string, string>>
|
||||
fromTemplate?: boolean
|
||||
ext? : string
|
||||
ext?: string
|
||||
}
|
||||
|
||||
export default class NameSuggestionIndex {
|
||||
|
@ -214,9 +214,7 @@ export default class NameSuggestionIndex {
|
|||
for (const nsiItem of actualBrands) {
|
||||
const tags = nsiItem.tags
|
||||
const frequency = frequencies[nsiItem.displayName]
|
||||
const iconUrl = this.getIconExternalUrl(nsiItem, type)
|
||||
const hasIcon = iconUrl !== undefined
|
||||
const icon = hasIcon ? this.getIconUrl(nsiItem, type) : undefined
|
||||
const icon = this.getIconUrl(nsiItem)
|
||||
mappings.push({
|
||||
if: new Tag(type, tags[type]),
|
||||
addExtraTags: Object.keys(tags)
|
||||
|
@ -274,7 +272,7 @@ export default class NameSuggestionIndex {
|
|||
const values = tags[osmKey]
|
||||
for (const osmValue of values) {
|
||||
const suggestions = this.getSuggestionsForKV(type, osmKey, osmValue)
|
||||
if(!suggestions){
|
||||
if (!suggestions) {
|
||||
console.warn("No suggestions found for", type, osmKey, osmValue)
|
||||
continue
|
||||
}
|
||||
|
@ -399,9 +397,14 @@ export default class NameSuggestionIndex {
|
|||
return logos?.facebook ?? logos?.wikidata
|
||||
}
|
||||
|
||||
public getIconUrl(nsiItem: NSIItem, type: string) {
|
||||
public getIconUrl(nsiItem: NSIItem): string | undefined {
|
||||
if (!nsiItem.ext) {
|
||||
// No extension -> there is no logo
|
||||
return undefined
|
||||
}
|
||||
return "./assets/data/nsi/logos/" + nsiItem.id + "." + nsiItem.ext
|
||||
}
|
||||
|
||||
private static readonly brandPrefix = ["name", "alt_name", "operator", "brand"] as const
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,8 +6,8 @@ import { UIEventSource } from "../UIEventSource"
|
|||
|
||||
export default class ThemeViewStateHashActor {
|
||||
private readonly _state: {
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
selectedElement: UIEventSource<Feature>,
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
selectedElement: UIEventSource<Feature>
|
||||
guistate: MenuState
|
||||
}
|
||||
private isUpdatingHash = false
|
||||
|
@ -22,7 +22,7 @@ export default class ThemeViewStateHashActor {
|
|||
"",
|
||||
"The possible hashes are:",
|
||||
"",
|
||||
MenuState.pageNames.map((tab) => "`" + tab + "`").join(",")
|
||||
MenuState.pageNames.map((tab) => "`" + tab + "`").join(","),
|
||||
]
|
||||
|
||||
/**
|
||||
|
@ -35,9 +35,9 @@ export default class ThemeViewStateHashActor {
|
|||
*
|
||||
*/
|
||||
constructor(state: {
|
||||
indexedFeatures: IndexedFeatureSource,
|
||||
selectedElement: UIEventSource<Feature>,
|
||||
guistate: MenuState,
|
||||
indexedFeatures: IndexedFeatureSource
|
||||
selectedElement: UIEventSource<Feature>
|
||||
guistate: MenuState
|
||||
}) {
|
||||
this._state = state
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ export type PageType = (typeof MenuState.pageNames)[number]
|
|||
* Some convenience methods are provided for this as well
|
||||
*/
|
||||
export class MenuState {
|
||||
|
||||
public static readonly pageNames = [
|
||||
"copyright",
|
||||
"copyright_icons",
|
||||
|
@ -28,14 +27,16 @@ export class MenuState {
|
|||
"favourites",
|
||||
"usersettings",
|
||||
"share",
|
||||
"menu"
|
||||
"menu",
|
||||
] as const
|
||||
|
||||
/**
|
||||
* Contains the 'providedImage' which is currently displayed on top of the UI
|
||||
* This object merely acts as lock or as means to signal the need to close
|
||||
*/
|
||||
public static readonly previewedImage: UIEventSource<object> = new UIEventSource<object>(undefined)
|
||||
public static readonly previewedImage: UIEventSource<object> = new UIEventSource<object>(
|
||||
undefined
|
||||
)
|
||||
|
||||
public readonly pageStates: Record<PageType, UIEventSource<boolean>>
|
||||
|
||||
|
@ -152,6 +153,5 @@ export class MenuState {
|
|||
this._selectedElement.setData(undefined)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,22 +32,26 @@ export class PruneFilters extends DesugaringStep<LayerConfigJson> {
|
|||
filter: FilterConfigJson,
|
||||
context: ConversionContext
|
||||
): FilterConfigJson {
|
||||
|
||||
if (filter.options.length === 1) {
|
||||
const option = filter.options[0]
|
||||
const tags = TagUtils.Tag(option.osmTags)
|
||||
const optimized = TagUtils.removeKnownParts(tags, sourceTags, true)
|
||||
if (optimized === true) {
|
||||
context.warn("Removing filter as always known: ", new Translation(option.question).textFor("en"))
|
||||
context.warn(
|
||||
"Removing filter as always known: ",
|
||||
new Translation(option.question).textFor("en")
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
if (optimized === false) {
|
||||
context.warn("Removing filter as not possible: ", new Translation(option.question).textFor("en"))
|
||||
context.warn(
|
||||
"Removing filter as not possible: ",
|
||||
new Translation(option.question).textFor("en")
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!filter.strict) {
|
||||
return filter
|
||||
}
|
||||
|
@ -85,7 +89,6 @@ export class PruneFilters extends DesugaringStep<LayerConfigJson> {
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
return { ...filter, options: newOptions, strict: undefined }
|
||||
}
|
||||
|
||||
|
@ -99,9 +102,9 @@ export class PruneFilters extends DesugaringStep<LayerConfigJson> {
|
|||
const sourceTags = TagUtils.Tag(json.source["osmTags"])
|
||||
return {
|
||||
...json,
|
||||
filter: Utils.NoNull(json.filter?.map((obj) =>
|
||||
this.prune(sourceTags, <FilterConfigJson>obj, context)
|
||||
)),
|
||||
filter: Utils.NoNull(
|
||||
json.filter?.map((obj) => this.prune(sourceTags, <FilterConfigJson>obj, context))
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,10 +59,9 @@ export class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
|
||||
public convert(
|
||||
spec: string | { "builtin": string | string[] } | (TagRenderingConfigJson),
|
||||
spec: string | { builtin: string | string[] } | TagRenderingConfigJson,
|
||||
ctx: ConversionContext
|
||||
): QuestionableTagRenderingConfigJson[] {
|
||||
|
||||
const trs = this.convertOnce(<any>spec, ctx)?.map((tr) =>
|
||||
this.pruneMappings<TagRenderingConfigJson & { id: string }>(tr, ctx)
|
||||
)
|
||||
|
@ -124,7 +123,7 @@ export class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
return {
|
||||
...mapping,
|
||||
if: newIf.asJson()
|
||||
if: newIf.asJson(),
|
||||
}
|
||||
})
|
||||
const after = newMappings?.length ?? 0
|
||||
|
@ -137,7 +136,7 @@ export class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
const tr = {
|
||||
...tagRendering,
|
||||
mappings: newMappings
|
||||
mappings: newMappings,
|
||||
}
|
||||
delete tr["strict"]
|
||||
return tr
|
||||
|
@ -249,7 +248,7 @@ export class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
|
||||
private convertOnce(
|
||||
tr: string | { "builtin": string } | TagRenderingConfigJson,
|
||||
tr: string | { builtin: string } | TagRenderingConfigJson,
|
||||
ctx: ConversionContext
|
||||
): TagRenderingConfigJson[] {
|
||||
const state = this._state
|
||||
|
@ -273,25 +272,25 @@ export class ExpandTagRendering extends Conversion<
|
|||
ctx.warn(
|
||||
`A literal rendering was detected: ${tr}
|
||||
Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` +
|
||||
Array.from(state.sharedLayers.keys()).join(", ")
|
||||
Array.from(state.sharedLayers.keys()).join(", ")
|
||||
)
|
||||
}
|
||||
|
||||
if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) {
|
||||
ctx.err(
|
||||
"Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " +
|
||||
tr +
|
||||
" \n Did you perhaps forget to add the layer as prefix, such as `icons." +
|
||||
tr +
|
||||
"`? "
|
||||
tr +
|
||||
" \n Did you perhaps forget to add the layer as prefix, such as `icons." +
|
||||
tr +
|
||||
"`? "
|
||||
)
|
||||
}
|
||||
|
||||
return [
|
||||
<TagRenderingConfigJson & { id: string }>{
|
||||
render: tr,
|
||||
id: tr.replace(/[^a-zA-Z0-9]/g, "")
|
||||
}
|
||||
id: tr.replace(/[^a-zA-Z0-9]/g, ""),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -316,9 +315,9 @@ export class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
ctx.err(
|
||||
"An object calling a builtin can only have keys `builtin` or `override`, but a key with name `" +
|
||||
key +
|
||||
"` was found. This won't be picked up! The full object is: " +
|
||||
JSON.stringify(tr)
|
||||
key +
|
||||
"` was found. This won't be picked up! The full object is: " +
|
||||
JSON.stringify(tr)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -345,19 +344,19 @@ export class ExpandTagRendering extends Conversion<
|
|||
if (state.sharedLayers.size === 0) {
|
||||
ctx.warn(
|
||||
"BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " +
|
||||
name +
|
||||
": layer " +
|
||||
layerName +
|
||||
" not found for now, but ignoring as this is a bootstrapping run. "
|
||||
name +
|
||||
": layer " +
|
||||
layerName +
|
||||
" not found for now, but ignoring as this is a bootstrapping run. "
|
||||
)
|
||||
} else {
|
||||
ctx.err(
|
||||
": While reusing tagrendering: " +
|
||||
name +
|
||||
": layer " +
|
||||
layerName +
|
||||
" not found. Maybe you meant one of " +
|
||||
candidates.slice(0, 3).join(", ")
|
||||
name +
|
||||
": layer " +
|
||||
layerName +
|
||||
" not found. Maybe you meant one of " +
|
||||
candidates.slice(0, 3).join(", ")
|
||||
)
|
||||
}
|
||||
continue
|
||||
|
@ -369,10 +368,10 @@ export class ExpandTagRendering extends Conversion<
|
|||
candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i)
|
||||
ctx.err(
|
||||
"The tagRendering with identifier " +
|
||||
name +
|
||||
" was not found.\n\tDid you mean one of " +
|
||||
candidates.join(", ") +
|
||||
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first"
|
||||
name +
|
||||
" was not found.\n\tDid you mean one of " +
|
||||
candidates.join(", ") +
|
||||
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first"
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
import { Concat, DesugaringContext, DesugaringStep, Each, FirstOf, Fuse, On, SetDefault } from "./Conversion"
|
||||
import {
|
||||
Concat,
|
||||
DesugaringContext,
|
||||
DesugaringStep,
|
||||
Each,
|
||||
FirstOf,
|
||||
Fuse,
|
||||
On,
|
||||
SetDefault,
|
||||
} from "./Conversion"
|
||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||
import {
|
||||
MinimalTagRenderingConfigJson,
|
||||
TagRenderingConfigJson,
|
||||
} from "../Json/TagRenderingConfigJson"
|
||||
import { Utils } from "../../../Utils"
|
||||
import RewritableConfigJson from "../Json/RewritableConfigJson"
|
||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||
|
@ -24,7 +36,7 @@ import { ExpandTagRendering } from "./ExpandTagRendering"
|
|||
class AddFiltersFromTagRenderings extends DesugaringStep<LayerConfigJson> {
|
||||
constructor() {
|
||||
super(
|
||||
"Inspects all the tagRenderings. If some tagRenderings have the `filter` attribute set, introduce those filters. This step might introduce shorthand filter names, thus 'ExpandFilter' should be run afterwards. Can be disabled with \"#filter\":\"no-auto\"",
|
||||
'Inspects all the tagRenderings. If some tagRenderings have the `filter` attribute set, introduce those filters. This step might introduce shorthand filter names, thus \'ExpandFilter\' should be run afterwards. Can be disabled with "#filter":"no-auto"',
|
||||
["filter"],
|
||||
"AddFiltersFromTagRenderings"
|
||||
)
|
||||
|
@ -127,7 +139,7 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
|||
if (json.freeform.inline === true) {
|
||||
context.err(
|
||||
"'inline' is set, but the rendering contains a special visualisation...\n " +
|
||||
spec[key]
|
||||
spec[key]
|
||||
)
|
||||
}
|
||||
json = JSON.parse(JSON.stringify(json))
|
||||
|
@ -226,20 +238,20 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
if (blacklisted?.length > 0 && used?.length > 0) {
|
||||
context.err(
|
||||
"The {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." +
|
||||
"\n Whitelisted: " +
|
||||
used.join(", ") +
|
||||
"\n Blacklisted: " +
|
||||
blacklisted.join(", ")
|
||||
"\n Whitelisted: " +
|
||||
used.join(", ") +
|
||||
"\n Blacklisted: " +
|
||||
blacklisted.join(", ")
|
||||
)
|
||||
}
|
||||
for (const usedLabel of used) {
|
||||
if (!allLabels.has(usedLabel)) {
|
||||
context.err(
|
||||
"This layers specifies a special question element for label `" +
|
||||
usedLabel +
|
||||
"`, but this label doesn't exist.\n" +
|
||||
" Available labels are " +
|
||||
Array.from(allLabels).join(", ")
|
||||
usedLabel +
|
||||
"`, but this label doesn't exist.\n" +
|
||||
" Available labels are " +
|
||||
Array.from(allLabels).join(", ")
|
||||
)
|
||||
}
|
||||
seen.add(usedLabel)
|
||||
|
@ -253,8 +265,8 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
const question: QuestionableTagRenderingConfigJson = {
|
||||
id: "leftover-questions",
|
||||
render: {
|
||||
"*": `{questions( ,${Array.from(seen).join(";")})}`
|
||||
}
|
||||
"*": `{questions( ,${Array.from(seen).join(";")})}`,
|
||||
},
|
||||
}
|
||||
json.tagRenderings.push(question)
|
||||
}
|
||||
|
@ -336,13 +348,13 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
|||
if (json.allowMove && !usedSpecialFunctions.has("move_button")) {
|
||||
json.tagRenderings.push({
|
||||
id: "move-button",
|
||||
render: { "*": "{move_button()}" }
|
||||
render: { "*": "{move_button()}" },
|
||||
})
|
||||
}
|
||||
if (json.deletion && !usedSpecialFunctions.has("delete_button")) {
|
||||
json.tagRenderings.push({
|
||||
id: "delete-button",
|
||||
render: { "*": "{delete_button()}" }
|
||||
render: { "*": "{delete_button()}" },
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -357,9 +369,9 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
|||
or: [
|
||||
"__featureSwitchIsDebugging=true",
|
||||
"mapcomplete-show_tags=full",
|
||||
"mapcomplete-show_debug=yes"
|
||||
]
|
||||
}
|
||||
"mapcomplete-show_debug=yes",
|
||||
],
|
||||
},
|
||||
}
|
||||
json.tagRenderings?.push(trc)
|
||||
}
|
||||
|
@ -467,10 +479,10 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
private static convertIfNeeded(
|
||||
input:
|
||||
| (object & {
|
||||
special: {
|
||||
type: string
|
||||
}
|
||||
})
|
||||
special: {
|
||||
type: string
|
||||
}
|
||||
})
|
||||
| any,
|
||||
context: ConversionContext
|
||||
): any {
|
||||
|
@ -568,7 +580,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
.map((nm) => RewriteSpecial.escapeStr(special[nm] ?? "", context))
|
||||
.join(",")
|
||||
return {
|
||||
"*": `{${type}(${args})${clss}}`
|
||||
"*": `{${type}(${args})${clss}}`,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,14 +678,14 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
}[] = []
|
||||
|
||||
for (let i = 0; i < badgesJson.length; i++) {
|
||||
const iconBadge: string | ({
|
||||
if: TagConfigJson
|
||||
then: string | MinimalTagRenderingConfigJson
|
||||
}) = badgesJson[i]
|
||||
|
||||
const iconBadge:
|
||||
| string
|
||||
| {
|
||||
if: TagConfigJson
|
||||
then: string | MinimalTagRenderingConfigJson
|
||||
} = badgesJson[i]
|
||||
|
||||
if (typeof iconBadge === "string") {
|
||||
|
||||
const expanded: QuestionableTagRenderingConfigJson[] = this._expand.convert(
|
||||
iconBadge,
|
||||
context.enters("iconBadges", i)
|
||||
|
@ -683,16 +695,18 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
const condition = tr.condition
|
||||
for (const trElement of tr.mappings) {
|
||||
const showIf = TagUtils.optimzeJson({
|
||||
and: Utils.NoNull([condition,
|
||||
and: Utils.NoNull([
|
||||
condition,
|
||||
{
|
||||
or: Utils.NoNull([
|
||||
trElement.alsoShowIf, trElement.if
|
||||
])
|
||||
}
|
||||
])
|
||||
or: Utils.NoNull([trElement.alsoShowIf, trElement.if]),
|
||||
},
|
||||
]),
|
||||
})
|
||||
if (showIf === true) {
|
||||
context.warn("Dropping iconBadge that would be _always_ shown: " + (trElement.icon ?? trElement.then))
|
||||
context.warn(
|
||||
"Dropping iconBadge that would be _always_ shown: " +
|
||||
(trElement.icon ?? trElement.then)
|
||||
)
|
||||
continue
|
||||
}
|
||||
if (showIf === false) {
|
||||
|
@ -700,11 +714,9 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
}
|
||||
iconBadges.push({
|
||||
if: showIf,
|
||||
then: trElement.icon ?? trElement.then
|
||||
then: trElement.icon ?? trElement.then,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -721,7 +733,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
iconBadges.push(
|
||||
...expanded.map((resolved) => ({
|
||||
if: iconBadge.if,
|
||||
then: <MinimalTagRenderingConfigJson>resolved
|
||||
then: <MinimalTagRenderingConfigJson>resolved,
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
@ -734,7 +746,7 @@ class PreparePointRendering extends Fuse<PointRenderingConfigJson> {
|
|||
constructor(state: DesugaringContext, layer: LayerConfigJson) {
|
||||
super(
|
||||
"Prepares point renderings by expanding 'icon' and 'iconBadges'." +
|
||||
" A tagRendering from the host tagRenderings will be substituted in",
|
||||
" A tagRendering from the host tagRenderings will be substituted in",
|
||||
new On(
|
||||
"marker",
|
||||
new Each(
|
||||
|
@ -861,7 +873,7 @@ export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
|
|||
|
||||
const specialVis: Exclude<RenderingSpecification, string>[] = <
|
||||
Exclude<RenderingSpecification, string>[]
|
||||
>ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
|
||||
>ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
|
||||
(rs) => typeof rs !== "string"
|
||||
)
|
||||
const funcs = new Set<string>(specialVis.map((rs) => rs.func.funcName))
|
||||
|
@ -897,7 +909,7 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
return <TagRenderingConfigJson>{
|
||||
id: "title_icon_auto_" + tr.id,
|
||||
mappings
|
||||
mappings,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -942,8 +954,8 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
.enters("titleIcons", i)
|
||||
.warn(
|
||||
"TagRendering with id " +
|
||||
trId +
|
||||
" does not have any icons, not generating an icon for this"
|
||||
trId +
|
||||
" does not have any icons, not generating an icon for this"
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -1006,7 +1018,7 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
|||
(layer) =>
|
||||
new Concat(
|
||||
new ExpandTagRendering(state, layer, {
|
||||
addToContext: options?.addTagRenderingsToContext ?? false
|
||||
addToContext: options?.addTagRenderingsToContext ?? false,
|
||||
})
|
||||
)
|
||||
),
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
|
||||
import {
|
||||
Concat,
|
||||
Conversion,
|
||||
DesugaringContext,
|
||||
DesugaringStep,
|
||||
Each,
|
||||
Fuse,
|
||||
On,
|
||||
Pass,
|
||||
SetDefault,
|
||||
} from "./Conversion"
|
||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||
import { PrepareLayer } from "./PrepareLayer"
|
||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
|
|
|
@ -75,14 +75,17 @@ export default interface PointRenderingConfigJson {
|
|||
* See ExpandIconBadges on how this is handled
|
||||
* group: hidden
|
||||
*/
|
||||
iconBadges?: (string | {
|
||||
if: TagConfigJson
|
||||
/**
|
||||
* Badge to show
|
||||
* Type: icon
|
||||
*/
|
||||
then: string | MinimalTagRenderingConfigJson
|
||||
})[]
|
||||
iconBadges?: (
|
||||
| string
|
||||
| {
|
||||
if: TagConfigJson
|
||||
/**
|
||||
* Badge to show
|
||||
* Type: icon
|
||||
*/
|
||||
then: string | MinimalTagRenderingConfigJson
|
||||
}
|
||||
)[]
|
||||
|
||||
/**
|
||||
* question: What size should the marker be on the map?
|
||||
|
|
|
@ -5,7 +5,10 @@ import { TagUtils } from "../../Logic/Tags/TagUtils"
|
|||
import { And } from "../../Logic/Tags/And"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Tag } from "../../Logic/Tags/Tag"
|
||||
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
|
||||
import {
|
||||
MappingConfigJson,
|
||||
QuestionableTagRenderingConfigJson,
|
||||
} from "./Json/QuestionableTagRenderingConfigJson"
|
||||
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
|
||||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||
import { RegexTag } from "../../Logic/Tags/RegexTag"
|
||||
|
|
|
@ -35,10 +35,8 @@ import ShowDataLayer from "../../UI/Map/ShowDataLayer"
|
|||
*/
|
||||
|
||||
export class UserMapFeatureswitchState extends WithUserRelatedState {
|
||||
|
||||
readonly map: UIEventSource<MlMap>
|
||||
|
||||
|
||||
readonly mapProperties: MapLibreAdaptor & MapProperties & ExportableMap
|
||||
readonly lastClickObject: LastClickFeatureSource
|
||||
|
||||
|
@ -47,19 +45,22 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
readonly geolocationControl: GeolocationControlState
|
||||
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>
|
||||
|
||||
|
||||
readonly availableLayers: { store: Store<RasterLayerPolygon[]> }
|
||||
readonly currentView: FeatureSource<Feature<Polygon>>
|
||||
readonly fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
||||
|
||||
constructor(theme: ThemeConfig, selectedElement: Store<object>) {
|
||||
const rasterLayer: UIEventSource<RasterLayerPolygon> = new UIEventSource<RasterLayerPolygon>(undefined)
|
||||
const rasterLayer: UIEventSource<RasterLayerPolygon> =
|
||||
new UIEventSource<RasterLayerPolygon>(undefined)
|
||||
super(theme, rasterLayer)
|
||||
this.geolocationState = new GeoLocationState()
|
||||
const initial = new InitialMapPositioning(theme, this.geolocationState, this.osmConnection)
|
||||
this.map = new UIEventSource<MlMap>(undefined)
|
||||
this.mapProperties = new MapLibreAdaptor(this.map, { rasterLayer, ...initial }, { correctClick: 20 })
|
||||
this.mapProperties = new MapLibreAdaptor(
|
||||
this.map,
|
||||
{ rasterLayer, ...initial },
|
||||
{ correctClick: 20 }
|
||||
)
|
||||
|
||||
this.geolocation = new GeoLocationHandler(
|
||||
this.geolocationState,
|
||||
|
@ -70,7 +71,6 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
this.geolocationControl = new GeolocationControlState(this.geolocation, this.mapProperties)
|
||||
this.historicalUserLocations = this.geolocation.historicalUserLocations
|
||||
|
||||
|
||||
this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => {
|
||||
this.mapProperties.allowRotating.setData(fixated !== "yes")
|
||||
})
|
||||
|
@ -100,8 +100,8 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
bbox.asGeoJson({
|
||||
zoom: this.mapProperties.zoom.data,
|
||||
...this.mapProperties.location.data,
|
||||
id: "current_view_" + currentViewIndex
|
||||
})
|
||||
id: "current_view_" + currentViewIndex,
|
||||
}),
|
||||
]
|
||||
})
|
||||
)
|
||||
|
@ -111,12 +111,10 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
this.fullNodeDatabase = new FullNodeDatabaseSource()
|
||||
}
|
||||
|
||||
|
||||
///////// Actors ///////////////
|
||||
|
||||
new BackgroundLayerResetter(this.mapProperties.rasterLayer, this.availableLayers)
|
||||
|
||||
|
||||
this.userRelatedState.showScale.addCallbackAndRun((showScale) => {
|
||||
this.mapProperties.showScale.set(showScale)
|
||||
})
|
||||
|
@ -127,14 +125,11 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
this.userRelatedState.preferredBackgroundLayer
|
||||
)
|
||||
|
||||
|
||||
this.initHotkeys()
|
||||
this.drawOverlayLayers()
|
||||
this.drawLock()
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the map is locked to a certain area _and_ we are in test mode, draw this on the map
|
||||
* @private
|
||||
|
@ -159,7 +154,6 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* By focussing on the map, the keyboard panning and zoom with '+' and '+' works */
|
||||
public focusOnMap() {
|
||||
if (this.map.data) {
|
||||
|
@ -205,55 +199,35 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
})
|
||||
}
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "O" },
|
||||
docs.selectOsmbasedmap,
|
||||
() => setLayerCategory("osmbasedmap")
|
||||
Hotkeys.RegisterHotkey({ nomod: "O" }, docs.selectOsmbasedmap, () =>
|
||||
setLayerCategory("osmbasedmap")
|
||||
)
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "M" },
|
||||
docs.selectMap,
|
||||
() => setLayerCategory("map")
|
||||
Hotkeys.RegisterHotkey({ nomod: "M" }, docs.selectMap, () => setLayerCategory("map"))
|
||||
|
||||
Hotkeys.RegisterHotkey({ nomod: "P" }, docs.selectAerial, () =>
|
||||
setLayerCategory("photo")
|
||||
)
|
||||
Hotkeys.RegisterHotkey({ shift: "O" }, docs.selectOsmbasedmap, () =>
|
||||
setLayerCategory("osmbasedmap", 2)
|
||||
)
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "P" },
|
||||
docs.selectAerial,
|
||||
() => setLayerCategory("photo")
|
||||
)
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ shift: "O" },
|
||||
docs.selectOsmbasedmap,
|
||||
() => setLayerCategory("osmbasedmap", 2)
|
||||
)
|
||||
Hotkeys.RegisterHotkey({ shift: "M" }, docs.selectMap, () => setLayerCategory("map", 2))
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ shift: "M" },
|
||||
docs.selectMap,
|
||||
() => setLayerCategory("map", 2)
|
||||
)
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ shift: "P" },
|
||||
docs.selectAerial,
|
||||
() => setLayerCategory("photo", 2)
|
||||
Hotkeys.RegisterHotkey({ shift: "P" }, docs.selectAerial, () =>
|
||||
setLayerCategory("photo", 2)
|
||||
)
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "L" },
|
||||
Translations.t.hotkeyDocumentation.geolocate,
|
||||
() => {
|
||||
this.geolocationControl.handleClick()
|
||||
}
|
||||
)
|
||||
Hotkeys.RegisterHotkey({ nomod: "L" }, Translations.t.hotkeyDocumentation.geolocate, () => {
|
||||
this.geolocationControl.handleClick()
|
||||
})
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{
|
||||
shift: "T"
|
||||
shift: "T",
|
||||
},
|
||||
docs.translationMode,
|
||||
() => {
|
||||
|
@ -286,7 +260,7 @@ export class UserMapFeatureswitchState extends WithUserRelatedState {
|
|||
return new ShowDataLayer(map, {
|
||||
features,
|
||||
layer,
|
||||
metaTags: this.userRelatedState.preferencesAsTags
|
||||
metaTags: this.userRelatedState.preferencesAsTags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
import {
|
||||
NewGeometryFromChangesFeatureSource
|
||||
} from "../../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"
|
||||
import { NewGeometryFromChangesFeatureSource } from "../../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"
|
||||
import { WithLayoutSourceState } from "./WithLayoutSourceState"
|
||||
import ThemeConfig from "../ThemeConfig/ThemeConfig"
|
||||
import { Utils } from "../../Utils"
|
||||
|
@ -20,10 +18,11 @@ import { Map as MlMap } from "maplibre-gl"
|
|||
import FilteringFeatureSource from "../../Logic/FeatureSource/Sources/FilteringFeatureSource"
|
||||
import ShowDataLayer from "../../UI/Map/ShowDataLayer"
|
||||
import SelectedElementTagsUpdater from "../../Logic/Actors/SelectedElementTagsUpdater"
|
||||
import NoElementsInViewDetector, { FeatureViewState } from "../../Logic/Actors/NoElementsInViewDetector"
|
||||
import NoElementsInViewDetector, {
|
||||
FeatureViewState,
|
||||
} from "../../Logic/Actors/NoElementsInViewDetector"
|
||||
|
||||
export class WithChangesState extends WithLayoutSourceState {
|
||||
|
||||
readonly changes: Changes
|
||||
readonly newFeatures: WritableFeatureSource
|
||||
readonly osmObjectDownloader: OsmObjectDownloader
|
||||
|
@ -44,7 +43,7 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
osmConnection: this.osmConnection,
|
||||
featureProperties: this.featureProperties,
|
||||
historicalUserLocations: this.historicalUserLocations,
|
||||
reportError: this.reportError
|
||||
reportError: this.reportError,
|
||||
},
|
||||
theme?.isLeftRightSensitive() ?? false
|
||||
)
|
||||
|
@ -66,8 +65,7 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
),
|
||||
new ChangeGeometryApplicator(this.indexedFeatures, this.changes),
|
||||
{
|
||||
constructStore: (features, layer) =>
|
||||
new GeoIndexedStoreForLayer(features, layer),
|
||||
constructStore: (features, layer) => new GeoIndexedStoreForLayer(features, layer),
|
||||
handleLeftovers: (features) => {
|
||||
console.warn(
|
||||
"Got ",
|
||||
|
@ -75,7 +73,7 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
"leftover features, such as",
|
||||
features[0].properties
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
this.perLayer = perLayer.perLayer
|
||||
|
@ -85,7 +83,6 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
|
||||
this.toCacheSavers = theme.enableCache ? this.initSaveToLocalStorage() : undefined
|
||||
|
||||
|
||||
////// ACTORS ////////
|
||||
|
||||
new ChangeToElementsActor(this.changes, this.featureProperties)
|
||||
|
@ -97,7 +94,7 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
featureProperties: this.featureProperties,
|
||||
indexedFeatures: this.indexedFeatures,
|
||||
osmObjectDownloader: this.osmObjectDownloader,
|
||||
perLayer: this.perLayer
|
||||
perLayer: this.perLayer,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -154,8 +151,8 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
userid: this.osmConnection.userDetails.data?.uid,
|
||||
pendingChanges: this.changes.pendingChanges.data,
|
||||
previousChanges: this.changes.allChanges.data,
|
||||
changeRewrites: Utils.MapToObj(this.changes._changesetHandler._remappings)
|
||||
})
|
||||
changeRewrites: Utils.MapToObj(this.changes._changesetHandler._remappings),
|
||||
}),
|
||||
})
|
||||
} catch (e) {
|
||||
console.error("Could not upload an error report")
|
||||
|
@ -227,10 +224,9 @@ export class WithChangesState extends WithLayoutSourceState {
|
|||
doShowLayer,
|
||||
metaTags: this.userRelatedState.preferencesAsTags,
|
||||
selectedElement: this.selectedElement,
|
||||
fetchStore: (id) => this.featureProperties.getStore(id)
|
||||
fetchStore: (id) => this.featureProperties.getStore(id),
|
||||
})
|
||||
})
|
||||
return filteringFeatureSource
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ export class WithGuiState extends WithSpecialLayers {
|
|||
this.initHotkeysGui()
|
||||
}
|
||||
|
||||
|
||||
private initHotkeysGui() {
|
||||
const docs = Translations.t.hotkeyDocumentation
|
||||
|
||||
|
@ -44,7 +43,7 @@ export class WithGuiState extends WithSpecialLayers {
|
|||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{
|
||||
nomod: "b"
|
||||
nomod: "b",
|
||||
},
|
||||
docs.openLayersPanel,
|
||||
() => {
|
||||
|
@ -55,7 +54,7 @@ export class WithGuiState extends WithSpecialLayers {
|
|||
)
|
||||
Hotkeys.RegisterHotkey(
|
||||
{
|
||||
nomod: "s"
|
||||
nomod: "s",
|
||||
},
|
||||
Translations.t.hotkeyDocumentation.openFilterPanel,
|
||||
() => {
|
||||
|
@ -70,5 +69,4 @@ export class WithGuiState extends WithSpecialLayers {
|
|||
this.guistate.closeAll()
|
||||
this.selectedElement.setData(this.currentView.features?.data?.[0])
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,12 +12,10 @@ import { WithGuiState } from "./WithGuiState"
|
|||
import { SpecialVisualizationState } from "../../UI/SpecialVisualization"
|
||||
|
||||
export class WithImageState extends WithGuiState implements SpecialVisualizationState {
|
||||
|
||||
readonly imageUploadManager: ImageUploadManager
|
||||
readonly previewedImage = new UIEventSource<ProvidedImage>(undefined)
|
||||
readonly nearbyImageSearcher: CombinedFetcher
|
||||
|
||||
|
||||
constructor(layout: ThemeConfig, mvtAvailableLayers: Store<Set<string>>) {
|
||||
super(layout, mvtAvailableLayers)
|
||||
this.imageUploadManager = new ImageUploadManager(
|
||||
|
@ -40,28 +38,23 @@ export class WithImageState extends WithGuiState implements SpecialVisualization
|
|||
longAgo.setTime(new Date().getTime() - 5 * 365 * 24 * 60 * 60 * 1000)
|
||||
this.nearbyImageSearcher = new CombinedFetcher(50, longAgo, this.indexedFeatures)
|
||||
|
||||
|
||||
this.initActors()
|
||||
Hash.hash.addCallbackAndRunD((hash) => {
|
||||
if (hash === "current_view" || hash.match(/current_view_[0-9]+/)) {
|
||||
this.selectCurrentView()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup various services for which no reference are needed
|
||||
*/
|
||||
private initActors() {
|
||||
|
||||
new ThemeViewStateHashActor({
|
||||
selectedElement: this.selectedElement,
|
||||
indexedFeatures: this.indexedFeatures,
|
||||
guistate: this.guistate
|
||||
guistate: this.guistate,
|
||||
})
|
||||
new PendingChangesUploader(this.changes, this.selectedElement, this.imageUploadManager)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import { FeatureSource, IndexedFeatureSource } from "../../Logic/FeatureSource/F
|
|||
import { Tag } from "../../Logic/Tags/Tag"
|
||||
|
||||
export class WithLayoutSourceState extends WithSelectedElementState {
|
||||
|
||||
readonly layerState: LayerState
|
||||
readonly dataIsLoading: Store<boolean>
|
||||
|
||||
|
@ -21,7 +20,6 @@ export class WithLayoutSourceState extends WithSelectedElementState {
|
|||
*/
|
||||
readonly floors: Store<string[]>
|
||||
|
||||
|
||||
constructor(theme: ThemeConfig, mvtAvailableLayers: Store<Set<string>>) {
|
||||
super(theme)
|
||||
/* Set up the layout source
|
||||
|
@ -62,24 +60,23 @@ export class WithLayoutSourceState extends WithSelectedElementState {
|
|||
this.layerState.filteredLayers
|
||||
.get("favourite")
|
||||
?.isDisplayed?.addCallbackAndRunD((favouritesShown) => {
|
||||
const oldGlobal = this.layerState.globalFilters.data
|
||||
const key = "show-favourite"
|
||||
if (favouritesShown) {
|
||||
this.layerState.globalFilters.set([
|
||||
...oldGlobal,
|
||||
{
|
||||
forceShowOnMatch: true,
|
||||
id: key,
|
||||
osmTags: new Tag("_favourite", "yes"),
|
||||
state: 0,
|
||||
onNewPoint: undefined
|
||||
}
|
||||
])
|
||||
} else {
|
||||
this.layerState.globalFilters.set(oldGlobal.filter((gl) => gl.id !== key))
|
||||
}
|
||||
})
|
||||
|
||||
const oldGlobal = this.layerState.globalFilters.data
|
||||
const key = "show-favourite"
|
||||
if (favouritesShown) {
|
||||
this.layerState.globalFilters.set([
|
||||
...oldGlobal,
|
||||
{
|
||||
forceShowOnMatch: true,
|
||||
id: key,
|
||||
osmTags: new Tag("_favourite", "yes"),
|
||||
state: 0,
|
||||
onNewPoint: undefined,
|
||||
},
|
||||
])
|
||||
} else {
|
||||
this.layerState.globalFilters.set(oldGlobal.filter((gl) => gl.id !== key))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private static initFloors(features: FeatureSource): Store<string[]> {
|
||||
|
@ -124,6 +121,4 @@ export class WithLayoutSourceState extends WithSelectedElementState {
|
|||
this.featureProperties.trackFeature(feature)
|
||||
this.selectedElement.setData(feature)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export class WithSearchState extends WithVisualFeedbackState {
|
|||
metaTags: this.userRelatedState.preferencesAsTags,
|
||||
onClick: (feature) => {
|
||||
this.searchState.clickedOnMap(feature)
|
||||
}
|
||||
},
|
||||
}
|
||||
new ShowDataLayer(this.map, options)
|
||||
}
|
||||
|
@ -39,17 +39,12 @@ export class WithSearchState extends WithVisualFeedbackState {
|
|||
private initHotkeysSearch() {
|
||||
const docs = Translations.t.hotkeyDocumentation
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ ctrl: "F" },
|
||||
docs.selectSearch,
|
||||
() => {
|
||||
this.searchState.feedback.set(undefined)
|
||||
this.searchState.searchIsFocused.set(true)
|
||||
}
|
||||
)
|
||||
Hotkeys.RegisterHotkey({ ctrl: "F" }, docs.selectSearch, () => {
|
||||
this.searchState.feedback.set(undefined)
|
||||
this.searchState.searchIsFocused.set(true)
|
||||
})
|
||||
|
||||
Hotkeys.RegisterHotkey({ nomod: "Escape", onUp: true }, docs.closeSidebar, () => {
|
||||
|
||||
if (this.guistate.closeAll()) {
|
||||
return
|
||||
}
|
||||
|
@ -59,7 +54,5 @@ export class WithSearchState extends WithVisualFeedbackState {
|
|||
Zoomcontrol.resetzoom()
|
||||
this.focusOnMap()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,12 +13,13 @@ import { GeocodeResult } from "../../Logic/Search/GeocodingProvider"
|
|||
* No GUI stuff
|
||||
*/
|
||||
export class WithSelectedElementState extends UserMapFeatureswitchState {
|
||||
|
||||
|
||||
readonly selectedElement: UIEventSource<Feature>
|
||||
|
||||
constructor(theme: ThemeConfig) {
|
||||
const selectedElement = new UIEventSource<Feature | undefined>(undefined, "Selected element")
|
||||
const selectedElement = new UIEventSource<Feature | undefined>(
|
||||
undefined,
|
||||
"Selected element"
|
||||
)
|
||||
super(theme, selectedElement)
|
||||
this.selectedElement = selectedElement
|
||||
this.selectedElement.addCallback((selected) => {
|
||||
|
@ -34,7 +35,6 @@ export class WithSelectedElementState extends UserMapFeatureswitchState {
|
|||
this.setSelectedElement(lastClick.nearestFeature)
|
||||
})
|
||||
|
||||
|
||||
// Add the selected element to the recently visited history
|
||||
this.selectedElement.addCallbackD((selected) => {
|
||||
const [osm_type, osm_id] = selected.properties.id.split("/")
|
||||
|
@ -47,7 +47,7 @@ export class WithSelectedElementState extends UserMapFeatureswitchState {
|
|||
selected?.properties?.local_name,
|
||||
layer?.title.GetRenderValue(selected?.properties ?? {}).txt,
|
||||
selected.properties.display_name,
|
||||
selected.properties.id
|
||||
selected.properties.id,
|
||||
]
|
||||
const r = <GeocodeResult>{
|
||||
feature: selected,
|
||||
|
@ -55,11 +55,10 @@ export class WithSelectedElementState extends UserMapFeatureswitchState {
|
|||
osm_id,
|
||||
osm_type,
|
||||
lon,
|
||||
lat
|
||||
lat,
|
||||
}
|
||||
this.userRelatedState.recentlyVisitedSearch.add(r)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
protected setSelectedElement(feature: Feature) {
|
||||
|
@ -73,6 +72,4 @@ export class WithSelectedElementState extends UserMapFeatureswitchState {
|
|||
}
|
||||
this.selectedElement.setData(feature)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -18,12 +18,11 @@ import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
|||
import NearbyFeatureSource from "../../Logic/FeatureSource/Sources/NearbyFeatureSource"
|
||||
import {
|
||||
SummaryTileSource,
|
||||
SummaryTileSourceRewriter
|
||||
SummaryTileSourceRewriter,
|
||||
} from "../../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
||||
import { ShowDataLayerOptions } from "../../UI/Map/ShowDataLayerOptions"
|
||||
|
||||
export class WithSpecialLayers extends WithChangesState {
|
||||
|
||||
readonly favourites: FavouritesFeatureSource
|
||||
/**
|
||||
* When hovering (in the popup) an image, the location of the image will be revealed on the main map.
|
||||
|
@ -42,7 +41,6 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
*/
|
||||
readonly visualFeedbackViewportBounds: UIEventSource<BBox> = new UIEventSource<BBox>(undefined)
|
||||
|
||||
|
||||
constructor(theme: ThemeConfig, mvtAvailableLayers: Store<Set<string>>) {
|
||||
super(theme, mvtAvailableLayers)
|
||||
|
||||
|
@ -57,7 +55,7 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
bounds: this.visualFeedbackViewportBounds.map(
|
||||
(bounds) => bounds ?? this.mapProperties.bounds?.data,
|
||||
[this.mapProperties.bounds]
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
this.closestFeatures.registerSource(this.favourites, "favourite")
|
||||
|
@ -85,11 +83,8 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private setupSummaryLayer(): SummaryTileSourceRewriter | undefined {
|
||||
/**
|
||||
* MaxZoom for the summary layer
|
||||
|
@ -113,17 +108,20 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)),
|
||||
this.mapProperties,
|
||||
{
|
||||
isActive: this.mapProperties.zoom.map((z) => z < maxzoom)
|
||||
isActive: this.mapProperties.zoom.map((z) => z < maxzoom),
|
||||
}
|
||||
)
|
||||
|
||||
const source = new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers)
|
||||
const source = new SummaryTileSourceRewriter(
|
||||
summaryTileSource,
|
||||
this.layerState.filteredLayers
|
||||
)
|
||||
|
||||
new ShowDataLayer(this.map, {
|
||||
features: source,
|
||||
layer: new LayerConfig(<LayerConfigJson>summaryLayer, "summaryLayer"),
|
||||
// doShowLayer: this.mapProperties.zoom.map((z) => z < maxzoom),
|
||||
selectedElement: this.selectedElement
|
||||
selectedElement: this.selectedElement,
|
||||
})
|
||||
return source
|
||||
}
|
||||
|
@ -139,7 +137,7 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
doShowLayer: flayer.isDisplayed,
|
||||
layer: flayer.layerDef,
|
||||
metaTags: this.userRelatedState.preferencesAsTags,
|
||||
selectedElement: this.selectedElement
|
||||
selectedElement: this.selectedElement,
|
||||
}
|
||||
new ShowDataLayer(this.map, options)
|
||||
}
|
||||
|
@ -154,14 +152,14 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
lastClickLayerConfig.isShown === undefined
|
||||
? source
|
||||
: source.features.mapD((fs) =>
|
||||
fs.filter((f) => {
|
||||
const matches = lastClickLayerConfig.isShown.matchesProperties(
|
||||
f.properties
|
||||
)
|
||||
console.debug("LastClick ", f, "matches", matches)
|
||||
return matches
|
||||
})
|
||||
)
|
||||
fs.filter((f) => {
|
||||
const matches = lastClickLayerConfig.isShown.matchesProperties(
|
||||
f.properties
|
||||
)
|
||||
console.debug("LastClick ", f, "matches", matches)
|
||||
return matches
|
||||
})
|
||||
)
|
||||
// show last click = new point/note marker
|
||||
const features = new StaticFeatureSource(lastClickFiltered)
|
||||
this.featureProperties.trackFeatureSource(features)
|
||||
|
@ -175,9 +173,9 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
}
|
||||
this.map.data.flyTo({
|
||||
zoom: Constants.minZoomLevelToAddNewPoint,
|
||||
center: GeoOperations.centerpointCoordinates(feature)
|
||||
center: GeoOperations.centerpointCoordinates(feature),
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -189,15 +187,17 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
}
|
||||
|
||||
private drawSpecialLayers() {
|
||||
|
||||
type AddedByDefaultTypes = (typeof Constants.added_by_default)[number]
|
||||
type LayersToAdd = "current_view" | Exclude<AddedByDefaultTypes,
|
||||
"search" // Handled by WithSearchState
|
||||
| "last_click" // handled by this.drawLastClick()
|
||||
| "summary" // handled by setupSummaryLayer
|
||||
| "range" // handled by UserMapFeatureSwitchState
|
||||
| "selected_element" // handled by this.drawSelectedElement
|
||||
>
|
||||
type LayersToAdd =
|
||||
| "current_view"
|
||||
| Exclude<
|
||||
AddedByDefaultTypes,
|
||||
| "search" // Handled by WithSearchState
|
||||
| "last_click" // handled by this.drawLastClick()
|
||||
| "summary" // handled by setupSummaryLayer
|
||||
| "range" // handled by UserMapFeatureSwitchState
|
||||
| "selected_element" // handled by this.drawSelectedElement
|
||||
>
|
||||
const empty = []
|
||||
/**
|
||||
* A listing which maps the layerId onto the featureSource
|
||||
|
@ -209,15 +209,13 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
gps_track: this.geolocation.historicalUserLocationsTrack,
|
||||
current_view: this.currentView,
|
||||
favourite: this.favourites,
|
||||
geocoded_image: new StaticFeatureSource(this.geocodedImages)
|
||||
geocoded_image: new StaticFeatureSource(this.geocodedImages),
|
||||
}
|
||||
|
||||
|
||||
// enumerate all 'normal' layers and match them with the appropriate 'special' layer - if applicable
|
||||
this.layerState.filteredLayers.forEach((flayer) => {
|
||||
this.registerSpecialLayer(flayer, specialLayers[flayer.layerDef.id])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private initActorsSpecialLayers() {
|
||||
|
@ -230,5 +228,4 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,11 @@ export class WithUserRelatedState {
|
|||
{
|
||||
// Some weird setups
|
||||
Utils.initDomPurify()
|
||||
if (!Utils.runningFromConsole && theme.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||
if (
|
||||
!Utils.runningFromConsole &&
|
||||
theme.customCss !== undefined &&
|
||||
window.location.pathname.indexOf("theme") >= 0
|
||||
) {
|
||||
Utils.LoadCustomCss(theme.customCss)
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +44,7 @@ export class WithUserRelatedState {
|
|||
"oauth_token",
|
||||
undefined,
|
||||
"Used to complete the login"
|
||||
)
|
||||
),
|
||||
})
|
||||
|
||||
this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting
|
||||
|
@ -61,7 +65,7 @@ export class WithUserRelatedState {
|
|||
icon: th.icon,
|
||||
title: th.title.translations,
|
||||
shortDescription: th.shortDescription.translations,
|
||||
layers: th.layers.filter((l) => l.isNormal()).map((l) => l.id)
|
||||
layers: th.layers.filter((l) => l.isNormal()).map((l) => l.id),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -103,5 +107,4 @@ export class WithUserRelatedState {
|
|||
}
|
||||
return this.theme.getMatchingLayer(properties)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ export class WithVisualFeedbackState extends ThemeViewState {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Selects the feature that is 'i' closest to the map center
|
||||
*/
|
||||
|
@ -65,7 +64,7 @@ export class WithVisualFeedbackState extends ThemeViewState {
|
|||
Hotkeys.RegisterHotkey(
|
||||
{
|
||||
nomod: " ",
|
||||
onUp: true
|
||||
onUp: true,
|
||||
},
|
||||
docs.selectItem,
|
||||
() => {
|
||||
|
@ -97,12 +96,11 @@ export class WithVisualFeedbackState extends ThemeViewState {
|
|||
Hotkeys.RegisterHotkey(
|
||||
{
|
||||
nomod: "" + i,
|
||||
onUp: true
|
||||
onUp: true,
|
||||
},
|
||||
doc,
|
||||
() => this.selectClosestAtCenter(i - 1)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<script lang="ts">
|
||||
import Loading from "./Loading.svelte"
|
||||
|
||||
</script>
|
||||
<div class="relative w-60 h-80">
|
||||
<div class="animate-pulse w-full h-full bg-gray-400">
|
||||
</div>
|
||||
<div class="w-full h-full absolute top-0 flex items-center justify-center">
|
||||
|
||||
<div class="relative h-80 w-60">
|
||||
<div class="h-full w-full animate-pulse bg-gray-400" />
|
||||
<div class="absolute top-0 flex h-full w-full items-center justify-center">
|
||||
<Loading />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
import PanoramaxLink from "./PanoramaxLink.svelte"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import MagnifyingGlassCircle from "@babeard/svelte-heroicons/mini/MagnifyingGlassCircle"
|
||||
import Forgejo from "../../assets/svg/Forgejo.svelte"
|
||||
|
||||
export let state: ThemeViewState
|
||||
let userdetails = state.osmConnection.userDetails
|
||||
|
@ -124,17 +125,17 @@
|
|||
</svelte:fragment>
|
||||
|
||||
<!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it -->
|
||||
<SelectedElementView
|
||||
highlightedRendering={state.guistate.highlightedUserSetting}
|
||||
layer={usersettingslayer}
|
||||
selectedElement={{
|
||||
type: "Feature",
|
||||
properties: { id: "settings" },
|
||||
geometry: { type: "Point", coordinates: [0, 0] },
|
||||
}}
|
||||
{state}
|
||||
tags={state.userRelatedState.preferencesAsTags}
|
||||
/>
|
||||
<SelectedElementView
|
||||
highlightedRendering={state.guistate.highlightedUserSetting}
|
||||
layer={usersettingslayer}
|
||||
selectedElement={{
|
||||
type: "Feature",
|
||||
properties: { id: "settings" },
|
||||
geometry: { type: "Point", coordinates: [0, 0] },
|
||||
}}
|
||||
{state}
|
||||
tags={state.userRelatedState.preferencesAsTags}
|
||||
/>
|
||||
</Page>
|
||||
|
||||
<LoginToggle {state} silentFail>
|
||||
|
@ -206,7 +207,7 @@
|
|||
{#if theme.official}
|
||||
<a
|
||||
class="flex"
|
||||
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
|
||||
href={"https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/Themes" +
|
||||
theme.id +
|
||||
".md"}
|
||||
target="_blank"
|
||||
|
@ -281,12 +282,16 @@
|
|||
<Tr t={Translations.t.inspector.menu} />
|
||||
</a>
|
||||
|
||||
<a class="flex" href="https://github.com/pietervdvn/MapComplete/" target="_blank">
|
||||
<Github class="h-6 w-6" />
|
||||
<a class="flex" href="https://source.mapcomplete.org/MapComplete/MapComplete/" target="_blank">
|
||||
<Forgejo class="h-6 w-6" />
|
||||
<Tr t={Translations.t.general.attribution.gotoSourceCode} />
|
||||
</a>
|
||||
|
||||
<a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank">
|
||||
<a
|
||||
class="flex"
|
||||
href="https://source.mapcomplete.org/MapComplete/MapComplete/issues"
|
||||
target="_blank"
|
||||
>
|
||||
<Bug class="h-6 w-6" />
|
||||
<Tr t={Translations.t.general.attribution.openIssueTracker} />
|
||||
</a>
|
||||
|
|
|
@ -60,7 +60,9 @@
|
|||
export let presetProperties: Tag[] = []
|
||||
let presetPropertiesUnpacked = TagUtils.KVtoProperties(presetProperties)
|
||||
|
||||
export let snappedTo: UIEventSource<WayId | undefined> = new UIEventSource<WayId | undefined>(undefined)
|
||||
export let snappedTo: UIEventSource<WayId | undefined> = new UIEventSource<WayId | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
const map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined)
|
||||
export let mapProperties: Partial<MapProperties> & { location } = {
|
||||
|
|
|
@ -137,11 +137,7 @@
|
|||
>
|
||||
{#each $unknownImages as image (image)}
|
||||
<div class="relative flex w-fit items-center bg-gray-200">
|
||||
<AttributedImage
|
||||
{state}
|
||||
imgClass="h-32 shrink-0"
|
||||
image={{ url: image, id: image }}
|
||||
/>
|
||||
<AttributedImage {state} imgClass="h-32 shrink-0" image={{ url: image, id: image }} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -6,17 +6,13 @@
|
|||
export let stack: string[]
|
||||
|
||||
function offerDefinitionForDownload() {
|
||||
Utils.offerContentsAsDownloadableFile(
|
||||
customDefinition,
|
||||
"mapcomplete-theme.json",
|
||||
{ mimetype: "application/json" }
|
||||
)
|
||||
Utils.offerContentsAsDownloadableFile(customDefinition, "mapcomplete-theme.json", {
|
||||
mimetype: "application/json",
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col w-full h-full m-8 justify-center items-center">
|
||||
|
||||
<div class="m-8 flex h-full w-full flex-col items-center justify-center">
|
||||
<h1>Something went wrong</h1>
|
||||
<div class="alert">{stack[0]}</div>
|
||||
{#each stack.slice(1) as stck}
|
||||
|
@ -24,7 +20,7 @@
|
|||
{/each}
|
||||
{#if customDefinition}
|
||||
<button on:click={() => offerDefinitionForDownload()}>
|
||||
<ArrowDownTray class="w-16 h-16" />
|
||||
<ArrowDownTray class="h-16 w-16" />
|
||||
Download the theme definition file
|
||||
</button>
|
||||
{/if}
|
||||
|
|
|
@ -145,11 +145,7 @@
|
|||
|
||||
<div class="relative w-fit shrink-0" style="scroll-snap-align: start">
|
||||
<div class="relative flex max-w-max items-center bg-gray-200">
|
||||
<AttributedImage
|
||||
imgClass="carousel-max-height"
|
||||
{image}
|
||||
{state}
|
||||
>
|
||||
<AttributedImage imgClass="carousel-max-height" {image} {state}>
|
||||
<svelte:fragment slot="dot-menu-actions">
|
||||
<button on:click={() => ImageProvider.offerImageAsDownload(image)}>
|
||||
<DownloadIcon />
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
export let tags: UIEventSource<Record<string, string>>
|
||||
|
||||
export let estimated: Store<number>
|
||||
|
||||
</script>
|
||||
|
||||
{#if $estimated > 0 && $images.length < 1}
|
||||
<LoadingPlaceholder />
|
||||
{:else}
|
||||
|
|
|
@ -123,7 +123,10 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
argsRaw: string[]
|
||||
): string[] {
|
||||
const deps = ImportFlowUtils.getLayerDependencies(argsRaw, argSpec)
|
||||
const argsParsed: PointImportFlowArguments = Utils.ParseVisArgs <PointImportFlowArguments>(argSpec, argsRaw)
|
||||
const argsParsed: PointImportFlowArguments = Utils.ParseVisArgs<PointImportFlowArguments>(
|
||||
argSpec,
|
||||
argsRaw
|
||||
)
|
||||
const snapOntoLayers = argsParsed.snap_onto_layers?.split(";")?.map((l) => l.trim()) ?? []
|
||||
deps.push(...snapOntoLayers)
|
||||
return deps
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
seenFreeforms.push(newProps[confg.freeform.key])
|
||||
}
|
||||
return matches
|
||||
})
|
||||
}),
|
||||
]
|
||||
|
||||
if (tgs !== undefined && confg.freeform) {
|
||||
|
@ -226,7 +226,7 @@
|
|||
freeform: $freeformInput,
|
||||
selectedMapping,
|
||||
checkedMappings,
|
||||
currentTags: tags.data
|
||||
currentTags: tags.data,
|
||||
},
|
||||
" --> ",
|
||||
selectedTags
|
||||
|
@ -284,7 +284,7 @@
|
|||
dispatch("saved", { config, applied: selectedTags })
|
||||
const change = new ChangeTagAction(tags.data.id, selectedTags, tags.data, {
|
||||
theme: tags.data["_orig_theme"] ?? state.theme.id,
|
||||
changeType: "answer"
|
||||
changeType: "answer",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
selectedMapping = undefined
|
||||
|
@ -328,7 +328,7 @@
|
|||
const tagsToSet = settableKeys.data.map((k) => new Tag(k, ""))
|
||||
const change = new ChangeTagAction(tags.data.id, new And(tagsToSet), tags.data, {
|
||||
theme: tags.data["_orig_theme"] ?? state.theme.id,
|
||||
changeType: "answer"
|
||||
changeType: "answer",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
selectedMapping = undefined
|
||||
|
@ -546,10 +546,7 @@
|
|||
{#if config.alwaysForceSaveButton}
|
||||
<button
|
||||
on:click={() => onSave()}
|
||||
class={twJoin(
|
||||
selectedTags === undefined ? "disabled" : "button-shadow",
|
||||
"primary"
|
||||
)}
|
||||
class={twJoin(selectedTags === undefined ? "disabled" : "button-shadow", "primary")}
|
||||
>
|
||||
<Tr t={Translations.t.general.save} />
|
||||
</button>
|
||||
|
|
|
@ -1,62 +1,61 @@
|
|||
<script lang="ts">/**
|
||||
* Wrapper around 'ThemeViewGui', which is responsible for some boiler plate things, such as:
|
||||
*
|
||||
* - Checking for WebGL support
|
||||
* - Loading the available layers
|
||||
* - ...
|
||||
*/
|
||||
import ThemeViewGUI from "./ThemeViewGUI.svelte"
|
||||
import Constants from "../Models/Constants.js"
|
||||
import { Utils } from "../Utils.js"
|
||||
import { UIEventSource } from "../Logic/UIEventSource"
|
||||
import { WithSearchState } from "../Models/ThemeViewState/WithSearchState"
|
||||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
<script lang="ts">
|
||||
/**
|
||||
* Wrapper around 'ThemeViewGui', which is responsible for some boiler plate things, such as:
|
||||
*
|
||||
* - Checking for WebGL support
|
||||
* - Loading the available layers
|
||||
* - ...
|
||||
*/
|
||||
import ThemeViewGUI from "./ThemeViewGUI.svelte"
|
||||
import Constants from "../Models/Constants.js"
|
||||
import { Utils } from "../Utils.js"
|
||||
import { UIEventSource } from "../Logic/UIEventSource"
|
||||
import { WithSearchState } from "../Models/ThemeViewState/WithSearchState"
|
||||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
|
||||
function webgl_support() {
|
||||
try {
|
||||
const canvas = document.createElement("canvas")
|
||||
if (
|
||||
!!window.WebGLRenderingContext &&
|
||||
(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))
|
||||
) {
|
||||
return true
|
||||
function webgl_support() {
|
||||
try {
|
||||
const canvas = document.createElement("canvas")
|
||||
if (
|
||||
!!window.WebGLRenderingContext &&
|
||||
(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function getAvailableLayers(): Promise<Set<string>> {
|
||||
if (!Constants.SummaryServer) {
|
||||
return new Set<string>()
|
||||
async function getAvailableLayers(): Promise<Set<string>> {
|
||||
if (!Constants.SummaryServer) {
|
||||
return new Set<string>()
|
||||
}
|
||||
try {
|
||||
const host = new URL(Constants.SummaryServer).host
|
||||
const status: { layers: string[] } = await Promise.any([
|
||||
Utils.downloadJson<{ layers }>("https://" + host + "/summary/status.json"),
|
||||
Utils.waitFor(2500, { layers: [] }),
|
||||
])
|
||||
return new Set<string>(status.layers)
|
||||
} catch (e) {
|
||||
console.error("Could not get MVT available layers due to", e)
|
||||
return new Set<string>()
|
||||
}
|
||||
}
|
||||
try {
|
||||
const host = new URL(Constants.SummaryServer).host
|
||||
const status: { layers: string[] } = await Promise.any([
|
||||
Utils.downloadJson<{ layers }>("https://" + host + "/summary/status.json"),
|
||||
Utils.waitFor(2500, { layers: [] })
|
||||
])
|
||||
return new Set<string>(status.layers)
|
||||
} catch (e) {
|
||||
console.error("Could not get MVT available layers due to", e)
|
||||
return new Set<string>()
|
||||
}
|
||||
}
|
||||
|
||||
export let theme: ThemeConfig
|
||||
export let theme: ThemeConfig
|
||||
|
||||
let webgl_supported = webgl_support()
|
||||
|
||||
let availableLayers = UIEventSource.FromPromise(getAvailableLayers())
|
||||
const state = new WithSearchState(theme, availableLayers)
|
||||
let webgl_supported = webgl_support()
|
||||
|
||||
let availableLayers = UIEventSource.FromPromise(getAvailableLayers())
|
||||
const state = new WithSearchState(theme, availableLayers)
|
||||
</script>
|
||||
|
||||
{#if !webgl_supported}
|
||||
<div class="alert w-full h-full justify-center items-center m-8">WebGL is not supported or not enabled. This is
|
||||
essential
|
||||
for MapComplete to function, please enable this.
|
||||
<div class="alert m-8 h-full w-full items-center justify-center">
|
||||
WebGL is not supported or not enabled. This is essential for MapComplete to function, please
|
||||
enable this.
|
||||
</div>
|
||||
{:else}
|
||||
<ThemeViewGUI {state} />
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||
import BaseUIElement from "./BaseUIElement"
|
||||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
|
||||
import {
|
||||
FeatureSource,
|
||||
IndexedFeatureSource,
|
||||
WritableFeatureSource,
|
||||
} from "../Logic/FeatureSource/FeatureSource"
|
||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||
import { Changes } from "../Logic/Osm/Changes"
|
||||
import { ExportableMap, MapProperties } from "../Models/MapProperties"
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
let lastIsString = false
|
||||
{
|
||||
|
||||
const types: string | string[] = Array.isArray(schema.type)
|
||||
? schema.type[schema.type.length - 1]["type"]
|
||||
: []
|
||||
|
@ -64,7 +63,7 @@
|
|||
inline: true,
|
||||
type: schema.hints.typehint,
|
||||
addExtraTags: ["chosen_type_index="],
|
||||
helperArgs: []
|
||||
helperArgs: [],
|
||||
},
|
||||
}
|
||||
let tags = new UIEventSource<Record<string, string>>({})
|
||||
|
|
|
@ -1125,8 +1125,8 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
element.click()
|
||||
}
|
||||
|
||||
public static async waitFor(timeMillis: number): Promise<void>;
|
||||
public static async waitFor<T>(timeMillis: number, t: T): Promise<T>;
|
||||
public static async waitFor(timeMillis: number): Promise<void>
|
||||
public static async waitFor<T>(timeMillis: number, t: T): Promise<T>
|
||||
|
||||
public static async waitFor<T = void>(timeMillis: number, t: T): Promise<T> {
|
||||
return new Promise((resolve) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"contributors": [
|
||||
{
|
||||
"commits": 8870,
|
||||
"commits": 8941,
|
||||
"contributor": "Pieter Vander Vennet"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -181,9 +181,9 @@
|
|||
"ar"
|
||||
],
|
||||
"ER": [
|
||||
"en",
|
||||
"ar",
|
||||
"ti",
|
||||
"en"
|
||||
"ti"
|
||||
],
|
||||
"ES": [
|
||||
"es",
|
||||
|
@ -236,9 +236,9 @@
|
|||
"fr"
|
||||
],
|
||||
"GQ": [
|
||||
"pt",
|
||||
"fr",
|
||||
"es",
|
||||
"pt"
|
||||
"es"
|
||||
],
|
||||
"GR": [
|
||||
"el"
|
||||
|
@ -309,7 +309,6 @@
|
|||
"sw"
|
||||
],
|
||||
"KG": [
|
||||
"ru",
|
||||
"ky"
|
||||
],
|
||||
"KH": [
|
||||
|
|
|
@ -10121,7 +10121,6 @@
|
|||
"_meta": {
|
||||
"countries": [
|
||||
"BY",
|
||||
"KG",
|
||||
"KZ",
|
||||
"RU",
|
||||
"TJ"
|
||||
|
|
|
@ -10920,6 +10920,10 @@
|
|||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=dog_toilet",
|
||||
"then": "dog_toilet - A dog toilet is a facility designated for dogs to urinate and excrete. This can be a designated, signposted patch of grass, a sand pit or a fenced area."
|
||||
},
|
||||
{
|
||||
"if": "value=dogpark",
|
||||
"then": "dogpark - A layer showing dogparks, which are areas where dog are allowed to run without a leash"
|
||||
|
|
|
@ -799,6 +799,10 @@
|
|||
"if": "value=doctors",
|
||||
"then": "<b>doctors</b> (builtin) - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=dog_toilet",
|
||||
"then": "<b>dog_toilet</b> (builtin) - A dog toilet is a facility designated for dogs to urinate and excrete. This can be a designated, signposted patch of grass, a sand pit or a fenced area."
|
||||
},
|
||||
{
|
||||
"if": "value=dogpark",
|
||||
"then": "<b>dogpark</b> (builtin) - A layer showing dogparks, which are areas where dog are allowed to run without a leash"
|
||||
|
@ -13531,6 +13535,10 @@
|
|||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=dog_toilet",
|
||||
"then": "dog_toilet - A dog toilet is a facility designated for dogs to urinate and excrete. This can be a designated, signposted patch of grass, a sand pit or a fenced area."
|
||||
},
|
||||
{
|
||||
"if": "value=dogpark",
|
||||
"then": "dogpark - A layer showing dogparks, which are areas where dog are allowed to run without a leash"
|
||||
|
@ -35299,6 +35307,10 @@
|
|||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=dog_toilet",
|
||||
"then": "dog_toilet - A dog toilet is a facility designated for dogs to urinate and excrete. This can be a designated, signposted patch of grass, a sand pit or a fenced area."
|
||||
},
|
||||
{
|
||||
"if": "value=dogpark",
|
||||
"then": "dogpark - A layer showing dogparks, which are areas where dog are allowed to run without a leash"
|
||||
|
|
4
src/assets/svg/Forgejo.svelte
Normal file
4
src/assets/svg/Forgejo.svelte
Normal file
|
@ -0,0 +1,4 @@
|
|||
<script>
|
||||
export let color = "#000000"
|
||||
</script>
|
||||
<svg {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave on:keydown on:focus viewBox="0 0 212 212" xmlns="http://www.w3.org/2000/svg"> <metadata xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" > <rdf:RDF> <cc:Work rdf:about="https://codeberg.org/forgejo/meta/src/branch/readme/branding#logo"> <dc:title>Forgejo logo</dc:title> <cc:creator rdf:resource="https://caesarschinas.com/"><cc:attributionName>Caesar Schinas</cc:attributionName></cc:creator> <cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" /> </cc:Work> </rdf:RDF> </metadata> <style type="text/css"> circle { fill: none !important; stroke: {color}; stroke-width: 15; } path { fill: none !important; stroke: {color}; stroke-width: 25; } .orange { stroke:#ff6600; } .red { stroke:#d40000; } </style> <g transform="translate(6,6)"> <path d="M58 168 v-98 a50 50 0 0 1 50-50 h20" class="orange" /> <path d="M58 168 v-30 a50 50 0 0 1 50-50 h20" class="red" /> <circle cx="142" cy="20" r="18" class="orange" /> <circle cx="142" cy="88" r="18" class="red" /> <circle cx="58" cy="180" r="18" class="red" /> </g> </svg>
|
|
@ -17,7 +17,7 @@
|
|||
"contributor": "Anonymous"
|
||||
},
|
||||
{
|
||||
"commits": 112,
|
||||
"commits": 119,
|
||||
"contributor": "mcliquid"
|
||||
},
|
||||
{
|
||||
|
@ -29,7 +29,7 @@
|
|||
"contributor": "Robin van der Linde"
|
||||
},
|
||||
{
|
||||
"commits": 80,
|
||||
"commits": 82,
|
||||
"contributor": "mike140"
|
||||
},
|
||||
{
|
||||
|
@ -216,6 +216,10 @@
|
|||
"commits": 9,
|
||||
"contributor": "Jacque Fresco"
|
||||
},
|
||||
{
|
||||
"commits": 8,
|
||||
"contributor": "Weblate Admin"
|
||||
},
|
||||
{
|
||||
"commits": 8,
|
||||
"contributor": "Joost Schouppe"
|
||||
|
@ -228,10 +232,6 @@
|
|||
"commits": 8,
|
||||
"contributor": "Vinicius"
|
||||
},
|
||||
{
|
||||
"commits": 7,
|
||||
"contributor": "Weblate Admin"
|
||||
},
|
||||
{
|
||||
"commits": 7,
|
||||
"contributor": "Franco"
|
||||
|
@ -588,6 +588,14 @@
|
|||
"commits": 2,
|
||||
"contributor": "Leo Alcaraz"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "Manuel"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "Hufkratzer"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "Túllio Morais Franca"
|
||||
|
|
|
@ -2,7 +2,6 @@ import DetermineTheme from "./Logic/DetermineTheme"
|
|||
import SingleThemeGui from "./UI/SingleThemeGui.svelte"
|
||||
import CustomThemeError from "./UI/CustomThemeError.svelte"
|
||||
|
||||
|
||||
async function main() {
|
||||
const target = document.getElementById("maindiv")
|
||||
const childs = Array.from(target.children)
|
||||
|
@ -10,7 +9,7 @@ async function main() {
|
|||
const theme = await DetermineTheme.getTheme()
|
||||
new SingleThemeGui({
|
||||
target,
|
||||
props: { theme }
|
||||
props: { theme },
|
||||
})
|
||||
childs.forEach((ch) => target.removeChild(ch))
|
||||
Array.from(document.getElementsByClassName("delete-on-load")).forEach((el) => {
|
||||
|
@ -24,10 +23,9 @@ async function main() {
|
|||
target,
|
||||
props: {
|
||||
stack: err.toString().split("\n"),
|
||||
customDefinition
|
||||
}
|
||||
customDefinition,
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue