Merge branch 'develop' of github.com:pietervdvn/MapComplete into develop
This commit is contained in:
commit
9623afeec9
46 changed files with 1300 additions and 1032 deletions
|
@ -23,11 +23,11 @@ export default class AvailableBaseLayers {
|
||||||
private static implementation: AvailableBaseLayersObj
|
private static implementation: AvailableBaseLayersObj
|
||||||
|
|
||||||
static AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
|
static AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
|
||||||
return AvailableBaseLayers.implementation.AvailableLayersAt(location);
|
return AvailableBaseLayers.implementation?.AvailableLayersAt(location) ?? new UIEventSource<BaseLayer[]>([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
|
static SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
|
||||||
return AvailableBaseLayers.implementation.SelectBestLayerAccordingTo(location, preferedCategory);
|
return AvailableBaseLayers.implementation?.SelectBestLayerAccordingTo(location, preferedCategory) ?? new UIEventSource<BaseLayer>(undefined);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {UIEventSource} from "../UIEventSource";
|
||||||
import BaseLayer from "../../Models/BaseLayer";
|
import BaseLayer from "../../Models/BaseLayer";
|
||||||
import AvailableBaseLayers from "./AvailableBaseLayers";
|
import AvailableBaseLayers from "./AvailableBaseLayers";
|
||||||
import Loc from "../../Models/Loc";
|
import Loc from "../../Models/Loc";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current background layer to a layer that is actually available
|
* Sets the current background layer to a layer that is actually available
|
||||||
|
@ -12,6 +13,11 @@ export default class BackgroundLayerResetter {
|
||||||
location: UIEventSource<Loc>,
|
location: UIEventSource<Loc>,
|
||||||
availableLayers: UIEventSource<BaseLayer[]>,
|
availableLayers: UIEventSource<BaseLayer[]>,
|
||||||
defaultLayerId: string = undefined) {
|
defaultLayerId: string = undefined) {
|
||||||
|
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
defaultLayerId = defaultLayerId ?? AvailableBaseLayers.osmCarto.id;
|
defaultLayerId = defaultLayerId ?? AvailableBaseLayers.osmCarto.id;
|
||||||
|
|
||||||
// Change the baselayer back to OSM if we go out of the current range of the layer
|
// Change the baselayer back to OSM if we go out of the current range of the layer
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
|
|
||||||
|
|
||||||
private readonly retries: UIEventSource<number> = new UIEventSource<number>(0);
|
private readonly retries: UIEventSource<number> = new UIEventSource<number>(0);
|
||||||
|
|
||||||
private readonly state: {
|
private readonly state: {
|
||||||
readonly locationControl: UIEventSource<Loc>,
|
readonly locationControl: UIEventSource<Loc>,
|
||||||
readonly layoutToUse: LayoutConfig,
|
readonly layoutToUse: LayoutConfig,
|
||||||
|
@ -39,6 +39,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
}
|
}
|
||||||
private readonly _isActive: UIEventSource<boolean>;
|
private readonly _isActive: UIEventSource<boolean>;
|
||||||
private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void;
|
private readonly onBboxLoaded: (bbox: BBox, date: Date, layers: LayerConfig[], zoomlevel: number) => void;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
state: {
|
state: {
|
||||||
readonly locationControl: UIEventSource<Loc>,
|
readonly locationControl: UIEventSource<Loc>,
|
||||||
|
@ -90,7 +91,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
}
|
}
|
||||||
const self = this;
|
const self = this;
|
||||||
this.updateAsync(paddedZoomLevel).then(bboxDate => {
|
this.updateAsync(paddedZoomLevel).then(bboxDate => {
|
||||||
if(bboxDate === undefined || self.onBboxLoaded === undefined){
|
if (bboxDate === undefined || self.onBboxLoaded === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [bbox, date, layers] = bboxDate
|
const [bbox, date, layers] = bboxDate
|
||||||
|
@ -109,41 +110,43 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(padToZoomLevel);
|
|
||||||
|
|
||||||
if (bounds === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
|
|
||||||
const layersToDownload = []
|
|
||||||
for (const layer of this.state.layoutToUse.layers) {
|
|
||||||
|
|
||||||
if (typeof (layer) === "string") {
|
|
||||||
throw "A layer was not expanded!"
|
|
||||||
}
|
|
||||||
if(this.state.locationControl.data.zoom < layer.minzoom){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (layer.doNotDownload) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (layer.source.geojsonSource !== undefined) {
|
|
||||||
// Not our responsibility to download this layer!
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
layersToDownload.push(layer)
|
|
||||||
}
|
|
||||||
|
|
||||||
let data: any = undefined
|
let data: any = undefined
|
||||||
let date: Date = undefined
|
let date: Date = undefined
|
||||||
const overpassUrls = self.state.overpassUrl.data
|
|
||||||
let lastUsed = 0;
|
let lastUsed = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const layersToDownload = []
|
||||||
|
for (const layer of this.state.layoutToUse.layers) {
|
||||||
|
|
||||||
|
if (typeof (layer) === "string") {
|
||||||
|
throw "A layer was not expanded!"
|
||||||
|
}
|
||||||
|
if (this.state.locationControl.data.zoom < layer.minzoom) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (layer.doNotDownload) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (layer.source.geojsonSource !== undefined) {
|
||||||
|
// Not our responsibility to download this layer!
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
layersToDownload.push(layer)
|
||||||
|
}
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
const overpassUrls = self.state.overpassUrl.data
|
||||||
|
let bounds : BBox
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(padToZoomLevel);
|
||||||
|
|
||||||
|
if (bounds === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const overpass = this.GetFilter(overpassUrls[lastUsed], layersToDownload);
|
const overpass = this.GetFilter(overpassUrls[lastUsed], layersToDownload);
|
||||||
|
|
||||||
if (overpass === undefined) {
|
if (overpass === undefined) {
|
||||||
|
@ -175,16 +178,21 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (data === undefined);
|
} while (data === undefined && this._isActive.data);
|
||||||
|
|
||||||
self.retries.setData(0);
|
|
||||||
try {
|
try {
|
||||||
|
if(data === undefined){
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
data.features.forEach(feature => SimpleMetaTagger.objectMetaInfo.applyMetaTagsOnFeature(feature, date, undefined));
|
data.features.forEach(feature => SimpleMetaTagger.objectMetaInfo.applyMetaTagsOnFeature(feature, date, undefined));
|
||||||
self.features.setData(data.features.map(f => ({feature: f, freshness: date})));
|
self.features.setData(data.features.map(f => ({feature: f, freshness: date})));
|
||||||
return [bounds, date, layersToDownload];
|
return [bounds, date, layersToDownload];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Got the overpass response, but could not process it: ", e, e.stack)
|
console.error("Got the overpass response, but could not process it: ", e, e.stack)
|
||||||
|
return undefined
|
||||||
} finally {
|
} finally {
|
||||||
|
self.retries.setData(0);
|
||||||
self.runningQuery.setData(false);
|
self.runningQuery.setData(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {Changes} from "../Osm/Changes";
|
import {Changes} from "../Osm/Changes";
|
||||||
import Constants from "../../Models/Constants";
|
import Constants from "../../Models/Constants";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export default class PendingChangesUploader {
|
export default class PendingChangesUploader {
|
||||||
|
|
||||||
|
@ -30,6 +31,10 @@ export default class PendingChangesUploader {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('mouseout', e => {
|
document.addEventListener('mouseout', e => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!e.toElement && !e.relatedTarget) {
|
if (!e.toElement && !e.relatedTarget) {
|
||||||
|
|
|
@ -9,6 +9,13 @@ import {OsmConnection} from "../Osm/OsmConnection";
|
||||||
|
|
||||||
export default class SelectedElementTagsUpdater {
|
export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
|
private static readonly metatags = new Set(["timestamp",
|
||||||
|
"version",
|
||||||
|
"changeset",
|
||||||
|
"user",
|
||||||
|
"uid",
|
||||||
|
"id"] )
|
||||||
|
|
||||||
constructor(state: {
|
constructor(state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
|
@ -18,15 +25,15 @@ export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
|
|
||||||
state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => {
|
state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => {
|
||||||
if(isLoggedIn){
|
if (isLoggedIn) {
|
||||||
SelectedElementTagsUpdater.installCallback(state)
|
SelectedElementTagsUpdater.installCallback(state)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static installCallback(state: {
|
public static installCallback(state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
changes: Changes,
|
changes: Changes,
|
||||||
|
@ -36,80 +43,99 @@ export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
state.selectedElement.addCallbackAndRunD(s => {
|
state.selectedElement.addCallbackAndRunD(s => {
|
||||||
let id = s.properties?.id
|
let id = s.properties?.id
|
||||||
|
|
||||||
const backendUrl = state.osmConnection._oauth_config.url
|
const backendUrl = state.osmConnection._oauth_config.url
|
||||||
if(id.startsWith(backendUrl)){
|
if (id.startsWith(backendUrl)) {
|
||||||
id = id.substring(backendUrl.length)
|
id = id.substring(backendUrl.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(id.startsWith("way") || id.startsWith("node") || id.startsWith("relation"))){
|
if (!(id.startsWith("way") || id.startsWith("node") || id.startsWith("relation"))) {
|
||||||
// This object is _not_ from OSM, so we skip it!
|
// This object is _not_ from OSM, so we skip it!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id.indexOf("-") >= 0){
|
if (id.indexOf("-") >= 0) {
|
||||||
// This is a new object
|
// This is a new object
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
OsmObject.DownloadPropertiesOf(id).then(latestTags => {
|
||||||
OsmObject.DownloadPropertiesOf(id).then(tags => {
|
SelectedElementTagsUpdater.applyUpdate(state, latestTags, id)
|
||||||
SelectedElementTagsUpdater.applyUpdate(state, tags, id)
|
|
||||||
}).catch(e => {
|
|
||||||
console.error("Could not update tags of ", id, "due to", e)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static applyUpdate(state: {
|
public static applyUpdate(state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
changes: Changes,
|
changes: Changes,
|
||||||
osmConnection: OsmConnection
|
osmConnection: OsmConnection
|
||||||
}, latestTags: any, id: string
|
}, latestTags: any, id: string
|
||||||
) {
|
) {
|
||||||
const pendingChanges = state.changes.pendingChanges.data
|
try {
|
||||||
.filter(change => change.type +"/"+ change.id === id)
|
|
||||||
.filter(change => change.tags !== undefined);
|
const pendingChanges = state.changes.pendingChanges.data
|
||||||
|
.filter(change => change.type + "/" + change.id === id)
|
||||||
for (const pendingChange of pendingChanges) {
|
.filter(change => change.tags !== undefined);
|
||||||
const tagChanges = pendingChange.tags;
|
|
||||||
for (const tagChange of tagChanges) {
|
for (const pendingChange of pendingChanges) {
|
||||||
const key = tagChange.k
|
const tagChanges = pendingChange.tags;
|
||||||
const v = tagChange.v
|
for (const tagChange of tagChanges) {
|
||||||
if (v === undefined || v === "") {
|
const key = tagChange.k
|
||||||
delete latestTags[key]
|
const v = tagChange.v
|
||||||
} else {
|
if (v === undefined || v === "") {
|
||||||
latestTags[key] = v
|
delete latestTags[key]
|
||||||
|
} else {
|
||||||
|
latestTags[key] = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// With the changes applied, we merge them onto the upstream object
|
// With the changes applied, we merge them onto the upstream object
|
||||||
let somethingChanged = false;
|
let somethingChanged = false;
|
||||||
const currentTagsSource = state.allElements.getEventSourceById(id);
|
const currentTagsSource = state.allElements.getEventSourceById(id);
|
||||||
const currentTags = currentTagsSource.data
|
const currentTags = currentTagsSource.data
|
||||||
for (const key in latestTags) {
|
for (const key in latestTags) {
|
||||||
let osmValue = latestTags[key]
|
let osmValue = latestTags[key]
|
||||||
|
|
||||||
if(typeof osmValue === "number"){
|
|
||||||
osmValue = ""+osmValue
|
|
||||||
}
|
|
||||||
|
|
||||||
const localValue = currentTags[key]
|
|
||||||
if (localValue !== osmValue) {
|
|
||||||
console.log("Local value for ", key ,":", localValue, "upstream", osmValue)
|
|
||||||
somethingChanged = true;
|
|
||||||
currentTags[key] = osmValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (somethingChanged) {
|
|
||||||
console.log("Detected upstream changes to the object when opening it, updating...")
|
|
||||||
currentTagsSource.ping()
|
|
||||||
}else{
|
|
||||||
console.debug("Fetched latest tags for ", id, "but detected no changes")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (typeof osmValue === "number") {
|
||||||
|
osmValue = "" + osmValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const localValue = currentTags[key]
|
||||||
|
if (localValue !== osmValue) {
|
||||||
|
console.log("Local value for ", key, ":", localValue, "upstream", osmValue)
|
||||||
|
somethingChanged = true;
|
||||||
|
currentTags[key] = osmValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const currentKey in currentTags) {
|
||||||
|
if (currentKey.startsWith("_")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if(this.metatags.has(currentKey)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (currentKey in latestTags) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
console.log("Removing key as deleted upstream", currentKey)
|
||||||
|
delete currentTags[currentKey]
|
||||||
|
somethingChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (somethingChanged) {
|
||||||
|
console.log("Detected upstream changes to the object when opening it, updating...")
|
||||||
|
currentTagsSource.ping()
|
||||||
|
} else {
|
||||||
|
console.debug("Fetched latest tags for ", id, "but detected no changes")
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Updating the tags of selected element ", id, "failed due to", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,20 @@ import {OsmObject} from "../Osm/OsmObject";
|
||||||
import Loc from "../../Models/Loc";
|
import Loc from "../../Models/Loc";
|
||||||
import {ElementStorage} from "../ElementStorage";
|
import {ElementStorage} from "../ElementStorage";
|
||||||
import FeaturePipeline from "../FeatureSource/FeaturePipeline";
|
import FeaturePipeline from "../FeatureSource/FeaturePipeline";
|
||||||
|
import {GeoOperations} from "../GeoOperations";
|
||||||
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure the hash shows the selected element and vice-versa.
|
* Makes sure the hash shows the selected element and vice-versa.
|
||||||
*/
|
*/
|
||||||
export default class SelectedFeatureHandler {
|
export default class SelectedFeatureHandler {
|
||||||
private static readonly _no_trigger_on = new Set(["welcome", "copyright", "layers", "new", "", undefined])
|
private static readonly _no_trigger_on = new Set(["welcome", "copyright", "layers", "new", "", undefined])
|
||||||
hash: UIEventSource<string>;
|
private readonly hash: UIEventSource<string>;
|
||||||
private readonly state: {
|
private readonly state: {
|
||||||
selectedElement: UIEventSource<any>
|
selectedElement: UIEventSource<any>,
|
||||||
|
allElements: ElementStorage,
|
||||||
|
locationControl: UIEventSource<Loc>,
|
||||||
|
layoutToUse: LayoutConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -19,7 +24,9 @@ export default class SelectedFeatureHandler {
|
||||||
state: {
|
state: {
|
||||||
selectedElement: UIEventSource<any>,
|
selectedElement: UIEventSource<any>,
|
||||||
allElements: ElementStorage,
|
allElements: ElementStorage,
|
||||||
featurePipeline: FeaturePipeline
|
featurePipeline: FeaturePipeline,
|
||||||
|
locationControl: UIEventSource<Loc>,
|
||||||
|
layoutToUse: LayoutConfig
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
|
@ -27,30 +34,9 @@ export default class SelectedFeatureHandler {
|
||||||
|
|
||||||
|
|
||||||
// If the hash changes, set the selected element correctly
|
// If the hash changes, set the selected element correctly
|
||||||
function setSelectedElementFromHash(h){
|
|
||||||
if (h === undefined || h === "") {
|
|
||||||
// Hash has been cleared - we clear the selected element
|
|
||||||
state.selectedElement.setData(undefined);
|
|
||||||
}else{
|
|
||||||
// we search the element to select
|
|
||||||
const feature = state.allElements.ContainingFeatures.get(h)
|
|
||||||
if(feature === undefined){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const currentlySeleced = state.selectedElement.data
|
|
||||||
if(currentlySeleced === undefined){
|
|
||||||
state.selectedElement.setData(feature)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(currentlySeleced.properties?.id === feature.properties.id){
|
|
||||||
// We already have the right feature
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.selectedElement.setData(feature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hash.addCallback(setSelectedElementFromHash)
|
const self = this;
|
||||||
|
hash.addCallback(() => self.setSelectedElementFromHash())
|
||||||
|
|
||||||
|
|
||||||
// IF the selected element changes, set the hash correctly
|
// IF the selected element changes, set the hash correctly
|
||||||
|
@ -66,41 +52,103 @@ export default class SelectedFeatureHandler {
|
||||||
hash.setData(h)
|
hash.setData(h)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
state.featurePipeline.newDataLoadedSignal.addCallbackAndRunD(_ => {
|
state.featurePipeline?.newDataLoadedSignal?.addCallbackAndRunD(_ => {
|
||||||
// New data was loaded. In initial startup, the hash might be set (via the URL) but might not be selected yet
|
// New data was loaded. In initial startup, the hash might be set (via the URL) but might not be selected yet
|
||||||
if(hash.data === undefined || SelectedFeatureHandler._no_trigger_on.has(hash.data)){
|
if (hash.data === undefined || SelectedFeatureHandler._no_trigger_on.has(hash.data)) {
|
||||||
// This is an invalid hash anyway
|
// This is an invalid hash anyway
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(state.selectedElement.data !== undefined){
|
if (state.selectedElement.data !== undefined) {
|
||||||
// We already have something selected
|
// We already have something selected
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSelectedElementFromHash(hash.data)
|
self.setSelectedElementFromHash()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
this.initialLoad()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On startup: check if the hash is loaded and eventually zoom to it
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private initialLoad() {
|
||||||
|
const hash = this.hash.data
|
||||||
|
if (hash === undefined || hash === "" || hash.indexOf("-") >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SelectedFeatureHandler._no_trigger_on.has(hash)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OsmObject.DownloadObjectAsync(hash).then(obj => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
console.log("Downloaded selected object from OSM-API for initial load: ", hash)
|
||||||
|
const geojson = obj.asGeoJson()
|
||||||
|
this.state.allElements.addOrGetElement(geojson)
|
||||||
|
this.state.selectedElement.setData(geojson)
|
||||||
|
this.zoomToSelectedFeature()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a feature is selected via the hash, zoom there
|
private setSelectedElementFromHash() {
|
||||||
public zoomToSelectedFeature(location: UIEventSource<Loc>) {
|
const state = this.state
|
||||||
const hash = this.hash.data;
|
const h = this.hash.data
|
||||||
if (hash === undefined || SelectedFeatureHandler._no_trigger_on.has(hash)) {
|
if (h === undefined || h === "") {
|
||||||
return; // No valid feature selected
|
// Hash has been cleared - we clear the selected element
|
||||||
}
|
state.selectedElement.setData(undefined);
|
||||||
// We should have a valid osm-ID and zoom to it... But we wrap it in try-catch to be sure
|
} else {
|
||||||
try {
|
// we search the element to select
|
||||||
|
const feature = state.allElements.ContainingFeatures.get(h)
|
||||||
OsmObject.DownloadObject(hash).addCallbackAndRunD(element => {
|
if (feature === undefined) {
|
||||||
const centerpoint = element.centerpoint();
|
return;
|
||||||
console.log("Zooming to location for select point: ", centerpoint)
|
}
|
||||||
location.data.lat = centerpoint[0]
|
const currentlySeleced = state.selectedElement.data
|
||||||
location.data.lon = centerpoint[1]
|
if (currentlySeleced === undefined) {
|
||||||
location.ping();
|
state.selectedElement.setData(feature)
|
||||||
})
|
return;
|
||||||
} catch (e) {
|
}
|
||||||
console.error("Could not download OSM-object with id", hash, " - probably a weird hash")
|
if (currentlySeleced.properties?.id === feature.properties.id) {
|
||||||
|
// We already have the right feature
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.selectedElement.setData(feature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a feature is selected via the hash, zoom there
|
||||||
|
private zoomToSelectedFeature() {
|
||||||
|
|
||||||
|
const selected = this.state.selectedElement.data
|
||||||
|
if(selected === undefined){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const centerpoint= GeoOperations.centerpointCoordinates(selected)
|
||||||
|
const location = this.state.locationControl;
|
||||||
|
location.data.lon = centerpoint[0]
|
||||||
|
location.data.lat = centerpoint[1]
|
||||||
|
|
||||||
|
const minZoom = Math.max(14, ...(this.state.layoutToUse?.layers?.map(l => l.minzoomVisible) ?? []))
|
||||||
|
if(location.data.zoom < minZoom ){
|
||||||
|
location.data.zoom = minZoom
|
||||||
|
}
|
||||||
|
|
||||||
|
location.ping();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import TagRenderingAnswer from "../../UI/Popup/TagRenderingAnswer";
|
||||||
import Combine from "../../UI/Base/Combine";
|
import Combine from "../../UI/Base/Combine";
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
import {ElementStorage} from "../ElementStorage";
|
import {ElementStorage} from "../ElementStorage";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export default class TitleHandler {
|
export default class TitleHandler {
|
||||||
constructor(state : {
|
constructor(state : {
|
||||||
|
@ -38,6 +39,9 @@ export default class TitleHandler {
|
||||||
|
|
||||||
|
|
||||||
currentTitle.addCallbackAndRunD(title => {
|
currentTitle.addCallbackAndRunD(title => {
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return
|
||||||
|
}
|
||||||
document.title = title
|
document.title = title
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import State from "../State";
|
||||||
import BaseUIElement from "../UI/BaseUIElement";
|
import BaseUIElement from "../UI/BaseUIElement";
|
||||||
import List from "../UI/Base/List";
|
import List from "../UI/Base/List";
|
||||||
import Title from "../UI/Base/Title";
|
import Title from "../UI/Base/Title";
|
||||||
import {UIEventSourceTools} from "./UIEventSource";
|
|
||||||
import AspectedRouting from "./Osm/aspectedRouting";
|
|
||||||
import {BBox} from "./BBox";
|
import {BBox} from "./BBox";
|
||||||
|
|
||||||
export interface ExtraFuncParams {
|
export interface ExtraFuncParams {
|
||||||
|
|
|
@ -21,11 +21,13 @@ export default class AllImageProviders {
|
||||||
)
|
)
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
public static defaultKeys = [].concat(AllImageProviders.ImageAttributionSource.map(provider => provider.defaultKeyPrefixes))
|
||||||
|
|
||||||
|
|
||||||
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
|
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
|
||||||
|
|
||||||
public static LoadImagesFor(tags: UIEventSource<any>, tagKey?: string): UIEventSource<ProvidedImage[]> {
|
public static LoadImagesFor(tags: UIEventSource<any>, tagKey?: string[]): UIEventSource<ProvidedImage[]> {
|
||||||
if (tags.data.id === undefined) {
|
if (tags.data.id === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +46,7 @@ export default class AllImageProviders {
|
||||||
|
|
||||||
let prefixes = imageProvider.defaultKeyPrefixes
|
let prefixes = imageProvider.defaultKeyPrefixes
|
||||||
if(tagKey !== undefined){
|
if(tagKey !== undefined){
|
||||||
prefixes = [...prefixes, tagKey]
|
prefixes = tagKey
|
||||||
}
|
}
|
||||||
|
|
||||||
const singleSource = imageProvider.GetRelevantUrls(tags, {
|
const singleSource = imageProvider.GetRelevantUrls(tags, {
|
||||||
|
|
|
@ -27,7 +27,8 @@ export default class ImgurUploader {
|
||||||
files,
|
files,
|
||||||
function (url) {
|
function (url) {
|
||||||
console.log("File saved at", url);
|
console.log("File saved at", url);
|
||||||
self.success.setData([...self.success.data, url]);
|
self.success.data.push(url)
|
||||||
|
self.success.ping();
|
||||||
self._handleSuccessUrl(url);
|
self._handleSuccessUrl(url);
|
||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import ImageProvider, {ProvidedImage} from "./ImageProvider";
|
import ImageProvider, {ProvidedImage} from "./ImageProvider";
|
||||||
import BaseUIElement from "../../UI/BaseUIElement";
|
import BaseUIElement from "../../UI/BaseUIElement";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg";
|
||||||
import {Utils} from "../../Utils";
|
import {Utils} from "../../Utils";
|
||||||
import {LicenseInfo} from "./LicenseInfo";
|
import {LicenseInfo} from "./LicenseInfo";
|
||||||
import Constants from "../../Models/Constants";
|
import Constants from "../../Models/Constants";
|
||||||
import {fail} from "assert";
|
|
||||||
|
|
||||||
export class Mapillary extends ImageProvider {
|
export class Mapillary extends ImageProvider {
|
||||||
|
|
||||||
|
@ -13,7 +11,7 @@ export class Mapillary extends ImageProvider {
|
||||||
|
|
||||||
public static readonly singleton = new Mapillary();
|
public static readonly singleton = new Mapillary();
|
||||||
private static readonly valuePrefix = "https://a.mapillary.com"
|
private static readonly valuePrefix = "https://a.mapillary.com"
|
||||||
public static readonly valuePrefixes = [Mapillary.valuePrefix, "http://mapillary.com","https://mapillary.com"]
|
public static readonly valuePrefixes = [Mapillary.valuePrefix, "http://mapillary.com","https://mapillary.com","http://www.mapillary.com","https://www.mapillary.com"]
|
||||||
|
|
||||||
private static ExtractKeyFromURL(value: string, failIfNoMath = false): {
|
private static ExtractKeyFromURL(value: string, failIfNoMath = false): {
|
||||||
key: string,
|
key: string,
|
||||||
|
|
|
@ -97,6 +97,7 @@ export class Changes {
|
||||||
console.log("Is already uploading... Abort")
|
console.log("Is already uploading... Abort")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log("Uploading changes due to: ", flushreason)
|
||||||
this.isUploading.setData(true)
|
this.isUploading.setData(true)
|
||||||
|
|
||||||
this.flushChangesAsync()
|
this.flushChangesAsync()
|
||||||
|
@ -287,7 +288,7 @@ export class Changes {
|
||||||
v = undefined;
|
v = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldV = obj.type[k]
|
const oldV = obj.tags[k]
|
||||||
if (oldV === v) {
|
if (oldV === v) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import Svg from "../../Svg";
|
||||||
import Img from "../../UI/Base/Img";
|
import Img from "../../UI/Base/Img";
|
||||||
import {Utils} from "../../Utils";
|
import {Utils} from "../../Utils";
|
||||||
import {OsmObject} from "./OsmObject";
|
import {OsmObject} from "./OsmObject";
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
|
||||||
import {Changes} from "./Changes";
|
import {Changes} from "./Changes";
|
||||||
|
|
||||||
export default class UserDetails {
|
export default class UserDetails {
|
||||||
|
@ -97,7 +96,6 @@ export class OsmConnection {
|
||||||
self.AttemptLogin()
|
self.AttemptLogin()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.isLoggedIn.addCallbackAndRunD(li => console.log("User is logged in!", li))
|
|
||||||
this._dryRun = options.dryRun;
|
this._dryRun = options.dryRun;
|
||||||
|
|
||||||
this.updateAuthObject();
|
this.updateAuthObject();
|
||||||
|
|
|
@ -263,7 +263,7 @@ export abstract class OsmObject {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const v = this.tags[key];
|
const v = this.tags[key];
|
||||||
if (v !== "") {
|
if (v !== "" && v !== undefined) {
|
||||||
tags += ' <tag k="' + Utils.EncodeXmlValue(key) + '" v="' + Utils.EncodeXmlValue(this.tags[key]) + '"/>\n'
|
tags += ' <tag k="' + Utils.EncodeXmlValue(key) + '" v="' + Utils.EncodeXmlValue(this.tags[key]) + '"/>\n'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
import {QueryParameters} from "../Web/QueryParameters";
|
import {QueryParameters} from "../Web/QueryParameters";
|
||||||
import Constants from "../../Models/Constants";
|
import Constants from "../../Models/Constants";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export default class FeatureSwitchState {
|
export default class FeatureSwitchState {
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ export default class FeatureSwitchState {
|
||||||
|
|
||||||
|
|
||||||
let testingDefaultValue = false;
|
let testingDefaultValue = false;
|
||||||
if (this.featureSwitchApiURL.data !== "osm-test" &&
|
if (this.featureSwitchApiURL.data !== "osm-test" && !Utils.runningFromConsole &&
|
||||||
(location.hostname === "localhost" || location.hostname === "127.0.0.1")) {
|
(location.hostname === "localhost" || location.hostname === "127.0.0.1")) {
|
||||||
testingDefaultValue = true
|
testingDefaultValue = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,6 +286,9 @@ export class UIEventSource<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public stabilized(millisToStabilize): UIEventSource<T> {
|
public stabilized(millisToStabilize): UIEventSource<T> {
|
||||||
|
if(Utils.runningFromConsole){
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
const newSource = new UIEventSource<T>(this.data);
|
const newSource = new UIEventSource<T>(this.data);
|
||||||
|
|
||||||
|
@ -334,21 +337,4 @@ export class UIEventSource<T> {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export class UIEventSourceTools {
|
|
||||||
|
|
||||||
private static readonly _download_cache = new Map<string, UIEventSource<any>>()
|
|
||||||
|
|
||||||
public static downloadJsonCached(url: string): UIEventSource<any> {
|
|
||||||
const cached = UIEventSourceTools._download_cache.get(url)
|
|
||||||
if (cached !== undefined) {
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
const src = new UIEventSource<any>(undefined)
|
|
||||||
UIEventSourceTools._download_cache.set(url, src)
|
|
||||||
Utils.downloadJson(url).then(r => src.setData(r))
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ import {Utils} from "../Utils";
|
||||||
|
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
|
|
||||||
public static vNumber = "0.11.0-rc-1";
|
public static vNumber = "0.11.0";
|
||||||
public static ImgurApiKey = '7070e7167f0a25a'
|
public static ImgurApiKey = '7070e7167f0a25a'
|
||||||
public static readonly mapillary_client_token_v3 = 'TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2'
|
public static readonly mapillary_client_token_v3 = 'TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2'
|
||||||
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
||||||
|
|
|
@ -113,9 +113,9 @@ export default class SimpleAddUI extends Toggle {
|
||||||
new Toggle(
|
new Toggle(
|
||||||
new Toggle(
|
new Toggle(
|
||||||
new Toggle(
|
new Toggle(
|
||||||
addUi,
|
|
||||||
Translations.t.general.add.stillLoading.Clone().SetClass("alert"),
|
Translations.t.general.add.stillLoading.Clone().SetClass("alert"),
|
||||||
state.featurePipeline.somethingLoaded
|
addUi,
|
||||||
|
state.featurePipeline.runningQuery
|
||||||
),
|
),
|
||||||
Translations.t.general.add.zoomInFurther.Clone().SetClass("alert"),
|
Translations.t.general.add.zoomInFurther.Clone().SetClass("alert"),
|
||||||
state.locationControl.map(loc => loc.zoom >= Constants.userJourney.minZoomLevelToAddNewPoints)
|
state.locationControl.map(loc => loc.zoom >= Constants.userJourney.minZoomLevelToAddNewPoints)
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
|
||||||
import BaseUIElement from "../BaseUIElement";
|
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
|
||||||
import Translations from "../i18n/Translations";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows that 'images are uploading', 'all images are uploaded' as relevant...
|
|
||||||
*/
|
|
||||||
export default class UploadFlowStateUI extends VariableUiElement {
|
|
||||||
|
|
||||||
|
|
||||||
constructor(queue: UIEventSource<string[]>, failed: UIEventSource<string[]>, success: UIEventSource<string[]>) {
|
|
||||||
const t = Translations.t.image;
|
|
||||||
|
|
||||||
super(
|
|
||||||
queue.map(queue => {
|
|
||||||
const failedReasons = failed.data
|
|
||||||
const successCount = success.data.length
|
|
||||||
const pendingCount = queue.length - successCount - failedReasons.length;
|
|
||||||
|
|
||||||
let stateMessages: BaseUIElement[] = []
|
|
||||||
|
|
||||||
if (pendingCount == 1) {
|
|
||||||
stateMessages.push(t.uploadingPicture.Clone().SetClass("alert"))
|
|
||||||
}
|
|
||||||
if (pendingCount > 1) {
|
|
||||||
stateMessages.push(t.uploadingMultiple.Subs({count: "" + pendingCount}).SetClass("alert"))
|
|
||||||
}
|
|
||||||
if (failedReasons.length > 0) {
|
|
||||||
stateMessages.push(t.uploadFailed.Clone().SetClass("alert"))
|
|
||||||
}
|
|
||||||
if (successCount > 0 && pendingCount == 0) {
|
|
||||||
stateMessages.push(t.uploadDone.SetClass("thanks"))
|
|
||||||
}
|
|
||||||
|
|
||||||
stateMessages.forEach(msg => msg.SetStyle("display: block ruby"))
|
|
||||||
|
|
||||||
return stateMessages
|
|
||||||
}, [failed, success])
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -23,6 +23,7 @@ import ScrollableFullScreen from "./Base/ScrollableFullScreen";
|
||||||
import Translations from "./i18n/Translations";
|
import Translations from "./i18n/Translations";
|
||||||
import SimpleAddUI from "./BigComponents/SimpleAddUI";
|
import SimpleAddUI from "./BigComponents/SimpleAddUI";
|
||||||
import StrayClickHandler from "../Logic/Actors/StrayClickHandler";
|
import StrayClickHandler from "../Logic/Actors/StrayClickHandler";
|
||||||
|
import Lazy from "./Base/Lazy";
|
||||||
|
|
||||||
export class DefaultGuiState {
|
export class DefaultGuiState {
|
||||||
public readonly welcomeMessageIsOpened;
|
public readonly welcomeMessageIsOpened;
|
||||||
|
@ -81,12 +82,22 @@ export default class DefaultGUI {
|
||||||
constructor(state: FeaturePipelineState, guiState: DefaultGuiState) {
|
constructor(state: FeaturePipelineState, guiState: DefaultGuiState) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this._guiState = guiState;
|
this._guiState = guiState;
|
||||||
const self = this;
|
|
||||||
|
|
||||||
if (state.layoutToUse.customCss !== undefined) {
|
if (state.layoutToUse.customCss !== undefined) {
|
||||||
Utils.LoadCustomCss(state.layoutToUse.customCss);
|
Utils.LoadCustomCss(state.layoutToUse.customCss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.SetupUIElements();
|
||||||
|
this.SetupMap()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private SetupMap(){
|
||||||
|
const state = this.state;
|
||||||
|
const guiState = this._guiState;
|
||||||
|
|
||||||
// Attach the map
|
// Attach the map
|
||||||
state.mainMapObject.SetClass("w-full h-full")
|
state.mainMapObject.SetClass("w-full h-full")
|
||||||
.AttachTo("leafletDiv")
|
.AttachTo("leafletDiv")
|
||||||
|
@ -96,8 +107,28 @@ export default class DefaultGUI {
|
||||||
state
|
state
|
||||||
)
|
)
|
||||||
|
|
||||||
this.InitWelcomeMessage();
|
|
||||||
|
|
||||||
|
new ShowDataLayer({
|
||||||
|
leafletMap: state.leafletMap,
|
||||||
|
layerToShow: AllKnownLayers.sharedLayers.get("home_location"),
|
||||||
|
features: state.homeLocation,
|
||||||
|
enablePopups: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
state.leafletMap.addCallbackAndRunD(_ => {
|
||||||
|
// Lets assume that all showDataLayers are initialized at this point
|
||||||
|
state.selectedElement.ping()
|
||||||
|
State.state.locationControl.ping();
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private SetupUIElements(){
|
||||||
|
const state = this.state;
|
||||||
|
const guiState = this._guiState;
|
||||||
|
|
||||||
|
const self =this
|
||||||
Toggle.If(state.featureSwitchUserbadge,
|
Toggle.If(state.featureSwitchUserbadge,
|
||||||
() => new UserBadge(state)
|
() => new UserBadge(state)
|
||||||
).AttachTo("userbadge")
|
).AttachTo("userbadge")
|
||||||
|
@ -119,36 +150,21 @@ export default class DefaultGUI {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new Toggle(self.InitWelcomeMessage(),
|
new Toggle(new Lazy(() => self.InitWelcomeMessage()),
|
||||||
Toggle.If(state.featureSwitchIframePopoutEnabled, iframePopout),
|
Toggle.If(state.featureSwitchIframePopoutEnabled, iframePopout),
|
||||||
state.featureSwitchWelcomeMessage
|
state.featureSwitchWelcomeMessage
|
||||||
).AttachTo("messagesbox");
|
).AttachTo("messagesbox");
|
||||||
|
|
||||||
new LeftControls(state, guiState).AttachTo("bottom-left");
|
new LeftControls(state, guiState).AttachTo("bottom-left");
|
||||||
new RightControls(state).AttachTo("bottom-right");
|
new RightControls(state).AttachTo("bottom-right");
|
||||||
State.state.locationControl.ping();
|
|
||||||
new CenterMessageBox(state).AttachTo("centermessage");
|
new CenterMessageBox(state).AttachTo("centermessage");
|
||||||
document
|
document
|
||||||
.getElementById("centermessage")
|
.getElementById("centermessage")
|
||||||
.classList.add("pointer-events-none");
|
.classList.add("pointer-events-none");
|
||||||
|
|
||||||
|
|
||||||
new ShowDataLayer({
|
|
||||||
leafletMap: state.leafletMap,
|
|
||||||
layerToShow: AllKnownLayers.sharedLayers.get("home_location"),
|
|
||||||
features: state.homeLocation,
|
|
||||||
enablePopups: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
state.leafletMap.addCallbackAndRunD(_ => {
|
|
||||||
// Lets assume that all showDataLayers are initialized at this point
|
|
||||||
state.selectedElement.ping()
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private InitWelcomeMessage() {
|
private InitWelcomeMessage() : BaseUIElement{
|
||||||
const isOpened = this._guiState.welcomeMessageIsOpened
|
const isOpened = this._guiState.welcomeMessageIsOpened
|
||||||
const fullOptions = new FullWelcomePaneWithTabs(isOpened, this._guiState.welcomeMessageOpenedTab, this.state);
|
const fullOptions = new FullWelcomePaneWithTabs(isOpened, this._guiState.welcomeMessageOpenedTab, this.state);
|
||||||
|
|
||||||
|
@ -180,7 +196,7 @@ export default class DefaultGUI {
|
||||||
|
|
||||||
public setupClickDialogOnMap(filterViewIsOpened: UIEventSource<boolean>, state: FeaturePipelineState) {
|
public setupClickDialogOnMap(filterViewIsOpened: UIEventSource<boolean>, state: FeaturePipelineState) {
|
||||||
|
|
||||||
function setup(){
|
function setup() {
|
||||||
let presetCount = 0;
|
let presetCount = 0;
|
||||||
for (const layer of state.layoutToUse.layers) {
|
for (const layer of state.layoutToUse.layers) {
|
||||||
for (const preset of layer.presets) {
|
for (const preset of layer.presets) {
|
||||||
|
|
|
@ -9,7 +9,9 @@ import ImageProvider from "../../Logic/ImageProviders/ImageProvider";
|
||||||
|
|
||||||
export class ImageCarousel extends Toggle {
|
export class ImageCarousel extends Toggle {
|
||||||
|
|
||||||
constructor(images: UIEventSource<{ key: string, url: string, provider: ImageProvider }[]>, tags: UIEventSource<any>) {
|
constructor(images: UIEventSource<{ key: string, url: string, provider: ImageProvider }[]>,
|
||||||
|
tags: UIEventSource<any>,
|
||||||
|
keys: string[]) {
|
||||||
const uiElements = images.map((imageURLS: { key: string, url: string, provider: ImageProvider }[]) => {
|
const uiElements = images.map((imageURLS: { key: string, url: string, provider: ImageProvider }[]) => {
|
||||||
const uiElements: BaseUIElement[] = [];
|
const uiElements: BaseUIElement[] = [];
|
||||||
for (const url of imageURLS) {
|
for (const url of imageURLS) {
|
||||||
|
|
|
@ -9,14 +9,23 @@ import LicensePicker from "../BigComponents/LicensePicker";
|
||||||
import Toggle from "../Input/Toggle";
|
import Toggle from "../Input/Toggle";
|
||||||
import FileSelectorButton from "../Input/FileSelectorButton";
|
import FileSelectorButton from "../Input/FileSelectorButton";
|
||||||
import ImgurUploader from "../../Logic/ImageProviders/ImgurUploader";
|
import ImgurUploader from "../../Logic/ImageProviders/ImgurUploader";
|
||||||
import UploadFlowStateUI from "../BigComponents/UploadFlowStateUI";
|
|
||||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||||
|
|
||||||
export class ImageUploadFlow extends Toggle {
|
export class ImageUploadFlow extends Toggle {
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly uploadCountsPerId = new Map<string, UIEventSource<number>>()
|
||||||
|
|
||||||
constructor(tagsSource: UIEventSource<any>, imagePrefix: string = "image", text: string = undefined) {
|
constructor(tagsSource: UIEventSource<any>, imagePrefix: string = "image", text: string = undefined) {
|
||||||
|
const perId = ImageUploadFlow.uploadCountsPerId
|
||||||
|
const id = tagsSource.data.id
|
||||||
|
if(!perId.has(id)){
|
||||||
|
perId.set(id, new UIEventSource<number>(0))
|
||||||
|
}
|
||||||
|
const uploadedCount = perId.get(id)
|
||||||
const uploader = new ImgurUploader(url => {
|
const uploader = new ImgurUploader(url => {
|
||||||
// A file was uploaded - we add it to the tags of the object
|
// A file was uploaded - we add it to the tags of the object
|
||||||
|
|
||||||
|
@ -30,7 +39,9 @@ export class ImageUploadFlow extends Toggle {
|
||||||
key = imagePrefix + ":" + freeIndex;
|
key = imagePrefix + ":" + freeIndex;
|
||||||
}
|
}
|
||||||
console.log("Adding image:" + key, url);
|
console.log("Adding image:" + key, url);
|
||||||
Promise.resolve(State.state.changes
|
uploadedCount.data ++
|
||||||
|
uploadedCount.ping()
|
||||||
|
Promise.resolve(State.state.changes
|
||||||
.applyAction(new ChangeTagAction(
|
.applyAction(new ChangeTagAction(
|
||||||
tags.id, new Tag(key, url), tagsSource.data,
|
tags.id, new Tag(key, url), tagsSource.data,
|
||||||
{
|
{
|
||||||
|
@ -40,10 +51,6 @@ export class ImageUploadFlow extends Toggle {
|
||||||
)))
|
)))
|
||||||
})
|
})
|
||||||
|
|
||||||
uploader.queue.addCallbackD(q => console.log("Image upload queue is ", q))
|
|
||||||
uploader.failed.addCallbackD(q => console.log("Image upload fail list is ", q))
|
|
||||||
uploader.success.addCallbackD(q => console.log("Image upload success list is ", q))
|
|
||||||
|
|
||||||
const licensePicker = new LicensePicker()
|
const licensePicker = new LicensePicker()
|
||||||
|
|
||||||
const t = Translations.t.image;
|
const t = Translations.t.image;
|
||||||
|
@ -105,10 +112,33 @@ export class ImageUploadFlow extends Toggle {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const uploadStateUi = new UploadFlowStateUI(uploader.queue, uploader.failed, uploader.success)
|
|
||||||
|
|
||||||
const uploadFlow: BaseUIElement = new Combine([
|
const uploadFlow: BaseUIElement = new Combine([
|
||||||
uploadStateUi,
|
new VariableUiElement(uploader.queue.map(q => q.length).map(l => {
|
||||||
|
if(l == 0){
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if(l == 1){
|
||||||
|
return t.uploadingPicture.Clone().SetClass("alert")
|
||||||
|
}else{
|
||||||
|
return t.uploadingMultiple.Subs({count: "" + l}).SetClass("alert")
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
new VariableUiElement(uploader.failed.map(q => q.length).map(l => {
|
||||||
|
if(l==0){
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return t.uploadFailed.Clone().SetClass("alert");
|
||||||
|
})),
|
||||||
|
new VariableUiElement(uploadedCount.map(l => {
|
||||||
|
if(l == 0){
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if(l == 1){
|
||||||
|
return t.uploadDone.Clone().SetClass("thanks");
|
||||||
|
}
|
||||||
|
return t.uploadMultipleDone.Subs({count: l}).SetClass("thanks")
|
||||||
|
})),
|
||||||
|
|
||||||
fileSelector,
|
fileSelector,
|
||||||
Translations.t.image.respectPrivacy.Clone().SetStyle("font-size:small;"),
|
Translations.t.image.respectPrivacy.Clone().SetStyle("font-size:small;"),
|
||||||
licensePicker
|
licensePicker
|
||||||
|
|
|
@ -83,15 +83,15 @@ export default class SpecialVisualizations {
|
||||||
docs: "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)",
|
docs: "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)",
|
||||||
args: [{
|
args: [{
|
||||||
name: "image key/prefix (multiple values allowed if comma-seperated)",
|
name: "image key/prefix (multiple values allowed if comma-seperated)",
|
||||||
defaultValue: "image",
|
defaultValue: AllImageProviders.defaultKeys.join(","),
|
||||||
doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... "
|
doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... "
|
||||||
}],
|
}],
|
||||||
constr: (state: State, tags, args) => {
|
constr: (state: State, tags, args) => {
|
||||||
let imagePrefixes = undefined;
|
let imagePrefixes: string[] = undefined;
|
||||||
if(args.length > 0){
|
if(args.length > 0){
|
||||||
imagePrefixes = args;
|
imagePrefixes = [].concat(...args.map(a => a.split(",")));
|
||||||
}
|
}
|
||||||
return new ImageCarousel(AllImageProviders.LoadImagesFor(tags, imagePrefixes), tags);
|
return new ImageCarousel(AllImageProviders.LoadImagesFor(tags, imagePrefixes), tags, imagePrefixes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
2
Utils.ts
2
Utils.ts
|
@ -330,7 +330,7 @@ export class Utils {
|
||||||
return cached.promise
|
return cached.promise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const promise = Utils.downloadJson(url, headers)
|
const promise = /*NO AWAIT as we work with the promise directly */Utils.downloadJson(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
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,8 +174,8 @@
|
||||||
"condition": "service:bicycle:diy=yes",
|
"condition": "service:bicycle:diy=yes",
|
||||||
"render": "<img src='./assets/layers/bike_shop/tools.svg'/>"
|
"render": "<img src='./assets/layers/bike_shop/tools.svg'/>"
|
||||||
},
|
},
|
||||||
{ "condition": "service:bicycle:cleaning=yes",
|
{
|
||||||
|
"condition": "service:bicycle:cleaning=yes",
|
||||||
"render": "<img src='./assets/layers/bike_cleaning/bike_cleaning_icon.svg'/>"
|
"render": "<img src='./assets/layers/bike_cleaning/bike_cleaning_icon.svg'/>"
|
||||||
},
|
},
|
||||||
"defaults"
|
"defaults"
|
||||||
|
|
|
@ -668,8 +668,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"question": {
|
"question": {
|
||||||
"en": "What is the carriage width of this road (in meters)?",
|
"en": "What is the carriage width of this road (in meters)?<br/><span class='subtle'>This is measured curb to curb and thus includes the width of parallell parking lanes</span>",
|
||||||
"nl": "Hoe breed is de rijbaan in deze straat (in meters)?"
|
"nl": "Hoe breed is de rijbaan in deze straat (in meters)?<br/><span class='subtle'>Dit is </span><br/><span class='subtle'>Meet dit van stoepsteen tot stoepsteen, dus inclusief een parallelle parkeerstrook</span>"
|
||||||
},
|
},
|
||||||
"id": "width:carriageway"
|
"id": "width:carriageway"
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
"startLat": 51.25634,
|
"startLat": 51.25634,
|
||||||
"startLon": 3.195682,
|
"startLon": 3.195682,
|
||||||
"startZoom": 12,
|
"startZoom": 12,
|
||||||
|
"clustering": {
|
||||||
|
"maxZoom": 0
|
||||||
|
},
|
||||||
"layers": [
|
"layers": [
|
||||||
"defibrillator",
|
"defibrillator",
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{
|
{
|
||||||
"id": "buurtnatuur",
|
"id": "buurtnatuur",
|
||||||
"title": {
|
"title": {
|
||||||
"#": "DO NOT TRANSLATE THIS THEME - this one is only meant to be in dutch!",
|
|
||||||
"nl": "Breng jouw buurtnatuur in kaart"
|
"nl": "Breng jouw buurtnatuur in kaart"
|
||||||
},
|
},
|
||||||
"shortDescription": {
|
"shortDescription": {
|
||||||
|
|
|
@ -207,7 +207,8 @@
|
||||||
"overrideAll": {
|
"overrideAll": {
|
||||||
"allowSplit": true,
|
"allowSplit": true,
|
||||||
"tagRenderings+": [
|
"tagRenderings+": [
|
||||||
{"id": "is_cyclestreet",
|
{
|
||||||
|
"id": "is_cyclestreet",
|
||||||
"question": {
|
"question": {
|
||||||
"nl": "Is deze straat een fietsstraat?",
|
"nl": "Is deze straat een fietsstraat?",
|
||||||
"en": "Is this street a cyclestreet?",
|
"en": "Is this street a cyclestreet?",
|
||||||
|
@ -283,7 +284,8 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{"id": "future_cyclestreet",
|
{
|
||||||
|
"id": "future_cyclestreet",
|
||||||
"question": {
|
"question": {
|
||||||
"nl": "Wanneer wordt deze straat een fietsstraat?",
|
"nl": "Wanneer wordt deze straat een fietsstraat?",
|
||||||
"en": "When will this street become a cyclestreet?",
|
"en": "When will this street become a cyclestreet?",
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
"ccb": "under the CC-BY-license",
|
"ccb": "under the CC-BY-license",
|
||||||
"uploadFailed": "Could not upload your picture. Are you connected to the Internet, and allow third party API's? The Brave browser or the uMatrix plugin might block them.",
|
"uploadFailed": "Could not upload your picture. Are you connected to the Internet, and allow third party API's? The Brave browser or the uMatrix plugin might block them.",
|
||||||
"respectPrivacy": "Do not photograph people nor license plates. Do not upload Google Maps, Google Streetview or other copyrighted sources.",
|
"respectPrivacy": "Do not photograph people nor license plates. Do not upload Google Maps, Google Streetview or other copyrighted sources.",
|
||||||
"uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>",
|
"uploadDone": "Your picture has been added. Thanks for helping out!",
|
||||||
|
"uploadMultipleDone": "{count} pictures have been added. Thanks for helping out!",
|
||||||
"dontDelete": "Cancel",
|
"dontDelete": "Cancel",
|
||||||
"doDelete": "Remove image",
|
"doDelete": "Remove image",
|
||||||
"isDeleted": "Deleted",
|
"isDeleted": "Deleted",
|
||||||
|
|
|
@ -2376,7 +2376,7 @@
|
||||||
"question": "Is this street lit?"
|
"question": "Is this street lit?"
|
||||||
},
|
},
|
||||||
"width:carriageway": {
|
"width:carriageway": {
|
||||||
"question": "What is the carriage width of this road (in meters)?",
|
"question": "What is the carriage width of this road (in meters)?<br/><span class='subtle'>This is measured curb to curb and thus includes the width of parallell parking lanes</span>",
|
||||||
"render": "The carriage width of this road is <strong>{width:carriageway}m</strong>"
|
"render": "The carriage width of this road is <strong>{width:carriageway}m</strong>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2329,7 +2329,7 @@
|
||||||
"question": "Is deze weg verlicht?"
|
"question": "Is deze weg verlicht?"
|
||||||
},
|
},
|
||||||
"width:carriageway": {
|
"width:carriageway": {
|
||||||
"question": "Hoe breed is de rijbaan in deze straat (in meters)?",
|
"question": "Hoe breed is de rijbaan in deze straat (in meters)?<br/><span class='subtle'>Dit is </span><br/><span class='subtle'>Meet dit van stoepsteen tot stoepsteen, dus inclusief een parallelle parkeerstrook</span>",
|
||||||
"render": "De breedte van deze rijbaan in deze straat is <strong>{width:carriageway}m</strong>"
|
"render": "De breedte van deze rijbaan in deze straat is <strong>{width:carriageway}m</strong>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -233,21 +233,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "Wer betreibt diesen Ort?",
|
"0": {
|
||||||
"render": "Dieser Ort wird betrieben von {operator}"
|
"question": "Wer betreibt diesen Ort?",
|
||||||
},
|
"render": "Dieser Ort wird betrieben von {operator}"
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Dieser Ort hat eine Stromversorgung"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Dieser Ort hat keine Stromversorgung"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Hat dieser Ort eine Stromversorgung?"
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Dieser Ort hat eine Stromversorgung"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Dieser Ort hat keine Stromversorgung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Hat dieser Ort eine Stromversorgung?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Finden Sie Plätze zum Übernachten mit Ihrem Wohnmobil",
|
"shortDescription": "Finden Sie Plätze zum Übernachten mit Ihrem Wohnmobil",
|
||||||
|
@ -428,6 +430,113 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overrideAll": {
|
"overrideAll": {
|
||||||
|
"tagRenderings+": {
|
||||||
|
"0": {
|
||||||
|
"question": "Gibt es eine (inoffizielle) Website mit mehr Informationen (z.B. Topos)?"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Öffentlich zugänglich für jedermann"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Zugang nur mit Genehmigung"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Nur für Kunden"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Nur für Vereinsmitglieder"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Wer hat hier Zugang?"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"question": "Wie lang sind die Routen (durchschnittlich) in Metern?",
|
||||||
|
"render": "Die Routen sind durchschnittlich <b>{canonical(climbing:length)}</b> lang"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"question": "Welche Schwierigkeit hat hier die leichteste Route (französisch/belgisches System)?",
|
||||||
|
"render": "Die leichteste Route hat hier die Schwierigkeit {climbing:grade:french:min} (französisch/belgisches System)"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"question": "Welche Schwierigkeit hat hier die schwerste Route (französisch/belgisches System)?",
|
||||||
|
"render": "Die schwerste Route hat hier die Schwierigkeit {climbing:grade:french:min} (französisch/belgisches System)"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Hier kann gebouldert werden"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Hier kann nicht gebouldert werden"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Bouldern ist hier nur an wenigen Routen möglich"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Hier gibt es {climbing:boulder} Boulder-Routen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Kann hier gebouldert werden?"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Toprope-Klettern ist hier möglich"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Toprope-Climbing ist hier nicht möglich"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Hier gibt es {climbing:toprope} Toprope-Routen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Ist Toprope-Klettern hier möglich?"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Sportklettern ist hier möglich"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Sportklettern ist hier nicht möglich"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Hier gibt es {climbing:sport} Sportkletter-Routen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Ist hier Sportklettern möglich (feste Ankerpunkte)?"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Traditionelles Klettern ist hier möglich"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Traditionelles Klettern ist hier nicht möglich"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Hier gibt es {climbing:traditional} Routen für traditionelles Klettern"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Ist hier traditionelles Klettern möglich (eigene Sicherung z.B. mit Klemmkleilen)?"
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Hier gibt es eine Speedkletter-Wand"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Hier gibt es keine Speedkletter-Wand"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Hier gibt es {climbing:speed} Speedkletter-Routen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Gibt es hier eine Speedkletter-Wand?"
|
||||||
|
}
|
||||||
|
},
|
||||||
"units+": {
|
"units+": {
|
||||||
"0": {
|
"0": {
|
||||||
"applicableUnits": {
|
"applicableUnits": {
|
||||||
|
@ -441,113 +550,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
|
||||||
"0": {
|
|
||||||
"question": "Gibt es eine (inoffizielle) Website mit mehr Informationen (z.B. Topos)?"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Öffentlich zugänglich für jedermann"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Zugang nur mit Genehmigung"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Nur für Kunden"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Nur für Vereinsmitglieder"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Wer hat hier Zugang?"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"question": "Wie lang sind die Routen (durchschnittlich) in Metern?",
|
|
||||||
"render": "Die Routen sind durchschnittlich <b>{canonical(climbing:length)}</b> lang"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"question": "Welche Schwierigkeit hat hier die leichteste Route (französisch/belgisches System)?",
|
|
||||||
"render": "Die leichteste Route hat hier die Schwierigkeit {climbing:grade:french:min} (französisch/belgisches System)"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"question": "Welche Schwierigkeit hat hier die schwerste Route (französisch/belgisches System)?",
|
|
||||||
"render": "Die schwerste Route hat hier die Schwierigkeit {climbing:grade:french:min} (französisch/belgisches System)"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Hier kann gebouldert werden"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Hier kann nicht gebouldert werden"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Bouldern ist hier nur an wenigen Routen möglich"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Hier gibt es {climbing:boulder} Boulder-Routen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Kann hier gebouldert werden?"
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Toprope-Klettern ist hier möglich"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Toprope-Climbing ist hier nicht möglich"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Hier gibt es {climbing:toprope} Toprope-Routen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Ist Toprope-Klettern hier möglich?"
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Sportklettern ist hier möglich"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Sportklettern ist hier nicht möglich"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Hier gibt es {climbing:sport} Sportkletter-Routen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Ist hier Sportklettern möglich (feste Ankerpunkte)?"
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Traditionelles Klettern ist hier möglich"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Traditionelles Klettern ist hier nicht möglich"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Hier gibt es {climbing:traditional} Routen für traditionelles Klettern"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Ist hier traditionelles Klettern möglich (eigene Sicherung z.B. mit Klemmkleilen)?"
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Hier gibt es eine Speedkletter-Wand"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Hier gibt es keine Speedkletter-Wand"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Hier gibt es {climbing:speed} Speedkletter-Routen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Gibt es hier eine Speedkletter-Wand?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": "Offene Kletterkarte"
|
"title": "Offene Kletterkarte"
|
||||||
},
|
},
|
||||||
"cycle_highways": {
|
"cycle_highways": {
|
||||||
|
@ -594,27 +596,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "Diese Straße ist eine Fahrradstraße (mit einer Geschwindigkeitsbegrenzung von 30 km/h)"
|
"0": {
|
||||||
|
"then": "Diese Straße ist eine Fahrradstraße (mit einer Geschwindigkeitsbegrenzung von 30 km/h)"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Diese Straße ist eine Fahrradstraße"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Diese Straße wird bald eine Fahrradstraße sein"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Diese Straße ist keine Fahrradstraße"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "Ist diese Straße eine Fahrradstraße?"
|
||||||
"then": "Diese Straße ist eine Fahrradstraße"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Diese Straße wird bald eine Fahrradstraße sein"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Diese Straße ist keine Fahrradstraße"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Ist diese Straße eine Fahrradstraße?"
|
"1": {
|
||||||
},
|
"question": "Wann wird diese Straße eine Fahrradstraße?",
|
||||||
"1": {
|
"render": "Diese Straße wird am {cyclestreet:start_date} zu einer Fahrradstraße"
|
||||||
"question": "Wann wird diese Straße eine Fahrradstraße?",
|
}
|
||||||
"render": "Diese Straße wird am {cyclestreet:start_date} zu einer Fahrradstraße"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Eine Karte von Fahrradstraßen",
|
"shortDescription": "Eine Karte von Fahrradstraßen",
|
||||||
|
|
|
@ -233,21 +233,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "Who operates this place?",
|
"0": {
|
||||||
"render": "This place is operated by {operator}"
|
"question": "Who operates this place?",
|
||||||
},
|
"render": "This place is operated by {operator}"
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "This place has a power supply"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "This place does not have power supply"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Does this place have a power supply?"
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "This place has a power supply"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "This place does not have power supply"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Does this place have a power supply?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Find sites to spend the night with your camper",
|
"shortDescription": "Find sites to spend the night with your camper",
|
||||||
|
@ -452,6 +454,129 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overrideAll": {
|
"overrideAll": {
|
||||||
|
"tagRenderings+": {
|
||||||
|
"0": {
|
||||||
|
"question": "Is there a (unofficial) website with more informations (e.g. topos)?"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that this is</span> publicly accessible<br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that </span> a permit is needed to access<br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that this is</span> only accessible to customers<br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that this is</span> only accessible to club members<br/>{_embedding_feature:access:description}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Publicly accessible to anyone"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "You need a permit to access here"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Only custumers"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Only club members"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Who can access here?"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"question": "What is the (average) length of the routes in meters?",
|
||||||
|
"render": "The routes are <b>{canonical(climbing:length)}</b> long on average"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"question": "What is the level of the easiest route here, accoring to the french classification system?",
|
||||||
|
"render": "The minimal difficulty is {climbing:grade:french:min} according to the french/belgian system"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"question": "What is the level of the most difficult route here, accoring to the french classification system?",
|
||||||
|
"render": "The maximal difficulty is {climbing:grade:french:max} according to the french/belgian system"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Bouldering is possible here"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Bouldering is not possible here"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Bouldering is possible, allthough there are only a few routes"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "There are {climbing:boulder} boulder routes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is bouldering possible here?"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Toprope climbing is possible here"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Toprope climbing is not possible here"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "There are {climbing:toprope} toprope routes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is toprope climbing possible here?"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Sport climbing is possible here"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Sport climbing is not possible here"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "There are {climbing:sport} sport climbing routes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is sport climbing possible here on fixed anchors?"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Traditional climbing is possible here"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Traditional climbing is not possible here"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "There are {climbing:traditional} traditional climbing routes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is traditional climbing possible here (using own gear e.g. chocks)?"
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "There is a speed climbing wall"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "There is no speed climbing wall"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "There are {climbing:speed} speed climbing walls"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is there a speed climbing wall?"
|
||||||
|
}
|
||||||
|
},
|
||||||
"units+": {
|
"units+": {
|
||||||
"0": {
|
"0": {
|
||||||
"applicableUnits": {
|
"applicableUnits": {
|
||||||
|
@ -465,129 +590,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
|
||||||
"0": {
|
|
||||||
"question": "Is there a (unofficial) website with more informations (e.g. topos)?"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that this is</span> publicly accessible<br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that </span> a permit is needed to access<br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that this is</span> only accessible to customers<br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "<span class='subtle'>The <a href='#{_embedding_feature:id}'>containing feature</a> states that this is</span> only accessible to club members<br/>{_embedding_feature:access:description}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Publicly accessible to anyone"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "You need a permit to access here"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Only custumers"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Only club members"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Who can access here?"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"question": "What is the (average) length of the routes in meters?",
|
|
||||||
"render": "The routes are <b>{canonical(climbing:length)}</b> long on average"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"question": "What is the level of the easiest route here, accoring to the french classification system?",
|
|
||||||
"render": "The minimal difficulty is {climbing:grade:french:min} according to the french/belgian system"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"question": "What is the level of the most difficult route here, accoring to the french classification system?",
|
|
||||||
"render": "The maximal difficulty is {climbing:grade:french:max} according to the french/belgian system"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Bouldering is possible here"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Bouldering is not possible here"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Bouldering is possible, allthough there are only a few routes"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "There are {climbing:boulder} boulder routes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is bouldering possible here?"
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Toprope climbing is possible here"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Toprope climbing is not possible here"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "There are {climbing:toprope} toprope routes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is toprope climbing possible here?"
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Sport climbing is possible here"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Sport climbing is not possible here"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "There are {climbing:sport} sport climbing routes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is sport climbing possible here on fixed anchors?"
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Traditional climbing is possible here"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Traditional climbing is not possible here"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "There are {climbing:traditional} traditional climbing routes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is traditional climbing possible here (using own gear e.g. chocks)?"
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "There is a speed climbing wall"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "There is no speed climbing wall"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "There are {climbing:speed} speed climbing walls"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is there a speed climbing wall?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": "Open Climbing Map"
|
"title": "Open Climbing Map"
|
||||||
},
|
},
|
||||||
"cycle_highways": {
|
"cycle_highways": {
|
||||||
|
@ -634,27 +636,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "This street is a cyclestreet (and has a speed limit of 30 km/h)"
|
"0": {
|
||||||
|
"then": "This street is a cyclestreet (and has a speed limit of 30 km/h)"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "This street is a cyclestreet"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "This street will become a cyclstreet soon"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "This street is not a cyclestreet"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "Is this street a cyclestreet?"
|
||||||
"then": "This street is a cyclestreet"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "This street will become a cyclstreet soon"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "This street is not a cyclestreet"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Is this street a cyclestreet?"
|
"1": {
|
||||||
},
|
"question": "When will this street become a cyclestreet?",
|
||||||
"1": {
|
"render": "This street will become a cyclestreet at {cyclestreet:start_date}"
|
||||||
"question": "When will this street become a cyclestreet?",
|
}
|
||||||
"render": "This street will become a cyclestreet at {cyclestreet:start_date}"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "A map of cyclestreets",
|
"shortDescription": "A map of cyclestreets",
|
||||||
|
|
|
@ -225,21 +225,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "Qui est l’exploitant du site ?",
|
"0": {
|
||||||
"render": "Ce site est exploité par {operator}"
|
"question": "Qui est l’exploitant du site ?",
|
||||||
},
|
"render": "Ce site est exploité par {operator}"
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Ce site a une source d’alimentation"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Ce site n’a pas de source d’alimentation"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Ce site a-t’il une source d’électricité ?"
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Ce site a une source d’alimentation"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Ce site n’a pas de source d’alimentation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Ce site a-t’il une source d’électricité ?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Trouver des sites pour passer la nuit avec votre camping-car",
|
"shortDescription": "Trouver des sites pour passer la nuit avec votre camping-car",
|
||||||
|
@ -439,6 +441,87 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overrideAll": {
|
"overrideAll": {
|
||||||
|
"tagRenderings+": {
|
||||||
|
"0": {
|
||||||
|
"question": "Existe-t’il un site avec plus d’informations (ex : topographie) ?"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique un </span> accès libre<br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique qu’</span> une autorisation d’accès est nécessaire<br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique que </span> l’accès est réservés aux clients<br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique que </span> l’accès est réservé aux membres<br/>{_embedding_feature:access:description}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Libre d’accès"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Une autorisation est nécessaire"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Réservé aux clients"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Réservé aux membres"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Qui peut y accéder ?"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"question": "Quelle est la longueur moyenne des voies en mètres ?",
|
||||||
|
"render": "Les voies font <b>{canonical(climbing:length)}</b> de long en moyenne"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"question": "Quel est le niveau de la voie la plus simple selon la classification franco-belge ?",
|
||||||
|
"render": "La difficulté minimale est {climbing:grade:french:min} selon la classification franco-belge"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"question": "Quel est le niveau de la voie la plus difficile selon la classification franco-belge ?",
|
||||||
|
"render": "La difficulté maximale est {climbing:grade:french:max} selon la classification franco-belge"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "L’escalade de bloc est possible"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "L’escalade de bloc n’est pas possible"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "L’escalade de bloc est possible sur des voies précises"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Il y a {climbing:boulder} voies d’escalade de bloc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "L’escalade de bloc est-elle possible ici ?"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "L’escalade à la moulinette est possible"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "L’escalade à la moulinette n’est pas possible"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "{climbing:toprope} voies sont équipées de moulinettes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Est-il possible d’escalader à la moulinette ?"
|
||||||
|
}
|
||||||
|
},
|
||||||
"units+": {
|
"units+": {
|
||||||
"0": {
|
"0": {
|
||||||
"applicableUnits": {
|
"applicableUnits": {
|
||||||
|
@ -452,87 +535,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
|
||||||
"0": {
|
|
||||||
"question": "Existe-t’il un site avec plus d’informations (ex : topographie) ?"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique un </span> accès libre<br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique qu’</span> une autorisation d’accès est nécessaire<br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique que </span> l’accès est réservés aux clients<br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "<span class='subtle'>L’<a href='#{_embedding_feature:id}'>élément englobant</a> indique que </span> l’accès est réservé aux membres<br/>{_embedding_feature:access:description}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Libre d’accès"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Une autorisation est nécessaire"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Réservé aux clients"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Réservé aux membres"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Qui peut y accéder ?"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"question": "Quelle est la longueur moyenne des voies en mètres ?",
|
|
||||||
"render": "Les voies font <b>{canonical(climbing:length)}</b> de long en moyenne"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"question": "Quel est le niveau de la voie la plus simple selon la classification franco-belge ?",
|
|
||||||
"render": "La difficulté minimale est {climbing:grade:french:min} selon la classification franco-belge"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"question": "Quel est le niveau de la voie la plus difficile selon la classification franco-belge ?",
|
|
||||||
"render": "La difficulté maximale est {climbing:grade:french:max} selon la classification franco-belge"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "L’escalade de bloc est possible"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "L’escalade de bloc n’est pas possible"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "L’escalade de bloc est possible sur des voies précises"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Il y a {climbing:boulder} voies d’escalade de bloc"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "L’escalade de bloc est-elle possible ici ?"
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "L’escalade à la moulinette est possible"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "L’escalade à la moulinette n’est pas possible"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "{climbing:toprope} voies sont équipées de moulinettes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Est-il possible d’escalader à la moulinette ?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": "Open Climbing Map"
|
"title": "Open Climbing Map"
|
||||||
},
|
},
|
||||||
"cyclofix": {
|
"cyclofix": {
|
||||||
|
|
|
@ -52,14 +52,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"1": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"1": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "Tempat ini memiliki catu daya"
|
"0": {
|
||||||
},
|
"then": "Tempat ini memiliki catu daya"
|
||||||
"1": {
|
},
|
||||||
"then": "Tempat ini tidak memiliki sumber listrik"
|
"1": {
|
||||||
|
"then": "Tempat ini tidak memiliki sumber listrik"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,21 +225,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "Chi gestisce questo luogo?",
|
"0": {
|
||||||
"render": "Questo luogo è gestito da {operator}"
|
"question": "Chi gestisce questo luogo?",
|
||||||
},
|
"render": "Questo luogo è gestito da {operator}"
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Questo luogo fornisce corrente elettrica"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Questo luogo non fornisce corrente elettrica"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Questo luogo fornisce corrente elettrica?"
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Questo luogo fornisce corrente elettrica"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Questo luogo non fornisce corrente elettrica"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Questo luogo fornisce corrente elettrica?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Trova aree dove passare la notte con il tuo camper",
|
"shortDescription": "Trova aree dove passare la notte con il tuo camper",
|
||||||
|
@ -310,17 +312,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"3": {
|
"mappings": {
|
||||||
"then": "Questa strada non è una strada ciclabile"
|
"3": {
|
||||||
|
"then": "Questa strada non è una strada ciclabile"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"question": "Questa strada diventerà una strada ciclabile quando?",
|
||||||
|
"render": "Questa strada diventerà una strada ciclabile dal {cyclestreet:start_date}"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"question": "Questa strada diventerà una strada ciclabile quando?",
|
|
||||||
"render": "Questa strada diventerà una strada ciclabile dal {cyclestreet:start_date}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -225,21 +225,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "この店は誰が経営しているんですか?",
|
"0": {
|
||||||
"render": "この場所は{operator}によって運営されます"
|
"question": "この店は誰が経営しているんですか?",
|
||||||
},
|
"render": "この場所は{operator}によって運営されます"
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "この場所には電源があります"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "この場所には電源がありません"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "この場所に電源はありますか?"
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "この場所には電源があります"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "この場所には電源がありません"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "この場所に電源はありますか?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "キャンパーと夜を共にするキャンプサイトを見つける",
|
"shortDescription": "キャンパーと夜を共にするキャンプサイトを見つける",
|
||||||
|
@ -379,94 +381,96 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "もっと情報のある(非公式の)ウェブサイトはありますか(例えば、topos)?"
|
"0": {
|
||||||
},
|
"question": "もっと情報のある(非公式の)ウェブサイトはありますか(例えば、topos)?"
|
||||||
"4": {
|
|
||||||
"question": "ルートの(平均)長さはメートル単位でいくつですか?",
|
|
||||||
"render": "ルートの長さは平均で<b>{canonical(climbing:length)}</b>です"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"question": "ここで一番簡単なルートのレベルは、フランスのランク評価システムで何ですか?",
|
|
||||||
"render": "フランス/ベルギーのランク評価システムでは、最小の難易度は{climbing:grade:french:min}です"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"question": "フランスのランク評価によると、ここで一番難しいルートのレベルはどれくらいですか?",
|
|
||||||
"render": "フランス/ベルギーのランク評価システムでは、最大の難易度は{climbing:grade:french:max}です"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "ボルダリングはここで可能です"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "ここではボルダリングはできません"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "ボルダリングは可能ですが、少しのルートしかありません"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "{climbing:boulder} ボルダールートがある"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "ここでボルダリングはできますか?"
|
"4": {
|
||||||
},
|
"question": "ルートの(平均)長さはメートル単位でいくつですか?",
|
||||||
"8": {
|
"render": "ルートの長さは平均で<b>{canonical(climbing:length)}</b>です"
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "ここでToprope登坂ができます"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "ここではToprope登坂はできません"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "{climbing:toprope} 登坂ルートがある"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "ここでtoprope登坂はできますか?"
|
"5": {
|
||||||
},
|
"question": "ここで一番簡単なルートのレベルは、フランスのランク評価システムで何ですか?",
|
||||||
"9": {
|
"render": "フランス/ベルギーのランク評価システムでは、最小の難易度は{climbing:grade:french:min}です"
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "ここでスポーツクライミングができます"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "ここではスポーツクライミングはできません"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "スポーツクライミングの {climbing:sport} ルートがある"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "ここでは固定アンカー式のスポーツクライミングはできますか?"
|
"6": {
|
||||||
},
|
"question": "フランスのランク評価によると、ここで一番難しいルートのレベルはどれくらいですか?",
|
||||||
"10": {
|
"render": "フランス/ベルギーのランク評価システムでは、最大の難易度は{climbing:grade:french:max}です"
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "ここでは伝統的な登山が可能です"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "伝統的な登山はここではできない"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "{climbing:traditional} の伝統的な登山ルートがある"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "伝統的な登山はここで可能ですか(例えば、チョックのような独自のギアを使用して)?"
|
"7": {
|
||||||
},
|
"mappings": {
|
||||||
"11": {
|
"0": {
|
||||||
"mappings": {
|
"then": "ボルダリングはここで可能です"
|
||||||
"0": {
|
},
|
||||||
"then": "スピードクライミングウォールがある"
|
"1": {
|
||||||
|
"then": "ここではボルダリングはできません"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "ボルダリングは可能ですが、少しのルートしかありません"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "{climbing:boulder} ボルダールートがある"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "ここでボルダリングはできますか?"
|
||||||
"then": "スピードクライミングウォールがない"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "{climbing:speed} のスピードクライミングウォールがある"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "スピードクライミングウォールはありますか?"
|
"8": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "ここでToprope登坂ができます"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "ここではToprope登坂はできません"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "{climbing:toprope} 登坂ルートがある"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "ここでtoprope登坂はできますか?"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "ここでスポーツクライミングができます"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "ここではスポーツクライミングはできません"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "スポーツクライミングの {climbing:sport} ルートがある"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "ここでは固定アンカー式のスポーツクライミングはできますか?"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "ここでは伝統的な登山が可能です"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "伝統的な登山はここではできない"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "{climbing:traditional} の伝統的な登山ルートがある"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "伝統的な登山はここで可能ですか(例えば、チョックのような独自のギアを使用して)?"
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "スピードクライミングウォールがある"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "スピードクライミングウォールがない"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "{climbing:speed} のスピードクライミングウォールがある"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "スピードクライミングウォールはありますか?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "登山地図を開く"
|
"title": "登山地図を開く"
|
||||||
|
@ -498,27 +502,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "cyclestreet(最高速度は30km/h)"
|
"0": {
|
||||||
|
"then": "cyclestreet(最高速度は30km/h)"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "この通りはcyclestreetだ"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "この通りはまもなくcyclstreetになるだろう"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "この通りはcyclestreetではない"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "この通りはcyclestreetですか?"
|
||||||
"then": "この通りはcyclestreetだ"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "この通りはまもなくcyclstreetになるだろう"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "この通りはcyclestreetではない"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "この通りはcyclestreetですか?"
|
"1": {
|
||||||
},
|
"question": "この通りはいつcyclestreetになるんですか?",
|
||||||
"1": {
|
"render": "この通りは{cyclestreet:start_date}に、cyclestreetになります"
|
||||||
"question": "この通りはいつcyclestreetになるんですか?",
|
}
|
||||||
"render": "この通りは{cyclestreet:start_date}に、cyclestreetになります"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "cyclestreetsの地図",
|
"shortDescription": "cyclestreetsの地図",
|
||||||
|
|
|
@ -108,17 +108,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"7": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"7": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "Buldring er mulig her"
|
"0": {
|
||||||
|
"then": "Buldring er mulig her"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Buldring er ikke mulig her"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "Er buldring mulig her?"
|
||||||
"then": "Buldring er ikke mulig her"
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Er buldring mulig her?"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Åpent klatrekart"
|
"title": "Åpent klatrekart"
|
||||||
|
@ -136,23 +138,25 @@
|
||||||
"name": "Alle gater"
|
"name": "Alle gater"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "Denne gaten er en sykkelvei (og har en fartsgrense på 30 km/t)"
|
"0": {
|
||||||
|
"then": "Denne gaten er en sykkelvei (og har en fartsgrense på 30 km/t)"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Denne gaten er en sykkelvei"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Denne gaten vil bli sykkelvei ganske snart"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Denne gaten er ikke en sykkelvei"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "Er denne gaten en sykkelvei?"
|
||||||
"then": "Denne gaten er en sykkelvei"
|
}
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Denne gaten vil bli sykkelvei ganske snart"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Denne gaten er ikke en sykkelvei"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Er denne gaten en sykkelvei?"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Et kart over sykkelveier"
|
"shortDescription": "Et kart over sykkelveier"
|
||||||
|
|
|
@ -97,67 +97,69 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "Dit gebied is vrij toegankelijk"
|
"0": {
|
||||||
|
"then": "Dit gebied is vrij toegankelijk"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Vrij toegankelijk"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Niet toegankelijk"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Niet toegankelijk, want privégebied"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"then": "Toegankelijk, ondanks dat het privegebied is"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"then": "Enkel toegankelijk met een gids of tijdens een activiteit"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"then": "Toegankelijk mits betaling"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "Is dit gebied toegankelijk?",
|
||||||
"then": "Vrij toegankelijk"
|
"render": "De toegankelijkheid van dit gebied is: {access:description}"
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Niet toegankelijk"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Niet toegankelijk, want privégebied"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"then": "Toegankelijk, ondanks dat het privegebied is"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"then": "Enkel toegankelijk met een gids of tijdens een activiteit"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"then": "Toegankelijk mits betaling"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Is dit gebied toegankelijk?",
|
"1": {
|
||||||
"render": "De toegankelijkheid van dit gebied is: {access:description}"
|
"mappings": {
|
||||||
},
|
"1": {
|
||||||
"1": {
|
"then": "<img src=\"./assets/themes/buurtnatuur/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door Natuurpunt"
|
||||||
"mappings": {
|
},
|
||||||
"1": {
|
"2": {
|
||||||
"then": "<img src=\"./assets/themes/buurtnatuur/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door Natuurpunt"
|
"then": "<img src=\"./assets/themes/buurtnatuur/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door {operator}"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "<img src=\"./assets/themes/buurtnatuur/ANB.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door het Agentschap Natuur en Bos"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"2": {
|
"question": "Wie beheert dit gebied?",
|
||||||
"then": "<img src=\"./assets/themes/buurtnatuur/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door {operator}"
|
"render": "Beheer door {operator}"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"render": "Extra info: <i>{description}</i>"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"render": "Extra info via buurtnatuur.be: <i>{description:0}</i>"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"question": "Wat is de Nederlandstalige naam van dit gebied?",
|
||||||
|
"render": "Dit gebied heet {name:nl}"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Dit gebied heeft geen naam"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"3": {
|
"question": "Wat is de naam van dit gebied?",
|
||||||
"then": "<img src=\"./assets/themes/buurtnatuur/ANB.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door het Agentschap Natuur en Bos"
|
"render": "Dit gebied heet {name}"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"question": "Wie beheert dit gebied?",
|
|
||||||
"render": "Beheer door {operator}"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"render": "Extra info: <i>{description}</i>"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"render": "Extra info via buurtnatuur.be: <i>{description:0}</i>"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"question": "Wat is de Nederlandstalige naam van dit gebied?",
|
|
||||||
"render": "Dit gebied heet {name:nl}"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Dit gebied heeft geen naam"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Wat is de naam van dit gebied?",
|
|
||||||
"render": "Dit gebied heet {name}"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje",
|
"shortDescription": "Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje",
|
||||||
|
@ -368,6 +370,106 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overrideAll": {
|
"overrideAll": {
|
||||||
|
"tagRenderings+": {
|
||||||
|
"0": {
|
||||||
|
"question": "Is er een (onofficiële) website met meer informatie (b.v. met topos)?"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "<span class='subtle'>Een <a href='#{_embedding_feature:id}'>omvattend element</a> geeft aan dat dit <span>publiek toegangkelijk is</span><br/>{_embedding_feature:access:description}"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "<span class='subtle'>Een <a href='#{_embedding_feature:id}'>omvattend element</a> geeft aan dat</span> een toelating nodig is om hier te klimmen<br/>{_embedding_feature:access:description}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"question": "Wat is de (gemiddelde) lengte van de klimroutes, in meter?",
|
||||||
|
"render": "De klimroutes zijn gemiddeld <b>{canonical(climbing:length)}</b> lang"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"question": "Wat is het niveau van de makkelijkste route, volgens het Franse classificatiesysteem?",
|
||||||
|
"render": "De minimale klimmoeilijkheid is {climbing:grade:french:min} volgens het Franse/Belgische systeem"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"question": "Wat is het niveau van de moeilijkste route, volgens het Franse classificatiesysteem?",
|
||||||
|
"render": "De maximale klimmoeilijkheid is {climbing:grade:french:max} volgens het Franse/Belgische systeem"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Bolderen kan hier"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Bolderen kan hier niet"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Bolderen kan hier, maar er zijn niet zoveel routes"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Er zijn hier {climbing:boulder} bolderroutes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is het mogelijk om hier te bolderen?"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Toprope-klimmen kan hier"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Toprope-klimmen kan hier niet"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Er zijn hier {climbing:toprope} toprope routes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is het mogelijk om hier te toprope-klimmen?"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Sportklimmen/voorklimmen kan hier"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Sportklimmen/voorklimmen kan hier niet"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Er zijn hier {climbing:sport} sportklimroutes/voorklimroutes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is het mogelijk om hier te sportklimmen/voorklimmen op reeds aangebrachte haken?"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Traditioneel klimmen kan hier"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Traditioneel klimmen kan hier niet"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Er zijn hier {climbing:traditional} traditionele klimroutes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is het mogelijk om hier traditioneel te klimmen? <br/><span class='subtle'>(Dit is klimmen met klemblokjes en friends)</span>"
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Er is een snelklimmuur voor speed climbing"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Er is geen snelklimmuur voor speed climbing"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Er zijn hier {climbing:speed} snelklimmuren"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Is er een snelklimmuur (speed climbing)?"
|
||||||
|
}
|
||||||
|
},
|
||||||
"units+": {
|
"units+": {
|
||||||
"0": {
|
"0": {
|
||||||
"applicableUnits": {
|
"applicableUnits": {
|
||||||
|
@ -381,106 +483,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
|
||||||
"0": {
|
|
||||||
"question": "Is er een (onofficiële) website met meer informatie (b.v. met topos)?"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "<span class='subtle'>Een <a href='#{_embedding_feature:id}'>omvattend element</a> geeft aan dat dit <span>publiek toegangkelijk is</span><br/>{_embedding_feature:access:description}"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "<span class='subtle'>Een <a href='#{_embedding_feature:id}'>omvattend element</a> geeft aan dat</span> een toelating nodig is om hier te klimmen<br/>{_embedding_feature:access:description}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"question": "Wat is de (gemiddelde) lengte van de klimroutes, in meter?",
|
|
||||||
"render": "De klimroutes zijn gemiddeld <b>{canonical(climbing:length)}</b> lang"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"question": "Wat is het niveau van de makkelijkste route, volgens het Franse classificatiesysteem?",
|
|
||||||
"render": "De minimale klimmoeilijkheid is {climbing:grade:french:min} volgens het Franse/Belgische systeem"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"question": "Wat is het niveau van de moeilijkste route, volgens het Franse classificatiesysteem?",
|
|
||||||
"render": "De maximale klimmoeilijkheid is {climbing:grade:french:max} volgens het Franse/Belgische systeem"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Bolderen kan hier"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Bolderen kan hier niet"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Bolderen kan hier, maar er zijn niet zoveel routes"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Er zijn hier {climbing:boulder} bolderroutes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is het mogelijk om hier te bolderen?"
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Toprope-klimmen kan hier"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Toprope-klimmen kan hier niet"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Er zijn hier {climbing:toprope} toprope routes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is het mogelijk om hier te toprope-klimmen?"
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Sportklimmen/voorklimmen kan hier"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Sportklimmen/voorklimmen kan hier niet"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Er zijn hier {climbing:sport} sportklimroutes/voorklimroutes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is het mogelijk om hier te sportklimmen/voorklimmen op reeds aangebrachte haken?"
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Traditioneel klimmen kan hier"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Traditioneel klimmen kan hier niet"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Er zijn hier {climbing:traditional} traditionele klimroutes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is het mogelijk om hier traditioneel te klimmen? <br/><span class='subtle'>(Dit is klimmen met klemblokjes en friends)</span>"
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"mappings": {
|
|
||||||
"0": {
|
|
||||||
"then": "Er is een snelklimmuur voor speed climbing"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"then": "Er is geen snelklimmuur voor speed climbing"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Er zijn hier {climbing:speed} snelklimmuren"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"question": "Is er een snelklimmuur (speed climbing)?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": "Open klimkaart"
|
"title": "Open klimkaart"
|
||||||
},
|
},
|
||||||
"cycle_infra": {
|
"cycle_infra": {
|
||||||
|
@ -515,27 +517,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"mappings": {
|
||||||
"then": "Deze straat is een fietsstraat (en dus zone 30)"
|
"0": {
|
||||||
|
"then": "Deze straat is een fietsstraat (en dus zone 30)"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Deze straat i een fietsstraat"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Deze straat wordt binnenkort een fietsstraat"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Deze straat is geen fietsstraat"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"1": {
|
"question": "Is deze straat een fietsstraat?"
|
||||||
"then": "Deze straat i een fietsstraat"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"then": "Deze straat wordt binnenkort een fietsstraat"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Deze straat is geen fietsstraat"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"question": "Is deze straat een fietsstraat?"
|
"1": {
|
||||||
},
|
"question": "Wanneer wordt deze straat een fietsstraat?",
|
||||||
"1": {
|
"render": "Deze straat wordt fietsstraat op {cyclestreet:start_date}"
|
||||||
"question": "Wanneer wordt deze straat een fietsstraat?",
|
}
|
||||||
"render": "Deze straat wordt fietsstraat op {cyclestreet:start_date}"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortDescription": "Een kaart met alle gekende fietsstraten",
|
"shortDescription": "Een kaart met alle gekende fietsstraten",
|
||||||
|
|
|
@ -269,24 +269,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roamingRenderings": {
|
"overrideAll": {
|
||||||
"0": {
|
"tagRenderings+": {
|
||||||
"question": "Есть ли (неофициальный) веб-сайт с более подробной информацией (напр., topos)?"
|
"0": {
|
||||||
},
|
"question": "Есть ли (неофициальный) веб-сайт с более подробной информацией (напр., topos)?"
|
||||||
"2": {
|
},
|
||||||
"mappings": {
|
"2": {
|
||||||
"3": {
|
"mappings": {
|
||||||
"then": "Только членам клуба"
|
"3": {
|
||||||
|
"then": "Только членам клуба"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
"9": {
|
||||||
"9": {
|
"mappings": {
|
||||||
"mappings": {
|
"0": {
|
||||||
"0": {
|
"then": "Здесь можно заняться спортивным скалолазанием"
|
||||||
"then": "Здесь можно заняться спортивным скалолазанием"
|
},
|
||||||
},
|
"1": {
|
||||||
"1": {
|
"then": "Спортивное скалолазание здесь невозможно"
|
||||||
"then": "Спортивное скалолазание здесь невозможно"
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -30,7 +30,7 @@
|
||||||
"jspdf": "^2.3.1",
|
"jspdf": "^2.3.1",
|
||||||
"latlon2country": "^1.1.3",
|
"latlon2country": "^1.1.3",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
"leaflet-providers": "^1.10.2",
|
"leaflet-providers": "^1.13.0",
|
||||||
"leaflet-simple-map-screenshoter": "^0.4.4",
|
"leaflet-simple-map-screenshoter": "^0.4.4",
|
||||||
"leaflet.markercluster": "^1.4.1",
|
"leaflet.markercluster": "^1.4.1",
|
||||||
"libphonenumber": "0.0.10",
|
"libphonenumber": "0.0.10",
|
||||||
|
@ -10035,9 +10035,9 @@
|
||||||
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
|
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
|
||||||
},
|
},
|
||||||
"node_modules/leaflet-providers": {
|
"node_modules/leaflet-providers": {
|
||||||
"version": "1.12.0",
|
"version": "1.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.13.0.tgz",
|
||||||
"integrity": "sha512-pU/mR4B+NbayBGCg5/88dmRq7t1EGiNPhsVGV3yqHuDn594vIwus4CiPVW0RtiKJNKg8Vf1pILAbFl0i+yk+lQ=="
|
"integrity": "sha512-f/sN5wdgBbVA2jcCYzScIfYNxKdn2wBJP9bu+5cRX9Xj6g8Bt1G9Sr8WgJAt/ckIFIc3LVVxCBNFpSCfTuUElg=="
|
||||||
},
|
},
|
||||||
"node_modules/leaflet-simple-map-screenshoter": {
|
"node_modules/leaflet-simple-map-screenshoter": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
|
@ -25965,9 +25965,9 @@
|
||||||
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
|
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
|
||||||
},
|
},
|
||||||
"leaflet-providers": {
|
"leaflet-providers": {
|
||||||
"version": "1.12.0",
|
"version": "1.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.13.0.tgz",
|
||||||
"integrity": "sha512-pU/mR4B+NbayBGCg5/88dmRq7t1EGiNPhsVGV3yqHuDn594vIwus4CiPVW0RtiKJNKg8Vf1pILAbFl0i+yk+lQ=="
|
"integrity": "sha512-f/sN5wdgBbVA2jcCYzScIfYNxKdn2wBJP9bu+5cRX9Xj6g8Bt1G9Sr8WgJAt/ckIFIc3LVVxCBNFpSCfTuUElg=="
|
||||||
},
|
},
|
||||||
"leaflet-simple-map-screenshoter": {
|
"leaflet-simple-map-screenshoter": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
"jspdf": "^2.3.1",
|
"jspdf": "^2.3.1",
|
||||||
"latlon2country": "^1.1.3",
|
"latlon2country": "^1.1.3",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
"leaflet-providers": "^1.10.2",
|
"leaflet-providers": "^1.13.0",
|
||||||
"leaflet-simple-map-screenshoter": "^0.4.4",
|
"leaflet-simple-map-screenshoter": "^0.4.4",
|
||||||
"leaflet.markercluster": "^1.4.1",
|
"leaflet.markercluster": "^1.4.1",
|
||||||
"libphonenumber": "0.0.10",
|
"libphonenumber": "0.0.10",
|
||||||
|
|
143
test/Actors.spec.ts
Normal file
143
test/Actors.spec.ts
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
import T from "./TestHelper";
|
||||||
|
import State from "../State";
|
||||||
|
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
|
||||||
|
import SelectedElementTagsUpdater from "../Logic/Actors/SelectedElementTagsUpdater";
|
||||||
|
import UserRelatedState from "../Logic/State/UserRelatedState";
|
||||||
|
import {Utils} from "../Utils";
|
||||||
|
import ScriptUtils from "../scripts/ScriptUtils";
|
||||||
|
import SelectedFeatureHandler from "../Logic/Actors/SelectedFeatureHandler";
|
||||||
|
import {UIEventSource} from "../Logic/UIEventSource";
|
||||||
|
import {ElementStorage} from "../Logic/ElementStorage";
|
||||||
|
import Loc from "../Models/Loc";
|
||||||
|
|
||||||
|
export default class ActorsSpec extends T {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
const latestTags = {
|
||||||
|
"amenity": "public_bookcase",
|
||||||
|
"books": "children;adults",
|
||||||
|
"capacity": "25",
|
||||||
|
"description": "Deze boekenruilkast vindt je recht tegenover de Pim Pam Poem",
|
||||||
|
"image:0": "https://i.imgur.com/Z8a69UG.jpg",
|
||||||
|
"name": "Stubbekwartier-buurtbibliotheek",
|
||||||
|
"nobrand": "yes",
|
||||||
|
"opening_hours": "24/7",
|
||||||
|
"operator": "Huisbewoner",
|
||||||
|
"public_bookcase:type": "reading_box"
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.injectJsonDownloadForTests(
|
||||||
|
"https://www.openstreetmap.org/api/0.6/node/5568693115",
|
||||||
|
{
|
||||||
|
"version": "0.6",
|
||||||
|
"generator": "CGImap 0.8.5 (1815943 spike-06.openstreetmap.org)",
|
||||||
|
"copyright": "OpenStreetMap and contributors",
|
||||||
|
"attribution": "http://www.openstreetmap.org/copyright",
|
||||||
|
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||||
|
"elements": [{
|
||||||
|
"type": "node",
|
||||||
|
"id": 5568693115,
|
||||||
|
"lat": 51.2179199,
|
||||||
|
"lon": 3.2154662,
|
||||||
|
"timestamp": "2021-08-21T16:22:55Z",
|
||||||
|
"version": 6,
|
||||||
|
"changeset": 110034454,
|
||||||
|
"user": "Pieter Vander Vennet",
|
||||||
|
"uid": 3818858,
|
||||||
|
"tags": latestTags
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
super("Actors", [
|
||||||
|
[
|
||||||
|
"download latest version",
|
||||||
|
() => {
|
||||||
|
const state = new UserRelatedState(AllKnownLayouts.allKnownLayouts.get("bookcases"))
|
||||||
|
const feature = {
|
||||||
|
"type": "Feature",
|
||||||
|
"id": "node/5568693115",
|
||||||
|
"properties": {
|
||||||
|
"amenity": "public_bookcase",
|
||||||
|
"books": "children;adults",
|
||||||
|
"capacity": "25",
|
||||||
|
"description": "Deze boekenruilkast vindt je recht tegenover de Pim Pam Poem",
|
||||||
|
"image:0": "https://i.imgur.com/Z8a69UG.jpg",
|
||||||
|
"name": "OUTDATED NAME",
|
||||||
|
"nobrand": "yes",
|
||||||
|
"opening_hours": "24/7",
|
||||||
|
"operator": "Huisbewoner",
|
||||||
|
"public_bookcase:type": "reading_box",
|
||||||
|
"id": "node/5568693115",
|
||||||
|
"_lat": "51.2179199",
|
||||||
|
"_lon": "3.2154662",
|
||||||
|
"fixme": "SOME FIXME"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
3.2154662,
|
||||||
|
51.2179199
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"bbox": {
|
||||||
|
"maxLat": 51.2179199,
|
||||||
|
"maxLon": 3.2154662,
|
||||||
|
"minLat": 51.2179199,
|
||||||
|
"minLon": 3.2154662
|
||||||
|
},
|
||||||
|
"_lon": 3.2154662,
|
||||||
|
"_lat": 51.2179199
|
||||||
|
}
|
||||||
|
state.allElements.addOrGetElement(feature)
|
||||||
|
SelectedElementTagsUpdater.installCallback(state)
|
||||||
|
|
||||||
|
// THis should trigger a download of the latest feaures and update the tags
|
||||||
|
// However, this doesn't work with ts-node for some reason
|
||||||
|
state.selectedElement.setData(feature)
|
||||||
|
|
||||||
|
SelectedElementTagsUpdater.applyUpdate(state, latestTags, feature.properties.id)
|
||||||
|
|
||||||
|
// The name should be updated
|
||||||
|
T.equals("Stubbekwartier-buurtbibliotheek", feature.properties.name)
|
||||||
|
// The fixme should be removed
|
||||||
|
T.equals(undefined, feature.properties.fixme)
|
||||||
|
|
||||||
|
}],
|
||||||
|
["Hash without selected element should download geojson from OSM-API", async () => {
|
||||||
|
const hash = new UIEventSource("node/5568693115")
|
||||||
|
const selected = new UIEventSource(undefined)
|
||||||
|
const loc = new UIEventSource<Loc>({
|
||||||
|
lat: 0,
|
||||||
|
lon: 0,
|
||||||
|
zoom: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
loc.addCallback(_ => {
|
||||||
|
T.equals("node/5568693115", selected.data.properties.id)
|
||||||
|
T.equals(14, loc.data.zoom)
|
||||||
|
T.equals( 51.2179199, loc.data.lat)
|
||||||
|
})
|
||||||
|
|
||||||
|
new SelectedFeatureHandler(hash, {
|
||||||
|
selectedElement: selected,
|
||||||
|
allElements: new ElementStorage(),
|
||||||
|
featurePipeline: undefined,
|
||||||
|
locationControl: loc,
|
||||||
|
layoutToUse: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import {Utils} from "../Utils";
|
||||||
import TileFreshnessCalculatorSpec from "./TileFreshnessCalculator.spec";
|
import TileFreshnessCalculatorSpec from "./TileFreshnessCalculator.spec";
|
||||||
import WikidataSpecTest from "./Wikidata.spec.test";
|
import WikidataSpecTest from "./Wikidata.spec.test";
|
||||||
import ImageProviderSpec from "./ImageProvider.spec";
|
import ImageProviderSpec from "./ImageProvider.spec";
|
||||||
|
import ActorsSpec from "./Actors.spec";
|
||||||
|
|
||||||
|
|
||||||
ScriptUtils.fixUtils()
|
ScriptUtils.fixUtils()
|
||||||
|
@ -27,7 +28,8 @@ const allTests = [
|
||||||
new SplitActionSpec(),
|
new SplitActionSpec(),
|
||||||
new TileFreshnessCalculatorSpec(),
|
new TileFreshnessCalculatorSpec(),
|
||||||
new WikidataSpecTest(),
|
new WikidataSpecTest(),
|
||||||
new ImageProviderSpec()
|
new ImageProviderSpec(),
|
||||||
|
new ActorsSpec()
|
||||||
]
|
]
|
||||||
|
|
||||||
Utils.externalDownloadFunction = async (url) => {
|
Utils.externalDownloadFunction = async (url) => {
|
||||||
|
|
|
@ -19,6 +19,7 @@ export default class T {
|
||||||
try {
|
try {
|
||||||
test();
|
test();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log("ERROR: ", e, e.stack)
|
||||||
failures.push({testsuite: this.name, name: name, msg: "" + e});
|
failures.push({testsuite: this.name, name: name, msg: "" + e});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue