Small fixes

This commit is contained in:
pietervdvn 2021-04-23 17:22:01 +02:00
parent 5c0e3662c1
commit 3e3da25edb
18 changed files with 263 additions and 103 deletions

2
.gitignore vendored
View file

@ -11,4 +11,4 @@ assets/generated/*
.parcel-cache .parcel-cache
Docs/Tools/stats.*.json Docs/Tools/stats.*.json
Docs/Tools/stats.csv Docs/Tools/stats.csv
missing_translations.txt

View file

@ -375,8 +375,8 @@ export class InitUiElements {
state.layoutToUse.map(layoutToUse => { state.layoutToUse.map(layoutToUse => {
const flayers = []; const flayers = [];
for (const layer of layoutToUse.layers) { for (const layer of layoutToUse.layers) {
const isDisplayed = QueryParameters.GetQueryParameter("layer-" + layer.id, "true", "Wether or not layer " + layer.id + " is shown") const isDisplayed = QueryParameters.GetQueryParameter("layer-" + layer.id, "true", "Wether or not layer " + layer.id + " is shown")
.map<boolean>((str) => str !== "false", [], (b) => b.toString()); .map<boolean>((str) => str !== "false", [], (b) => b.toString());
const flayer = { const flayer = {

View file

@ -3,9 +3,9 @@ import {UIEventSource} from "../UIEventSource";
import {Review} from "./Review"; import {Review} from "./Review";
export class MangroveIdentity { export class MangroveIdentity {
private readonly _mangroveIdentity: UIEventSource<string>;
public keypair: any = undefined; public keypair: any = undefined;
public readonly kid: UIEventSource<string> = new UIEventSource<string>(undefined); public readonly kid: UIEventSource<string> = new UIEventSource<string>(undefined);
private readonly _mangroveIdentity: UIEventSource<string>;
constructor(mangroveIdentity: UIEventSource<string>) { constructor(mangroveIdentity: UIEventSource<string>) {
const self = this; const self = this;
@ -26,7 +26,7 @@ export class MangroveIdentity {
if ((mangroveIdentity.data ?? "") === "") { if ((mangroveIdentity.data ?? "") === "") {
this.CreateIdentity(); this.CreateIdentity();
} }
}catch(e){ } catch (e) {
console.error("Could not create identity: ", e) console.error("Could not create identity: ", e)
} }
} }
@ -53,46 +53,47 @@ export class MangroveIdentity {
} }
export default class MangroveReviews { export default class MangroveReviews {
private static _reviewsCache = {};
private static didWarn = false;
private readonly _lon: number; private readonly _lon: number;
private readonly _lat: number; private readonly _lat: number;
private readonly _name: string; private readonly _name: string;
private readonly _reviews: UIEventSource<Review[]> = new UIEventSource<Review[]>([]); private readonly _reviews: UIEventSource<Review[]> = new UIEventSource<Review[]>([]);
private _dryRun: boolean; private _dryRun: boolean;
private _mangroveIdentity: MangroveIdentity; private _mangroveIdentity: MangroveIdentity;
private _lastUpdate : Date = undefined; private _lastUpdate: Date = undefined;
private constructor(lon: number, lat: number, name: string,
identity: MangroveIdentity,
dryRun?: boolean) {
private static _reviewsCache = {};
public static Get(lon: number, lat: number, name: string,
identity: MangroveIdentity,
dryRun?: boolean){
const newReviews = new MangroveReviews(lon, lat, name, identity, dryRun);
const uri = newReviews.GetSubjectUri();
const cached = MangroveReviews._reviewsCache[uri];
if(cached !== undefined){
return cached;
}
MangroveReviews._reviewsCache[uri] = newReviews;
return newReviews;
}
private constructor(lon: number, lat: number, name: string,
identity: MangroveIdentity,
dryRun?: boolean) {
this._lon = lon; this._lon = lon;
this._lat = lat; this._lat = lat;
this._name = name; this._name = name;
this._mangroveIdentity = identity; this._mangroveIdentity = identity;
this._dryRun = dryRun; this._dryRun = dryRun;
if(dryRun){ if (dryRun && !MangroveReviews.didWarn) {
MangroveReviews.didWarn = true;
console.warn("Mangrove reviews will _not_ be saved as dryrun is specified") console.warn("Mangrove reviews will _not_ be saved as dryrun is specified")
} }
} }
public static Get(lon: number, lat: number, name: string,
identity: MangroveIdentity,
dryRun?: boolean) {
const newReviews = new MangroveReviews(lon, lat, name, identity, dryRun);
const uri = newReviews.GetSubjectUri();
const cached = MangroveReviews._reviewsCache[uri];
if (cached !== undefined) {
return cached;
}
MangroveReviews._reviewsCache[uri] = newReviews;
return newReviews;
}
/** /**
* Gets an URI which represents the item in a mangrove-compatible way * Gets an URI which represents the item in a mangrove-compatible way
* @constructor * @constructor
@ -111,10 +112,10 @@ export default class MangroveReviews {
* Note: rating is between 1 and 100 * Note: rating is between 1 and 100
*/ */
public GetReviews(): UIEventSource<Review[]> { public GetReviews(): UIEventSource<Review[]> {
if(this._lastUpdate !== undefined && this._reviews.data !== undefined && if (this._lastUpdate !== undefined && this._reviews.data !== undefined &&
(new Date().getTime() - this._lastUpdate.getTime()) < 15000 (new Date().getTime() - this._lastUpdate.getTime()) < 15000
){ ) {
// Last update was pretty recent // Last update was pretty recent
return this._reviews; return this._reviews;
} }
@ -140,7 +141,6 @@ export default class MangroveReviews {
rating: r.rating // percentage points rating: r.rating // percentage points
}; };
(rev.made_by_user ? reviewsByUser : reviews).push(rev); (rev.made_by_user ? reviewsByUser : reviews).push(rev);
} }

View file

@ -2,7 +2,7 @@ import { Utils } from "../Utils";
export default class Constants { export default class Constants {
public static vNumber = "0.6.11a"; public static vNumber = "0.6.11b";
// The user journey states thresholds when a new feature gets unlocked // The user journey states thresholds when a new feature gets unlocked
public static userJourney = { public static userJourney = {

View file

@ -1,4 +1,3 @@
import {UIElement} from "../UIElement";
import Combine from "../Base/Combine"; import Combine from "../Base/Combine";
import Translations from "../i18n/Translations"; import Translations from "../i18n/Translations";
import Attribution from "./Attribution"; import Attribution from "./Attribution";
@ -8,9 +7,8 @@ import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
import {FixedUiElement} from "../Base/FixedUiElement"; import {FixedUiElement} from "../Base/FixedUiElement";
import * as licenses from "../../assets/generated/license_info.json" import * as licenses from "../../assets/generated/license_info.json"
import SmallLicense from "../../Models/smallLicense"; import SmallLicense from "../../Models/smallLicense";
import {Icon} from "leaflet";
import Img from "../Base/Img";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import Link from "../Base/Link";
/** /**
* The attribution panel shown on mobile * The attribution panel shown on mobile
@ -48,12 +46,25 @@ export default class AttributionPanel extends Combine {
return undefined; return undefined;
} }
const sources =Utils.NoNull(Utils.NoEmpty(license.sources))
return new Combine([ return new Combine([
`<img src='${iconPath}' style="width: 50px; height: 50px; margin-right: 0.5em;">`, `<img src='${iconPath}' style="width: 50px; height: 50px; margin-right: 0.5em;">`,
new Combine([ new Combine([
new FixedUiElement(license.authors.join("; ")).SetClass("font-bold"), new FixedUiElement(license.authors.join("; ")).SetClass("font-bold"),
new Combine([license.license, license.sources.length > 0 ? " - " : "", new Combine([license.license,
...license.sources.map(link => `<a href='${link}' target="_blank">${new URL(link).hostname}</a> `)]).SetClass("block") sources.length > 0 ? " - " : "",
... sources.map(lnk => {
let sourceLinkContent = lnk;
try{
sourceLinkContent = new URL(lnk).hostname
}catch{
console.error("Not a valid URL:", lnk)
}
return new Link(sourceLinkContent, lnk, true);
})
]
).SetClass("block")
]).SetClass("flex flex-col") ]).SetClass("flex flex-col")
]).SetClass("flex") ]).SetClass("flex")
} }

View file

@ -117,6 +117,12 @@ export class SubstitutedTranslation extends UIElement {
} }
} }
// Let's to a small sanity check to help the theme designers:
if(template.search(/{[^}]+\([^}]*\)}/) >= 0){
// Hmm, we might have found an invalid rendering name
console.warn("Found a suspicious special rendering value in: ", template, " did you mean one of: ", SpecialVisualizations.specialVisualizations.map(sp => sp.funcName+"()").join(", "))
}
// IF we end up here, no changes have to be made - except to remove any resting {} // IF we end up here, no changes have to be made - except to remove any resting {}
return [new FixedUiElement(template.replace(/{.*}/g, ""))]; return [new FixedUiElement(template.replace(/{.*}/g, ""))];
} }

View file

@ -20,6 +20,7 @@ export class Translation extends UIElement {
for (const translationsKey in translations) { for (const translationsKey in translations) {
count++; count++;
if (typeof (translations[translationsKey]) != "string") { if (typeof (translations[translationsKey]) != "string") {
console.error("Non-string object in translation: ", translations[translationsKey])
throw "Error in an object depicting a translation: a non-string object was found. (" + context + ")\n You probably put some other section accidentally in the translation" throw "Error in an object depicting a translation: a non-string object was found. (" + context + ")\n You probably put some other section accidentally in the translation"
} }
} }

View file

@ -32,7 +32,7 @@
] ]
}, },
"icon": "./assets/themes/playgrounds/playground.svg", "icon": "./assets/themes/playgrounds/playground.svg",
"iconSize": "40,40,bottom", "iconSize": "40,40,center",
"width": "1", "width": "1",
"color": "#0f0", "color": "#0f0",
"wayHandling": 2, "wayHandling": 2,

View file

@ -335,7 +335,8 @@
{ {
"#": "Surface area", "#": "Surface area",
"render": { "render": {
"en": "Surface area: {_surface:ha}Ha" "en": "Surface area: {_surface:ha}Ha",
"nl": "Totale oppervlakte: {_surface:ha}Ha"
}, },
"mappings":[ { "mappings":[ {
"if": "_surface:ha=0", "if": "_surface:ha=0",

View file

@ -13,6 +13,9 @@
] ]
} }
}, },
"calculatedTags": [
"_size_classification=Number(feat.properties._surface) < 10 ? 'small' : (Number(feat.properties._surface) < 100 ? 'medium' : 'large') "
],
"description": { "description": {
"nl": "Speeltuinen", "nl": "Speeltuinen",
"en": "Playgrounds" "en": "Playgrounds"
@ -331,7 +334,25 @@
"render": "1" "render": "1"
}, },
"iconSize": { "iconSize": {
"render": "40,40,center" "render": "40,40,center",
"mappings": [
{
"if": "id~node/.*",
"then": "40,40,center"
},
{
"if": "_size_classification=small",
"then": "25,25,center"
},
{
"if": "_size_classification=medium",
"then": "40,40,center"
},
{
"if": "_size_classification=large",
"then": "60,60,center"
}
]
}, },
"color": { "color": {
"render": "#0c3" "render": "#0c3"

View file

@ -1,13 +1,112 @@
[ [
{ {
"authors": [ "authors": [
"@fontawesome" "Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
], ],
"path": "tabletennis.svg", "path": "baseball.svg",
"license": "CC-BY 4.0", "license": "CC-BY-SA 4.0",
"sources": [ "sources": [
"https://commons.wikimedia.org/wiki/File:Font_Awesome_5_solid_table-tennis.svg", "https://createlli.com/",
" https://fontawesome.com" "https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "basketball.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "beachvolleyball.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "boules.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "skateboard.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": ".svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "soccer.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "table_tennis.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "tennis.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
]
},
{
"authors": [
"Gitte Loos (Createlli) in opdracht van Provincie Antwerpen "
],
"path": "volleyball.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://createlli.com/",
"https://www.provincieantwerpen.be/"
] ]
} }
] ]

View file

@ -4,7 +4,7 @@
"nl": "Sportterrein", "nl": "Sportterrein",
"en": "Sport pitches" "en": "Sport pitches"
}, },
"wayHandling": 2, "wayHandling": 1,
"minzoom": 12, "minzoom": 12,
"source": { "source": {
"osmTags": { "osmTags": {
@ -13,6 +13,9 @@
] ]
} }
}, },
"calculatedTags": [
"_size_classification=Number(feat.properties._surface) < 200 ? 'small' : (Number(feat.properties._surface) < 750 ? 'medium' : 'large') "
],
"title": { "title": {
"render": { "render": {
"nl": "Sportterrein", "nl": "Sportterrein",
@ -264,7 +267,7 @@
"nl": "Wanneer is dit sportveld toegankelijk?", "nl": "Wanneer is dit sportveld toegankelijk?",
"en": "When is this pitch accessible?" "en": "When is this pitch accessible?"
}, },
"render": "{opening_hours()}", "render": "Openingsuren: {opening_hours_table()}",
"freeform": { "freeform": {
"key": "opening_hours", "key": "opening_hours",
"type": "opening_hours" "type": "opening_hours"
@ -292,7 +295,25 @@
], ],
"hideUnderlayingFeaturesMinPercentage": 0, "hideUnderlayingFeaturesMinPercentage": 0,
"icon": { "icon": {
"render": "circle:white;./assets/layers/sport_pitch/tabletennis.svg" "render": "./assets/layers/sport_pitch/basketball.svg",
"mappings": [
{
"if": {
"or": [
"sport=baseball",
"sport=basketball",
"sport=beachvolleyball",
"sport=boules",
"sport=skateboard",
"sport=soccer",
"sport=table_tennis",
"sport=tennis",
"sport=volleyball"
]
},
"then": "./assets/layers/sport_pitch/{sport}.svg"
}
]
}, },
"iconOverlays": [ "iconOverlays": [
{ {
@ -310,7 +331,24 @@
"render": "1" "render": "1"
}, },
"iconSize": { "iconSize": {
"render": "25,25,center" "render": "25,25,center",
"mappings": [
{
"if": {
"or": ["_size_classification=medium","id~node/.*"]
},
"then": "40,40,center"
},
{
"if": "_size_classification=small",
"then": "25,25,center"
},
{
"if": "_size_classification=large",
"then": "50,50,center"
}
]
}, },
"color": { "color": {
"render": "#009" "render": "#009"

View file

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496.2 296.5C527.7 218.7 512 126.2 449 63.1 365.1-21 229-21 145.1 63.1l-56 56.1 211.5 211.5c46.1-62.1 131.5-77.4 195.6-34.2zm-217.9 79.7L57.9 155.9c-27.3 45.3-21.7 105 17.3 144.1l34.5 34.6L6.7 424c-8.6 7.5-9.1 20.7-1 28.8l53.4 53.5c8 8.1 21.2 7.6 28.7-1L177.1 402l35.7 35.7c19.7 19.7 44.6 30.5 70.3 33.3-7.1-17-11-35.6-11-55.1-.1-13.8 2.5-27 6.2-39.7zM416 320c-53 0-96 43-96 96s43 96 96 96 96-43 96-96-43-96-96-96z"/></svg>
<!--
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->

Before

Width:  |  Height:  |  Size: 669 B

View file

@ -21,7 +21,7 @@
] ]
}, },
"icon": "./assets/themes/playgrounds/playground.svg", "icon": "./assets/themes/playgrounds/playground.svg",
"iconSize": "40,40,bottom", "iconSize": "40,40,center",
"width": "1", "width": "1",
"color": "#0f0", "color": "#0f0",
"wayHandling": 2, "wayHandling": 2,

View file

@ -33,9 +33,7 @@
], ],
"path": "social_image_front.png", "path": "social_image_front.png",
"license": "CC-BY-SA", "license": "CC-BY-SA",
"sources": [ "sources": []
""
]
}, },
{ {
"authors": [ "authors": [

View file

@ -6,7 +6,7 @@
"path": "SocialImageForeground.svg", "path": "SocialImageForeground.svg",
"license": "CC-BY-SA", "license": "CC-BY-SA",
"sources": [ "sources": [
"" "https://mapcomplete.osm.be"
] ]
}, },
{ {
@ -15,9 +15,7 @@
], ],
"path": "add.svg", "path": "add.svg",
"license": "CC0", "license": "CC0",
"sources": [ "sources": []
""
]
}, },
{ {
"authors": [ "authors": [
@ -354,7 +352,7 @@
"path": "mapcomplete_logo.svg", "path": "mapcomplete_logo.svg",
"license": "Logo; CC-BY-SA", "license": "Logo; CC-BY-SA",
"sources": [ "sources": [
"" "https://mapcomplete.osm.be"
] ]
}, },
{ {

View file

@ -30,58 +30,39 @@
"source": { "source": {
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson", "geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14 "geoJsonZoomLevel": 14
} },
"icon": "./assets/themes/speelplekken/speelbos.svg"
} }
}, },
{ {
"builtin": "playground", "builtin": "playground",
"override": { "override": {
"source": { "icon": "./assets/themes/speelplekken/speeltuin.svg"
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14
}
}
},
{
"builtin": "sport_pitch",
"override": {
"minzoom": 15,
"source": {
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14
}
}
},
{
"builtin": "slow_roads",
"override": {
"source": {
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14
},
"calculatedTags": [
"_part_of_walking_routes=feat.memberships().map(r => \"<a href='#relation/\"+r.relation.id+\"'>\" + r.relation.tags.name + \"</a>\").join(', ')"
]
}
},
{
"builtin": "grass_in_parks",
"override": {
"source": {
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14
}
} }
}, },
{ {
"builtin": "village_green", "builtin": "village_green",
"override": { "override": {
"source": { "icon": "./assets/themes/speelplekken/speelweide.svg"
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14
}
} }
}, },
{
"builtin": "grass_in_parks",
"override": {
"icon": "./assets/themes/speelplekken/speelweide.svg"
}
},
"sport_pitch",
{
"builtin": "slow_roads",
"override": {
"calculatedTags": [
"_part_of_walking_routes=feat.memberships().map(r => \"<a href='#relation/\"+r.relation.id+\"'>\" + r.relation.tags.name + \"</a>\").join(', ')"
]
}
},
{ {
"id": "walking_routes", "id": "walking_routes",
"name": { "name": {
@ -190,6 +171,12 @@
} }
} }
], ],
"overrideAll": {
"source": {
"geoJson": "https://pietervdvn.github.io/speelplekken_cache/speelplekken_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 14
}
},
"roamingRenderings": [ "roamingRenderings": [
{ {
"render": "Maakt deel uit van {_part_of_walking_routes}", "render": "Maakt deel uit van {_part_of_walking_routes}",

View file

@ -13,6 +13,9 @@ Utils.runningFromConsole = true;
function generateLicenseInfos(paths: string[]): SmallLicense[] { function generateLicenseInfos(paths: string[]): SmallLicense[] {
const licenses = [] const licenses = []
for (const path of paths) { for (const path of paths) {
try{
const parsed = JSON.parse(readFileSync(path, "UTF-8")) const parsed = JSON.parse(readFileSync(path, "UTF-8"))
if (Array.isArray(parsed)) { if (Array.isArray(parsed)) {
const l: SmallLicense[] = parsed const l: SmallLicense[] = parsed
@ -30,6 +33,8 @@ function generateLicenseInfos(paths: string[]): SmallLicense[] {
smallLicens.path = path.substring(0, 1 + path.lastIndexOf("/")) + smallLicens.path smallLicens.path = path.substring(0, 1 + path.lastIndexOf("/")) + smallLicens.path
licenses.push(smallLicens) licenses.push(smallLicens)
}}catch(e){
console.error("Error: ",e, "while handling",path)
} }
} }