forked from MapComplete/MapComplete
Auto-formatting
This commit is contained in:
parent
9e000d521f
commit
fed4cff878
26 changed files with 360 additions and 304 deletions
|
@ -210,8 +210,8 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
if (overpass === undefined) {
|
if (overpass === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
this.runningQuery.setData(true);
|
this.runningQuery.setData(true)
|
||||||
[data, date] = await overpass.queryGeoJson(bounds)
|
;[data, date] = await overpass.queryGeoJson(bounds)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
self.retries.data++
|
self.retries.data++
|
||||||
self.retries.ping()
|
self.retries.ping()
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* This actor will download the latest version of the selected element from OSM and update the tags if necessary.
|
* This actor will download the latest version of the selected element from OSM and update the tags if necessary.
|
||||||
*/
|
*/
|
||||||
import {UIEventSource} from "../UIEventSource"
|
import { UIEventSource } from "../UIEventSource"
|
||||||
import {ElementStorage} from "../ElementStorage"
|
import { ElementStorage } from "../ElementStorage"
|
||||||
import {Changes} from "../Osm/Changes"
|
import { Changes } from "../Osm/Changes"
|
||||||
import {OsmObject} from "../Osm/OsmObject"
|
import { OsmObject } from "../Osm/OsmObject"
|
||||||
import {OsmConnection} from "../Osm/OsmConnection"
|
import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import SimpleMetaTagger from "../SimpleMetaTagger"
|
import SimpleMetaTagger from "../SimpleMetaTagger"
|
||||||
|
|
||||||
|
@ -59,17 +59,16 @@ export default class SelectedElementTagsUpdater {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const latestTags = await OsmObject.DownloadPropertiesOf(id)
|
const latestTags = await OsmObject.DownloadPropertiesOf(id)
|
||||||
if (latestTags === "deleted") {
|
if (latestTags === "deleted") {
|
||||||
console.warn("The current selected element has been deleted upstream!")
|
console.warn("The current selected element has been deleted upstream!")
|
||||||
const currentTagsSource = state.allElements.getEventSourceById(id)
|
const currentTagsSource = state.allElements.getEventSourceById(id)
|
||||||
if(currentTagsSource.data["_deleted"] === "yes"){
|
if (currentTagsSource.data["_deleted"] === "yes") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
currentTagsSource.data["_deleted"] = "yes"
|
currentTagsSource.data["_deleted"] = "yes"
|
||||||
currentTagsSource.ping()
|
currentTagsSource.ping()
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
SelectedElementTagsUpdater.applyUpdate(state, latestTags, id)
|
SelectedElementTagsUpdater.applyUpdate(state, latestTags, id)
|
||||||
console.log("Updated", id)
|
console.log("Updated", id)
|
||||||
|
|
|
@ -85,7 +85,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
||||||
if (isShown !== undefined && !isShown.matchesProperties(tags)) {
|
if (isShown !== undefined && !isShown.matchesProperties(tags)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if(tags._deleted === "yes"){
|
if (tags._deleted === "yes") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indicates with what renderConfig it should be rendered.
|
* This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indicates with what renderConfig it should be rendered.
|
||||||
*/
|
*/
|
||||||
import {Store} from "../../UIEventSource"
|
import { Store } from "../../UIEventSource"
|
||||||
import {GeoOperations} from "../../GeoOperations"
|
import { GeoOperations } from "../../GeoOperations"
|
||||||
import FeatureSource from "../FeatureSource"
|
import FeatureSource from "../FeatureSource"
|
||||||
import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig"
|
import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig"
|
||||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||||
|
@ -17,7 +17,10 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
>
|
>
|
||||||
private readonly pointRenderings: { rendering: PointRenderingConfig; index: number }[]
|
private readonly pointRenderings: { rendering: PointRenderingConfig; index: number }[]
|
||||||
private readonly centroidRenderings: { rendering: PointRenderingConfig; index: number }[]
|
private readonly centroidRenderings: { rendering: PointRenderingConfig; index: number }[]
|
||||||
private readonly projectedCentroidRenderings: { rendering: PointRenderingConfig; index: number }[]
|
private readonly projectedCentroidRenderings: {
|
||||||
|
rendering: PointRenderingConfig
|
||||||
|
index: number
|
||||||
|
}[]
|
||||||
private readonly startRenderings: { rendering: PointRenderingConfig; index: number }[]
|
private readonly startRenderings: { rendering: PointRenderingConfig; index: number }[]
|
||||||
private readonly endRenderings: { rendering: PointRenderingConfig; index: number }[]
|
private readonly endRenderings: { rendering: PointRenderingConfig; index: number }[]
|
||||||
private readonly hasCentroid: boolean
|
private readonly hasCentroid: boolean
|
||||||
|
@ -90,10 +93,15 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
}
|
}
|
||||||
} else if (feat.geometry.type === "MultiPolygon") {
|
} else if (feat.geometry.type === "MultiPolygon") {
|
||||||
if (this.centroidRenderings.length > 0 || this.projectedCentroidRenderings.length > 0) {
|
if (this.centroidRenderings.length > 0 || this.projectedCentroidRenderings.length > 0) {
|
||||||
|
const centerpoints: [number, number][] = (<[number, number][][][]>(
|
||||||
const centerpoints: [number, number][] = (<[number, number][][][]>feat.geometry.coordinates).map(rings => GeoOperations.centerpointCoordinates(
|
feat.geometry.coordinates
|
||||||
{type: "Feature", properties: {}, geometry: {type: "Polygon", coordinates: rings}}
|
)).map((rings) =>
|
||||||
))
|
GeoOperations.centerpointCoordinates({
|
||||||
|
type: "Feature",
|
||||||
|
properties: {},
|
||||||
|
geometry: { type: "Polygon", coordinates: rings },
|
||||||
|
})
|
||||||
|
)
|
||||||
for (const centroidRendering of this.centroidRenderings) {
|
for (const centroidRendering of this.centroidRenderings) {
|
||||||
for (const centerpoint of centerpoints) {
|
for (const centerpoint of centerpoints) {
|
||||||
addAsPoint(feat, centroidRendering, centerpoint)
|
addAsPoint(feat, centroidRendering, centerpoint)
|
||||||
|
@ -105,8 +113,6 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
addAsPoint(feat, centroidRendering, centerpoint)
|
addAsPoint(feat, centroidRendering, centerpoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AT last, add it 'as is' to what we should render
|
// AT last, add it 'as is' to what we should render
|
||||||
|
@ -116,7 +122,6 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
lineRenderingIndex: i,
|
lineRenderingIndex: i,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This is a a line or polygon: add the centroids
|
// This is a a line or polygon: add the centroids
|
||||||
let centerpoint: [number, number] = undefined
|
let centerpoint: [number, number] = undefined
|
||||||
|
|
|
@ -19,9 +19,9 @@ export default class UserDetails {
|
||||||
public totalMessages: number = 0
|
public totalMessages: number = 0
|
||||||
public home: { lon: number; lat: number }
|
public home: { lon: number; lat: number }
|
||||||
public backend: string
|
public backend: string
|
||||||
public account_created: string;
|
public account_created: string
|
||||||
public tracesCount: number = 0;
|
public tracesCount: number = 0
|
||||||
public description: string;
|
public description: string
|
||||||
|
|
||||||
constructor(backend: string) {
|
constructor(backend: string) {
|
||||||
this.backend = backend
|
this.backend = backend
|
||||||
|
@ -214,8 +214,12 @@ export class OsmConnection {
|
||||||
data.name = userInfo.getAttribute("display_name")
|
data.name = userInfo.getAttribute("display_name")
|
||||||
data.account_created = userInfo.getAttribute("account_created")
|
data.account_created = userInfo.getAttribute("account_created")
|
||||||
data.uid = Number(userInfo.getAttribute("id"))
|
data.uid = Number(userInfo.getAttribute("id"))
|
||||||
data.csCount = Number.parseInt( userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? 0)
|
data.csCount = Number.parseInt(
|
||||||
data.tracesCount = Number.parseInt( userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? 0)
|
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? 0
|
||||||
|
)
|
||||||
|
data.tracesCount = Number.parseInt(
|
||||||
|
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? 0
|
||||||
|
)
|
||||||
|
|
||||||
data.img = undefined
|
data.img = undefined
|
||||||
const imgEl = userInfo.getElementsByTagName("img")
|
const imgEl = userInfo.getElementsByTagName("img")
|
||||||
|
|
|
@ -71,7 +71,7 @@ export abstract class OsmObject {
|
||||||
const url = `${OsmObject.backendURL}api/0.6/${id}`
|
const url = `${OsmObject.backendURL}api/0.6/${id}`
|
||||||
const rawData = await Utils.downloadJsonCachedAdvanced(url, 1000)
|
const rawData = await Utils.downloadJsonCachedAdvanced(url, 1000)
|
||||||
console.log(rawData)
|
console.log(rawData)
|
||||||
if(rawData["error"] !== undefined && rawData["statuscode"] === 410){
|
if (rawData["error"] !== undefined && rawData["statuscode"] === 410) {
|
||||||
return "deleted"
|
return "deleted"
|
||||||
}
|
}
|
||||||
return rawData["contents"].elements[0].tags
|
return rawData["contents"].elements[0].tags
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
import UserRelatedState from "./UserRelatedState"
|
import UserRelatedState from "./UserRelatedState"
|
||||||
import {Store, Stores, UIEventSource} from "../UIEventSource"
|
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||||
import BaseLayer from "../../Models/BaseLayer"
|
import BaseLayer from "../../Models/BaseLayer"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import AvailableBaseLayers from "../Actors/AvailableBaseLayers"
|
import AvailableBaseLayers from "../Actors/AvailableBaseLayers"
|
||||||
import Attribution from "../../UI/BigComponents/Attribution"
|
import Attribution from "../../UI/BigComponents/Attribution"
|
||||||
import Minimap, {MinimapObj} from "../../UI/Base/Minimap"
|
import Minimap, { MinimapObj } from "../../UI/Base/Minimap"
|
||||||
import {Tiles} from "../../Models/TileRange"
|
import { Tiles } from "../../Models/TileRange"
|
||||||
import BaseUIElement from "../../UI/BaseUIElement"
|
import BaseUIElement from "../../UI/BaseUIElement"
|
||||||
import FilteredLayer, {FilterState} from "../../Models/FilteredLayer"
|
import FilteredLayer, { FilterState } from "../../Models/FilteredLayer"
|
||||||
import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig"
|
import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig"
|
||||||
import {QueryParameters} from "../Web/QueryParameters"
|
import { QueryParameters } from "../Web/QueryParameters"
|
||||||
import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer"
|
import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer"
|
||||||
import {FeatureSourceForLayer, Tiled} from "../FeatureSource/FeatureSource"
|
import { FeatureSourceForLayer, Tiled } from "../FeatureSource/FeatureSource"
|
||||||
import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource"
|
import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource"
|
||||||
import {LocalStorageSource} from "../Web/LocalStorageSource"
|
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
import {GeoOperations} from "../GeoOperations"
|
import { GeoOperations } from "../GeoOperations"
|
||||||
import TitleHandler from "../Actors/TitleHandler"
|
import TitleHandler from "../Actors/TitleHandler"
|
||||||
import {BBox} from "../BBox"
|
import { BBox } from "../BBox"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import {TiledStaticFeatureSource} from "../FeatureSource/Sources/StaticFeatureSource"
|
import { TiledStaticFeatureSource } from "../FeatureSource/Sources/StaticFeatureSource"
|
||||||
import {Translation, TypedTranslation} from "../../UI/i18n/Translation"
|
import { Translation, TypedTranslation } from "../../UI/i18n/Translation"
|
||||||
import {Tag} from "../Tags/Tag"
|
import { Tag } from "../Tags/Tag"
|
||||||
import {OsmConnection} from "../Osm/OsmConnection"
|
import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
import {Feature, LineString} from "geojson"
|
import { Feature, LineString } from "geojson"
|
||||||
import {OsmTags} from "../../Models/OsmFeature"
|
import { OsmTags } from "../../Models/OsmFeature"
|
||||||
|
|
||||||
export interface GlobalFilter {
|
export interface GlobalFilter {
|
||||||
filter: FilterState
|
filter: FilterState
|
||||||
|
@ -266,27 +266,30 @@ export default class MapState extends UserRelatedState {
|
||||||
this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0))
|
this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
private initSelectedElement(){
|
private initSelectedElement() {
|
||||||
const layerDef: FilteredLayer = this.filteredLayers.data.filter(
|
const layerDef: FilteredLayer = this.filteredLayers.data.filter(
|
||||||
(l) => l.layerDef.id === "selected_element"
|
(l) => l.layerDef.id === "selected_element"
|
||||||
)[0]
|
)[0]
|
||||||
const empty = []
|
const empty = []
|
||||||
const store = this.selectedElement.map(feature => {
|
const store = this.selectedElement.map((feature) => {
|
||||||
if(feature === undefined || feature === null){
|
if (feature === undefined || feature === null) {
|
||||||
return empty
|
return empty
|
||||||
}
|
}
|
||||||
return [{
|
return [
|
||||||
feature: {
|
{
|
||||||
type:"Feature",
|
feature: {
|
||||||
properties: {
|
type: "Feature",
|
||||||
selected: "yes",
|
properties: {
|
||||||
id: "selected" + feature.properties.id
|
selected: "yes",
|
||||||
|
id: "selected" + feature.properties.id,
|
||||||
|
},
|
||||||
|
geometry: feature.geometry,
|
||||||
},
|
},
|
||||||
geometry:feature.geometry
|
freshness: new Date(),
|
||||||
}
|
},
|
||||||
, freshness: new Date()}];
|
]
|
||||||
});
|
})
|
||||||
this.selectedElementsLayer = new TiledStaticFeatureSource(store,layerDef);
|
this.selectedElementsLayer = new TiledStaticFeatureSource(store, layerDef)
|
||||||
}
|
}
|
||||||
|
|
||||||
private initUserLocationTrail() {
|
private initUserLocationTrail() {
|
||||||
|
|
|
@ -127,35 +127,38 @@ export default class MangroveReviews {
|
||||||
this._lastUpdate = new Date()
|
this._lastUpdate = new Date()
|
||||||
|
|
||||||
const self = this
|
const self = this
|
||||||
mangrove.getReviews({ sub: this.GetSubjectUri() })
|
mangrove
|
||||||
|
.getReviews({ sub: this.GetSubjectUri() })
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const reviews = []
|
const reviews = []
|
||||||
const reviewsByUser = []
|
const reviewsByUser = []
|
||||||
for (const review of data.reviews) {
|
for (const review of data.reviews) {
|
||||||
const r = review.payload
|
const r = review.payload
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"PublicKey is ",
|
"PublicKey is ",
|
||||||
self._mangroveIdentity.kid.data,
|
self._mangroveIdentity.kid.data,
|
||||||
"reviews.kid is",
|
"reviews.kid is",
|
||||||
review.kid
|
review.kid
|
||||||
)
|
)
|
||||||
const byUser = self._mangroveIdentity.kid.map((data) => data === review.signature)
|
const byUser = self._mangroveIdentity.kid.map(
|
||||||
const rev: Review = {
|
(data) => data === review.signature
|
||||||
made_by_user: byUser,
|
)
|
||||||
date: new Date(r.iat * 1000),
|
const rev: Review = {
|
||||||
comment: r.opinion,
|
made_by_user: byUser,
|
||||||
author: r.metadata.nickname,
|
date: new Date(r.iat * 1000),
|
||||||
affiliated: r.metadata.is_affiliated,
|
comment: r.opinion,
|
||||||
rating: r.rating, // percentage points
|
author: r.metadata.nickname,
|
||||||
|
affiliated: r.metadata.is_affiliated,
|
||||||
|
rating: r.rating, // percentage points
|
||||||
|
}
|
||||||
|
|
||||||
|
;(rev.made_by_user ? reviewsByUser : reviews).push(rev)
|
||||||
}
|
}
|
||||||
|
self._reviews.setData(reviewsByUser.concat(reviews))
|
||||||
;(rev.made_by_user ? reviewsByUser : reviews).push(rev)
|
})
|
||||||
}
|
.catch((e) => {
|
||||||
self._reviews.setData(reviewsByUser.concat(reviews))
|
console.error("Could not download review for ", e)
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.error("Could not download review for ", e);
|
|
||||||
})
|
})
|
||||||
return this._reviews
|
return this._reviews
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,8 +147,8 @@ export default class Wikipedia {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if(result["error"]){
|
if (result["error"]) {
|
||||||
throw "Could not download: "+JSON.stringify(result)
|
throw "Could not download: " + JSON.stringify(result)
|
||||||
}
|
}
|
||||||
const el = document.createElement("html")
|
const el = document.createElement("html")
|
||||||
el.innerHTML = result["content"].replace(/href="\//g, 'href="' + this.backend + "/")
|
el.innerHTML = result["content"].replace(/href="\//g, 'href="' + this.backend + "/")
|
||||||
|
|
|
@ -49,11 +49,12 @@ export default class DeleteConfig {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if(!json.omitDefaultDeleteReasons ){
|
if (!json.omitDefaultDeleteReasons) {
|
||||||
for (const defaultDeleteReason of DeleteConfig.defaultDeleteReasons) {
|
for (const defaultDeleteReason of DeleteConfig.defaultDeleteReasons) {
|
||||||
this.deleteReasons.push({
|
this.deleteReasons.push({
|
||||||
changesetMessage: defaultDeleteReason.changesetMessage,
|
changesetMessage: defaultDeleteReason.changesetMessage,
|
||||||
explanation: defaultDeleteReason.explanation.Clone(/*Must clone, hides translation otherwise*/)
|
explanation:
|
||||||
|
defaultDeleteReason.explanation.Clone(/*Must clone, hides translation otherwise*/),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,8 +67,12 @@ export default class DeleteConfig {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if(this.nonDeleteMappings.length + this.deleteReasons.length == 0){
|
if (this.nonDeleteMappings.length + this.deleteReasons.length == 0) {
|
||||||
throw "At "+context+": a deleteconfig should have some reasons to delete: either the default delete reasons or a nonDeleteMapping or extraDeletereason should be given"
|
throw (
|
||||||
|
"At " +
|
||||||
|
context +
|
||||||
|
": a deleteconfig should have some reasons to delete: either the default delete reasons or a nonDeleteMapping or extraDeletereason should be given"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.softDeletionTags = undefined
|
this.softDeletionTags = undefined
|
||||||
|
|
|
@ -10,9 +10,9 @@ import { FilterState } from "../FilteredLayer"
|
||||||
import { QueryParameters } from "../../Logic/Web/QueryParameters"
|
import { QueryParameters } from "../../Logic/Web/QueryParameters"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
import { RegexTag } from "../../Logic/Tags/RegexTag"
|
import { RegexTag } from "../../Logic/Tags/RegexTag"
|
||||||
import BaseUIElement from "../../UI/BaseUIElement";
|
import BaseUIElement from "../../UI/BaseUIElement"
|
||||||
import Table from "../../UI/Base/Table";
|
import Table from "../../UI/Base/Table"
|
||||||
import Combine from "../../UI/Base/Combine";
|
import Combine from "../../UI/Base/Combine"
|
||||||
|
|
||||||
export default class FilterConfig {
|
export default class FilterConfig {
|
||||||
public readonly id: string
|
public readonly id: string
|
||||||
|
@ -247,19 +247,22 @@ export default class FilterConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenerateDocs(): BaseUIElement {
|
public GenerateDocs(): BaseUIElement {
|
||||||
const hasField = this.options.some(opt => opt.fields?.length > 0)
|
const hasField = this.options.some((opt) => opt.fields?.length > 0)
|
||||||
return new Table(
|
return new Table(
|
||||||
Utils.NoNull(["id","question","osmTags",hasField ? "fields" : undefined]),
|
Utils.NoNull(["id", "question", "osmTags", hasField ? "fields" : undefined]),
|
||||||
this.options.map((opt, i) => {
|
this.options.map((opt, i) => {
|
||||||
const isDefault = this.options.length > 1 && ((this.defaultSelection ?? 0) == i)
|
const isDefault = this.options.length > 1 && (this.defaultSelection ?? 0) == i
|
||||||
return Utils.NoNull([
|
return Utils.NoNull([
|
||||||
this.id + "." + i,
|
this.id + "." + i,
|
||||||
isDefault ? new Combine([opt.question.SetClass("font-bold"), "(default)"]) : opt.question ,
|
isDefault
|
||||||
|
? new Combine([opt.question.SetClass("font-bold"), "(default)"])
|
||||||
|
: opt.question,
|
||||||
opt.osmTags?.asHumanString(false, false, {}) ?? "",
|
opt.osmTags?.asHumanString(false, false, {}) ?? "",
|
||||||
opt.fields?.length > 0 ? new Combine(opt.fields.map(f => f.name+" ("+f.type+")")) : undefined
|
opt.fields?.length > 0
|
||||||
|
? new Combine(opt.fields.map((f) => f.name + " (" + f.type + ")"))
|
||||||
]);
|
: undefined,
|
||||||
|
])
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@ export default interface PointRenderingConfigJson {
|
||||||
*/
|
*/
|
||||||
css?: string | TagRenderingConfigJson
|
css?: string | TagRenderingConfigJson
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A snippet of css-classes. They can be space-separated
|
* A snippet of css-classes. They can be space-separated
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -301,7 +301,10 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
|
|
||||||
const hasCenterRendering = this.mapRendering.some(
|
const hasCenterRendering = this.mapRendering.some(
|
||||||
(r) =>
|
(r) =>
|
||||||
r.location.has("centroid") || r.location.has("projected_centerpoint") || r.location.has("start") || r.location.has("end")
|
r.location.has("centroid") ||
|
||||||
|
r.location.has("projected_centerpoint") ||
|
||||||
|
r.location.has("start") ||
|
||||||
|
r.location.has("end")
|
||||||
)
|
)
|
||||||
|
|
||||||
if (this.lineRendering.length === 0 && this.mapRendering.length === 0) {
|
if (this.lineRendering.length === 0 && this.mapRendering.length === 0) {
|
||||||
|
@ -602,10 +605,10 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterDocs: (string | BaseUIElement)[] = []
|
const filterDocs: (string | BaseUIElement)[] = []
|
||||||
if(this.filters.length > 0){
|
if (this.filters.length > 0) {
|
||||||
filterDocs.push(new Title("Filters", 4))
|
filterDocs.push(new Title("Filters", 4))
|
||||||
filterDocs.push(...this.filters.map(filter => filter.GenerateDocs()))
|
filterDocs.push(...this.filters.map((filter) => filter.GenerateDocs()))
|
||||||
}
|
}
|
||||||
return new Combine([
|
return new Combine([
|
||||||
new Combine([new Title(this.id, 1), iconImg, this.description, "\n"]).SetClass(
|
new Combine([new Title(this.id, 1), iconImg, this.description, "\n"]).SetClass(
|
||||||
|
@ -621,7 +624,7 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
new Title("Supported attributes", 2),
|
new Title("Supported attributes", 2),
|
||||||
quickOverview,
|
quickOverview,
|
||||||
...this.tagRenderings.map((tr) => tr.GenerateDocumentation()),
|
...this.tagRenderings.map((tr) => tr.GenerateDocumentation()),
|
||||||
...filterDocs
|
...filterDocs,
|
||||||
])
|
])
|
||||||
.SetClass("flex-col")
|
.SetClass("flex-col")
|
||||||
.SetClass("link-underline")
|
.SetClass("link-underline")
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { FixedUiElement } from "../../UI/Base/FixedUiElement"
|
||||||
import Img from "../../UI/Base/Img"
|
import Img from "../../UI/Base/Img"
|
||||||
import Combine from "../../UI/Base/Combine"
|
import Combine from "../../UI/Base/Combine"
|
||||||
import { VariableUiElement } from "../../UI/Base/VariableUIElement"
|
import { VariableUiElement } from "../../UI/Base/VariableUIElement"
|
||||||
import {TagRenderingConfigJson} from "./Json/TagRenderingConfigJson";
|
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||||
|
|
||||||
export default class PointRenderingConfig extends WithContextLoader {
|
export default class PointRenderingConfig extends WithContextLoader {
|
||||||
private static readonly allowed_location_codes = new Set<string>([
|
private static readonly allowed_location_codes = new Set<string>([
|
||||||
|
@ -64,7 +64,7 @@ export default class PointRenderingConfig extends WithContextLoader {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
this.icon = this.tr("icon", undefined)
|
this.icon = this.tr("icon", undefined)
|
||||||
if(json.css !== undefined){
|
if (json.css !== undefined) {
|
||||||
this.cssDef = this.tr("css", undefined)
|
this.cssDef = this.tr("css", undefined)
|
||||||
}
|
}
|
||||||
this.cssClasses = this.tr("cssClasses", undefined)
|
this.cssClasses = this.tr("cssClasses", undefined)
|
||||||
|
@ -247,8 +247,8 @@ export default class PointRenderingConfig extends WithContextLoader {
|
||||||
iconAndBadges.SetClass("w-full h-full")
|
iconAndBadges.SetClass("w-full h-full")
|
||||||
}
|
}
|
||||||
|
|
||||||
const css= this.cssDef?.GetRenderValue(tags , undefined)?.txt
|
const css = this.cssDef?.GetRenderValue(tags, undefined)?.txt
|
||||||
const cssClasses = this.cssClasses?.GetRenderValue(tags , undefined)?.txt
|
const cssClasses = this.cssClasses?.GetRenderValue(tags, undefined)?.txt
|
||||||
|
|
||||||
let label = this.GetLabel(tags)
|
let label = this.GetLabel(tags)
|
||||||
let htmlEl: BaseUIElement
|
let htmlEl: BaseUIElement
|
||||||
|
@ -262,11 +262,11 @@ export default class PointRenderingConfig extends WithContextLoader {
|
||||||
htmlEl = new Combine([iconAndBadges, label]).SetStyle("flex flex-col")
|
htmlEl = new Combine([iconAndBadges, label]).SetStyle("flex flex-col")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(css !== undefined){
|
if (css !== undefined) {
|
||||||
htmlEl?.SetStyle(css)
|
htmlEl?.SetStyle(css)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cssClasses !== undefined){
|
if (cssClasses !== undefined) {
|
||||||
htmlEl?.SetClass(cssClasses)
|
htmlEl?.SetClass(cssClasses)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Loc from "../../Models/Loc"
|
||||||
import BaseLayer from "../../Models/BaseLayer"
|
import BaseLayer from "../../Models/BaseLayer"
|
||||||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
|
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
|
||||||
import * as L from "leaflet"
|
import * as L from "leaflet"
|
||||||
import {LeafletMouseEvent, Map} from "leaflet"
|
import { LeafletMouseEvent, Map } from "leaflet"
|
||||||
import Minimap, { MinimapObj, MinimapOptions } from "./Minimap"
|
import Minimap, { MinimapObj, MinimapOptions } from "./Minimap"
|
||||||
import { BBox } from "../../Logic/BBox"
|
import { BBox } from "../../Logic/BBox"
|
||||||
import "leaflet-polylineoffset"
|
import "leaflet-polylineoffset"
|
||||||
|
@ -317,7 +317,7 @@ export default class MinimapImplementation extends BaseUIElement implements Mini
|
||||||
if (this._options.lastClickLocation) {
|
if (this._options.lastClickLocation) {
|
||||||
const lastClickLocation = this._options.lastClickLocation
|
const lastClickLocation = this._options.lastClickLocation
|
||||||
map.on("click", function (e: LeafletMouseEvent) {
|
map.on("click", function (e: LeafletMouseEvent) {
|
||||||
if(e.originalEvent["dismissed"] ){
|
if (e.originalEvent["dismissed"]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lastClickLocation?.setData({ lat: e.latlng.lat, lon: e.latlng.lng })
|
lastClickLocation?.setData({ lat: e.latlng.lat, lon: e.latlng.lng })
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Svg from "../../Svg"
|
import Svg from "../../Svg"
|
||||||
import Combine from "./Combine"
|
import Combine from "./Combine"
|
||||||
import {FixedUiElement} from "./FixedUiElement"
|
import { FixedUiElement } from "./FixedUiElement"
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import Hash from "../../Logic/Web/Hash"
|
import Hash from "../../Logic/Web/Hash"
|
||||||
import BaseUIElement from "../BaseUIElement"
|
import BaseUIElement from "../BaseUIElement"
|
||||||
import Title from "./Title"
|
import Title from "./Title"
|
||||||
|
@ -71,20 +71,17 @@ export default class ScrollableFullScreen {
|
||||||
}
|
}
|
||||||
ScrollableFullScreen._currentlyOpen = self
|
ScrollableFullScreen._currentlyOpen = self
|
||||||
self.Activate()
|
self.Activate()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if(self.hashToShow !== undefined){
|
if (self.hashToShow !== undefined) {
|
||||||
Hash.hash.setData(undefined)
|
Hash.hash.setData(undefined)
|
||||||
}
|
}
|
||||||
// Some cleanup...
|
// Some cleanup...
|
||||||
ScrollableFullScreen.collapse()
|
ScrollableFullScreen.collapse()
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private static initEmpty(): FixedUiElement{
|
private static initEmpty(): FixedUiElement {
|
||||||
|
|
||||||
document.addEventListener("keyup", function (event) {
|
document.addEventListener("keyup", function (event) {
|
||||||
if (event.code === "Escape") {
|
if (event.code === "Escape") {
|
||||||
ScrollableFullScreen.collapse()
|
ScrollableFullScreen.collapse()
|
||||||
|
@ -93,9 +90,8 @@ export default class ScrollableFullScreen {
|
||||||
})
|
})
|
||||||
|
|
||||||
return new FixedUiElement("")
|
return new FixedUiElement("")
|
||||||
|
|
||||||
}
|
}
|
||||||
public static collapse(){
|
public static collapse() {
|
||||||
const fs = document.getElementById("fullscreen")
|
const fs = document.getElementById("fullscreen")
|
||||||
if (fs !== null) {
|
if (fs !== null) {
|
||||||
ScrollableFullScreen.empty.AttachTo("fullscreen")
|
ScrollableFullScreen.empty.AttachTo("fullscreen")
|
||||||
|
@ -103,8 +99,8 @@ export default class ScrollableFullScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
const opened = ScrollableFullScreen._currentlyOpen
|
const opened = ScrollableFullScreen._currentlyOpen
|
||||||
if( opened !== undefined){
|
if (opened !== undefined) {
|
||||||
opened?.isShown?.setData(false)
|
opened?.isShown?.setData(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +120,6 @@ export default class ScrollableFullScreen {
|
||||||
fs.classList.remove("hidden")
|
fs.classList.remove("hidden")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private BuildComponent(title: BaseUIElement, content: BaseUIElement): BaseUIElement {
|
private BuildComponent(title: BaseUIElement, content: BaseUIElement): BaseUIElement {
|
||||||
const returnToTheMap = new Combine([
|
const returnToTheMap = new Combine([
|
||||||
Svg.back_svg().SetClass("block md:hidden w-12 h-12 p-2 svg-foreground"),
|
Svg.back_svg().SetClass("block md:hidden w-12 h-12 p-2 svg-foreground"),
|
||||||
|
|
|
@ -147,15 +147,11 @@ export default class CopyrightPanel extends Combine {
|
||||||
imgSize,
|
imgSize,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
new SubtleButton(
|
new SubtleButton(Svg.mastodon_ui(), t.followOnMastodon, {
|
||||||
Svg.mastodon_ui(),
|
url: "https://en.osm.town/web/notifications",
|
||||||
t.followOnMastodon,
|
newTab: true,
|
||||||
{
|
imgSize,
|
||||||
url: "https://en.osm.town/web/notifications",
|
}),
|
||||||
newTab: true,
|
|
||||||
imgSize,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
new OpenIdEditor(state, iconStyle),
|
new OpenIdEditor(state, iconStyle),
|
||||||
new MapillaryLink(state, iconStyle),
|
new MapillaryLink(state, iconStyle),
|
||||||
new OpenJosm(state, iconStyle),
|
new OpenJosm(state, iconStyle),
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { VariableUiElement } from "../Base/VariableUIElement"
|
||||||
import FeatureInfoBox from "../Popup/FeatureInfoBox"
|
import FeatureInfoBox from "../Popup/FeatureInfoBox"
|
||||||
import CopyrightPanel from "./CopyrightPanel"
|
import CopyrightPanel from "./CopyrightPanel"
|
||||||
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
|
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||||
|
|
||||||
export default class LeftControls extends Combine {
|
export default class LeftControls extends Combine {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -46,14 +46,11 @@ export default class LeftControls extends Combine {
|
||||||
})
|
})
|
||||||
).SetClass("inline-block w-full h-full")
|
).SetClass("inline-block w-full h-full")
|
||||||
|
|
||||||
|
|
||||||
feature.map((feature) => {
|
feature.map((feature) => {
|
||||||
if (feature === undefined) {
|
if (feature === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const tagsSource = state.allElements.getEventSourceById(
|
const tagsSource = state.allElements.getEventSourceById(feature.properties.id)
|
||||||
feature.properties.id
|
|
||||||
)
|
|
||||||
return new FeatureInfoBox(tagsSource, currentViewFL.layerDef, state, {
|
return new FeatureInfoBox(tagsSource, currentViewFL.layerDef, state, {
|
||||||
hashToShow: "currentview",
|
hashToShow: "currentview",
|
||||||
isShown: guiState.currentViewControlIsOpened,
|
isShown: guiState.currentViewControlIsOpened,
|
||||||
|
@ -85,7 +82,6 @@ export default class LeftControls extends Combine {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
new ScrollableFullScreen(
|
new ScrollableFullScreen(
|
||||||
() => Translations.t.general.layerSelection.title.Clone(),
|
() => Translations.t.general.layerSelection.title.Clone(),
|
||||||
() =>
|
() =>
|
||||||
|
@ -96,8 +92,8 @@ export default class LeftControls extends Combine {
|
||||||
guiState.filterViewIsOpened
|
guiState.filterViewIsOpened
|
||||||
)
|
)
|
||||||
const toggledFilter = new MapControlButton(Svg.layers_svg()).onClick(() =>
|
const toggledFilter = new MapControlButton(Svg.layers_svg()).onClick(() =>
|
||||||
guiState.filterViewIsOpened.setData(true)
|
guiState.filterViewIsOpened.setData(true)
|
||||||
)
|
)
|
||||||
|
|
||||||
const filterButton = new Toggle(toggledFilter, undefined, state.featureSwitchFilter)
|
const filterButton = new Toggle(toggledFilter, undefined, state.featureSwitchFilter)
|
||||||
|
|
||||||
|
@ -110,22 +106,17 @@ export default class LeftControls extends Combine {
|
||||||
// If the welcomeMessage is disabled, the copyright is hidden (as that is where the copyright is located
|
// If the welcomeMessage is disabled, the copyright is hidden (as that is where the copyright is located
|
||||||
const copyright = new Toggle(
|
const copyright = new Toggle(
|
||||||
undefined,
|
undefined,
|
||||||
new Lazy(
|
new Lazy(() => {
|
||||||
() =>
|
new ScrollableFullScreen(
|
||||||
{
|
() => Translations.t.general.attribution.attributionTitle,
|
||||||
|
() => new CopyrightPanel(state),
|
||||||
new ScrollableFullScreen(
|
"copyright",
|
||||||
() => Translations.t.general.attribution.attributionTitle,
|
guiState.copyrightViewIsOpened
|
||||||
() => new CopyrightPanel(state),
|
)
|
||||||
"copyright",
|
return new MapControlButton(Svg.copyright_svg()).onClick(() =>
|
||||||
guiState.copyrightViewIsOpened
|
guiState.copyrightViewIsOpened.setData(true)
|
||||||
);
|
)
|
||||||
return new MapControlButton(Svg.copyright_svg()).onClick(() =>
|
}),
|
||||||
guiState.copyrightViewIsOpened.setData(true)
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
),
|
|
||||||
state.featureSwitchWelcomeMessage
|
state.featureSwitchWelcomeMessage
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
import ScrollableFullScreen from "../Base/ScrollableFullScreen"
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations"
|
||||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import Combine from "../Base/Combine";
|
import Combine from "../Base/Combine"
|
||||||
import {SubtleButton} from "../Base/SubtleButton";
|
import { SubtleButton } from "../Base/SubtleButton"
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg"
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||||
import Img from "../Base/Img";
|
import Img from "../Base/Img"
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||||
import Link from "../Base/Link";
|
import Link from "../Base/Link"
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import Loc from "../../Models/Loc";
|
import Loc from "../../Models/Loc"
|
||||||
import BaseUIElement from "../BaseUIElement";
|
import BaseUIElement from "../BaseUIElement"
|
||||||
import Showdown from "showdown"
|
import Showdown from "showdown"
|
||||||
import LanguagePicker from "../LanguagePicker";
|
import LanguagePicker from "../LanguagePicker"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import Constants from "../../Models/Constants";
|
import Constants from "../../Models/Constants"
|
||||||
|
|
||||||
export class ImportViewerLinks extends VariableUiElement {
|
export class ImportViewerLinks extends VariableUiElement {
|
||||||
constructor(osmConnection: OsmConnection) {
|
constructor(osmConnection: OsmConnection) {
|
||||||
|
@ -37,22 +37,25 @@ export class ImportViewerLinks extends VariableUiElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserInformationMainPanel extends Combine {
|
class UserInformationMainPanel extends Combine {
|
||||||
constructor(osmConnection: OsmConnection, locationControl: UIEventSource<Loc>, layout: LayoutConfig) {
|
constructor(
|
||||||
const t = Translations.t.userinfo;
|
osmConnection: OsmConnection,
|
||||||
|
locationControl: UIEventSource<Loc>,
|
||||||
|
layout: LayoutConfig
|
||||||
|
) {
|
||||||
|
const t = Translations.t.userinfo
|
||||||
const imgSize = "h-6 w-6"
|
const imgSize = "h-6 w-6"
|
||||||
const ud = osmConnection.userDetails;
|
const ud = osmConnection.userDetails
|
||||||
super([
|
super([
|
||||||
|
new VariableUiElement(
|
||||||
new VariableUiElement(ud.map(ud => {
|
ud.map((ud) => {
|
||||||
|
|
||||||
if (!ud?.loggedIn) {
|
if (!ud?.loggedIn) {
|
||||||
// Not logged in
|
// Not logged in
|
||||||
return new SubtleButton(
|
return new SubtleButton(Svg.login_svg(), "Login", { imgSize }).onClick(
|
||||||
Svg.login_svg(), "Login", {imgSize}
|
osmConnection.AttemptLogin
|
||||||
).onClick(osmConnection.AttemptLogin)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let img: Img = Svg.person_svg();
|
let img: Img = Svg.person_svg()
|
||||||
if (ud.img !== undefined) {
|
if (ud.img !== undefined) {
|
||||||
img = new Img(ud.img)
|
img = new Img(ud.img)
|
||||||
}
|
}
|
||||||
|
@ -64,69 +67,95 @@ class UserInformationMainPanel extends Combine {
|
||||||
Svg.pencil_svg().SetClass("h-4 w-4"),
|
Svg.pencil_svg().SetClass("h-4 w-4"),
|
||||||
"https://www.openstreetmap.org/profile/edit",
|
"https://www.openstreetmap.org/profile/edit",
|
||||||
true
|
true
|
||||||
).SetClass("absolute block bg-subtle rounded-full p-2 bottom-2 right-2 w-min self-end")
|
).SetClass(
|
||||||
|
"absolute block bg-subtle rounded-full p-2 bottom-2 right-2 w-min self-end"
|
||||||
|
)
|
||||||
|
|
||||||
description = new Combine([
|
description = new Combine([
|
||||||
new FixedUiElement(new Showdown.Converter().makeHtml(ud.description)).SetClass("link-underline"),
|
new FixedUiElement(
|
||||||
editButton
|
new Showdown.Converter().makeHtml(ud.description)
|
||||||
|
).SetClass("link-underline"),
|
||||||
|
editButton,
|
||||||
]).SetClass("relative w-full m-2")
|
]).SetClass("relative w-full m-2")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
description = new Combine([
|
description = new Combine([
|
||||||
t.noDescription, new SubtleButton(Svg.pencil_svg(), t.noDescriptionCallToAction, {imgSize})
|
t.noDescription,
|
||||||
|
new SubtleButton(Svg.pencil_svg(), t.noDescriptionCallToAction, {
|
||||||
|
imgSize,
|
||||||
|
}),
|
||||||
]).SetClass("w-full m-2")
|
]).SetClass("w-full m-2")
|
||||||
}
|
}
|
||||||
|
|
||||||
let panToHome: BaseUIElement;
|
let panToHome: BaseUIElement
|
||||||
if (ud.home) {
|
if (ud.home) {
|
||||||
panToHome = new SubtleButton(Svg.home_svg(), t.moveToHome, {imgSize})
|
panToHome = new SubtleButton(Svg.home_svg(), t.moveToHome, {
|
||||||
.onClick(() => {
|
imgSize,
|
||||||
const home = ud?.home
|
}).onClick(() => {
|
||||||
if (home === undefined) {
|
const home = ud?.home
|
||||||
return
|
if (home === undefined) {
|
||||||
}
|
return
|
||||||
locationControl.setData({...home, zoom: 16})
|
}
|
||||||
}
|
locationControl.setData({ ...home, zoom: 16 })
|
||||||
);
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Combine([
|
return new Combine([
|
||||||
new Combine([img, description]).SetClass("flex border border-black rounded-md"),
|
new Combine([img, description]).SetClass(
|
||||||
new LanguagePicker(layout.language, Translations.t.general.pickLanguage.Clone()),
|
"flex border border-black rounded-md"
|
||||||
|
),
|
||||||
|
new LanguagePicker(
|
||||||
|
layout.language,
|
||||||
|
Translations.t.general.pickLanguage.Clone()
|
||||||
|
),
|
||||||
|
|
||||||
new SubtleButton(Svg.envelope_svg(), new Combine([t.gotoInbox,
|
new SubtleButton(
|
||||||
ud.unreadMessages == 0 ? undefined : t.newMessages.SetClass("alert block")
|
Svg.envelope_svg(),
|
||||||
|
new Combine([
|
||||||
|
t.gotoInbox,
|
||||||
|
ud.unreadMessages == 0
|
||||||
|
? undefined
|
||||||
|
: t.newMessages.SetClass("alert block"),
|
||||||
]),
|
]),
|
||||||
{imgSize, url: `${ud.backend}/messages/inbox`, newTab: true}),
|
{ imgSize, url: `${ud.backend}/messages/inbox`, newTab: true }
|
||||||
new SubtleButton(Svg.gear_svg(), t.gotoSettings,
|
),
|
||||||
{imgSize, url: `${ud.backend}/user/${encodeURIComponent(ud.name)}/account`, newTab: true}),
|
new SubtleButton(Svg.gear_svg(), t.gotoSettings, {
|
||||||
|
imgSize,
|
||||||
|
url: `${ud.backend}/user/${encodeURIComponent(ud.name)}/account`,
|
||||||
|
newTab: true,
|
||||||
|
}),
|
||||||
panToHome,
|
panToHome,
|
||||||
new ImportViewerLinks(osmConnection),
|
new ImportViewerLinks(osmConnection),
|
||||||
new SubtleButton(Svg.logout_svg(), Translations.t.general.logout, {imgSize}).onClick(osmConnection.LogOut)
|
new SubtleButton(Svg.logout_svg(), Translations.t.general.logout, {
|
||||||
|
imgSize,
|
||||||
|
}).onClick(osmConnection.LogOut),
|
||||||
])
|
])
|
||||||
}
|
})
|
||||||
)).SetClass("flex flex-col"),
|
).SetClass("flex flex-col"),
|
||||||
|
])
|
||||||
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class UserInformationPanel extends ScrollableFullScreen {
|
export default class UserInformationPanel extends ScrollableFullScreen {
|
||||||
constructor(state: {
|
constructor(state: {
|
||||||
layoutToUse: LayoutConfig;
|
layoutToUse: LayoutConfig
|
||||||
osmConnection: OsmConnection, locationControl: UIEventSource<Loc>
|
osmConnection: OsmConnection
|
||||||
|
locationControl: UIEventSource<Loc>
|
||||||
}) {
|
}) {
|
||||||
const t = Translations.t.general;
|
const t = Translations.t.general
|
||||||
super(
|
super(
|
||||||
() => {
|
() => {
|
||||||
return new VariableUiElement(state.osmConnection.userDetails.map(ud => "Welcome " + ud.name))
|
return new VariableUiElement(
|
||||||
|
state.osmConnection.userDetails.map((ud) => "Welcome " + ud.name)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
return new UserInformationMainPanel(state.osmConnection, state.locationControl, state.layoutToUse)
|
return new UserInformationMainPanel(
|
||||||
|
state.osmConnection,
|
||||||
|
state.locationControl,
|
||||||
|
state.layoutToUse
|
||||||
|
)
|
||||||
},
|
},
|
||||||
"userinfo"
|
"userinfo"
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,7 @@ export default class DeleteWizard extends Toggle {
|
||||||
return t.explanations.hardDelete
|
return t.explanations.hardDelete
|
||||||
}
|
}
|
||||||
// This is a soft deletion: we explain _why_ the deletion is soft
|
// This is a soft deletion: we explain _why_ the deletion is soft
|
||||||
return t.explanations.softDelete.Subs({ reason: reason})
|
return t.explanations.softDelete.Subs({ reason: reason })
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import TagRenderingQuestion from "./TagRenderingQuestion"
|
import TagRenderingQuestion from "./TagRenderingQuestion"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Combine from "../Base/Combine"
|
import Combine from "../Base/Combine"
|
||||||
|
@ -6,10 +6,10 @@ import TagRenderingAnswer from "./TagRenderingAnswer"
|
||||||
import Toggle from "../Input/Toggle"
|
import Toggle from "../Input/Toggle"
|
||||||
import BaseUIElement from "../BaseUIElement"
|
import BaseUIElement from "../BaseUIElement"
|
||||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
|
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
|
||||||
import {Unit} from "../../Models/Unit"
|
import { Unit } from "../../Models/Unit"
|
||||||
import Lazy from "../Base/Lazy"
|
import Lazy from "../Base/Lazy"
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement"
|
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||||
import {EditButton} from "./SaveButton"
|
import { EditButton } from "./SaveButton"
|
||||||
|
|
||||||
export default class EditableTagRendering extends Toggle {
|
export default class EditableTagRendering extends Toggle {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -52,9 +52,9 @@ export default class EditableTagRendering extends Toggle {
|
||||||
undefined,
|
undefined,
|
||||||
renderingIsShown
|
renderingIsShown
|
||||||
)
|
)
|
||||||
const self = this;
|
const self = this
|
||||||
editMode.addCallback(editing => {
|
editMode.addCallback((editing) => {
|
||||||
if(editing){
|
if (editing) {
|
||||||
console.log("Scrolling etr into view")
|
console.log("Scrolling etr into view")
|
||||||
self.ScrollIntoView()
|
self.ScrollIntoView()
|
||||||
}
|
}
|
||||||
|
@ -91,18 +91,16 @@ export default class EditableTagRendering extends Toggle {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
const answerWithEditButton = new Combine([
|
const answerWithEditButton = new Combine([
|
||||||
answer,
|
answer,
|
||||||
new EditButton(state.osmConnection, () => {
|
new EditButton(state.osmConnection, () => {
|
||||||
editMode.setData(true)
|
editMode.setData(true)
|
||||||
question.ScrollIntoView({
|
question.ScrollIntoView({
|
||||||
onlyIfPartiallyHidden:true
|
onlyIfPartiallyHidden: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
}),
|
}),
|
||||||
]).SetClass("flex justify-between w-full")
|
]).SetClass("flex justify-between w-full")
|
||||||
rendering = new Toggle(question, answerWithEditButton, editMode)
|
rendering = new Toggle(question, answerWithEditButton, editMode)
|
||||||
|
|
||||||
}
|
}
|
||||||
return rendering
|
return rendering
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,11 +79,15 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
|
||||||
public static GenerateContent(
|
public static GenerateContent(
|
||||||
tags: UIEventSource<any>,
|
tags: UIEventSource<any>,
|
||||||
layerConfig: LayerConfig,
|
layerConfig: LayerConfig,
|
||||||
state: FeaturePipelineState): BaseUIElement{
|
state: FeaturePipelineState
|
||||||
|
): BaseUIElement {
|
||||||
return new Toggle(
|
return new Toggle(
|
||||||
new Combine([Svg.delete_icon_svg().SetClass("w-8 h-8"), Translations.t.delete.isDeleted]).SetClass("flex justify-center font-bold items-center") ,
|
new Combine([
|
||||||
|
Svg.delete_icon_svg().SetClass("w-8 h-8"),
|
||||||
|
Translations.t.delete.isDeleted,
|
||||||
|
]).SetClass("flex justify-center font-bold items-center"),
|
||||||
FeatureInfoBox.GenerateMainContent(tags, layerConfig, state),
|
FeatureInfoBox.GenerateMainContent(tags, layerConfig, state),
|
||||||
tags.map(t => t["_deleted"] == "yes")
|
tags.map((t) => t["_deleted"] == "yes")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
private static GenerateMainContent(
|
private static GenerateMainContent(
|
||||||
|
@ -91,7 +95,6 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
|
||||||
layerConfig: LayerConfig,
|
layerConfig: LayerConfig,
|
||||||
state: FeaturePipelineState
|
state: FeaturePipelineState
|
||||||
): BaseUIElement {
|
): BaseUIElement {
|
||||||
|
|
||||||
let questionBoxes: Map<string, QuestionBox> = new Map<string, QuestionBox>()
|
let questionBoxes: Map<string, QuestionBox> = new Map<string, QuestionBox>()
|
||||||
const t = Translations.t.general
|
const t = Translations.t.general
|
||||||
const allGroupNames = Utils.Dedup(layerConfig.tagRenderings.map((tr) => tr.group))
|
const allGroupNames = Utils.Dedup(layerConfig.tagRenderings.map((tr) => tr.group))
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
import {SubtleButton} from "../Base/SubtleButton"
|
import { SubtleButton } from "../Base/SubtleButton"
|
||||||
import Combine from "../Base/Combine"
|
import Combine from "../Base/Combine"
|
||||||
import Svg from "../../Svg"
|
import Svg from "../../Svg"
|
||||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import Toggle from "../Input/Toggle"
|
import Toggle from "../Input/Toggle"
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement"
|
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||||
import {Translation} from "../i18n/Translation"
|
import { Translation } from "../i18n/Translation"
|
||||||
import BaseUIElement from "../BaseUIElement"
|
import BaseUIElement from "../BaseUIElement"
|
||||||
import LocationInput from "../Input/LocationInput"
|
import LocationInput from "../Input/LocationInput"
|
||||||
import Loc from "../../Models/Loc"
|
import Loc from "../../Models/Loc"
|
||||||
import {GeoOperations} from "../../Logic/GeoOperations"
|
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||||
import {OsmObject} from "../../Logic/Osm/OsmObject"
|
import { OsmObject } from "../../Logic/Osm/OsmObject"
|
||||||
import {Changes} from "../../Logic/Osm/Changes"
|
import { Changes } from "../../Logic/Osm/Changes"
|
||||||
import ChangeLocationAction from "../../Logic/Osm/Actions/ChangeLocationAction"
|
import ChangeLocationAction from "../../Logic/Osm/Actions/ChangeLocationAction"
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import MoveConfig from "../../Models/ThemeConfig/MoveConfig"
|
import MoveConfig from "../../Models/ThemeConfig/MoveConfig"
|
||||||
import {ElementStorage} from "../../Logic/ElementStorage"
|
import { ElementStorage } from "../../Logic/ElementStorage"
|
||||||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
|
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
|
||||||
import BaseLayer from "../../Models/BaseLayer"
|
import BaseLayer from "../../Models/BaseLayer"
|
||||||
import SearchAndGo from "../BigComponents/SearchAndGo";
|
import SearchAndGo from "../BigComponents/SearchAndGo"
|
||||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
||||||
import {And} from "../../Logic/Tags/And";
|
import { And } from "../../Logic/Tags/And"
|
||||||
import {Tag} from "../../Logic/Tags/Tag";
|
import { Tag } from "../../Logic/Tags/Tag"
|
||||||
|
|
||||||
interface MoveReason {
|
interface MoveReason {
|
||||||
text: Translation | string
|
text: Translation | string
|
||||||
|
@ -71,7 +71,7 @@ export default class MoveWizard extends Toggle {
|
||||||
includeSearch: true,
|
includeSearch: true,
|
||||||
startZoom: 12,
|
startZoom: 12,
|
||||||
minZoom: 6,
|
minZoom: 6,
|
||||||
eraseAddressFields: true
|
eraseAddressFields: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (options.enableImproveAccuracy) {
|
if (options.enableImproveAccuracy) {
|
||||||
|
@ -85,7 +85,7 @@ export default class MoveWizard extends Toggle {
|
||||||
background: "photo",
|
background: "photo",
|
||||||
startZoom: 17,
|
startZoom: 17,
|
||||||
minZoom: 16,
|
minZoom: 16,
|
||||||
eraseAddressFields: false
|
eraseAddressFields: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ export default class MoveWizard extends Toggle {
|
||||||
let searchPanel: BaseUIElement = undefined
|
let searchPanel: BaseUIElement = undefined
|
||||||
if (reason.includeSearch) {
|
if (reason.includeSearch) {
|
||||||
searchPanel = new SearchAndGo({
|
searchPanel = new SearchAndGo({
|
||||||
leafletMap: locationInput.leafletMap
|
leafletMap: locationInput.leafletMap,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,12 +186,14 @@ export default class MoveWizard extends Toggle {
|
||||||
|
|
||||||
if (reason.eraseAddressFields) {
|
if (reason.eraseAddressFields) {
|
||||||
await state.changes.applyAction(
|
await state.changes.applyAction(
|
||||||
new ChangeTagAction(featureToMove.properties.id,
|
new ChangeTagAction(
|
||||||
new And([new Tag("addr:housenumber", ""),
|
featureToMove.properties.id,
|
||||||
|
new And([
|
||||||
|
new Tag("addr:housenumber", ""),
|
||||||
new Tag("addr:street", ""),
|
new Tag("addr:street", ""),
|
||||||
new Tag("addr:city", ""),
|
new Tag("addr:city", ""),
|
||||||
new Tag("addr:postcode","")]
|
new Tag("addr:postcode", ""),
|
||||||
),
|
]),
|
||||||
featureToMove.properties,
|
featureToMove.properties,
|
||||||
{
|
{
|
||||||
changeType: "relocated",
|
changeType: "relocated",
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default class QuestionBox extends VariableUiElement {
|
||||||
.filter((tr) => tr.question !== undefined)
|
.filter((tr) => tr.question !== undefined)
|
||||||
.filter((tr) => tr.question !== null)
|
.filter((tr) => tr.question !== null)
|
||||||
|
|
||||||
let focus: () => void = () => {};
|
let focus: () => void = () => {}
|
||||||
|
|
||||||
const tagRenderingQuestions = tagRenderings.map(
|
const tagRenderingQuestions = tagRenderings.map(
|
||||||
(tagRendering, i) =>
|
(tagRendering, i) =>
|
||||||
|
@ -53,7 +53,6 @@ export default class QuestionBox extends VariableUiElement {
|
||||||
skippedQuestions.data.push(i)
|
skippedQuestions.data.push(i)
|
||||||
skippedQuestions.ping()
|
skippedQuestions.ping()
|
||||||
focus()
|
focus()
|
||||||
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -141,8 +140,9 @@ export default class QuestionBox extends VariableUiElement {
|
||||||
|
|
||||||
this.skippedQuestions = skippedQuestions
|
this.skippedQuestions = skippedQuestions
|
||||||
this.restingQuestions = questionsToAsk
|
this.restingQuestions = questionsToAsk
|
||||||
focus = () => this.ScrollIntoView({
|
focus = () =>
|
||||||
onlyIfPartiallyHidden: true
|
this.ScrollIntoView({
|
||||||
})
|
onlyIfPartiallyHidden: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {Store, UIEventSource} from "../../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import {ShowDataLayerOptions} from "./ShowDataLayerOptions"
|
import { ShowDataLayerOptions } from "./ShowDataLayerOptions"
|
||||||
import {ElementStorage} from "../../Logic/ElementStorage"
|
import { ElementStorage } from "../../Logic/ElementStorage"
|
||||||
import RenderingMultiPlexerFeatureSource from "../../Logic/FeatureSource/Sources/RenderingMultiPlexerFeatureSource"
|
import RenderingMultiPlexerFeatureSource from "../../Logic/FeatureSource/Sources/RenderingMultiPlexerFeatureSource"
|
||||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen"
|
import ScrollableFullScreen from "../Base/ScrollableFullScreen"
|
||||||
import {LeafletMouseEvent} from "leaflet";
|
import { LeafletMouseEvent } from "leaflet"
|
||||||
import Hash from "../../Logic/Web/Hash";
|
import Hash from "../../Logic/Web/Hash"
|
||||||
/*
|
/*
|
||||||
// import 'leaflet-polylineoffset';
|
// import 'leaflet-polylineoffset';
|
||||||
We don't actually import it here. It is imported in the 'MinimapImplementation'-class, which'll result in a patched 'L' object.
|
We don't actually import it here. It is imported in the 'MinimapImplementation'-class, which'll result in a patched 'L' object.
|
||||||
|
@ -43,7 +43,10 @@ export default class ShowDataLayerImplementation {
|
||||||
* Note: the key of this dictionary is 'feature.properties.id+features.geometry.type' as one feature might have multiple presentations
|
* Note: the key of this dictionary is 'feature.properties.id+features.geometry.type' as one feature might have multiple presentations
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private readonly leafletLayersPerId = new Map<string, { feature: any; activateFunc: (event: LeafletMouseEvent) => void }>()
|
private readonly leafletLayersPerId = new Map<
|
||||||
|
string,
|
||||||
|
{ feature: any; activateFunc: (event: LeafletMouseEvent) => void }
|
||||||
|
>()
|
||||||
private readonly showDataLayerid: number
|
private readonly showDataLayerid: number
|
||||||
private readonly createPopup: (
|
private readonly createPopup: (
|
||||||
tags: UIEventSource<any>,
|
tags: UIEventSource<any>,
|
||||||
|
@ -324,18 +327,18 @@ export default class ShowDataLayerImplementation {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const key = feature.properties.id
|
const key = feature.properties.id
|
||||||
if(this.leafletLayersPerId.has(key)){
|
if (this.leafletLayersPerId.has(key)) {
|
||||||
const activate = this.leafletLayersPerId.get(key)
|
const activate = this.leafletLayersPerId.get(key)
|
||||||
leafletLayer.addEventListener('click', activate.activateFunc)
|
leafletLayer.addEventListener("click", activate.activateFunc)
|
||||||
if(Hash.hash.data === key ){
|
if (Hash.hash.data === key) {
|
||||||
activate.activateFunc(null)
|
activate.activateFunc(null)
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let infobox: ScrollableFullScreen = undefined
|
let infobox: ScrollableFullScreen = undefined
|
||||||
const self = this
|
const self = this
|
||||||
|
|
||||||
function activate (event: LeafletMouseEvent) {
|
function activate(event: LeafletMouseEvent) {
|
||||||
if (infobox === undefined) {
|
if (infobox === undefined) {
|
||||||
const tags =
|
const tags =
|
||||||
self.allElements?.getEventSourceById(key) ??
|
self.allElements?.getEventSourceById(key) ??
|
||||||
|
@ -348,25 +351,26 @@ export default class ShowDataLayerImplementation {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
infobox.Activate()
|
infobox.Activate()
|
||||||
self._selectedElement.setData( self.allElements.ContainingFeatures.get(feature.id) ?? feature )
|
self._selectedElement.setData(
|
||||||
|
self.allElements.ContainingFeatures.get(feature.id) ?? feature
|
||||||
|
)
|
||||||
event?.originalEvent?.preventDefault()
|
event?.originalEvent?.preventDefault()
|
||||||
event?.originalEvent?.stopPropagation()
|
event?.originalEvent?.stopPropagation()
|
||||||
event?.originalEvent?.stopImmediatePropagation()
|
event?.originalEvent?.stopImmediatePropagation()
|
||||||
if(event?.originalEvent){
|
if (event?.originalEvent) {
|
||||||
// This is a total workaround, as 'preventDefault' and everything above seems to be not working
|
// This is a total workaround, as 'preventDefault' and everything above seems to be not working
|
||||||
event.originalEvent["dismissed"] = true
|
event.originalEvent["dismissed"] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leafletLayer.addEventListener('click', activate)
|
leafletLayer.addEventListener("click", activate)
|
||||||
|
|
||||||
|
|
||||||
// Add the feature to the index to open the popup when needed
|
// Add the feature to the index to open the popup when needed
|
||||||
this.leafletLayersPerId.set(key, {
|
this.leafletLayersPerId.set(key, {
|
||||||
feature: feature,
|
feature: feature,
|
||||||
activateFunc: activate,
|
activateFunc: activate,
|
||||||
})
|
})
|
||||||
if(Hash.hash.data === key ){
|
if (Hash.hash.data === key) {
|
||||||
activate(null)
|
activate(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
70
Utils.ts
70
Utils.ts
|
@ -1,6 +1,5 @@
|
||||||
import * as colors from "./assets/colors.json"
|
import * as colors from "./assets/colors.json"
|
||||||
|
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
/**
|
/**
|
||||||
* In the 'deploy'-step, some code needs to be run by ts-node.
|
* In the 'deploy'-step, some code needs to be run by ts-node.
|
||||||
|
@ -139,7 +138,13 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
"false",
|
"false",
|
||||||
]
|
]
|
||||||
private static injectedDownloads = {}
|
private static injectedDownloads = {}
|
||||||
private static _download_cache = new Map<string, { promise: Promise<any | {error: string, url: string, statuscode?: number}>; timestamp: number }>()
|
private static _download_cache = new Map<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
promise: Promise<any | { error: string; url: string; statuscode?: number }>
|
||||||
|
timestamp: number
|
||||||
|
}
|
||||||
|
>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the arguments for special visualisations
|
* Parses the arguments for special visualisations
|
||||||
|
@ -570,7 +575,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
object[head] = leaf.map((o) => replaceLeaf(o, travelledPath))
|
object[head] = leaf.map((o) => replaceLeaf(o, travelledPath))
|
||||||
} else {
|
} else {
|
||||||
object[head] = replaceLeaf(leaf, travelledPath)
|
object[head] = replaceLeaf(leaf, travelledPath)
|
||||||
if(object[head] === undefined){
|
if (object[head] === undefined) {
|
||||||
delete object[head]
|
delete object[head]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -803,7 +808,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
|
|
||||||
public static async download(url: string, headers?: any): Promise<string | undefined> {
|
public static async download(url: string, headers?: any): Promise<string | undefined> {
|
||||||
const result = await Utils.downloadAdvanced(url, headers)
|
const result = await Utils.downloadAdvanced(url, headers)
|
||||||
if(result["error"] !== undefined){
|
if (result["error"] !== undefined) {
|
||||||
throw result["error"]
|
throw result["error"]
|
||||||
}
|
}
|
||||||
return result["content"]
|
return result["content"]
|
||||||
|
@ -816,8 +821,12 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
*/
|
*/
|
||||||
public static downloadAdvanced(
|
public static downloadAdvanced(
|
||||||
url: string,
|
url: string,
|
||||||
headers?: any,
|
headers?: any
|
||||||
): Promise<{ content: string } | { redirect: string } | { error: string,url: string, statuscode?: number}> {
|
): Promise<
|
||||||
|
| { content: string }
|
||||||
|
| { redirect: string }
|
||||||
|
| { error: string; url: string; statuscode?: number }
|
||||||
|
> {
|
||||||
if (this.externalDownloadFunction !== undefined) {
|
if (this.externalDownloadFunction !== undefined) {
|
||||||
return this.externalDownloadFunction(url, headers)
|
return this.externalDownloadFunction(url, headers)
|
||||||
}
|
}
|
||||||
|
@ -831,9 +840,13 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
} else if (xhr.status === 302) {
|
} else if (xhr.status === 302) {
|
||||||
resolve({ redirect: xhr.getResponseHeader("location") })
|
resolve({ redirect: xhr.getResponseHeader("location") })
|
||||||
} else if (xhr.status === 509 || xhr.status === 429) {
|
} else if (xhr.status === 509 || xhr.status === 429) {
|
||||||
resolve ({error: "rate limited", url, statuscode: xhr.status})
|
resolve({ error: "rate limited", url, statuscode: xhr.status })
|
||||||
} else {
|
} else {
|
||||||
resolve ({error: "other error: "+xhr.statusText, url, statuscode: xhr.status})
|
resolve({
|
||||||
|
error: "other error: " + xhr.statusText,
|
||||||
|
url,
|
||||||
|
statuscode: xhr.status,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xhr.open("GET", url)
|
xhr.open("GET", url)
|
||||||
|
@ -878,7 +891,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
headers?: any
|
headers?: any
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const result = await Utils.downloadJsonAdvanced(url, headers)
|
const result = await Utils.downloadJsonAdvanced(url, headers)
|
||||||
if(result["content"]){
|
if (result["content"]) {
|
||||||
return result["content"]
|
return result["content"]
|
||||||
}
|
}
|
||||||
throw result["error"]
|
throw result["error"]
|
||||||
|
@ -888,56 +901,58 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
url: string,
|
url: string,
|
||||||
maxCacheTimeMs: number,
|
maxCacheTimeMs: number,
|
||||||
headers?: any
|
headers?: any
|
||||||
): Promise<any | {error: string, url: string, statuscode?: number}> {
|
): Promise<any | { error: string; url: string; statuscode?: number }> {
|
||||||
const cached = Utils._download_cache.get(url)
|
const cached = Utils._download_cache.get(url)
|
||||||
if (cached !== undefined) {
|
if (cached !== undefined) {
|
||||||
if (new Date().getTime() - cached.timestamp <= maxCacheTimeMs) {
|
if (new Date().getTime() - cached.timestamp <= maxCacheTimeMs) {
|
||||||
return cached.promise
|
return cached.promise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const promise = /*NO AWAIT as we work with the promise directly */ Utils.downloadJsonAdvanced(
|
const promise =
|
||||||
url,
|
/*NO AWAIT as we work with the promise directly */ Utils.downloadJsonAdvanced(
|
||||||
headers
|
url,
|
||||||
)
|
headers
|
||||||
|
)
|
||||||
Utils._download_cache.set(url, { promise, timestamp: new Date().getTime() })
|
Utils._download_cache.set(url, { promise, timestamp: new Date().getTime() })
|
||||||
return await promise
|
return await promise
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async downloadJson(url: string, headers?: any): Promise<any> {
|
public static async downloadJson(url: string, headers?: any): Promise<any> {
|
||||||
const result = await Utils.downloadJsonAdvanced(url, headers)
|
const result = await Utils.downloadJsonAdvanced(url, headers)
|
||||||
if(result["content"]){
|
if (result["content"]) {
|
||||||
return result["content"]
|
return result["content"]
|
||||||
}
|
}
|
||||||
throw result["error"]
|
throw result["error"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async downloadJsonAdvanced(
|
||||||
public static async downloadJsonAdvanced(url: string, headers?: any): Promise<{content: any} | {error: string, url: string, statuscode?: number}> {
|
url: string,
|
||||||
|
headers?: any
|
||||||
|
): Promise<{ content: any } | { error: string; url: string; statuscode?: number }> {
|
||||||
const injected = Utils.injectedDownloads[url]
|
const injected = Utils.injectedDownloads[url]
|
||||||
if (injected !== undefined) {
|
if (injected !== undefined) {
|
||||||
console.log("Using injected resource for test for URL", url)
|
console.log("Using injected resource for test for URL", url)
|
||||||
return new Promise((resolve, _) => resolve({content: injected}))
|
return new Promise((resolve, _) => resolve({ content: injected }))
|
||||||
}
|
}
|
||||||
const result = await Utils.downloadAdvanced(
|
const result = await Utils.downloadAdvanced(
|
||||||
url,
|
url,
|
||||||
Utils.Merge({ accept: "application/json" }, headers ?? {})
|
Utils.Merge({ accept: "application/json" }, headers ?? {})
|
||||||
)
|
)
|
||||||
if(result["error"] !== undefined){
|
if (result["error"] !== undefined) {
|
||||||
return <{error: string, url: string, statuscode?: number}> result
|
return <{ error: string; url: string; statuscode?: number }>result
|
||||||
}
|
}
|
||||||
const data = result["content"]
|
const data = result["content"]
|
||||||
try {
|
try {
|
||||||
if (typeof data === "string") {
|
if (typeof data === "string") {
|
||||||
return {content: JSON.parse(data)}
|
return { content: JSON.parse(data) }
|
||||||
}
|
}
|
||||||
return {"content": data}
|
return { content: data }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Could not parse ", data, "due to", e, "\n", e.stack)
|
console.error("Could not parse ", data, "due to", e, "\n", e.stack)
|
||||||
return {error: "malformed", url}
|
return { error: "malformed", url }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers a 'download file' popup which will download the contents
|
* Triggers a 'download file' popup which will download the contents
|
||||||
*/
|
*/
|
||||||
|
@ -1261,16 +1276,15 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
public static findParentWithScrolling(element: HTMLElement): HTMLElement {
|
public static findParentWithScrolling(element: HTMLElement): HTMLElement {
|
||||||
// Check if the element itself has scrolling
|
// Check if the element itself has scrolling
|
||||||
if (element.scrollHeight > element.clientHeight) {
|
if (element.scrollHeight > element.clientHeight) {
|
||||||
return element;
|
return element
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the element does not have scrolling, check if it has a parent element
|
// If the element does not have scrolling, check if it has a parent element
|
||||||
if (!element.parentElement) {
|
if (!element.parentElement) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the element has a parent, repeat the process for the parent element
|
// If the element has a parent, repeat the process for the parent element
|
||||||
return Utils.findParentWithScrolling(element.parentElement);
|
return Utils.findParentWithScrolling(element.parentElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue