diff --git a/.github/workflows/deploy_pietervdvn.yml b/.github/workflows/deploy_pietervdvn.yml index f787b077d5..36d4ebc269 100644 --- a/.github/workflows/deploy_pietervdvn.yml +++ b/.github/workflows/deploy_pietervdvn.yml @@ -3,7 +3,8 @@ on: push: branches: - develop - - feature/svelte + - feature/* + - theme/* jobs: build: runs-on: ubuntu-latest diff --git a/.gitpod.yml b/.gitpod.yml index d7253fb462..964b5c27f1 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,6 +1,9 @@ tasks: - init: npm run init command: npm run start + name: Initialize and start MapComplete + - name: Generate Layeroverview + command: npm run generate:layeroverview ports: - name: MapComplete Website @@ -11,4 +14,7 @@ vscode: extensions: - "esbenp.prettier-vscode" - "eamodio.gitlens" - - "GitHub.vscode-pull-request-github" + - "github.vscode-pull-request-github" + - "svelte.svelte-vscode" + - "bradlc.vscode-tailwindcss" + - "editorconfig.editorconfig" diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 8ca85028f6..f2dca9d05f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,8 +2,9 @@ "recommendations": [ "esbenp.prettier-vscode", "eamodio.gitlens", - "GitHub.vscode-pull-request-github", + "github.vscode-pull-request-github", "svelte.svelte-vscode", - "bradlc.vscode-tailwindcss" + "bradlc.vscode-tailwindcss", + "editorconfig.editorconfig" ] -} \ No newline at end of file +} diff --git a/Logic/ElementStorage.ts b/Logic/ElementStorage.ts index 49213b99f6..8d9723f8e4 100644 --- a/Logic/ElementStorage.ts +++ b/Logic/ElementStorage.ts @@ -38,7 +38,7 @@ export class ElementStorage { return es } - getEventSourceById(elementId): UIEventSource { + getEventSourceById(elementId): UIEventSource | undefined { if (elementId === undefined) { return undefined } diff --git a/Logic/Osm/OsmObject.ts b/Logic/Osm/OsmObject.ts index 2982778943..b9bff14ec8 100644 --- a/Logic/Osm/OsmObject.ts +++ b/Logic/Osm/OsmObject.ts @@ -163,6 +163,11 @@ export abstract class OsmObject { }) } + public static DownloadHistory(id: NodeId): UIEventSource + public static DownloadHistory(id: WayId): UIEventSource + public static DownloadHistory(id: RelationId): UIEventSource + + public static DownloadHistory(id: OsmId): UIEventSource public static DownloadHistory(id: string): UIEventSource { if (OsmObject.historyCache.has(id)) { return OsmObject.historyCache.get(id) @@ -180,6 +185,7 @@ export abstract class OsmObject { const osmObjects: OsmObject[] = [] for (const element of elements) { let osmObject: OsmObject = null + element.nodes = [] switch (type) { case "node": osmObject = new OsmNode(idN) diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts index eb8479e7fe..faddf29063 100644 --- a/Logic/SimpleMetaTagger.ts +++ b/Logic/SimpleMetaTagger.ts @@ -69,7 +69,7 @@ export class ReferencingWaysMetaTagger extends SimpleMetaTagger { { keys: ["_referencing_ways"], isLazy: true, - doc: "_referencing_ways contains - for a node - which ways use this this node as point in their geometry. ", + doc: "_referencing_ways contains - for a node - which ways use this this node as point in their geometry. If the preset has 'snapToLayer' defined, the icon will be calculated based on the preset tags with `_referencing_ways=[\"way/-1\"]` added.", }, (feature, _, __, state) => { if (!ReferencingWaysMetaTagger.enabled) { @@ -80,20 +80,25 @@ export class ReferencingWaysMetaTagger extends SimpleMetaTagger { if (!id.startsWith("node/")) { return false } - console.trace("Downloading referencing ways for", feature.properties.id) - OsmObject.DownloadReferencingWays(id).then((referencingWays) => { - const currentTagsSource = state.allElements?.getEventSourceById(id) ?? [] - const wayIds = referencingWays.map((w) => "way/" + w.id) - wayIds.sort() - const wayIdsStr = wayIds.join(";") - if ( - wayIdsStr !== "" && - currentTagsSource.data["_referencing_ways"] !== wayIdsStr - ) { - currentTagsSource.data["_referencing_ways"] = wayIdsStr - currentTagsSource.ping() + + const currentTagsSource = state.allElements?.getEventSourceById(id) + if (currentTagsSource === undefined) { + return + } + Utils.AddLazyPropertyAsync( + currentTagsSource.data, + "_referencing_ways", + async () => { + const referencingWays = await OsmObject.DownloadReferencingWays(id) + const wayIds = referencingWays.map((w) => "way/" + w.id) + wayIds.sort() + const wayIdsStr = wayIds.join(";") + if (wayIdsStr !== "" && currentTagsSource.data[""] !== wayIdsStr) { + currentTagsSource.data["_referencing_ways"] = wayIdsStr + currentTagsSource.ping() + } } - }) + ) return true } @@ -282,16 +287,9 @@ export default class SimpleMetaTaggers { }, }) - Object.defineProperty(feature.properties, "_surface:ha", { - enumerable: false, - configurable: true, - get: () => { - const sqMeters = GeoOperations.surfaceAreaInSqMeters(feature) - const sqMetersHa = "" + Math.floor(sqMeters / 1000) / 10 - delete feature.properties["_surface:ha"] - feature.properties["_surface:ha"] = sqMetersHa - return sqMetersHa - }, + Utils.AddLazyProperty(feature.properties, "_surface:ha", () => { + const sqMeters = GeoOperations.surfaceAreaInSqMeters(feature) + return "" + Math.floor(sqMeters / 1000) / 10 }) return true @@ -443,8 +441,6 @@ export default class SimpleMetaTaggers { } }, }) - - const tagsSource = state.allElements.getEventSourceById(feature.properties.id) } ) private static directionSimplified = new SimpleMetaTagger( diff --git a/Logic/Tags/RegexTag.ts b/Logic/Tags/RegexTag.ts index 988f9987c4..c6f448fcbd 100644 --- a/Logic/Tags/RegexTag.ts +++ b/Logic/Tags/RegexTag.ts @@ -25,6 +25,10 @@ export class RegexTag extends TagsFilter { if (typeof possibleRegex === "string") { return fromTag === possibleRegex } + if (typeof fromTag.match !== "function") { + console.error("Error: fromTag is not a regex: ", fromTag, possibleRegex) + throw "Error: fromTag is not a regex: " + fromTag + possibleRegex + } return fromTag.match(possibleRegex) !== null } diff --git a/Models/ThemeConfig/Json/LayerConfigJson.ts b/Models/ThemeConfig/Json/LayerConfigJson.ts index 69e132e8a0..4baee1063a 100644 --- a/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -303,8 +303,11 @@ export interface LayerConfigJson { */ tagRenderings?: ( | string - | { builtin: string | string[]; override: Partial } - | { id: string; builtin: string[]; override: Partial } + | { + id?: string + builtin: string | string[] + override: Partial + } | QuestionableTagRenderingConfigJson | (RewritableConfigJson< ( diff --git a/Models/ThemeConfig/PointRenderingConfig.ts b/Models/ThemeConfig/PointRenderingConfig.ts index 8c3712f1fc..8183ab0320 100644 --- a/Models/ThemeConfig/PointRenderingConfig.ts +++ b/Models/ThemeConfig/PointRenderingConfig.ts @@ -5,7 +5,7 @@ import { TagUtils } from "../../Logic/Tags/TagUtils" import { Utils } from "../../Utils" import Svg from "../../Svg" import WithContextLoader from "./WithContextLoader" -import { UIEventSource } from "../../Logic/UIEventSource" +import { Store, UIEventSource } from "../../Logic/UIEventSource" import BaseUIElement from "../../UI/BaseUIElement" import { FixedUiElement } from "../../UI/Base/FixedUiElement" import Img from "../../UI/Base/Img" @@ -164,7 +164,7 @@ export default class PointRenderingConfig extends WithContextLoader { return PointRenderingConfig.FromHtmlMulti(htmlDefs, rotation, false, defaultPin) } - public GetSimpleIcon(tags: UIEventSource): BaseUIElement { + public GetSimpleIcon(tags: Store): BaseUIElement { const self = this if (this.icon === undefined) { return undefined @@ -175,7 +175,7 @@ export default class PointRenderingConfig extends WithContextLoader { } public GenerateLeafletStyle( - tags: UIEventSource, + tags: Store, clickable: boolean, options?: { noSize?: false | boolean @@ -272,7 +272,7 @@ export default class PointRenderingConfig extends WithContextLoader { } } - private GetBadges(tags: UIEventSource): BaseUIElement { + private GetBadges(tags: Store): BaseUIElement { if (this.iconBadges.length === 0) { return undefined } @@ -304,7 +304,7 @@ export default class PointRenderingConfig extends WithContextLoader { ).SetClass("absolute bottom-0 right-1/3 h-1/2 w-0") } - private GetLabel(tags: UIEventSource): BaseUIElement { + private GetLabel(tags: Store): BaseUIElement { if (this.label === undefined) { return undefined } diff --git a/Models/ThemeConfig/TagRenderingConfig.ts b/Models/ThemeConfig/TagRenderingConfig.ts index a20011d74d..1bd4149da1 100644 --- a/Models/ThemeConfig/TagRenderingConfig.ts +++ b/Models/ThemeConfig/TagRenderingConfig.ts @@ -335,6 +335,10 @@ export default class TagRenderingConfig { if (allKeys.length > 1 && !allHaveIfNot) { throw `${context}: A multi-answer is defined, which generates values over multiple keys. Please define ifnot-tags too on every mapping` } + + if (allKeys.length > 1 && this.freeform?.key !== undefined) { + throw `${context}: A multi-answer is defined, which generates values over multiple keys. This is incompatible with having a freeform key` + } } } diff --git a/UI/BigComponents/AddNewMarker.ts b/UI/BigComponents/AddNewMarker.ts index 6c3fe93d6e..ab2c727301 100644 --- a/UI/BigComponents/AddNewMarker.ts +++ b/UI/BigComponents/AddNewMarker.ts @@ -24,13 +24,17 @@ export default class AddNewMarker extends Combine { for (const preset of filteredLayer.layerDef.presets) { const tags = TagUtils.KVtoProperties(preset.tags) const icon = layer.mapRendering[0] - .GenerateLeafletStyle(new UIEventSource(tags), false) + .GenerateLeafletStyle(new UIEventSource(tags), false, { + noSize: true, + }) .html.SetClass("block relative") .SetStyle("width: 42px; height: 42px;") icons.push(icon) if (last === undefined) { last = layer.mapRendering[0] - .GenerateLeafletStyle(new UIEventSource(tags), false) + .GenerateLeafletStyle(new UIEventSource(tags), false, { + noSize: true, + }) .html.SetClass("block relative") .SetStyle("width: 42px; height: 42px;") } diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 2cebb2512e..46c252ccb9 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -1,7 +1,7 @@ /** * Asks to add a feature at the last clicked location, at least if zoom is sufficient */ -import { Store, UIEventSource } from "../../Logic/UIEventSource" +import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" import Svg from "../../Svg" import { SubtleButton } from "../Base/SubtleButton" import Combine from "../Base/Combine" @@ -26,7 +26,7 @@ import BaseLayer from "../../Models/BaseLayer" import Loading from "../Base/Loading" import Hash from "../../Logic/Web/Hash" import { GlobalFilter } from "../../Logic/State/MapState" -import { WayId } from "../../Models/OsmFeature" +import { OsmTags, WayId } from "../../Models/OsmFeature" import { Tag } from "../../Logic/Tags/Tag" import { LoginToggle } from "../Popup/LoginButton" @@ -286,9 +286,16 @@ export default class SimpleAddUI extends LoginToggle { const presets = layer.layerDef.presets for (const preset of presets) { const tags = TagUtils.KVtoProperties(preset.tags ?? []) + const isSnapping = preset.preciseInput.snapToLayers?.length > 0 let icon: () => BaseUIElement = () => layer.layerDef.mapRendering[0] - .GenerateLeafletStyle(new UIEventSource(tags), false) + .GenerateLeafletStyle( + new ImmutableStore( + isSnapping ? { _referencing_ways: '["way/-1"]', ...tags } : tags + ), + false, + { noSize: true } + ) .html.SetClass("w-12 h-12 block relative") const presetInfo: PresetInfo = { layerToAddTo: layer, diff --git a/UI/Input/LocationInput.ts b/UI/Input/LocationInput.ts index 56f20f4451..f52a392434 100644 --- a/UI/Input/LocationInput.ts +++ b/UI/Input/LocationInput.ts @@ -176,13 +176,13 @@ export default class LocationInput loc.lat, ]) if (min === undefined) { - min = nearestPointOnLine + min = { ...nearestPointOnLine } matchedWay = feature continue } if (min.properties.dist > nearestPointOnLine.properties.dist) { - min = nearestPointOnLine + min = { ...nearestPointOnLine } matchedWay = feature } } catch (e) { @@ -208,6 +208,10 @@ export default class LocationInput } } min.properties = options?.snappedPointTags ?? min.properties + min.properties = { + ...min.properties, + _referencing_ways: JSON.stringify([matchedWay.properties.id]), + } self.snappedOnto.setData(matchedWay) return min }, diff --git a/Utils.ts b/Utils.ts index 8bc0e011cf..7e8fdff24b 100644 --- a/Utils.ts +++ b/Utils.ts @@ -300,6 +300,49 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be return str.substr(0, l - 3) + "..." } + /** + * Adds a property to the given object, but the value will _only_ be calculated when it is actually requested + * @param object + * @param name + * @param init + * @constructor + */ + public static AddLazyProperty(object: any, name: string, init: () => any) { + Object.defineProperty(object, name, { + enumerable: false, + configurable: true, + get: () => { + delete object[name] + object[name] = init() + return object[name] + }, + }) + } + + /** + * Adds a property to the given object, but the value will _only_ be calculated when it is actually requested + */ + public static AddLazyPropertyAsync( + object: any, + name: string, + init: () => Promise, + whenDone?: () => void + ) { + Object.defineProperty(object, name, { + enumerable: false, + configurable: true, + get: () => { + init().then((r) => { + delete object[name] + object[name] = r + if (whenDone) { + whenDone() + } + }) + }, + }) + } + public static FixedLength(str: string, l: number) { str = Utils.EllipsesAfter(str, l) while (str.length < l) { @@ -1281,13 +1324,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be return d } - private static colorDiff( - c0: { r: number; g: number; b: number }, - c1: { r: number; g: number; b: number } - ) { - return Math.abs(c0.r - c1.r) + Math.abs(c0.g - c1.g) + Math.abs(c0.b - c1.b) - } - static toIdRecord(ts: T[]): Record { const result: Record = {} for (const t of ts) { @@ -1317,4 +1353,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be // If the element has a parent, repeat the process for the parent element return Utils.findParentWithScrolling(element.parentElement) } + + private static colorDiff( + c0: { r: number; g: number; b: number }, + c1: { r: number; g: number; b: number } + ) { + return Math.abs(c0.r - c1.r) + Math.abs(c0.g - c1.g) + Math.abs(c0.b - c1.b) + } } diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index 147d73a038..dd8f98d785 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -31,9 +31,6 @@ }, { "id": "isOpen", - "labels": [ - "defaults" - ], "#": "Shows a coloured clock if opening hours are parsed. Uses the metatagging, suitable to use as a (badged) overlay", "mappings": [ { @@ -128,4 +125,4 @@ } ], "mapRendering": null -} \ No newline at end of file +} diff --git a/assets/layers/map/map.json b/assets/layers/map/map.json index 47844271a7..48c8693187 100644 --- a/assets/layers/map/map.json +++ b/assets/layers/map/map.json @@ -44,6 +44,9 @@ "tagRenderings": [ "images", { + "labels": [ + "map" + ], "question": { "en": "On which data is this map based?", "nl": "Op welke data is deze kaart gebaseerd?", @@ -87,6 +90,9 @@ }, { "id": "map-attribution", + "labels": [ + "map" + ], "question": { "en": "Is the OpenStreetMap-attribution given?", "nl": "Is de attributie voor OpenStreetMap aanwezig?", diff --git a/assets/layers/recycling/license_info.json b/assets/layers/recycling/license_info.json index 6698ec44cf..957f2d98ff 100644 --- a/assets/layers/recycling/license_info.json +++ b/assets/layers/recycling/license_info.json @@ -164,6 +164,17 @@ "https://github.com/streetcomplete/StreetComplete/blob/master/res/graphics/recycling%20icons/plastic_packaging.svg" ] }, + { + "path": "printer_cartridges.svg", + "license": "CC-BY", + "authors": [ + "Noun Project", + "Zach Bogart" + ], + "sources": [ + "https://thenounproject.com/icon/ink-4963274/" + ] + }, { "path": "recycling-14.svg", "license": "CC0", @@ -205,4 +216,4 @@ "https://github.com/streetcomplete/StreetComplete/blob/master/res/graphics/recycling%20icons/small_electrical_appliances.svg" ] } -] \ No newline at end of file +] diff --git a/assets/layers/recycling/printer_cartridges.svg b/assets/layers/recycling/printer_cartridges.svg new file mode 100644 index 0000000000..860f6ad4de --- /dev/null +++ b/assets/layers/recycling/printer_cartridges.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/layers/recycling/recycling.json b/assets/layers/recycling/recycling.json index 64194c2100..d180550811 100644 --- a/assets/layers/recycling/recycling.json +++ b/assets/layers/recycling/recycling.json @@ -223,6 +223,15 @@ }, "then": "circle:white;./assets/layers/recycling/plastic.svg" }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:printer_cartridges=yes" + ] + }, + "then": "circle:white;./assets/layers/recycling/printer_cartridges.svg" + }, { "if": { "and": [ @@ -416,6 +425,15 @@ }, "then": "circle:white;./assets/layers/recycling/plastic.svg" }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:printer_cartridges=yes" + ] + }, + "then": "circle:white;./assets/layers/recycling/printer_cartridges.svg" + }, { "if": { "and": [ @@ -549,6 +567,7 @@ "recycling:plastic_bottles=", "recycling:plastic_packaging=", "recycling:plastic=", + "recycling:printer_cartridges=", "recycling:scrap_metal=", "recycling:shoes=", "recycling:small_appliances=", @@ -918,6 +937,18 @@ "class": "medium" } }, + { + "if": "recycling:printer_cartridges=yes", + "ifnot": "recycling:printer_cartridges=", + "then": { + "en": "Printer cartridges (inkjet/toner) can be recycled here", + "nl": "Printer cartridges (inkjet/toner) kunnen hier gerecycled worden" + }, + "icon": { + "path": "./assets/layers/recycling/printer_cartridges.svg", + "class": "medium" + } + }, { "if": "recycling:scrap_metal=yes", "ifnot": "recycling:scrap_metal=", @@ -1271,6 +1302,13 @@ }, "osmTags": "recycling:plastic=yes" }, + { + "question": { + "en": "Recycling of printer cartridges", + "nl": "Recycling van printer cartridges" + }, + "osmTags": "recycling:printer_cartridges=yes" + }, { "question": { "en": "Recycling of scrap metal", @@ -1336,4 +1374,4 @@ "enableRelocation": true, "enableImproveAccuracy": true } -} \ No newline at end of file +} diff --git a/assets/layers/waste_disposal/waste_disposal.json b/assets/layers/waste_disposal/waste_disposal.json index aca9b8cd27..216ec4a671 100644 --- a/assets/layers/waste_disposal/waste_disposal.json +++ b/assets/layers/waste_disposal/waste_disposal.json @@ -197,6 +197,11 @@ ] } ], + "allowMove": { + "enableImproveAccuracy": true, + "enableRelocation": true + }, + "deletion": true, "filter": [ { "#": "ignore-possible-duplicate", @@ -216,4 +221,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/assets/svg/brick_wall_raw.svg b/assets/svg/brick_wall_raw.svg new file mode 100644 index 0000000000..72dade8939 --- /dev/null +++ b/assets/svg/brick_wall_raw.svg @@ -0,0 +1,910 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/brick_wall_round.svg b/assets/svg/brick_wall_round.svg new file mode 100644 index 0000000000..f4be352bb2 --- /dev/null +++ b/assets/svg/brick_wall_round.svg @@ -0,0 +1,926 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/brick_wall_square.svg b/assets/svg/brick_wall_square.svg new file mode 100644 index 0000000000..9e9fc293fb --- /dev/null +++ b/assets/svg/brick_wall_square.svg @@ -0,0 +1,929 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 12a5de4d94..eadb7dba08 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -95,6 +95,30 @@ ], "sources": [] }, + { + "path": "brick_wall_raw.svg", + "license": "CC0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + }, + { + "path": "brick_wall_round.svg", + "license": "CC0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + }, + { + "path": "brick_wall_square.svg", + "license": "CC0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + }, { "path": "bug.svg", "license": "MIT", diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index 78c71f3a9d..2c15ce77ee 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -1936,5 +1936,52 @@ "ca": "El nom de la xarxa és {internet_access:ssid}", "pl": "Nazwa sieci to {internet_access:ssid}" } + }, + "luminous_or_lit": { + "question": { + "en": "Is this object lit or does it emit light?" + }, + "mappings": [ + { + "if": { + "and": [ + "lit=yes", + "luminous=yes" + ] + }, + "then": { + "en": "This object both emits light and is lighted by an external light source" + } + }, + { + "if": "luminous=yes", + "then": { + "en": "This object emits light" + }, + "addExtraTags": [ + "lit=no" + ] + }, + { + "if": "lit=yes", + "then": { + "en": "This object is lit externally, e.g. by a spotlight or other lights" + }, + "addExtraTags": [ + "luminous=no" + ] + }, + { + "if": { + "and": [ + "lit=no", + "luminous=no" + ] + }, + "then": { + "en": "This object does not emit light and is not lighted by externally" + } + } + ] } -} +} \ No newline at end of file diff --git a/assets/themes/advertising/AdvertisingColumn_001.jpg b/assets/themes/advertising/AdvertisingColumn_001.jpg new file mode 100644 index 0000000000..71b69cbe8c Binary files /dev/null and b/assets/themes/advertising/AdvertisingColumn_001.jpg differ diff --git a/assets/themes/advertising/AdvertisingColumn_003.jpg b/assets/themes/advertising/AdvertisingColumn_003.jpg new file mode 100644 index 0000000000..8efb383acf Binary files /dev/null and b/assets/themes/advertising/AdvertisingColumn_003.jpg differ diff --git a/assets/themes/advertising/AdvertisingTotem_003.jpg b/assets/themes/advertising/AdvertisingTotem_003.jpg new file mode 100644 index 0000000000..62cde80c06 Binary files /dev/null and b/assets/themes/advertising/AdvertisingTotem_003.jpg differ diff --git a/assets/themes/advertising/AdvertisingTotem_004.jpg b/assets/themes/advertising/AdvertisingTotem_004.jpg new file mode 100644 index 0000000000..7a15b44944 Binary files /dev/null and b/assets/themes/advertising/AdvertisingTotem_004.jpg differ diff --git a/assets/themes/advertising/Advertising_flag.jpg b/assets/themes/advertising/Advertising_flag.jpg new file mode 100644 index 0000000000..3b315e4b3a Binary files /dev/null and b/assets/themes/advertising/Advertising_flag.jpg differ diff --git a/assets/themes/advertising/Aircraft_Sculpture.jpg b/assets/themes/advertising/Aircraft_Sculpture.jpg new file mode 100644 index 0000000000..b9bfc6386f Binary files /dev/null and b/assets/themes/advertising/Aircraft_Sculpture.jpg differ diff --git a/assets/themes/advertising/BS.JPG b/assets/themes/advertising/BS.JPG new file mode 100644 index 0000000000..58d79e516c Binary files /dev/null and b/assets/themes/advertising/BS.JPG differ diff --git a/assets/themes/advertising/Capitol_wall.jpg b/assets/themes/advertising/Capitol_wall.jpg new file mode 100644 index 0000000000..2c137771ab Binary files /dev/null and b/assets/themes/advertising/Capitol_wall.jpg differ diff --git a/assets/themes/advertising/City-Light-Poster.jpg b/assets/themes/advertising/City-Light-Poster.jpg new file mode 100644 index 0000000000..b0c1c86cf5 Binary files /dev/null and b/assets/themes/advertising/City-Light-Poster.jpg differ diff --git a/assets/themes/advertising/FGV_Founding.jpg b/assets/themes/advertising/FGV_Founding.jpg new file mode 100644 index 0000000000..e57a4bb92f Binary files /dev/null and b/assets/themes/advertising/FGV_Founding.jpg differ diff --git a/assets/themes/advertising/JR_Central.jpg b/assets/themes/advertising/JR_Central.jpg new file mode 100644 index 0000000000..8e07fb47b8 Binary files /dev/null and b/assets/themes/advertising/JR_Central.jpg differ diff --git a/assets/themes/advertising/KFC_Billboard.jpg b/assets/themes/advertising/KFC_Billboard.jpg new file mode 100644 index 0000000000..dd489eceaa Binary files /dev/null and b/assets/themes/advertising/KFC_Billboard.jpg differ diff --git a/assets/themes/advertising/LIDL_Billboard.jpg b/assets/themes/advertising/LIDL_Billboard.jpg new file mode 100644 index 0000000000..60985764b3 Binary files /dev/null and b/assets/themes/advertising/LIDL_Billboard.jpg differ diff --git a/assets/themes/advertising/Lidl_totem.jpg b/assets/themes/advertising/Lidl_totem.jpg new file mode 100644 index 0000000000..0d65058eb3 Binary files /dev/null and b/assets/themes/advertising/Lidl_totem.jpg differ diff --git a/assets/themes/advertising/Mug.jpg b/assets/themes/advertising/Mug.jpg new file mode 100644 index 0000000000..31ab48ccd5 Binary files /dev/null and b/assets/themes/advertising/Mug.jpg differ diff --git a/assets/themes/advertising/Mupi_Alcoi.jpg b/assets/themes/advertising/Mupi_Alcoi.jpg new file mode 100644 index 0000000000..1b5db60502 Binary files /dev/null and b/assets/themes/advertising/Mupi_Alcoi.jpg differ diff --git a/assets/themes/advertising/Mupi_spain.jpg b/assets/themes/advertising/Mupi_spain.jpg new file mode 100644 index 0000000000..44400a69a4 Binary files /dev/null and b/assets/themes/advertising/Mupi_spain.jpg differ diff --git a/assets/themes/advertising/Repsol_Billboard.jpg b/assets/themes/advertising/Repsol_Billboard.jpg new file mode 100644 index 0000000000..0fd1ad9c7d Binary files /dev/null and b/assets/themes/advertising/Repsol_Billboard.jpg differ diff --git a/assets/themes/advertising/Screen_poster_box.jpg b/assets/themes/advertising/Screen_poster_box.jpg new file mode 100644 index 0000000000..3465db0dc9 Binary files /dev/null and b/assets/themes/advertising/Screen_poster_box.jpg differ diff --git a/assets/themes/advertising/Small_Board.jpg b/assets/themes/advertising/Small_Board.jpg new file mode 100644 index 0000000000..3c0a66f030 Binary files /dev/null and b/assets/themes/advertising/Small_Board.jpg differ diff --git a/assets/themes/advertising/Subway_screen.jpg b/assets/themes/advertising/Subway_screen.jpg new file mode 100644 index 0000000000..cdc9bff448 Binary files /dev/null and b/assets/themes/advertising/Subway_screen.jpg differ diff --git a/assets/themes/advertising/TV_media.jpg b/assets/themes/advertising/TV_media.jpg new file mode 100644 index 0000000000..f5a07f9a2a Binary files /dev/null and b/assets/themes/advertising/TV_media.jpg differ diff --git a/assets/themes/advertising/Times square.jpg b/assets/themes/advertising/Times square.jpg new file mode 100644 index 0000000000..a5445cf15a Binary files /dev/null and b/assets/themes/advertising/Times square.jpg differ diff --git a/assets/themes/advertising/Waitrose_sign.jpg b/assets/themes/advertising/Waitrose_sign.jpg new file mode 100644 index 0000000000..f0099c9d61 Binary files /dev/null and b/assets/themes/advertising/Waitrose_sign.jpg differ diff --git a/assets/themes/advertising/advertising.json b/assets/themes/advertising/advertising.json new file mode 100644 index 0000000000..2f1a1e7a78 --- /dev/null +++ b/assets/themes/advertising/advertising.json @@ -0,0 +1,1061 @@ +{ + "id": "advertising", + "credits": "Offsel", + "title": { + "en": "Open Advertising Map", + "ca": "Mapa obert de publicitat", + "es": "Mapa abierto de publicidad" + }, + "shortDescription": { + "ca": "On puc trobar elements publicitaris?", + "es": "Dónde puedo encontrar elementos publicitarios?", + "en": "Where I can find advertising features?" + }, + "description": { + "ca": "Alguna vegada t'has preguntat quanta publictat hi ha als nostres carrers i carreteres? Amb aquest mapa podràs trobar i afegir informació de tots els elements publictaris que t'hi trobes pel carrer", + "es": "¿Alguna vez te has preguntado cuanta publicidad hay en nuestras calles y carreteras? Con este mapa podrás encontrar y añadir información de todos los elementos publicitarios que te encuentres por la calle", + "en": "Have you ever wondered how many advertising there are in our streets and roads? With this map you could find and add information about all the advertising features that you can find on the street" + }, + "maintainer": "Offsel", + "icon": "./assets/themes/advertising/icon.svg", + "version": "2023_01_29", + "startLat": 0, + "startLon": 0, + "startZoom": 1, + "widenFactor": 0.01, + "layers": [ + { + "id": "advertising", + "name": { + "ca": "Publicitat", + "es": "Publicidad", + "en": "Advertise" + }, + "minzoom": 15, + "source": { + "osmTags": "advertising~*" + }, + "title": { + "render": { + "*": "{advertising}" + }, + "mappings": [ + { + "if": { + "and": [ + "advertising=billboard" + ] + }, + "then": { + "ca": "Tanca publicitària", + "es": "Valla publicitaria", + "en": "Billboard" + } + }, + { + "if": { + "and": [ + "advertising=board" + ] + }, + "then": { + "ca": "Tauló d'anuncis", + "es": "Tablon de anuncios", + "en": "Board" + } + }, + { + "if": { + "and": [ + "advertising=poster_box" + ] + }, + "then": { + "ca": "Mupi", + "es": "Mupi", + "en": "Poster Box" + } + }, + { + "if": { + "and": [ + "advertising=column" + ] + }, + "then": { + "ca": "Columna", + "es": "Columna", + "en": "Column" + } + }, + { + "if": { + "and": [ + "advertising=flag" + ] + }, + "then": { + "ca": "Bandera", + "es": "Bandera", + "en": "Flag" + } + }, + { + "if": { + "and": [ + "advertising=screen" + ] + }, + "then": { + "ca": "Pantalla", + "es": "Pantalla", + "en": "Screen" + } + }, + { + "if": { + "and": [ + "advertising=sculpture" + ] + }, + "then": { + "ca": "Esculptura", + "es": "Escultura", + "en": "Sculpture" + } + }, + { + "if": { + "and": [ + "advertising=sign" + ] + }, + "then": { + "ca": "Cartell", + "es": "Cartel", + "en": "Sign" + } + }, + { + "if": { + "and": [ + "advertising=tarp" + ] + }, + "then": { + "ca": "Lona", + "es": "Lona", + "en": "Tarp" + } + }, + { + "if": { + "and": [ + "advertising=totem" + ] + }, + "then": { + "ca": "Tòtem", + "es": "Tótem", + "en": "Totem" + } + }, + { + "if": { + "and": [ + "advertising=wall_painting" + ] + }, + "then": { + "ca": "Paret Pintada", + "es": "Pared Pintada", + "en": "Wall painting" + } + } + ] + }, + "description": { + "ca": "Completarem les dades dels elements publicitaris amb referència, operador i il·luminació", + "es": "Completaremos los datos de los elementos publicitarios con referencia, operador y iluminación", + "en": "We will complete data from advertising features with reference, operator and lit" + }, + "tagRenderings": [ + "images", + { + "id": "type", + "render": { + "ca": "Açò és un {advertising}", + "es": "Esto es un {advertising}", + "en": "This is a {advertising}" + }, + "question": { + "ca": "Quin tipus d'element publicitari és aquest?", + "es": "¿Qué tipo de elemento publicitario es?", + "en": "Which type of advertising feature is this?" + }, + "freeform": { + "key": "advertising" + }, + "mappings": [ + { + "if": { + "and": [ + "advertising=billboard" + ] + }, + "then": { + "ca": "Açò és una tanca publicitària", + "es": "Esto es una valla publicitaria", + "en": "This is a billboard" + }, + "icon": { + "path": "./assets/themes/advertising/billboard.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=board" + ] + }, + "then": { + "ca": "Açò és un tauló d'anunis", + "es": "Esto es un tablón de anuncios", + "en": "This is a board" + }, + "icon": { + "path": "./assets/themes/advertising/board.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=column" + ] + }, + "then": { + "ca": "Açò és una columna", + "es": "Esto es una columna", + "en": "This is a column" + }, + "icon": { + "path": "./assets/themes/advertising/column.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=flag" + ] + }, + "then": { + "ca": "Açò és una bandera", + "es": "Esto es una bndera", + "en": "This is a flag" + }, + "icon": { + "path": "./assets/themes/advertising/flag.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=poster_box" + ] + }, + "then": { + "ca": "Açò és un mupi", + "es": "Esto es un mupi", + "en": "This is a poster Box" + }, + "icon": { + "path": "./assets/themes/advertising/poster_box.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=screen" + ] + }, + "then": { + "ca": "Açò és una pantalla", + "es": "Esto es una pantalla", + "en": "This is a screen" + }, + "icon": { + "path": "./assets/themes/advertising/screen.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=sculpture" + ] + }, + "then": { + "ca": "Açò és una esculptura", + "es": "Esto es una escultura", + "en": "This is a sculpture" + }, + "icon": { + "path": "./assets/themes/advertising/sculpture.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=sign" + ] + }, + "then": { + "ca": "Açò és un cartell", + "es": "Esto es un cartel", + "en": "This is a sign" + }, + "icon": { + "path": "./assets/themes/advertising/sign.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=tarp" + ] + }, + "then": { + "ca": "Açò és una lona (una peça de tèxtil impermeable amb un missatge publicitari)", + "es": "Esto es una lona (una pieza de tela resistente a la intemperie con un mensaje publicitario)", + "en": "This is a tarp (a weatherproof piece of textile with an advertising message)" + }, + "icon": { + "path": "./assets/themes/advertising/tarp.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=totem" + ] + }, + "then": { + "ca": "Açò és un tòtem", + "es": "Esto es un tótem", + "en": "This is a totem" + }, + "icon": { + "path": "./assets/themes/advertising/totem.svg", + "class": "medium" + } + }, + { + "if": { + "and": [ + "advertising=wall_painting" + ] + }, + "then": { + "ca": "Açò és una paret pintada", + "es": "Esto es una pared pintada", + "en": "This is a wall painting" + }, + "icon": { + "path": "./assets/themes/advertising/wall_painting.svg", + "class": "medium" + } + } + ] + }, + { + "id": "animated", + "question": { + "ca": "Com canvien els anuncis d'aquest element?", + "es": "¿Como cambian los anuncios de este elemento?", + "en": "Does this advertisement cycle through multiple messages?" + }, + "condition": { + "#": "Screens are _always_ animated; flags, tarps, and wall_paintings cannot be animated; signs can be anything so we don't make guesses", + "and": [ + "advertising!=screen", + "advertising!=flag", + "advertising!=tarp", + "advertising!=wall_painting", + "advertising!=sign" + ] + }, + "mappings": [ + { + "if": "animated=no", + "then": { + "ca": "Estàtic, sempre mostra el mateix missatge", + "es": "Estático, siempre muestra el mismo mensaje", + "en": "Static, always shows the same message" + } + }, + { + "if": "animated=digital_display", + "then": { + "en": "This object has a built-in digital display to show prices or some other message", + "ca": "Aquest objecte té una pantalla digital integrada per a mostrar els preus o algun altre missatge", + "es": "Este objeto tiene una pantalla digital incorporada para mostrar precios o algún otro mensaje" + }, + "hideInAnswer": { + "and": [ + "advertising!=billboard", + "advertising!=poster_box", + "advertising!=totem", + "advertising!=column" + ] + } + }, + { + "if": "animated=travision_blades", + "then": { + "ca": "Trivision - la tanca publicitària consta de molts prismes triangulars que giren regularment", + "es": "Trivision - la valla publicitaria consta de muchos prismas triangulares que giran regularmente", + "en": "Trivision - the billboard consists of many triangular prisms which regularly rotate" + }, + "icon": { + "class": "large", + "path": "./assets/themes/advertising/trivision.svg" + }, + "#": "Only applicable to billboards", + "hideInAnswer": "advertising!=billboard" + }, + { + "if": "animated=winding_posters", + "then": { + "ca": "Cartells Rotatius", + "es": "Cartells Rotatius", + "en": "Scrolling posters" + }, + "hideInAnswer": { + "and": [ + "advertising!=poster_box", + "advertising!=column" + ] + } + }, + { + "if": "animated=revolving", + "then": { + "ca": "Rota sobre si mateix", + "es": "Rota sobre si mismo", + "en": "Rotates on itself" + }, + "hideInAnswer": { + "and": [ + "advertising!=totem", + "advertising!=column", + "advertising!=poster_box" + ] + } + } + ] + }, + { + "id": "luminous_or_lit_advertising", + "builtin": "luminous_or_lit", + "override": { + "+mappings": [ + { + "if": "luminous=neon", + "then": { + "en": "This is a neon-tube light", + "ca": "Aquesta és una llum de tub de neó", + "es": "Esta es una luz de tubo de neón." + }, + "hideInAnswer": "advertising!=sign" + } + ], + "condition": { + "#": "A screen is always luminous", + "and": [ + "advertising!=screen" + ] + } + } + }, + { + "id": "operator", + "render": { + "ca": "L'operador és {operator}", + "es": "El operador es {operator}", + "en": "Operated by {operator}" + }, + "question": { + "ca": "Qui opera aquest element?", + "es": "¿Quien opera este elemento?", + "en": "Who operates this feature?" + }, + "freeform": { + "addExtraTags": [], + "key": "operator" + } + }, + { + "id": "message_type", + "question": { + "ca": "Quin tipus de missatge es mostra?", + "es": "Que tipo de mensaje se muestra?", + "en": "What kind of message is shown?" + }, + "mappings": [ + { + "if": "message=commercial", + "ifnot": "message=", + "then": { + "ca": "Missatge comercial", + "es": "Mensaje comercial", + "en": "Commercial message" + } + }, + { + "if": "message=local", + "ifnot": "message=", + "then": { + "ca": "Informació municipal", + "es": "Información municipal", + "en": "Local information" + } + }, + { + "if": "message=safety", + "ifnot": "message=", + "then": { + "ca": "Informació de seguretat", + "es": "Información de seguridad", + "en": "Securty information" + }, + "hideInAnswer": { + "and": [ + "advertising=flag" + ] + } + }, + { + "if": "message=political", + "ifnot": "message=", + "then": { + "ca": "Publicitat electoral", + "es": "Publicidad electoral", + "en": "Electoral advertising" + } + }, + { + "if": "message=showbiz", + "ifnot": "message=", + "then": { + "ca": "Informació sobre teatres, concerts, ...", + "es": "Información sobre teatros, conciertos, ...", + "en": "Inormation related to theatre, concerts, ..." + }, + "hideInAnswer": { + "and": [ + "advertising=flag" + ] + } + }, + { + "if": "message=non_profit", + "ifnot": "message=", + "then": { + "ca": "Missatge d'organitzacions sense ànim de lucre", + "es": "Mensaje de organizaciones sin ánimo de lucro", + "en": "Message from non-profit organizations" + } + }, + { + "if": "message=opinion", + "ifnot": "message=", + "then": { + "ca": "Per a expressar la teua opinió", + "es": "Para expresar tu opinión", + "en": "To expres your opinion" + }, + "hideInAnswer": { + "or": [ + "advertising=flag", + "advertising=screen" + ] + } + }, + { + "if": "message=religion", + "ifnot": "message=", + "then": { + "ca": "Missatge religiós", + "es": "Mensaje religioso", + "en": "Religious message" + } + }, + { + "if": "message=funding", + "ifnot": "message=", + "then": { + "ca": "Cartell de financiació", + "es": "Cartel de financiación", + "en": "Funding sign" + }, + "hideInAnswer": { + "or": [ + "advertising=flag", + "advertising=column" + ] + } + }, + { + "if": "information=map", + "ifnot": "information=", + "then": { + "en": "A map", + "ca": "un mapa", + "es": "un mapa" + } + } + ], + "multiAnswer": true + }, + { + "id": "Sides", + "condition": { + "and": [ + "_referencing_ways=", + { + "or": [ + "advertising=poster_box", + "advertising=screen", + "advertising=billboard" + ] + } + ] + }, + "question": { + "ca": "Per quants costats pots veure publicitat?", + "es": "¿Por cuantos lados puedes ver publicidad?", + "en": "From how many sides you can watch advertisments?" + }, + "mappings": [ + { + "if": "sides=1", + "then": { + "en": "This object has advertisements on a single side", + "ca": "Aquest mupi té publicitat a un únic costat", + "es": "Este mupi tiene publicidad en un único lado" + } + }, + { + "if": "sides=2", + "then": { + "en": "This object has advertisements on both sides", + "ca": "Aquest mupi té publicitat pels dos costas", + "es": "Este mupi tiene publicidad por los dos lados" + } + } + ] + }, + { + "id": "ref", + "render": { + "ca": "El número de referència és {ref}", + "es": "El número de referencia es {ref}", + "en": "Reference number is {ref}" + }, + "question": { + "ca": "Quin és el número de refèrencia?", + "es": "¿Cual es el número de referencia?", + "en": "Wich is the reference number?" + }, + "freeform": { + "key": "ref" + }, + "condition": { + "and": [ + "advertising!=sign" + ] + } + } + ], + "mapRendering": [ + { + "location": [ + "point", + "centroid" + ], + "icon": { + "render": "./assets/themes/advertising/sign.svg", + "mappings": [ + { + "if": { + "or": [ + "advertising=billboard" + ] + }, + "then": "./assets/themes/advertising/billboard.svg" + }, + { + "if": "advertising=board", + "then": "./assets/themes/advertising/board.svg" + }, + { + "if": "advertising=column", + "then": "./assets/themes/advertising/column.svg" + }, + { + "if": "advertising=flag", + "then": "./assets/themes/advertising/flag.svg" + }, + { + "if": { + "and": [ + "advertising=poster_box", + "_referencing_ways=[\"way/-1\"]" + ] + }, + "then": "brick_wall_square;./assets/themes/advertising/poster_box_no_support.svg" + }, + { + "if": { + "and": [ + "advertising=poster_box", + "_referencing_ways~*" + ] + }, + "then": "./assets/themes/advertising/poster_box_no_support.svg" + }, + { + "if": "advertising=poster_box", + "then": "./assets/themes/advertising/poster_box.svg" + }, + { + "if": { + "and": [ + "advertising=screen", + "_referencing_ways=[\"way/-1\"]" + ] + }, + "then": "brick_wall_square;./assets/themes/advertising/screen_no_support.svg" + }, + { + "if": { + "and": [ + "advertising=screen", + "_referencing_ways~*" + ] + }, + "then": "./assets/themes/advertising/screen_no_support.svg" + }, + { + "if": "advertising=screen", + "then": "./assets/themes/advertising/screen.svg" + }, + { + "if": "advertising=sculpture", + "then": "./assets/themes/advertising/sculpture.svg" + }, + { + "if": { + "and": [ + "advertising=sign", + "_referencing_ways=[\"way/-1\"]" + ] + }, + "then": "brick_wall_square;./assets/themes/advertising/sign.svg" + }, + { + "if": "advertising=sign", + "then": "./assets/themes/advertising/sign.svg" + }, + { + "if": "advertising=tarp", + "then": "./assets/themes/advertising/tarp.svg" + }, + { + "if": "advertising=totem", + "then": "./assets/themes/advertising/totem.svg" + }, + { + "if": "advertising=wall_painting", + "then": "./assets/themes/advertising/wall_painting.svg" + } + ] + }, + "iconSize": { + "render": "40,40,bottom", + "mappings": [ + { + "if": "_referencing_ways~*", + "then": "40,40,center" + }, + { + "if": "advertising=flag", + "then": "60,60,bottom" + }, + { + "if": "advertising=sculpture", + "then": "50,50,bottom" + } + ] + } + }, + { + "width": { + "render": "8" + }, + "color": { + "render": "#00f" + } + } + ], + "allowMove": { + "enableImproveAccuracy": true, + "enableRelocation": false + }, + "deletion": true, + "presets": [ + { + "tags": [ + "advertising=billboard" + ], + "title": { + "en": "a billboard", + "ca": "una tanca publicitària", + "es": "una valla publicitària" + }, + "description": { + "en": "A large outdoor advertising structure, typically found in high-traffic areas such as alongside busy roads", + "ca": "Una estructura publicitària gran a l'exterior, que normalment es troba a zones transitades com ara al costat de carreteres amb molta intensitat", + "es": "Una estructura publicitaria grande al aire libre, que normalmente se encuentra en áreas transitadas como carreteras con mucha intensidad" + }, + "exampleImages": [ + "./assets/themes/advertising/KFC_Billboard.jpg", + "./assets/themes/advertising/LIDL_Billboard.jpg", + "./assets/themes/advertising/Repsol_Billboard.jpg" + ] + }, + { + "tags": [ + "advertising=poster_box" + ], + "title": { + "en": "a freestanding poster box", + "ca": "un mupi", + "es": "un mupi" + }, + "exampleImages": [ + "./assets/themes/advertising/Mupi_spain.jpg", + "./assets/themes/advertising/Mupi_Alcoi.jpg" + ] + }, + { + "tags": [ + "advertising=poster_box" + ], + "title": { + "en": "a poster box mounted on a wall", + "ca": "un mupi sobre la paret", + "es": "un mupi sobre la pared" + }, + "preciseInput": { + "snapToLayer": "walls_and_buildings" + } + }, + { + "tags": [ + "advertising=board" + ], + "title": { + "ca": "un tauló d'anunis", + "es": "un tablón de anuncios", + "en": "a billboard" + }, + "description": { + "en": "Small billboard for neighbourhood advertising, generally intended for pedestrians", + "es": "Un pequeño tablón de anuncios para anuncios del vecindario, normalmente destinado a peatones", + "ca": "Un xicotet tauló d'anuncics per a anuncis del veïnat, normalment destitat a peatons" + }, + "exampleImages": [ + "./assets/themes/advertising/local_Board.jpg", + "./assets/themes/advertising/FGV_Founding.jpg", + "./assets/themes/advertising/Small_Board.jpg" + ] + }, + { + "tags": [ + "advertising=column" + ], + "title": { + "ca": "una columna", + "es": "una columna", + "en": "a column" + }, + "description": { + "en": "A cylindrical outdoor structure which shows advertisements", + "es": "Una estructura cilíndrica exterior que muestra publicidad", + "ca": "Una extructura cilíndica exterior que mostra publicitat" + }, + "exampleImages": [ + "./assets/themes/advertising/AdvertisingColumn_001.jpg", + "./assets/themes/advertising/AdvertisingColumn_003.jpg" + ] + }, + { + "tags": [ + "advertising=flag", + "man_made=pole" + ], + "title": { + "ca": "una bandera", + "es": "una bandera", + "en": "a flag" + }, + "exampleImages": [ + "./assets/themes/advertising/Advertising_flag.jpg", + "./assets/themes/advertising/JR_Central.jpg" + ] + }, + { + "tags": [ + "advertising=screen" + ], + "title": { + "ca": "una pantalla", + "es": "una pantalla", + "en": "a screen" + }, + "exampleImages": [ + "./assets/themes/advertising/Screen_poster_box.jpg", + "./assets/themes/advertising/City-Light-Poster.jpg" + ] + }, + { + "tags": [ + "advertising=screen" + ], + "title": { + "ca": "una patalla sobre una paret", + "es": "una pantalla sobre una pared", + "en": "a screen mounted on a wall" + }, + "preciseInput": { + "preferredBackground": "map", + "snapToLayer": "walls_and_buildings", + "maxSnapDistance": 5 + }, + "exampleImages": [ + "./assets/themes/advertising/Subway_screen.jpg", + "./assets/themes/advertising/TV_media.jpg", + "./assets/themes/advertising/Times square.jpg" + ] + }, + { + "tags": [ + "advertising=tarp" + ], + "title": { + "ca": "una lona", + "es": "una lona", + "en": "a tarp" + }, + "description": { + "en": "A piece of waterproof textile with a printed message, permanently anchored on a wall", + "ca": "Una peça de tèxtil impermeable amb un missatge imprès, fixada permanentment a una paret", + "es": "Una pieza de tela impermeable con un mensaje impreso, anclada permanentemente en una pared" + }, + "preciseInput": { + "preferredBackground": "map", + "snapToLayer": "walls_and_buildings", + "maxSnapDistance": 5 + }, + "exampleImages": [ + "./assets/themes/advertising/tarp_feder.jpg", + "./assets/themes/advertising/tarp_madrid.jpg" + ] + }, + { + "tags": [ + "advertising=totem" + ], + "title": { + "ca": "un tòtem", + "es": "un tótem", + "en": "a totem" + }, + "exampleImages": [ + "./assets/themes/advertising/AdvertisingTotem_004.jpg", + "./assets/themes/advertising/AdvertisingTotem_003.jpg", + "./assets/themes/advertising/Lidl_totem.jpg" + ] + }, + { + "tags": [ + "advertising=sign" + ], + "title": { + "ca": "un lletrer", + "es": "un lletrer", + "en": "a sign" + }, + "preciseInput": { + "preferredBackground": "map", + "snapToLayer": "walls_and_buildings", + "maxSnapDistance": 5 + }, + "description": { + "en": "Used for advertising signs, neon signs, logos & institutional entrance signs", + "es": "Se utiliza para carteles publicitarios, letreros de neón, logotipos y carteles en entradas institucionales", + "ca": "S'utilitza per a cartells publicitaris, retols de neó, logotips i cartells en entrades institucionals" + }, + "exampleImages": [ + "./assets/themes/advertising/Waitrose_sign.jpg", + "./assets/themes/advertising/sign_EOI.jpg", + "./assets/themes/advertising/farma_sign.jpg" + ] + }, + { + "tags": [ + "advertising=sculpture" + ], + "title": { + "ca": "una escupltura", + "es": "una escultura", + "en": "a sculpture" + }, + "exampleImages": [ + "./assets/themes/advertising/Aircraft_Sculpture.jpg", + "./assets/themes/advertising/Mug.jpg", + "./assets/themes/advertising/BS.JPG" + ] + }, + { + "tags": [ + "advertising=wall_painting" + ], + "title": { + "ca": "una paret pintada", + "es": "una pared pintada", + "en": "a wall painting" + }, + "preciseInput": { + "preferredBackground": "map", + "snapToLayer": "walls_and_buildings", + "maxSnapDistance": 5 + }, + "exampleImages": [ + "./assets/themes/advertising/Capitol_wall.jpg", + "./assets/themes/advertising/clarke_wall.jpg" + ] + } + ] + } + ] +} diff --git a/assets/themes/advertising/billboard.svg b/assets/themes/advertising/billboard.svg new file mode 100644 index 0000000000..b98e6e834c --- /dev/null +++ b/assets/themes/advertising/billboard.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/board.svg b/assets/themes/advertising/board.svg new file mode 100644 index 0000000000..917190ea8e --- /dev/null +++ b/assets/themes/advertising/board.svg @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/clarke_wall.jpg b/assets/themes/advertising/clarke_wall.jpg new file mode 100644 index 0000000000..4e031a1908 Binary files /dev/null and b/assets/themes/advertising/clarke_wall.jpg differ diff --git a/assets/themes/advertising/column.svg b/assets/themes/advertising/column.svg new file mode 100644 index 0000000000..f1ff90bf2c --- /dev/null +++ b/assets/themes/advertising/column.svg @@ -0,0 +1,285 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/farma_sign.jpg b/assets/themes/advertising/farma_sign.jpg new file mode 100644 index 0000000000..62360c3f09 Binary files /dev/null and b/assets/themes/advertising/farma_sign.jpg differ diff --git a/assets/themes/advertising/flag.svg b/assets/themes/advertising/flag.svg new file mode 100644 index 0000000000..668b69d975 --- /dev/null +++ b/assets/themes/advertising/flag.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/icon.svg b/assets/themes/advertising/icon.svg new file mode 100644 index 0000000000..e90f1f84e9 --- /dev/null +++ b/assets/themes/advertising/icon.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/license_info.json b/assets/themes/advertising/license_info.json new file mode 100644 index 0000000000..b813d045e2 --- /dev/null +++ b/assets/themes/advertising/license_info.json @@ -0,0 +1,484 @@ +[ + { + "path": "AdvertisingColumn_001.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Segnargs" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:AdvertisingColumn_001.jpg" + ] + }, + { + "path": "AdvertisingColumn_003.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Segnargsed" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:AdvertisingColumn_003.jpg#file" + ] + }, + { + "path": "AdvertisingTotem_003.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Segnargsed" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:AdvertisingTotem_003.jpg" + ] + }, + { + "path": "AdvertisingTotem_004.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Segnargsed" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:AdvertisingTotem_004.jpg" + ] + }, + { + "path": "Advertising_flag.jpg", + "license": "CC BY-SA 2.0", + "authors": [ + "Sandy B" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Advertising_flags_-_geograph.org.uk_-_2433864.jpg" + ] + }, + { + "path": "Aircraft_Sculpture.jpg", + "license": "CC BY-SA 2.0", + "authors": [ + "Rod Waddington" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Aircraft_Sculpture-Advertisment-Restaurant_Jimma_Ethiopia.jpg" + ] + }, + { + "path": "BS.JPG", + "license": "CC BY-SA 4.0", + "authors": [ + "TeWeBs" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:BS_Schraubenschluessel.JPG" + ] + }, + { + "path": "Capitol_wall.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Artaxerxes" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Advertising_mural_on_wall_of_Capitol_Stationers_65_Main_Street_downtown_Montpelier_VT_August_2017.jpg" + ] + }, + { + "path": "City-Light-Poster.jpg", + "license": "CC-BY SA 4.0", + "authors": [ + "Bärwinkel, Klaus" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:City-Light-Poster_Mittelstra%C3%9Fe.jpg" + ] + }, + { + "path": "FGV_Founding.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Paunofu" + ], + "sources": [ + "https://imgur.com/epyuPXs" + ] + }, + { + "path": "JR_Central.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "ジェーアール東海一口株主" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:JR_Central_corporate_flag_by_Nagoya_Station.jpg" + ] + }, + { + "path": "KFC_Billboard.jpg", + "license": "CC BY 4.0", + "authors": [ + "Paunofu" + ], + "sources": [ + "https://imgur.com/2xJaUXd" + ] + }, + { + "path": "LIDL_Billboard.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Paul Williams" + ], + "sources": [ + "https://archive.org/details/northfleet-2021-05-30/PXL_20210530_175057096.jpg" + ] + }, + { + "path": "Lidl_totem.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Donald Trung" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Lidl_informational_sign,_Hesel_(2019)_01.jpg" + ] + }, + { + "path": "Mug.jpg", + "license": "Public Domain", + "authors": [ + "Carol M. Highsmith" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:The_Frostop_mug_advertising_sign_outside_%22The_Drive_In%22_restaurant_in_Taylors_Falls,_Minnesota.jpg" + ] + }, + { + "path": "Mupi_Alcoi.jpg", + "license": "CC-BY 4.0", + "authors": [ + "Paunofu" + ], + "sources": [ + "https://imgur.com/4Q3glWH" + ] + }, + { + "path": "Mupi_spain.jpg", + "license": "CC0 1.0", + "authors": [ + "Jusotil_1943" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Mupi_(42556631491).jpg" + ] + }, + { + "path": "Repsol_Billboard.jpg", + "license": "CC BY 4.0", + "authors": [ + "Paunofu" + ], + "sources": [ + "https://imgur.com/MwvK0jc" + ] + }, + { + "path": "Screen_poster_box.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "T. Segonds" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Screen_poster_box.jpg" + ] + }, + { + "path": "Small_Board.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "Segnargsed" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:AdvertisingBoard_001.jpg" + ] + }, + { + "path": "Subway_screen.jpg", + "license": "CC BY 2.0", + "authors": [ + "Metropolitan Transportation Authority of the State of New York" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Subway_Station_Digital_Advertising_Screens_(13251000543).jpg" + ] + }, + { + "path": "TV_media.jpg", + "license": "CC BY 3.0", + "authors": [ + "Roger Carvell" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:TV_media_advertising_at_London_Victoria_station._-_panoramio.jpg" + ] + }, + { + "path": "Times square.jpg", + "license": "CC BY-SA 4.0", + "authors": [ + "chensiyuan" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:1_times_square_night_2013.jpg" + ] + }, + { + "path": "Waitrose_sign.jpg", + "license": "CC BY-SA 2.0", + "authors": [ + "Geographer" + ], + "sources": [ + "https://www.geograph.org.uk/photo/4343364" + ] + }, + { + "path": "billboard.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Billboard_trunk.svg" + ] + }, + { + "path": "board.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Board.svg" + ] + }, + { + "path": "clarke_wall.jpg", + "license": "CC BY-SA 2.0", + "authors": [ + "Albert Bridge" + ], + "sources": [ + "https://www.geograph.org.uk/photo/2478313" + ] + }, + { + "path": "column.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Column.svg" + ] + }, + { + "path": "farma_sign.jpg", + "license": "CC-BY-SA 4.0", + "authors": [ + "paunofu" + ], + "sources": [ + "https://imgur.com/bGF0kdd" + ] + }, + { + "path": "flag.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38", + "Ash Crow", + "Happy-melon", + "Aris Katsaris", + "Pietervdvn" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Column.svg", + "https://commons.wikimedia.org/wiki/File:Flag_icon_darkblue.svg" + ] + }, + { + "path": "icon.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "Panier Avide" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Advertising_icon.svg" + ] + }, + { + "path": "local_Board.jpg", + "license": "CC-BY-SA 4.0", + "authors": [ + "Segnargsed" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:ReservedAdvertisingUnit_008.jpg" + ] + }, + { + "path": "newspaper_kiosk.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Newspaper_kiosk_3.svg" + ] + }, + { + "path": "poster_box.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Poster_box.svg" + ] + }, + { + "path": "poster_box_no_support.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Poster_box.svg" + ] + }, + { + "path": "screen alcoi.jpg", + "license": "CC-BY 4.0", + "authors": [ + "paunofu" + ], + "sources": [ + "https://imgur.com/HKsRycm" + ] + }, + { + "path": "screen.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "Barnes38", + "Pietervdvn" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Poster_box.svg" + ] + }, + { + "path": "screen_no_support.svg", + "license": "CC-BY-SA 4.0", + "authors": [ + "Barnes38", + "Pietervdvn" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Poster_box.svg" + ] + }, + { + "path": "sculpture.svg", + "license": "CC BY 3.0", + "authors": [ + "Nathaniel Smith", + "Pietervdvn" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Column.svg", + "https://commons.wikimedia.org/wiki/File:Sculpture_(NP100738).svg" + ] + }, + { + "path": "sign.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Totem.svg" + ] + }, + { + "path": "sign_EOI.jpg", + "license": "CC-BY-SA 4.0", + "authors": [ + "paunofu" + ], + "sources": [ + "https://imgur.com/8D0BKNq" + ] + }, + { + "path": "tarp.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38", + "Pietervdvn" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Billboard_trunk.svg" + ] + }, + { + "path": "tarp_feder.jpg", + "license": "CC-BY SA 4.0", + "authors": [ + "paunofu" + ], + "sources": [ + "https://imgur.com/Gc3Tk41" + ] + }, + { + "path": "tarp_madrid.jpg", + "license": "CC BY 2.0", + "authors": [ + "Rogotan" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Lona_(3741637137).jpg" + ] + }, + { + "path": "totem.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Totem.svg" + ] + }, + { + "path": "trivision.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "pietervdvn", + "Louis Dawson (via the Noun Project)" + ], + "sources": [ + "https://thenounproject.com/icon/rotating-arrow-184486/" + ] + }, + { + "path": "wall_painting.svg", + "license": "CC BY-SA 3.0", + "authors": [ + "Barnes38", + "Pietervdvn" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Billboard_trunk.svg" + ] + } +] \ No newline at end of file diff --git a/assets/themes/advertising/local_Board.jpg b/assets/themes/advertising/local_Board.jpg new file mode 100644 index 0000000000..eb204c0a44 Binary files /dev/null and b/assets/themes/advertising/local_Board.jpg differ diff --git a/assets/themes/advertising/newspaper_kiosk.svg b/assets/themes/advertising/newspaper_kiosk.svg new file mode 100644 index 0000000000..debaea46b5 --- /dev/null +++ b/assets/themes/advertising/newspaper_kiosk.svg @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/poster_box.svg b/assets/themes/advertising/poster_box.svg new file mode 100644 index 0000000000..cc3cf216bc --- /dev/null +++ b/assets/themes/advertising/poster_box.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/poster_box_no_support.svg b/assets/themes/advertising/poster_box_no_support.svg new file mode 100644 index 0000000000..cd3e701e1a --- /dev/null +++ b/assets/themes/advertising/poster_box_no_support.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/screen alcoi.jpg b/assets/themes/advertising/screen alcoi.jpg new file mode 100644 index 0000000000..46d2b17103 Binary files /dev/null and b/assets/themes/advertising/screen alcoi.jpg differ diff --git a/assets/themes/advertising/screen.svg b/assets/themes/advertising/screen.svg new file mode 100644 index 0000000000..40b676f5e1 --- /dev/null +++ b/assets/themes/advertising/screen.svg @@ -0,0 +1,127 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/screen_no_support.svg b/assets/themes/advertising/screen_no_support.svg new file mode 100644 index 0000000000..120390f95a --- /dev/null +++ b/assets/themes/advertising/screen_no_support.svg @@ -0,0 +1,151 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/sculpture.svg b/assets/themes/advertising/sculpture.svg new file mode 100644 index 0000000000..ec063bc4e6 --- /dev/null +++ b/assets/themes/advertising/sculpture.svg @@ -0,0 +1,64 @@ + + diff --git a/assets/themes/advertising/sign.svg b/assets/themes/advertising/sign.svg new file mode 100644 index 0000000000..23478cce29 --- /dev/null +++ b/assets/themes/advertising/sign.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/assets/themes/advertising/sign_EOI.jpg b/assets/themes/advertising/sign_EOI.jpg new file mode 100644 index 0000000000..405a7b6742 Binary files /dev/null and b/assets/themes/advertising/sign_EOI.jpg differ diff --git a/assets/themes/advertising/tarp.svg b/assets/themes/advertising/tarp.svg new file mode 100644 index 0000000000..8349c1b59a --- /dev/null +++ b/assets/themes/advertising/tarp.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/tarp_feder.jpg b/assets/themes/advertising/tarp_feder.jpg new file mode 100644 index 0000000000..ef42dfe924 Binary files /dev/null and b/assets/themes/advertising/tarp_feder.jpg differ diff --git a/assets/themes/advertising/tarp_madrid.jpg b/assets/themes/advertising/tarp_madrid.jpg new file mode 100644 index 0000000000..470739156e Binary files /dev/null and b/assets/themes/advertising/tarp_madrid.jpg differ diff --git a/assets/themes/advertising/totem.svg b/assets/themes/advertising/totem.svg new file mode 100644 index 0000000000..2e97da890f --- /dev/null +++ b/assets/themes/advertising/totem.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/trivision.svg b/assets/themes/advertising/trivision.svg new file mode 100644 index 0000000000..6b13551ba7 --- /dev/null +++ b/assets/themes/advertising/trivision.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/advertising/wall_painting.svg b/assets/themes/advertising/wall_painting.svg new file mode 100644 index 0000000000..fbf462c648 --- /dev/null +++ b/assets/themes/advertising/wall_painting.svg @@ -0,0 +1,967 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.json index b6b71d1cbb..fa56481d1d 100644 --- a/assets/themes/mapcomplete-changes/mapcomplete-changes.json +++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.json @@ -114,6 +114,10 @@ "icon": { "render": "teardrop:#00cc00", "mappings": [ + { + "if": "theme=advertising", + "then": "./assets/themes/advertising/poster_box.svg" + }, { "if": "theme=aed", "then": "./assets/themes/aed/aed.svg" diff --git a/langs/shared-questions/en.json b/langs/shared-questions/en.json index 6fe7f2ad34..dadb187b95 100644 --- a/langs/shared-questions/en.json +++ b/langs/shared-questions/en.json @@ -152,6 +152,23 @@ "question": "On what level is this feature located?", "render": "Located on the {level}th floor" }, + "luminous_or_lit": { + "mappings": { + "0": { + "then": "This object both emits light and is lighted by an external light source" + }, + "1": { + "then": "This object emits light" + }, + "2": { + "then": "This object is lit externally, e.g. by a spotlight or other lights" + }, + "3": { + "then": "This object does not emit light and is not lighted by externally" + } + }, + "question": "Is this object lit or does it emit light?" + }, "multilevels": { "override": { "question": "What levels does this elevator go to?", diff --git a/langs/themes/ca.json b/langs/themes/ca.json index c2bb8cb97f..0a2f5edf1c 100644 --- a/langs/themes/ca.json +++ b/langs/themes/ca.json @@ -1,4 +1,222 @@ { + "advertising": { + "description": "Alguna vegada t'has preguntat quanta publictat hi ha als nostres carrers i carreteres? Amb aquest mapa podràs trobar i afegir informació de tots els elements publictaris que t'hi trobes pel carrer", + "layers": { + "0": { + "description": "Completarem les dades dels elements publicitaris amb referència, operador i il·luminació", + "name": "Publicitat", + "presets": { + "0": { + "description": "Una estructura publicitària gran a l'exterior, que normalment es troba a zones transitades com ara al costat de carreteres amb molta intensitat", + "title": "una tanca publicitària" + }, + "1": { + "title": "un mupi" + }, + "2": { + "title": "un mupi sobre la paret" + }, + "3": { + "description": "Un xicotet tauló d'anuncics per a anuncis del veïnat, normalment destitat a peatons", + "title": "un tauló d'anunis" + }, + "4": { + "description": "Una extructura cilíndica exterior que mostra publicitat", + "title": "una columna" + }, + "5": { + "title": "una bandera" + }, + "6": { + "title": "una pantalla" + }, + "7": { + "title": "una patalla sobre una paret" + }, + "8": { + "description": "Una peça de tèxtil impermeable amb un missatge imprès, fixada permanentment a una paret", + "title": "una lona" + }, + "9": { + "title": "un tòtem" + }, + "10": { + "description": "S'utilitza per a cartells publicitaris, retols de neó, logotips i cartells en entrades institucionals", + "title": "un lletrer" + }, + "11": { + "title": "una escupltura" + }, + "12": { + "title": "una paret pintada" + } + }, + "tagRenderings": { + "Sides": { + "mappings": { + "0": { + "then": "Aquest mupi té publicitat a un únic costat" + }, + "1": { + "then": "Aquest mupi té publicitat pels dos costas" + } + }, + "question": "Per quants costats pots veure publicitat?" + }, + "animated": { + "mappings": { + "0": { + "then": "Estàtic, sempre mostra el mateix missatge" + }, + "1": { + "then": "Aquest objecte té una pantalla digital integrada per a mostrar els preus o algun altre missatge" + }, + "2": { + "then": "Trivision - la tanca publicitària consta de molts prismes triangulars que giren regularment" + }, + "3": { + "then": "Cartells Rotatius" + }, + "4": { + "then": "Rota sobre si mateix" + } + }, + "question": "Com canvien els anuncis d'aquest element?" + }, + "luminous_or_lit_advertising": { + "override": { + "+mappings": { + "0": { + "then": "Aquesta és una llum de tub de neó" + } + } + } + }, + "message_type": { + "mappings": { + "0": { + "then": "Missatge comercial" + }, + "1": { + "then": "Informació municipal" + }, + "2": { + "then": "Informació de seguretat" + }, + "3": { + "then": "Publicitat electoral" + }, + "4": { + "then": "Informació sobre teatres, concerts, ..." + }, + "5": { + "then": "Missatge d'organitzacions sense ànim de lucre" + }, + "6": { + "then": "Per a expressar la teua opinió" + }, + "7": { + "then": "Missatge religiós" + }, + "8": { + "then": "Cartell de financiació" + }, + "9": { + "then": "un mapa" + } + }, + "question": "Quin tipus de missatge es mostra?" + }, + "operator": { + "question": "Qui opera aquest element?", + "render": "L'operador és {operator}" + }, + "ref": { + "question": "Quin és el número de refèrencia?", + "render": "El número de referència és {ref}" + }, + "type": { + "mappings": { + "0": { + "then": "Açò és una tanca publicitària" + }, + "1": { + "then": "Açò és un tauló d'anunis" + }, + "2": { + "then": "Açò és una columna" + }, + "3": { + "then": "Açò és una bandera" + }, + "4": { + "then": "Açò és un mupi" + }, + "5": { + "then": "Açò és una pantalla" + }, + "6": { + "then": "Açò és una esculptura" + }, + "7": { + "then": "Açò és un cartell" + }, + "8": { + "then": "Açò és una lona (una peça de tèxtil impermeable amb un missatge publicitari)" + }, + "9": { + "then": "Açò és un tòtem" + }, + "10": { + "then": "Açò és una paret pintada" + } + }, + "question": "Quin tipus d'element publicitari és aquest?", + "render": "Açò és un {advertising}" + } + }, + "title": { + "mappings": { + "0": { + "then": "Tanca publicitària" + }, + "1": { + "then": "Tauló d'anuncis" + }, + "2": { + "then": "Mupi" + }, + "3": { + "then": "Columna" + }, + "4": { + "then": "Bandera" + }, + "5": { + "then": "Pantalla" + }, + "6": { + "then": "Esculptura" + }, + "7": { + "then": "Cartell" + }, + "8": { + "then": "Lona" + }, + "9": { + "then": "Tòtem" + }, + "10": { + "then": "Paret Pintada" + } + } + } + } + }, + "shortDescription": "On puc trobar elements publicitaris?", + "title": "Mapa obert de publicitat" + }, "aed": { "description": "En aquest mapa , qualsevol pot trobar i marcar els desfibril·ladors externs automàtics més propers", "title": "Mapa obert de desfibril·ladors (DEA)" diff --git a/langs/themes/en.json b/langs/themes/en.json index 1af038368a..d85cf59ffd 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1,4 +1,222 @@ { + "advertising": { + "description": "Have you ever wondered how many advertising there are in our streets and roads? With this map you could find and add information about all the advertising features that you can find on the street", + "layers": { + "0": { + "description": "We will complete data from advertising features with reference, operator and lit", + "name": "Advertise", + "presets": { + "0": { + "description": "A large outdoor advertising structure, typically found in high-traffic areas such as alongside busy roads", + "title": "a billboard" + }, + "1": { + "title": "a freestanding poster box" + }, + "2": { + "title": "a poster box mounted on a wall" + }, + "3": { + "description": "Small billboard for neighbourhood advertising, generally intended for pedestrians", + "title": "a billboard" + }, + "4": { + "description": "A cylindrical outdoor structure which shows advertisements", + "title": "a column" + }, + "5": { + "title": "a flag" + }, + "6": { + "title": "a screen" + }, + "7": { + "title": "a screen mounted on a wall" + }, + "8": { + "description": "A piece of waterproof textile with a printed message, permanently anchored on a wall", + "title": "a tarp" + }, + "9": { + "title": "a totem" + }, + "10": { + "description": "Used for advertising signs, neon signs, logos & institutional entrance signs", + "title": "a sign" + }, + "11": { + "title": "a sculpture" + }, + "12": { + "title": "a wall painting" + } + }, + "tagRenderings": { + "Sides": { + "mappings": { + "0": { + "then": "This object has advertisements on a single side" + }, + "1": { + "then": "This object has advertisements on both sides" + } + }, + "question": "From how many sides you can watch advertisments?" + }, + "animated": { + "mappings": { + "0": { + "then": "Static, always shows the same message" + }, + "1": { + "then": "This object has a built-in digital display to show prices or some other message" + }, + "2": { + "then": "Trivision - the billboard consists of many triangular prisms which regularly rotate" + }, + "3": { + "then": "Scrolling posters" + }, + "4": { + "then": "Rotates on itself" + } + }, + "question": "Does this advertisement cycle through multiple messages?" + }, + "luminous_or_lit_advertising": { + "override": { + "+mappings": { + "0": { + "then": "This is a neon-tube light" + } + } + } + }, + "message_type": { + "mappings": { + "0": { + "then": "Commercial message" + }, + "1": { + "then": "Local information" + }, + "2": { + "then": "Securty information" + }, + "3": { + "then": "Electoral advertising" + }, + "4": { + "then": "Inormation related to theatre, concerts, ..." + }, + "5": { + "then": "Message from non-profit organizations" + }, + "6": { + "then": "To expres your opinion" + }, + "7": { + "then": "Religious message" + }, + "8": { + "then": "Funding sign" + }, + "9": { + "then": "A map" + } + }, + "question": "What kind of message is shown?" + }, + "operator": { + "question": "Who operates this feature?", + "render": "Operated by {operator}" + }, + "ref": { + "question": "Wich is the reference number?", + "render": "Reference number is {ref}" + }, + "type": { + "mappings": { + "0": { + "then": "This is a billboard" + }, + "1": { + "then": "This is a board" + }, + "2": { + "then": "This is a column" + }, + "3": { + "then": "This is a flag" + }, + "4": { + "then": "This is a poster Box" + }, + "5": { + "then": "This is a screen" + }, + "6": { + "then": "This is a sculpture" + }, + "7": { + "then": "This is a sign" + }, + "8": { + "then": "This is a tarp (a weatherproof piece of textile with an advertising message)" + }, + "9": { + "then": "This is a totem" + }, + "10": { + "then": "This is a wall painting" + } + }, + "question": "Which type of advertising feature is this?", + "render": "This is a {advertising}" + } + }, + "title": { + "mappings": { + "0": { + "then": "Billboard" + }, + "1": { + "then": "Board" + }, + "2": { + "then": "Poster Box" + }, + "3": { + "then": "Column" + }, + "4": { + "then": "Flag" + }, + "5": { + "then": "Screen" + }, + "6": { + "then": "Sculpture" + }, + "7": { + "then": "Sign" + }, + "8": { + "then": "Tarp" + }, + "9": { + "then": "Totem" + }, + "10": { + "then": "Wall painting" + } + } + } + } + }, + "shortDescription": "Where I can find advertising features?", + "title": "Open Advertising Map" + }, "aed": { "description": "On this map, one can find and mark nearby defibrillators", "title": "Open AED Map" diff --git a/langs/themes/es.json b/langs/themes/es.json index b16d36b420..01cfdcd104 100644 --- a/langs/themes/es.json +++ b/langs/themes/es.json @@ -1,4 +1,222 @@ { + "advertising": { + "description": "¿Alguna vez te has preguntado cuanta publicidad hay en nuestras calles y carreteras? Con este mapa podrás encontrar y añadir información de todos los elementos publicitarios que te encuentres por la calle", + "layers": { + "0": { + "description": "Completaremos los datos de los elementos publicitarios con referencia, operador y iluminación", + "name": "Publicidad", + "presets": { + "0": { + "description": "Una estructura publicitaria grande al aire libre, que normalmente se encuentra en áreas transitadas como carreteras con mucha intensidad", + "title": "una valla publicitària" + }, + "1": { + "title": "un mupi" + }, + "2": { + "title": "un mupi sobre la pared" + }, + "3": { + "description": "Un pequeño tablón de anuncios para anuncios del vecindario, normalmente destinado a peatones", + "title": "un tablón de anuncios" + }, + "4": { + "description": "Una estructura cilíndrica exterior que muestra publicidad", + "title": "una columna" + }, + "5": { + "title": "una bandera" + }, + "6": { + "title": "una pantalla" + }, + "7": { + "title": "una pantalla sobre una pared" + }, + "8": { + "description": "Una pieza de tela impermeable con un mensaje impreso, anclada permanentemente en una pared", + "title": "una lona" + }, + "9": { + "title": "un tótem" + }, + "10": { + "description": "Se utiliza para carteles publicitarios, letreros de neón, logotipos y carteles en entradas institucionales", + "title": "un lletrer" + }, + "11": { + "title": "una escultura" + }, + "12": { + "title": "una pared pintada" + } + }, + "tagRenderings": { + "Sides": { + "mappings": { + "0": { + "then": "Este mupi tiene publicidad en un único lado" + }, + "1": { + "then": "Este mupi tiene publicidad por los dos lados" + } + }, + "question": "¿Por cuantos lados puedes ver publicidad?" + }, + "animated": { + "mappings": { + "0": { + "then": "Estático, siempre muestra el mismo mensaje" + }, + "1": { + "then": "Este objeto tiene una pantalla digital incorporada para mostrar precios o algún otro mensaje" + }, + "2": { + "then": "Trivision - la valla publicitaria consta de muchos prismas triangulares que giran regularmente" + }, + "3": { + "then": "Cartells Rotatius" + }, + "4": { + "then": "Rota sobre si mismo" + } + }, + "question": "¿Como cambian los anuncios de este elemento?" + }, + "luminous_or_lit_advertising": { + "override": { + "+mappings": { + "0": { + "then": "Esta es una luz de tubo de neón." + } + } + } + }, + "message_type": { + "mappings": { + "0": { + "then": "Mensaje comercial" + }, + "1": { + "then": "Información municipal" + }, + "2": { + "then": "Información de seguridad" + }, + "3": { + "then": "Publicidad electoral" + }, + "4": { + "then": "Información sobre teatros, conciertos, ..." + }, + "5": { + "then": "Mensaje de organizaciones sin ánimo de lucro" + }, + "6": { + "then": "Para expresar tu opinión" + }, + "7": { + "then": "Mensaje religioso" + }, + "8": { + "then": "Cartel de financiación" + }, + "9": { + "then": "un mapa" + } + }, + "question": "Que tipo de mensaje se muestra?" + }, + "operator": { + "question": "¿Quien opera este elemento?", + "render": "El operador es {operator}" + }, + "ref": { + "question": "¿Cual es el número de referencia?", + "render": "El número de referencia es {ref}" + }, + "type": { + "mappings": { + "0": { + "then": "Esto es una valla publicitaria" + }, + "1": { + "then": "Esto es un tablón de anuncios" + }, + "2": { + "then": "Esto es una columna" + }, + "3": { + "then": "Esto es una bndera" + }, + "4": { + "then": "Esto es un mupi" + }, + "5": { + "then": "Esto es una pantalla" + }, + "6": { + "then": "Esto es una escultura" + }, + "7": { + "then": "Esto es un cartel" + }, + "8": { + "then": "Esto es una lona (una pieza de tela resistente a la intemperie con un mensaje publicitario)" + }, + "9": { + "then": "Esto es un tótem" + }, + "10": { + "then": "Esto es una pared pintada" + } + }, + "question": "¿Qué tipo de elemento publicitario es?", + "render": "Esto es un {advertising}" + } + }, + "title": { + "mappings": { + "0": { + "then": "Valla publicitaria" + }, + "1": { + "then": "Tablon de anuncios" + }, + "2": { + "then": "Mupi" + }, + "3": { + "then": "Columna" + }, + "4": { + "then": "Bandera" + }, + "5": { + "then": "Pantalla" + }, + "6": { + "then": "Escultura" + }, + "7": { + "then": "Cartel" + }, + "8": { + "then": "Lona" + }, + "9": { + "then": "Tótem" + }, + "10": { + "then": "Pared Pintada" + } + } + } + } + }, + "shortDescription": "Dónde puedo encontrar elementos publicitarios?", + "title": "Mapa abierto de publicidad" + }, "aed": { "description": "En este mapa , cualquiera puede encontrar y marcar los desfibriladores externos automáticos más cercanos", "title": "Mapa Abierto de Desfibriladores (DEA)" diff --git a/scripts/downloadEli.ts b/scripts/downloadEli.ts index dc6501db25..d64e50c8b0 100644 --- a/scripts/downloadEli.ts +++ b/scripts/downloadEli.ts @@ -32,6 +32,14 @@ class DownloadEli extends Script { continue } + if(props.id === "Mapbox"){ + /** + * This token is managed by Martin Reifer on the 'OpenStreetMap'-account on MapBox + */ + const token = "pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJjbGZkempiNDkyandvM3lwY3M4MndpdWdzIn0.QnvRv52n3qffVEKmQa9vJA" + props.url = props.url.replace("{apikey}", token) + } + if (props.url.toLowerCase().indexOf("apikey") > 0) { continue } diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index f98e3fac46..d18e437db3 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -21,15 +21,19 @@ import { PrepareLayer } from "../Models/ThemeConfig/Conversion/PrepareLayer" import { PrepareTheme } from "../Models/ThemeConfig/Conversion/PrepareTheme" import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion" import { Utils } from "../Utils" +import Script from "./Script" import { AllSharedLayers } from "../Customizations/AllSharedLayers" // 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 -class LayerOverviewUtils { +class LayerOverviewUtils extends Script { public static readonly layerPath = "./assets/generated/layers/" public static readonly themePath = "./assets/generated/themes/" + constructor() { + super("Reviews and generates the compiled themes") + } private static publicLayerIdsFrom(themefiles: LayoutConfigJson[]): Set { const publicThemes = [].concat(...themefiles.filter((th) => !th.hideFromOverview)) @@ -225,7 +229,7 @@ class LayerOverviewUtils { } } - main(args: string[]) { + async main(args: string[]) { if (fakedom === undefined) { throw "Fakedom not initialized" } @@ -505,4 +509,4 @@ class LayerOverviewUtils { } } -new LayerOverviewUtils().main(process.argv) +new LayerOverviewUtils().run() diff --git a/scripts/generateLicenseInfo.ts b/scripts/generateLicenseInfo.ts index 2ee17be968..7980e5493b 100644 --- a/scripts/generateLicenseInfo.ts +++ b/scripts/generateLicenseInfo.ts @@ -1,326 +1,352 @@ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs" import SmallLicense from "../Models/smallLicense" import ScriptUtils from "./ScriptUtils" +import Script from "./Script" const prompt = require("prompt-sync")() -function validateLicenseInfo(l: SmallLicense) { - l.sources.map((s) => { - try { - return new URL(s) - } catch (e) { - throw "Could not parse URL " + s + " for a license for " + l.path + " due to " + e - } - }) -} -/** - * 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) { - try { - const parsed = JSON.parse(readFileSync(path, { encoding: "utf8" })) - 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 - smallLicens.path = path.substring(0, 1 + path.lastIndexOf("/")) + smallLicens.path - licenses.push(smallLicens) - } - } catch (e) { - console.error("Error: ", e, "while handling", path) - } - } - return licenses -} - -function missingLicenseInfos(licenseInfos: SmallLicense[], allIcons: string[]) { - const missing = [] - - const knownPaths = new Set() - for (const licenseInfo of licenseInfos) { - knownPaths.add(licenseInfo.path) +export class GenerateLicenseInfo extends Script { + constructor() { + super("Validates the licenses and compiles them into one single asset file") } - for (const iconPath of allIcons) { - if (iconPath.indexOf("license_info.json") >= 0) { - continue - } - if (knownPaths.has(iconPath)) { - continue - } - missing.push(iconPath) - } - return missing -} + static defaultLicenses() { + const knownLicenses = new Map() + knownLicenses.set("me", { + authors: ["Pieter Vander Vennet"], + path: undefined, + license: "CC0", + sources: [], + }) + knownLicenses.set("streetcomplete", { + authors: ["Tobias Zwick (westnordost)"], + path: undefined, + license: "CC0", + sources: [ + "https://github.com/streetcomplete/StreetComplete/tree/master/res/graphics", + "https://f-droid.org/packages/de.westnordost.streetcomplete/", + ], + }) -const knownLicenses = new Map() -knownLicenses.set("me", { - authors: ["Pieter Vander Vennet"], - path: undefined, - license: "CC0", - sources: [], -}) -knownLicenses.set("streetcomplete", { - authors: ["Tobias Zwick (westnordost)"], - path: undefined, - license: "CC0", - sources: [ - "https://github.com/streetcomplete/StreetComplete/tree/master/res/graphics", - "https://f-droid.org/packages/de.westnordost.streetcomplete/", - ], -}) + knownLicenses.set("temaki", { + authors: ["Temaki"], + path: undefined, + license: "CC0", + sources: [ + "https://github.com/ideditor/temaki", + "https://ideditor.github.io/temaki/docs/", + ], + }) -knownLicenses.set("temaki", { - authors: ["Temaki"], - path: undefined, - license: "CC0", - sources: ["https://github.com/ideditor/temaki", "https://ideditor.github.io/temaki/docs/"], -}) + knownLicenses.set("maki", { + authors: ["Maki"], + path: undefined, + license: "CC0", + sources: ["https://labs.mapbox.com/maki-icons/"], + }) -knownLicenses.set("maki", { - authors: ["Maki"], - path: undefined, - license: "CC0", - sources: ["https://labs.mapbox.com/maki-icons/"], -}) - -knownLicenses.set("t", { - authors: [], - path: undefined, - license: "CC0; trivial", - sources: [], -}) -knownLicenses.set("na", { - authors: [], - path: undefined, - license: "CC0", - sources: [], -}) -knownLicenses.set("tv", { - authors: ["Toerisme Vlaanderen"], - path: undefined, - license: "CC0", - sources: [ - "https://toerismevlaanderen.be/pinjepunt", - "https://mapcomplete.osm.be/toerisme_vlaanderenn", - ], -}) -knownLicenses.set("tvf", { - authors: ["Jo De Baerdemaeker "], - path: undefined, - license: "All rights reserved", - sources: ["https://www.studiotype.be/fonts/flandersart"], -}) -knownLicenses.set("twemoji", { - authors: ["Twemoji"], - path: undefined, - license: "CC-BY 4.0", - sources: ["https://github.com/twitter/twemoji"], -}) - -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 + knownLicenses.set("t", { + authors: [], + path: undefined, + license: "CC0; trivial", + sources: [], + }) + knownLicenses.set("na", { + authors: [], + path: undefined, + license: "CC0", + sources: [], + }) + knownLicenses.set("tv", { + authors: ["Toerisme Vlaanderen"], + path: undefined, + license: "CC0", + sources: [ + "https://toerismevlaanderen.be/pinjepunt", + "https://mapcomplete.osm.be/toerisme_vlaanderenn", + ], + }) + knownLicenses.set("tvf", { + authors: ["Jo De Baerdemaeker "], + path: undefined, + license: "All rights reserved", + sources: ["https://www.studiotype.be/fonts/flandersart"], + }) + knownLicenses.set("twemoji", { + authors: ["Twemoji"], + path: undefined, + license: "CC-BY 4.0", + sources: ["https://github.com/twitter/twemoji"], + }) + return knownLicenses } - 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 allPaths) { - unlinkSync(licensePath) - } - - const perDirectory = new Map() - - 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, []) - } - const cloned: SmallLicense = { - // We make a clone to force the order of the keys - path: license.path, - license: license.license, - authors: license.authors, - sources: license.sources, - } - perDirectory.get(dir).push(cloned) - } - - perDirectory.forEach((licenses, dir) => { - for (let i = licenses.length - 1; i >= 0; i--) { - const license = licenses[i] - const path = dir + "/" + license.path - if (!existsSync(path)) { - console.log( - "Found license for now missing file: ", - path, - " - removing this license" - ) - licenses.splice(i, 1) - } - } - - licenses.sort((a, b) => (a.path < b.path ? -1 : 1)) - 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!") -} - -/** - * Creates the humongous license_info in the generated assets, containing all licenses with a path relative to the root - * @param licensePaths - */ -function createFullLicenseOverview(licensePaths: string[]) { - const allLicenses: SmallLicense[] = [] - for (const licensePath of licensePaths) { - if (!existsSync(licensePath)) { - continue - } - const licenses = JSON.parse(readFileSync(licensePath, { encoding: "utf8" })) - for (const license of licenses) { - validateLicenseInfo(license) - const dir = licensePath.substring(0, licensePath.length - "license_info.json".length) - license.path = dir + license.path - allLicenses.push(license) - } - } - - writeFileSync("./assets/generated/license_info.json", JSON.stringify(allLicenses, null, " ")) -} - -function main(args: string[]) { - console.log("Checking and compiling license info") - - if (!existsSync("./assets/generated")) { - mkdirSync("./assets/generated") - } - - let contents = ScriptUtils.readDirRecSync("./assets") - .filter((p) => !p.startsWith("./assets/templates/")) - .filter((entry) => entry.indexOf("./assets/generated") != 0) - let licensePaths = contents.filter((entry) => entry.indexOf("license_info.json") >= 0) - let licenseInfos = generateLicenseInfos(licensePaths) - - const artwork = contents.filter( - (pth) => pth.match(/(.svg|.png|.jpg|.ttf|.otf|.woff)$/i) != null - ) - const missingLicenses = missingLicenseInfos(licenseInfos, artwork) - if (args.indexOf("--prompt") >= 0 || args.indexOf("--query") >= 0) { - queryMissingLicenses(missingLicenses) - return main([]) - } - - const invalidLicenses = licenseInfos - .filter((l) => (l.license ?? "") === "") - .map((l) => `License for artwork ${l.path} is empty string or undefined`) - - let invalid = 0 - for (const licenseInfo of licenseInfos) { - const isTrivial = - licenseInfo.license - .split(";") - .map((l) => l.trim().toLowerCase()) - .indexOf("trivial") >= 0 - if (licenseInfo.sources.length + licenseInfo.authors.length == 0 && !isTrivial) { - invalid++ - invalidLicenses.push( - "Invalid license: No sources nor authors given in the license for " + - JSON.stringify(licenseInfo) - ) - continue - } - - for (const source of licenseInfo.sources) { - if (source == "") { - invalidLicenses.push( - "Invalid license: empty string in " + JSON.stringify(licenseInfo) - ) - } + validateLicenseInfo(l: SmallLicense) { + l.sources.map((s) => { try { - new URL(source) - } catch { - invalidLicenses.push("Not a valid URL: " + source) + return new URL(s) + } catch (e) { + throw "Could not parse URL " + s + " for a license for " + l.path + " due to " + e + } + }) + } + + /** + * 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 + */ + + generateLicenseInfos(paths: string[]): SmallLicense[] { + const licenses = [] + for (const path of paths) { + try { + const parsed = JSON.parse(readFileSync(path, { encoding: "utf8" })) + 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 + smallLicens.path = + path.substring(0, 1 + path.lastIndexOf("/")) + smallLicens.path + licenses.push(smallLicens) + } + } catch (e) { + console.error("Error: ", e, "while handling", path) } } + return licenses } - if (missingLicenses.length > 0 || invalidLicenses.length) { - const msg = `There are ${missingLicenses.length} licenses missing and ${invalidLicenses.length} invalid licenses.` - console.log(missingLicenses.concat(invalidLicenses).join("\n")) - console.error(msg) - if (args.indexOf("--no-fail") < 0) { - throw msg + missingLicenseInfos(licenseInfos: SmallLicense[], allIcons: string[]) { + const missing = [] + + const knownPaths = new Set() + 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 + } + + promptLicenseFor(path): SmallLicense { + const knownLicenses = GenerateLicenseInfo.defaultLicenses() + 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(";"), } } - cleanLicenseInfo(licensePaths, licenseInfos) - createFullLicenseOverview(licensePaths) + createLicenseInfoFor(path): void { + const li = this.promptLicenseFor(path) + if (li == null) { + return + } + writeFileSync(path + ".license_info.json", JSON.stringify(li, null, " ")) + } + + 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 allPaths) { + unlinkSync(licensePath) + } + + const perDirectory = new Map() + + 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, []) + } + const cloned: SmallLicense = { + // We make a clone to force the order of the keys + path: license.path, + license: license.license, + authors: license.authors, + sources: license.sources, + } + perDirectory.get(dir).push(cloned) + } + + perDirectory.forEach((licenses, dir) => { + for (let i = licenses.length - 1; i >= 0; i--) { + const license = licenses[i] + const path = dir + "/" + license.path + if (!existsSync(path)) { + console.log( + "Found license for now missing file: ", + path, + " - removing this license" + ) + licenses.splice(i, 1) + } + } + + licenses.sort((a, b) => (a.path < b.path ? -1 : 1)) + writeFileSync(dir + "/license_info.json", JSON.stringify(licenses, null, 2)) + }) + } + + 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 + } + this.createLicenseInfoFor(missingLicens) + } + + console.log("You're through!") + } + + /** + * Creates the humongous license_info in the generated assets, containing all licenses with a path relative to the root + * @param licensePaths + */ + createFullLicenseOverview(licensePaths: string[]) { + const allLicenses: SmallLicense[] = [] + for (const licensePath of licensePaths) { + if (!existsSync(licensePath)) { + continue + } + const licenses = ( + JSON.parse(readFileSync(licensePath, { encoding: "utf8" })) + ) + for (const license of licenses) { + this.validateLicenseInfo(license) + const dir = licensePath.substring( + 0, + licensePath.length - "license_info.json".length + ) + license.path = dir + license.path + allLicenses.push(license) + } + } + + writeFileSync( + "./assets/generated/license_info.json", + JSON.stringify(allLicenses, null, " ") + ) + } + + async main(args: string[]) { + console.log("Checking and compiling license info") + + if (!existsSync("./assets/generated")) { + mkdirSync("./assets/generated") + } + + let contents = ScriptUtils.readDirRecSync("./assets") + .filter((p) => !p.startsWith("./assets/templates/")) + .filter((entry) => entry.indexOf("./assets/generated") != 0) + let licensePaths = contents.filter((entry) => entry.indexOf("license_info.json") >= 0) + let licenseInfos = this.generateLicenseInfos(licensePaths) + + const artwork = contents.filter( + (pth) => pth.match(/(.svg|.png|.jpg|.ttf|.otf|.woff)$/i) != null + ) + const missingLicenses = this.missingLicenseInfos(licenseInfos, artwork) + if (args.indexOf("--prompt") >= 0 || args.indexOf("--query") >= 0) { + this.queryMissingLicenses(missingLicenses) + return this.main([]) + } + + const invalidLicenses = licenseInfos + .filter((l) => (l.license ?? "") === "") + .map((l) => `License for artwork ${l.path} is empty string or undefined`) + + let invalid = 0 + for (const licenseInfo of licenseInfos) { + const isTrivial = + licenseInfo.license + .split(";") + .map((l) => l.trim().toLowerCase()) + .indexOf("trivial") >= 0 + if (licenseInfo.sources.length + licenseInfo.authors.length == 0 && !isTrivial) { + invalid++ + invalidLicenses.push( + "Invalid license: No sources nor authors given in the license for " + + JSON.stringify(licenseInfo) + ) + continue + } + + for (const source of licenseInfo.sources) { + if (source == "") { + invalidLicenses.push( + "Invalid license: empty string in " + JSON.stringify(licenseInfo) + ) + } + try { + new URL(source) + } catch { + invalidLicenses.push("Not a valid URL: " + source) + } + } + } + + if (missingLicenses.length > 0 || invalidLicenses.length) { + const msg = `There are ${missingLicenses.length} licenses missing and ${invalidLicenses.length} invalid licenses.` + console.log(missingLicenses.concat(invalidLicenses).join("\n")) + console.error(msg) + if (args.indexOf("--no-fail") < 0) { + throw msg + } + } + + this.cleanLicenseInfo(licensePaths, licenseInfos) + this.createFullLicenseOverview(licensePaths) + } } -main(process.argv.slice(2)) +new GenerateLicenseInfo().run() diff --git a/scripts/printVersion.ts b/scripts/printVersion.ts deleted file mode 100644 index 10bdf47657..0000000000 --- a/scripts/printVersion.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Constants from "../Models/Constants" - -console.log("git tag -a", Constants.vNumber, `-m "Deployed on ${new Date()}"`)