Merge develop

This commit is contained in:
pietervdvn 2021-04-10 16:12:40 +02:00
commit 2ad72ae346
95 changed files with 2856 additions and 594 deletions

View file

@ -0,0 +1,31 @@
name: Pull request check
on:
pull_request:
types: [opened, edited, synchronize, ready_for_review, review_requested]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v1.2.0
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
- name: install deps
run: npm install
- name: create generated dir
run: mkdir ./assets/generated
- name: create stub themes
run: "echo '{\"layers\": [], \"themes\": []}' > ./assets/generated/known_layers_and_themes.json"
- name: Compile license info; creates missing_licenses.txt if any missing
run: npm run validate:licenses
- name: Compile and validate themes and layers; creates layer_report.txt if any errors are found
run: npm run validate:layeroverview

32
.github/workflows/theme_validation.yml vendored Normal file
View file

@ -0,0 +1,32 @@
name: Theme Validation
on:
push:
branches:
- develop
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v1.2.0
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
- name: install deps
run: npm install
- name: create generated dir
run: mkdir ./assets/generated
- name: create stub themes
run: "echo '{\"layers\": [], \"themes\": []}' > ./assets/generated/known_layers_and_themes.json"
- name: Compile license info
run: npm run generate:licenses
- name: Compile themes and layers
run: npm run generate:layeroverview

File diff suppressed because one or more lines are too long

View file

@ -1,90 +1,35 @@
import * as drinkingWater from "../assets/layers/drinking_water/drinking_water.json";
import * as ghostbikes from "../assets/layers/ghost_bike/ghost_bike.json"
import * as viewpoint from "../assets/layers/viewpoint/viewpoint.json"
import * as bike_parking from "../assets/layers/bike_parking/bike_parking.json"
import * as bike_repair_station from "../assets/layers/bike_repair_station/bike_repair_station.json"
import * as birdhides from "../assets/layers/bird_hide/birdhides.json"
import * as nature_reserve from "../assets/layers/nature_reserve/nature_reserve.json"
import * as bike_cafes from "../assets/layers/bike_cafe/bike_cafes.json"
import * as bike_monitoring_station from "../assets/layers/bike_monitoring_station/bike_monitoring_station.json"
import * as cycling_themed_objects from "../assets/layers/cycling_themed_object/cycling_themed_objects.json"
import * as bike_shops from "../assets/layers/bike_shop/bike_shop.json"
import * as bike_cleaning from "../assets/layers/bike_cleaning/bike_cleaning.json"
import * as bicycle_library from "../assets/layers/bicycle_library/bicycle_library.json"
import * as bicycle_tube_vending_machine from "../assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json"
import * as maps from "../assets/layers/maps/maps.json"
import * as information_boards from "../assets/layers/information_board/information_board.json"
import * as direction from "../assets/layers/direction/direction.json"
import * as surveillance_camera from "../assets/layers/surveillance_cameras/surveillance_cameras.json"
import * as toilets from "../assets/layers/toilets/toilets.json"
import * as bookcases from "../assets/layers/public_bookcases/public_bookcases.json"
import * as tree_nodes from "../assets/layers/trees/tree_nodes.json"
import * as benches from "../assets/layers/benches/benches.json"
import * as benches_at_pt from "../assets/layers/benches/benches_at_pt.json"
import * as picnic_tables from "../assets/layers/benches/picnic_tables.json"
import * as play_forest from "../assets/layers/play_forest/play_forest.json"
import * as playground from "../assets/layers/playground/playground.json"
import * as sport_pitch from "../assets/layers/sport_pitch/sport_pitch.json"
import * as slow_roads from "../assets/layers/slow_roads/slow_roads.json"
import LayerConfig from "./JSON/LayerConfig"; import LayerConfig from "./JSON/LayerConfig";
import {LayerConfigJson} from "./JSON/LayerConfigJson"; import {LayerConfigJson} from "./JSON/LayerConfigJson";
import * as grass_in_parks from "../assets/layers/village_green/grass_in_parks.json" import * as known_layers from "../assets/generated/known_layers_and_themes.json"
import * as village_green from "../assets/layers/village_green/village_green.json" import {Utils} from "../Utils";
export default class AllKnownLayers { export default class AllKnownLayers {
private static sharedLayersListRaw : LayerConfigJson[] = [
drinkingWater,
ghostbikes,
viewpoint,
bike_parking,
bike_repair_station,
bike_monitoring_station,
birdhides,
nature_reserve,
bike_cafes,
bicycle_library,
cycling_themed_objects,
bike_shops,
bike_cleaning,
bicycle_tube_vending_machine,
maps,
direction,
information_boards,
toilets,
bookcases,
surveillance_camera,
tree_nodes,
benches,
benches_at_pt,
picnic_tables,
play_forest,
playground,
sport_pitch,
slow_roads,
grass_in_parks,
village_green
];
// Must be below the list... // Must be below the list...
public static sharedLayers: Map<string, LayerConfig> = AllKnownLayers.getSharedLayers(); public static sharedLayers: Map<string, LayerConfig> = AllKnownLayers.getSharedLayers();
public static sharedLayersJson: Map<string, any> = AllKnownLayers.getSharedLayersJson(); public static sharedLayersJson: Map<string, any> = AllKnownLayers.getSharedLayersJson();
private static sharedLayersListRaw: LayerConfigJson[] = known_layers.layers;
private static getSharedLayers(): Map<string, LayerConfig> { private static getSharedLayers(): Map<string, LayerConfig> {
const sharedLayers = new Map<string, LayerConfig>(); const sharedLayers = new Map<string, LayerConfig>();
for (const layer of AllKnownLayers.sharedLayersListRaw) { for (const layer of known_layers.layers) {
try {
const parsed = new LayerConfig(layer, "shared_layers") const parsed = new LayerConfig(layer, "shared_layers")
sharedLayers.set(layer.id, parsed); sharedLayers.set(layer.id, parsed);
sharedLayers[layer.id] = parsed; sharedLayers[layer.id] = parsed;
} catch (e) {
if (!Utils.runningFromConsole) {
console.error("CRITICAL: Could not parse a layer configuration!", layer.id, " due to", e)
}
}
} }
return sharedLayers; return sharedLayers;
} }
private static getSharedLayersJson(): Map<string, any> { private static getSharedLayersJson(): Map<string, any> {
const sharedLayers = new Map<string, any>(); const sharedLayers = new Map<string, any>();
for (const layer of AllKnownLayers.sharedLayersListRaw) { for (const layer of known_layers.layers) {
sharedLayers.set(layer.id, layer); sharedLayers.set(layer.id, layer);
sharedLayers[layer.id] = layer; sharedLayers[layer.id] = layer;
} }

View file

@ -1,74 +1,29 @@
import * as bookcases from "../assets/themes/bookcases/Bookcases.json";
import * as aed from "../assets/themes/aed/aed.json";
import * as toilets from "../assets/themes/toilets/toilets.json";
import * as artworks from "../assets/themes/artwork/artwork.json";
import * as cyclestreets from "../assets/themes/cyclestreets/cyclestreets.json";
import * as ghostbikes from "../assets/themes/ghostbikes/ghostbikes.json"
import * as cyclofix from "../assets/themes/cyclofix/cyclofix.json"
import * as buurtnatuur from "../assets/themes/buurtnatuur/buurtnatuur.json"
import * as nature from "../assets/themes/nature/nature.json"
import * as maps from "../assets/themes/maps/maps.json"
import * as shops from "../assets/themes/shops/shops.json"
import * as bike_monitoring_stations from "../assets/themes/bike_monitoring_station/bike_monitoring_stations.json"
import * as fritures from "../assets/themes/fritures/fritures.json"
import * as benches from "../assets/themes/benches/benches.json";
import * as charging_stations from "../assets/themes/charging_stations/charging_stations.json"
import * as widths from "../assets/themes/widths/width.json"
import * as drinking_water from "../assets/themes/drinking_water/drinking_water.json"
import * as climbing from "../assets/themes/climbing/climbing.json"
import * as surveillance_cameras from "../assets/themes/surveillance_cameras/surveillance_cameras.json"
import * as trees from "../assets/themes/trees/trees.json"
import * as personal from "../assets/themes/personalLayout/personalLayout.json"
import * as playgrounds from "../assets/themes/playgrounds/playgrounds.json"
import * as bicycle_lib from "../assets/themes/bicycle_library/bicycle_library.json"
import * as campersites from "../assets/themes/campersites/campersites.json"
import * as play_forests from "../assets/themes/play_forests/play_forests.json"
import * as speelplekken from "../assets/themes/speelplekken/speelplekken.json"
import * as sport_pitches from "../assets/themes/sport_pitches/sport_pitches.json"
import * as grb from "../assets/themes/grb.json"
import * as facadegardens from "../assets/themes/facadegardens/facadegardens.json"
import LayerConfig from "./JSON/LayerConfig";
import LayoutConfig from "./JSON/LayoutConfig"; import LayoutConfig from "./JSON/LayoutConfig";
import AllKnownLayers from "./AllKnownLayers"; import AllKnownLayers from "./AllKnownLayers";
import * as known_themes from "../assets/generated/known_layers_and_themes.json"
import {LayoutConfigJson} from "./JSON/LayoutConfigJson";
import * as all_layouts from "../assets/generated/known_layers_and_themes.json"
export class AllKnownLayouts { export class AllKnownLayouts {
public static allLayers: Map<string, LayerConfig> = undefined;
public static layoutsList: LayoutConfig[] = [
new LayoutConfig(personal),
AllKnownLayouts.GenerateCycloFix(),
new LayoutConfig(aed),
new LayoutConfig(bookcases),
new LayoutConfig(toilets),
new LayoutConfig(artworks),
new LayoutConfig(ghostbikes),
new LayoutConfig(shops),
new LayoutConfig(drinking_water),
new LayoutConfig(nature),
new LayoutConfig(cyclestreets),
new LayoutConfig(bicycle_lib),
new LayoutConfig(maps),
new LayoutConfig(fritures),
new LayoutConfig(benches),
new LayoutConfig(charging_stations),
new LayoutConfig(widths),
new LayoutConfig(buurtnatuur),
new LayoutConfig(bike_monitoring_stations),
new LayoutConfig(surveillance_cameras),
new LayoutConfig(climbing),
new LayoutConfig(playgrounds),
new LayoutConfig(trees),
new LayoutConfig(campersites),
new LayoutConfig(play_forests),
new LayoutConfig(speelplekken),
new LayoutConfig(sport_pitches),
new LayoutConfig(grb),
new LayoutConfig(facadegardens)
];
public static allSets: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts();
private static GenerateCycloFix(): LayoutConfig { public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts();
const layout = new LayoutConfig(cyclofix) public static layoutsList: LayoutConfig[] = AllKnownLayouts.GenerateOrderedList(AllKnownLayouts.allKnownLayouts);
private static GenerateOrderedList(allKnownLayouts: Map<string, LayoutConfig>): LayoutConfig[] {
const keys = ["personal", "cyclofix", "bookcases", "toilets", "aed"]
const list = []
for (const key of keys) {
list.push(allKnownLayouts.get(key))
}
allKnownLayouts.forEach((layout, key) => {
if (keys.indexOf(key) < 0) {
list.push(layout)
}
})
return list;
}
private static AddGhostBikes(layout: LayoutConfig): LayoutConfig {
const now = new Date(); const now = new Date();
const m = now.getMonth() + 1; const m = now.getMonth() + 1;
const day = new Date().getDate() + 1; const day = new Date().getDate() + 1;
@ -86,8 +41,15 @@ export class AllKnownLayouts {
} }
private static AllLayouts(): Map<string, LayoutConfig> { private static AllLayouts(): Map<string, LayoutConfig> {
this.allLayers = new Map<string, LayerConfig>(); const dict: Map<string, LayoutConfig> = new Map();
for (const layout of this.layoutsList) { for (const layoutConfigJson of known_themes.themes) {
const layout = new LayoutConfig(layoutConfigJson, true)
if (layout.id === "cyclofix") {
AllKnownLayouts.AddGhostBikes(layout)
}
dict.set(layout.id, layout)
for (let i = 0; i < layout.layers.length; i++) { for (let i = 0; i < layout.layers.length; i++) {
let layer = layout.layers[i]; let layer = layout.layers[i];
if (typeof (layer) === "string") { if (typeof (layer) === "string") {
@ -98,20 +60,9 @@ export class AllKnownLayouts {
} }
} }
if (this.allLayers[layer.id] !== undefined) {
continue;
}
this.allLayers[layer.id] = layer;
this.allLayers[layer.id.toLowerCase()] = layer;
} }
} }
return dict;
const allSets: Map<string, LayoutConfig> = new Map();
for (const layout of this.layoutsList) {
allSets[layout.id] = layout;
allSets[layout.id.toLowerCase()] = layout;
}
return allSets;
} }
} }

View file

@ -7,6 +7,7 @@ import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
import {Translation} from "../../UI/i18n/Translation"; import {Translation} from "../../UI/i18n/Translation";
import Img from "../../UI/Base/Img"; import Img from "../../UI/Base/Img";
import Svg from "../../Svg"; import Svg from "../../Svg";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import Combine from "../../UI/Base/Combine"; import Combine from "../../UI/Base/Combine";
import {VariableUiElement} from "../../UI/Base/VariableUIElement"; import {VariableUiElement} from "../../UI/Base/VariableUIElement";
@ -18,7 +19,6 @@ import SourceConfig from "./SourceConfig";
import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import {TagsFilter} from "../../Logic/Tags/TagsFilter";
import {Tag} from "../../Logic/Tags/Tag"; import {Tag} from "../../Logic/Tags/Tag";
import SubstitutingTag from "../../Logic/Tags/SubstitutingTag"; import SubstitutingTag from "../../Logic/Tags/SubstitutingTag";
export default class LayerConfig { export default class LayerConfig {
@ -452,5 +452,23 @@ export default class LayerConfig {
}; };
} }
public ExtractImages(): Set<string> {
const parts: Set<string>[] = []
parts.push(...this.tagRenderings?.map(tr => tr.ExtractImages(false)))
parts.push(...this.titleIcons?.map(tr => tr.ExtractImages(true)))
parts.push(this.icon?.ExtractImages(true))
parts.push(...this.iconOverlays?.map(overlay => overlay.then.ExtractImages(true)))
for (const preset of this.presets) {
parts.push(new Set<string>(preset.description?.ExtractImages(false)))
}
const allIcons = new Set<string>();
for (const part of parts) {
part?.forEach(allIcons.add, allIcons)
}
return allIcons;
}
} }

View file

@ -9,6 +9,7 @@ import {Utils} from "../../Utils";
export default class LayoutConfig { export default class LayoutConfig {
public readonly id: string; public readonly id: string;
public readonly maintainer: string; public readonly maintainer: string;
public readonly credits?: string;
public readonly changesetmessage?: string; public readonly changesetmessage?: string;
public readonly version: string; public readonly version: string;
public readonly language: string[]; public readonly language: string[];
@ -48,6 +49,7 @@ export default class LayoutConfig {
this.id = json.id; this.id = json.id;
context = (context ?? "") + "." + this.id; context = (context ?? "") + "." + this.id;
this.maintainer = json.maintainer; this.maintainer = json.maintainer;
this.credits = json.credits;
this.changesetmessage = json.changesetmessage; this.changesetmessage = json.changesetmessage;
this.version = json.version; this.version = json.version;
this.language = []; this.language = [];
@ -182,4 +184,14 @@ export default class LayoutConfig {
custom.splice(0, 0, msg); custom.splice(0, 0, msg);
return custom; return custom;
} }
public ExtractImages() : Set<string>{
const icons = new Set<string>()
for (const layer of this.layers) {
layer.ExtractImages().forEach(icons.add, icons)
}
icons.add(this.icon)
icons.add(this.socialImage)
return icons
}
} }

View file

@ -24,6 +24,12 @@ export interface LayoutConfigJson {
* 'cyclestreets' which become 'cyclestreets.html' * 'cyclestreets' which become 'cyclestreets.html'
*/ */
id: string; id: string;
/**
* Who helped to create this theme and should be attributed?
*/
credits?: string;
/** /**
* Who does maintian this preset? * Who does maintian this preset?
*/ */

View file

@ -70,7 +70,7 @@ export default class TagRenderingConfig {
addExtraTags: json.freeform.addExtraTags?.map((tg, i) => addExtraTags: json.freeform.addExtraTags?.map((tg, i) =>
FromJSON.Tag(tg, `${context}.extratag[${i}]`)) ?? [] FromJSON.Tag(tg, `${context}.extratag[${i}]`)) ?? []
} }
if(json.freeform["extraTags"] !== undefined){ if (json.freeform["extraTags"] !== undefined) {
throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})` throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})`
} }
if (this.freeform.key === undefined || this.freeform.key === "") { if (this.freeform.key === undefined || this.freeform.key === "") {
@ -90,6 +90,9 @@ export default class TagRenderingConfig {
this.multiAnswer = json.multiAnswer ?? false this.multiAnswer = json.multiAnswer ?? false
if (json.mappings) { if (json.mappings) {
if(!Array.isArray(json.mappings)){
throw "Tagrendering has a 'mappings'-object, but expected a list ("+context+")"
}
this.mappings = json.mappings.map((mapping, i) => { this.mappings = json.mappings.map((mapping, i) => {
@ -254,5 +257,16 @@ export default class TagRenderingConfig {
return undefined; return undefined;
} }
public ExtractImages(isIcon: boolean): Set<string> {
const usedIcons = new Set<string>()
this.render?.ExtractImages(isIcon)?.forEach(usedIcons.add, usedIcons)
for (const mapping of this.mappings ?? []) {
mapping.then.ExtractImages(isIcon).forEach(usedIcons.add, usedIcons)
}
return usedIcons;
}
} }

View file

@ -51,9 +51,10 @@ The preferred way to add your theme is via a Pull Request. A Pull Request is les
2) Go to `assets/themes` and create a new directory `yourtheme` 2) Go to `assets/themes` and create a new directory `yourtheme`
3) Create a new file `yourtheme.json`, paste the theme configuration in there. You can find your theme configuration in the customThemeBuilder (the tab with the *Floppy disk* icon) 3) Create a new file `yourtheme.json`, paste the theme configuration in there. You can find your theme configuration in the customThemeBuilder (the tab with the *Floppy disk* icon)
4) Copy all the images into this new directory. **No external sources are allowed!** External image sources leak privacy or can break. 4) Copy all the images into this new directory. **No external sources are allowed!** External image sources leak privacy or can break.
- Make sure the license is suitable, preferable a Creative Commons license. Attribution can be added at the bottom of this document - Make sure the license is suitable, preferable a Creative Commons license or CC0-license.
- If an SVG version is available, use the SVG version - If an SVG version is available, use the SVG version
- Make sure all the links in `yourtheme.json` are updated. You can use `./assets/themes/yourtheme/yourimage.svg` instead of the HTML link - Make sure all the links in `yourtheme.json` are updated. You can use `./assets/themes/yourtheme/yourimage.svg` instead of the HTML link
- Create a file `license_info.json` in the theme directory, which contains metadata on every artwork source
5) Add your theme to the code base: 5) Add your theme to the code base:
- Open [AllKnownLayouts.ts](https://github.com/pietervdvn/MapComplete/blob/master/Customizations/AllKnownLayouts.ts) - Open [AllKnownLayouts.ts](https://github.com/pietervdvn/MapComplete/blob/master/Customizations/AllKnownLayouts.ts)
- Add an import statement, e.g. `import * as yourtheme from "../assets/themes/yourtheme/yourthemes.json";` - Add an import statement, e.g. `import * as yourtheme from "../assets/themes/yourtheme/yourthemes.json";`

View file

@ -38,6 +38,7 @@ import Combine from "./UI/Base/Combine";
import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler";
import LZString from "lz-string"; import LZString from "lz-string";
import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson"; import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson";
import AttributionPanel from "./UI/BigComponents/AttributionPanel";
export class InitUiElements { export class InitUiElements {
@ -287,11 +288,7 @@ export class InitUiElements {
const copyrightNotice = const copyrightNotice =
new ScrollableFullScreen( new ScrollableFullScreen(
() => Translations.t.general.attribution.attributionTitle.Clone(), () => Translations.t.general.attribution.attributionTitle.Clone(),
() => new Combine([ () => new AttributionPanel(State.state.layoutToUse),
Translations.t.general.attribution.attributionContent,
"<br/>",
new Attribution(undefined, undefined, State.state.layoutToUse, undefined)
]),
"copyright" "copyright"
) )
@ -300,7 +297,7 @@ export class InitUiElements {
copyrightNotice, copyrightNotice,
new MapControlButton(Svg.osm_copyright_svg()), new MapControlButton(Svg.osm_copyright_svg()),
copyrightNotice.isShown copyrightNotice.isShown
).SetClass("p-0.5 md:hidden") ).SetClass("p-0.5")
new Combine([copyrightButton, checkbox]) new Combine([copyrightButton, checkbox])
.AttachTo("bottom-left"); .AttachTo("bottom-left");

View file

@ -2,7 +2,7 @@ import { Utils } from "../Utils";
export default class Constants { export default class Constants {
public static vNumber = "0.6.6c"; public static vNumber = "0.6.7";
// 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 = {

6
Models/smallLicense.ts Normal file
View file

@ -0,0 +1,6 @@
export default interface SmallLicense {
path: string,
authors: string[],
license: string,
sources: string[]
}

View file

@ -142,49 +142,9 @@ Whenever a change is made -even adding a single tag- the change is uploaded into
Note that changesets are closed automatically after one hour of inactivity, so we don't have to worry about closing them. Note that changesets are closed automatically after one hour of inactivity, so we don't have to worry about closing them.
### Query parameters # Documentation
By adding extra query parameters, more options are available to influence: All documentation can be found in [here](Docs/)
**test**: If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org (default value: _false_)
**layout**: The layout to load into MapComplete (default value: _bookcases_)
**userlayout**: undefined (default value: _false_)
**layer-control-toggle**: Wether or not the layer control is shown (default value: _false_)
**tab**: The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >200 changesets) (default value: _0_)
**z**: The initial/current zoom level (default value: _1_)
**lat**: The initial/current latitude (default value: _0_)
**lon**: The initial/current longitude of the app (default value: _0_)
**fs-userbadge**: Disables/Enables the userbadge (and thus disables login capabilities) (default value: _true_)
**fs-search**: Disables/Enables the search bar (default value: _true_)
**fs-layers**: Disables/Enables the layer control (default value: _true_)
**fs-add-new**: Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place) (default value: _true_)
**fs-welcome-message**: undefined (default value: _true_)
**fs-iframe**: Disables/Enables the iframe-popup (default value: _false_)
**fs-more-quests**: Disables/Enables the 'More Quests'-tab in the welcome message (default value: _true_)
**fs-share-screen**: Disables/Enables the 'Share-screen'-tab in the welcome message (default value: _true_)
**fs-geolocation**: Disables/Enables the geolocation button (default value: _true_)
**oauth_token**: Used to complete the login (default value: _undefined_)
**background**: The id of the background layer to start with (default value: _undefined_)
**layer-bookcases**: Wehter or not layer bookcases is shown (default value: _true_) index.ts:104:8
# Privacy # Privacy
@ -195,53 +155,12 @@ Geolocation is available on mobile only throught hte device's GPS location (so n
TODO: erase cookies of third party websites and API's TODO: erase cookies of third party websites and API's
# Attributions # Attribution
Data from OpenStreetMap Data from OpenStreetMap
Background layer selection: curated by https://github.com/osmlab/editor-layer-index Background layer selection: curated by https://github.com/osmlab/editor-layer-index
Images from Wikipedia/Wikimedia Icons are attributed in various 'license_info.json'-files and can be found in the app.
https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg
Camera Icon, Dave Gandy, CC-BY-SA 3.0
https://commons.wikimedia.org/wiki/File:OOjs_UI_indicator_search-rtl.svg
Search Icon, MIT
https://commons.wikimedia.org/wiki/File:Trash_font_awesome.svg
Trash icon by Dave Gandy, CC-BY-SA
https://commons.wikimedia.org/wiki/File:Home-icon.svg
Home icon by Timothy Miller, CC-BY-SA 3.0
https://commons.wikimedia.org/wiki/File:Map_icons_by_Scott_de_Jonge_-_bicycle-store.svg
Bicycle logo, Scott de Jonge
Nature Reserve icon via http://www.onlinewebfonts.com/icon/389579, CC BY 3.0 (@ Эдуард Черных)
Park icon via http://www.onlinewebfonts.com/icon/425974, CC BY 3.0 (@sterankofrank)
Forest icon via https://www.onlinewebfonts.com/icon/498112, CC BY
Statistics icon via https://www.onlinewebfonts.com/icon/197818
Chronometer (on monitoring_station.svg): ANTU chronometer
https://commons.wikimedia.org/w/index.php?title=Antu_chronometer
Fries icon:
https://www.flaticon.com/free-icon/french-fries_1144288
Shower icon (used in 'bike_cleaning.svg'):
https://commons.wikimedia.org/wiki/File:Shower_symbol.svg
Bench icons from StreetComplete: https://github.com/westnordost/StreetComplete/tree/v25.0-beta1/res/graphics/quest%20icons, GPLv3.0
Urinal icon: https://thenounproject.com/term/urinal/1307984/
24/7 icon: https://www.vecteezy.com/vector-art/1394992-24-7-service-and-support-icon-set
Translation-icon: https://commons.wikimedia.org/wiki/File:OOjs_UI_icon_language-ltr.svg
PingPong-table icon: Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com

View file

@ -10,6 +10,9 @@ import Loc from "../../Models/Loc";
import LeafletMap from "../../Models/LeafletMap"; import LeafletMap from "../../Models/LeafletMap";
import * as L from "leaflet" import * as L from "leaflet"
/**
* The bottom right attribution panel in the leaflet map
*/
export default class Attribution extends UIElement { export default class Attribution extends UIElement {
private readonly _location: UIEventSource<Loc>; private readonly _location: UIEventSource<Loc>;

View file

@ -0,0 +1,69 @@
import {UIElement} from "../UIElement";
import Combine from "../Base/Combine";
import Translations from "../i18n/Translations";
import Attribution from "./Attribution";
import State from "../../State";
import {UIEventSource} from "../../Logic/UIEventSource";
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
import {FixedUiElement} from "../Base/FixedUiElement";
import * as licenses from "../../assets/generated/license_info.json"
import SmallLicense from "../../Models/smallLicense";
import {Icon} from "leaflet";
import Img from "../Base/Img";
import {Utils} from "../../Utils";
/**
* The attribution panel shown on mobile
*/
export default class AttributionPanel extends Combine {
private static LicenseObject = AttributionPanel.GenerateLicenses();
constructor(layoutToUse: UIEventSource<LayoutConfig>) {
super([
Translations.t.general.attribution.attributionContent,
((layoutToUse.data.maintainer ?? "") == "") ? "" : Translations.t.general.attribution.themeBy.Subs({author: layoutToUse.data.maintainer}),
layoutToUse.data.credits ,
"<br/>",
new Attribution(undefined, undefined, State.state.layoutToUse, undefined),
"<br/>",
Translations.t.general.attribution.iconAttribution.title.Clone().SetClass("font-bold pt-12 pb-3"),
...Utils.NoNull(Array.from(layoutToUse.data.ExtractImages()))
.map(AttributionPanel.IconAttribution)
]);
this.SetClass("flex flex-col")
}
private static IconAttribution(iconPath: string) {
if (iconPath.startsWith("http")) {
iconPath = "." + new URL(iconPath).pathname;
}
const license: SmallLicense = AttributionPanel.LicenseObject[iconPath]
if (license == undefined) {
return undefined;
}
if(license.license.indexOf("trivial")>=0){
return undefined;
}
return new Combine([
`<img src='${iconPath}' style="width: 50px; height: 50px; margin-right: 0.5em;">`,
new Combine([
new FixedUiElement(license.authors.join("; ")).SetClass("font-bold"),
new Combine([license.license, license.sources.length > 0 ? " - " : "",
...license.sources.map(link => `<a href='${link}' target="_blank">${new URL(link).hostname}</a> `)]).SetClass("block")
]).SetClass("flex flex-col")
]).SetClass("flex")
}
private static GenerateLicenses() {
const allLicenses = {}
for (const key in licenses) {
const license: SmallLicense = licenses[key];
allLicenses[license.path] = license
}
return allLicenses;
}
}

View file

@ -85,16 +85,12 @@ export default class MoreScreen extends UIElement {
const linkButton: UIElement[] = [] const linkButton: UIElement[] = []
for (const k in AllKnownLayouts.allSets) { for (const layout of AllKnownLayouts.layoutsList) {
const layout: LayoutConfig = AllKnownLayouts.allSets[k]; if (layout.id === personal.id) {
if (k === personal.id) {
if (State.state.osmConnection.userDetails.data.csCount < Constants.userJourney.personalLayoutUnlock) { if (State.state.osmConnection.userDetails.data.csCount < Constants.userJourney.personalLayoutUnlock) {
continue; continue;
} }
} }
if (layout.id !== k) {
continue; // This layout was added multiple time due to an uppercase
}
linkButton.push(this.createLinkButton(layout)); linkButton.push(this.createLinkButton(layout));
} }

View file

@ -8,6 +8,8 @@ export class Translation extends UIElement {
public static forcedLanguage = undefined; public static forcedLanguage = undefined;
public readonly translations: object public readonly translations: object
return
allIcons;
constructor(translations: object, context?: string) { constructor(translations: object, context?: string) {
super(Locale.language) super(Locale.language)
@ -17,6 +19,9 @@ export class Translation extends UIElement {
let count = 0; let count = 0;
for (const translationsKey in translations) { for (const translationsKey in translations) {
count++; count++;
if(typeof(translations[translationsKey]) != "string"){
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"
}
} }
this.translations = translations; this.translations = translations;
if (count === 0) { if (count === 0) {
@ -46,7 +51,7 @@ export class Translation extends UIElement {
public SupportedLanguages(): string[] { public SupportedLanguages(): string[] {
const langs = [] const langs = []
for (const translationsKey in this.translations) { for (const translationsKey in this.translations) {
if(translationsKey === "#"){ if (translationsKey === "#") {
continue; continue;
} }
langs.push(translationsKey) langs.push(translationsKey)
@ -102,7 +107,6 @@ export class Translation extends UIElement {
return new Translation(this.translations) return new Translation(this.translations)
} }
FirstSentence() { FirstSentence() {
const tr = {}; const tr = {};
@ -115,4 +119,38 @@ export class Translation extends UIElement {
return new Translation(tr); return new Translation(tr);
} }
public ExtractImages(isIcon = false): string[] {
const allIcons: string[] = []
for (const key in this.translations) {
const render = this.translations[key]
if (isIcon) {
const icons = render.split(";").filter(part => part.match(/(\.svg|\.png|\.jpg)$/) != null)
allIcons.push(...icons)
} else if (!Utils.runningFromConsole) {
// This might be a tagrendering containing some img as html
const htmlElement = document.createElement("div")
htmlElement.innerHTML = render
const images = Array.from(htmlElement.getElementsByTagName("img")).map(img => img.src)
allIcons.push(...images)
} else {
// We are running this in ts-node (~= nodejs), and can not access document
// So, we fallback to simple regex
try {
const matches = render.match(/<img[^>]+>/g)
if (matches != null) {
const sources = matches.map(img => img.match(/src=("[^"]+"|'[^']+'|[^/ ]+)/))
.filter(match => match != null)
.map(match => match[1].trim().replace(/^['"]/, '').replace(/['"]$/, ''));
allIcons.push(...sources)
}
}catch(e){
console.error("Could not search for images: ", render, this.txt)
throw e
}
}
}
return allIcons.filter(icon => icon != undefined)
}
} }

View file

@ -0,0 +1,10 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "picnic_table.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "bicycle_library.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,18 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "pinIcon.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "tube.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,16 @@
[
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "bike_cafe.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

View file

@ -0,0 +1,18 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "bike_cleaning.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "bike_cleaning_icon.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,12 @@
[
{
"authors": [
"Fabián Alexis"
],
"path": "monitoring_station.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Antu_chronometer-reset.svg"
]
}
]

View file

@ -293,7 +293,6 @@
"question": { "question": {
"en": "Does this bicycle parking have spots for cargo bikes?", "en": "Does this bicycle parking have spots for cargo bikes?",
"nl": "Heeft deze fietsparking plaats voor bakfietsen?", "nl": "Heeft deze fietsparking plaats voor bakfietsen?",
"fr": "TODO: fr",
"gl": "Este aparcadoiro de bicicletas ten espazo para bicicletas de carga?", "gl": "Este aparcadoiro de bicicletas ten espazo para bicicletas de carga?",
"de": "Gibt es auf diesem Fahrrad-Parkplatz Plätze für Lastenfahrräder?" "de": "Gibt es auf diesem Fahrrad-Parkplatz Plätze für Lastenfahrräder?"
}, },
@ -303,7 +302,6 @@
"then": { "then": {
"en": "This parking has room for cargo bikes", "en": "This parking has room for cargo bikes",
"nl": "Deze parking heeft plaats voor bakfietsen", "nl": "Deze parking heeft plaats voor bakfietsen",
"fr": "TODO: fr",
"gl": "Este aparcadoiro ten espazo para bicicletas de carga.", "gl": "Este aparcadoiro ten espazo para bicicletas de carga.",
"de": "Dieser Parkplatz bietet Platz für Lastenfahrräder" "de": "Dieser Parkplatz bietet Platz für Lastenfahrräder"
} }
@ -313,7 +311,6 @@
"then": { "then": {
"en": "This parking has designated (official) spots for cargo bikes.", "en": "This parking has designated (official) spots for cargo bikes.",
"nl": "Er zijn speciale plaatsen voorzien voor bakfietsen", "nl": "Er zijn speciale plaatsen voorzien voor bakfietsen",
"fr": "TODO: fr",
"gl": "Este aparcadoiro ten espazos designados (oficiais) para bicicletas de carga.", "gl": "Este aparcadoiro ten espazos designados (oficiais) para bicicletas de carga.",
"de": "Dieser Parkplatz verfügt über ausgewiesene (offizielle) Plätze für Lastenfahrräder." "de": "Dieser Parkplatz verfügt über ausgewiesene (offizielle) Plätze für Lastenfahrräder."
} }
@ -323,7 +320,6 @@
"then": { "then": {
"en": "You're not allowed to park cargo bikes", "en": "You're not allowed to park cargo bikes",
"nl": "Je mag hier geen bakfietsen parkeren", "nl": "Je mag hier geen bakfietsen parkeren",
"fr": "TODO: fr",
"gl": "Non está permitido aparcar bicicletas de carga", "gl": "Non está permitido aparcar bicicletas de carga",
"de": "Es ist nicht erlaubt, Lastenfahrräder zu parken" "de": "Es ist nicht erlaubt, Lastenfahrräder zu parken"
} }

View file

@ -0,0 +1,100 @@
[
{
"authors": [
"Gitte Vande Graveele"
],
"path": "bollard.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
},
{
"authors": [
"Gitte Vande Graveele"
],
"path": "handlebar_holder.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "parking.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "parking_old.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Gitte Vande Graveele"
],
"path": "rack.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
},
{
"authors": [
"Gitte Vande Graveele"
],
"path": "shed.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
},
{
"authors": [
"Gitte Vande Graveele"
],
"path": "staple.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
},
{
"authors": [
"Gitte Vande Graveele"
],
"path": "two_tier.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
},
{
"authors": [
"Gitte Vande Graveele"
],
"path": "wall_loops.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/walk-by-brussels"
]
}
]

View file

@ -0,0 +1,126 @@
[
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "bike_pump.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "broken_pump.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "broken_pump_2.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "pump.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Turvec Solutions"
],
"path": "pump_example.png",
"license": "Used with permission; all rights reserved",
"note": "Used with permission after email conversation, can be assumed to be CC-BY",
"sources": [
"https://turvec.com/product/public-bike-pump/"
]
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "pump_example_manual.jpg",
"license": "CC0",
"sources": []
},
{
"authors": [
"©Altinnova"
],
"path": "pump_example_round.jpg",
"license": "Used with permission; all rights reserved",
"sources": [
"https://www.altinnova.com",
"https://www.teeken.de/produkte/stadtmobiliar/green-air1/12?lang=3"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "repair_station.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Polarbear24"
],
"path": "repair_station_example.jpg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Public_Bike_Repair_Station.jpg"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "repair_station_pump.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

View file

@ -0,0 +1,58 @@
[
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "pump.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "repair_shop.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "shop.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "tools.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

View file

@ -0,0 +1,22 @@
[
{
"authors": [
"Font Awesome"
],
"path": "birdhide.svg",
"license": "CC-BY 4.0",
"sources": [
"https://fontawesome.com"
]
},
{
"authors": [
"Font Awesome Free 5.2.0 by @fontawesome"
],
"path": "birdshelter.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://fontawesome.com\r"
]
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "other_services.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,16 @@
[
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "drips.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "ghost_bike.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [],
"path": "board.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Board-14.svg"
]
}
]

View file

@ -0,0 +1,42 @@
[
{
"authors": [
"OpenStreetMap",
" Pieter Vander Vennet",
" M!dgard"
],
"path": "map-stickered.svg",
"license": "CC-BY-SA",
"sources": [
"https://OpenStreetMap.org",
" https://wiki.openstreetmap.org/wiki/Logos"
]
},
{
"authors": [],
"path": "map.svg",
"license": "CC-BY-SA",
"sources": [
"https://www.OpenStreetMap.org"
],
"note": "Modified OpenStreetMap logo"
},
{
"authors": [],
"path": "osm-logo-buggy-attr.svg",
"license": "CC-BY-SA",
"sources": [
"https://www.OpenStreetMap.org"
],
"note": "Modified OpenStreetMap logo"
},
{
"authors": [],
"path": "osm-logo-white-bg.svg",
"license": "CC-BY-SA",
"sources": [
"https://www.OpenStreetMap.org"
],
"note": "Modified OpenStreetMap logo"
}
]

View file

@ -0,0 +1,42 @@
[
{
"authors": [
"Agentschap Natuur en Bos"
],
"path": "ANB.jpg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.natuurenbos.be/"
]
},
{
"authors": [
"Natuurpunt"
],
"path": "Natuurpunt.jpg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.natuurpunt.be/"
]
},
{
"authors": [
"Groen"
],
"path": "groen_logo.svg",
"license": "All rights reserved",
"sources": [
"https://www.groen.be/"
]
},
{
"authors": [
"@ Эдуард Черных"
],
"path": "nature_reserve.svg",
"license": "CC-BY 3.0",
"sources": [
"https://www.onlinewebfonts.com/icon/389579"
]
}
]

View file

@ -333,14 +333,14 @@
} }
}, },
{ {
"#": "Surface are", "#": "Surface area",
"render": { "render": {
"en": "Surface area: {_surface:ha}Ha", "en": "Surface area: {_surface:ha}Ha"
"mappings": { },
"mappings":[ {
"if": "_surface:ha=0", "if": "_surface:ha=0",
"then": "" "then": {"*":""}
} }]
}
} }
], ],
"hideUnderlayingFeaturesMinPercentage": 10, "hideUnderlayingFeaturesMinPercentage": 10,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View file

@ -0,0 +1,12 @@
[
{
"authors": [
"Agentschap Natuur en Bos"
],
"path": "icon.svg",
"license": "?",
"sources": [
"https://www.natuurenbos.be/spelen"
]
}
]

View file

@ -313,7 +313,7 @@
], ],
"hideUnderlayingFeaturesMinPercentage": 0, "hideUnderlayingFeaturesMinPercentage": 0,
"icon": { "icon": {
"render": "https://upload.wikimedia.org/wikipedia/commons/0/00/Map_icons_by_Scott_de_Jonge_-_playground.svg" "render": "./assets/themes/playgrounds/playground.svg"
}, },
"iconOverlays": [ "iconOverlays": [
{ {

View file

@ -0,0 +1,13 @@
[
{
"authors": [
"@fontawesome"
],
"path": "tabletennis.svg",
"license": "CC-BY 4.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Font_Awesome_5_solid_table-tennis.svg",
" https://fontawesome.com"
]
}
]

View file

@ -0,0 +1,27 @@
[
{
"authors": [],
"path": "toilets.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Toilets-16.svg"
]
},
{
"authors": [
"asianson.design",
" Pieter Vander Vennet"
],
"path": "urinal.svg",
"license": "CC-BY",
"sources": [
"https://thenounproject.com/term/urinal/1307984/"
]
},
{
"authors": [],
"path": "wheelchair.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="85" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="a" x1="0" x2="0" y1="0" y2="1">
<stop stop-color="#aa368d" offset="0"/>
<stop stop-color="#a8378c" offset=".25"/>
<stop stop-color="#92328a" offset=".6"/>
<stop stop-color="#792e87" offset=".75"/>
<stop stop-color="#542886" offset=".9"/>
<stop stop-color="#3b257c" offset="1"/>
</linearGradient>
</defs>
<path d="m42.5 99c-75-49.5-33.62-98 0-98 33.7 0 74.5 48.5-0 98" fill="url(#a)"/>
<rect x="36.25" y="19.25" width="12.5" height="36.5" rx="6.25" ry="6.25" fill="#fff"/>
<circle cx="42.5" cy="66" r="6.75" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 700 B

View file

@ -0,0 +1,12 @@
[
{
"authors": [
"M!dgard"
],
"path": "Onroerend_Erfgoed_logo_without_text.svg",
"license": "CC0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Onroerend_Erfgoed_logo_without_text.svg"
]
}
]

View file

@ -277,8 +277,8 @@
] ]
}, },
"then": { "then": {
"nl": "<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/60/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Erkend als houtig erfgoed door Onroerend Erfgoed Vlaanderen", "nl": "<img src=\"./assets/layers/trees/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Erkend als houtig erfgoed door Onroerend Erfgoed Vlaanderen",
"en": "<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/60/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Registered as heritage by <i>Onroerend Erfgoed</i> Flanders" "en": "<img src=\"./assets/layers/trees/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Registered as heritage by <i>Onroerend Erfgoed</i> Flanders"
} }
}, },
{ {
@ -339,8 +339,8 @@
}, },
{ {
"render": { "render": {
"nl": "<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/60/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Onroerend Erfgoed-ID: <a href=\"https://id.erfgoed.net/erfgoedobjecten/{ref:OnroerendErfgoed}\">{ref:OnroerendErfgoed}</a>", "nl": "<img src=\"./assets/layers/trees/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Onroerend Erfgoed-ID: <a href=\"https://id.erfgoed.net/erfgoedobjecten/{ref:OnroerendErfgoed}\">{ref:OnroerendErfgoed}</a>",
"en": "<img src=\"https://upload.wikimedia.org/wikipedia/commons/6/60/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Onroerend Erfgoed ID: <a href=\"https://id.erfgoed.net/erfgoedobjecten/{ref:OnroerendErfgoed}\">{ref:OnroerendErfgoed}</a>" "en": "<img src=\"./assets/layers/trees/Onroerend_Erfgoed_logo_without_text.svg\" style=\"width:0.85em;height:1em;vertical-align:middle\" alt=\"\"/> Onroerend Erfgoed ID: <a href=\"https://id.erfgoed.net/erfgoedobjecten/{ref:OnroerendErfgoed}\">{ref:OnroerendErfgoed}</a>"
}, },
"question": { "question": {
"nl": "Wat is het ID uitgegeven door Onroerend Erfgoed Vlaanderen?", "nl": "Wat is het ID uitgegeven door Onroerend Erfgoed Vlaanderen?",
@ -359,8 +359,8 @@
}, },
{ {
"render": { "render": {
"nl": "<img src=\"https://upload.wikimedia.org/wikipedia/commons/e/e4/Wikidata-logo_S.svg\" style=\"width:1em;height:0.56em;vertical-align:middle\" alt=\"\"/> Wikidata: <a href=\"http://www.wikidata.org/entity/{wikidata}\">{wikidata}</a>", "nl": "<img src=\"./assets/svg/wikidata.svg\" style=\"width:1em;height:0.56em;vertical-align:middle\" alt=\"\"/> Wikidata: <a href=\"http://www.wikidata.org/entity/{wikidata}\">{wikidata}</a>",
"en": "<img src=\"https://upload.wikimedia.org/wikipedia/commons/e/e4/Wikidata-logo_S.svg\" style=\"width:1em;height:0.56em;vertical-align:middle\" alt=\"\"/> Wikidata: <a href=\"http://www.wikidata.org/entity/{wikidata}\">{wikidata}</a>" "en": "<img src=\"./assets/svg/wikidata.svg\" style=\"width:1em;height:0.56em;vertical-align:middle\" alt=\"\"/> Wikidata: <a href=\"http://www.wikidata.org/entity/{wikidata}\">{wikidata}</a>"
}, },
"question": { "question": {
"nl": "Wat is het Wikidata-ID van deze boom?", "nl": "Wat is het Wikidata-ID van deze boom?",

View file

@ -0,0 +1,10 @@
[
{
"authors": [],
"path": "viewpoint.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Viewpoint-16.svg"
]
}
]

64
assets/license_info.json Normal file
View file

@ -0,0 +1,64 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "SocialImage.png",
"license": "CC0",
"sources": []
},
{
"authors": [
"OpenStreetMap"
],
"path": "generic_osm_background.png",
"license": "CC-BY-SA",
"sources": [
"https://www.OpenStreetMap.org"
]
},
{
"authors": [
"Mangrove Reviews"
],
"path": "mangrove_logo.png",
"license": "logo; All rights reserved",
"sources": [
"https://mangrove.reviews/"
]
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "social_image_front.png",
"license": "CC-BY-SA",
"sources": [
""
]
},
{
"authors": [
"Pieter Vander Vennet",
" OpenStreetMap"
],
"path": "weblogo.png",
"license": "Logo; CC-BY-SA",
"sources": [
"https://mapcomplete.osm.be",
" https://www.openstreetmap.org"
]
},
{
"authors": [
"Pieter Vander Vennet",
" OpenStreetMap"
],
"path": "weblogo.svg",
"license": "Logo; CC-BY-SA",
"sources": [
"https://mapcomplete.osm.be",
" https://www.openstreetmap.org"
]
}
]

View file

@ -0,0 +1,554 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "SocialImageForeground.svg",
"license": "CC-BY-SA",
"sources": [
""
]
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "add.svg",
"license": "CC0",
"sources": [
""
]
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "addSmall.svg",
"license": "CC0",
"sources": []
},
{
"authors": [],
"path": "ampersand.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "arrow-left-smooth.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "arrow-right-smooth.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "back.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Github"
],
"path": "bug.svg",
"license": "MIT",
"sources": [
"https://commons.wikimedia.org/wiki/File:Octicons-bug.svg",
" https://github.com/primer/octicons"
]
},
{
"path": "camera-plus.svg",
"license": "CC-BY-SA 3.0",
"authors": [
"Dave Gandy",
"Pieter Vander Vennet"
],
"sources": [
"https://fontawesome.com/",
"https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg"
]
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "checkmark.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "circle.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "clock.svg",
"license": "CC0",
"sources": []
},
{
"authors": [],
"path": "close.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "compass.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "cross_bottom_right.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "crosshair-blue-center.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "crosshair-blue.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "crosshair.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"Dave Gandy"
],
"path": "delete_icon.svg",
"license": "CC-BY-SA",
"sources": [
"https://commons.wikimedia.org/wiki/File:Trash_font_awesome.svg\rT"
]
},
{
"authors": [],
"path": "direction.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "direction_gradient.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "down.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "envelope.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"The Tango Desktop Project"
],
"path": "floppy.svg",
"license": "CC0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Media-floppy.svg",
" http://tango.freedesktop.org/Tango_Desktop_Project"
]
},
{
"authors": [],
"path": "gear.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "help.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"Timothy Miller"
],
"path": "home.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Home-icon.svg"
]
},
{
"authors": [
"Timothy Miller"
],
"path": "home_white_bg.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Home-icon.svg"
]
},
{
"authors": [
"JOSM Team"
],
"path": "josm_logo.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:JOSM_Logotype_2019.svg",
" https://josm.openstreetmap.de/"
]
},
{
"authors": [],
"path": "layers.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "layersAdd.svg",
"license": "CC0; trivial",
"sources": []
},
{
"path": "Ornament-Horiz-0.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"path": "Ornament-Horiz-1.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"path": "Ornament-Horiz-2.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"path": "Ornament-Horiz-3.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"path": "Ornament-Horiz-4.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"path": "Ornament-Horiz-5.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"path": "Ornament-Horiz-6.svg",
"license": "CC-BY",
"authors": [
"Nightwolfdezines"
],
"sources": [
"https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes"
]
},
{
"authors": [],
"path": "star.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "star_outline.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "star_half.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "star_outline_half.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "logo.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "logout.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet",
" OSM"
],
"path": "mapcomplete_logo.svg",
"license": "Logo; CC-BY-SA",
"sources": [
""
]
},
{
"authors": [
"Mapillary"
],
"path": "mapillary.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://mapillary.com/"
]
},
{
"authors": [],
"path": "min.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "no_checkmark.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "or.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "osm-copyright.svg",
"license": "logo; all rights reserved",
"sources": [
"https://www.OpenStreetMap.org"
]
},
{
"authors": [
"OpenStreetMap U.S. Chapter"
],
"path": "osm-logo-us.svg",
"license": "Logo",
"sources": [
"https://www.openstreetmap.us/"
]
},
{
"authors": [],
"path": "osm-logo.svg",
"license": "logo; all rights reserved",
"sources": [
"https://www.OpenStreetMap.org"
]
},
{
"authors": [
"GitHub Octicons"
],
"path": "pencil.svg",
"license": "MIT",
"sources": [
"https://github.com/primer/octicons",
" https://commons.wikimedia.org/wiki/File:Octicons-pencil.svg"
]
},
{
"authors": [
"@ tyskrat"
],
"path": "phone.svg",
"license": "CC-BY 3.0",
"sources": [
"https://www.onlinewebfonts.com/icon/1059"
]
},
{
"authors": [],
"path": "pin.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "plus.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"@fatih"
],
"path": "pop-out.svg",
"license": "CC-BY 3.0",
"sources": [
"https://www.onlinewebfonts.com/icon/2151"
]
},
{
"authors": [],
"path": "reload.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "ring.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"OOjs UI Team and other contributors"
],
"path": "search.svg",
"license": "MIT",
"sources": [
"https://commons.wikimedia.org/wiki/File:OOjs_UI_indicator_search-rtl.svg",
"https://phabricator.wikimedia.org/diffusion/GOJU/browse/master/AUTHORS.txt"
]
},
{
"authors": [],
"path": "send_email.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "share.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "square.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"@felpgrc"
],
"path": "statistics.svg",
"license": "CC-BY 3.0",
"sources": [
"https://www.onlinewebfonts.com/icon/197818"
]
},
{
"authors": [
"MGalloway (WMF)"
],
"path": "translate.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:OOjs_UI_icon_language-ltr.svg"
]
},
{
"authors": [],
"path": "up.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [
"Wikidata"
],
"path": "wikidata.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.wikidata.org"
]
},
{
"authors": [
"Wikimedia"
],
"path": "wikimedia-commons-white.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://commons.wikimedia.org"
]
},
{
"authors": [
"Wikipedia"
],
"path": "wikipedia.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.wikipedia.org/"
]
}
]

View file

@ -0,0 +1,22 @@
[
{
"authors": [
"MaxxL"
],
"path": "aed.svg",
"license": "CC0",
"sources": [
"https://commons.wikimedia.org/wiki/File:ISO_7010_E010.svg"
]
},
{
"authors": [
"M!dgard"
],
"path": "logo.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:ISO_7010_E010.svg"
]
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [],
"path": "artwork.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Statue-14.svg"
]
}
]

View file

@ -0,0 +1,24 @@
[
{
"authors": [
"Tobias Zwick"
],
"path": "bench_poi.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://github.com/streetcomplete/StreetComplete/blob/v25.0-beta1/res/graphics/authors.txt",
"https://github.com/streetcomplete/StreetComplete/tree/v25.0-beta1/res/graphics/quest%20icons"
]
},
{
"authors": [
"Tobias Zwick"
],
"path": "bench_public_transport.svg",
"license": "CC-BY-SA 4.0",
"sources": [
"https://github.com/streetcomplete/StreetComplete/blob/v25.0-beta1/res/graphics/authors.txt",
"https://github.com/streetcomplete/StreetComplete/tree/v25.0-beta1/res/graphics/quest%20icons"
]
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "logo.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [],
"path": "bookcase.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Public_bookcase-14.svg"
]
}
]

View file

@ -0,0 +1,72 @@
[
{
"authors": [
"Agentschap Natuur en Bos"
],
"path": "ANB.jpg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.natuurenbos.be/"
]
},
{
"authors": [
"Natuurpunt"
],
"path": "Natuurpunt.jpg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.natuurpunt.be/"
]
},
{
"authors": [
"@ Federico Sibella"
],
"path": "forest.svg",
"license": "CC-BY 3.0",
"sources": [
"https://www.onlinewebfonts.com/icon/498112"
]
},
{
"authors": [
"Groen"
],
"path": "groen_logo.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://www.groen.be/"
]
},
{
"authors": [
"@ Эдуард Черных"
],
"path": "nature_reserve.svg",
"license": "CC-BY 3.0",
"sources": [
"https://www.onlinewebfonts.com/icon/389579"
]
},
{
"authors": [
"@sterankofrank"
],
"path": "park.svg",
"license": "CC-BY 3.0",
"sources": [
"http://www.onlinewebfonts.com/icon/425974"
]
},
{
"authors": [
"Groen"
],
"path": "social_image.jpg",
"license": "All rights reserved",
"sources": [
""
]
}
]

View file

@ -0,0 +1,45 @@
[
{
"path": "Barßel_Wohnmobilstellplatz.jpg",
"authors": [
"ES01"
],
"license": "CC-BY-SA 3.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Bar%C3%9Fel_Wohnmobilstellplatz.jpg"
]
},
{
"path": "caravan.svg",
"authors": [
"OsmAnd"
],
"license": "CC0",
"sources": [
"https://github.com/osmandapp/Osmand/blob/master/LICENSE",
"https://github.com/osmandapp/OsmAnd-resources/blob/36d8b90a8933e0a28f9ee19f28abbd520f9da3c7/icons/svg/accommodation/caravan.svg"
]
},
{
"path": "caravan_green.svg",
"authors": [
"OsmAnd"
],
"license": "CC0",
"sources": [
"https://github.com/osmandapp/Osmand/blob/master/LICENSE",
"https://github.com/osmandapp/OsmAnd-resources/blob/36d8b90a8933e0a28f9ee19f28abbd520f9da3c7/icons/svg/accommodation/caravan.svg"
]
},
{
"path": "sanitary_dump_station.svg",
"authors": [
"OsmAnd"
],
"license": "CC0",
"sources": [
"https://github.com/osmandapp/Osmand/blob/master/LICENSE",
"https://github.com/osmandapp/OsmAnd-resources/blob/16892d8b2fc00dd422abfb2fef967d5ccd05eeac/icons/svg/poi/sanitary_dump_station.svg"
]
}
]

View file

@ -0,0 +1,31 @@
[
{
"authors": [
"Stijn Wens"
],
"path": "bicycle.svg",
"license": "CC0",
"sources": [
"https://wens.be/free-antwerpenize-bicycle-font",
" https://antwerpenize.be/post/634396003556081664/antwerpenize-lettertype"
]
},
{
"authors": [],
"path": "car.svg",
"license": "CC0",
"sources": []
},
{
"authors": [],
"path": "logo.svg",
"license": "CC0; trivial",
"sources": []
},
{
"authors": [],
"path": "plug.svg",
"license": "CC0; trivial",
"sources": []
}
]

View file

@ -0,0 +1,79 @@
[
{
"authors": [
"Christian Neumann"
],
"path": "climbing_gym.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
},
{
"authors": [
"Christian Neumann"
],
"path": "climbing_icon.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
},
{
"authors": [
"Christian Neumann"
],
"path": "climbing_no_rope.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
},
{
"authors": [
"Christian Neumann"
],
"path": "climbing_rope.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
},
{
"authors": [
"Christian Neumann"
],
"path": "climbing_route.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
},
{
"authors": [
"Christian Neumann"
],
"path": "climbing_unknown.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
},
{
"authors": [
"Christian Neumann"
],
"path": "club.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://utopicode.de/",
"https://github.com/chrneumann/MapComplete"
]
}
]

View file

@ -0,0 +1,22 @@
[
{
"authors": [
"The RedBurn"
],
"path": "F111.svg",
"license": "CC0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Belgian_road_sign_F111_nl.svg"
]
},
{
"authors": [
"The RedBurn"
],
"path": "F113.svg",
"license": "CC0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Belgian_road_sign_F113_nl.svg"
]
}
]

View file

@ -22,6 +22,7 @@
"de" "de"
], ],
"maintainer": "MapComplete", "maintainer": "MapComplete",
"credits": "Originally created during Open Summer of Code by Pieter Fiers, Thibault Declercq, Pierre Barban, Joost Schouppe and Pieter Vander Vennet",
"icon": "assets/themes/cyclofix/logo.svg", "icon": "assets/themes/cyclofix/logo.svg",
"version": "0", "version": "0",
"startLat": 0, "startLat": 0,

View file

@ -0,0 +1,36 @@
[
{
"authors": [
"De Fietsambassade"
],
"path": "fietsambassade_gent_logo.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://fietsambassade.gent.be"
]
},
{
"authors": [
"De Fietsambassade"
],
"path": "fietsambassade_gent_logo_small.svg",
"license": "Logo; All rights reserved",
"sources": [
"https://fietsambassade.gent.be"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "logo.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

View file

@ -0,0 +1,44 @@
[
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "place_with_pump.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "non_bike_repair_shop.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
},
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "non_bike_shop.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -0,0 +1,16 @@
[
{
"authors": [
"Pieter Fiers",
"Thibault Declercq",
"Pierre Barban",
"Joost Schouppe",
"Pieter Vander Vennet"
],
"path": "logo.svg",
"license": "CC-BY-SA",
"sources": [
"https://osoc.be/editions/2020/cyclofix"
]
}
]

View file

@ -0,0 +1,102 @@
[
{
"authors": [
"Klimaan VZW"
],
"path": "bloei.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "bodembedekker.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "eetbaar.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "gevelton.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "geveltuin.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "halfzon.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "klimplant.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "schaduw.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "struik.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
},
{
"authors": [
"Klimaan VZW"
],
"path": "zon.svg",
"license": "CC-BY-SA 3.0",
"sources": [
"https://klimaan.be/"
]
}
]

View file

@ -0,0 +1,22 @@
[
{
"authors": [
"Freepik"
],
"path": "logo.svg",
"license": "CC-BY",
"sources": [
"https://www.flaticon.com/free-icon/french-fries_1144288"
]
},
{
"authors": [
"Freepik"
],
"path": "fries.svg",
"license": "CC-BY",
"sources": [
"https://www.flaticon.com/free-icon/french-fries_1144288"
]
}
]

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><g><circle fill="#000000" cx="38.612" cy="57.84" r="4.324"></circle><circle fill="#000000" cx="22.758" cy="53.401" r="4.324"></circle><circle fill="#000000" cx="20.568" cy="38.942" r="4.324"></circle><path fill="#000000" d="M77.255,46.586c1.56-1.04,4.097-3.166,4.443-6.156c0.151-1.302-0.082-3.158-1.779-5.133 c0.825-1.783,1.815-4.765,0.856-7.45c-0.401-1.127-1.292-2.578-3.258-3.567c-0.462-1.787-1.656-4.959-4.522-6.666 c-1.802-1.071-3.884-1.355-6.203-0.854c-0.652-1.04-1.688-2.239-3.231-2.913c-0.9-0.394-2.229-0.705-3.9-0.353 c-1.023-1.537-2.862-3.653-5.63-4.541c-2.332-0.75-4.809-0.5-7.375,0.734c-0.965-0.603-2.384-1.213-4.122-1.116 c-1.748,0.096-3.378,0.869-4.865,2.302c-1.873-1.025-4.958-2.261-7.738-1.28c-1.146,0.404-2.582,1.313-3.564,3.351 c-1.711-0.076-4.216,0.156-5.963,1.853c-0.898,0.873-1.837,2.386-1.789,4.881c-1.876,0.678-4.57,2.046-5.619,4.53 c-0.372,0.882-0.632,2.135-0.234,3.674c-1.775,0.856-4.052,2.383-4.96,4.83c-0.438,1.179-0.676,2.936,0.263,5.095 c-1.171,1.221-2.661,3.247-2.959,5.846c-0.256,2.238,0.388,4.417,1.915,6.492c-0.504,1.859-1.119,5.386,0.459,8.011 c0.475,0.788,1.28,1.715,2.624,2.324c-0.067,1.598,0.179,3.814,1.628,5.697c1.448,1.885,3.702,2.929,6.695,3.126 c0.384,1.995,2.135,3.504,4.241,3.504c1.686,0,3.13-0.975,3.844-2.382c1.001,0.352,2.019,0.501,3.006,0.501 c1.121,0,2.195-0.187,3.165-0.442c0.707,1.636,2.371,2.737,4.253,2.608c1.693-0.116,3.077-1.202,3.685-2.672 c0.559-0.016,1.131-0.081,1.713-0.241c1.91-0.522,3.479-1.797,4.677-3.799c1.158,0.205,2.848,0.258,4.517-0.59 c1.87-0.95,3.224-2.747,4.03-5.346c0.812-0.15,1.856-0.509,2.819-1.338c0.426-0.366,0.789-0.796,1.104-1.274 c3.9,4.479,5.844,10.147,5.781,16.925c-0.062,6.806-2.223,12.233-2.245,12.288c-0.135,0.333-0.095,0.712,0.105,1.01 c0.202,0.297,0.537,0.477,0.896,0.477h15.134c0.579,0,1.056-0.456,1.079-1.034c0.604-14.172-3.678-25.654-9.613-33.623 c1.561-0.406,3.193-1.123,4.47-2.386C76.383,50.203,77.121,48.527,77.255,46.586z M72.938,45.516 c0.119,1.682-0.45,2.457-0.889,2.894c-1.131,1.125-3.163,1.507-4.688,1.608c-4.747-4.965-10.091-7.932-14.73-8.544 c-0.755-0.099-1.542-0.25-2.401-0.46c-6.739-2.44-6.931-11.761-6.932-11.855c-0.007-0.517-0.378-0.958-0.887-1.05 c-0.514-0.098-1.013,0.187-1.201,0.668c-0.936,2.39-0.465,6.405,0.248,8.956c-7.655-1.251-13.255-11.143-13.314-11.25 c-0.202-0.363-0.601-0.58-1.012-0.552c-0.416,0.026-0.78,0.288-0.936,0.674C24.38,31.12,31.333,39.79,41.485,46.146 c-5.066-0.652-10.301-4.816-10.358-4.862c-0.414-0.333-1.008-0.315-1.4,0.04c-0.394,0.355-0.474,0.943-0.185,1.389 c4.261,6.608,9.249,7.089,14.072,7.553c3.65,0.352,7.424,0.716,11.42,3.565c0.724,0.517,1.401,1.062,2.05,1.626 c-0.741,1.774-2.154,1.872-2.651,1.848c-0.813-0.066-1.545,0.461-1.727,1.252c-0.514,2.235-1.398,3.693-2.627,4.33 c-1.526,0.794-3.256,0.104-3.261,0.104c-0.807-0.343-1.741,0.012-2.109,0.808c-0.833,1.795-1.916,2.887-3.218,3.25 c-2.252,0.628-4.644-0.969-4.663-0.981c-0.53-0.365-1.229-0.378-1.774-0.04c-0.047,0.028-4.756,2.894-8.182,1.032 c-0.053-0.028-0.109-0.045-0.163-0.067c-0.609-1.649-2.182-2.831-4.043-2.831c-1.006,0-1.919,0.357-2.653,0.933 c-0.169-0.042-0.344-0.071-0.526-0.071c-2.107,0-3.562-0.493-4.319-1.466c-1.002-1.285-0.762-3.392-0.588-4.082 c0.159-0.602,0.052-1.242-0.295-1.759c-0.347-0.516-0.899-0.859-1.516-0.939c-1.044-0.136-1.403-0.547-1.582-0.843 c-0.826-1.365-0.177-4.289,0.265-5.488c0.281-0.749,0.125-1.591-0.405-2.19c-1.254-1.417-1.794-2.755-1.649-4.089 c0.259-2.381,2.621-4.129,2.635-4.14c0.955-0.679,1.194-1.995,0.541-2.967c-1.14-1.695-0.823-2.555-0.72-2.837 c0.611-1.664,3.431-2.795,4.363-3.059c0.662-0.183,1.197-0.667,1.443-1.307c0.247-0.64,0.176-1.359-0.193-1.938 c-0.808-1.268-0.568-1.837-0.489-2.024c0.499-1.193,2.937-2.219,4.421-2.536c1.159-0.241,1.908-1.369,1.682-2.531 c-0.194-0.995-0.295-2.311,0.331-2.924c0.852-0.833,3.011-0.694,3.917-0.498c1.131,0.258,2.27-0.432,2.567-1.559 c0.317-1.208,0.812-1.94,1.47-2.174c1.546-0.549,4.324,0.939,5.424,1.742c0.952,0.703,2.288,0.509,3.004-0.43 c0.693-0.911,1.769-2.013,2.949-2.093c1.183-0.085,2.142,0.857,2.143,0.857c0.698,0.735,1.816,0.883,2.685,0.359 c1.916-1.16,3.64-1.51,5.12-1.043c2.6,0.82,3.977,3.875,3.985,3.896c0.23,0.538,0.671,0.959,1.219,1.167 c0.547,0.208,1.156,0.184,1.686-0.064c1.354-0.635,2.021-0.351,2.239-0.259c0.994,0.424,1.625,1.745,1.779,2.202 c0.181,0.564,0.583,1.03,1.116,1.288c0.533,0.258,1.151,0.286,1.703,0.078c1.801-0.677,3.266-0.691,4.356-0.05 c1.809,1.066,2.579,3.84,2.722,4.81c0.114,0.814,0.679,1.494,1.458,1.754c1.266,0.422,1.604,1.006,1.749,1.409 c0.599,1.662-0.754,4.419-1.272,5.25c-0.574,0.91-0.393,2.103,0.427,2.8c1.113,0.948,1.635,1.817,1.549,2.58 c-0.163,1.442-2.295,2.992-3.296,3.514C73.338,43.834,72.878,44.652,72.938,45.516z"></path></g></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -13,13 +13,14 @@
"nl" "nl"
], ],
"maintainer": "", "maintainer": "",
"icon": "https://upload.wikimedia.org/wikipedia/commons/4/4e/Low_Hanging_Fruit_-_The_Noun_Project.svg", "icon": "./assets/themes/fruit_trees/fruit_tree.svg",
"version": "0", "version": "0",
"startLat": 0, "startLat": 0,
"startLon": 0, "startLon": 0,
"startZoom": 1, "startZoom": 1,
"widenFactor": 0.001, "widenFactor": 0.001,
"socialImage": "", "socialImage": "",
"hideFromOverview": true,
"layers": [ "layers": [
{ {
"id": "orchards", "id": "orchards",
@ -27,11 +28,12 @@
"nl": "Boomgaarden" "nl": "Boomgaarden"
}, },
"minzoom": 12, "minzoom": 12,
"overpassTags": { "source":{
"osmTags": {
"and": [ "and": [
"landuse=orchard" "landuse=orchard"
] ]
}, } },
"title": { "title": {
"render": { "render": {
"nl": "Boomgaard" "nl": "Boomgaard"
@ -72,11 +74,12 @@
"nl": "Boom" "nl": "Boom"
}, },
"minzoom": 12, "minzoom": 12,
"overpassTags": { "source":{
"osmTags": {
"and": [ "and": [
"natural=tree" "natural=tree"
] ]
}, }},
"title": { "title": {
"render": { "render": {
"nl": "Boom" "nl": "Boom"
@ -138,7 +141,7 @@
], ],
"hideUnderlayingFeaturesMinPercentage": 0, "hideUnderlayingFeaturesMinPercentage": 0,
"icon": { "icon": {
"render": "https://upload.wikimedia.org/wikipedia/commons/4/4e/Low_Hanging_Fruit_-_The_Noun_Project.svg" "render": "./assets/themes/fruit_trees/fruit_tree.svg"
}, },
"width": { "width": {
"render": "8" "render": "8"

View file

@ -0,0 +1,12 @@
[
{
"path": "fruit_tree.svg",
"authors": [
"The Noun Project"
],
"license": "CC0",
"sources": [
"https://upload.wikimedia.org/wikipedia/commons/4/4e/Low_Hanging_Fruit_-_The_Noun_Project.svg"
]
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "logo.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,12 @@
[
{
"authors": [
"CC0"
],
"path": "logo.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Board-14.svg"
]
}
]

View file

@ -0,0 +1,12 @@
[
{
"authors": [
"Font Awesome"
],
"path": "logo.svg",
"license": "CC-BY 4.0",
"sources": [
"https://fontawesome.com"
]
}
]

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 85 KiB

View file

@ -0,0 +1,13 @@
[
{
"authors": [
"Scott de Jonge"
],
"path": "playground.svg",
"license": "CC-BY 3.0",
"sources": [
"https://commons.wikimedia.org/wiki/File:Map_icons_by_Scott_de_Jonge_-_playground.svg",
" https://github.com/scottdejonge/map-icons/blob/b74a0e00afdd6b734883671da7a9e5f30497353e/src/icons/playground.svg"
]
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [],
"path": "shop.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Convenience-14.svg"
]
}
]

View file

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
id="svg8"
version="1.1"
viewBox="0 0 100 100"
height="100"
width="100">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6">
<linearGradient
id="linearGradient823">
<stop
id="stop819"
offset="0"
style="stop-color:#55ff55;stop-opacity:1;" />
<stop
id="stop821"
offset="1"
style="stop-color:#55ff55;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient820">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="innercolor" />
<stop
style="stop-color:#000000;stop-opacity:0"
offset="1"
id="outercolor" />
</linearGradient>
<radialGradient
xlink:href="#linearGradient820"
id="radialGradient828"
cx="49.787739"
cy="53.828533"
fx="49.787739"
fy="53.828533"
r="28.883806"
gradientTransform="matrix(1.5439431,-0.01852438,0.02075364,1.7297431,-28.198837,-42.329969)"
gradientUnits="userSpaceOnUse" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.99367722,0,0.31814846)"
r="50.261864"
fy="50.317799"
fx="50.211864"
cy="50.317799"
cx="50.211864"
id="radialGradient825"
xlink:href="#linearGradient823" />
</defs>
<ellipse
ry="49.89407"
rx="50.211864"
cy="50.317799"
cx="50.211864"
id="path817"
style="fill:url(#radialGradient825);fill-opacity:1;stroke:#0f0000;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529" />
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,34 @@
[
{
"authors": [
"Pieter Vander Vennet"
],
"path": "cam_left.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "cam_right.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "dome.svg",
"license": "CC0",
"sources": []
},
{
"authors": [
"Pieter Vander Vennet"
],
"path": "logo.svg",
"license": "CC0",
"sources": []
}
]

View file

@ -0,0 +1,10 @@
[
{
"authors": [],
"path": "toilets.svg",
"license": "CC0",
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Toilets-16.svg"
]
}
]

View file

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="14"
height="14"
viewBox="0 0 14 14"
id="svg2"
sodipodi:docname="guidepost.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1001"
id="namedview7"
showgrid="false"
inkscape:zoom="33.714286"
inkscape:cx="11.006743"
inkscape:cy="3.62286"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<rect
width="14"
height="14"
x="0"
y="0"
id="canvas"
style="fill:none;stroke:none;visibility:hidden" />
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="bg"
style="display:inline">
<circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:32.77777863;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path820"
cx="7"
cy="7"
r="7" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="fg"
sodipodi:insensitive="true">
<path
d="m 7.2669492,1.9396186 c -0.282839,0 -0.565678,0.1885594 -0.565678,0.565678 v 9.8050844 h 1.131356 V 2.5052966 c 0,-0.3771186 -0.282839,-0.565678 -0.565678,-0.565678 z M 3.4957628,2.5052966 1.9872882,3.6366525 3.4957628,4.7680085 H 6.5127119 V 2.5052966 Z M 8.0211865,4.7680085 V 7.0307203 H 11.038135 L 12.54661,5.8993644 11.038135,4.7680085 Z"
id="guidepost"
style="fill:#555555;fill-opacity:1;stroke:none;stroke-width:0.75423729"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,52 @@
[
{
"path": "broadleaved.svg",
"authors": [
"Midgard"
],
"license": "CC BY-SA 4.0",
"sources": [
"https://www.openstreetmap.org/user/M!dgard"
]
},
{
"path": "leafless.svg",
"authors": [
"Midgard"
],
"license": "CC BY-SA 4.0",
"sources": [
"https://www.openstreetmap.org/user/M!dgard"
]
},
{
"path": "logo.svg",
"authors": [
"Midgard"
],
"license": "CC BY-SA 4.0",
"sources": [
"https://www.openstreetmap.org/user/M!dgard"
]
},
{
"path": "needleleaved.svg",
"authors": [
"Midgard"
],
"license": "CC BY-SA 4.0",
"sources": [
"https://www.openstreetmap.org/user/M!dgard"
]
},
{
"path": "unknown.svg",
"authors": [
"Midgard"
],
"license": "CC BY-SA 4.0",
"sources": [
"https://www.openstreetmap.org/user/M!dgard"
]
}
]

View file

@ -0,0 +1,8 @@
[
{
"authors": [],
"path": "icon.svg",
"license": "CC0; trivial",
"sources": []
}
]

View file

@ -519,7 +519,15 @@
"nl": "Met dank aan" "nl": "Met dank aan"
}, },
"attributionContent": { "attributionContent": {
"en": "<p>All data is provided by <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, freely reusable under <a href='https://osm.org/copyright' target='_blank'>the Open DataBase License</a>.</p><p>Some images are provided by Wikimedia</p>" "en": "<p>All data is provided by <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, freely reusable under <a href='https://osm.org/copyright' target='_blank'>the Open DataBase License</a>.</p>"
},
"themeBy": {
"en": "Theme maintained by {author}"
},
"iconAttribution": {
"title": {
"en": "Used icons"
}
} }
}, },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

View file

@ -27,7 +27,7 @@
<link rel="icon" href="./assets/svg/add.svg" sizes="any" type="image/svg+xml"> <link rel="icon" href="./assets/svg/add.svg" sizes="any" type="image/svg+xml">
<meta property="og:image" content="./assets/SocialImage.png"> <meta property="og:image" content="./assets/SocialImage.png">
<meta property="og:title" content="MapComplete - editable, thematic maps with OpenStreetMap"> <meta property="og:title" content="MapComplete - editable, thematic maps with OpenStreetMap">
<meta property="og:description" content="MapComplete is a platform to visualize OpenStreetMap on a specific topic and to easily contribute data back to it.">` <meta property="og:description" content="MapComplete is a platform to visualize OpenStreetMap on a specific topic and to easily contribute data back to it.">
<link rel="apple-touch-icon" sizes="512x512" href="./assets/generated/svg_mapcomplete_logo512.png"> <link rel="apple-touch-icon" sizes="512x512" href="./assets/generated/svg_mapcomplete_logo512.png">
<link rel="apple-touch-icon" sizes="384x384" href="./assets/generated/svg_mapcomplete_logo384.png"> <link rel="apple-touch-icon" sizes="384x384" href="./assets/generated/svg_mapcomplete_logo384.png">

View file

@ -52,7 +52,7 @@ if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
} }
// ----------------- SELECT THE RIGHT QUESTSET ----------------- // ----------------- SELECT THE RIGHT Theme -----------------
const path = window.location.pathname.split("/").slice(-1)[0]; const path = window.location.pathname.split("/").slice(-1)[0];
@ -64,7 +64,7 @@ if (path !== "index.html" && path !== "") {
console.log("Using layout", defaultLayout); console.log("Using layout", defaultLayout);
} }
defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout, "The layout to load into MapComplete").data; defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout, "The layout to load into MapComplete").data;
let layoutToUse: LayoutConfig = AllKnownLayouts.allSets[defaultLayout.toLowerCase()]; let layoutToUse: LayoutConfig = AllKnownLayouts.allKnownLayouts.get(defaultLayout.toLowerCase());
const userLayoutParam = QueryParameters.GetQueryParameter("userlayout", "false"); const userLayoutParam = QueryParameters.GetQueryParameter("userlayout", "false");
@ -81,7 +81,7 @@ if (layoutFromBase64.startsWith("http")) {
$.ajax({ $.ajax({
url: link, url: link,
success: function (data) { success: (data) => {
try { try {
const parsed = JSON.parse(data); const parsed = JSON.parse(data);
@ -121,6 +121,6 @@ if (layoutFromBase64.startsWith("http")) {
.SetStyle("pointer-events: all;") .SetStyle("pointer-events: all;")
.AttachTo("topleft-tools"); .AttachTo("topleft-tools");
} }
window.addEventListener('contextmenu', function (e) { // Not compatible with IE < 9 window.addEventListener('contextmenu', (e) => { // Not compatible with IE < 9
e.preventDefault(); e.preventDefault();
}, false); }, false);

102
package-lock.json generated
View file

@ -4029,6 +4029,11 @@
"integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA==", "integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA==",
"dev": true "dev": true
}, },
"@types/prompt-sync": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.1.0.tgz",
"integrity": "sha1-utMynv9bQRXjTvRpgjckTUEdRHA="
},
"@types/q": { "@types/q": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
@ -4726,6 +4731,11 @@
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
}, },
"builtin-modules": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
},
"builtin-status-codes": { "builtin-status-codes": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
@ -9903,6 +9913,29 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
}, },
"prompt-sync": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz",
"integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==",
"requires": {
"strip-ansi": "^5.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"protocol-buffers-schema": { "protocol-buffers-schema": {
"version": "3.5.1", "version": "3.5.1",
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz",
@ -11583,6 +11616,75 @@
} }
} }
}, },
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"tslint": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
"integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
"requires": {
"@babel/code-frame": "^7.0.0",
"builtin-modules": "^1.1.1",
"chalk": "^2.3.0",
"commander": "^2.12.1",
"diff": "^4.0.1",
"glob": "^7.1.1",
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.3",
"resolve": "^1.3.2",
"semver": "^5.3.0",
"tslib": "^1.13.0",
"tsutils": "^2.29.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"tslint-no-circular-imports": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/tslint-no-circular-imports/-/tslint-no-circular-imports-0.7.0.tgz",
"integrity": "sha512-k3wxpeMC4ef40UbpfBVHEHIzKfNZq5/SCtAO1YjGsaNTklo+K53/TWLrym+poA65RJFDiYgYNWvkeIIkJNA0Vw==",
"dev": true
},
"tsutils": {
"version": "2.29.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
"requires": {
"tslib": "^1.8.1"
}
},
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",

View file

@ -8,19 +8,25 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"increase-memory": "export NODE_OPTIONS=--max_old_space_size=4096", "increase-memory": "export NODE_OPTIONS=--max_old_space_size=4096",
"start": "npm run increase-memory && parcel *.html UI/** Logic/** assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", "start": "ts-node scripts/generateLayerOverview.ts && npm run increase-memory && parcel *.html UI/** Logic/** assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
"test": "ts-node test/Tag.spec.ts && ts-node test/TagQuestion.spec.ts && ts-node test/ImageSearcher.spec.ts", "test": "ts-node test/Tag.spec.ts && ts-node test/TagQuestion.spec.ts && ts-node test/ImageSearcher.spec.ts && ts-node test/ImageAttribution.spec.ts",
"generate:editor-layer-index": "cd assets/ && wget https://osmlab.github.io/editor-layer-index/imagery.geojson --output-document=editor-layer-index.json", "generate:editor-layer-index": "cd assets/ && wget https://osmlab.github.io/editor-layer-index/imagery.geojson --output-document=editor-layer-index.json",
"generate:images": "ts-node scripts/generateIncludedImages.ts", "generate:images": "ts-node scripts/generateIncludedImages.ts",
"generate:translations": "ts-node scripts/generateTranslations.ts", "generate:translations": "ts-node scripts/generateTranslations.ts",
"generate:layouts": "ts-node scripts/createLayouts.ts", "generate:layouts": "ts-node scripts/generateLayouts.ts",
"generate:docs": "ts-node scripts/generateDocs.ts",
"generate:layeroverview": "ts-node scripts/generateLayerOverview.ts",
"generate:licenses": "ts-node scripts/generateLicenseInfo.ts",
"validate:layeroverview": "ts-node scripts/generateLayerOverview.ts",
"validate:licenses": "ts-node scripts/generateLicenseInfo.ts",
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", "optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
"generate": "npm run generate:images && npm run generate:translations", "generate": "npm run generate:images && npm run generate:translations && npm run generate:licenses",
"build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", "build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
"prepare-deploy": "npm run test && npm run generate:editor-layer-index && npm run generate:layouts && npm run generate && npm run build && rm -rf .cache", "prepare-deploy": "npm run test && npm run generate:editor-layer-index && npm run generate:layouts && npm run generate:layeroverview && npm run generate && npm run build && rm -rf .cache && npm run generate:docs",
"deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", "deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"deploy:pietervdvn": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", "deploy:pietervdvn": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/mapcomplete.github.io/* && cp -r dist/* /home/pietervdvn/git/mapcomplete.github.io/ && cd /home/pietervdvn/git/mapcomplete.github.io/ && echo \"mapcomplete.osm.be\" > CNAME && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", "deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/mapcomplete.github.io/* && cp -r dist/* /home/pietervdvn/git/mapcomplete.github.io/ && cd /home/pietervdvn/git/mapcomplete.github.io/ && echo \"mapcomplete.osm.be\" > CNAME && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"lint": "tslint --project . -c tslint.json '**.ts' ",
"clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(index\\|land\\|test\\|preferences\\|customGenerator\\).html\" | xargs rm) && rm *.webmanifest" "clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(index\\|land\\|test\\|preferences\\|customGenerator\\).html\" | xargs rm) && rm *.webmanifest"
}, },
"keywords": [ "keywords": [
@ -38,6 +44,7 @@
"@types/leaflet-providers": "^1.2.0", "@types/leaflet-providers": "^1.2.0",
"@types/leaflet.markercluster": "^1.4.3", "@types/leaflet.markercluster": "^1.4.3",
"@types/lz-string": "^1.3.34", "@types/lz-string": "^1.3.34",
"@types/prompt-sync": "^4.1.0",
"autoprefixer": "^9.8.6", "autoprefixer": "^9.8.6",
"country-language": "^0.1.7", "country-language": "^0.1.7",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
@ -58,9 +65,11 @@
"osmtogeojson": "^3.0.0-beta.4", "osmtogeojson": "^3.0.0-beta.4",
"parcel": "^1.2.4", "parcel": "^1.2.4",
"postcss": "^7.0.35", "postcss": "^7.0.35",
"prompt-sync": "^4.2.0",
"sharp": "^0.27.0", "sharp": "^0.27.0",
"slick-carousel": "^1.8.1", "slick-carousel": "^1.8.1",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2", "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",
"tslint": "^6.1.3",
"turf": "^3.0.14" "turf": "^3.0.14"
}, },
"devDependencies": { "devDependencies": {
@ -73,6 +82,7 @@
"read-file": "^0.2.0", "read-file": "^0.2.0",
"ts-node": "^9.0.0", "ts-node": "^9.0.0",
"ts-node-dev": "^1.0.0-pre.63", "ts-node-dev": "^1.0.0-pre.63",
"tslint-no-circular-imports": "^0.7.0",
"turndown": "^7.0.0", "turndown": "^7.0.0",
"typescript": "^3.9.7", "typescript": "^3.9.7",
"write-file": "^1.0.0" "write-file": "^1.0.0"

View file

@ -17,9 +17,7 @@ function createTable(preferences: any) {
} }
rendered = true; rendered = true;
const prefs = []; const prefs = [];
console.log(preferences);
for (const key in preferences) { for (const key in preferences) {
console.log(key)
const pref = connection.GetPreference(key, ""); const pref = connection.GetPreference(key, "");
let value: UIElement = new FixedUiElement(pref.data); let value: UIElement = new FixedUiElement(pref.data);
@ -42,13 +40,11 @@ function createTable(preferences: any) {
prefs.push(...c); prefs.push(...c);
} }
const el = new Combine( new Combine(
["<table>", ["<table>",
...prefs, ...prefs,
"</table>"] "</table>"]
); // .AttachTo("maindiv"); ).AttachTo("maindiv");
console.log(el.InnerRender())
el.AttachTo("maindiv");
} }
connection.preferencesHandler.preferences.addCallback((prefs) => createTable(prefs)) connection.preferencesHandler.preferences.addCallback((prefs) => createTable(prefs))

20
scripts/ScriptUtils.ts Normal file
View file

@ -0,0 +1,20 @@
import {lstatSync, readdirSync} from "fs";
export default class ScriptUtils {
public static readDirRecSync(path): string[] {
const result = []
for (const entry of readdirSync(path)) {
const fullEntry = path + "/" + entry
const stats = lstatSync(fullEntry)
if (stats.isDirectory()) {
// Subdirectory
// @ts-ignore
result.push(...ScriptUtils.readDirRecSync(fullEntry))
} else {
result.push(fullEntry)
}
}
return result;
}
}

View file

@ -9,6 +9,10 @@ function genImages() {
const allNames: string[] = []; const allNames: string[] = [];
for (const path of dir) { for (const path of dir) {
if(path.endsWith("license_info.json")){
continue;
}
if (!path.endsWith(".svg")) { if (!path.endsWith(".svg")) {
throw "Non-svg file detected in the svg files: " + path; throw "Non-svg file detected in the svg files: " + path;
} }

View file

@ -0,0 +1,136 @@
import ScriptUtils from "./ScriptUtils";
import {Utils} from "../Utils";
import {lstatSync, readdirSync, readFileSync, writeFileSync} from "fs";
Utils.runningFromConsole = true
import LayerConfig from "../Customizations/JSON/LayerConfig";
import {error} from "util";
import * as licenses from "../assets/generated/license_info.json"
import SmallLicense from "../Models/smallLicense";
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
import {LayerConfigJson} from "../Customizations/JSON/LayerConfigJson";
import {Layer} from "leaflet";
// This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
// It spits out an overview of those to be used to load them
// First, remove the old file. It might be buggy!
writeFileSync("./assets/generated/known_layers_and_themes.json", JSON.stringify({
"layers": [],
"themes": []
}))
const layerFiles = ScriptUtils.readDirRecSync("./assets/layers")
.filter(path => path.indexOf(".json") > 0)
.filter(path => path.indexOf("license_info.json") < 0)
.map(path => {
try {
const parsed = JSON.parse(readFileSync(path, "UTF8"));
return parsed
} catch (e) {
console.error("Could not parse file ", path, "due to ", e)
}
})
const themeFiles: any[] = ScriptUtils.readDirRecSync("./assets/themes")
.filter(path => path.indexOf(".json") > 0)
.filter(path => path.indexOf("license_info.json") < 0)
.map(path => {
return JSON.parse(readFileSync(path, "UTF8"));
})
writeFileSync("./assets/generated/known_layers_and_themes.json", JSON.stringify({
"layers": layerFiles,
"themes": themeFiles
}))
console.log("Discovered ", layerFiles.length, "layers and ", themeFiles.length, "themes\n")
console.log(" ---------- VALIDATING ---------")
// ------------- VALIDATION --------------
const licensePaths = []
for (const i in licenses) {
licensePaths.push(licenses[i].path)
}
const knownPaths = new Set<string>(licensePaths)
function validateLayer(layerJson: LayerConfigJson, context?: string): string[] {
let errorCount = [];
if (layerJson["overpassTags"] !== undefined) {
errorCount.push("CRIT! Layer ", layerJson.id, "still uses the old 'overpassTags'-format. Please use 'source: {osmTags: <tags>}' instead")
}
try {
const layer = new LayerConfig(layerJson, "test", true)
const images = Array.from(layer.ExtractImages())
const remoteImages = images.filter(img => img.indexOf("http") == 0)
for (const remoteImage of remoteImages) {
errorCount.push("Found a remote image: "+ remoteImage+ " in layer "+ layer.id)
}
for (const image of images) {
if (!knownPaths.has(image)) {
const ctx = context === undefined ? "" : ` in a layer defined in the theme ${context}`
errorCount.push(`Image with path ${image} not found or not attributed; it is used in ${layer.id}${ctx}`)
}
}
} catch (e) {
return [`Layer ${layerJson.id}` ?? JSON.stringify(layerJson).substring(0, 50)+" is invalid: "+ e]
}
return errorCount
}
let layerErrorCount = []
const knownLayerIds = new Set<string>();
for (const layerFile of layerFiles) {
knownLayerIds.add(layerFile.id)
layerErrorCount .push(...validateLayer(layerFile))
}
let themeErrorCount = []
for (const themeFile of themeFiles) {
for (const layer of themeFile.layers) {
if (typeof layer === "string") {
if (!knownLayerIds.has(layer)) {
themeErrorCount.push("Unknown layer id: "+ layer)
}
} else {
if (layer.builtin !== undefined) {
if (!knownLayerIds.has(layer.builtin)) {
themeErrorCount.push("Unknown layer id: "+ layer.builtin+ "(which uses inheritance)")
}
} else {
// layer.builtin contains layer overrides - we can skip those
layerErrorCount .push(...validateLayer(layer, themeFile.id))
}
}
}
themeFile.layers = themeFile.layers
.filter(l => typeof l != "string") // We remove all the builtin layer references as they don't work with ts-node for some weird reason
.filter(l => l.builtin === undefined)
try {
const theme = new LayoutConfig(themeFile, true, "test")
if (theme.id !== theme.id.toLowerCase()) {
themeErrorCount.push("Theme ids should be in lowercase, but it is "+ theme.id)
}
} catch (e) {
themeErrorCount.push("Could not parse theme "+ themeFile["id"]+ "due to", e)
}
}
console.log("LE", layerErrorCount)
if (layerErrorCount.length + themeErrorCount.length == 0) {
console.log("All good!")
} else {
const errors = layerErrorCount.concat(themeErrorCount).join("\n")
console.log(errors)
const msg = (`Found ${errors.length} errors in the layers; ${themeErrorCount} errors in the themes`)
if(process.argv.indexOf("--no-fail") >= 0) {
console.log(msg)
}else if(process.argv.indexOf("--report") >= 0){
writeFileSync("layer_report.txt", errors)
}else{
throw msg;
}
}

View file

@ -3,13 +3,13 @@ import {Utils} from "../Utils";
Utils.runningFromConsole = true; Utils.runningFromConsole = true;
import LayoutConfig from "../Customizations/JSON/LayoutConfig"; import LayoutConfig from "../Customizations/JSON/LayoutConfig";
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
import {existsSync, mkdirSync, readFileSync, writeFile, writeFileSync} from "fs"; import {existsSync, mkdirSync, readFileSync, writeFile, writeFileSync} from "fs";
import Locale from "../UI/i18n/Locale"; import Locale from "../UI/i18n/Locale";
import Translations from "../UI/i18n/Translations"; import Translations from "../UI/i18n/Translations";
import {Translation} from "../UI/i18n/Translation"; import {Translation} from "../UI/i18n/Translation";
import Constants from "../Models/Constants"; import Constants from "../Models/Constants";
import * as all_known_layouts from "../assets/generated/known_layers_and_themes.json"
import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson";
const sharp = require('sharp'); const sharp = require('sharp');
@ -234,9 +234,12 @@ if (!existsSync(generatedDir)) {
} }
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom"] const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom"]
const all = AllKnownLayouts.allSets; const all : LayoutConfigJson[] = all_known_layouts.themes;
for (const layoutName in all) { for (const i in all) {
const layoutConfigJson : LayoutConfigJson = all[i]
const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts")
const layoutName = layout.id
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) { if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`); console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`);
continue; continue;
@ -246,7 +249,6 @@ for (const layoutName in all) {
console.log("Could not write manifest for ", layoutName, " because ", err) console.log("Could not write manifest for ", layoutName, " because ", err)
} }
}; };
const layout = all[layoutName];
validate(layout) validate(layout)
createManifest(layout, "").then(manifObj => { createManifest(layout, "").then(manifObj => {
const manif = JSON.stringify(manifObj, undefined, 2); const manif = JSON.stringify(manifObj, undefined, 2);

View file

@ -0,0 +1,213 @@
import {Utils} from "../Utils";
import {lstatSync, readdirSync, readFileSync, writeFileSync, unlinkSync} from "fs";
import SmallLicense from "../Models/smallLicense";
import ScriptUtils from "./ScriptUtils";
Utils.runningFromConsole = true;
/**
* Sweeps the entire 'assets/' (except assets/generated) directory for image files and any 'license_info.json'-file.
* Checks that the license info is included for each of them and generates a compiles license_info.json for those
*/
function generateLicenseInfos(paths: string[]): SmallLicense[] {
const licenses = []
for (const path of paths) {
const parsed = JSON.parse(readFileSync(path, "UTF-8"))
if (Array.isArray(parsed)) {
const l: SmallLicense[] = parsed
for (const smallLicens of l) {
smallLicens.path = path.substring(0, path.length - "license_info.json".length) + smallLicens.path
}
licenses.push(...l)
} else {
const smallLicens: SmallLicense = parsed;
/*if(parsed.license === "CC-BY"){
console.log("Rewriting ", path)
parsed.license === "CC-BY 4.0"
writeFileSync(path, JSON.stringify(smallLicens, null, " "))
}*/
smallLicens.path = path.substring(0, 1 + path.lastIndexOf("/")) + smallLicens.path
licenses.push(smallLicens)
}
}
return licenses
}
function missingLicenseInfos(licenseInfos: SmallLicense[], allIcons: string[]) {
const missing = []
const knownPaths = new Set<string>()
for (const licenseInfo of licenseInfos) {
knownPaths.add(licenseInfo.path)
}
for (const iconPath of allIcons) {
if (iconPath.indexOf("license_info.json") >= 0) {
continue;
}
if (knownPaths.has(iconPath)) {
continue;
}
missing.push(iconPath)
}
return missing;
}
const prompt = require('prompt-sync')();
const knownLicenses = new Map<string, SmallLicense>()
knownLicenses.set("cf", {
authors: ["Pieter Fiers", "Thibault Declercq", "Pierre Barban", "Joost Schouppe", "Pieter Vander Vennet"],
path: undefined,
license: "CC-BY-SA",
sources: ["https://osoc.be/editions/2020/cyclofix"]
})
knownLicenses.set("me", {
authors: ["Pieter Vander Vennet"],
path: undefined,
license: "CC0",
sources: []
})
knownLicenses.set("t", {
authors: [],
path: undefined,
license: "CC0; trivial",
sources: []
})
knownLicenses.set("na", {
authors: [],
path: undefined,
license: "CC0",
sources: []
})
knownLicenses.set("chrn", {
authors: ["Christian Neumann"],
path: undefined,
license: "CC-BY-SA 3.0",
sources: ["https://utopicode.de/", "https://github.com/chrneumann/MapComplete"]
})
knownLicenses.set("klimaan", {
authors: ["Klimaan VZW"],
path: undefined,
license: "CC-BY-SA 3.0",
sources: ["https://klimaan.be/"]
})
function promptLicenseFor(path): SmallLicense {
console.log("License abbreviations:")
knownLicenses.forEach((value, key) => {
console.log(key, " => ", value)
})
const author = prompt("What is the author for artwork " + path + "? (or: [Q]uit, [S]kip) > ")
path = path.substring(path.lastIndexOf("/") + 1)
if (knownLicenses.has(author)) {
const license = knownLicenses.get(author);
license.path = path;
return license;
}
if (author == "s") {
return null;
}
if (author == "Q" || author == "q" || author == "") {
throw "Quitting now!"
}
let authors = author.split(";")
if (author.toLowerCase() == "none") {
authors = []
}
return {
authors: author.split(";"),
path: path,
license: prompt("What is the license for artwork " + path + "? > "),
sources: prompt("Where was this artwork found? > ").split(";")
}
}
function createLicenseInfoFor(path): void {
const li = promptLicenseFor(path);
if (li == null) {
return;
}
writeFileSync(path + ".license_info.json", JSON.stringify(li, null, " "))
}
function cleanLicenseInfo(allPaths: string[], allLicenseInfos: SmallLicense[]){
// Read the license info file from the generated assets, creates a compiled license info in every directory
// Note: this removes all the old license infos
for (const licensePath of licensePaths) {
unlinkSync(licensePath)
}
const perDirectory = new Map<string, SmallLicense[]>()
for (const license of allLicenseInfos) {
const p = license.path
const dir = p.substring(0, p.lastIndexOf("/"))
license.path = p.substring(dir.length + 1)
if(!perDirectory.has(dir)){
perDirectory.set(dir, [])
}
perDirectory.get(dir).push(license)
}
perDirectory.forEach((licenses, dir) => {
writeFileSync( dir+"/license_info.json", JSON.stringify(licenses, null, 2))
})
}
function queryMissingLicenses(missingLicenses: string[]) {
process.on('SIGINT', function () {
console.log("Aborting... Bye!");
process.exit();
});
let i = 1;
for (const missingLicens of missingLicenses) {
console.log(i + " / " + missingLicenses.length)
i++;
if (i < missingLicenses.length - 5) {
// continue
}
createLicenseInfoFor(missingLicens)
}
console.log("You're through!")
}
console.log("Checking and compiling license info")
const contents = ScriptUtils.readDirRecSync("./assets")
.filter(entry => entry.indexOf("./assets/generated") != 0)
const licensePaths = contents.filter(entry => entry.indexOf("license_info.json") >= 0)
const licenseInfos = generateLicenseInfos(licensePaths);
writeFileSync("./assets/generated/license_info.json", JSON.stringify(licenseInfos, null, " "))
const artwork = contents.filter(pth => pth.match(/(.svg|.png|.jpg)$/i) != null)
const missingLicenses = missingLicenseInfos(licenseInfos, artwork)
if(process.argv.indexOf("--prompt") >= 0 || process.argv.indexOf("--query") >= 0 ) {
queryMissingLicenses(missingLicenses)
}
if(missingLicenses.length > 0){
const msg = `There are ${missingLicenses.length} licenses missing.`
if(process.argv.indexOf("--no-fail") >= 0){
console.log(msg)
}else if(process.argv.indexOf("--report") >= 0){
writeFileSync("missing_licenses.txt", missingLicenses.join("\n"))
} else{
throw msg
}
}
cleanLicenseInfo(licensePaths, licenseInfos)

View file

@ -0,0 +1,58 @@
import {Utils} from "../Utils";
Utils.runningFromConsole = true;
import {equal} from "assert";
import T from "./TestHelper";
import {FromJSON} from "../Customizations/JSON/FromJSON";
import Locale from "../UI/i18n/Locale";
import Translations from "../UI/i18n/Translations";
import {UIEventSource} from "../Logic/UIEventSource";
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
import {Translation} from "../UI/i18n/Translation";
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
import PublicHolidayInput from "../UI/OpeningHours/PublicHolidayInput";
import {SubstitutedTranslation} from "../UI/SubstitutedTranslation";
import {Tag} from "../Logic/Tags/Tag";
import {And} from "../Logic/Tags/And";
import {ImageSearcher} from "../Logic/Actors/ImageSearcher";
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
import AllKnownLayers from "../Customizations/AllKnownLayers";
import LayerConfig from "../Customizations/JSON/LayerConfig";
new T("ImageAttribution Tests", [
[
"Should find all the images",
() => {
const pumps: LayerConfig = AllKnownLayers.sharedLayers["bike_repair_station"]
const images = pumps.ExtractImages();
const expectedValues = ['./assets/layers/bike_repair_station/repair_station.svg',
'./assets/layers/bike_repair_station/repair_station_pump.svg',
'./assets/layers/bike_repair_station/broken_pump_2.svg',
'./assets/layers/bike_repair_station/pump.svg',
'./assets/themes/cyclofix/fietsambassade_gent_logo_small.svg',
'./assets/layers/bike_repair_station/pump_example_manual.jpg',
'./assets/layers/bike_repair_station/pump_example.png',
'./assets/layers/bike_repair_station/pump_example_round.jpg',
'./assets/layers/bike_repair_station/repair_station_example.jpg']
for (const expected of expectedValues) {
T.isTrue(images.has(expected), expected + " not found")
}
}
],
[
"Test image discovery regex",
() => {
const tr = new Translation({en: "XYZ <img src='a.svg'/> XYZ <img src=\"some image.svg\"></img> XYZ <img src=b.svg/>"})
const images = new Set<string>(tr.ExtractImages(false));
equal(3, images.size)
T.isTrue(images.has("a.svg"), "a.svg not found")
T.isTrue(images.has("b.svg"), "b.svg not found")
T.isTrue(images.has("some image.svg"), "some image.svg not found")
}
]
])

View file

@ -25,4 +25,9 @@ export default class T {
} }
} }
static isTrue(b: boolean, msg: string) {
if(!b){
throw "Expected true, but got false: "+msg
}
}
} }

10
tslint.json Normal file
View file

@ -0,0 +1,10 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended",
"tslint-no-circular-imports"
],
"jsRules": {},
"rules": {},
"rulesDirectory": []
}