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 {LayerConfigJson} from "./JSON/LayerConfigJson";
import * as grass_in_parks from "../assets/layers/village_green/grass_in_parks.json"
import * as village_green from "../assets/layers/village_green/village_green.json"
import * as known_layers from "../assets/generated/known_layers_and_themes.json"
import {Utils} from "../Utils";
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...
public static sharedLayers: Map<string, LayerConfig> = AllKnownLayers.getSharedLayers();
public static sharedLayersJson: Map<string, any> = AllKnownLayers.getSharedLayersJson();
private static sharedLayersListRaw: LayerConfigJson[] = known_layers.layers;
private static getSharedLayers(): 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")
sharedLayers.set(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;
}
private static getSharedLayersJson(): 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[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 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 {
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 {
const layout = new LayoutConfig(cyclofix)
public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts();
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 m = now.getMonth() + 1;
const day = new Date().getDate() + 1;
@ -86,8 +41,15 @@ export class AllKnownLayouts {
}
private static AllLayouts(): Map<string, LayoutConfig> {
this.allLayers = new Map<string, LayerConfig>();
for (const layout of this.layoutsList) {
const dict: Map<string, LayoutConfig> = new Map();
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++) {
let layer = layout.layers[i];
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;
}
}
const allSets: Map<string, LayoutConfig> = new Map();
for (const layout of this.layoutsList) {
allSets[layout.id] = layout;
allSets[layout.id.toLowerCase()] = layout;
}
return allSets;
return dict;
}
}

View file

@ -7,6 +7,7 @@ import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
import {Translation} from "../../UI/i18n/Translation";
import Img from "../../UI/Base/Img";
import Svg from "../../Svg";
import {Utils} from "../../Utils";
import Combine from "../../UI/Base/Combine";
import {VariableUiElement} from "../../UI/Base/VariableUIElement";
@ -18,7 +19,6 @@ import SourceConfig from "./SourceConfig";
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
import {Tag} from "../../Logic/Tags/Tag";
import SubstitutingTag from "../../Logic/Tags/SubstitutingTag";
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 {
public readonly id: string;
public readonly maintainer: string;
public readonly credits?: string;
public readonly changesetmessage?: string;
public readonly version: string;
public readonly language: string[];
@ -48,6 +49,7 @@ export default class LayoutConfig {
this.id = json.id;
context = (context ?? "") + "." + this.id;
this.maintainer = json.maintainer;
this.credits = json.credits;
this.changesetmessage = json.changesetmessage;
this.version = json.version;
this.language = [];
@ -182,4 +184,14 @@ export default class LayoutConfig {
custom.splice(0, 0, msg);
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'
*/
id: string;
/**
* Who helped to create this theme and should be attributed?
*/
credits?: string;
/**
* Who does maintian this preset?
*/

View file

@ -90,6 +90,9 @@ export default class TagRenderingConfig {
this.multiAnswer = json.multiAnswer ?? false
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) => {
@ -254,5 +257,16 @@ export default class TagRenderingConfig {
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`
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.
- 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
- 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:
- 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";`

View file

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

View file

@ -2,7 +2,7 @@ import { Utils } from "../Utils";
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
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.
### Query parameters
# Documentation
By adding extra query parameters, more options are available to influence:
**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
All documentation can be found in [here](Docs/)
# 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
# Attributions
# Attribution
Data from OpenStreetMap
Background layer selection: curated by https://github.com/osmlab/editor-layer-index
Images from Wikipedia/Wikimedia
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
Icons are attributed in various 'license_info.json'-files and can be found in the app.
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 * as L from "leaflet"
/**
* The bottom right attribution panel in the leaflet map
*/
export default class Attribution extends UIElement {
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[] = []
for (const k in AllKnownLayouts.allSets) {
const layout: LayoutConfig = AllKnownLayouts.allSets[k];
if (k === personal.id) {
for (const layout of AllKnownLayouts.layoutsList) {
if (layout.id === personal.id) {
if (State.state.osmConnection.userDetails.data.csCount < Constants.userJourney.personalLayoutUnlock) {
continue;
}
}
if (layout.id !== k) {
continue; // This layout was added multiple time due to an uppercase
}
linkButton.push(this.createLinkButton(layout));
}

View file

@ -8,6 +8,8 @@ export class Translation extends UIElement {
public static forcedLanguage = undefined;
public readonly translations: object
return
allIcons;
constructor(translations: object, context?: string) {
super(Locale.language)
@ -17,6 +19,9 @@ export class Translation extends UIElement {
let count = 0;
for (const translationsKey in translations) {
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;
if (count === 0) {
@ -102,7 +107,6 @@ export class Translation extends UIElement {
return new Translation(this.translations)
}
FirstSentence() {
const tr = {};
@ -115,4 +119,38 @@ export class Translation extends UIElement {
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": {
"en": "Does this bicycle parking have spots for cargo bikes?",
"nl": "Heeft deze fietsparking plaats voor bakfietsen?",
"fr": "TODO: fr",
"gl": "Este aparcadoiro de bicicletas ten espazo para bicicletas de carga?",
"de": "Gibt es auf diesem Fahrrad-Parkplatz Plätze für Lastenfahrräder?"
},
@ -303,7 +302,6 @@
"then": {
"en": "This parking has room for cargo bikes",
"nl": "Deze parking heeft plaats voor bakfietsen",
"fr": "TODO: fr",
"gl": "Este aparcadoiro ten espazo para bicicletas de carga.",
"de": "Dieser Parkplatz bietet Platz für Lastenfahrräder"
}
@ -313,7 +311,6 @@
"then": {
"en": "This parking has designated (official) spots for cargo bikes.",
"nl": "Er zijn speciale plaatsen voorzien voor bakfietsen",
"fr": "TODO: fr",
"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."
}
@ -323,7 +320,6 @@
"then": {
"en": "You're not allowed to park cargo bikes",
"nl": "Je mag hier geen bakfietsen parkeren",
"fr": "TODO: fr",
"gl": "Non está permitido aparcar bicicletas de carga",
"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": {
"en": "Surface area: {_surface:ha}Ha",
"mappings": {
"en": "Surface area: {_surface:ha}Ha"
},
"mappings":[ {
"if": "_surface:ha=0",
"then": ""
}
}
"then": {"*":""}
}]
}
],
"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,
"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": [
{

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": {
"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",
"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"
"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=\"./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": {
"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>",
"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>"
"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=\"./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": {
"nl": "Wat is het ID uitgegeven door Onroerend Erfgoed Vlaanderen?",
@ -359,8 +359,8 @@
},
{
"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>",
"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>"
"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=\"./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": {
"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"
],
"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",
"version": "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"
],
"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",
"startLat": 0,
"startLon": 0,
"startZoom": 1,
"widenFactor": 0.001,
"socialImage": "",
"hideFromOverview": true,
"layers": [
{
"id": "orchards",
@ -27,11 +28,12 @@
"nl": "Boomgaarden"
},
"minzoom": 12,
"overpassTags": {
"source":{
"osmTags": {
"and": [
"landuse=orchard"
]
},
} },
"title": {
"render": {
"nl": "Boomgaard"
@ -72,11 +74,12 @@
"nl": "Boom"
},
"minzoom": 12,
"overpassTags": {
"source":{
"osmTags": {
"and": [
"natural=tree"
]
},
}},
"title": {
"render": {
"nl": "Boom"
@ -138,7 +141,7 @@
],
"hideUnderlayingFeaturesMinPercentage": 0,
"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": {
"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"
},
"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">
<meta property="og:image" content="./assets/SocialImage.png">
<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="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];
@ -64,7 +64,7 @@ if (path !== "index.html" && path !== "") {
console.log("Using layout", defaultLayout);
}
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");
@ -81,7 +81,7 @@ if (layoutFromBase64.startsWith("http")) {
$.ajax({
url: link,
success: function (data) {
success: (data) => {
try {
const parsed = JSON.parse(data);
@ -121,6 +121,6 @@ if (layoutFromBase64.startsWith("http")) {
.SetStyle("pointer-events: all;")
.AttachTo("topleft-tools");
}
window.addEventListener('contextmenu', function (e) { // Not compatible with IE < 9
window.addEventListener('contextmenu', (e) => { // Not compatible with IE < 9
e.preventDefault();
}, false);

102
package-lock.json generated
View file

@ -4029,6 +4029,11 @@
"integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA==",
"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": {
"version": "1.5.4",
"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",
"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": {
"version": "3.0.0",
"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",
"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": {
"version": "3.5.1",
"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": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",

View file

@ -8,19 +8,25 @@
"main": "index.js",
"scripts": {
"increase-memory": "export NODE_OPTIONS=--max_old_space_size=4096",
"start": "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",
"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 && 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:images": "ts-node scripts/generateIncludedImages.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'",
"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/*/*",
"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: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",
"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"
},
"keywords": [
@ -38,6 +44,7 @@
"@types/leaflet-providers": "^1.2.0",
"@types/leaflet.markercluster": "^1.4.3",
"@types/lz-string": "^1.3.34",
"@types/prompt-sync": "^4.1.0",
"autoprefixer": "^9.8.6",
"country-language": "^0.1.7",
"email-validator": "^2.0.4",
@ -58,9 +65,11 @@
"osmtogeojson": "^3.0.0-beta.4",
"parcel": "^1.2.4",
"postcss": "^7.0.35",
"prompt-sync": "^4.2.0",
"sharp": "^0.27.0",
"slick-carousel": "^1.8.1",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",
"tslint": "^6.1.3",
"turf": "^3.0.14"
},
"devDependencies": {
@ -73,6 +82,7 @@
"read-file": "^0.2.0",
"ts-node": "^9.0.0",
"ts-node-dev": "^1.0.0-pre.63",
"tslint-no-circular-imports": "^0.7.0",
"turndown": "^7.0.0",
"typescript": "^3.9.7",
"write-file": "^1.0.0"

View file

@ -17,9 +17,7 @@ function createTable(preferences: any) {
}
rendered = true;
const prefs = [];
console.log(preferences);
for (const key in preferences) {
console.log(key)
const pref = connection.GetPreference(key, "");
let value: UIElement = new FixedUiElement(pref.data);
@ -42,13 +40,11 @@ function createTable(preferences: any) {
prefs.push(...c);
}
const el = new Combine(
new Combine(
["<table>",
...prefs,
"</table>"]
); // .AttachTo("maindiv");
console.log(el.InnerRender())
el.AttachTo("maindiv");
).AttachTo("maindiv");
}
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[] = [];
for (const path of dir) {
if(path.endsWith("license_info.json")){
continue;
}
if (!path.endsWith(".svg")) {
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;
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
import {existsSync, mkdirSync, readFileSync, writeFile, writeFileSync} from "fs";
import Locale from "../UI/i18n/Locale";
import Translations from "../UI/i18n/Translations";
import {Translation} from "../UI/i18n/Translation";
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');
@ -234,9 +234,12 @@ if (!existsSync(generatedDir)) {
}
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) {
console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`);
continue;
@ -246,7 +249,6 @@ for (const layoutName in all) {
console.log("Could not write manifest for ", layoutName, " because ", err)
}
};
const layout = all[layoutName];
validate(layout)
createManifest(layout, "").then(manifObj => {
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": []
}