forked from MapComplete/MapComplete
Merge remote-tracking branch 'source/master' into develop
This commit is contained in:
commit
b7a4930583
113 changed files with 2402 additions and 1435 deletions
|
@ -66,15 +66,19 @@ export default class InitialMapPositioning {
|
|||
defaultLon,
|
||||
"The initial/current longitude of the app"
|
||||
)
|
||||
const geouri = QueryParameters.GetQueryParameter("geouri", undefined, "Alternative format to set lat/lon; but with an entire geouri instead. ")
|
||||
console.log("geouri", geouri.data, !!geouri.data)
|
||||
if (geouri.data) {
|
||||
const geouri = QueryParameters.GetQueryParameter(
|
||||
"geouri",
|
||||
undefined,
|
||||
"Alternative format to set lat/lon; but with an entire geouri instead. "
|
||||
)
|
||||
console.log("geouri", geouri.data, !!geouri.data)
|
||||
if (geouri.data) {
|
||||
try {
|
||||
const url = new URL("geo:"+decodeURIComponent(geouri.data))
|
||||
const [latN, lonN] = url.pathname.split(",").map(n => parseFloat(n))
|
||||
const url = new URL("geo:" + decodeURIComponent(geouri.data))
|
||||
const [latN, lonN] = url.pathname.split(",").map((n) => parseFloat(n))
|
||||
lat.set(latN)
|
||||
lon.set(lonN)
|
||||
if(url.searchParams.has("q")){
|
||||
if (url.searchParams.has("q")) {
|
||||
QueryParameters.GetQueryParameter("q", undefined).set(url.searchParams.get("q"))
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -265,7 +265,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
features = [features]
|
||||
}
|
||||
|
||||
let allFeatures: Feature[][] = []
|
||||
const allFeatures: Feature[][] = []
|
||||
for (const spec of features) {
|
||||
if (typeof spec === "string") {
|
||||
const name = spec
|
||||
|
@ -284,7 +284,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
}
|
||||
|
||||
const selfCenter = GeoOperations.centerpointCoordinates(feature)
|
||||
let closestFeatures: { feat: any; distance: number }[] = []
|
||||
const closestFeatures: { feat: any; distance: number }[] = []
|
||||
|
||||
for (const feats of allFeatures ?? []) {
|
||||
for (const otherFeature of feats) {
|
||||
|
|
|
@ -25,7 +25,7 @@ export default class FeatureSourceMerger<Src extends FeatureSource = FeatureSour
|
|||
this.featuresById = this._featuresById
|
||||
const self = this
|
||||
sources = Utils.NoNull(sources)
|
||||
for (let source of sources) {
|
||||
for (const source of sources) {
|
||||
source.features.addCallback(() => {
|
||||
self.addDataFromSources(sources)
|
||||
})
|
||||
|
|
|
@ -34,7 +34,7 @@ export class PolygonSourceMerger extends UpdatableDynamicTileSource<
|
|||
const zooms: Map<string, number> = new Map()
|
||||
|
||||
for (const source of sources) {
|
||||
let z = source.z
|
||||
const z = source.z
|
||||
for (const f of source.features.data) {
|
||||
const id = f.properties.id
|
||||
if (id.endsWith("146616907")) {
|
||||
|
|
|
@ -35,8 +35,9 @@ export default class GenericImageProvider extends ImageProvider {
|
|||
id: value,
|
||||
isSpherical: undefined,
|
||||
originalAttribute: {
|
||||
key, value
|
||||
}
|
||||
key,
|
||||
value,
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export interface ProvidedImage {
|
|||
host?: string
|
||||
isSpherical: boolean
|
||||
license?: LicenseInfo
|
||||
originalAttribute?: {key: string, value: string}
|
||||
originalAttribute?: { key: string; value: string }
|
||||
}
|
||||
|
||||
export interface PanoramaView {
|
||||
|
|
|
@ -180,13 +180,13 @@ export class ImageUploadManager {
|
|||
queue = [...queue]
|
||||
while (queue.length > 0) {
|
||||
const currentItem = queue.shift()
|
||||
if(!currentItem){
|
||||
if (!currentItem) {
|
||||
continue
|
||||
}
|
||||
const uploadOk = await this.handleQueueItem(currentItem)
|
||||
if(uploadOk){
|
||||
if (uploadOk) {
|
||||
this._queue.delete(currentItem)
|
||||
}else{
|
||||
} else {
|
||||
// Our local 'queue' is a copy where we've removed the failed item from
|
||||
// A next attempt to 'uploadQueue' will retry the upload
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ export class ImageUploadManager {
|
|||
if (properties === undefined) {
|
||||
const downloaded = await new OsmObjectDownloader(
|
||||
this._osmConnection.Backend(),
|
||||
this._changes,
|
||||
this._changes
|
||||
).DownloadObjectAsync(args.featureId)
|
||||
if (downloaded === "deleted") {
|
||||
this._queue.delete(args)
|
||||
|
@ -264,16 +264,10 @@ export class ImageUploadManager {
|
|||
this._featureProperties.trackFeature(downloaded.asGeoJson())
|
||||
properties = this._featureProperties.getStore(args.featureId)
|
||||
}
|
||||
const action = new LinkImageAction(
|
||||
args.featureId,
|
||||
result.key,
|
||||
result.value,
|
||||
properties,
|
||||
{
|
||||
theme: args.layoutId ?? properties?.data?.["_orig_theme"] ?? this._theme.id,
|
||||
changeType: "add-image",
|
||||
},
|
||||
)
|
||||
const action = new LinkImageAction(args.featureId, result.key, result.value, properties, {
|
||||
theme: args.layoutId ?? properties?.data?.["_orig_theme"] ?? this._theme.id,
|
||||
changeType: "add-image",
|
||||
})
|
||||
await this._changes.applyAction(action)
|
||||
await this._changes.flushChanges("Image upload completed")
|
||||
return true
|
||||
|
@ -303,7 +297,7 @@ export class ImageUploadManager {
|
|||
let absoluteUrl: string
|
||||
|
||||
try {
|
||||
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||
({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||
blob,
|
||||
location,
|
||||
author,
|
||||
|
|
|
@ -33,7 +33,7 @@ export class Imgur extends ImageProvider {
|
|||
provider: this,
|
||||
id: value,
|
||||
isSpherical: false,
|
||||
originalAttribute: {key, value}
|
||||
originalAttribute: { key, value },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ export class Mapillary extends ImageProvider {
|
|||
response.camera_type === "spherical" || response.camera_type === "equirectangular",
|
||||
lat: geometry.coordinates[1],
|
||||
lon: geometry.coordinates[0],
|
||||
originalAttribute: {key, value}
|
||||
originalAttribute: { key, value },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,14 +260,15 @@ export class Mapillary extends ImageProvider {
|
|||
return Mapillary.createLink(location, 17, image.id)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if we are in firefox strict mode (or if we are offline)
|
||||
* @private
|
||||
*/
|
||||
private static async checkStrictMode(): Promise<boolean> {
|
||||
try {
|
||||
const result = await fetch("https://scontent-bru2-1.xx.fbcdn.net/m1/v/t6/Xn8-ISUUYQyBD9FyACzPFRGZnBJRqIFmnQ_yd7FU6vxFYwD21fvAcZwDQoMzsScxcQyCWeBviKpWO4nX8yf--neJDvVjC4JlQtfBYb6TrpXQTniyafSFeZeePT_NVx3H6gMjceEvXHyvBqOOcCB_xQ?stp=c2048.2048.2000.988a_s1000x1000&_nc_gid=E2oHnrAtHutVvjaIm9qDLg&_nc_oc=AdkcScR9HuKt1X_K5-GrUeR5Paj8d7MsNFFYEBSmgc0IiBey_wS3RiNJpflWIKaQzNE&ccb=10-5&oh=00_AfNJ1Ki1IeGdUMxdFUc3ZX9VYIVFxVfXZ9MUATU3vj_RJw&oe=686AF002&_nc_sid=201bca")
|
||||
const result = await fetch(
|
||||
"https://scontent-bru2-1.xx.fbcdn.net/m1/v/t6/Xn8-ISUUYQyBD9FyACzPFRGZnBJRqIFmnQ_yd7FU6vxFYwD21fvAcZwDQoMzsScxcQyCWeBviKpWO4nX8yf--neJDvVjC4JlQtfBYb6TrpXQTniyafSFeZeePT_NVx3H6gMjceEvXHyvBqOOcCB_xQ?stp=c2048.2048.2000.988a_s1000x1000&_nc_gid=E2oHnrAtHutVvjaIm9qDLg&_nc_oc=AdkcScR9HuKt1X_K5-GrUeR5Paj8d7MsNFFYEBSmgc0IiBey_wS3RiNJpflWIKaQzNE&ccb=10-5&oh=00_AfNJ1Ki1IeGdUMxdFUc3ZX9VYIVFxVfXZ9MUATU3vj_RJw&oe=686AF002&_nc_sid=201bca"
|
||||
)
|
||||
console.log("Not blocked, got a forbidden", result.status)
|
||||
return false
|
||||
} catch (e) {
|
||||
|
|
|
@ -174,7 +174,7 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
}
|
||||
const providedImage = await this.getInfo(value)
|
||||
providedImage.alt_id = alt_id
|
||||
providedImage.originalAttribute = {key, value}
|
||||
providedImage.originalAttribute = { key, value }
|
||||
return [providedImage]
|
||||
}
|
||||
|
||||
|
|
|
@ -61,9 +61,9 @@ export class WikidataImageProvider extends ImageProvider {
|
|||
allImages.push(promises)
|
||||
}
|
||||
const resolved = await Promise.all(Utils.NoNull(allImages))
|
||||
const flattened = resolved.flatMap( x => x)
|
||||
if(flattened.length === 1){
|
||||
flattened[0].originalAttribute = {key, value}
|
||||
const flattened = resolved.flatMap((x) => x)
|
||||
if (flattened.length === 1) {
|
||||
flattened[0].originalAttribute = { key, value }
|
||||
}
|
||||
return flattened
|
||||
}
|
||||
|
|
|
@ -221,8 +221,8 @@ export class WikimediaImageProvider extends ImageProvider {
|
|||
id: image,
|
||||
isSpherical: false,
|
||||
}
|
||||
if(key && value){
|
||||
providedImage.originalAttribute = {key, value}
|
||||
if (key && value) {
|
||||
providedImage.originalAttribute = { key, value }
|
||||
}
|
||||
return providedImage
|
||||
}
|
||||
|
|
|
@ -110,11 +110,11 @@ export class TurnRestrictionRSH extends AbstractRelationSplitHandler {
|
|||
// We have to keep only the way with a common point with the rest of the relation
|
||||
// Let's figure out which member is neighbouring our way
|
||||
|
||||
let commonStartPoint: number = await this.targetNodeAt(members.indexOf(selfMember), true)
|
||||
let commonEndPoint: number = await this.targetNodeAt(members.indexOf(selfMember), false)
|
||||
const commonStartPoint: number = await this.targetNodeAt(members.indexOf(selfMember), true)
|
||||
const commonEndPoint: number = await this.targetNodeAt(members.indexOf(selfMember), false)
|
||||
|
||||
// In normal circumstances, only one of those should be defined
|
||||
let commonPoint = commonStartPoint ?? commonEndPoint
|
||||
const commonPoint = commonStartPoint ?? commonEndPoint
|
||||
|
||||
// Let's select the way to keep
|
||||
const idToKeep: { id: number } = this._input.allWaysNodesInOrder
|
||||
|
|
|
@ -120,7 +120,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
const allWaysNodesInOrder: number[][] = []
|
||||
// Lets create OsmWays based on them
|
||||
for (const wayPart of wayParts) {
|
||||
let isOriginal = wayPart === longest
|
||||
const isOriginal = wayPart === longest
|
||||
if (isOriginal) {
|
||||
// We change the existing way
|
||||
const nodeIds = wayPart.map((p) => p.originalIndex)
|
||||
|
@ -140,7 +140,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
allWayIdsInOrder.push(originalElement.id)
|
||||
allWaysNodesInOrder.push(nodeIds)
|
||||
} else {
|
||||
let id = changes.getNewID()
|
||||
const id = changes.getNewID()
|
||||
// Copy the tags from the original object onto the new
|
||||
const kv = []
|
||||
for (const k in originalElement.tags) {
|
||||
|
@ -219,7 +219,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
// - `index`: closest point was found on nth line part,
|
||||
// - `dist`: distance between pt and the closest point,
|
||||
// `location`: distance along the line between start and the closest point.
|
||||
let projected = GeoOperations.nearestPoint(wayGeoJson, c)
|
||||
const projected = GeoOperations.nearestPoint(wayGeoJson, c)
|
||||
// c is lon lat
|
||||
return {
|
||||
coordinates: c,
|
||||
|
@ -232,8 +232,8 @@ export default class SplitAction extends OsmChangeAction {
|
|||
// We have a bunch of coordinates here: [ [lon, lon], [lat, lon], ...] ...
|
||||
// We project them onto the line (which should yield pretty much the same point and add them to allPoints
|
||||
for (let i = 0; i < originalPoints.length; i++) {
|
||||
let originalPoint = originalPoints[i]
|
||||
let projected = GeoOperations.nearestPoint(wayGeoJson, originalPoint)
|
||||
const originalPoint = originalPoints[i]
|
||||
const projected = GeoOperations.nearestPoint(wayGeoJson, originalPoint)
|
||||
allPoints.push({
|
||||
coordinates: originalPoint,
|
||||
isSplitPoint: false,
|
||||
|
|
|
@ -24,7 +24,7 @@ export default class AspectedRouting {
|
|||
|
||||
let functionName /*: string*/ = undefined
|
||||
let functionArguments /*: any */ = undefined
|
||||
let otherValues = {}
|
||||
const otherValues = {}
|
||||
// @ts-ignore
|
||||
Object.entries(program).forEach((tag) => {
|
||||
const [key, value] = tag
|
||||
|
@ -135,9 +135,9 @@ export default class AspectedRouting {
|
|||
private static getFirstMatchScore(tags, order: any) {
|
||||
/*Order should be a list of arguments after evaluation*/
|
||||
order = <string[]>AspectedRouting.interpret(order, tags)
|
||||
for (let key of order) {
|
||||
for (const key of order) {
|
||||
// @ts-ignore
|
||||
for (let entry of Object.entries(JSON.parse(tags))) {
|
||||
for (const entry of Object.entries(JSON.parse(tags))) {
|
||||
const [tagKey, value] = entry
|
||||
if (key === tagKey) {
|
||||
// We have a match... let's evaluate the subprogram
|
||||
|
|
|
@ -269,20 +269,23 @@ export default class UserRelatedState {
|
|||
)
|
||||
this.language = this.osmConnection.getPreference("language")
|
||||
this.showTags = this.osmConnection.getPreference("show_tags")
|
||||
this.showTagsB = this.showTags.map(showTags => {
|
||||
if (showTags === "always" || showTags === "full") {
|
||||
return true
|
||||
}
|
||||
if (showTags === "no") {
|
||||
return false
|
||||
}
|
||||
const userdetails = this.osmConnection.userDetails.data
|
||||
if (!userdetails) {
|
||||
return false
|
||||
}
|
||||
const csCount = userdetails.csCount
|
||||
return csCount >= Constants.userJourney.tagsVisibleAt
|
||||
}, [this.osmConnection.userDetails])
|
||||
this.showTagsB = this.showTags.map(
|
||||
(showTags) => {
|
||||
if (showTags === "always" || showTags === "full") {
|
||||
return true
|
||||
}
|
||||
if (showTags === "no") {
|
||||
return false
|
||||
}
|
||||
const userdetails = this.osmConnection.userDetails.data
|
||||
if (!userdetails) {
|
||||
return false
|
||||
}
|
||||
const csCount = userdetails.csCount
|
||||
return csCount >= Constants.userJourney.tagsVisibleAt
|
||||
},
|
||||
[this.osmConnection.userDetails]
|
||||
)
|
||||
this.showCrosshair = this.osmConnection.getPreference("show_crosshair")
|
||||
this.fixateNorth = this.osmConnection.getPreference("fixate-north")
|
||||
this.morePrivacy = this.osmConnection.getPreference("more_privacy", { defaultValue: "no" })
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ export default class LinkedDataLoader {
|
|||
return await LinkedDataLoader.compact(data, options)
|
||||
}
|
||||
|
||||
let htmlContent = await Utils.download(url)
|
||||
const htmlContent = await Utils.download(url)
|
||||
const div = document.createElement("div")
|
||||
div.innerHTML = htmlContent
|
||||
const script = Array.from(div.getElementsByTagName("script")).find(
|
||||
|
|
|
@ -234,7 +234,7 @@ export default class Wikidata {
|
|||
}[]
|
||||
> {
|
||||
const maxCount = options?.maxCount ?? 20
|
||||
let pageCount = Math.min(maxCount, 50)
|
||||
const pageCount = Math.min(maxCount, 50)
|
||||
const start = page * pageCount - pageCount
|
||||
const lang = options?.lang ?? "en"
|
||||
const url =
|
||||
|
|
|
@ -69,15 +69,13 @@ export class AvailableRasterLayers {
|
|||
console.log("Invalid layers:", JSON.stringify(joined.filter((l) => !l.id)))
|
||||
throw "Detected invalid global layer with invalid id"
|
||||
}
|
||||
return joined.map(
|
||||
(properties) => {
|
||||
return <RasterLayerPolygon>{
|
||||
type: "Feature",
|
||||
properties,
|
||||
geometry: BBox.global.asGeometry(),
|
||||
}
|
||||
return joined.map((properties) => {
|
||||
return <RasterLayerPolygon>{
|
||||
type: "Feature",
|
||||
properties,
|
||||
geometry: BBox.global.asGeometry(),
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -170,7 +170,10 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
|||
|
||||
export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
||||
constructor() {
|
||||
super("AddQuestionBox", "Adds a 'questions'-object if no question element is added yet. Will ignore all elements which were previously asked for (and questions labeled with 'hidden')")
|
||||
super(
|
||||
"AddQuestionBox",
|
||||
"Adds a 'questions'-object if no question element is added yet. Will ignore all elements which were previously asked for (and questions labeled with 'hidden')"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,14 +213,12 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
(sp) => sp.args.length === 0 || sp.args[0].trim() === ""
|
||||
)
|
||||
|
||||
|
||||
if (noLabels.length > 1) {
|
||||
context.err(
|
||||
"Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this - questions will be shown twice. Did you perhaps import all questions from another layer?",
|
||||
"Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this - questions will be shown twice. Did you perhaps import all questions from another layer?"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We want to construct a questionbox that shows all leftover questions.
|
||||
* For this, we need to determine what those leftover questions _are_ in the first place.
|
||||
|
@ -227,14 +228,14 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
|
||||
// ALl labels that are used in this layer
|
||||
const allLabels = new Set(
|
||||
json.tagRenderings.flatMap(
|
||||
(tr) => (<QuestionableTagRenderingConfigJson>tr).labels ?? []
|
||||
)
|
||||
json.tagRenderings.flatMap(
|
||||
(tr) => (<QuestionableTagRenderingConfigJson>tr).labels ?? []
|
||||
)
|
||||
)
|
||||
/**
|
||||
* The essence of all questionboxes: what is whitelisted, what is blacklisted?
|
||||
*/
|
||||
const questionBoxes: { blacklist: string[], whitelist: string[] }[] = []
|
||||
const questionBoxes: { blacklist: string[]; whitelist: string[] }[] = []
|
||||
for (const questionSpecial of questionSpecials) {
|
||||
if (typeof questionSpecial === "string") {
|
||||
// Probably a header or something
|
||||
|
@ -273,7 +274,7 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
for (const { blacklist, whitelist } of questionBoxes) {
|
||||
if (whitelist.length > 0 && blacklist.length == 0) {
|
||||
// All questions from "whitelist" are guaranteed to be used here
|
||||
whitelist.forEach(label => usedLabels.add(label))
|
||||
whitelist.forEach((label) => usedLabels.add(label))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,12 +282,14 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
* Can we say that the whitelisted items are fully consumed?
|
||||
*/
|
||||
let needsEvaluation = true
|
||||
let toEvaluate = questionBoxes.filter(q => q.whitelist.length > 0 && q.blacklist.length > 0)
|
||||
let toEvaluate = questionBoxes.filter(
|
||||
(q) => q.whitelist.length > 0 && q.blacklist.length > 0
|
||||
)
|
||||
while (needsEvaluation && toEvaluate.length > 0) {
|
||||
needsEvaluation = false
|
||||
const toReEvaluate = []
|
||||
for (const { blacklist, whitelist } of toEvaluate) {
|
||||
const blacklistRest = blacklist.filter(label => !usedLabels.has(label))
|
||||
const blacklistRest = blacklist.filter((label) => !usedLabels.has(label))
|
||||
if (blacklistRest.length == 0) {
|
||||
// All items from the blacklist have been handled by a different questionbox
|
||||
// We can safely say that all whitelisted items are consumed
|
||||
|
@ -294,7 +297,7 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
// Even better: this questionbox will show all leftover questions
|
||||
return json
|
||||
}
|
||||
whitelist.forEach(label => {
|
||||
whitelist.forEach((label) => {
|
||||
usedLabels.add(label)
|
||||
})
|
||||
needsEvaluation = true
|
||||
|
@ -312,11 +315,12 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
|
||||
context.err(
|
||||
"Could not calculate a non-ambiguous leftover questions block. A {questions()}-special rendering is found which has both a whitelist and a blacklist; where the blacklist was not fully consumed by other tagRenderings\n\t" +
|
||||
JSON.stringify(toEvaluate)+"\n\tConsumed labels are: "+Array.from(usedLabels).join(", "),
|
||||
JSON.stringify(toEvaluate) +
|
||||
"\n\tConsumed labels are: " +
|
||||
Array.from(usedLabels).join(", ")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/* At this point, we know which question labels are not yet handled and which already are handled, and we
|
||||
* know there is no previous catch-all questions
|
||||
*/
|
||||
|
@ -926,7 +930,7 @@ export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
|
|||
const funcs = new Set<string>(specialVis.map((rs) => rs.func.funcName))
|
||||
|
||||
if (funcs.has("list_reviews")) {
|
||||
;(<(string | TagRenderingConfigJson)[]>json.titleIcons).push("icons.rating")
|
||||
(<(string | TagRenderingConfigJson)[]>json.titleIcons).push("icons.rating")
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
|
|
@ -6,17 +6,24 @@ import SpecialVisualizations from "../../UI/SpecialVisualizations"
|
|||
import { LayerConfigJson } from "./Json/LayerConfigJson"
|
||||
|
||||
export default class DependencyCalculator {
|
||||
|
||||
/**
|
||||
* For every tagRendering in the listed layers, determines in what layers they end up
|
||||
*/
|
||||
public static tagRenderingImportedBy(questionedLayer: LayerConfig, layers: LayerConfig[]): Map<string, {
|
||||
layer: string
|
||||
}[]> {
|
||||
public static tagRenderingImportedBy(
|
||||
questionedLayer: LayerConfig,
|
||||
layers: LayerConfig[]
|
||||
): Map<
|
||||
string,
|
||||
{
|
||||
layer: string
|
||||
}[]
|
||||
> {
|
||||
const result: Map<string, { layer: string }[]> = new Map()
|
||||
|
||||
for (const layer of layers) {
|
||||
const hasRightContext = layer.tagRenderings.filter(tr => tr._definedIn !== undefined && tr?._definedIn?.[0] === questionedLayer.id)
|
||||
const hasRightContext = layer.tagRenderings.filter(
|
||||
(tr) => tr._definedIn !== undefined && tr?._definedIn?.[0] === questionedLayer.id
|
||||
)
|
||||
for (const tr of hasRightContext) {
|
||||
const id = tr._definedIn[1]
|
||||
if (!result.has(id)) {
|
||||
|
|
|
@ -18,7 +18,7 @@ export default class ExtraLinkConfig {
|
|||
this.newTab = configJson.newTab
|
||||
this.requirements = new Set(configJson.requirements)
|
||||
|
||||
for (let requirement of configJson.requirements) {
|
||||
for (const requirement of configJson.requirements) {
|
||||
if (this.requirements.has(<any>("no-" + requirement))) {
|
||||
throw (
|
||||
"Conflicting requirements found for " +
|
||||
|
|
|
@ -438,17 +438,23 @@ export default class LayerConfig extends WithContextLoader {
|
|||
)
|
||||
}
|
||||
|
||||
public generateDocumentation(
|
||||
{ usedInThemes = [], layerIsNeededBy, dependencies = [], addedByDefault = false, canBeIncluded = true, lang = "en", reusedTagRenderings }: {
|
||||
usedInThemes?: string[],
|
||||
layerIsNeededBy?: Map<string, string[]>,
|
||||
dependencies?: { context?: string; reason: string; neededLayer: string }[],
|
||||
addedByDefault?: boolean,
|
||||
canBeIncluded?: boolean,
|
||||
reusedTagRenderings?: Map<string, {layer: string}[]>,
|
||||
lang?: string
|
||||
}
|
||||
): string {
|
||||
public generateDocumentation({
|
||||
usedInThemes = [],
|
||||
layerIsNeededBy,
|
||||
dependencies = [],
|
||||
addedByDefault = false,
|
||||
canBeIncluded = true,
|
||||
lang = "en",
|
||||
reusedTagRenderings,
|
||||
}: {
|
||||
usedInThemes?: string[]
|
||||
layerIsNeededBy?: Map<string, string[]>
|
||||
dependencies?: { context?: string; reason: string; neededLayer: string }[]
|
||||
addedByDefault?: boolean
|
||||
canBeIncluded?: boolean
|
||||
reusedTagRenderings?: Map<string, { layer: string }[]>
|
||||
lang?: string
|
||||
}): string {
|
||||
const extraProps: string[] = []
|
||||
extraProps.push("This layer is shown at zoomlevel **" + this.minzoom + "** and higher")
|
||||
|
||||
|
@ -669,7 +675,12 @@ export default class LayerConfig extends WithContextLoader {
|
|||
this.generateDocumentationQuickTable(),
|
||||
...this.tagRenderings
|
||||
.filter((tr) => tr.labels.indexOf("ignore_docs") < 0)
|
||||
.map((tr) => tr.generateDocumentation(lang, reusedTagRenderings?.get(tr.id)?.map(l => l.layer))),
|
||||
.map((tr) =>
|
||||
tr.generateDocumentation(
|
||||
lang,
|
||||
reusedTagRenderings?.get(tr.id)?.map((l) => l.layer)
|
||||
)
|
||||
),
|
||||
...filterDocs,
|
||||
].join("\n\n")
|
||||
}
|
||||
|
|
|
@ -1020,10 +1020,11 @@ export default class TagRenderingConfig {
|
|||
...this.labels.map((label) => "`" + label + "`"),
|
||||
].join(" ")
|
||||
}
|
||||
let reuse : string = undefined
|
||||
if(usedInLayers?.length > 0){
|
||||
reuse = [`This tagRendering is used in ${usedInLayers.length} layers:`,
|
||||
...usedInLayers.map(l => `[${l}](./Layers/${l}.md)`)
|
||||
let reuse: string = undefined
|
||||
if (usedInLayers?.length > 0) {
|
||||
reuse = [
|
||||
`This tagRendering is used in ${usedInLayers.length} layers:`,
|
||||
...usedInLayers.map((l) => `[${l}](./Layers/${l}.md)`),
|
||||
].join(" ")
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1039,7 @@ export default class TagRenderingConfig {
|
|||
condition,
|
||||
labels,
|
||||
"",
|
||||
reuse
|
||||
reuse,
|
||||
]).join("\n")
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export default class WithContextLoader {
|
|||
* The found value is interpreted as a tagrendering and fetched/parsed
|
||||
* */
|
||||
public tr(key: string, deflt?: string, translationContext?: string) {
|
||||
let v: Translatable | TagRenderingConfigJson = this._json[key]
|
||||
const v: Translatable | TagRenderingConfigJson = this._json[key]
|
||||
if (v === undefined || v === null) {
|
||||
if (deflt === undefined) {
|
||||
return undefined
|
||||
|
|
|
@ -131,8 +131,9 @@ export class WithLayoutSourceState extends WithSelectedElementState {
|
|||
|
||||
protected setSelectedElement(feature: Feature) {
|
||||
// The given feature might be a partial one from the cache
|
||||
if(feature !== undefined){
|
||||
feature = this.indexedFeatures.featuresById.data?.get(feature?.properties?.id) ?? feature
|
||||
if (feature !== undefined) {
|
||||
feature =
|
||||
this.indexedFeatures.featuresById.data?.get(feature?.properties?.id) ?? feature
|
||||
}
|
||||
super.setSelectedElement(feature)
|
||||
}
|
||||
|
|
|
@ -17,11 +17,9 @@ export class WithSearchState extends WithVisualFeedbackState {
|
|||
this.searchState = new SearchState(this)
|
||||
this.initHotkeysSearch()
|
||||
this.displaySearchLayer()
|
||||
|
||||
}
|
||||
|
||||
private displaySearchLayer() {
|
||||
|
||||
const source = this.searchState.locationResults
|
||||
const flayer = this.layerState.filteredLayers.get("search")
|
||||
this.featureProperties.trackFeatureSource(source)
|
||||
|
|
|
@ -86,7 +86,7 @@ export class Tiles {
|
|||
static asGeojson(zIndex: number, x?: number, y?: number): Feature<Polygon> {
|
||||
let z = zIndex
|
||||
if (x === undefined) {
|
||||
;[z, x, y] = Tiles.tile_from_index(zIndex)
|
||||
[z, x, y] = Tiles.tile_from_index(zIndex)
|
||||
}
|
||||
const bounds = Tiles.tile_bounds_lon_lat(z, x, y)
|
||||
return new BBox(bounds).asGeoJson()
|
||||
|
|
|
@ -156,7 +156,7 @@ export default class Hotkeys {
|
|||
}
|
||||
const contents: string[][] = this.prepareDocumentation(docs).map(
|
||||
([key, doc, alsoTriggeredBy]) => {
|
||||
let keyEl: string = [key, ...(alsoTriggeredBy ?? [])]
|
||||
const keyEl: string = [key, ...(alsoTriggeredBy ?? [])]
|
||||
.map((k) => "`" + t(k) + "`")
|
||||
.join(" ")
|
||||
return [keyEl, t(doc)]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
</script>
|
||||
|
||||
<div class="relative h-80 w-60">
|
||||
<div class="h-full w-full animate-pulse interactive" />
|
||||
<div class="interactive h-full w-full animate-pulse" />
|
||||
<div class="absolute top-0 flex h-full w-full items-center justify-center">
|
||||
<Loading />
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* Show the button, even though we are logged in
|
||||
*/
|
||||
export let forceShow: boolean = false
|
||||
export let msg: String = undefined
|
||||
export let msg: string = undefined
|
||||
if (osmConnection === undefined) {
|
||||
console.error("No osmConnection passed into loginButton")
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ export default abstract class BaseUIElement {
|
|||
}
|
||||
|
||||
AttachTo(divId: string) {
|
||||
let element = document.getElementById(divId)
|
||||
const element = document.getElementById(divId)
|
||||
if (element === null) {
|
||||
if (Utils.runningFromConsole) {
|
||||
this.ConstructElement()
|
||||
|
@ -78,7 +78,7 @@ export default abstract class BaseUIElement {
|
|||
|
||||
public RemoveClass(classes: string): BaseUIElement {
|
||||
const all = classes.split(" ").map((clsName) => clsName.trim())
|
||||
for (let clss of all) {
|
||||
for (const clss of all) {
|
||||
if (this.clss.has(clss)) {
|
||||
this.clss.delete(clss)
|
||||
this._constructedHtmlElement?.classList.remove(clss)
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
function showFor(timeoutSeconds: number = 5) {
|
||||
open = true
|
||||
window.setTimeout(() => {
|
||||
open = false
|
||||
},
|
||||
timeoutSeconds * 1000)
|
||||
open = false
|
||||
}, timeoutSeconds * 1000)
|
||||
}
|
||||
|
||||
mapIsDragged.addCallback(() => {
|
||||
|
@ -28,27 +27,30 @@
|
|||
}
|
||||
})
|
||||
gpsState.requestMoment.stabilized(50).addCallback(() => {
|
||||
if(gpsState.gpsAvailable.data && gpsState.allowMoving.data){
|
||||
if (gpsState.gpsAvailable.data && gpsState.allowMoving.data) {
|
||||
return
|
||||
}
|
||||
showFor(5)
|
||||
})
|
||||
let explanation = gpsState.gpsStateExplanation
|
||||
onDestroy(
|
||||
explanation.stabilized(50).addCallbackD(
|
||||
expl => {
|
||||
if (expl) {
|
||||
showFor(5)
|
||||
} else {
|
||||
open = false
|
||||
}
|
||||
},
|
||||
),
|
||||
explanation.stabilized(50).addCallbackD((expl) => {
|
||||
if (expl) {
|
||||
showFor(5)
|
||||
} else {
|
||||
open = false
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
<Popover reference={undefined} trigger=null placement="left" transition={e => fade(e, {duration: 150})} bind:open>
|
||||
<Popover
|
||||
reference={undefined}
|
||||
trigger="null"
|
||||
placement="left"
|
||||
transition={(e) => fade(e, { duration: 150 })}
|
||||
bind:open
|
||||
>
|
||||
<div class="break-words" style="max-width: calc( 100vw - 8rem)">
|
||||
<Tr t={$explanation} />
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
|
||||
import { Popover } from "flowbite-svelte"
|
||||
import { fade } from "svelte/transition"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
|
@ -8,23 +7,28 @@
|
|||
export let state: { osmConnection: OsmConnection }
|
||||
let userdetails = state.osmConnection.userDetails
|
||||
|
||||
userdetails.addCallbackAndRunD(ud => {
|
||||
userdetails.addCallbackAndRunD((ud) => {
|
||||
if (ud) {
|
||||
open = true
|
||||
window.setTimeout(() => {
|
||||
open = false
|
||||
open = false
|
||||
}, 5000)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<Popover class="mt-4 z-50" defaultClass="py-2 px-3 w-fit " trigger=null placement="bottom"
|
||||
transition={e => fade(e, {duration: 150})} bind:open>
|
||||
<Popover
|
||||
class="z-50 mt-4"
|
||||
defaultClass="py-2 px-3 w-fit "
|
||||
trigger="null"
|
||||
placement="bottom"
|
||||
transition={(e) => fade(e, { duration: 150 })}
|
||||
bind:open
|
||||
>
|
||||
{#if $userdetails !== undefined}
|
||||
<div style="width: max-content" class="flex items-center">
|
||||
{#if $userdetails.img}
|
||||
<img src={$userdetails.img } alt="profile picture" class="w-8 h-8 rounded-full mr-4" />
|
||||
<img src={$userdetails.img} alt="profile picture" class="mr-4 h-8 w-8 rounded-full" />
|
||||
{/if}
|
||||
<div>
|
||||
<div>Welcome back</div>
|
||||
|
@ -35,4 +39,3 @@
|
|||
</div>
|
||||
{/if}
|
||||
</Popover>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export class ComparisonState {
|
|||
externalProperties = { ...externalProperties }
|
||||
delete externalProperties["@context"]
|
||||
|
||||
let externalKeys: string[] = Object.keys(externalProperties).sort()
|
||||
const externalKeys: string[] = Object.keys(externalProperties).sort()
|
||||
|
||||
const imageKeyRegex = /image|image:[0-9]+/
|
||||
|
||||
|
@ -35,7 +35,7 @@ export class ComparisonState {
|
|||
)
|
||||
|
||||
this.propertyKeysExternal = externalKeys.filter((k) => k.match(imageKeyRegex) === null)
|
||||
let propertyKeysExternal = this.propertyKeysExternal
|
||||
const propertyKeysExternal = this.propertyKeysExternal
|
||||
this.missing = tags.map((osmProperties) =>
|
||||
propertyKeysExternal.filter((k) => {
|
||||
if (k.startsWith("_")) {
|
||||
|
|
|
@ -50,26 +50,21 @@
|
|||
|
||||
async function detectErrorReason() {
|
||||
try {
|
||||
|
||||
const response = await fetch(
|
||||
image.url,
|
||||
{
|
||||
headers: {
|
||||
"Accept": "image/avif,image/webp,*/*",
|
||||
},
|
||||
const response = await fetch(image.url, {
|
||||
headers: {
|
||||
Accept: "image/avif,image/webp,*/*",
|
||||
},
|
||||
)
|
||||
})
|
||||
if (response.status === 404) {
|
||||
notFound = true
|
||||
}
|
||||
} catch
|
||||
(e) {
|
||||
} catch (e) {
|
||||
console.log("Could not load image while trying to remediate", e)
|
||||
}
|
||||
}
|
||||
|
||||
async function onError() {
|
||||
Mapillary.isInStrictMode().addCallbackAndRunD(isStrict => {
|
||||
Mapillary.isInStrictMode().addCallbackAndRunD((isStrict) => {
|
||||
isInStrictMode.set(isStrict)
|
||||
return true // unregister
|
||||
})
|
||||
|
@ -82,16 +77,16 @@
|
|||
onDestroy(
|
||||
showBigPreview.addCallbackAndRun((shown) => {
|
||||
state?.guistate?.setPreviewedImage(shown ? image : undefined)
|
||||
}),
|
||||
})
|
||||
)
|
||||
if (previewedImage) {
|
||||
onDestroy(
|
||||
previewedImage.addCallbackAndRun((previewedImage) => {
|
||||
showBigPreview.set(
|
||||
previewedImage !== undefined &&
|
||||
(previewedImage?.id ?? previewedImage?.url) === (image.id ?? image.url),
|
||||
(previewedImage?.id ?? previewedImage?.url) === (image.id ?? image.url)
|
||||
)
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -135,17 +130,17 @@
|
|||
</div>
|
||||
</Popup>
|
||||
{#if error}
|
||||
<div class="h-80 w-60 interactive flex flex-col justify-center items-center p-4 text-center">
|
||||
<div class="interactive flex h-80 w-60 flex-col items-center justify-center p-4 text-center">
|
||||
{#if notFound}
|
||||
<div class="alert flex items-center">
|
||||
<TriangleOutline class="shrink-0 h-8 w-8" />
|
||||
<TriangleOutline class="h-8 w-8 shrink-0" />
|
||||
Not found
|
||||
</div>
|
||||
This image is probably incorrect or deleted.
|
||||
<slot name="not-found-extra" />
|
||||
{:else}
|
||||
<div class="alert flex items-center">
|
||||
<TriangleOutline class="shrink-0 h-8 w-8" />
|
||||
<TriangleOutline class="h-8 w-8 shrink-0" />
|
||||
<Tr t={Translations.t.image.loadingFailed} />
|
||||
</div>
|
||||
{#if image.provider.name.toLowerCase() === "mapillary" && $isInStrictMode}
|
||||
|
@ -153,7 +148,7 @@
|
|||
{:else if $isInStrictMode}
|
||||
<Tr t={Translations.t.image.strictProtectionDetected} />
|
||||
{image.provider.name}
|
||||
<div class="subtle text-sm mt-8">{image.url}</div>
|
||||
<div class="subtle mt-8 text-sm">{image.url}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -225,10 +220,10 @@
|
|||
</div>
|
||||
</div>
|
||||
{:else if image.status === "hidden"}
|
||||
<div class="h-80 w-60 flex flex-col justify-center items-center break-words p-4 text-center">
|
||||
<TriangleOutline class="w-8 h-8 subtle" />
|
||||
<div class="flex h-80 w-60 flex-col items-center justify-center break-words p-4 text-center">
|
||||
<TriangleOutline class="subtle h-8 w-8" />
|
||||
<Tr t={Translations.t.image.reported} />
|
||||
<button class="text-sm" on:click={() => ignoreHidden = true}>
|
||||
<button class="text-sm" on:click={() => (ignoreHidden = true)}>
|
||||
<Tr t={Translations.t.image.showAnyway} />
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
}
|
||||
|
||||
async function unlink() {
|
||||
const {key} = image.originalAttribute
|
||||
const { key } = image.originalAttribute
|
||||
await state?.changes?.applyAction(
|
||||
new ChangeTagAction(tags.data.id, new Tag(key, ""), tags.data, {
|
||||
changeType: "delete-image",
|
||||
|
@ -95,7 +95,7 @@
|
|||
<div class="my-4">
|
||||
<AccordionSingle noBorder>
|
||||
<div slot="header" class="flex text-sm">
|
||||
<Tr t={t.requestDeletion}/>
|
||||
<Tr t={t.requestDeletion} />
|
||||
</div>
|
||||
<div class="interactive flex flex-col p-2">
|
||||
<h3>
|
||||
|
|
|
@ -157,7 +157,9 @@
|
|||
type: "Feature",
|
||||
geometry: { type: "Point", coordinates: GeoOperations.centerpointCoordinates(feature) },
|
||||
properties: <HotspotProperties>{
|
||||
name: layer.title?.GetRenderValue(feature.properties)?.Subs(feature.properties)?.txt ?? "Feature",
|
||||
name:
|
||||
layer.title?.GetRenderValue(feature.properties)?.Subs(feature.properties)?.txt ??
|
||||
"Feature",
|
||||
focus: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -31,16 +31,15 @@
|
|||
|
||||
const state = new OpeningHoursState(value, prefix, postfix)
|
||||
let expanded = new UIEventSource(false)
|
||||
|
||||
</script>
|
||||
|
||||
<Popup bodyPadding="p-0" shown={expanded}>
|
||||
<OHTable value={state.normalOhs} />
|
||||
<div class="absolute w-full flex justify-center" style="bottom: -3rem">
|
||||
<button class=" primary " on:click={() => expanded.set(false)}>
|
||||
<Check class="m-0 h-6 w-6 shrink-0 p-0" color="white" />
|
||||
<Tr t={Translations.t.general.confirm}/>
|
||||
</button>
|
||||
<div class="absolute flex w-full justify-center" style="bottom: -3rem">
|
||||
<button class=" primary" on:click={() => expanded.set(false)}>
|
||||
<Check class="m-0 h-6 w-6 shrink-0 p-0" color="white" />
|
||||
<Tr t={Translations.t.general.confirm} />
|
||||
</button>
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
|
|
|
@ -757,10 +757,11 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
if (!showScale) {
|
||||
if (this.scaleControl) {
|
||||
try {
|
||||
|
||||
map.removeControl(this.scaleControl)
|
||||
} catch (e) {
|
||||
console.warn("Could not remove scale control, underlying map might have had a reset")
|
||||
console.warn(
|
||||
"Could not remove scale control, underlying map might have had a reset"
|
||||
)
|
||||
}
|
||||
this.scaleControl = undefined
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
<div class="flex h-full w-full flex-col items-center justify-center p-8">
|
||||
<div class="flex flex-col items-center">
|
||||
|
||||
<World class="w-full h-auto"/>
|
||||
<World class="h-auto w-full" />
|
||||
<h1>
|
||||
<Tr t={Translations.t.general["404"]} />
|
||||
</h1>
|
||||
|
|
|
@ -466,9 +466,8 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
|||
*/
|
||||
public static allChangeMoments(
|
||||
ranges: OpeningRange[][],
|
||||
includeOpenEnds = false,
|
||||
includeOpenEnds = false
|
||||
): [number[], string[]] {
|
||||
|
||||
const changeHours: number[] = []
|
||||
const changeHourText: string[] = []
|
||||
|
||||
|
@ -477,7 +476,6 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
|||
|
||||
for (const weekday of ranges) {
|
||||
for (const range of weekday) {
|
||||
|
||||
if (!(range.openEnd || range.isOpen || range.isSpecial)) {
|
||||
continue
|
||||
}
|
||||
|
@ -494,7 +492,7 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
|||
)
|
||||
}
|
||||
|
||||
if(range.openEnd && !includeOpenEnds){
|
||||
if (range.openEnd && !includeOpenEnds) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -572,7 +570,7 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
|||
public static createOhObject(
|
||||
tags: Record<string, string | number> & { _lat: number; _lon: number; _country?: string },
|
||||
textToParse: string,
|
||||
country: string,
|
||||
country: string
|
||||
) {
|
||||
return new opening_hours(
|
||||
textToParse,
|
||||
|
|
|
@ -14,11 +14,12 @@
|
|||
let startOfDay: Date = new Date(range.startDate)
|
||||
startOfDay.setHours(0, 0, 0, 0)
|
||||
let startpoint = (range.startDate.getTime() - startOfDay.getTime()) / 1000 - earliestOpen
|
||||
let width = (100 * (range.endDate.getTime() - range.startDate.getTime()) / 1000) / availableArea
|
||||
let width = (100 * (range.endDate.getTime() - range.startDate.getTime())) / 1000 / availableArea
|
||||
let startPercentage = (100 * startpoint) / availableArea
|
||||
</script>
|
||||
|
||||
{#if range.openEnd}
|
||||
<div class="ohviz-range open-end" style={`left:${startPercentage}%; width:${width}%`}/>
|
||||
<div class="ohviz-range open-end" style={`left:${startPercentage}%; width:${width}%`} />
|
||||
{:else if !range.isOpen && !range.isSpecial}
|
||||
<div class="ohviz-day-off">{textToShow}</div>
|
||||
{:else}
|
||||
|
|
|
@ -33,7 +33,7 @@ export class ShareLinkViz implements SpecialVisualizationSvelte {
|
|||
const generateShareData = () => {
|
||||
const title = state?.theme?.title?.txt ?? "MapComplete"
|
||||
|
||||
let matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tagSource?.data)
|
||||
const matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tagSource?.data)
|
||||
let name =
|
||||
matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ??
|
||||
tagSource.data?.name ??
|
||||
|
|
|
@ -80,7 +80,7 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
|
|||
const newTags: Tag[] = []
|
||||
for (const [key, value] of tgsSpec) {
|
||||
if (value.indexOf("$") >= 0) {
|
||||
let parts = value.split("$")
|
||||
const parts = value.split("$")
|
||||
// The first item of the split won't start with a '$', so no substitution needed
|
||||
let actualValue = parts[0]
|
||||
parts.shift()
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
|
||||
let baseQuestions = (layer?.tagRenderings ?? [])?.filter(
|
||||
(tr) => tr.question !== undefined && allowed(tr.labels),
|
||||
(tr) => tr.question !== undefined && allowed(tr.labels)
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -128,16 +128,19 @@
|
|||
<div slot="header" class="small subtle text-sm">
|
||||
Questionbox debug info: labels (whitelist) : {onlyForLabels?.join(",")}
|
||||
</div>
|
||||
<div class="flex flex-col" >
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div>
|
||||
notForLabes (blacklist): {notForLabels?.join(",")} ;
|
||||
</div>
|
||||
<div>
|
||||
baseQuestions: {baseQuestions.length === 0 ? "NONE" : baseQuestions.map(q => q.id)?.join(",")} ;
|
||||
baseQuestions: {baseQuestions.length === 0
|
||||
? "NONE"
|
||||
: baseQuestions.map((q) => q.id)?.join(",")} ;
|
||||
</div>
|
||||
<div>
|
||||
questionsMeetingConditions: {$questionsToAsk.length === 0 ? "NONE" : baseQuestions.map(q => q.id)?.join(",")}
|
||||
questionsMeetingConditions: {$questionsToAsk.length === 0
|
||||
? "NONE"
|
||||
: baseQuestions.map((q) => q.id)?.join(",")}
|
||||
;
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -62,7 +62,9 @@
|
|||
"due to",
|
||||
e
|
||||
)
|
||||
return new FixedUiElement("Could not construct visualization "+specpart.func.funcName+" due to "+e)
|
||||
return new FixedUiElement(
|
||||
"Could not construct visualization " + specpart.func.funcName + " due to " + e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,7 +313,7 @@
|
|||
let featureSwitchIsTesting = state?.featureSwitchIsTesting ?? new ImmutableStore(false)
|
||||
let featureSwitchIsDebugging =
|
||||
state?.featureSwitches?.featureSwitchIsDebugging ?? new ImmutableStore(false)
|
||||
let showTags : Store<boolean> = state?.userRelatedState?.showTagsB ?? new ImmutableStore(false)
|
||||
let showTags: Store<boolean> = state?.userRelatedState?.showTagsB ?? new ImmutableStore(false)
|
||||
let question = config.question
|
||||
let hideMappingsUnlessSearchedFor =
|
||||
config.mappings.length > 8 && config.mappings.some((m) => m.priorityIf !== undefined)
|
||||
|
@ -565,9 +565,7 @@
|
|||
<Tr t={Translations.t.unknown.title} />
|
||||
</h2>
|
||||
<Tr t={Translations.t.unknown.explanation} />
|
||||
<If
|
||||
condition={state.userRelatedState?.showTagsB}
|
||||
>
|
||||
<If condition={state.userRelatedState?.showTagsB}>
|
||||
<div class="subtle">
|
||||
<Tr t={Translations.t.unknown.removedKeys} />
|
||||
<TagHint tags={$onMarkUnknown} />
|
||||
|
|
|
@ -180,16 +180,18 @@
|
|||
let apiState = state?.osmConnection?.apiIsOnline ?? new ImmutableStore("online")
|
||||
|
||||
let mapIsDragged: UIEventSource<void> = new UIEventSource(undefined)
|
||||
function onMapDragged(){
|
||||
function onMapDragged() {
|
||||
mapIsDragged.ping()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<div class="absolute left-0 top-0 h-screen w-screen" style="background-color: #f0efdd" />
|
||||
<!-- Main map -->
|
||||
<div class="absolute left-0 top-0 h-screen w-screen overflow-hidden" use:dragDetection={() => onMapDragged()}>
|
||||
<div
|
||||
class="absolute left-0 top-0 h-screen w-screen overflow-hidden"
|
||||
use:dragDetection={() => onMapDragged()}
|
||||
>
|
||||
<MaplibreMap map={maplibremap} mapProperties={mapproperties} autorecovery={true} />
|
||||
</div>
|
||||
|
||||
|
@ -321,7 +323,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<GpsElementHelper reference = "#gps-control-button" {state} {mapIsDragged}/>
|
||||
<GpsElementHelper reference="#gps-control-button" {state} {mapIsDragged} />
|
||||
</If>
|
||||
<If condition={state.mapProperties.showScale}>
|
||||
<div class="h-6">
|
||||
|
@ -354,7 +356,7 @@
|
|||
on:keydown={forwardEventToMap}
|
||||
>
|
||||
<MenuIcon class="h-6 w-6 cursor-pointer" />
|
||||
<WelcomeBack {state}/>
|
||||
<WelcomeBack {state} />
|
||||
</MapControlButton>
|
||||
|
||||
<MapControlButton
|
||||
|
|
|
@ -1596,7 +1596,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
let _: string
|
||||
const matchWithFuncName = stackItem.match(regex)
|
||||
if (matchWithFuncName) {
|
||||
;[_, functionName, path, line, column] = matchWithFuncName
|
||||
[_, functionName, path, line, column] = matchWithFuncName
|
||||
} else {
|
||||
const regexNoFuncName: RegExp = new RegExp("at ([a-zA-Z0-9-/.]+):([0-9]+):([0-9]+)")
|
||||
;[_, path, line, column] = stackItem.match(regexNoFuncName)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export function dragDetection(htmlElement: HTMLElement, callback: () => {}) {
|
||||
|
||||
let isDown = false
|
||||
let threshold = 5
|
||||
const threshold = 5
|
||||
let start = null
|
||||
|
||||
htmlElement.addEventListener("pointerdown", (e) => {
|
||||
|
@ -30,7 +29,6 @@ export function dragDetection(htmlElement: HTMLElement, callback: () => {}) {
|
|||
})
|
||||
|
||||
return {
|
||||
destroy: () => {
|
||||
},
|
||||
destroy: () => {},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"contributors": [
|
||||
{
|
||||
"commits": 9857,
|
||||
"commits": 9968,
|
||||
"contributor": "Pieter Vander Vennet"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -11013,10 +11013,6 @@
|
|||
"if": "value=hydrant",
|
||||
"then": "hydrant - Map layer to show fire hydrants."
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "ice_cream - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=id_presets",
|
||||
"then": "id_presets - Layer containing various presets and questions generated by ID. These are meant to be reused in other layers by importing the tagRenderings with `id_preset.<tagrendering>"
|
||||
|
@ -11377,10 +11373,6 @@
|
|||
"if": "value=dentist",
|
||||
"then": "dentist - This layer shows dentist offices"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=ghostsign",
|
||||
"then": "ghostsign - Layer showing disused signs on buildings"
|
||||
|
@ -11389,10 +11381,6 @@
|
|||
"if": "value=hospital",
|
||||
"then": "hospital - A layer showing hospital grounds"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "pharmacy - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=physiotherapist",
|
||||
"then": "physiotherapist - This layer shows physiotherapists"
|
||||
|
@ -11441,10 +11429,22 @@
|
|||
"if": "value=cafe_pub",
|
||||
"then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=food",
|
||||
"then": "food - A layer showing restaurants and fast-food amenities (with a special rendering for friteries)"
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "ice_cream - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "pharmacy - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=shops",
|
||||
"then": "shops - A shop"
|
||||
|
|
|
@ -892,10 +892,6 @@
|
|||
"if": "value=hydrant",
|
||||
"then": "<b>hydrant</b> (builtin) - Map layer to show fire hydrants."
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "<b>ice_cream</b> (builtin) - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=id_presets",
|
||||
"then": "<b>id_presets</b> (builtin) - Layer containing various presets and questions generated by ID. These are meant to be reused in other layers by importing the tagRenderings with `id_preset.<tagrendering>"
|
||||
|
@ -1256,10 +1252,6 @@
|
|||
"if": "value=dentist",
|
||||
"then": "<b>dentist</b> (builtin) - This layer shows dentist offices"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "<b>doctors</b> (builtin) - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=ghostsign",
|
||||
"then": "<b>ghostsign</b> (builtin) - Layer showing disused signs on buildings"
|
||||
|
@ -1268,10 +1260,6 @@
|
|||
"if": "value=hospital",
|
||||
"then": "<b>hospital</b> (builtin) - A layer showing hospital grounds"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "<b>pharmacy</b> (builtin) - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=physiotherapist",
|
||||
"then": "<b>physiotherapist</b> (builtin) - This layer shows physiotherapists"
|
||||
|
@ -1320,10 +1308,22 @@
|
|||
"if": "value=cafe_pub",
|
||||
"then": "<b>cafe_pub</b> (builtin) - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "<b>doctors</b> (builtin) - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=food",
|
||||
"then": "<b>food</b> (builtin) - A layer showing restaurants and fast-food amenities (with a special rendering for friteries)"
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "<b>ice_cream</b> (builtin) - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "<b>pharmacy</b> (builtin) - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=shops",
|
||||
"then": "<b>shops</b> (builtin) - A shop"
|
||||
|
@ -13681,10 +13681,6 @@
|
|||
"if": "value=hydrant",
|
||||
"then": "hydrant - Map layer to show fire hydrants."
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "ice_cream - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=id_presets",
|
||||
"then": "id_presets - Layer containing various presets and questions generated by ID. These are meant to be reused in other layers by importing the tagRenderings with `id_preset.<tagrendering>"
|
||||
|
@ -14045,10 +14041,6 @@
|
|||
"if": "value=dentist",
|
||||
"then": "dentist - This layer shows dentist offices"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=ghostsign",
|
||||
"then": "ghostsign - Layer showing disused signs on buildings"
|
||||
|
@ -14057,10 +14049,6 @@
|
|||
"if": "value=hospital",
|
||||
"then": "hospital - A layer showing hospital grounds"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "pharmacy - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=physiotherapist",
|
||||
"then": "physiotherapist - This layer shows physiotherapists"
|
||||
|
@ -14109,10 +14097,22 @@
|
|||
"if": "value=cafe_pub",
|
||||
"then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=food",
|
||||
"then": "food - A layer showing restaurants and fast-food amenities (with a special rendering for friteries)"
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "ice_cream - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "pharmacy - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=shops",
|
||||
"then": "shops - A shop"
|
||||
|
@ -35506,10 +35506,6 @@
|
|||
"if": "value=hydrant",
|
||||
"then": "hydrant - Map layer to show fire hydrants."
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "ice_cream - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=id_presets",
|
||||
"then": "id_presets - Layer containing various presets and questions generated by ID. These are meant to be reused in other layers by importing the tagRenderings with `id_preset.<tagrendering>"
|
||||
|
@ -35870,10 +35866,6 @@
|
|||
"if": "value=dentist",
|
||||
"then": "dentist - This layer shows dentist offices"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=ghostsign",
|
||||
"then": "ghostsign - Layer showing disused signs on buildings"
|
||||
|
@ -35882,10 +35874,6 @@
|
|||
"if": "value=hospital",
|
||||
"then": "hospital - A layer showing hospital grounds"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "pharmacy - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=physiotherapist",
|
||||
"then": "physiotherapist - This layer shows physiotherapists"
|
||||
|
@ -35934,10 +35922,22 @@
|
|||
"if": "value=cafe_pub",
|
||||
"then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
|
||||
},
|
||||
{
|
||||
"if": "value=doctors",
|
||||
"then": "doctors - This layer shows doctor offices"
|
||||
},
|
||||
{
|
||||
"if": "value=food",
|
||||
"then": "food - A layer showing restaurants and fast-food amenities (with a special rendering for friteries)"
|
||||
},
|
||||
{
|
||||
"if": "value=ice_cream",
|
||||
"then": "ice_cream - A place where ice cream is sold over the counter"
|
||||
},
|
||||
{
|
||||
"if": "value=pharmacy",
|
||||
"then": "pharmacy - A layer showing pharmacies, which (probably) dispense prescription drugs"
|
||||
},
|
||||
{
|
||||
"if": "value=shops",
|
||||
"then": "shops - A shop"
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
"contributor": "danieldegroot2"
|
||||
},
|
||||
{
|
||||
"commits": 67,
|
||||
"commits": 68,
|
||||
"contributor": "Supaplex"
|
||||
},
|
||||
{
|
||||
|
@ -112,6 +112,10 @@
|
|||
"commits": 16,
|
||||
"contributor": "macpac"
|
||||
},
|
||||
{
|
||||
"commits": 15,
|
||||
"contributor": "Lukáš Jelínek"
|
||||
},
|
||||
{
|
||||
"commits": 15,
|
||||
"contributor": "Ettore Atalan"
|
||||
|
@ -132,10 +136,6 @@
|
|||
"commits": 14,
|
||||
"contributor": "J. Lavoie"
|
||||
},
|
||||
{
|
||||
"commits": 13,
|
||||
"contributor": "Lukáš Jelínek"
|
||||
},
|
||||
{
|
||||
"commits": 13,
|
||||
"contributor": "Weblate Admin"
|
||||
|
@ -604,6 +604,10 @@
|
|||
"commits": 2,
|
||||
"contributor": "Leo Alcaraz"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "ERyPTION"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "POG"
|
||||
|
|
|
@ -24,8 +24,8 @@ async function activate() {
|
|||
}
|
||||
|
||||
async function fetchAndCache(event: ServiceWorkerFetchEvent): Promise<Response> {
|
||||
let networkResponse = await fetch(event.request)
|
||||
let cache = await caches.open(version)
|
||||
const networkResponse = await fetch(event.request)
|
||||
const cache = await caches.open(version)
|
||||
await cache.put(event.request, networkResponse.clone())
|
||||
console.log("Cached", event.request)
|
||||
return networkResponse
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue