Merge develop

This commit is contained in:
Pieter Vander Vennet 2024-01-16 04:27:59 +01:00
commit c672fe7668
138 changed files with 14304 additions and 1299 deletions

View file

@ -0,0 +1,307 @@
# 2023 in review
Now that 2023 has come to an end, it is an appropriate time to take a look back and see what has happened within the MapComplete-sphere.
2023 also marked the year that I (pietervdvn) received a grant by NlNet, meaning that I could spend a ton of time on improving MapComplete - and with success.
Looking back, a humongous amount of work happened. I'm giving a quick recap here.
## User survey and other statistics
I've started the year with orienting myself. I ran a user survey (part [1](https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/diary/401127), [2](https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/diary/401133) and [3](https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/diary/401152)) and analyzed how mapcomplete was used.
For example, there are some interesting statistics about [the number of pictures created](https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/diary/400716) and [about the reviews that were made](https://www.openstreetmap.org/user/Pieter%20Vander%20Vennet/diary/400854)
## Lots of improvements
Most of the work of course went to programming MapComplete, which underwent a few big changes (notably the UI-framework and Mapping-library) and received numerous small improvements.
A quick recap:
### Svelte (Q1)
The first big change of the year was switching to an _actual_ frontend framework. MapComplete was written in a hand-rolled framework, which wasn't very performant.
And while I really loved it, using Svelte made the frontend more approachable for other programmers, more maintainable and faster.
Svelte was chosen partly because it works and has a large ecosystem, but also because it turns out to be conceptually similar to the previous, handrolled framework.
Even better: the old framework is so similar, that they can be used together! With a few tweaks and adaptions, they were made compatible.
The big advantage of this compatibility is that it becomes possible to _gently_ migrate. Instead of porting everything at once, component per component can be switched when the time is right. As such, there are still a few components around written in the old framework, but they are slowly getting replaced.
Another important bit here is that I received lots of help, both in making the choice of Svelte and actually switching.
I received help from Tobias (and the rest from fixmycity.de), but also from Robin van der Linde and Wouter van der Wal.
They had experience with Svelte - which I lacked. They basically did all the nasty configuration files and the adapter classes.
Back then, it was as if they used some arcane magic to get it all working ;) Luckily, I know Svelte better know, so I at least know how to do such a tricks. But the configuration files are still scary...
### UX overhaul
A designer from FixMyCity Berlin had a look to MapComplete as well; they worked out a conceptual framework to design mapcomplete against.
The calmer, cleaner, gray-based design is thanks to them.
Furthermore, they gave some feedback on various flows, which made the app more consistent and easier to use.
### MapLibre (June)
Another big change was replacing Leaflet and using MapLibre instead.
This was another big change which had some fallout, but is worth it in the long run.
Not only does it give more possibilities (such as rotating the map or pitching it for a 3D-view),
it also paves the way for more optimalisations later on (which I've just begun working on).
### Move of domain name (August)
In august, I've finally made the switch to a proper domain name: mapcomplete.org. This change had quite some fallout,
as MapComplete relies on several external services which suddenly need to be updated.
### Studio
Another big, new feature is MapComplete studio, which allows to create new map layers without having to know the JSON-configuration.
I have to be honest: it works, but there are still many bugs and inconsistencies. It is not as good as it can be, but I'll be fixing small issues when someone complains about them (and when I do have time)
### Export-functionality
Another neat feature which has been polished up and released is the 'export'-functionality.
This allows everyone to export the visible data as CSV, PNG or PDF, ideal to further process the map data.
There even is a 'line only'-export function, which, in combination with the cycle-infra theme, is perfect to get an SVG-road map.
With some post-processing, this can be fed into a 3D-printer...
### Imgur data backup
Imgur - our image host - announced a change to their policy indicating that _they might start deleting old, unused pictures_.
As such, many people were a bit worried and we started backing up all pictures on image which are linked to from OpenStreetMap.
This collection of around 30K images has several copies now with various people.
And, as it turned out, only 6 of them became dead. It seems that Imgur's policy was mostly applied on a specific kind of pictures, namely [the indecent type](https://piped.video/watch?v=zBDCq6Q8k2E)...
## New themes and theme improvements
Of course, various improvements to the map themes were made. There are too much improvements to sum them all, but I'd like to give an overview of themes that have been officially added to MapComplete this year:
- [advertising](https://mapcomplete.org/advertising)
- [clock](https://mapcomplete.org/clock)
- [elongated_coin](https://mapcomplete.org/elongated_coin)
- [guideposts](https://mapcomplete.org/guideposts)
- [icecream](https://mapcomplete.org/icecream)
- [vending_machine](https://mapcomplete.org/vending_machine)
- [walkingnodes](https://mapcomplete.org/walkingnodes)
This is a small amount of themes, especially compared to 2022 when 25 new themes were added.
This is partly because I focused on improving the system itself (and not on creating new themes) and partly because there was no Open Summer of Code this year,
which traditionally meant the addition of many new themes and layers.
Another reason is that many topical maps already exist by now - especially the broadly applicable ones. As such, there is less need to create new ones.
And maybe I should improve Studio further and officialize a few of those themes. In either case, if you have a thematic map or layer lying around,
let me know and we'll add it to official mapcomplete!
And even though there weren't many new themes added, quite some improvements were made to the already existing themes.
For example, drinking water was improved with more specific questions, one can indicate what services a hackerspace offers,
...
### Accessibility
One of the last big changes made in 2023 is the effort to make MapComplete more accessible for people using screenreaders, braille devices or similar.
This effort is still ongoing (but nearly finished). In a few weeks time, MapComplete went from being utterly unusable to being (nearly) feature-equivalent for blind people.
## Community
2023 was the year that the community had a small but healthy growth.
### Community calls
In the first 6 months, there were biweekly community calls. They were mostly between Pietervdvn and Tordans, but often joined by Robin
or people passing by once to tell about their project.
After the summer holiday, the community calls waned and weren't restarted - I was to busy and neglected them a bit.
But - rejoice: we will restart them! The next one is [on friday the 26th of january, 14:00 CET](https://mobilizon.openstreetmap.fr/events/568afd3a-d18a-4ff0-acc4-626d6d09d6d5).
### Patrons
Another nice milestone is that two more patrons started pledging a small amount for the development of MapComplete.
I'm now [receiving €1.03 per week via Liberapay](https://liberapay.com/pietervdvn). I'd like to thank my three patrons for the trust and small financial contribution!
If you feel like becoming a patron too, [head over to Liberapay](https://liberapay.com/pietervdvn).
### Mastodon-accounts
Another _huge_ success in 2023 were the mastodon-accounts.
The [MapComplete-account](https://en.osm.town/@MapComplete) had 800 followers in march, which passed the 1.000 mark in August and around 1200 at the time of writing,
with a few new followers daily.
Another success is the [automated account](https://botsin.space/@mapcomplete/) which posts a small, daily overview of changes made with MapComplete,
including up to 12 pictures which were made the day before. 133 people follow this account, and there was some interaction every day (e.g. a star, a boost or a small message)
Another fun fact: the automated account was registered on the 12th of january 2023, so it is a year old now!
## Change Metrics
But of course, the most interesting statistics are how MapComplete was used in the past year.
Some basic logging is done with [goatcounter](https://pietervdvn.goatcounter.com), which shows around 200 up to 300 visitors per day on average.
That isn't a neglectable amount, but it is not very big either. On the other hand, I suspect that goat counter misses quite a few visitors.
OSM-people tend to be privacy-aware and run scriptblocker, which'll also block goatcounter.
Also, there is a big gap in December. The script was not properly configured and thus not counting visitors.
However, the most interesting stastic is of course how much changes are made to OpenStreetMap with MapComplete.
There is a small, unpolished, irregularly updated [statistics page on MapComplete](https://mapcomplete.org/statistics) which
has some nice statistics, so lets dive in!
### Modifications name sorted by theme
Lets start our little analysis by the graph "number of changed objects per theme".
This graph is dominated by two themes. One of them, the *'GRB'*-theme (in red) is quite a special theme which causes thousands of changed objects, on one day even more then 18.000 changed objects by a single person.
This might seem like an extra-ordinary amount for MapComplete, which is supposed to focus on individual POIs...
However, the GRB theme is a very special theme which helps to import building data in Flanders.
As such, this is a glorified copy-paste from the governmental dataset into OpenStreetMap, which causes this ampount of changes.
![ModificatiosPerTheme.png](2023_in_review/ModificationsPerTheme.png)
### The etymology theme
The second theme causing thousands of changes is the *etymology*-theme. Here to, some automation inflates the numbers:
when one selects a road and applies an etymology to it, _all_ nearby segments with the same name get this etymology applied,
which in some cases can amount to quite some changed segments - often five to ten, but sometimes even 50 or 100 segments.
If a few contributors add data on the same day, this can amount to a lot of changes - one day even close to 10.000
Another interesting fact about the Etymology theme is that it is _very_ popular.
Many days had several contributors making changes with the theme; 346 days of the year saw at least one contribution with the change!
That makes that no changes with the etymology map were made on only 19 days.
Kalepom, AE35, Mikalet, NaanAvanlllai and Peter Broderson were the five top contributors here.
![ModificationsEtymologyPerContributor.png](2023_in_review%2FModificationsEtymologyPerContributor.png)
### Modifications name sorted by theme, excluding GRB and etymology
When filtering away those themes, a much more uniform image appears, as a patchwork of various edits by all the maps.
Of course, there is some variability - e.g. if a single mapper did a campaign around e.g. benches or AEDs
![ModificationsPerThemeClean.png](2023_in_review/ModificationsPerThemeClean.png)
If we have a look to the number of changesets created per theme, we see a typical distribution where a few themes have a lot of edits, whereas others are less popular.
![ThemesChangesetCount.png](2023_in_review/ThemesChangesetCount.png)
The most popular themes are:
- Cyclofix (988 changesets, red)
- trees (880 changesets, yellow)
- 853 changesets without actual changes (these are caused by bugs - should figure out why this happens rather soon...)
- Benches (701 changesets, green)
- aed (656 changesets)
- artwork (630 CS, orange)
- charging stations (563)
- street_lighting (437)
- toilets (416)
- food (391)
- advertising (380)
- waste (377)
- surveillance (357)
- shops (347)
- and then a long tail
What can we learn from these statistics?
First of all, the number of changesets has some indication of actual changes, but it is not directly related. A changeset can be a single answered question or hundred of new items.
Second, cyclofix remains the most popular theme; this is probably because a lot of OSM-people are interested in sustainable mobility,
because it is one of the themes I pich as example and because it is has the first position in the index.
Trees follows closely, with 10% less changesets. This is due to the easy to make changes with it - there are many unmapped trees,
but also because a few people are dedicated to mapping all the trees in their environment.
I suspect that a similar reasoning applies for the third theme, namely 'benches'.
Benches also have a strong usecase, as it is important for less mobile people.
The fourth theme, AEDs, got a whopping 656 changesets. This might be because the emergency services of the Province of East-Flanders (Belgium) did a
campaign where they imported all the AEDs that they knew of with MapComplete. Additionally, Toni Sierra and PhillipeC seem to be very intersted with 84 and 78 changeset respectively.
Some other surprises are in the big number of changesets by the surveillance- and advertisement-maps,
which both have very strong political connotations. Especially the surveillance camera map is very delicate, yet 89 people made changes with it.
### Who did contribute?
With the number of contributors, we see another, very typical distributions. A few very active people and a long tail of contributors making a few changes:
(The graph and statistics below are without Etymology and GRB)
![ContributorsChangesetcount.png](2023_in_review/ContributorsChangesetcount.png)
The top contributor - by number of changesets - were:
- 5R-MFT with 1.171 changesets
- Pietervdvn (me) with 733 changesets
- vjyblauw with 605 changesets
- Awo (495 changesets)
- ThibaultMol (485 changesets)
- Kalepom (430 changesets)
- Toni Sierra (362 changesets)
- paunofu (312 changesets)
- user_5589 (312 changesets)
- APNeunzehn74 (277 changesets)
- Prem Das (245 changesets)
No big surprises here, except that I have been completely overtaken in number of changesets :gasp:
Congratulations 5R-MFT! This is the first year ever that I'm _not_ the one who made the most changesets with MapComplete.
This is still the case including etymology and GRB themes with 1.174 against 790 changesets.
### What languages were used when making changesets?
To finish the metrics: a small statistic about the languages that people use MapComplete with:
![Languages.png](2023_in_review/Languages.png)
The top languages are:
- English + English-US (4544)
- Dutch (2360 changesets)
- German (2.255 changesets)
- French (1314 changesets)
- Spanish (837 changesets)
- Catalan (803 changesets)
No big surprises here for me. As I'm Dutch-speaking and promoted MapComplete in Flanders (and had a few Flanders-specific projects),
it is not a surprise that Dutch is over-represented.
Catalan is also slightly overrepresented, but that is because a proud catalan took the time to translate it to catalan early on and
uses it frequently.
If you want to see MapComplete in _your_ language, head over to [Weblate](https://hosted.weblate.org/projects/mapcomplete/), create an account
and start translating!
There is, in settings, also an option to enable 'translation mode' in MapComplete.
Many pieces of text in the interface will gain a small 'translate'-button which you can click to immediately translate or correct that piece of text.
If you enable translate mode, you'll also have a button to quickly translate all strings of the specific theme.
Translations are pulled in regularly (about once week) so you'll see your translations quite fast. As of january 2024,
the translation completeness for English and German is (near) 100%, where as translations for Polish, Dutch, Czech and Catalan are
quite complete as well.
![2024-01-15 TranslationCompleteness.svg](2023_in_review%2F2024-01-15%20TranslationCompleteness.svg)
# Wrapping up 2023
In summary, MapComplete has become a lot more mature, usable and faster within 2023.
The absolute number of changes made in 2023 went up in a sustainable manner - increasing by a factor 1.5.
So, all in all, not a bad result; but it would be nice to see a doubling in number of changes next year!
Around 14.000 changesets (!) were made with MapComplete last year, so lets try to get 30.000 changesets together next year!
# Sources
Want to see the number for yourself? Have a look at https://mapcomplete.org/statistics
Generating the creation date of themes was done by running a small script in `./assets/themes`:
````
for f in $( ls */*.json | grep -v "license_info.json" )
do
echo -en "$f "
git log --follow --format=%ad --date iso $f | tail -1
done
````

View file

@ -0,0 +1,261 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="465" height="320" xml:lang="en"><script xmlns="">{
document.currentScript.dataset.injected = true;
const o = JSON.parse(decodeURIComponent(escape(atob('eyJ1c2VyQWdlbnQiOiJNb3ppbGxhLzUuMCAoWDExOyBMaW51eCB4ODZfNjQ7IHJ2OjEwOS4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzExNC4wIiwiYXBwVmVyc2lvbiI6IjUuMCAoWDExKSIsInBsYXRmb3JtIjoiTGludXgiLCJ2ZW5kb3IiOiIiLCJwcm9kdWN0IjoiR2Vja28iLCJ1c2VyQWdlbnREYXRhIjoiW2RlbGV0ZV0iLCJvc2NwdSI6IkxpbnV4IHg4Nl82NCIsInByb2R1Y3RTdWIiOiIyMDEwMDEwMSIsImJ1aWxkSUQiOiIyMDE4MTAwMTAwMDAwMCJ9'))));
if (o.userAgentDataBuilder) {
const v = new class NavigatorUAData {
#p;
constructor({p, ua}) {
this.#p = p;
const version = p.browser.major;
const name = p.browser.name === 'Chrome' ? 'Google Chrome' : p.browser.name;
this.brands = [{
brand: name,
version
}, {
brand: 'Chromium',
version
}, {
brand: 'Not=A?Brand',
version: '24'
}];
this.mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA-Platform
this.platform = 'Unknown';
if (p.os &amp;&amp; p.os.name) {
const name = p.os.name.toLowerCase();
if (name.includes('mac')) {
this.platform = 'macOS';
}
else if (name.includes('debian')) {
this.platform = 'Linux';
}
else {
this.platform = p.os.name;
}
}
}
toJSON() {
return {
brands: this.brands,
mobile: this.mobile,
platform: this.platform
};
}
getHighEntropyValues(hints) {
if (!hints || Array.isArray(hints) === false) {
return Promise.reject(Error("Failed to execute 'getHighEntropyValues' on 'NavigatorUAData'"));
}
const r = this.toJSON();
if (hints.includes('architecture')) {
r.architecture = this.#p?.cpu?.architecture || 'x86';
}
if (hints.includes('bitness')) {
r.bitness = '64';
}
if (hints.includes('model')) {
r.model = '';
}
if (hints.includes('platformVersion')) {
r.platformVersion = this.#p?.os?.version || '10.0.0';
}
if (hints.includes('uaFullVersion')) {
r.uaFullVersion = this.brands[0].version;
}
if (hints.includes('fullVersionList')) {
r.fullVersionList = this.brands;
}
return Promise.resolve(r);
}
}(o.userAgentDataBuilder);
navigator.__defineGetter__('userAgentData', () =&gt; {
return v;
});
}
delete o.userAgentDataBuilder;
for (const key of Object.keys(o)) {
if (o[key] === '[delete]') {
delete Object.getPrototypeOf(window.navigator)[key];
}
else {
navigator.__defineGetter__(key, () =&gt; {
if (o[key] === 'empty') {
return '';
}
return o[key];
});
}
}
}</script>
<defs>
<style type="text/css">@import url(https://s.weblate.org/cdn/font-source/source-sans-3.css);</style>
</defs>
<g id="layer1">
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/eu/" xlink:title="Basque">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="20" transform="rotate(-90)" id="text20">Basque</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect20" height="3" width="6" rx="2" y="156" x="14"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/ca/" xlink:title="Catalan">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="35" transform="rotate(-90)" id="text35">Catalan</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect35" height="126" width="6" rx="2" y="33" x="29"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/nan/" xlink:title="Chinese (Min Nan) (nan)">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="50" transform="rotate(-90)" id="text50">Chinese (Min Nan) (nan)</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect50" height="0" width="6" rx="2" y="159" x="44"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/zh_Hans/" xlink:title="Chinese (Simplified)">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="65" transform="rotate(-90)" id="text65">Chinese (Simplified)</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect65" height="7" width="6" rx="2" y="152" x="59"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/zh_Hant/" xlink:title="Chinese (Traditional)">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="80" transform="rotate(-90)" id="text80">Chinese (Traditional)</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect80" height="81" width="6" rx="2" y="78" x="74"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/cs/" xlink:title="Czech">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="95" transform="rotate(-90)" id="text95">Czech</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect95" height="124" width="6" rx="2" y="35" x="89"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/da/" xlink:title="Danish">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="110" transform="rotate(-90)" id="text110">Danish</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect110" height="93" width="6" rx="2" y="66" x="104"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/nl/" xlink:title="Dutch">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="125" transform="rotate(-90)" id="text125">Dutch</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect125" height="126" width="6" rx="2" y="33" x="119"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/en/" xlink:title="English">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="140" transform="rotate(-90)" id="text140">English</text>
<rect style="fill:#2eccaa;fill-opacity:1;stroke:none" id="rect140" height="150" width="6" rx="2" y="10" x="134"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/eo/" xlink:title="Esperanto">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="155" transform="rotate(-90)" id="text155">Esperanto</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect155" height="13" width="6" rx="2" y="146" x="149"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/fil/" xlink:title="Filipino">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="170" transform="rotate(-90)" id="text170">Filipino</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect170" height="7" width="6" rx="2" y="152" x="164"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/fi/" xlink:title="Finnish">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="185" transform="rotate(-90)" id="text185">Finnish</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect185" height="57" width="6" rx="2" y="102" x="179"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/fr/" xlink:title="French">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="200" transform="rotate(-90)" id="text200">French</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect200" height="82" width="6" rx="2" y="77" x="194"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/gl/" xlink:title="Galician">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="215" transform="rotate(-90)" id="text215">Galician</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect215" height="24" width="6" rx="2" y="135" x="209"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/de/" xlink:title="German">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="230" transform="rotate(-90)" id="text230">German</text>
<rect style="fill:#2eccaa;fill-opacity:1;stroke:none" id="rect230" height="149" width="6" rx="2" y="10" x="224"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/he/" xlink:title="Hebrew">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="245" transform="rotate(-90)" id="text245">Hebrew</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect245" height="3" width="6" rx="2" y="156" x="239"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/hu/" xlink:title="Hungarian">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="260" transform="rotate(-90)" id="text260">Hungarian</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect260" height="58" width="6" rx="2" y="101" x="254"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/id/" xlink:title="Indonesian">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="275" transform="rotate(-90)" id="text275">Indonesian</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect275" height="31" width="6" rx="2" y="128" x="269"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/it/" xlink:title="Italian">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="290" transform="rotate(-90)" id="text290">Italian</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect290" height="66" width="6" rx="2" y="94" x="284"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/ja/" xlink:title="Japanese">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="305" transform="rotate(-90)" id="text305">Japanese</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect305" height="25" width="6" rx="2" y="134" x="299"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/nb_NO/" xlink:title="Norwegian Bokmål">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="320" transform="rotate(-90)" id="text320">Norwegian Bokmål</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect320" height="74" width="6" rx="2" y="85" x="314"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/pl/" xlink:title="Polish">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="335" transform="rotate(-90)" id="text335">Polish</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect335" height="124" width="6" rx="2" y="35" x="329"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/pt/" xlink:title="Portuguese">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="350" transform="rotate(-90)" id="text350">Portuguese</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect350" height="68" width="6" rx="2" y="91" x="344"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/pt_BR/" xlink:title="Portuguese (Brazil)">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="365" transform="rotate(-90)" id="text365">Portuguese (Brazil)</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect365" height="27" width="6" rx="2" y="132" x="359"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/pa_PK/" xlink:title="Punjabi (Pakistan)">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="380" transform="rotate(-90)" id="text380">Punjabi (Pakistan)</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect380" height="17" width="6" rx="2" y="142" x="374"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/ru/" xlink:title="Russian">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="395" transform="rotate(-90)" id="text395">Russian</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect395" height="32" width="6" rx="2" y="127" x="389"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/sl/" xlink:title="Slovenian">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="410" transform="rotate(-90)" id="text410">Slovenian</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect410" height="8" width="6" rx="2" y="151" x="404"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/es/" xlink:title="Spanish">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="425" transform="rotate(-90)" id="text425">Spanish</text>
<rect style="fill:#38f;fill-opacity:1;stroke:none" id="rect425" height="91" width="6" rx="2" y="68" x="419"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/sv/" xlink:title="Swedish">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="440" transform="rotate(-90)" id="text440">Swedish</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect440" height="11" width="6" rx="2" y="148" x="434"/>
</a>
<a xlink:href="https://hosted.weblate.org/projects/mapcomplete/core/-/zgh/" xlink:title="Tamazight (Standard Moroccan)">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:11px;font-family:'Source Sans 3',sans-serif;fill:#808080;text-anchor:end;" x="-170" y="455" transform="rotate(-90)" id="text455">Tamazight (Standard Moroccan)</text>
<rect style="fill:#f6664c;fill-opacity:1;stroke:none" id="rect455" height="1" width="6" rx="2" y="158" x="449"/>
</a>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View file

@ -121,6 +121,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -117,6 +117,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -2,7 +2,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -174,6 +174,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -2,7 +2,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -170,6 +170,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -85,7 +85,7 @@
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"type": "array",
"items": {
"type": "string"
@ -136,14 +136,26 @@
"type": "boolean"
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox",
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nUse `auto:<tagrenderingId>` to automatically create an icon based on a tagRendering which has icons\n\nType: icon[]\ngroup: infobox",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
"allOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
]
},
{
"type": "string"
@ -253,7 +265,7 @@
}
},
"tagRenderings": {
"description": "question: Edit this attribute showing piece/question\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"description": "question: Edit this way this attributed is displayed or queried\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"type": "array",
"items": {
"anyOf": [
@ -370,7 +382,14 @@
"units": {
"type": "array",
"items": {
"$ref": "#/definitions/default_2"
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"$ref": "#/definitions/Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>"
}
]
}
},
"syncSelection": {
@ -518,6 +537,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -561,7 +584,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -850,6 +873,20 @@
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [
@ -1242,6 +1279,17 @@
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1457,6 +1505,17 @@
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1597,33 +1656,71 @@
"sourceString"
]
},
"subexpand": {
"$ref": "#/definitions/Record<string,string[]>"
},
"renderings": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
},
{
"type": "array",
"items": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
}
}
]
}
},
"required": [
@ -1784,6 +1881,10 @@
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "object",
"properties": {
"quantity": {
"description": "What is quantified? E.g. 'speed', 'length' (including width, diameter, ...), 'electric tension', 'electric current', 'duration'",
"type": "string"
},
"appliesToKey": {
"description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical(<key>)}`",
"type": "array",
@ -1808,10 +1909,13 @@
}
},
"required": [
"applicableUnits",
"appliesToKey"
"applicableUnits"
],
"additionalProperties": false
},
"Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>": {
"type": "object",
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#",

View file

@ -85,7 +85,7 @@ export default {
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"type": "array",
"items": {
"type": "string"
@ -136,14 +136,26 @@ export default {
"type": "boolean"
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox",
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nUse `auto:<tagrenderingId>` to automatically create an icon based on a tagRendering which has icons\n\nType: icon[]\ngroup: infobox",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
"allOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
]
},
{
"type": "string"
@ -253,7 +265,7 @@ export default {
}
},
"tagRenderings": {
"description": "question: Edit this attribute showing piece/question\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"description": "question: Edit this way this attributed is displayed or queried\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"type": "array",
"items": {
"anyOf": [
@ -370,7 +382,14 @@ export default {
"units": {
"type": "array",
"items": {
"$ref": "#/definitions/default_2"
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"$ref": "#/definitions/Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>"
}
]
}
},
"syncSelection": {
@ -514,6 +533,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -555,7 +578,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -841,6 +864,20 @@ export default {
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [
@ -1229,6 +1266,17 @@ export default {
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1443,6 +1491,17 @@ export default {
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1582,33 +1641,71 @@ export default {
"sourceString"
]
},
"subexpand": {
"$ref": "#/definitions/Record<string,string[]>"
},
"renderings": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
},
{
"type": "array",
"items": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
}
}
]
}
},
"required": [
@ -1765,6 +1862,10 @@ export default {
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "object",
"properties": {
"quantity": {
"description": "What is quantified? E.g. 'speed', 'length' (including width, diameter, ...), 'electric tension', 'electric current', 'duration'",
"type": "string"
},
"appliesToKey": {
"description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical(<key>)}`",
"type": "array",
@ -1789,9 +1890,11 @@ export default {
}
},
"required": [
"applicableUnits",
"appliesToKey"
"applicableUnits"
]
},
"Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>": {
"type": "object"
}
},
"$schema": "http://json-schema.org/draft-07/schema#"

View file

@ -427,6 +427,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -470,7 +474,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -759,6 +763,20 @@
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [
@ -1151,6 +1169,17 @@
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1366,6 +1395,17 @@
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1506,33 +1546,71 @@
"sourceString"
]
},
"subexpand": {
"$ref": "#/definitions/Record<string,string[]>"
},
"renderings": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
},
{
"type": "array",
"items": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
}
}
]
}
},
"required": [
@ -1693,6 +1771,10 @@
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "object",
"properties": {
"quantity": {
"description": "What is quantified? E.g. 'speed', 'length' (including width, diameter, ...), 'electric tension', 'electric current', 'duration'",
"type": "string"
},
"appliesToKey": {
"description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical(<key>)}`",
"type": "array",
@ -1717,11 +1799,14 @@
}
},
"required": [
"applicableUnits",
"appliesToKey"
"applicableUnits"
],
"additionalProperties": false
},
"Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>": {
"type": "object",
"additionalProperties": false
},
"default": {
"type": "object",
"properties": {
@ -1854,7 +1939,7 @@
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"type": "array",
"items": {
"type": "string"
@ -1905,14 +1990,26 @@
"type": "boolean"
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox",
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nUse `auto:<tagrenderingId>` to automatically create an icon based on a tagRendering which has icons\n\nType: icon[]\ngroup: infobox",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
"allOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
]
},
{
"type": "string"
@ -2022,7 +2119,7 @@
}
},
"tagRenderings": {
"description": "question: Edit this attribute showing piece/question\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"description": "question: Edit this way this attributed is displayed or queried\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"type": "array",
"items": {
"anyOf": [
@ -2139,7 +2236,14 @@
"units": {
"type": "array",
"items": {
"$ref": "#/definitions/default_2"
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"$ref": "#/definitions/Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>"
}
]
}
},
"syncSelection": {
@ -2254,7 +2358,7 @@
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"type": "array",
"items": {
"type": "string"
@ -2305,14 +2409,26 @@
"type": "boolean"
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox",
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nUse `auto:<tagrenderingId>` to automatically create an icon based on a tagRendering which has icons\n\nType: icon[]\ngroup: infobox",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
"allOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
]
},
{
"type": "string"
@ -2422,7 +2538,7 @@
}
},
"tagRenderings": {
"description": "question: Edit this attribute showing piece/question\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"description": "question: Edit this way this attributed is displayed or queried\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"type": "array",
"items": {
"anyOf": [
@ -2539,7 +2655,14 @@
"units": {
"type": "array",
"items": {
"$ref": "#/definitions/default_2"
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"$ref": "#/definitions/Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>"
}
]
}
},
"syncSelection": {

View file

@ -423,6 +423,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -464,7 +468,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -750,6 +754,20 @@ export default {
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [
@ -1138,6 +1156,17 @@ export default {
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1352,6 +1381,17 @@ export default {
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -1491,33 +1531,71 @@ export default {
"sourceString"
]
},
"subexpand": {
"$ref": "#/definitions/Record<string,string[]>"
},
"renderings": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
},
{
"type": "array",
"items": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/QuestionableTagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"builtin": {
"type": "string"
},
"override": {
"$ref": "#/definitions/Partial<QuestionableTagRenderingConfigJson>"
}
},
"required": [
"builtin",
"override"
]
},
{
"type": "string"
}
]
}
}
}
]
}
},
"required": [
@ -1674,6 +1752,10 @@ export default {
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "object",
"properties": {
"quantity": {
"description": "What is quantified? E.g. 'speed', 'length' (including width, diameter, ...), 'electric tension', 'electric current', 'duration'",
"type": "string"
},
"appliesToKey": {
"description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical(<key>)}`",
"type": "array",
@ -1698,10 +1780,12 @@ export default {
}
},
"required": [
"applicableUnits",
"appliesToKey"
"applicableUnits"
]
},
"Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>": {
"type": "object"
},
"default": {
"type": "object",
"properties": {
@ -1833,7 +1917,7 @@ export default {
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"type": "array",
"items": {
"type": "string"
@ -1884,14 +1968,26 @@ export default {
"type": "boolean"
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox",
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nUse `auto:<tagrenderingId>` to automatically create an icon based on a tagRendering which has icons\n\nType: icon[]\ngroup: infobox",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
"allOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
]
},
{
"type": "string"
@ -2001,7 +2097,7 @@ export default {
}
},
"tagRenderings": {
"description": "question: Edit this attribute showing piece/question\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"description": "question: Edit this way this attributed is displayed or queried\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"type": "array",
"items": {
"anyOf": [
@ -2118,7 +2214,14 @@ export default {
"units": {
"type": "array",
"items": {
"$ref": "#/definitions/default_2"
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"$ref": "#/definitions/Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>"
}
]
}
},
"syncSelection": {
@ -2232,7 +2335,7 @@ export default {
]
},
"calculatedTags": {
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to <a>Docs/CalculatedTags.md</a> for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?",
"type": "array",
"items": {
"type": "string"
@ -2283,14 +2386,26 @@ export default {
"type": "boolean"
},
"titleIcons": {
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox",
"description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nUse `auto:<tagrenderingId>` to automatically create an icon based on a tagRendering which has icons\n\nType: icon[]\ngroup: infobox",
"anyOf": [
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
"allOf": [
{
"$ref": "#/definitions/TagRenderingConfigJson"
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
]
},
{
"type": "string"
@ -2400,7 +2515,7 @@ export default {
}
},
"tagRenderings": {
"description": "question: Edit this attribute showing piece/question\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"description": "question: Edit this way this attributed is displayed or queried\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings",
"type": "array",
"items": {
"anyOf": [
@ -2517,7 +2632,14 @@ export default {
"units": {
"type": "array",
"items": {
"$ref": "#/definitions/default_2"
"anyOf": [
{
"$ref": "#/definitions/default_2"
},
{
"$ref": "#/definitions/Record<string,string|{quantity:string;denominations:string[];canonical?:string|undefined;}>"
}
]
}
},
"syncSelection": {

View file

@ -186,6 +186,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -229,7 +233,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"

View file

@ -182,6 +182,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -223,7 +227,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"

View file

@ -57,6 +57,20 @@
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [
@ -226,6 +240,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -269,7 +287,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"

View file

@ -57,6 +57,20 @@ export default {
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [
@ -222,6 +236,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -263,7 +281,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"

View file

@ -131,6 +131,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -127,6 +127,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -287,6 +287,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -330,7 +334,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"

View file

@ -283,6 +283,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -324,7 +328,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"

View file

@ -97,6 +97,17 @@
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -333,6 +344,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -376,7 +391,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -665,6 +680,20 @@
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [

View file

@ -97,6 +97,17 @@ export default {
}
]
},
"editButtonAriaLabel": {
"description": "When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.\nIn some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).\nIf the user presses _tab_ again, they'll select the button and have the link read aloud a second time.",
"anyOf": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
]
},
"labels": {
"description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer",
"type": "array",
@ -329,6 +340,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -370,7 +385,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -656,6 +671,20 @@ export default {
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [

View file

@ -24,8 +24,21 @@
"sourceString"
]
},
"subexpand": {
"$ref": "#/definitions/Record<string,string[]>"
},
"renderings": {
"$ref": "#/definitions/T"
"anyOf": [
{
"$ref": "#/definitions/T"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/T"
}
}
]
}
},
"required": [
@ -153,6 +166,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -196,7 +213,7 @@
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -485,6 +502,20 @@
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [

View file

@ -24,8 +24,21 @@ export default {
"sourceString"
]
},
"subexpand": {
"$ref": "#/definitions/Record<string,string[]>"
},
"renderings": {
"$ref": "#/definitions/T"
"anyOf": [
{
"$ref": "#/definitions/T"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/T"
}
}
]
}
},
"required": [
@ -149,6 +162,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [
@ -190,7 +207,7 @@ export default {
"type": "object",
"properties": {
"icon": {
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"description": "question: What icon should be used?\ntype: icon\nsuggestions: return Constants.defaultPinIcons.map(i => ({if: \"value=\"+i, then: i, icon: i}))",
"anyOf": [
{
"$ref": "#/definitions/MinimalTagRenderingConfigJson"
@ -476,6 +493,20 @@ export default {
}
]
},
"alsoShowIf": {
"description": "Also show this 'then'-option if the feature matches these tags.\nIdeal for outdated tags.",
"anyOf": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
]
},
"ifnot": {
"description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`\n\nifunset: Do not apply a tag if a different mapping is chosen.",
"anyOf": [

View file

@ -2,6 +2,10 @@
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "object",
"properties": {
"quantity": {
"description": "What is quantified? E.g. 'speed', 'length' (including width, diameter, ...), 'electric tension', 'electric current', 'duration'",
"type": "string"
},
"appliesToKey": {
"description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical(<key>)}`",
"type": "array",
@ -26,8 +30,7 @@
}
},
"required": [
"applicableUnits",
"appliesToKey"
"applicableUnits"
],
"definitions": {
"TagConfigJson": {
@ -150,6 +153,10 @@
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -2,6 +2,10 @@ export default {
"description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given",
"type": "object",
"properties": {
"quantity": {
"description": "What is quantified? E.g. 'speed', 'length' (including width, diameter, ...), 'electric tension', 'electric current', 'duration'",
"type": "string"
},
"appliesToKey": {
"description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical(<key>)}`",
"type": "array",
@ -26,8 +30,7 @@ export default {
}
},
"required": [
"applicableUnits",
"appliesToKey"
"applicableUnits"
],
"definitions": {
"TagConfigJson": {
@ -146,6 +149,10 @@ export default {
"prefix": {
"description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field",
"type": "boolean"
},
"addSpace": {
"description": "If set, add a space between the quantity and the denomination.\n\nE.g.: `50 mph` instad of `50mph`",
"type": "boolean"
}
},
"required": [

View file

@ -5,7 +5,8 @@
"de": "Tierheime",
"es": "Centros de acogida de animales",
"zh_Hans": "动物收容所",
"pt": "Abrigo para animais"
"pt": "Abrigo para animais",
"ca": "Refugis d'animals"
},
"description": {
"en": "An animal shelter is a facility where animals in trouble are brought and facility's staff (volunteers or not) feeds them and cares of them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres. ",
@ -22,7 +23,8 @@
"de": "Tierheim",
"es": "Centro de acogida de animales",
"zh_Hans": "动物收容所",
"pt": "Abrigo para animais"
"pt": "Abrigo para animais",
"ca": "Refugi d'animals"
},
"mappings": [
{
@ -31,7 +33,8 @@
"en": "{name}",
"de": "{name}",
"es": "{name}",
"zh_Hans": "{name}"
"zh_Hans": "{name}",
"ca": "{name}"
}
}
]
@ -67,7 +70,8 @@
"de": "ein Tierheim",
"es": "una protectora de animales",
"zh_Hans": "动物收容所",
"pt": "um abrigo para animais"
"pt": "um abrigo para animais",
"ca": "un refugi d'animals"
},
"tags": [
"amenity=animal_shelter"
@ -86,7 +90,8 @@
"en": "What is the name of this animal shelter?",
"de": "Wie lautet der Name des Tierheims?",
"es": "¿Cómo se llama este refugio de animales?",
"zh_Hans": "这个动物收容所叫什么名字?"
"zh_Hans": "这个动物收容所叫什么名字?",
"ca": "Quin nom té aquest refugi d'animals?"
},
"render": {
"en": "This animal shelter is named <b>{name}</b>",
@ -104,7 +109,8 @@
"en": "What is the purpose of the animal shelter?",
"de": "Was ist der Zweck des Tierheims?",
"es": "¿Cuál es la finalidad del refugio de animales?",
"zh_Hans": "动物收容所的目的是什么?"
"zh_Hans": "动物收容所的目的是什么?",
"ca": "Quina és la finalitat del refugi d'animals?"
},
"mappings": [
{
@ -112,7 +118,8 @@
"en": "Animals are kept here until adopted by a new owner",
"de": "Tiere werden hier bis zur Abgabe an einen neuen Besitzer untergebracht",
"es": "Los animales permanecen aquí hasta que son adoptados por un nuevo propietario",
"zh_Hans": "动物被饲养在这里直到被新主人收养"
"zh_Hans": "动物被饲养在这里直到被新主人收养",
"ca": "Els animals romanen ací fins que son adoptats per un nou propietari"
},
"if": "purpose=adoption"
},
@ -121,7 +128,8 @@
"en": "Animals are taken care of for the rest of their lives",
"de": "Tiere werden hier bis zum Ende Ihres Lebens untergebracht",
"es": "Los animales reciben cuidados para el resto de su vida",
"zh_Hans": "动物的余生都得到照顾"
"zh_Hans": "动物的余生都得到照顾",
"ca": "Els animals reben cures per a la resta de la seva vida"
},
"if": "purpose=sanctuary"
},
@ -130,7 +138,8 @@
"en": "Injured animals are rehabilitated here until they can be released in nature again ",
"de": "Tiere werden hier untergebracht und gepflegt bis sie wieder in freier Natur ausgesetzt werden können ",
"es": "Los animales heridos se rehabilitan aquí hasta que pueden ser liberados de nuevo en la naturaleza ",
"zh_Hans": "受伤的动物在这里康复,直到它们可以再次被释放到大自然中 "
"zh_Hans": "受伤的动物在这里康复,直到它们可以再次被释放到大自然中 ",
"ca": "Els animals ferits es rehabiliten aquí fins que puguen ser alliberats de nou a la natura "
},
"if": "purpose=release"
}
@ -142,14 +151,16 @@
"en": "When is this animal shelter opened?",
"de": "Wann ist das Tierheim geöffnet?",
"es": "¿Cuándo se abre este refugio de animales?",
"zh_Hans": "这个动物收容所什么时候开放?"
"zh_Hans": "这个动物收容所什么时候开放?",
"ca": "Quan està obert aquest refugi d'animals?"
},
"id": "7",
"render": {
"en": "{opening_hours_table()}",
"de": "{opening_hours_table()}",
"es": "{opening_hours_table()}",
"zh_Hans": "{opening_hours_table()}"
"zh_Hans": "{opening_hours_table()}",
"ca": "{opening_hours_table()}"
},
"freeform": {
"key": "opening_hours",

View file

@ -1,17 +1,5 @@
{
"id": "bank",
"description": {
"en": "A financial institution to deposit money",
"de": "Ein Finanzinstitut, um Geld einzuzahlen",
"nl": "Een financiële instelling waar je geld kunt",
"ca": "Una institució financera per a dipositar diners",
"cs": "Finanční instituce pro ukládání peněz",
"he": "מוסד פיננסי להפקדת כסף",
"pl": "Instytucja finansowa pozwalająca wpłacić pieniądze",
"pt_BR": "Um instituição financeira para depositar dinheiro",
"es": "Una institución financiera para depositar dinero",
"pt": "Uma instituição financeira para depositar dinheiro"
},
"name": {
"en": "Banks",
"de": "Banken",
@ -26,6 +14,21 @@
"es": "Bancos",
"pt": "Bancos"
},
"description": {
"en": "A financial institution to deposit money",
"de": "Ein Finanzinstitut, um Geld einzuzahlen",
"nl": "Een financiële instelling waar je geld kunt",
"ca": "Una institució financera per a dipositar diners",
"cs": "Finanční instituce pro ukládání peněz",
"he": "מוסד פיננסי להפקדת כסף",
"pl": "Instytucja finansowa pozwalająca wpłacić pieniądze",
"pt_BR": "Um instituição financeira para depositar dinheiro",
"es": "Una institución financiera para depositar dinero",
"pt": "Uma instituição financeira para depositar dinheiro"
},
"source": {
"osmTags": "amenity=bank"
},
"title": {
"render": "Bank",
"mappings": [
@ -35,9 +38,24 @@
}
]
},
"source": {
"osmTags": "amenity=bank"
},
"pointRendering": [
{
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "./assets/layers/bank/bank.svg"
}
],
"location": [
"point",
"centroid"
]
}
],
"lineRendering": [],
"tagRenderings": [
"images",
{
@ -127,24 +145,6 @@
]
}
],
"pointRendering": [
{
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "./assets/layers/bank/bank.svg"
}
],
"location": [
"point",
"centroid"
]
}
],
"lineRendering": [],
"deletion": {
"softDeletionTags": "amenity="
}

View file

@ -166,7 +166,7 @@
"hu": "Korlát",
"it": "Archetti",
"zh_Hant": "單車架",
"ca": "Bastidors de grapes",
"ca": "Bastidors",
"da": "Hæftestativer",
"cs": "Stojany",
"pt_BR": "Racks para prender a bicicleta"

View file

@ -0,0 +1,92 @@
{
"id": "brothel",
"name": {
"en": "Brothels"
},
"description": {
"en": "An establishment specifically dedicated to prostitution. "
},
"source": {
"osmTags": "amenity=brothel"
},
"minzoom": 6,
"title": {
"render": {
"en": "Brothel"
},
"mappings": [
{
"if": "name~*",
"then": {
"*": "{name}"
}
}
]
},
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "ring",
"color": "#fc6488"
}
]
},
{
"location": [
"centroid",
"point"
],
"marker": [
{
"icon": "heart",
"color": "#fc6488"
}
],
"iconSize": "28,28"
}
],
"presets": [
{
"title": {
"en": "a brothel"
},
"tags": [
"amenity=brothel"
]
}
],
"tagRenderings": [
"images",
"reviews",
{
"multiAnswer": false,
"id": "name",
"freeform": {
"inline": false,
"key": "name"
},
"question": {
"en": "What is the name of this brothel?"
},
"render": {
"en": "This brothel is named <b>{name}</b>"
}
},
"opening_hours",
"contact"
],
"deletion": {
"omitDefaultDeleteReasons": false
},
"allowMove": true,
"allowSplit": false
}

View file

@ -5,7 +5,11 @@
"nl": "Oplaadpunten",
"de": "Ladestationen"
},
"minzoom": 10,
"description": {
"en": "A charging station",
"nl": "Oplaadpunten",
"de": "Eine Ladestation"
},
"source": {
"osmTags": {
"and": [
@ -20,6 +24,7 @@
]
}
},
"minzoom": 10,
"title": {
"render": {
"en": "Charging station",
@ -65,12 +70,103 @@
}
]
},
"description": {
"en": "A charging station",
"nl": "Oplaadpunten",
"de": "Eine Ladestation"
},
"#": "no-question-hint-check",
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "pin",
"color": "#fff"
},
{
"icon": {
"render": "./assets/themes/charging_stations/plug.svg",
"mappings": [
{
"if": "bicycle=yes",
"then": "./assets/themes/charging_stations/bicycle.svg"
},
{
"if": {
"or": [
"car=yes",
"motorcar=yes"
]
},
"then": "./assets/themes/charging_stations/car.svg"
}
]
}
}
],
"iconBadges": [
{
"if": {
"or": [
"disused:amenity=charging_station",
"operational_status=broken"
]
},
"then": "close:#c22;"
},
{
"if": {
"or": [
"proposed:amenity=charging_station",
"planned:amenity=charging_station"
]
},
"then": "./assets/layers/charging_station/under_construction.svg"
},
{
"if": {
"and": [
"bicycle=yes",
{
"or": [
"motorcar=yes",
"car=yes"
]
}
]
},
"then": "circle:#fff;./assets/themes/charging_stations/car.svg"
}
],
"anchor": "bottom",
"iconSize": "50,50"
}
],
"lineRendering": [],
"presets": [
{
"tags": [
"amenity=charging_station",
"motorcar=no",
"bicycle=yes"
],
"title": {
"en": "charging station for electrical bikes",
"nl": "oplaadpunt voor elektrische fietsen",
"de": "Ladestation für Elektrofahrräder"
}
},
{
"tags": [
"amenity=charging_station",
"motorcar=yes",
"bicycle=no"
],
"title": {
"en": "charging station for cars",
"nl": "oplaadstation voor elektrische auto's",
"de": "Ladestation für Elektrofahrräder"
}
}
],
"tagRenderings": [
"images",
{
@ -79,7 +175,8 @@
"question": {
"en": "Which vehicles are allowed to charge here?",
"nl": "Welke voertuigen kunnen hier opgeladen worden?",
"de": "Welche Fahrzeuge können hier laden?"
"de": "Welche Fahrzeuge können hier laden?",
"ca": "Quins vehicles tenen permesa la càrrega aquí?"
},
"multiAnswer": true,
"mappings": [
@ -89,7 +186,8 @@
"then": {
"en": "<b>Bicycles</b> can be charged here",
"nl": "<b>Elektrische fietsen</b> kunnen hier opgeladen worden",
"de": "Hier können <b>Fahrräder</b> laden"
"de": "Hier können <b>Fahrräder</b> laden",
"ca": "Aquí es poden carregar <b>bicicletes</b>"
}
},
{
@ -98,7 +196,8 @@
"then": {
"en": "<b>Cars</b> can be charged here",
"nl": "<b>Elektrische auto's</b> kunnen hier opgeladen worden",
"de": "Hier können <b>Autos</b> laden"
"de": "Hier können <b>Autos</b> laden",
"ca": "Aquí es poden carregar <b>cotxes</b>"
}
},
{
@ -107,7 +206,8 @@
"then": {
"en": "<b>Scooters</b> can be charged here",
"nl": "<b>Elektrische scooters</b> (snorfiets of bromfiets) kunnen hier opgeladen worden",
"de": "Hier können <b>Roller</b> laden"
"de": "Hier können <b>Roller</b> laden",
"ca": "Aquí es poden carregar <b>Scooters</b>"
}
},
{
@ -116,7 +216,8 @@
"then": {
"en": "<b>Heavy good vehicles</b> (such as trucks) can be charged here",
"nl": "<b>Vrachtwagens</b> kunnen hier opgeladen worden",
"de": "Hier können <b>LKW</b> laden"
"de": "Hier können <b>LKW</b> laden",
"ca": "Aquí es poden carregar <b>camions o trailers</b>"
}
},
{
@ -125,7 +226,8 @@
"then": {
"en": "<b>Buses</b> can be charged here",
"nl": "<b>Bussen</b> kunnen hier opgeladen worden",
"de": "Hier können <b>Busse</b> laden"
"de": "Hier können <b>Busse</b> laden",
"ca": "Aquí es poden carregar <b>autobusos</b>"
}
}
]
@ -135,12 +237,14 @@
"question": {
"en": "Who is allowed to use this charging station?",
"nl": "Wie mag er dit oplaadpunt gebruiken?",
"de": "Wer darf diese Ladestation benutzen?"
"de": "Wer darf diese Ladestation benutzen?",
"ca": "Qui pot utilitzar aquesta estació de càrrega?"
},
"render": {
"en": "Access is {access}",
"nl": "Toegang voor {access}",
"de": "Zugang ist {access}"
"de": "Zugang ist {access}",
"ca": "L'accés està {access}"
},
"freeform": {
"key": "access",
@ -154,7 +258,8 @@
"then": {
"en": "Anyone can use this charging station (payment might be needed)",
"nl": "Toegankelijk voor iedereen (mogelijks met aanmelden en/of te betalen)",
"de": "Jeder kann die Station nutzen (eventuell gegen Bezahlung)"
"de": "Jeder kann die Station nutzen (eventuell gegen Bezahlung)",
"ca": "Qualsevol persona pot utilitzar aquesta estació de recàrrega (pot ser calgui un pagament)"
}
},
{
@ -162,7 +267,8 @@
"then": {
"en": "Anyone can use this charging station (payment might be needed)",
"nl": "Toegankelijk voor iedereen (mogelijks met aanmelden en/of te betalen)",
"de": "Jeder kann diese Ladestation nutzen (eventuell gegen Bezahlung)"
"de": "Jeder kann diese Ladestation nutzen (eventuell gegen Bezahlung)",
"ca": "Qualsevol persona pot utilitzar aquesta estació de recàrrega (pot ser calgui un pagament)"
},
"hideInAnswer": true
},
@ -171,7 +277,8 @@
"then": {
"en": "Only customers of the place this station belongs to can use this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests</span>",
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>",
"de": "Nur Kunden des Ortes, zu dem diese Station gehört, können diese Ladestation nutzen<br/><span class='subtle'>Z.B. eine von einem Hotel betriebene Ladestation, die nur von dessen Gästen genutzt werden kann</span>"
"de": "Nur Kunden des Ortes, zu dem diese Station gehört, können diese Ladestation nutzen<br/><span class='subtle'>Z.B. eine von einem Hotel betriebene Ladestation, die nur von dessen Gästen genutzt werden kann</span>",
"ca": "Sols clientes del lloc al que pertany aquest punt de càrrega poden utilitzar-lo <br/><span class='subtle'>p.e. un punt de càrrega d'un hotel que sols poden utilizar-los els hostes</span>"
}
},
{
@ -179,7 +286,8 @@
"then": {
"en": "A <b>key</b> must be requested to access this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station</span>",
"nl": "Een <b>sleutel</b> is nodig om dit oplaadpunt te gebruiken<br/><span class='subtle'>Bv. voor klanten van een hotel of een bar, die de sleutel aan de receptie kunnen krijgen</span>",
"de": "Für den Zugang zur Station muss ein <b>Schlüssel</b> angefordert werden<br/><span class='subtle'>z.B. eine von einem Hotel betriebene Ladestation, die nur von dessen Gästen genutzt werden kann, die an der Rezeption einen Schlüssel erhalten, um die Ladestation aufzuschließen</span>"
"de": "Für den Zugang zur Station muss ein <b>Schlüssel</b> angefordert werden<br/><span class='subtle'>z.B. eine von einem Hotel betriebene Ladestation, die nur von dessen Gästen genutzt werden kann, die an der Rezeption einen Schlüssel erhalten, um die Ladestation aufzuschließen</span>",
"ca": "S'ha de sol·licitar una <b>clau</b> per a utilitzar aquest punt de càrrega<br/><span class='subtle'>p.e un punt de càrrega operat per un hotel nomes utilitzable pel seus hostes, els quals reben una clau des de recepció per a desbloquejar el punt de càrrega</span>"
}
},
{
@ -187,7 +295,8 @@
"then": {
"en": "Not accessible to the general public (e.g. only accessible to the owners, employees, ...)",
"nl": "Niet toegankelijk voor het publiek <br/><span class='subtle'>Bv. enkel toegankelijk voor de eigenaar, medewerkers ,...</span> ",
"de": "Die Station ist nicht für die Allgemeinheit zugänglich (z. B. nur für die Eigentümer, Mitarbeiter, …)"
"de": "Die Station ist nicht für die Allgemeinheit zugänglich (z. B. nur für die Eigentümer, Mitarbeiter, …)",
"ca": "No accessible per al públic general (p.e. només accessible pels propietaris, empleats, ...)"
}
},
{
@ -195,7 +304,8 @@
"then": {
"en": "This charging station is accessible to the public during certain hours or conditions. Restrictions might apply, but general use is allowed.",
"nl": "Dit oplaadstation is publiek toegankelijk onder voorwaarden (bv. enkel tijdens bepaalde uren). ",
"de": "Diese Ladestation ist zu gewissen Öffnungszeiten oder Bedingungen öffentlich zugänglich. Einschränkungen sind möglich, aber generelle Nutzung ist erlaubt."
"de": "Diese Ladestation ist zu gewissen Öffnungszeiten oder Bedingungen öffentlich zugänglich. Einschränkungen sind möglich, aber generelle Nutzung ist erlaubt.",
"ca": "Aquesta estació de càrrega és accessible al públic durant certes hores o condicions. Es poden aplicar restriccions, però es permet l'ús general."
}
}
]
@ -205,12 +315,14 @@
"render": {
"en": "{capacity} vehicles can be charged here at the same time",
"nl": "{capacity} voertuigen kunnen hier op hetzelfde moment opgeladen worden",
"de": "Hier können {capacity} Fahrzeuge gleichzeitig laden"
"de": "Hier können {capacity} Fahrzeuge gleichzeitig laden",
"ca": "Aquí poden carregar {capacity} vehicles a l'hora"
},
"question": {
"en": "How much vehicles can be charged here at the same time?",
"nl": "Hoeveel voertuigen kunnen hier opgeladen worden?",
"de": "Wie viele Fahrzeuge können hier gleichzeitig laden?"
"de": "Wie viele Fahrzeuge können hier gleichzeitig laden?",
"ca": "Quants vehicles poden carregar a la vegada?"
},
"freeform": {
"key": "capacity",
@ -232,7 +344,8 @@
"then": {
"en": "<b>Schuko wall plug</b> without ground pin (CEE7/4 type F)",
"nl": "<b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)",
"de": "<b>Schuko-Stecker</b> ohne Erdungsstift (CEE7/4 Typ F)"
"de": "<b>Schuko-Stecker</b> ohne Erdungsstift (CEE7/4 Typ F)",
"ca": "<b>Endoll de paret Schuko</b> sense pin a terra (CEE7/4 tipus F)"
},
"icon": {
"path": "./assets/layers/charging_station/CEE7_4F.svg",
@ -326,7 +439,8 @@
"then": {
"en": "<b>Schuko wall plug</b> without ground pin (CEE7/4 type F)",
"nl": "<b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)",
"de": "<b>Schuko-Stecker</b> ohne Erdungsstift (CEE7/4 Typ F)"
"de": "<b>Schuko-Stecker</b> ohne Erdungsstift (CEE7/4 Typ F)",
"ca": "<b>Endoll de paret Schuko</b> sense pin a terra (CEE7/4 tipus F)"
},
"hideInAnswer": true,
"icon": {
@ -340,7 +454,8 @@
"then": {
"en": "<b>European wall plug</b> with ground pin (CEE7/4 type E)",
"nl": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)",
"de": "<b>Europäischer Netzstecker</b> mit Erdungsstift (CEE7/4 Typ E)"
"de": "<b>Europäischer Netzstecker</b> mit Erdungsstift (CEE7/4 Typ E)",
"ca": "<b>Endoll de paret Europeu</b> amb pin a terra (CEE7/4 tipus E)"
},
"icon": {
"path": "./assets/layers/charging_station/TypeE.svg",
@ -403,7 +518,8 @@
"then": {
"en": "<b>European wall plug</b> with ground pin (CEE7/4 type E)",
"nl": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)",
"de": "<b>Europäischer Netzstecker</b> mit Erdungsstift (CEE7/4 Typ E)"
"de": "<b>Europäischer Netzstecker</b> mit Erdungsstift (CEE7/4 Typ E)",
"ca": "<b>Endoll de paret Europeu</b> amb pin a terra (CEE7/4 tipus E)"
},
"hideInAnswer": true,
"icon": {
@ -417,7 +533,8 @@
"then": {
"en": "<b>Chademo</b>",
"nl": "<b>Chademo</b>",
"de": "<b>Chademo-Anschluss</b>"
"de": "<b>Chademo-Anschluss</b>",
"ca": "<b>CHAdeMo</b>"
},
"icon": {
"path": "./assets/layers/charging_station/Chademo_type4.svg",
@ -460,7 +577,8 @@
"then": {
"en": "<b>Chademo</b>",
"nl": "<b>Chademo</b>",
"de": "<b>Chademo-Anschluss</b>"
"de": "<b>Chademo-Anschluss</b>",
"ca": "<b>CHAdeMo</b>"
},
"hideInAnswer": true,
"icon": {
@ -474,7 +592,8 @@
"then": {
"en": "<b>Type 1 with cable</b> (J1772)",
"nl": "<b>Type 1 met kabel</b> (J1772)",
"de": "<b>Typ 1 mit Kabel</b> (J1772)"
"de": "<b>Typ 1 mit Kabel</b> (J1772)",
"ca": "<b>Tipus 1 amb cable</b>"
},
"icon": {
"path": "./assets/layers/charging_station/Type1_J1772.svg",
@ -517,7 +636,8 @@
"then": {
"en": "<b>Type 1 with cable</b> (J1772)",
"nl": "<b>Type 1 met kabel</b> (J1772)",
"de": "<b>Typ 1 mit Kabel</b> (J1772)"
"de": "<b>Typ 1 mit Kabel</b> (J1772)",
"ca": "<b>Tipus 1 amb cable</b>"
},
"hideInAnswer": true,
"icon": {
@ -531,7 +651,8 @@
"then": {
"en": "<b>Type 1 <i>without</i> cable</b> (J1772)",
"nl": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)",
"de": "<b>Typ 1 <i>ohne</i> Kabel</b> (J1772)"
"de": "<b>Typ 1 <i>ohne</i> Kabel</b> (J1772)",
"ca": "<b>Tipus 1 <i>sense</i> cable</b>"
},
"icon": {
"path": "./assets/layers/charging_station/Type1_J1772.svg",
@ -574,7 +695,8 @@
"then": {
"en": "<b>Type 1 <i>without</i> cable</b> (J1772)",
"nl": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)",
"de": "<b> Typ 1 <i>ohne </i> Kabel</b> (J1772)"
"de": "<b> Typ 1 <i>ohne </i> Kabel</b> (J1772)",
"ca": "<b>Tipus 1 <i>sense</i> cable</b>(J1772)"
},
"hideInAnswer": true,
"icon": {
@ -588,7 +710,8 @@
"then": {
"en": "<b>Type 1 CCS</b> (aka Type 1 Combo)",
"nl": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)",
"de": "<b>Typ 1 CCS</b> (Typ 1 Combo)"
"de": "<b>Typ 1 CCS</b> (Typ 1 Combo)",
"ca": "<b>CSS Tipus 1</b> (també conegut com a Tipus 1 Combo)"
},
"icon": {
"path": "./assets/layers/charging_station/Type1-ccs.svg",
@ -631,7 +754,8 @@
"then": {
"en": "<b>Type 1 CCS</b> (aka Type 1 Combo)",
"nl": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)",
"de": "<b> Typ 1 CCS </b> (auch bekannt als Typ 1 Combo)"
"de": "<b> Typ 1 CCS </b> (auch bekannt als Typ 1 Combo)",
"ca": "<b>CSS Tipus 1</b> (també conegut com a Tipus 1 Combo)"
},
"hideInAnswer": true,
"icon": {
@ -645,7 +769,8 @@
"then": {
"en": "<b>Tesla Supercharger</b>",
"nl": "<b>Tesla Supercharger</b>",
"de": "<b>Tesla Supercharger</b>"
"de": "<b>Tesla Supercharger</b>",
"ca": "<b>Supercarregador de Tesla"
},
"icon": {
"path": "./assets/layers/charging_station/Tesla-hpwc-model-s.svg",
@ -688,7 +813,8 @@
"then": {
"en": "<b>Tesla Supercharger</b>",
"nl": "<b>Tesla Supercharger</b>",
"de": "<b>Tesla Supercharger</b>"
"de": "<b>Tesla Supercharger</b>",
"ca": "<b>Supercarregador de Tesla</b>"
},
"hideInAnswer": true,
"icon": {
@ -702,7 +828,8 @@
"then": {
"en": "<b>Type 2</b> (mennekes)",
"nl": "<b>Type 2</b> (mennekes)",
"de": "<b>Typ 2</b> (Mennekes)"
"de": "<b>Typ 2</b> (Mennekes)",
"ca": "<b>Tipus 2</b> (mennekes)"
},
"icon": {
"path": "./assets/layers/charging_station/Type2_socket.svg",
@ -745,7 +872,8 @@
"then": {
"en": "<b>Type 2</b> (mennekes)",
"nl": "<b>Type 2</b> (mennekes)",
"de": "<b>Typ 2</b> (Mennekes)"
"de": "<b>Typ 2</b> (Mennekes)",
"ca": "<b>Tipus 2</b> (mennekes)"
},
"hideInAnswer": true,
"icon": {
@ -759,7 +887,8 @@
"then": {
"en": "<b>Type 2 CCS</b> (mennekes)",
"nl": "<b>Type 2 CCS</b> (mennekes)",
"de": "<b>Typ 2 CCS</b> (Mennekes)"
"de": "<b>Typ 2 CCS</b> (Mennekes)",
"ca": "<b>CSS Tipus 2</b> (mennekes)"
},
"icon": {
"path": "./assets/layers/charging_station/Type2_CCS.svg",
@ -802,7 +931,8 @@
"then": {
"en": "<b>Type 2 CCS</b> (mennekes)",
"nl": "<b>Type 2 CCS</b> (mennekes)",
"de": "<b>Typ 2 CCS</b> (mennekes)"
"de": "<b>Typ 2 CCS</b> (mennekes)",
"ca": "<b>CSS Tipus 2</b> (mennekes)"
},
"hideInAnswer": true,
"icon": {
@ -1656,7 +1786,8 @@
"question": {
"en": "When is this charging station opened?",
"nl": "Wanneer is dit oplaadpunt beschikbaar??",
"de": "Wann ist die Ladestation geöffnet?"
"de": "Wann ist die Ladestation geöffnet?",
"ca": "Quan està oberta aquesta estació de càrrega?"
}
},
"id": "OH"
@ -1666,7 +1797,8 @@
"question": {
"en": "Does one have to pay to use this charging station?",
"nl": "Moet men betalen om dit oplaadpunt te gebruiken?",
"de": "Muss man für die Nutzung dieser Ladestation bezahlen?"
"de": "Muss man für die Nutzung dieser Ladestation bezahlen?",
"ca": "Hi ha que pagar per utilitzar aquest punt de càrrega?"
},
"mappings": [
{
@ -1681,7 +1813,8 @@
"then": {
"nl": "Gratis te gebruiken (zonder aan te melden)",
"en": "Free to use (without authenticating)",
"de": "Die Nutzung ist kostenlos, keine Authentifizierung erforderlich"
"de": "Die Nutzung ist kostenlos, keine Authentifizierung erforderlich",
"ca": "Ús gratuït (sense autentificació)"
}
},
{
@ -1696,7 +1829,8 @@
"then": {
"nl": "Gratis te gebruiken, maar aanmelden met een applicatie is verplicht",
"en": "Free to use, but one has to authenticate",
"de": "Die Nutzung ist kostenlos, Authentifizierung erforderlich"
"de": "Die Nutzung ist kostenlos, Authentifizierung erforderlich",
"ca": "Ús gratuït, però un s'ha d'autentificar"
}
},
{
@ -1708,7 +1842,8 @@
"then": {
"nl": "Gratis te gebruiken",
"en": "Free to use",
"de": "Kostenlose Nutzung"
"de": "Kostenlose Nutzung",
"ca": "Ús gratuït"
},
"hideInAnswer": true
},
@ -1722,7 +1857,8 @@
"then": {
"nl": "Betalend te gebruiken, maar gratis voor klanten van het bijhorende hotel/café/ziekenhuis/...",
"en": "Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station",
"de": "Die Nutzung ist kostenpflichtig, aber für Kunden des Betreibers der Einrichtung, wie Hotel, Krankenhaus, … kostenlos"
"de": "Die Nutzung ist kostenpflichtig, aber für Kunden des Betreibers der Einrichtung, wie Hotel, Krankenhaus, … kostenlos",
"ca": "De pagament, però gratuït per als clients de l'hotel/bar/hospital/... que gestiona l'estació de càrrega"
}
},
{
@ -1735,7 +1871,8 @@
"then": {
"nl": "Betalend",
"en": "Paid use",
"de": "Die Nutzung ist kostenpflichtig"
"de": "Die Nutzung ist kostenpflichtig",
"ca": "Ús de pagament"
}
}
]
@ -1745,12 +1882,14 @@
"question": {
"en": "How much does one have to pay to use this charging station?",
"nl": "Hoeveel moet men betalen om dit oplaadpunt te gebruiken?",
"de": "Wie viel muss man für die Nutzung dieser Ladestation bezahlen?"
"de": "Wie viel muss man für die Nutzung dieser Ladestation bezahlen?",
"ca": "Quant cal pagar per utilitzar aquesta estació de càrrega?"
},
"render": {
"en": "Using this charging station costs <b>{charge}</b>",
"nl": "Dit oplaadpunt gebruiken kost <b>{charge}</b>",
"de": "Die Nutzung dieser Ladestation kostet <b>{charge}</b>"
"de": "Die Nutzung dieser Ladestation kostet <b>{charge}</b>",
"ca": "Utilitzar aquesta estació de càrrega costa <b>{charge}</b>"
},
"freeform": {
"key": "charge"
@ -1775,7 +1914,8 @@
"question": {
"en": "What kind of authentication is available at the charging station?",
"nl": "Hoe kan men zich aanmelden aan dit oplaadstation?",
"de": "Welche Art der Authentifizierung ist an der Ladestation möglich?"
"de": "Welche Art der Authentifizierung ist an der Ladestation möglich?",
"ca": "Quin tipus d'autenticació hi ha disponible a l'estació de càrrega?"
},
"multiAnswer": true,
"mappings": [
@ -1821,7 +1961,8 @@
"then": {
"en": "Authentication via NFC is available",
"nl": "Aanmelden via NFC is mogelijk",
"de": "Authentifizierung per NFC ist möglich"
"de": "Authentifizierung per NFC ist möglich",
"ca": "L'autenticació mitjançant NFC està disponible"
}
},
{
@ -1830,7 +1971,8 @@
"then": {
"en": "Authentication via Money Card is available",
"nl": "Aanmelden met Money Card is mogelijk",
"de": "Authentifizierung per Geldkarte ist möglich"
"de": "Authentifizierung per Geldkarte ist möglich",
"ca": "L'autenticació mitjançant targeta de pagament està disponible"
}
},
{
@ -1839,7 +1981,8 @@
"then": {
"en": "Authentication via debit card is available",
"nl": "Aanmelden met een betaalkaart is mogelijk",
"de": "Authentifizierung per Kreditkarte ist möglich"
"de": "Authentifizierung per Kreditkarte ist möglich",
"ca": "L'autenticació mitjançant targeta de debit està disponible"
}
},
{
@ -1848,7 +1991,8 @@
"then": {
"en": "Charging here is (also) possible without authentication",
"nl": "Hier opladen is (ook) mogelijk zonder aan te melden",
"de": "Das Laden ist hier (auch) ohne Authentifizierung möglich"
"de": "Das Laden ist hier (auch) ohne Authentifizierung möglich",
"ca": "Carregar aquí (també) és possible sense autenticació"
}
}
],
@ -1887,7 +2031,8 @@
"question": {
"en": "What is the maximum amount of time one is allowed to stay here?",
"nl": "Hoelang mag een voertuig hier blijven staan?",
"de": "Wie lange darf man hier maximal parken?"
"de": "Wie lange darf man hier maximal parken?",
"ca": "Quina és la quantitat màxima de temps que es permet permaneixer aquí?"
},
"freeform": {
"key": "maxstay"
@ -1895,7 +2040,8 @@
"render": {
"en": "One can stay at most <b>{canonical(maxstay)}</b>",
"nl": "De maximale parkeertijd hier is <b>{canonical(maxstay)}</b>",
"de": "Die maximale Parkdauer beträgt <b>{canonical(maxstay)}</b>"
"de": "Die maximale Parkdauer beträgt <b>{canonical(maxstay)}</b>",
"ca": "Un pot quedar-se com a màxim <b>{canonical(maxstay)}</b>"
},
"mappings": [
{
@ -1903,7 +2049,8 @@
"then": {
"en": "No timelimit on leaving your vehicle here",
"nl": "Geen maximum parkeertijd",
"de": "Keine Höchstparkdauer"
"de": "Keine Höchstparkdauer",
"ca": "No hi ha límit de temps per a deixar el teu vehicle aquí"
}
}
],
@ -1921,12 +2068,14 @@
"render": {
"en": "Part of the network <b>{network}</b>",
"nl": "Maakt deel uit van het <b>{network}</b>-netwerk",
"de": "Teil des Netzwerks <b>{network}</b>"
"de": "Teil des Netzwerks <b>{network}</b>",
"ca": "Part de la xarxa <b>{network}</b>"
},
"question": {
"en": "Is this charging station part of a network?",
"nl": "Is dit oplaadpunt deel van een groter netwerk?",
"de": "Ist diese Ladestation Teil eines Netzwerks?"
"de": "Ist diese Ladestation Teil eines Netzwerks?",
"ca": "Aquesta estació de càrrega forma part d'una xarxa?"
},
"freeform": {
"key": "network"
@ -1992,12 +2141,14 @@
"question": {
"en": "Who is the operator of this charging station?",
"nl": "Wie beheert dit oplaadpunt?",
"de": "Wer ist der Betreiber dieser Ladestation?"
"de": "Wer ist der Betreiber dieser Ladestation?",
"ca": "Qui és l'operadora d'aquesta estació de càrrega?"
},
"render": {
"en": "This charging station is operated by {operator}",
"nl": "Wordt beheerd door {operator}",
"de": "Die Station wird betrieben von {operator}"
"de": "Die Station wird betrieben von {operator}",
"ca": "Aquesta estació de càrrega l'opera {operator}"
},
"freeform": {
"key": "operator"
@ -2012,7 +2163,8 @@
"then": {
"en": "Actually, {operator} is the network",
"nl": "Eigenlijk is {operator} het netwerk waarvan het deel uitmaakt",
"de": "Eigentlich ist {operator} das Netzwerk"
"de": "Eigentlich ist {operator} das Netzwerk",
"ca": "De fet, {operator} és la xarxa"
},
"addExtraTags": [
"operator="
@ -2027,12 +2179,14 @@
"question": {
"en": "What number can one call if there is a problem with this charging station?",
"nl": "Wat is het telefoonnummer van de beheerder van dit oplaadpunt?",
"de": "Welche Nummer kann man anrufen, wenn es ein Problem mit dieser Ladestation gibt?"
"de": "Welche Nummer kann man anrufen, wenn es ein Problem mit dieser Ladestation gibt?",
"ca": "A quin número es pot cridar si hi ha algun problema amb aquest punt de càrrega?"
},
"render": {
"en": "In case of problems, call <a href='tel:{phone}'>{phone}</a>",
"nl": "Bij problemen, bel naar <a href='tel:{phone}'>{phone}</a>",
"de": "Bei Problemen, anrufen unter <a href='tel:{phone}'>{phone}</a>"
"de": "Bei Problemen, anrufen unter <a href='tel:{phone}'>{phone}</a>",
"ca": "En cas de problemes, truqueu a <a href='tel:{phone}'>{phone}</a>"
},
"freeform": {
"key": "phone",
@ -2044,12 +2198,14 @@
"question": {
"en": "What is the email address of the operator?",
"nl": "Wat is het email-adres van de operator?",
"de": "Wie lautet die E-Mail-Adresse des Betreibers?"
"de": "Wie lautet die E-Mail-Adresse des Betreibers?",
"ca": "Quin és el correu electrònic de l'operadora?"
},
"render": {
"en": "In case of problems, send an email to <a href='mailto:{email}'>{email}</a>",
"nl": "Bij problemen, email naar <a href='mailto:{email}'>{email}</a>",
"de": "Bei Problemen senden Sie bitte eine E-Mail an <a href='mailto:{email}'>{email}</a>"
"de": "Bei Problemen senden Sie bitte eine E-Mail an <a href='mailto:{email}'>{email}</a>",
"ca": "En cas de problemes, envia un email a <a href='mailto:{email}'>{email}</a>"
},
"freeform": {
"key": "email",
@ -2097,7 +2253,8 @@
"question": {
"en": "Is this charging point in use?",
"nl": "Is dit oplaadpunt operationeel?",
"de": "Ist die Station in Betrieb?"
"de": "Ist die Station in Betrieb?",
"ca": "Està en ús aquest punt de càrrega?"
},
"mappings": [
{
@ -2113,7 +2270,8 @@
"then": {
"en": "This charging station works",
"nl": "Dit oplaadpunt werkt",
"de": "Die Station ist in Betrieb"
"de": "Die Station ist in Betrieb",
"ca": "Aquesta estació de càrrega funciona"
}
},
{
@ -2129,7 +2287,8 @@
"then": {
"en": "This charging station is broken",
"nl": "Dit oplaadpunt is kapot",
"de": "Die Station ist defekt"
"de": "Die Station ist defekt",
"ca": "Aquesta estació de carrega està trencada"
}
},
{
@ -2145,7 +2304,8 @@
"then": {
"en": "A charging station is planned here",
"nl": "Hier zal binnenkort een oplaadpunt gebouwd worden",
"de": "Die Station ist erst in Planung"
"de": "Die Station ist erst in Planung",
"ca": "Aquí està prevista una estació de recàrrega"
}
},
{
@ -2177,7 +2337,8 @@
"then": {
"en": "This charging station has beed permanently disabled and is not in use anymore but is still visible",
"nl": "Dit oplaadpunt is niet meer in gebruik maar is wel nog aanwezig",
"de": "Die Station ist dauerhaft geschlossen und nicht mehr in Nutzung, aber noch sichtbar"
"de": "Die Station ist dauerhaft geschlossen und nicht mehr in Nutzung, aber noch sichtbar",
"ca": "Aquesta estació de recàrrega s'ha desactivat permanentment i ja no s'utilitza, però encara és visible"
}
}
]
@ -2187,7 +2348,8 @@
"question": {
"en": "Does one have to pay a parking fee while charging?",
"nl": "Moet men parkeergeld betalen tijdens het opladen?",
"de": "Muss man während des Ladens eine Parkgebühr bezahlen?"
"de": "Muss man während des Ladens eine Parkgebühr bezahlen?",
"ca": "Cal pagar una taxa d'aparcament mentre es carrega?"
},
"mappings": [
{
@ -2195,7 +2357,8 @@
"then": {
"en": "No additional parking cost while charging",
"nl": "Geen extra parkeerkost tijdens het opladen",
"de": "Keine zusätzlichen Parkkosten während des Ladens"
"de": "Keine zusätzlichen Parkkosten während des Ladens",
"ca": "No cal pagar una taxa addicional mentres carrega"
}
},
{
@ -2203,7 +2366,8 @@
"then": {
"en": "An additional parking fee should be paid while charging",
"nl": "Tijdens het opladen moet er parkeergeld betaald worden",
"de": "Während des Ladens ist eine zusätzliche Parkgebühr zu entrichten"
"de": "Während des Ladens ist eine zusätzliche Parkgebühr zu entrichten",
"ca": "Cal pagar una taxa addicional d'aparcament mentres carrega"
}
}
],
@ -2227,103 +2391,6 @@
}
}
],
"lineRendering": [],
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "pin",
"color": "#fff"
},
{
"icon": {
"render": "./assets/themes/charging_stations/plug.svg",
"mappings": [
{
"if": "bicycle=yes",
"then": "./assets/themes/charging_stations/bicycle.svg"
},
{
"if": {
"or": [
"car=yes",
"motorcar=yes"
]
},
"then": "./assets/themes/charging_stations/car.svg"
}
]
}
}
],
"iconBadges": [
{
"if": {
"or": [
"disused:amenity=charging_station",
"operational_status=broken"
]
},
"then": "close:#c22;"
},
{
"if": {
"or": [
"proposed:amenity=charging_station",
"planned:amenity=charging_station"
]
},
"then": "./assets/layers/charging_station/under_construction.svg"
},
{
"if": {
"and": [
"bicycle=yes",
{
"or": [
"motorcar=yes",
"car=yes"
]
}
]
},
"then": "circle:#fff;./assets/themes/charging_stations/car.svg"
}
],
"anchor": "bottom",
"iconSize": "50,50"
}
],
"presets": [
{
"tags": [
"amenity=charging_station",
"motorcar=no",
"bicycle=yes"
],
"title": {
"en": "charging station for electrical bikes",
"nl": "oplaadpunt voor elektrische fietsen",
"de": "Ladestation für Elektrofahrräder"
}
},
{
"tags": [
"amenity=charging_station",
"motorcar=yes",
"bicycle=no"
],
"title": {
"en": "charging station for cars",
"nl": "oplaadstation voor elektrische auto's",
"de": "Ladestation für Elektrofahrräder"
}
}
],
"filter": [
{
"id": "vehicle-type",
@ -2517,6 +2584,20 @@
]
}
],
"deletion": {
"softDeletionTags": {
"and": [
"amenity=",
"disused:amenity=charging_station"
]
},
"neededChangesets": 10
},
"allowMove": {
"enableRelocation": false,
"enableImproveAccuracy": true
},
"#": "no-question-hint-check",
"units": [
{
"maxstay": {
@ -2665,18 +2746,5 @@
]
}
}
],
"allowMove": {
"enableRelocation": false,
"enableImproveAccuracy": true
},
"deletion": {
"softDeletionTags": {
"and": [
"amenity=",
"disused:amenity=charging_station"
]
},
"neededChangesets": 10
}
}
]
}

View file

@ -0,0 +1,70 @@
{
"id": "cinema",
"name": {
"en": "Cinema"
},
"description": {
"en": " A place showing movies (films), generally open to the public for a fee. Commonly referred to as a movie theater in the US"
},
"source": {
"osmTags": "amenity=cinema"
},
"minzoom": 10,
"title": {
"mappings": [
{
"if": "name~*",
"then": {
"*": "{name}"
}
}
],
"render": {
"en": "Cinema"
}
},
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "./assets/layers/cinema/cinema.svg"
}
],
"iconBadges": []
}
],
"tagRenderings": [
"images",
"reviews",
"contact",
"wikipedia",
{
"id": "cinema_type",
"question": {
"en": "What type of cinema is this?"
},
"mappings": [
{
"if": "cinema=",
"then": {
"en": "This is a normal cinema showing movies for all ages"
}
},
{
"if": "cinema=erotic",
"then": {
"en": "This is an erotic cinema showing adult movies"
}
}
]
}
]
}

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="16"
height="16"
viewBox="0 0 16 16"
id="svg2">
<metadata id="metadata8">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs id="defs6"/>
<rect width="16" height="16" x="0" y="0" id="canvas" style="fill:none;stroke:none;visibility:hidden"/>
<path d="M 1,1 C 0.446,1 0,1.446 0,2 l 0,11 c 0,0.554 0.446,1 1,1 l 12,0 c 0.554,0 1,-0.446 1,-1 L 14,2 C 14,1.446 13.554,1 13,1 L 1,1 z m 0.25,1 0.5,0 C 1.8885,2 2,2.1115 2,2.25 l 0,0.5 C 2,2.8885 1.8885,3 1.75,3 L 1.25,3 C 1.1115,3 1,2.8885 1,2.75 L 1,2.25 C 1,2.1115 1.1115,2 1.25,2 z M 4,2 10,2 10,7 4,7 4,2 z m 8.25,0 0.5,0 C 12.8885,2 13,2.1115 13,2.25 l 0,0.5 C 13,2.8885 12.8885,3 12.75,3 l -0.5,0 C 12.1115,3 12,2.8885 12,2.75 l 0,-0.5 C 12,2.1115 12.1115,2 12.25,2 z m -11,2 0.5,0 C 1.8885,4 2,4.1115 2,4.25 l 0,0.5 C 2,4.8885 1.8885,5 1.75,5 L 1.25,5 C 1.1115,5 1,4.8885 1,4.75 L 1,4.25 C 1,4.1115 1.1115,4 1.25,4 z m 11,0 0.5,0 C 12.8885,4 13,4.1115 13,4.25 l 0,0.5 C 13,4.8885 12.8885,5 12.75,5 l -0.5,0 C 12.1115,5 12,4.8885 12,4.75 l 0,-0.5 C 12,4.1115 12.1115,4 12.25,4 z m -11,2 0.5,0 C 1.8885,6 2,6.1115 2,6.25 l 0,0.5 C 2,6.8885 1.8885,7 1.75,7 L 1.25,7 C 1.1115,7 1,6.8885 1,6.75 L 1,6.25 C 1,6.1115 1.1115,6 1.25,6 z m 11,0 0.5,0 C 12.8885,6 13,6.1115 13,6.25 l 0,0.5 C 13,6.8885 12.8885,7 12.75,7 l -0.5,0 C 12.1115,7 12,6.8885 12,6.75 l 0,-0.5 C 12,6.1115 12.1115,6 12.25,6 z m -11,2 0.5,0 C 1.8885,8 2,8.1115 2,8.25 l 0,0.5 C 2,8.8885 1.8885,9 1.75,9 L 1.25,9 C 1.1115,9 1,8.8885 1,8.75 L 1,8.25 C 1,8.1115 1.1115,8 1.25,8 z M 4,8 l 6,0 0,5 -6,0 0,-5 z m 8.25,0 0.5,0 C 12.8885,8 13,8.1115 13,8.25 l 0,0.5 C 13,8.8885 12.8885,9 12.75,9 l -0.5,0 C 12.1115,9 12,8.8885 12,8.75 l 0,-0.5 C 12,8.1115 12.1115,8 12.25,8 z m -11,2 0.5,0 C 1.8885,10 2,10.1115 2,10.25 l 0,0.5 C 2,10.8885 1.8885,11 1.75,11 l -0.5,0 C 1.1115,11 1,10.8885 1,10.75 l 0,-0.5 C 1,10.1115 1.1115,10 1.25,10 z m 11,0 0.5,0 c 0.1385,0 0.25,0.1115 0.25,0.25 l 0,0.5 C 13,10.8885 12.8885,11 12.75,11 l -0.5,0 C 12.1115,11 12,10.8885 12,10.75 l 0,-0.5 C 12,10.1115 12.1115,10 12.25,10 z m -11,2 0.5,0 C 1.8885,12 2,12.1115 2,12.25 l 0,0.5 C 2,12.8885 1.8885,13 1.75,13 l -0.5,0 C 1.1115,13 1,12.8885 1,12.75 l 0,-0.5 C 1,12.1115 1.1115,12 1.25,12 z m 11,0 0.5,0 c 0.1385,0 0.25,0.1115 0.25,0.25 l 0,0.5 C 13,12.8885 12.8885,13 12.75,13 l -0.5,0 C 12.1115,13 12,12.8885 12,12.75 l 0,-0.5 C 12,12.1115 12.1115,12 12.25,12 z" id="cinema" style="fill:#734a08;fill-opacity:1;stroke:none" transform="translate(1,1)"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: OSM Carto
SPDX-License-Identifier: PUBLIC-DOMAIN

View file

@ -0,0 +1,12 @@
[
{
"path": "cinema.svg",
"license": "PUBLIC-DOMAIN",
"authors": [
"OSM Carto"
],
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Cinema-16.svg"
]
}
]

View file

@ -40,12 +40,12 @@
]
}
},
"minzoom": 12,
"calculatedTags": [
"_closest_other_drinking_water=closestn(feat)('drinking_water', 1, undefined, 5000).map(f => ({id: f.feat.id, distance: ''+f.distance}))[0]",
"_closest_other_drinking_water_id=get(feat)('_closest_other_drinking_water')?.id",
"_closest_other_drinking_water_distance=Math.floor(Number(get(feat)('_closest_other_drinking_water')?.distance))"
],
"minzoom": 12,
"title": {
"render": {
"en": "Drinking water",

View file

@ -286,7 +286,7 @@
"es": "Se trata de un negocio de comida rápida, centrado en el servicio rápido. Si hay asientos disponibles, son más bien limitados y funcionales.",
"fr": "C'est un fast-food, centrée sur le service rapide. Si des places sont disponibles, elles sont plutôt limitées et fonctionnelles.",
"hu": "Ez egy gyorsétterem (büfé), amely a gyors kiszolgálásra összpontosít. Ha vannak is ülőhelyek, ezek meglehetősen korlátozottak és funkcionálisak.",
"ca": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seràn limitats i funcionals.",
"ca": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seran limitats i funcionals.",
"cs": "Jedná se o podnik s rychlým občerstvením, zaměřený na rychlou obsluhu. Pokud je k dispozici místo k sezení, je spíše omezené a funkční."
}
},
@ -319,7 +319,7 @@
"de": "Was für Essen gibt es hier?",
"es": "¿Qué tipo de comida sirven aquí?",
"fr": "Quelle type de nourriture est servie ici ?",
"ca": "Quin menjar es serveix aquí?",
"ca": "Quin tipus de menjar es serveix aquí?",
"cs": "Jaké jídlo se zde podává?"
},
"render": {
@ -395,7 +395,7 @@
"nl": "Dit is een broodjeszaak",
"de": "Dies ist ein Sandwichladen",
"fr": "C'est une sandwicherie",
"ca": "Això és un sandvitxeria",
"ca": "Això és una botiga d'entrepans",
"cs": "Toto je obchod se sendviči"
}
},

View file

@ -23,7 +23,22 @@
"cs": "Ujetá cesta"
}
},
"pointRendering": [],
"pointRendering": [
{
"location": [
"start"
],
"marker": [
{
"icon": "circle",
"color": "#bb000077"
}
],
"iconSize": "10,10",
"pitchAlignment": "map",
"rotationAlignment": "map"
}
],
"lineRendering": [
{
"width": 3,

View file

@ -355,7 +355,7 @@
"en": "a metal workshop"
},
{
"en": "meta workshop"
"en": "metal workshop"
},
"./assets/layers/hackerspace/metal.svg",
false

View file

@ -556,5 +556,9 @@
]
}
}
]
],
"allowMove": {
"enableRelocation": false,
"enableImproveAccuracy": true
}
}

View file

@ -73,13 +73,14 @@
"defaults",
"in_favourite"
],
"#": "Titleicon showing 'open until 17:00'",
"#": "Titleicon showing e.g. 'open until 17:00'",
"icon": {
"class": "w-20 mx-1 flex items-center"
},
"render": "{opening_hours_state()}",
"condition": {
"or": [
"opening_hours~*",
"seasonal=",
"seasonal=no",
{

View file

@ -130,7 +130,12 @@
},
"mappings": [
{
"if": "highway=living_street",
"if": {
"and": [
"highway=living_street",
"_country=be"
]
},
"then": {
"en": "This is a living street, which has a maxspeed of 20km/h",
"nl": "Dit is een woonerf en heeft dus een maximale snelheid van 20km/h",

View file

@ -204,7 +204,7 @@
},
"description": {
"en": "You can specify later on what this shop sells.",
"ca": "Afegir una botiga nova",
"ca": "Podeu especificar més endavant el que ven aquesta botiga.",
"cs": "Přidat nový obchod",
"de": "Ein neues Geschäft hinzufügen",
"eo": "Enmeti novan butikon",

View file

@ -298,7 +298,8 @@
"ru": "Здесь можно играть в баскетбол",
"de": "Hier wird Basketball gespielt",
"es": "Aquí se juega al baloncesto",
"cs": "Zde se hraje basketbal"
"cs": "Zde se hraje basketbal",
"ca": "Aquí es juga bàsquet"
},
"hideInAnswer": true
},
@ -320,7 +321,8 @@
"question": {
"en": "How much basketball hoops does this pitch have?",
"de": "Wie viele Basketballkörbe hat das Spielfeld?",
"cs": "Kolik má toto hřiště basketbalových košů?"
"cs": "Kolik má toto hřiště basketbalových košů?",
"ca": "Quants cèrcols té aquesta pista?"
},
"mappings": [
{
@ -336,7 +338,8 @@
"then": {
"en": "This basketball pitch has two hoops",
"de": "Dieses Basketballfeld hat zwei Körbe",
"cs": "Toto basketbalové hřiště má dva koše"
"cs": "Toto basketbalové hřiště má dva koše",
"ca": "Aquest camp de bàsquet té dos cèrcols"
}
},
{
@ -344,7 +347,8 @@
"then": {
"en": "This basketball pitch has four hoops",
"de": "Dieses Basketballfeld hat vier Körbe",
"cs": "Toto basketbalové hřiště má čtyři koše"
"cs": "Toto basketbalové hřiště má čtyři koše",
"ca": "Aquest camp de bàsquet té quatre cèrcols"
}
},
{
@ -352,7 +356,8 @@
"then": {
"en": "This basketball pitch has {hoops} hoops",
"de": "Dieses Basketballfeld hat {hoops} Körbe",
"cs": "Toto basketbalové hřiště má {hoops} koše"
"cs": "Toto basketbalové hřiště má {hoops} koše",
"ca": "Aquest camp de bàsquet té {hoops} cèrcols"
},
"hideInAnswer": true
}
@ -461,14 +466,16 @@
"then": {
"en": "The surface is <b>fine gravel</b>",
"nl": "De ondergrond bestaat uit <b>grind</b>",
"de": "Die Oberfläche ist <b>feiner Kies</b>"
"de": "Die Oberfläche ist <b>feiner Kies</b>",
"ca": "La superfície és <b> grava fina</b>"
}
},
{
"if": "surface=tartan",
"then": {
"en": "The surface of this track is Tartan, a synthetic, slightly springy, porous surface",
"nl": "De ondergrond is Tartan, een synthetisch, licht verende en poreuze ondergrond"
"nl": "De ondergrond is Tartan, een synthetisch, licht verende en poreuze ondergrond",
"ca": "La superfície d'aquesta pista és Tartan, una superfície sintètica, lleugerament molla i porosa"
}
}
],
@ -553,7 +560,8 @@
"ru": "Свободный доступ",
"de": "Der Sportplatz ist öffentlich zugänglich",
"es": "Acceso público",
"cs": "Veřejný přístup"
"cs": "Veřejný přístup",
"ca": "Accés públic"
},
"hideInAnswer": true
}
@ -711,7 +719,8 @@
"it": "Sempre aperto",
"de": "Immer zugänglich",
"es": "Siempre accesible",
"cs": "Vždy přístupné"
"cs": "Vždy přístupné",
"ca": "Sempre accesible"
}
}
],

View file

@ -293,27 +293,31 @@
{
"id": "incline",
"render": {
"en": "These stairs have an incline of {incline}"
"en": "These stairs have an incline of {incline}",
"ca": "Aquestes escales tenen una inclinació de {incline}"
},
"freeform": {
"key": "incline",
"type": "slope"
},
"question": {
"en": "What is the incline of these stairs?"
"en": "What is the incline of these stairs?",
"ca": "Quina és la inclinació d'aquestes escales?"
},
"mappings": [
{
"if": "incline=up",
"then": {
"en": "The upward direction is {direction_absolute()}"
"en": "The upward direction is {direction_absolute()}",
"ca": "La direcció ascendent és {direction_absolute()}"
},
"hideInAnswer": true
},
{
"if": "incline=down",
"then": {
"en": "The downward direction is {direction_absolute()}"
"en": "The downward direction is {direction_absolute()}",
"ca": "La direcció descendent és {direction_absolute()}"
},
"hideInAnswer": true
}

View file

@ -0,0 +1,12 @@
[
{
"path": "stripclub.svg",
"license": "PUBLIC-DOMAIN",
"authors": [
"Unkown"
],
"sources": [
"https://publicdomainpictures.net/en/view-image.php?image=120141&picture="
]
}
]

View file

@ -0,0 +1,86 @@
{
"id": "stripclub",
"name": {
"en": "Stripclubs"
},
"description": {
"en": "A venue where erotic dance, striptease, or lap dances are performed commercially. "
},
"source": {
"osmTags": "amenity=stripclub",
"isOsmCache": false
},
"minzoom": 6,
"title": {
"render": {
"en": "Stripclub"
},
"mappings": [
{
"if": "name~*",
"then": {
"*": "{name}"
}
}
]
},
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "ring",
"color": "#be57b4ff"
}
]
},
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "./assets/layers/stripclub/stripclub.svg"
}
]
}
],
"presets": [
{
"title": {
"en": "a stripclub"
},
"tags": [
"amenity=stripclub"
]
}
],
"tagRenderings": [
"images",
"reviews",
{
"multiAnswer": false,
"id": "name",
"freeform": {
"inline": false,
"key": "name"
},
"question": {
"en": "What is the name of this stripclub?"
},
"render": {
"en": "This stripclub is named <b>{name}</b>"
}
},
"opening_hours",
"contact"
]
}

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="7.1035852mm"
height="15.871516mm"
viewBox="0 0 7.1035852 15.871516"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="stripclub.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="4.8257159"
inkscape:cx="1.9686198"
inkscape:cy="44.242141"
inkscape:window-width="1920"
inkscape:window-height="995"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs1" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-87.169665,-130.08849)"><path
style="fill:#be57b4;fill-opacity:1"
d="m 91.611366,145.92861 c -0.02978,-0.0298 -0.05414,-1.19487 -0.05414,-2.58909 0,-2.38093 -0.009,-2.53125 -0.148166,-2.4742 -0.08149,0.0334 -0.310092,0.0805 -0.508,0.10474 -0.440991,0.0539 -0.488646,-0.10219 -0.08295,-0.2717 0.152287,-0.0636 0.347879,-0.19414 0.434649,-0.29001 0.08677,-0.0959 0.188594,-0.15528 0.226275,-0.13199 0.03768,0.0233 -0.03049,-0.13479 -0.151496,-0.35129 -0.121005,-0.21651 -0.344304,-0.46698 -0.49622,-0.55661 -0.569157,-0.33581 -0.670164,-0.77749 -0.374398,-1.63715 0.153155,-0.44516 0.157305,-0.51214 0.04258,-0.68724 -0.07457,-0.1138 -0.299474,-0.24519 -0.544044,-0.31782 -0.229309,-0.0681 -0.490712,-0.1633 -0.580895,-0.21157 -0.248744,-0.13312 -0.40017,0.24053 -0.257439,0.63525 0.08944,0.24735 0.08306,0.32484 -0.04457,0.5409 -0.107625,0.1822 -0.125887,0.29344 -0.0658,0.40081 0.05946,0.10624 0.04798,0.18749 -0.04025,0.28499 -0.08948,0.0989 -0.102019,0.19267 -0.0456,0.34106 0.05758,0.15143 0.0371,0.28115 -0.07871,0.49867 -0.15027,0.28224 -0.156671,0.28521 -0.160078,0.0743 -0.002,-0.12084 -0.07975,-0.28867 -0.172883,-0.37296 -0.134419,-0.12164 -0.169333,-0.12784 -0.169333,-0.03 0,0.0677 0.04572,0.16891 0.1016,0.22479 0.0662,0.0662 0.06981,0.1016 0.01037,0.1016 -0.146173,0 -0.285189,-0.21652 -0.261135,-0.40673 0.01219,-0.0964 -0.01593,-0.17719 -0.0625,-0.17952 -0.08224,-0.004 -0.09919,0.0669 -0.118,0.49452 -0.01081,0.2457 -0.09689,0.18614 -0.131962,-0.0913 -0.04455,-0.35239 -0.08523,-0.43821 -0.297327,-0.62719 -0.190503,-0.16974 -0.199099,-0.20679 -0.09896,-0.42656 0.09895,-0.21718 0.09153,-0.25535 -0.07596,-0.39098 -0.151401,-0.1226 -0.175504,-0.20422 -0.130752,-0.44277 0.03266,-0.17408 0.01432,-0.35738 -0.0453,-0.45285 -0.125966,-0.20171 -0.05533,-0.49047 0.21879,-0.89441 0.117597,-0.17329 0.213813,-0.37277 0.213813,-0.4433 0,-0.0705 0.0381,-0.10469 0.08467,-0.0759 0.04657,0.0288 0.08467,0.0184 0.08467,-0.023 0,-0.0414 0.09395,-0.12564 0.208781,-0.1871 0.155848,-0.0834 0.237872,-0.0876 0.323529,-0.0165 0.07202,0.0598 0.270118,0.0753 0.532052,0.0417 0.398923,-0.0512 0.452734,-0.0921 1.221638,-0.92696 0.442383,-0.48036 0.940127,-0.97636 1.106096,-1.10222 l 0.301763,-0.22884 0.0202,-1.3185 c 0.01111,-0.72518 0.05504,-1.35345 0.09763,-1.39616 0.116881,-0.11722 0.154807,0.0722 0.201962,1.00899 0.02344,0.46567 0.06748,1.00931 0.09787,1.20809 0.03048,0.19939 0.01823,0.40816 -0.02732,0.46567 -0.04899,0.0618 -0.0872,1.15897 -0.09396,2.6978 l -0.0114,2.59356 0.190747,0.0511 c 0.104911,0.0281 0.324098,0.0527 0.487081,0.0546 0.162983,0.002 0.560379,0.11606 0.883102,0.2537 0.978471,0.41731 0.973527,0.58177 -0.03992,1.32784 -0.732824,0.53949 -0.763135,0.57464 -0.710454,0.82393 0.06649,0.31463 1.107064,2.57784 1.269522,2.76116 0.280284,0.31629 0.508345,1.2669 0.30394,1.2669 -0.03949,0 -0.1409,-0.15322 -0.225346,-0.34048 -0.0972,-0.21555 -0.226191,-0.35873 -0.351526,-0.39018 -0.151704,-0.0381 -0.197987,-0.10823 -0.197987,-0.30008 0,-0.33005 -0.10762,-0.51976 -0.640405,-1.12889 -0.284183,-0.3249 -0.465643,-0.61929 -0.502354,-0.81497 -0.03161,-0.16849 -0.14818,-0.45396 -0.259047,-0.63437 l -0.201576,-0.32803 -0.0026,2.59851 c -0.0024,2.35764 -0.03644,2.80048 -0.2025,2.63441 z m 1.052932,-6.43181 c 0.16527,-0.18134 0.175044,-0.21433 0.05017,-0.16933 -0.0853,0.0307 -0.224609,0.0559 -0.309574,0.0559 -0.112798,0 -0.142534,0.0457 -0.110201,0.16933 0.05849,0.22366 0.123844,0.21378 0.369607,-0.0559 z m -3.973753,-0.80839 c -0.09816,-0.1533 -0.179111,-0.2465 -0.179895,-0.20711 -0.0021,0.10653 0.280213,0.56398 0.322184,0.522 0.0199,-0.0199 -0.04413,-0.1616 -0.142289,-0.31489 z m -0.377485,-0.42159 c -0.02703,-0.0675 -0.04709,-0.0475 -0.05115,0.0512 -0.0037,0.0892 0.01633,0.13926 0.04447,0.11113 0.02813,-0.0281 0.03114,-0.10116 0.0067,-0.16228 z m 3.238797,-1.99496 c -0.0045,-0.33665 -0.01826,-0.36999 -0.08452,-0.20468 -0.07026,0.17529 -0.02991,0.60685 0.05674,0.60685 0.01823,0 0.03074,-0.18098 0.02779,-0.40217 z m -0.281016,-0.88708 c 0.147142,-0.28454 0.188427,-0.53093 0.252131,-1.50475 l 0.04154,-0.635 -0.236208,0.29633 c -0.129915,0.16298 -0.313898,0.37253 -0.408851,0.46567 -0.09495,0.0931 -0.298301,0.33125 -0.451883,0.52916 l -0.279241,0.35984 h 0.244181 c 0.292255,0 0.447381,0.13558 0.447381,0.391 0,0.26277 0.0881,0.46353 0.178807,0.40747 0.04202,-0.026 0.137484,-0.16534 0.212143,-0.30972 z"
id="path2" /></g></svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Unkown
SPDX-License-Identifier: PUBLIC-DOMAIN

View file

@ -13,7 +13,8 @@
"description": {
"en": "Waymarked trails",
"nl": "Aangeduide wandeltochten",
"de": "Markierte Wanderwege"
"de": "Markierte Wanderwege",
"ca": "Rutes marcades"
},
"source": {
"osmTags": {
@ -107,12 +108,14 @@
"question": {
"en": "What is the name of this trail?",
"nl": "Wat is de naam van deze wandeling?",
"de": "Wie heißt dieser Weg?"
"de": "Wie heißt dieser Weg?",
"ca": "Quin és el nom d'aquest sender?"
},
"render": {
"en": "This trail is called <b>{name}</b>",
"nl": "Deze wandeling heet <b>{name}</b>",
"de": "Dieser Weg heißt <b>{name}</b>"
"de": "Dieser Weg heißt <b>{name}</b>",
"ca": "Aquest sender s'anomena <b>{name}</b>"
},
"freeform": {
"key": "name"
@ -143,7 +146,8 @@
"then": {
"en": "This trail is maintained by Natuurpunt",
"nl": "Dit gebied wordt beheerd door Natuurpunt",
"de": "Dieser Weg wird von Natuurpunt gepflegt"
"de": "Dieser Weg wird von Natuurpunt gepflegt",
"ca": "Aquest sender és mantingut per Natuurpunt"
},
"icon": {
"path": "./assets/themes/buurtnatuur/Natuurpunt.jpg",
@ -174,12 +178,14 @@
"question": {
"en": "What is the reference colour of this trail?",
"nl": "Welke kleur heeft deze wandeling?",
"de": "Was ist die Referenzfarbe dieses Weges?"
"de": "Was ist die Referenzfarbe dieses Weges?",
"ca": "Quin és el color de referència d'aquest sender?"
},
"render": {
"en": "The reference colour is {colour}",
"nl": "Deze wandeling heeft kleur {colour}",
"de": "Die Referenzfarbe ist {colour}"
"de": "Die Referenzfarbe ist {colour}",
"ca": "El color de referència és {colour}"
},
"freeform": {
"key": "colour",

View file

@ -4,6 +4,8 @@
"en": "Library layer with all common units. Units can _only_ be imported from this file."
},
"source": "special:library",
"pointRendering": null,
"lineRendering": null,
"units": [
{
"quantity": "power",
@ -132,7 +134,8 @@
],
"human": {
"en": "{quantity} A",
"nl": "{quantity} A"
"nl": "{quantity} A",
"ca": "{quantity} A"
}
}
],
@ -173,7 +176,8 @@
"en": "one meter",
"fr": "un mètre",
"nl": "één meter",
"de": "ein Meter"
"de": "ein Meter",
"ca": "un metre"
}
},
{
@ -197,7 +201,8 @@
},
"humanSingular": {
"en": "one centimeter",
"nl": "één centimeter"
"nl": "één centimeter",
"ca": "un centímetre"
}
},
{
@ -218,7 +223,8 @@
"humanSingular": {
"en": "one millimeter",
"nl": "één millimeter",
"de": "ein Millimeter"
"de": "ein Millimeter",
"ca": "un mil·límetre"
}
},
{
@ -330,11 +336,13 @@
],
"human": {
"en": "{quantity} minutes",
"nl": "{quantity} minuten"
"nl": "{quantity} minuten",
"ca": "{quantity} minuts"
},
"humanSingular": {
"en": "one minute",
"nl": "één minuut"
"nl": "één minuut",
"ca": "un minut"
}
},
{
@ -351,11 +359,13 @@
],
"human": {
"en": "{quantity} hours",
"nl": "{quantity} uren"
"nl": "{quantity} uren",
"ca": "{quantity} hores"
},
"humanSingular": {
"en": "one hour",
"nl": "één uur"
"nl": "één uur",
"ca": "una hora"
}
},
{
@ -369,7 +379,8 @@
],
"human": {
"en": "{quantity} days",
"nl": "{quantity} day"
"nl": "{quantity} day",
"ca": "{quantity} dies"
},
"humanSingular": {
"en": "one day",
@ -378,7 +389,5 @@
}
]
}
],
"pointRendering": null,
"lineRendering": null
]
}

View file

@ -50,7 +50,7 @@
"then": {
"en": "The language was set via an URL-parameter and cannot be set by the user.",
"de": "Die Sprache wurde über einen URL-Parameter gesetzt und kann nicht vom Benutzer eingestellt werden.²",
"ca": "L'idioma es va establir mitjançant un paràmetre d'URL i l'usuari no pot definir-lo.²",
"ca": "L'idioma es va establir mitjançant un paràmetre d'URL i l'usuari no pot definir-lo.",
"cs": "Jazyk byl nastaven pomocí parametru URL a uživatel jej nemůže nastavit.²"
}
}
@ -83,7 +83,7 @@
"text": {
"en": "<b class='alert'>You have {_unreadMessages} messages</b><br/>Open your inbox",
"de": "<b class='alert'>Du hast {_unreadMessages}</b><br/>Öffne Deinen Posteingang",
"ca": "<b class='alert'>Tens {_unreadMessages}</b><br/>Open your inbox",
"ca": "<b class='alert'>Tens {_unreadMessages} missatges </b><br/>Obri la safata d'entrada",
"cs": "<b class='alert'>Máte {_unreadMessages}</b><br/>Otevřít schránku"
},
"href": "{_backend}/messages/inbox"
@ -123,13 +123,15 @@
"if": "mapcomplete-a11y=default",
"alsoShowIf": "mapcomplete-a11y=",
"then": {
"en": "Enable accessibility features when arrow keys are used to navigate the map"
"en": "Enable accessibility features when arrow keys are used to navigate the map",
"ca": "Activar les funcions d'accessibilitat quan s'utilitzen les tecles de fletxa per navegar pel mapa"
}
},
{
"if": "mapcomplete-a11y=always",
"then": {
"en": "Always enable accessibility features"
"en": "Always enable accessibility features",
"ca": "Sempre habilita les característiques d'accessibilitat"
}
},
{
@ -411,7 +413,8 @@
"en": "This can help to accurately position a new element",
"cs": "To může pomoci přesněji umístit nový prvek",
"de": "Dies kann dazu beitragen, ein neues Element genau zu positionieren",
"nl": "Dit kan helpen om nieuwe elementen accuraat te plaatsen"
"nl": "Dit kan helpen om nieuwe elementen accuraat te plaatsen",
"ca": "Això pot ajudar a posicionar amb precisió un nou element"
},
"mappings": [
{

View file

@ -579,7 +579,8 @@
"en": "Fruit is sold",
"nl": "Fruit wordt verkocht",
"de": "Obst wird verkauft",
"cs": "Prodává ovoce"
"cs": "Prodává ovoce",
"ca": "Es ven fruita"
},
"icon": "./assets/layers/vending_machine/fruits.svg"
},
@ -589,7 +590,8 @@
"en": "Strawberries are sold",
"nl": "Aardbeien worden verkocht",
"de": "Erdbeeren werden verkauft",
"cs": "Prodává jahody"
"cs": "Prodává jahody",
"ca": "Es venen maduixes"
},
"icon": "./assets/layers/vending_machine/strawberry.svg"
},
@ -643,7 +645,8 @@
"en": "Bicycle lights are sold",
"nl": "Fietslampjes worden verkocht",
"de": "Fahrradlampen werden verkauft",
"cs": "Prodává světla na kolo"
"cs": "Prodává světla na kolo",
"ca": "Es venen llums per a bicicletes"
}
},
{
@ -652,7 +655,8 @@
"en": "Gloves are sold",
"nl": "Handschoenen worden verkocht",
"de": "Fahrradhandschuhe werden verkauft",
"cs": "Prodává rukavice"
"cs": "Prodává rukavice",
"ca": "Es venen guants"
}
},
{
@ -661,7 +665,8 @@
"en": "Bicycle repair kits are sold",
"nl": "Fietsreparatiesets worden verkocht",
"de": "Fahrrad-Reparaturset werden verkauft",
"cs": "Prodává sady na opravu jízdních kol"
"cs": "Prodává sady na opravu jízdních kol",
"ca": "Es venen kits de reparació de bicicletes"
}
},
{
@ -670,7 +675,8 @@
"en": "Bicycle pumps are sold",
"nl": "Fietspompen worden verkocht",
"de": "Fahrradpumpen werden verkauft",
"cs": "Prodává pumpy na kolo"
"cs": "Prodává pumpy na kolo",
"ca": "Es venen bombes de bicicletes"
}
},
{
@ -679,7 +685,8 @@
"en": "Bicycle locks are sold",
"nl": "Fietssloten worden verkocht",
"de": "Fahrradschlösser werden verkauft",
"cs": "Prodává zámky na kolo"
"cs": "Prodává zámky na kolo",
"ca": "Es venen cadenats per a bicicletes"
}
}
],
@ -980,7 +987,7 @@
"question": {
"en": "Sale of fruit",
"nl": "Verkoop van fruit",
"ca": "Venda de flors",
"ca": "Venda de fruites",
"de": "Verkauf von Obst",
"cs": "Prodej ovoce"
},
@ -990,7 +997,7 @@
"question": {
"en": "Sale of strawberries",
"nl": "Verkoop van aardbeien",
"ca": "Venda de tiquets d'aparcament",
"ca": "Venda de maduixes",
"de": "Verkauf von Erdbeeren",
"cs": "Prodej jahod"
},
@ -1011,7 +1018,7 @@
"osmTags": "vending~i~.*parking_tickets.*",
"question": {
"en": "Sale of parking tickets",
"ca": "Venda de bitllets de transport públic",
"ca": "Venda de tiquets d'aparcament",
"de": "Verkauf von Parkscheinen",
"cs": "Prodej parkovacích lístků"
}
@ -1040,7 +1047,8 @@
"en": "Sale of bicycle lights",
"nl": "Verkoop van fietslampjes",
"de": "Verkauf von Fahrradlampen",
"cs": "Prodej světel na kolo"
"cs": "Prodej světel na kolo",
"ca": "Venda de llums de bicicletes"
}
},
{
@ -1049,7 +1057,8 @@
"en": "Sale of gloves",
"nl": "Verkoop van handschoenen",
"de": "Verkauf von Fahrradhandschuhen",
"cs": "Prodej rukavic"
"cs": "Prodej rukavic",
"ca": "Venda de guants"
}
},
{
@ -1058,7 +1067,8 @@
"en": "Sale of bicycle repair kits",
"nl": "Verkoop van fietsreparatiesets",
"de": "Verkauf von Fahrrad-Reparatursets",
"cs": "Prodej sad na opravu jízdních kol"
"cs": "Prodej sad na opravu jízdních kol",
"ca": "Venda de kits de reparació de bicicletes"
}
},
{
@ -1067,7 +1077,8 @@
"en": "Sale of bicycle pumps",
"nl": "Verkoop van fietspompen",
"de": "Verkauf von Fahrradpumpen",
"cs": "Prodej pump na kolo"
"cs": "Prodej pump na kolo",
"ca": "Venda de bombes de bicicletes"
}
},
{
@ -1076,7 +1087,8 @@
"en": "Sale of bicycle locks",
"nl": "Verkoop van fietssloten",
"de": "Verkauf von Fahrradschlössern",
"cs": "Prodej zámků na kola"
"cs": "Prodej zámků na kola",
"ca": "Venda de cadenat per a bicicletes"
}
}
]

View file

@ -39,7 +39,7 @@
"es": "enlaces nodo a nodo",
"nl": "Verbindingen van node naar node",
"fr": "liens noeud à noeud",
"ca": "enllaços node a node",
"ca": "Enllaços node a node",
"cs": "propojení mezi uzly",
"pl": "łącza węzeł do węzła"
},
@ -130,7 +130,7 @@
"name": {
"en": "Nodes",
"de": "Knotenpunkte",
"ca": "nodes",
"ca": "Nodes",
"es": "nodos",
"nb_NO": "noder",
"nl": "Knooppunten",
@ -214,7 +214,8 @@
"en": "What is the reference number of this cycling node?",
"nl": "Wat is het referentienummer van dit fietsknooppunt?",
"de": "Wie lautet die Nummer des Knotenpunkts im Fahrradknotenpunktnetzwerk?",
"cs": "Jaké je referenční číslo tohoto cyklistického uzlu?"
"cs": "Jaké je referenční číslo tohoto cyklistického uzlu?",
"ca": "Quin és el número de referència d'aquest node ciclista?"
},
"freeform": {
"key": "rcn_ref",
@ -230,7 +231,8 @@
"en": "This cycling node has reference number {rcn_ref}",
"nl": "Dit fietsknooppunt heeft referentienummer {rcn_ref}",
"de": "Knotenpunktnummer {rcn_ref} des Fahrradknotenpunktnetzwerks",
"cs": "Tento cyklistický uzel má referenční číslo {rcn_ref}"
"cs": "Tento cyklistický uzel má referenční číslo {rcn_ref}",
"ca": "Aquest node ciclista té la referència número {rcn_ref}"
},
"condition": "rcn_ref~*"
},
@ -304,7 +306,8 @@
"title": {
"en": "a cycling node",
"nl": "een fietsknooppunt",
"de": "ein Knoten eines Fahrradknotenpunktnetzwerks"
"de": "ein Knoten eines Fahrradknotenpunktnetzwerks",
"ca": "un node ciclista"
},
"snapToLayer": [
"cycleways_and_roads"

View file

@ -70,14 +70,16 @@
{
"question": {
"en": "Only show fritures using vegetable oil",
"de": "Nur Friteusen mit Pflanzenöl anzeigen"
"de": "Nur Friteusen mit Pflanzenöl anzeigen",
"ca": "Només mostra freiduries que utilitzen oli vegetal"
},
"osmTags": "friture:oil=vegetable"
},
{
"question": {
"en": "Only show fritures using animal oil",
"de": "Nur Friteusen mit tierischem Öl anzeigen"
"de": "Nur Friteusen mit tierischem Öl anzeigen",
"ca": "Només mostra freiduries que utilitzen oli animal"
},
"osmTags": "friture:oil=animal"
}

View file

@ -22,7 +22,6 @@
"startZoom": 9,
"startLat": 51.0249,
"startLon": 4.026489,
"defaultBackgroundId": "osm",
"credits": [
"Pieter Vander Vennet"

View file

@ -5,7 +5,8 @@
"cs": "Rozcestníky",
"de": "Wegweiser",
"es": "Poste guía",
"pl": "Drogowskazy"
"pl": "Drogowskazy",
"ca": "Pal guia"
},
"description": {
"en": "Guideposts (also known as fingerposts or finger posts) are often found along official hiking, cycling, skiing or horseback riding routes to indicate the directions to different destinations. Additionally, they are often named after a region or place and show the altitude.\n\nThe position of a signpost can be used by a hiker/biker/rider/skier as a confirmation of the current position, especially if they use a printed map without a GPS receiver. ",

View file

@ -3,12 +3,14 @@
"title": {
"en": "Icecream",
"de": "Eiscreme",
"cs": "Zmrzlina"
"cs": "Zmrzlina",
"ca": "Gelat"
},
"description": {
"en": "A map showing ice cream parlors and ice cream vending machines",
"de": "Eine Karte, die Eisdielen und Eisautomaten zeigt",
"cs": "Mapa zobrazující prodej zmrzliny a automaty na zmrzlinu"
"cs": "Mapa zobrazující prodej zmrzliny a automaty na zmrzlinu",
"ca": "Un mapa que mostra les gelateries i les màquines expenedores de gelats"
},
"icon": "./assets/layers/ice_cream/ice_cream.svg",
"layers": [

View file

@ -316,6 +316,10 @@
"if": "theme=onwheels",
"then": "./assets/themes/onwheels/crest.svg"
},
{
"if": "theme=openlovemap",
"then": "./assets/layers/stripclub/stripclub.svg"
},
{
"if": "theme=openwindpowermap",
"then": "./assets/themes/openwindpowermap/logo.svg"

View file

@ -0,0 +1,209 @@
{
"id": "openlovemap",
"title": {
"en": "Open Love Map"
},
"description": {
"en": "<p><i>Love in the palm of your hand</i></p>Open Love Map lists various adult entries, such as brothels, erotic stores and stripclubs."
},
"icon": "./assets/layers/stripclub/stripclub.svg",
"layers": [
"brothel",
"stripclub",
{
"builtin": "shops",
"override": {
"id": "erotic-shop",
"source": {
"osmTags": "shop=erotic"
},
"minzoom": 6,
"=filter": [
"open_now"
],
"=presets": [
{
"title": {
"en": "an erotic shop"
},
"tags": [
"shop=erotic"
]
}
]
}
},
{
"builtin": "shops",
"override": {
"minzoom": 18,
"=presets": [],
"=name": null
}
},
{
"builtin": "vending_machine",
"override": {
"id": "condom_vending_machine",
"pointRendering": [
{
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "ring",
"color": "black"
}
],
"location": [
"centroid",
"point"
],
"iconSize": "40,40",
"anchor": "center"
},
{
"marker": [
{
"icon": "./assets/layers/vending_machine/condom.svg"
}
],
"location": [
"centroid",
"point"
],
"iconSize": "26,26",
"anchor": "center"
}
],
"=filter": [
"open_now"
],
"source": {
"osmTags": {
"=and": [
"amenity=vending_machine",
"vending=condoms"
]
}
},
"minzoom": 6,
"=presets": [
{
"title": {
"en": "a condom vending machine"
},
"tags": [
"amenity=vending_machine",
"vending=condoms"
]
}
]
}
},
{
"builtin": "vending_machine",
"override": {
"minzoom": 18,
"=presets": [],
"=name": null
}
},
{
"builtin": "cinema",
"hideTagRenderingsWithLabels": ["wikipedia"],
"override": {
"id": "erotic_cinema",
"pointRendering": [
{
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "ring",
"color": "#734a08"
}
],
"location": [
"centroid",
"point"
],
"iconSize": "40,40",
"anchor": "center"
},
{
"marker": [
{
"icon": "./assets/layers/cinema/cinema.svg"
}
],
"location": [
"centroid",
"point"
],
"iconSize": "26,26",
"anchor": "center"
}
],
"=filter": [
"open_now"
],
"tagRenderings+": ["opening_hours"],
"source": {
"osmTags": {
"=and": [
"amenity=cinema",
"cinema=erotic"
]
}
},
"minzoom": 6,
"=presets": [
{
"title": {
"en": "an erotic cinema"
},
"tags": [
"amenity=cinema",
"cinema=erotic"
]
}
]
}
},
{
"builtin": "cinema",
"override": {
"minzoom": 18,
"=presets": [],
"=name": null
}
}
],
"overrideAll": {
"tagRenderings+": [{
"id": "has_video_booth",
"question": {"en":
"Does {title()} have a private video booth?"
},
"questionHint": {
"en": "This is for use by a single person."
},
"mappings": [
{
"if": "service:private_video_booth=yes",
"then": "Private video booths are available"
},
{
"if": "service:private_video_booth=no",
"then": "No private video booths"
}
]
}]
}
}

View file

@ -50,6 +50,13 @@
"panelIntro": "<h3>La teva interfície personal</h3>Activa les teves capes favorites de totes les interfícies oficials",
"reload": "Recarregar dades"
},
"favouritePoi": {
"button": {
"isMarkedShort": "Marcat com a ubicació favorita",
"isNotMarkedShort": "No marcat com a favorit",
"markAsFavouriteTitle": "Marca aquesta ubicació com a preferida"
}
},
"flyer": {
"aerial": "Aquest mapa utilitza un fons diferent, és a dir, imatges aèries de Agentschap Informatie Vlaanderen",
"callToAction": "Prova'l a mapcomplete.org",
@ -124,7 +131,7 @@
"pleaseLogin": "Entra per afegir un nou element",
"presetInfo": "El nou PDI tindrà les etiquetes {tags}",
"stillLoading": "Les dades es segueixen carregant. Espera una mica abans d'afegir cap element.",
"title": "Vols afegir un element?",
"title": "Afegeix un element nou",
"warnVisibleForEveryone": "La teva contribució serà vista per tothom",
"wrongType": "Aquest element no és un punt o una via i no pot ser importat",
"zoomInFurther": "Apropa per afegir un element.",
@ -166,7 +173,7 @@
"backgroundSwitch": "Canvia el fons",
"cancel": "Cancel·lar",
"confirm": "Confirmar",
"customThemeIntro": "<h3>Peticions personalitzades</h3>Aquestes són les peticions generades pels usuaris que has visitat abans.",
"customThemeIntro": "Aquestes són les peticions generades pels usuaris que has visitat abans.",
"download": {
"downloadAsPdf": "Baixar un PDF del mapa actual",
"downloadAsPdfHelper": "Ideal per imprimir el mapa actual",
@ -186,7 +193,6 @@
"includeMetaData": "Incloure metadades (darrer editor, valors calculats, ...)",
"licenseInfo": "<h3>Avís de drets de còpia</h3>Les dades proveïdes estan sota ODbL. Es poden reutilitzar de forma gratuïta, però <ul><li>l'atribució a <b>© Contribuïdors d'OpenStreetMap</b> s'ha de mostrar</li><li> Qualsevol canvi s'ha de publicar sota la mateixa llicència</li></ul> Llegeix sencer <ahref=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">l'avís de drets de còpia</a> per més detalls.",
"noDataLoaded": "No s'han carregat dades. La baixada estarà disponible aviat",
"pdf": {},
"title": "Descarrega",
"uploadGpx": "Pujar la teva traça a OpenStreetMap"
},
@ -342,6 +348,13 @@
},
"useSearch": "Utilitzeu la cerca de dalt per veure els valors predefinits",
"useSearchForMore": "Utilitzeu la funció de cerca per cercar dins de {total} valors més…",
"visualFeedback": {
"directionsRelative": {
"left": "esquerra",
"right": "dreta"
},
"fromGps": "{distance} {direction} de la seva ubicació"
},
"waitingForGeopermission": "Esperant al vostre permís per a utilitzar la geolocalització…",
"waitingForLocation": "Buscant la vostra ubicació actual…",
"weekdays": {
@ -620,6 +633,11 @@
"description": "un número",
"feedback": "No és un nombre"
},
"id": {
"description": "un identificador",
"invalidCharacter": "Un identificador només pot contenir lletres, dígits i guions baixos",
"shouldBeLonger": "Un identificador ha de tenir almenys 3 caràcters"
},
"int": {
"description": "un número sencer"
},
@ -644,6 +662,10 @@
"description": "un número sencer, positiu",
"noZero": "No es permet el zero"
},
"slope": {
"inputExplanation": "Poseu el telèfon a terra amb la part superior del telèfon apuntant cap a la part superior del pendent.",
"inputIncorrect": "Per a les mesures correctes, assegureu-vos que la fletxa està dins de la zona verda."
},
"string": {
"description": "un tros de text"
},

View file

@ -22,13 +22,18 @@
"delete": "Poista",
"explanations": {
"hardDelete": "Tämä kohde poistetaan OpenStreetMapistä. Kokenut kartoittaja voi palauttaa sen.",
"retagNoOtherThemes": "Tämä kohde luokitellaan uudelleen ja piilotetaan tältä sovellukselta",
"retagOtherThemes": "Tämän kohteen ominaisuustietoja muutetaan, ja se ilmestyy näkyviin teemoissa {otherThemes}",
"selectReason": "Valitse, miksi tämä kohde pitäisi poistaa",
"softDelete": "Tämä kohde päivitetään ja piilotetaan tässä sovelluksessa. <span class='subtle'>{reason}</span>"
},
"isDeleted": "Tämä kohde on poistettu",
"isntAPoint": "Vain pisteitä voi poistaa. Valittu kohde on viiva, alue tai relaatio.",
"loading": "Tutkitaan ominaisuuksista, voiko tämän kohteen poistaa.",
"loginToDelete": "Kohteen poistamiseksi täytyy kirjautua",
"notEnoughExperience": "Tämän kohteen loi joku muu.",
"onlyEditedByLoggedInUser": "Tätä kohdetta ei ole muokannut kukaan muu kuin sinä, joten sen voi huoletta poistaa.",
"partOfOthers": "Tämä piste on osa viivaa tai relaatiota eikä sitä voi poistaa suoraan.",
"readMessages": "Sinulle on lukemattomia viestejä. Lue ne ennen kuin poistat kohteen joku on saattanut lähettää palautetta",
"reasons": {
"disused": "Tämä kohde on poistettu käytöstä tai poistettu",
@ -37,18 +42,23 @@
"test": "Tämä oli testikohde kohdetta ei ollut ikinä olemassa"
},
"safeDelete": "Tämä kohde voidaan turvallisesti poistaa.",
"useSomethingElse": "Poista se toisella OpenStreetMap-editorilla",
"whyDelete": "Miksi tämä kohde pitäisi poistaa?"
},
"favourite": {
"loginNeeded": "<h3>Kirjaudu sisään</h3>Oma asettelu on saatavilla vain OpenStreetMap-käyttäjille",
"panelIntro": "<h3>Oma teema</h3>Käytä suosikkitasojasi kaikista virallisista teemoista",
"reload": "Lataa data uudelleen"
},
"favouritePoi": {
"button": {
"isFavourite": "Tämä paikka on merkitty suosikiksi ja näkyy kaikilla MapCompleten teemakartoilla, joita katselet.",
"isMarkedShort": "Merkitty suosikkisijainniksi",
"isNotMarkedShort": "Ei merkitty suosikiksi",
"markAsFavouriteTitle": "Merkitse tämä paikka suosikkisijainniksi",
"markDescription": "Lisää tämä paikka henkilökohtaiselle suosikkilistalle",
"unmark": "Poista henkilökohtaiselta suosikkilistalta"
"markDescription": "Lisää tämä paikka omalle suosikkilistalle",
"unmark": "Poista omalta suosikkilistalta",
"unmarkNotDeleted": "Tätä pistettä ei poisteta ja se pysyy näkyvissä kartoilla sinulle ja muille"
},
"downloadGeojson": "Lataa suosikkisi geojson-muodossa",
"downloadGpx": "Lataa suosikkisi GPX-muodossa",
@ -59,39 +69,109 @@
"title": "Suosikkisijaintisi"
},
"flyer": {
"aerial": "Tämä kartta käyttää eri taustaa, joka on ilmakuva taholta Agentschap Informatie Vlaanderen",
"callToAction": "Kokeile sitä osoitteessa mapcomplete.org",
"cyclofix": "Pyöränpumput, korjausasemat, juomavesi ja pyöräkaupat ovat CycloFixissä",
"description": "Vaakasuuntainen A4-lentolehtinen MapCompleten mainostamiseen",
"editing": {
"ex": "Alla on yksinkertainen esimerkki siitä, miltä tämä näyttää luonnonsuojelualueella.",
"intro": "Käyttäjää tervehtii kartta, jolla on kohteita. Kun kohde valitaan, sen tiedot näytetään.",
"title": "Miltä käyttöliittymä näyttää?"
},
"examples": "MapCompletessa on paljon teemakarttoja. Muutamia niistä näkyy tässä.\n\nVerkossa on vielä lisää teemakarttoja aiheista: terveydenhuolto, sisänavigointi, esteettömyydes pyörätuolilla, jätteenkäsittelylaitokset, julkiset kirjahyllyt, sateenkaaren väreissä olevat suojatiet, … Löydä ne kaikki mapcomplete.org-sivustolta",
"fakeui": {
"add_images": "Lisää kuvia muutamalla napsautuksella"
"add_images": "Lisää kuvia muutamalla napsautuksella",
"attributes": "Näyttää ominaisuudet ystävällisellä tavalla",
"edit": "Väärää tai vanhentunutta tietoa? Muokkauspainike on käden ulottuvilla.",
"question": "Jos ominaisuus ei ole vielä tiedossa, MapComplete esittää kysymyksen",
"see_images": "Näyttää kuvia aiemmilta tekijöiltä, Wikipediasta, Mapillarystä, …",
"wikipedia": "Linkitetyt Wikipedia-artikkelit näytetään"
},
"frontParagraph": "MapComplete on helppokäyttöinen verkkosovellus, jolla voi kerätä paikkatietoa OpenStreetMapiin. Sen avulla voi kerätä ja hallita olennaista tietoa avoimella, joukkoistetulla ja uudelleenkäytettävällä tavalla.\n\nUusia luokkia ja ominaisuuksia voi lisätä pyydettäessä.",
"lines_too": "Viivat ja monikulmiot näytetään myös. Lisäksi niiden ominaisuuksia ja kuvia voi muokata ja päivittää.",
"mapcomplete": {
"customize": "MapCompleten voi räätälöidä tarpeisiisi. Siihen voi lisätä uusia karttatasoja, uutta toiminnallisuutta tai sen voi tyylitellä käyttämään organisaatiosi väerjä ja fontteja.\nMeillä on myös kokemusta paikkatiedon joukkoistamiskampanjoiden aloittamisesta.\nPyydä tarjous ottamalla yhteyttä osoitteeseen pietervdvn@posteo.net.",
"intro": "MapComplete on sivusto, jolla on {mapCount} vuorovaikutteista karttaa. Jokaiselle kartalle voi lisätä ja päivittää tietoja. Siinä on paljon ominaisuuksia:",
"li0": "Näytä, missä on kiinnostavia paikkoja",
"li1": "Lisää uusia pisteitä ja päivitä nykyisten tietoja",
"li2": "Lisää yhteystietoja ja aukioloaikoja helposti",
"li3": "Voidaan lisätä muille verkkosivuille iFramen muodossa",
"li4": "Osa OpenStreetMap-ekosysteemiä, johon kuuluu paljon työkaluja",
"li5": "Mahdollisuus tuota olemassa olevia aineistoja",
"li6": "Paljon kehittyneitä ominaisuuksia, kuten puiden tunnistus ja kehittyneet syöttömenetelmät",
"li7": "Avoimen lähdekoodin ohjelmisto (GPL-lisenssillä) ja ilmainen käyttää",
"title": "Mikä MapComplete on?"
},
"onwheels": "Myös sisätilakartat pyörätuolillä liikkuville on käytettävissä.",
"osm": "OpenStreetMap on verkkokartta, jota voi muokata ja uudelleenkäyttää kuka tahansa mihin tahansa tarkoitukseen, kunhan lähde nimetään asianmukaisesti sekä data pidetään avoimena.\n\nSe on maailman suurin paikkatietokanta, ja sitä käytetään tuhansissa sovelluksissa ja verkkosivustoissa.",
"tagline": "Kerää paikkatietoa OpenStreetMapillä",
"title": "mapcomplete.org",
"toerisme_vlaanderen": "”Pin your point” -hanke tehtiin yhteistyössä Visit Flandersin kanssa. Yli 160 kartoittajaa lisäsi muutama tuhat penkkiä ja piknikpöytää sekä löysi 100 latausasemaa polkupyörille.",
"whatIsOsm": "Mikä OpenStreetMap on?"
},
"general": {
"404": "Tätä sivua ei ole olemassa",
"about": "Muokkaa ja lisää tiettyyn teemaan liittyviä tietoja OpenStreetMapiin helposti",
"aboutMapComplete": {
"intro": "MapCompletea voi käyttää lisäämään tietoja OpenStreetMapiin <b>yhdestä teemasta.</b> Vastaa kysymyksiin, niin muutoksesi ovat käytettävissä kaikkialla minuuttien kuluessa. Useimmissa teemoissa voi lisätä kuvia tai jopa jättää arvostelun. <b>Teeman ylläpitäjä</b> määrittelee teeman kohteet, kysymykset ja kielet."
},
"add": {
"addNew": "Lisää {category}",
"backToSelect": "Valitse toinen luokka",
"confirmButton": "Lisää {category}<br/><div class='alert'>Lisäyksesi näkyy kaikille</div>",
"confirmLocation": "Vahvista tämä sijainti",
"confirmTitle": "Lisätäänkö {title}?",
"title": "Lisää uusi kohde"
"confirmWarning": "Täällä luomasi kohde <b>näkyy kaikille</b>. Ole hyvä ja lisää kartalle vain kohteita, jotka ovat oikeasti olemassa. Monet sovellukset käyttävät tätä tietoa.",
"disableFilters": "Poista käytöstä kaikki suodattimet",
"disableFiltersExplanation": "Jotkin kohteet saattavat olla piilossa suodattimen takia",
"enableLayer": "Ota käyttöön taso {name}",
"hasBeenImported": "Tämä kohde on jo tuotu",
"import": {
"hasBeenImported": "Tämä kohde on tuotu",
"howToTest": "Testaa lisäämällä <b>test=true</b> tai <b>backend=osm-test</b> URL-osoitteeseen. Muutoskokoelma tulostetaan konsoliin. Ole hyvä ja avaa pull request, jotta tämä teema voidaan virallistaa ja tuontipainike ottaa käyttöön.",
"importTags": "Kohteelle kirjataan {tags}",
"officialThemesOnly": "Tuontipainike ei ole käytössä epävirallisille teemoille vahinkojen välttämiseksi",
"wrongType": "Tämä kohde ei ole piste eikä viiva eikä sitä voida tuoda",
"wrongTypeToConflate": "Tämä kohde ei ole piste eikä viiva eikä sitä voida yhdistää",
"zoomInMore": "Lähennä karttaa lisää, jotta tämän kohteen voi tuoda"
},
"importTags": "Kohteelle kirjataan {tags}",
"intro": "Painoit kohtaa, jolle ei ole vielä tietoa.<br/>",
"layerNotEnabled": "Taso {layer} ei ole käytössä. Ota taso käyttöön, jotta voit lisätä kohteen",
"openLayerControl": "Avaa tason hallintaikkuna",
"pleaseLogin": "Kirjaudu sisään, jotta voit lisätä uuden kohteen",
"presetInfo": "Uudelle pisteelle kirjataan {tags}",
"stillLoading": "Data latautuu vielä. Odota hetki ennen kuin lisäät uuden kohteen.",
"title": "Lisää uusi kohde",
"warnVisibleForEveryone": "Lisäyksesi näkyy kaikille",
"wrongType": "Tämä kohde ei ole piste eikä viiva eikä sitä voida tuoda",
"zoomInFurther": "Lähennä karttaa lisää, jotta kohteen voi lisätä.",
"zoomInMore": "Lähennä karttaa lisää, jotta voit tuoda tämän kohteen"
},
"apply_button": {
"appliedOnAnotherObject": "Kohteelle {id} kirjataan {tags}",
"isApplied": "Muutokset otetaan käyttöön"
},
"attribution": {
"attributionBackgroundLayer": "Nykyinen taustataso on {name}",
"attributionBackgroundLayerWithCopyright": "Nykyinen taustataso on {name}: {copyright}",
"attributionContent": "<p>Kaiken datan tarjoaa <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, vapaasti uudelleenkäytettävissä <a href='https://osm.org/copyright' target='_blank'>Open Database Licensen</a> mukaisesti.</p>",
"attributionTitle": "Kiitokset",
"donate": "Tue MapCompletea rahallisesti",
"editId": "Avaa OpenStreetMap-verkkoeditori tänne",
"editJosm": "Muokkaa täällä JOSM:illa",
"followOnMastodon": "Seuraa MapCompletea Mastodonissa",
"iconAttribution": {
"title": "Käytetyt kuvakkeet"
},
"josmOpened": "JOSM on avattu",
"openIssueTracker": "Ilmoita ohjelmavirheestä",
"openMapillary": "Avaa Mapillary tänne"
"openMapillary": "Avaa Mapillary tänne",
"title": "Tekijänoikeudet ja alkuperä"
},
"backToIndex": "Palaa kaikkien teemakarttojen yleiskuvaan",
"backgroundMap": "Taustakartta",
"backgroundMap": "Valitse taustataso",
"backgroundSwitch": "Vaihda taustaa",
"cancel": "Peruuta",
"download": {
"title": "Lataa"
@ -112,12 +192,14 @@
"loginWithOpenStreetMap": "Kirjaudu sisään OpenStreetMapilla",
"logout": "Kirjaudu ulos",
"menu": {
"aboutMapComplete": "Tietoa MapCompletesta"
"aboutMapComplete": "Tietoa MapCompletesta",
"filter": "Suodata dataa"
},
"morescreen": {
"createYourOwnTheme": "Luo oma MapComplete-teema alusta asti",
"noSearch": "Näytä kaikki teemat",
"searchForATheme": "Etsi teemaa",
"streetcomplete": "Toinen, samanlainen sovellus on <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' class='underline hover:text-blue-800' class='underline hover:text-blue-800' target='_blank'>StreetComplete</a>."
"streetcomplete": "Toinen, samankaltainen sovellus on <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' class='underline hover:text-blue-800' class='underline hover:text-blue-800' target='_blank'>StreetComplete</a>."
},
"number": "numero",
"openTheMap": "Avaa kartta",
@ -126,9 +208,12 @@
"loadingCountry": "Määritetään maata…",
"ph_closed": "suljettu",
"ph_not_known": " ",
"ph_open": "avattu"
"ph_open": "auki"
},
"pickLanguage": "Valitse kieli: ",
"pdf": {
"attrBackground": "Taustataso: {background}"
},
"pickLanguage": "Valitse kieli",
"questionBox": {
"answeredMultiple": "Vastasit {answered} kysymykseen",
"answeredOne": "Vastasit yhteen kysymykseen",
@ -143,6 +228,7 @@
"search": {
"nothing": "Mitään ei löytynyt…",
"search": "Etsi paikkaa",
"searchShort": "Etsi…",
"searching": "Etsitään…"
},
"sharescreen": {
@ -180,13 +266,24 @@
},
"hotkeyDocumentation": {
"action": "Toiminto",
"key": "Näppäinyhdistelmä"
"key": "Näppäinyhdistelmä",
"openLayersPanel": "Avaa taustatasojen paneelin",
"selectAerial": "Asettaa taustaksi joko ilma- tai satelliittikuvan. Vaihtaa kahden parhaimman, saatavilla olevan tason välillä",
"selectMap": "Asettaa taustaksi kartan ulkoisesta lähteestä. Vaihtaa kahden parhaimman, saatavilla olevan tason välillä",
"selectMapnik": "Aseta taustatasoksi OpenStreetMap-carto",
"selectOsmbasedmap": "Aseta taustatasoksi OpenStreetMap-pohjainen kartta (tai poista käytöstä rasterimuotoinen taustataso)"
},
"image": {
"addPicture": "Lisää kuva",
"currentLicense": "Kuvasi julkaistaan lisenssillä {license}",
"doDelete": "Poista kuva",
"dontDelete": "Peruuta",
"isDeleted": "Poistettu",
"nearby": {
"link": "Tämä kuva näyttää kohteen",
"seeNearby": "Selaa ja linkitä läheisiä kuvia",
"title": "Läheiset katukuvat"
},
"pleaseLogin": "Kirjaudu sisään, jotta voit lisätä kuvan",
"respectPrivacy": "Älä valokuvaa ihmisiä tai rekisterikilpiä. Älä lähetä kuvia Google Mapsistä, Google Streetviewstä tai muista tekijänoikeuden alaisista lähteistä.",
"uploadDone": "Kuvasi on lisätty. Kiitoksia avusta!",
@ -198,6 +295,15 @@
"pickTheme": "Aloita valitsemalla teema alta.",
"title": "Tervetuloa MapCompleteen"
},
"move": {
"inviteToMove": {
"generic": "Siirrä tätä pistettä"
},
"whyMove": "Miksi haluat siirtää tätä pistettä?"
},
"multi_apply": {
"autoApply": "Kun ominaisuuksia {attr_names} muutetaan, nämä ominaisuudet muuttuvat automaattisesti myös {count} muussa kohteessa"
},
"plantDetection": {
"tryAgain": "Valitse eri laji"
},

View file

@ -284,6 +284,45 @@
"render": "Estació d'Ambulàncies"
}
},
"animal_shelter": {
"name": "Refugis d'animals",
"presets": {
"0": {
"title": "un refugi d'animals"
}
},
"tagRenderings": {
"2": {
"question": "Quin nom té aquest refugi d'animals?"
},
"6": {
"mappings": {
"0": {
"then": "Els animals romanen ací fins que son adoptats per un nou propietari"
},
"1": {
"then": "Els animals reben cures per a la resta de la seva vida"
},
"2": {
"then": "Els animals ferits es rehabiliten aquí fins que puguen ser alliberats de nou a la natura "
}
},
"question": "Quina és la finalitat del refugi d'animals?"
},
"7": {
"question": "Quan està obert aquest refugi d'animals?",
"render": "{opening_hours_table()}"
}
},
"title": {
"mappings": {
"0": {
"then": "{name}"
}
},
"render": "Refugi d'animals"
}
},
"artwork": {
"description": "Un mapa obert d'estàtues, busts, grafitis i altres obres d'art del tot el món",
"name": "Obres d'art",
@ -1226,7 +1265,7 @@
"Bicycle parking type": {
"mappings": {
"0": {
"then": "Bastidors de grapes"
"then": "Bastidors"
},
"1": {
"then": "Portarodes/bucles"
@ -1856,6 +1895,216 @@
},
"charging_station": {
"tagRenderings": {
"Authentication": {
"mappings": {
"4": {
"then": "L'autenticació mitjançant NFC està disponible"
},
"5": {
"then": "L'autenticació mitjançant targeta de pagament està disponible"
},
"6": {
"then": "L'autenticació mitjançant targeta de debit està disponible"
},
"7": {
"then": "Carregar aquí (també) és possible sense autenticació"
}
},
"question": "Quin tipus d'autenticació hi ha disponible a l'estació de càrrega?"
},
"Available_charging_stations (generated)": {
"mappings": {
"0": {
"then": "<b>Endoll de paret Schuko</b> sense pin a terra (CEE7/4 tipus F)"
},
"1": {
"then": "<b>Endoll de paret Schuko</b> sense pin a terra (CEE7/4 tipus F)"
},
"2": {
"then": "<b>Endoll de paret Europeu</b> amb pin a terra (CEE7/4 tipus E)"
},
"3": {
"then": "<b>Endoll de paret Europeu</b> amb pin a terra (CEE7/4 tipus E)"
},
"4": {
"then": "<b>CHAdeMo</b>"
},
"5": {
"then": "<b>CHAdeMo</b>"
},
"6": {
"then": "<b>Tipus 1 amb cable</b>"
},
"7": {
"then": "<b>Tipus 1 amb cable</b>"
},
"8": {
"then": "<b>Tipus 1 <i>sense</i> cable</b>"
},
"9": {
"then": "<b>Tipus 1 <i>sense</i> cable</b>(J1772)"
},
"10": {
"then": "<b>CSS Tipus 1</b> (també conegut com a Tipus 1 Combo)"
},
"11": {
"then": "<b>CSS Tipus 1</b> (també conegut com a Tipus 1 Combo)"
},
"12": {
"then": "<b>Supercarregador de Tesla"
},
"13": {
"then": "<b>Supercarregador de Tesla</b>"
},
"14": {
"then": "<b>Tipus 2</b> (mennekes)"
},
"15": {
"then": "<b>Tipus 2</b> (mennekes)"
},
"16": {
"then": "<b>CSS Tipus 2</b> (mennekes)"
},
"17": {
"then": "<b>CSS Tipus 2</b> (mennekes)"
}
}
},
"Network": {
"question": "Aquesta estació de càrrega forma part d'una xarxa?",
"render": "Part de la xarxa <b>{network}</b>"
},
"OH": {
"override": {
"question": "Quan està oberta aquesta estació de càrrega?"
}
},
"Operational status": {
"mappings": {
"0": {
"then": "Aquesta estació de càrrega funciona"
},
"1": {
"then": "Aquesta estació de carrega està trencada"
},
"2": {
"then": "Aquí està prevista una estació de recàrrega"
},
"4": {
"then": "Aquesta estació de recàrrega s'ha desactivat permanentment i ja no s'utilitza, però encara és visible"
}
},
"question": "Està en ús aquest punt de càrrega?"
},
"Operator": {
"mappings": {
"0": {
"then": "De fet, {operator} és la xarxa"
}
},
"question": "Qui és l'operadora d'aquesta estació de càrrega?",
"render": "Aquesta estació de càrrega l'opera {operator}"
},
"Parking:fee": {
"mappings": {
"0": {
"then": "No cal pagar una taxa addicional mentres carrega"
},
"1": {
"then": "Cal pagar una taxa addicional d'aparcament mentres carrega"
}
},
"question": "Cal pagar una taxa d'aparcament mentre es carrega?"
},
"Type": {
"mappings": {
"0": {
"then": "Aquí es poden carregar <b>bicicletes</b>"
},
"1": {
"then": "Aquí es poden carregar <b>cotxes</b>"
},
"2": {
"then": "Aquí es poden carregar <b>Scooters</b>"
},
"3": {
"then": "Aquí es poden carregar <b>camions o trailers</b>"
},
"4": {
"then": "Aquí es poden carregar <b>autobusos</b>"
}
},
"question": "Quins vehicles tenen permesa la càrrega aquí?"
},
"access": {
"mappings": {
"0": {
"then": "Qualsevol persona pot utilitzar aquesta estació de recàrrega (pot ser calgui un pagament)"
},
"1": {
"then": "Qualsevol persona pot utilitzar aquesta estació de recàrrega (pot ser calgui un pagament)"
},
"2": {
"then": "Sols clientes del lloc al que pertany aquest punt de càrrega poden utilitzar-lo <br/><span class='subtle'>p.e. un punt de càrrega d'un hotel que sols poden utilizar-los els hostes</span>"
},
"3": {
"then": "S'ha de sol·licitar una <b>clau</b> per a utilitzar aquest punt de càrrega<br/><span class='subtle'>p.e un punt de càrrega operat per un hotel nomes utilitzable pel seus hostes, els quals reben una clau des de recepció per a desbloquejar el punt de càrrega</span>"
},
"4": {
"then": "No accessible per al públic general (p.e. només accessible pels propietaris, empleats, ...)"
},
"5": {
"then": "Aquesta estació de càrrega és accessible al públic durant certes hores o condicions. Es poden aplicar restriccions, però es permet l'ús general."
}
},
"question": "Qui pot utilitzar aquesta estació de càrrega?",
"render": "L'accés està {access}"
},
"capacity": {
"question": "Quants vehicles poden carregar a la vegada?",
"render": "Aquí poden carregar {capacity} vehicles a l'hora"
},
"charge": {
"question": "Quant cal pagar per utilitzar aquesta estació de càrrega?",
"render": "Utilitzar aquesta estació de càrrega costa <b>{charge}</b>"
},
"email": {
"question": "Quin és el correu electrònic de l'operadora?",
"render": "En cas de problemes, envia un email a <a href='mailto:{email}'>{email}</a>"
},
"fee": {
"mappings": {
"0": {
"then": "Ús gratuït (sense autentificació)"
},
"1": {
"then": "Ús gratuït, però un s'ha d'autentificar"
},
"2": {
"then": "Ús gratuït"
},
"3": {
"then": "De pagament, però gratuït per als clients de l'hotel/bar/hospital/... que gestiona l'estació de càrrega"
},
"4": {
"then": "Ús de pagament"
}
},
"question": "Hi ha que pagar per utilitzar aquest punt de càrrega?"
},
"maxstay": {
"mappings": {
"0": {
"then": "No hi ha límit de temps per a deixar el teu vehicle aquí"
}
},
"question": "Quina és la quantitat màxima de temps que es permet permaneixer aquí?",
"render": "Un pot quedar-se com a màxim <b>{canonical(maxstay)}</b>"
},
"phone": {
"question": "A quin número es pot cridar si hi ha algun problema amb aquest punt de càrrega?",
"render": "En cas de problemes, truqueu a <a href='tel:{phone}'>{phone}</a>"
},
"rewritten-questions": {
"renderings": {
"0": {
@ -3653,7 +3902,7 @@
"then": "Aquesta és una botiga de kebabs"
},
"4": {
"then": "Això és un sandvitxeria"
"then": "Això és una botiga d'entrepans"
},
"5": {
"then": "Aquí es serveixen hamburgueses"
@ -3686,13 +3935,13 @@
"then": "Aquí es serveixen plats tailandesos"
}
},
"question": "Quin menjar es serveix aquí?",
"question": "Quin tipus de menjar es serveix aquí?",
"render": "Aquest lloc serveix principalment {cuisine}"
},
"Fastfood vs restaurant": {
"mappings": {
"0": {
"then": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seràn limitats i funcionals."
"then": "Aquest és un negoci de menjar ràpid, centrat en el servei ràpid. Si hi han seients disponibles, aquests seran limitats i funcionals."
},
"1": {
"then": "Un <b>restaurant</b>, centrat en crear una bona experiència on es serveix a taula"
@ -6665,7 +6914,7 @@
"name": "Botiga",
"presets": {
"0": {
"description": "Afegir una botiga nova",
"description": "Podeu especificar més endavant el que ven aquesta botiga.",
"title": "una botiga"
}
},
@ -6906,6 +7155,20 @@
}
},
"tagRenderings": {
"basketball-hoops": {
"mappings": {
"1": {
"then": "Aquest camp de bàsquet té dos cèrcols"
},
"2": {
"then": "Aquest camp de bàsquet té quatre cèrcols"
},
"3": {
"then": "Aquest camp de bàsquet té {hoops} cèrcols"
}
},
"question": "Quants cèrcols té aquesta pista?"
},
"sport-pitch-access": {
"mappings": {
"0": {
@ -6919,6 +7182,9 @@
},
"3": {
"then": "Privat - no accessible al públic"
},
"4": {
"then": "Accés públic"
}
},
"question": "Aquesta pista d'esports és accessible públicament?"
@ -6947,6 +7213,9 @@
"mappings": {
"0": {
"then": "Sempre accesible"
},
"1": {
"then": "Sempre accesible"
}
}
},
@ -6970,6 +7239,9 @@
"4": {
"then": "Aquí es juga al corfbol"
},
"5": {
"then": "Aquí es juga bàsquet"
},
"6": {
"then": "Açò és un skatepark"
}
@ -6993,6 +7265,12 @@
},
"4": {
"then": "La superfície és <b>formigó</b>"
},
"5": {
"then": "La superfície és <b> grava fina</b>"
},
"6": {
"then": "La superfície d'aquesta pista és Tartan, una superfície sintètica, lleugerament molla i porosa"
}
},
"question": "Quina és la superfície d'aquest camp esportiu?",
@ -7043,6 +7321,18 @@
},
"question": "Aquestes escales tenen un passamà?"
},
"incline": {
"mappings": {
"0": {
"then": "La direcció ascendent és {direction_absolute()}"
},
"1": {
"then": "La direcció descendent és {direction_absolute()}"
}
},
"question": "Quina és la inclinació d'aquestes escales?",
"render": "Aquestes escales tenen una inclinació de {incline}"
},
"multilevels": {
"override": {
"question": "Entre quines plantes estan aquestes escales?",
@ -7765,6 +8055,7 @@
}
},
"trail": {
"description": "Rutes marcades",
"name": "Camins",
"tagRenderings": {
"Color": {
@ -7781,6 +8072,19 @@
"3": {
"then": "Ruta groga"
}
},
"question": "Quin és el color de referència d'aquest sender?",
"render": "El color de referència és {colour}"
},
"Name": {
"question": "Quin és el nom d'aquest sender?",
"render": "Aquest sender s'anomena <b>{name}</b>"
},
"Operator tag": {
"mappings": {
"0": {
"then": "Aquest sender és mantingut per Natuurpunt"
}
}
},
"trail-length": {
@ -8110,16 +8414,26 @@
}
}
},
"2": {
"applicableUnits": {
"0": {
"human": "{quantity} A"
}
}
},
"3": {
"applicableUnits": {
"0": {
"human": "{quantity} metre"
"human": "{quantity} metre",
"humanSingular": "un metre"
},
"1": {
"human": "{quantity} centimetre"
"human": "{quantity} centimetre",
"humanSingular": "un centímetre"
},
"2": {
"human": "{quantity} mil·límetres"
"human": "{quantity} mil·límetres",
"humanSingular": "un mil·límetre"
},
"3": {
"human": "{quantity} peus"
@ -8137,12 +8451,37 @@
"humanShort": "{quantity} mph"
}
}
},
"5": {
"applicableUnits": {
"0": {
"human": "{quantity} minuts",
"humanSingular": "un minut"
},
"1": {
"human": "{quantity} hores",
"humanSingular": "una hora"
},
"2": {
"human": "{quantity} dies"
}
}
}
}
},
"usersettings": {
"description": "Una capa especial que no està pensada per mostrar-se en un mapa, però que s'utilitza per configurar la configuració de l'usuari",
"tagRenderings": {
"a11y-features": {
"mappings": {
"0": {
"then": "Activar les funcions d'accessibilitat quan s'utilitzen les tecles de fletxa per navegar pel mapa"
},
"1": {
"then": "Sempre habilita les característiques d'accessibilitat"
}
}
},
"all-questions-at-once": {
"mappings": {
"0": {
@ -8217,7 +8556,7 @@
"1": {
"then": {
"special": {
"text": "<b class='alert'>Tens {_unreadMessages}</b><br/>Open your inbox"
"text": "<b class='alert'>Tens {_unreadMessages} missatges </b><br/>Obri la safata d'entrada"
}
}
}
@ -8226,7 +8565,7 @@
"language_picker": {
"mappings": {
"0": {
"then": "L'idioma es va establir mitjançant un paràmetre d'URL i l'usuari no pot definir-lo.²"
"then": "L'idioma es va establir mitjançant un paràmetre d'URL i l'usuari no pot definir-lo."
}
}
},
@ -8262,6 +8601,9 @@
}
}
},
"show_crosshair": {
"questionHint": "Això pot ajudar a posicionar amb precisió un nou element"
},
"show_debug": {
"mappings": {
"0": {
@ -8402,22 +8744,37 @@
"question": "Venda de productes carnis"
},
"17": {
"question": "Venda de flors"
"question": "Venda de fruites"
},
"18": {
"question": "Venda de tiquets d'aparcament"
"question": "Venda de maduixes"
},
"19": {
"question": "Venda de flors"
},
"20": {
"question": "Venda de bitllets de transport públic"
"question": "Venda de tiquets d'aparcament"
},
"21": {
"question": "Venda de monedes premsades"
},
"22": {
"question": "Venda de bitllets de transport públic"
},
"23": {
"question": "Venda de llums de bicicletes"
},
"24": {
"question": "Venda de guants"
},
"25": {
"question": "Venda de kits de reparació de bicicletes"
},
"26": {
"question": "Venda de bombes de bicicletes"
},
"27": {
"question": "Venda de cadenat per a bicicletes"
}
}
}
@ -8506,6 +8863,12 @@
"15": {
"then": "Es venen productes carnis"
},
"16": {
"then": "Es ven fruita"
},
"17": {
"then": "Es venen maduixes"
},
"18": {
"then": "Es venen flors"
},
@ -8517,6 +8880,21 @@
},
"21": {
"then": "Es venen bitllets de transport públic"
},
"22": {
"then": "Es venen llums per a bicicletes"
},
"23": {
"then": "Es venen guants"
},
"24": {
"then": "Es venen kits de reparació de bicicletes"
},
"25": {
"then": "Es venen bombes de bicicletes"
},
"26": {
"then": "Es venen cadenats per a bicicletes"
}
},
"question": "Que ven aquesta màquina expenedora?",

View file

@ -5042,6 +5042,30 @@
"2": {
"1": "a CNC drill",
"2": "CNC drill"
},
"3": {
"1": "a multimedia studio",
"2": "multimedia studio"
},
"4": {
"1": "a sewing machine",
"2": "sewing machine"
},
"5": {
"1": "a woodworking workshop",
"2": "woodworking workshop"
},
"6": {
"1": "a ceramics workshop",
"2": "ceramics workshop"
},
"7": {
"1": "a metal workshop",
"2": "metal workshop"
},
"8": {
"1": "a bicycle repair workshop",
"2": "bicycle repair workshop"
}
}
}

View file

@ -27,6 +27,9 @@
"advertising": {
"name": "Reclame",
"presets": {
"12": {
"title": "een muurschildering"
},
"3": {
"description": "Een klein uithangbord voor buurtadvertenties, meestal gericht op voetgangers",
"title": "een uithangbord"
@ -47,9 +50,6 @@
"8": {
"description": "Een stuk groot, weerbestendig textiel met opgedrukte reclameboodschap die permanent aan de muur hangt",
"title": "een spandoek"
},
"12": {
"title": "een muurschildering"
}
},
"tagRenderings": {
@ -107,6 +107,9 @@
},
"title": {
"mappings": {
"10": {
"then": "Muurschildering"
},
"3": {
"then": "Aanplakzuil"
},
@ -124,9 +127,6 @@
},
"9": {
"then": "Aanplakzuil"
},
"10": {
"then": "Muurschildering"
}
}
}
@ -208,6 +208,15 @@
"1": {
"then": "Muurschildering"
},
"10": {
"then": "Azulejo (Spaanse siertegels)"
},
"11": {
"then": "Tegelwerk"
},
"12": {
"then": "Houtsculptuur"
},
"2": {
"then": "Schilderij"
},
@ -231,15 +240,6 @@
},
"9": {
"then": "Reliëf"
},
"10": {
"then": "Azulejo (Spaanse siertegels)"
},
"11": {
"then": "Tegelwerk"
},
"12": {
"then": "Houtsculptuur"
}
},
"question": "Wat voor soort kunstwerk is dit?",
@ -1791,6 +1791,27 @@
"1": {
"question": "Heeft een <div style='display: inline-block'><b><b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/CEE7_4F.svg'/></div>"
},
"10": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2 met kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div>"
},
"11": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div>"
},
"12": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div>"
},
"13": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (Een Type 2 met kabel en Tesla-logo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div>"
},
"14": {
"question": "Heeft een <div style='display: inline-block'><b><b>USB</b> om GSMs en kleine electronica op te laden</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div>"
},
"15": {
"question": "Heeft een <div style='display: inline-block'><b><b>Bosch Active Connect met 3 pinnen</b> aan een kabel</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/bosch-3pin.svg'/></div>"
},
"16": {
"question": "Heeft een <div style='display: inline-block'><b><b>Bosch Active Connect met 5 pinnen</b> aan een kabel</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/bosch-5pin.svg'/></div>"
},
"2": {
"question": "Heeft een <div style='display: inline-block'><b><b>Europese stekker</b> met aardingspin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div>"
},
@ -1814,27 +1835,6 @@
},
"9": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div>"
},
"10": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2 met kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div>"
},
"11": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div>"
},
"12": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger (destination)</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div>"
},
"13": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla supercharger (destination</b> (Een Type 2 met kabel en Tesla-logo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div>"
},
"14": {
"question": "Heeft een <div style='display: inline-block'><b><b>USB</b> om GSMs en kleine electronica op te laden</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/usb_port.svg'/></div>"
},
"15": {
"question": "Heeft een <div style='display: inline-block'><b><b>Bosch Active Connect met 3 pinnen</b> aan een kabel</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/bosch-3pin.svg'/></div>"
},
"16": {
"question": "Heeft een <div style='display: inline-block'><b><b>Bosch Active Connect met 5 pinnen</b> aan een kabel</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/bosch-5pin.svg'/></div>"
}
}
}
@ -1890,30 +1890,6 @@
"1": {
"then": "<b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)"
},
"2": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"3": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"4": {
"then": "<b>Chademo</b>"
},
"5": {
"then": "<b>Chademo</b>"
},
"6": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"7": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"8": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"9": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"10": {
"then": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)"
},
@ -1944,6 +1920,9 @@
"19": {
"then": "<b>Type 2 met kabel</b> (J1772)"
},
"2": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"20": {
"then": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)"
},
@ -1974,11 +1953,32 @@
"29": {
"then": "<b>Bosch Active Connect met 3 pinnen</b> aan een kabel"
},
"3": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"30": {
"then": "<b>Bosch Active Connect met 5 pinnen</b> aan een kabel"
},
"31": {
"then": "<b>Bosch Active Connect met 5 pinnen</b> aan een kabel"
},
"4": {
"then": "<b>Chademo</b>"
},
"5": {
"then": "<b>Chademo</b>"
},
"6": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"7": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"8": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"9": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
}
},
"question": "Welke aansluitingen zijn hier beschikbaar?"
@ -2172,6 +2172,24 @@
"1": {
"2": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"10": {
"2": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)"
},
"11": {
"2": "<b>Tesla Supercharger (destination)</b>"
},
"12": {
"2": "<b>Tesla supercharger (destination</b> (Een Type 2 met kabel en Tesla-logo)"
},
"13": {
"2": "<b>USB</b> om GSMs en kleine electronica op te laden"
},
"14": {
"2": "<b>Bosch Active Connect met 3 pinnen</b> aan een kabel"
},
"15": {
"2": "<b>Bosch Active Connect met 5 pinnen</b> aan een kabel"
},
"2": {
"2": "<b>Chademo</b>"
},
@ -2195,24 +2213,6 @@
},
"9": {
"2": "<b>Type 2 met kabel</b> (J1772)"
},
"10": {
"2": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)"
},
"11": {
"2": "<b>Tesla Supercharger (destination)</b>"
},
"12": {
"2": "<b>Tesla supercharger (destination</b> (Een Type 2 met kabel en Tesla-logo)"
},
"13": {
"2": "<b>USB</b> om GSMs en kleine electronica op te laden"
},
"14": {
"2": "<b>Bosch Active Connect met 3 pinnen</b> aan een kabel"
},
"15": {
"2": "<b>Bosch Active Connect met 5 pinnen</b> aan een kabel"
}
}
}
@ -2978,6 +2978,15 @@
"1": {
"then": "Dit fietspad is geplaveid"
},
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
},
"2": {
"then": "Dit fietspad is gemaakt van asfalt"
},
@ -3001,15 +3010,6 @@
},
"9": {
"then": "Dit fietspad is gemaakt van grind"
},
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
}
},
"question": "Waaruit is het oppervlak van het fietspad van gemaakt?",
@ -3058,6 +3058,15 @@
"1": {
"then": "Dit fietspad is geplaveid"
},
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
},
"2": {
"then": "Dit fietspad is gemaakt van asfalt"
},
@ -3081,15 +3090,6 @@
},
"9": {
"then": "Dit fietspad is gemaakt van grind"
},
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
}
},
"question": "Waaruit is het oppervlak van de straat gemaakt?",
@ -4138,6 +4138,21 @@
"1": {
"then": "Dit is een frituur"
},
"10": {
"then": "Dit is een Chinees restaurant"
},
"11": {
"then": "Dit is een Grieks restaurant"
},
"12": {
"then": "Dit is een Indisch restaurant"
},
"13": {
"then": "Dit is een Turks restaurant (dat meer dan enkel kebab verkoopt)"
},
"14": {
"then": "Dit is een Thaïs restaurant"
},
"2": {
"then": "Dit is een pastazaak"
},
@ -4161,21 +4176,6 @@
},
"9": {
"then": "Dit is een Frans restaurant"
},
"10": {
"then": "Dit is een Chinees restaurant"
},
"11": {
"then": "Dit is een Grieks restaurant"
},
"12": {
"then": "Dit is een Indisch restaurant"
},
"13": {
"then": "Dit is een Turks restaurant (dat meer dan enkel kebab verkoopt)"
},
"14": {
"then": "Dit is een Thaïs restaurant"
}
},
"question": "Welk soort gerechten worden hier geserveerd?",
@ -4516,6 +4516,30 @@
"2": {
"1": "een CNC-boormachine",
"2": "CNC-boormachine"
},
"3": {
"1": "een multimedia-studio",
"2": "multimedia-studio"
},
"4": {
"1": "een naaimachine",
"2": "naaimachine"
},
"5": {
"1": "een houtbewerkingsatelier",
"2": "houtbewerkingsatelier"
},
"6": {
"1": "een keramiekatelier",
"2": "keramiekatelier"
},
"7": {
"1": "een metaalatelier",
"2": "metaalatelier"
},
"8": {
"1": "een fietsherstelplaats",
"2": "fietsherstelplaats"
}
}
}
@ -5322,6 +5346,19 @@
}
}
},
"10": {
"options": {
"0": {
"question": "Alle Notes"
},
"1": {
"question": "Verberg import Notes"
},
"2": {
"question": "Toon enkel import Notes"
}
}
},
"2": {
"options": {
"0": {
@ -5377,19 +5414,6 @@
"question": "Toon enkel open Notes"
}
}
},
"10": {
"options": {
"0": {
"question": "Alle Notes"
},
"1": {
"question": "Verberg import Notes"
},
"2": {
"question": "Toon enkel import Notes"
}
}
}
},
"name": "OpenStreetMap Notes",
@ -5681,6 +5705,21 @@
"1": {
"then": "Dit is een normale parkeerplek."
},
"10": {
"then": "Deze parkeerplek is gereserveerd voor ouders met kinderen."
},
"11": {
"then": "Deze parkeerplek is gereserveerd voor personeel."
},
"12": {
"then": "Deze parkeerplek is gereserveerd voor taxis."
},
"13": {
"then": "Deze parkeerplek is gereserveerd voor voertuigen met een aanhanger."
},
"14": {
"then": "Deze parkeerplek is gereserveerd voor autodelen."
},
"2": {
"then": "Dit is een gehandicaptenparkeerplaats."
},
@ -5704,21 +5743,6 @@
},
"9": {
"then": "Deze parkeerplek is gereserveerd voor motoren."
},
"10": {
"then": "Deze parkeerplek is gereserveerd voor ouders met kinderen."
},
"11": {
"then": "Deze parkeerplek is gereserveerd voor personeel."
},
"12": {
"then": "Deze parkeerplek is gereserveerd voor taxis."
},
"13": {
"then": "Deze parkeerplek is gereserveerd voor voertuigen met een aanhanger."
},
"14": {
"then": "Deze parkeerplek is gereserveerd voor autodelen."
}
},
"question": "Wat voor parkeerplek is dit?"
@ -6285,6 +6309,21 @@
"1": {
"then": "Munten van 2 cent worden geaccepteerd"
},
"10": {
"then": "Munten van 20 rappen worden geaccepteerd"
},
"11": {
"then": "Munten van ½ frank worden geaccepteerd"
},
"12": {
"then": "Munten van 1 frank worden geaccepteerd"
},
"13": {
"then": "Munten van 2 frank worden geaccepteerd"
},
"14": {
"then": "Munten van 5 frank worden geaccepteerd"
},
"2": {
"then": "Munten van 5 cent worden geaccepteerd"
},
@ -6308,21 +6347,6 @@
},
"9": {
"then": "Munten van 10 rappen worden geaccepteerd"
},
"10": {
"then": "Munten van 20 rappen worden geaccepteerd"
},
"11": {
"then": "Munten van ½ frank worden geaccepteerd"
},
"12": {
"then": "Munten van 1 frank worden geaccepteerd"
},
"13": {
"then": "Munten van 2 frank worden geaccepteerd"
},
"14": {
"then": "Munten van 5 frank worden geaccepteerd"
}
},
"question": "Met welke munten kan je hier betalen?"
@ -6335,6 +6359,15 @@
"1": {
"then": "Biljetten van 10 euro worden geaccepteerd"
},
"10": {
"then": "Biljetten van 100 frank worden geaccepteerd"
},
"11": {
"then": "Biljetten van 200 frank worden geaccepteerd"
},
"12": {
"then": "Biljetten van 1000 frank worden geaccepteerd"
},
"2": {
"then": "Biljetten van 20 euro worden geaccepteerd"
},
@ -6358,15 +6391,6 @@
},
"9": {
"then": "Biljetten van 50 frank worden geaccepteerd"
},
"10": {
"then": "Biljetten van 100 frank worden geaccepteerd"
},
"11": {
"then": "Biljetten van 200 frank worden geaccepteerd"
},
"12": {
"then": "Biljetten van 1000 frank worden geaccepteerd"
}
},
"question": "Met welke bankbiljetten kan je hier betalen?"
@ -6685,30 +6709,6 @@
"1": {
"question": "Recycling van batterijen"
},
"2": {
"question": "Recycling van drankpakken"
},
"3": {
"question": "Recycling van blikken"
},
"4": {
"question": "Recycling van kleding"
},
"5": {
"question": "Recycling van frituurvet"
},
"6": {
"question": "Recycling van motorolie"
},
"7": {
"question": "Recycling van tl-buizen"
},
"8": {
"question": "Recycling van groen afval"
},
"9": {
"question": "Recycling van glazen flessen"
},
"10": {
"question": "Recycling van glas"
},
@ -6739,11 +6739,35 @@
"19": {
"question": "Recycling van restafval"
},
"2": {
"question": "Recycling van drankpakken"
},
"20": {
"question": "Recycling van inktpatronen"
},
"21": {
"question": "Recycling van fietsen"
},
"3": {
"question": "Recycling van blikken"
},
"4": {
"question": "Recycling van kleding"
},
"5": {
"question": "Recycling van frituurvet"
},
"6": {
"question": "Recycling van motorolie"
},
"7": {
"question": "Recycling van tl-buizen"
},
"8": {
"question": "Recycling van groen afval"
},
"9": {
"question": "Recycling van glazen flessen"
}
}
},
@ -6811,30 +6835,6 @@
"1": {
"then": "Drankpakken kunnen hier gerecycled worden"
},
"2": {
"then": "Blikken kunnen hier gerecycled worden"
},
"3": {
"then": "Kleren kunnen hier gerecycled worden"
},
"4": {
"then": "Frituurvet kan hier gerecycled worden"
},
"5": {
"then": "Motorolie kan hier gerecycled worden"
},
"6": {
"then": "TL-buizen kunnen hier gerecycled worden"
},
"7": {
"then": "Groen afval kan hier gerecycled worden"
},
"8": {
"then": "Organisch afval kan hier gerecycled worden"
},
"9": {
"then": "Glazen flessen kunnen hier gerecycled worden"
},
"10": {
"then": "Glas kan hier gerecycled worden"
},
@ -6865,6 +6865,9 @@
"19": {
"then": "Schoenen kunnen hier gerecycled worden"
},
"2": {
"then": "Blikken kunnen hier gerecycled worden"
},
"20": {
"then": "Kleine elektrische apparaten kunnen hier gerecycled worden"
},
@ -6879,6 +6882,27 @@
},
"24": {
"then": "Fietsen (en fietswrakken) kunnen hier gerecycled worden"
},
"3": {
"then": "Kleren kunnen hier gerecycled worden"
},
"4": {
"then": "Frituurvet kan hier gerecycled worden"
},
"5": {
"then": "Motorolie kan hier gerecycled worden"
},
"6": {
"then": "TL-buizen kunnen hier gerecycled worden"
},
"7": {
"then": "Groen afval kan hier gerecycled worden"
},
"8": {
"then": "Organisch afval kan hier gerecycled worden"
},
"9": {
"then": "Glazen flessen kunnen hier gerecycled worden"
}
},
"question": "Wat kan hier gerecycled worden?"
@ -7600,6 +7624,12 @@
"1": {
"then": "Deze lantaarn gebruikt LEDs"
},
"10": {
"then": "Deze lantaarn gebruikt hogedruknatriumlampen (oranje met wit)"
},
"11": {
"then": "Deze lantaarn wordt verlicht met gas"
},
"2": {
"then": "Deze lantaarn gebruikt gloeilampen"
},
@ -7623,12 +7653,6 @@
},
"9": {
"then": "Deze lantaarn gebruikt lagedruknatriumlampen (monochroom oranje)"
},
"10": {
"then": "Deze lantaarn gebruikt hogedruknatriumlampen (oranje met wit)"
},
"11": {
"then": "Deze lantaarn wordt verlicht met gas"
}
},
"question": "Wat voor verlichting gebruikt deze lantaarn?"
@ -8541,6 +8565,20 @@
"usersettings": {
"description": "Een speciale lag die niet getoond wordt op de kaart, maar die de instellingen van de gebruiker weergeeft",
"tagRenderings": {
"a11y-features": {
"mappings": {
"0": {
"then": "Schakel toegankelijkheidsmode aan wanneer op de pijltjestoetsen wordt geduwd om de kaart te bewegen"
},
"1": {
"then": "Schakel de toegankelijkheidsmode altijd aan"
},
"2": {
"then": "Gebruik geen toegankelijkheidsmode"
}
},
"question": "Wanneer moet de toegankelijkheidsmode ingeschakeld worden?"
},
"all-questions-at-once": {
"mappings": {
"0": {
@ -8596,8 +8634,12 @@
"mappings": {
"0": {
"then": "Sta kaartrotatie toe"
},
"1": {
"then": "Hou het noorden altijd naar boven"
}
}
},
"question": "Moet het noorden altijd naar boven getoond worden?"
},
"inbox": {
"mappings": {
@ -8607,12 +8649,29 @@
"text": "Ga naar je inbox"
}
}
},
"1": {
"then": {
"special": {
"text": "<b class='alert'>Je hebt {_unreadMessages} ongelezen berichten</b><br/>Ga naar je inbox"
}
}
}
}
},
"language_picker": {
"mappings": {
"0": {
"then": "De taal werd ingesteld via een URL-parameter en kan niet manueel ingesteld worden."
}
}
},
"mangrove-keys": {
"render": {
"after": "Iedereen die dit bestand bezit, kan met jouw identiteit wijzigingen maken"
"after": "Iedereen die dit bestand bezit, kan met jouw identiteit wijzigingen maken",
"special": {
"text": "Download de private sleutel van je Mangrove-account"
}
}
},
"picture-license": {
@ -8632,7 +8691,15 @@
},
"question": "Met welke licentie wil je je afbeeldingen toevoegen?"
},
"settings-link": {
"render": {
"special": {
"text": "Open je instellingen op OpenStreetMap.org"
}
}
},
"show_crosshair": {
"question": "Moet er een kruisje getoond worden in het centrum van je display?",
"questionHint": "Dit kan helpen om nieuwe elementen accuraat te plaatsen"
},
"show_debug": {
@ -8729,30 +8796,6 @@
"1": {
"question": "Verkoop van dranken"
},
"2": {
"question": "Verkoop van snoep"
},
"3": {
"question": "Verkoop van eten"
},
"4": {
"question": "Verkoop van sigaretten"
},
"5": {
"question": "Verkoop van condooms"
},
"6": {
"question": "Verkoop van koffie"
},
"7": {
"question": "Verkoop van water"
},
"8": {
"question": "Verkoop van kranten"
},
"9": {
"question": "Verkoop van fietsbinnenbanden"
},
"10": {
"question": "Verkoop van melk"
},
@ -8783,6 +8826,9 @@
"19": {
"question": "Verkoop van bloemen"
},
"2": {
"question": "Verkoop van snoep"
},
"23": {
"question": "Verkoop van fietslampjes"
},
@ -8797,6 +8843,27 @@
},
"27": {
"question": "Verkoop van fietssloten"
},
"3": {
"question": "Verkoop van eten"
},
"4": {
"question": "Verkoop van sigaretten"
},
"5": {
"question": "Verkoop van condooms"
},
"6": {
"question": "Verkoop van koffie"
},
"7": {
"question": "Verkoop van water"
},
"8": {
"question": "Verkoop van kranten"
},
"9": {
"question": "Verkoop van fietsbinnenbanden"
}
}
}
@ -8837,30 +8904,6 @@
"1": {
"then": "Snoep wordt verkocht"
},
"2": {
"then": "Eten wordt verkocht"
},
"3": {
"then": "Sigaretten worden verkocht"
},
"4": {
"then": "Condooms worden verkocht"
},
"5": {
"then": "Koffie wordt verkocht"
},
"6": {
"then": "Drinkwater wordt verkocht"
},
"7": {
"then": "Kranten worden verkocht"
},
"8": {
"then": "Binnenbanden voor fietsen worden verkocht"
},
"9": {
"then": "Melk wordt verkocht"
},
"10": {
"then": "Brood wordt verkocht"
},
@ -8891,6 +8934,9 @@
"19": {
"then": "Parkeerkaarten worden verkocht"
},
"2": {
"then": "Eten wordt verkocht"
},
"21": {
"then": "Openbaar vervoerkaartjes worden verkocht"
},
@ -8908,6 +8954,27 @@
},
"26": {
"then": "Fietssloten worden verkocht"
},
"3": {
"then": "Sigaretten worden verkocht"
},
"4": {
"then": "Condooms worden verkocht"
},
"5": {
"then": "Koffie wordt verkocht"
},
"6": {
"then": "Drinkwater wordt verkocht"
},
"7": {
"then": "Kranten worden verkocht"
},
"8": {
"then": "Binnenbanden voor fietsen worden verkocht"
},
"9": {
"then": "Melk wordt verkocht"
}
},
"question": "Wat verkoopt deze verkoopautomaat?",
@ -9200,4 +9267,4 @@
"render": "windturbine"
}
}
}
}

View file

@ -464,7 +464,7 @@
"description": "Aquest mapa mostra xarxes de nodes ciclistes i et permet afegir-ne de nous de manera senzilla",
"layers": {
"0": {
"name": "enllaços node a node",
"name": "Enllaços node a node",
"tagRenderings": {
"node2node-survey:date": {
"override": {
@ -483,12 +483,21 @@
}
},
"1": {
"name": "nodes",
"name": "Nodes",
"presets": {
"0": {
"title": "un node ciclista"
}
},
"tagRenderings": {
"node-expected_rcn_route_relations": {
"question": "A quants altes nodes ciclistes enllaça aquest node?",
"render": "Aquest node enllaça a {expected_rcn_route_relations} altres nodes ciclistes."
},
"node-rxn_ref": {
"question": "Quin és el número de referència d'aquest node ciclista?",
"render": "Aquest node ciclista té la referència número {rcn_ref}"
},
"node-survey:date": {
"override": {
"question": "Quan va ser sondejat aquest node ciclista per última vegada?",
@ -746,6 +755,18 @@
"layers": {
"0": {
"override": {
"filter+": {
"0": {
"options": {
"1": {
"question": "Només mostra freiduries que utilitzen oli vegetal"
},
"2": {
"question": "Només mostra freiduries que utilitzen oli animal"
}
}
}
},
"name": "Botigues de patates"
}
}
@ -785,6 +806,9 @@
}
}
},
"guideposts": {
"title": "Pal guia"
},
"hackerspaces": {
"description": "En aquest mapa podeu veure els hackerspaces, afegir un nou hackerspace o actualitzar les dades directament",
"shortDescription": "Un mapa dels hackerspaces",
@ -820,6 +844,10 @@
"description": "En aquest mapa trobareu hotels a la vostra zona",
"title": "Hotels"
},
"icecream": {
"description": "Un mapa que mostra les gelateries i les màquines expenedores de gelats",
"title": "Gelat"
},
"indoors": {
"description": "En aquest mapa es mostren els llocs interiors accessibles al públic",
"title": "Interiors"
@ -840,6 +868,111 @@
},
"title": "Vorals i encreuaments"
},
"mapcomplete-changes": {
"description": "Aquest mapa mostra tots els canvis fets amb MapComplete",
"layers": {
"0": {
"description": "Mostra tots els canvis de MapComplete",
"filter": {
"0": {
"options": {
"0": {
"question": "El nom del tema conté {search}"
}
}
},
"2": {
"options": {
"0": {
"question": "Fet pel col·laborador {search}"
}
}
},
"3": {
"options": {
"0": {
"question": "<b>No</b> fet pel col·laborador {search}"
}
}
},
"4": {
"options": {
"0": {
"question": "Fet abans de {search}"
}
}
},
"5": {
"options": {
"0": {
"question": "Fet després de {search}"
}
}
},
"6": {
"options": {
"0": {
"question": "Idioma de l'usuari (codi iso) {search}"
}
}
},
"7": {
"options": {
"0": {
"question": "Fet amb l'amfitrió {search}"
}
}
},
"8": {
"options": {
"0": {
"question": "El conjunt de canvis ha afegit almenys una imatge"
}
}
}
},
"tagRenderings": {
"contributor": {
"question": "Quin col·laborador va fer aquest canvi?",
"render": "Canvi fet per <a href='https://openstreetmap.org/user/{user}' target='_blank'>{user}</a>"
},
"host": {
"question": "Amb quin amfitrió (lloc web) es va fer aquest canvi?",
"render": "Canviat amb <a href='{host}'>{host}</a>"
},
"locale": {
"question": "Amb quina configuració regional (idioma) s'ha fet aquest canvi?",
"render": "La configuració regional de l'usuari és {locale}"
},
"show_changeset_id": {
"render": "Conjunt de canvi <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>"
},
"theme-id": {
"question": "Quin tema es va utilitzar per fer aquest canvi?",
"render": "Canvi amb el tema <a href='https://mapcomplete.org/{theme}'>{theme}</a>"
},
"version": {
"question": "Quina versió de MapComplete es va utilitzar per fer aquest canvi?",
"render": "Fet amb {editor}"
}
},
"title": {
"render": "Conjunt de canvis per a {theme}"
}
},
"1": {
"override": {
"tagRenderings+": {
"0": {
"render": "Es pot trobar més estadística <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>aquí</a>"
}
}
}
}
},
"shortDescription": "Mostra els canvis fets amb MapComplete",
"title": "Canvis fets amb MapComplete"
},
"maproulette": {
"description": "Tema que mostra les tasques de MapRoulette, que us permet cercar-les, filtrar-les i solucionar-les.",
"title": "Tasques de MapRoulette"

24
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "mapcomplete",
"version": "0.36.11",
"version": "0.36.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mapcomplete",
"version": "0.36.11",
"version": "0.36.12",
"license": "GPL-3.0-or-later",
"dependencies": {
"@rgossiaux/svelte-headlessui": "^1.0.2",
@ -83,6 +83,7 @@
"@types/xml2js": "^0.4.9",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"@vitejs/plugin-basic-ssl": "^1.0.2",
"assert": "^2.0.0",
"chai": "^4.3.6",
"dependency-cruiser": "^10.4.0",
@ -4608,6 +4609,18 @@
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
},
"node_modules/@vitejs/plugin-basic-ssl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.2.tgz",
"integrity": "sha512-DKHKVtpI+eA5fvObVgQ3QtTGU70CcCnedalzqmGSR050AzKZMdUzgC8KmlOneHWH8dF2hJ3wkC9+8FDVAaDRCw==",
"dev": true,
"engines": {
"node": ">=14.6.0"
},
"peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
}
},
"node_modules/@vitest/expect": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.28.3.tgz",
@ -17096,6 +17109,13 @@
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
},
"@vitejs/plugin-basic-ssl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.2.tgz",
"integrity": "sha512-DKHKVtpI+eA5fvObVgQ3QtTGU70CcCnedalzqmGSR050AzKZMdUzgC8KmlOneHWH8dF2hJ3wkC9+8FDVAaDRCw==",
"dev": true,
"requires": {}
},
"@vitest/expect": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.28.3.tgz",

View file

@ -1,6 +1,6 @@
{
"name": "mapcomplete",
"version": "0.36.11",
"version": "0.36.12",
"repository": "https://github.com/pietervdvn/MapComplete",
"description": "A small website to edit OSM easily",
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
@ -16,11 +16,18 @@
"Alternatively, you can override the `osm` credentials using the environment variables `VITE_OSM_OAUTH_CLIENT_ID` and `VITE_OSM_OAUTH_SECRET`"
],
"oauth_credentials": {
"#": "This client-id is registered by 'MapComplete' on osm.org",
"#": "This client-id is registered by 'MapComplete' on OpenStreetMap.org",
"oauth_client_id": "K93H1d8ve7p-tVLE1ZwsQ4lAFLQk8INx5vfTLMu5DWk",
"oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg",
"url": "https://www.openstreetmap.org"
},
"disabled:oauth_credentials": {
"##": "DEV",
"#": "This client-id is registered by 'MapComplete' on https://master.apis.dev.openstreetmap.org/",
"oauth_client_id": "BAPPMRuojjFsY__0APmScr1hbebYj1GlDbV6S5TsUbo",
"oauth_secret": "Lq1UKYAySRfQfwgFctGvlGrfxbGHQwggheE52HIGrO8",
"url": "https://master.apis.dev.openstreetmap.org"
},
"api_keys": {
"#": "Various API-keys for various services. Feel free to reuse those in another MapComplete-hosted version",
"imgur": "7070e7167f0a25a",
@ -36,8 +43,9 @@
},
"scripts": {
"start": "npm run generate:layeroverview && npm run strt",
"#strt:https": "Start in HTTPS mode. Makes a few things a bit harder, but allows to debug on Android with logging in",
"strt:https": "vite --host | sed 's/localhost:/127.0.0.1:/g'",
"strt": "vite --host | sed 's/localhost:/127.0.0.1:/g'",
"strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html assets/templates/*.svg assets/templates/fonts/*.ttf",
"watch:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css --watch",
"generate:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css",
"generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts",
@ -72,9 +80,10 @@
"generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
"prepare-deploy": "npm run generate:service-worker && ./scripts/prepare-build.sh && npm run build",
"build": "./scripts/build.sh",
"lint": "npm run lint:prettier && npm run lint:eslint",
"lint": "npm run lint:prettier && npm run lint:eslint && npm run lint:themes",
"lint:eslint": "eslint ./src",
"lint:prettier": "prettier --check '**/*.ts' '**/*.svelte'",
"lint:themes": "vite-node scripts/lint.ts",
"format": "prettier --write '**/*.ts' '**/*.svelte'",
"clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
"clean": "rm -rf .cache/ && (find *.html | grep -v \"^\\(404\\|index\\|land\\|privacy\\|test\\|studio\\|theme\\|style_test\\|statistics\\|leaderboard\\).html\" | xargs -r rm) && (ls | grep \"^index_[a-zA-Z_-]\\+\\.ts$\" | xargs -r rm)",
@ -172,6 +181,7 @@
"@types/xml2js": "^0.4.9",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"@vitejs/plugin-basic-ssl": "^1.0.2",
"assert": "^2.0.0",
"chai": "^4.3.6",
"dependency-cruiser": "^10.4.0",

View file

@ -777,6 +777,10 @@ video {
float: left;
}
.m-8 {
margin: 2rem;
}
.m-4 {
margin: 1rem;
}
@ -789,10 +793,6 @@ video {
margin: 0px;
}
.m-8 {
margin: 2rem;
}
.m-2 {
margin: 0.5rem;
}
@ -1059,6 +1059,10 @@ video {
display: contents;
}
.\!contents {
display: contents !important;
}
.list-item {
display: list-item;
}
@ -1106,6 +1110,10 @@ video {
height: fit-content;
}
.h-16 {
height: 4rem;
}
.h-0 {
height: 0px;
}
@ -1134,10 +1142,6 @@ video {
height: 1.25rem;
}
.h-16 {
height: 4rem;
}
.h-48 {
height: 12rem;
}
@ -1202,6 +1206,10 @@ video {
width: 1.5rem;
}
.w-16 {
width: 4rem;
}
.w-screen {
width: 100vw;
}
@ -1236,14 +1244,14 @@ video {
width: 2.75rem;
}
.w-16 {
width: 4rem;
}
.w-64 {
width: 16rem;
}
.w-1\/2 {
width: 50%;
}
.w-auto {
width: auto;
}
@ -2249,6 +2257,9 @@ video {
--catch-detail-foregroundcolor: white;
--catch-detail-color-contrast: #fb3afb;
--image-carousel-height: 350px;
/** Technical value, used by icon.svelte
*/
--svg-color: #000000;
}
/***********************************************************************\
@ -2794,6 +2805,10 @@ a.link-underline {
overflow: visible !important;
}
svg.apply-fill path {
fill: var(--svg-color)
}
.compass_arrow {
width: calc( 2.5rem - 1px ) ;
height: calc( 2.5rem - 1px )

View file

@ -66,7 +66,7 @@
width: 3rem;
max-height: 3rem;
margin-right: 1rem;
margin-left: 1rem;
margin-left: 0.5rem;
}
.mapping-icon-large {
@ -76,7 +76,7 @@
margin-top: 0.5rem;
margin-bottom: 0.5rem;
margin-right: 1.5rem;
margin-left: 1.5rem;
margin-left: 0.5rem;
}

View file

@ -6,6 +6,7 @@ import { Utils } from "../src/Utils"
import Validators from "../src/UI/InputElement/Validators"
import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts"
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
import Constants from "../src/Models/Constants"
const metainfo = {
type: "One of the inputValidator types",
@ -199,11 +200,12 @@ function extractHintsFrom(
if (hints["suggestions"]) {
const suggestions = hints["suggestions"]
const f = new Function("{ layers, themes, validators }", suggestions)
const f = new Function("{ layers, themes, validators, Constants }", suggestions)
hints["suggestions"] = f({
layers: AllSharedLayers.sharedLayers,
themes: AllKnownLayouts.allKnownLayouts,
validators: Validators,
Constants: Constants
})
}
return hints

View file

@ -13,6 +13,11 @@ import { Utils } from "../src/Utils"
import Constants from "../src/Models/Constants"
export default class GenerateImageAnalysis extends Script {
/**
* Max N in `image:N`-keys and `imageN` keys
* @private
*/
private static readonly maxImageIndex = 31
constructor() {
super(
[
@ -57,8 +62,9 @@ export default class GenerateImageAnalysis extends Script {
}
await this.fetchImages("image", datapath, refresh)
await this.fetchImages("image:streetsign", datapath, refresh)
for (let i = 0; i < 5; i++) {
for (let i = 0; i < GenerateImageAnalysis.maxImageIndex; i++) {
await this.fetchImages("image:" + i, datapath, refresh)
await this.fetchImages("image" + i, datapath, refresh)
}
}
@ -120,11 +126,16 @@ export default class GenerateImageAnalysis extends Script {
imageSource[feature.properties["image:streetsign"]] =
feature.properties.id + " (streetsign)"
for (let i = 0; i < 10; i++) {
for (let i = 0; i < GenerateImageAnalysis.maxImageIndex; i++) {
allImages.add(feature.properties["image:" + i])
imageSource[
feature.properties["image:" + i]
] = `${feature.properties.id} (image:${i})`
allImages.add(feature.properties["image" + i])
imageSource[
feature.properties["image" + i]
] = `${feature.properties.id} (image${i})`
}
}
allImages.delete(undefined)
@ -442,7 +453,7 @@ export default class GenerateImageAnalysis extends Script {
const imageBackupPath = args[0]
await this.downloadData(datapath, cached)
await this.downloadViews(datapath)
// await this.downloadViews(datapath)
await this.downloadMetadata(datapath)
await this.downloadAllImages(datapath, imageBackupPath)
this.analyze(datapath)

View file

@ -6,68 +6,99 @@ function genImages(dryrun = false) {
const blacklist: string[] = [
"add",
"addSmall",
"back",
"blocked",
"brick_wall",
"brick_wall_raw",
"brick_wall_round",
"brick_wall_square",
"bug",
"center",
"checkmark",
"clock",
"close",
"community",
"compass",
"compass_arrow",
"confirm",
"copyright",
"cross",
"cross_bottom_right",
"crosshair",
"crosshair_locked",
"crosshair-locked",
"delete_not_allowed",
"direction_gradient",
"direction_stroke",
"duplicate",
"elevator",
"elevator_wheelchair",
"liberapay",
"length_crosshair",
"speech_bubble_black_outline",
"square",
"star_half",
"star_outline",
"star",
"osm_logo_us",
"triangle",
"teardrop_with_hole_green",
"SocialImageForeground",
"wikipedia",
"Upload",
"pin",
"mapillary_black",
"plantnet_logo",
"mastodon",
"move-arrows",
"mapcomplete_logo",
"logo",
"logout",
"hand",
"help",
"home",
"reload",
"min",
"plus",
"not_found",
"osm_logo_us",
"party",
"eye",
"filter",
"filter_disable",
"floppy",
"eye",
"gear",
"gender_bi",
"compass",
"blocked",
"brick_wall",
"brick_wall_raw",
"brick_wall_round",
"bug",
"back",
"gender_inter",
"gender_female",
"gender_male",
"gender_trans",
"gender_queer",
"generic_map",
"gps_arrow",
"hand",
"help",
"home",
"length_crosshair",
"length-crosshair",
"liberapay",
"location",
"location_empty",
"location_locked",
"location_refused",
"location-refused",
"location_unlocked",
"logo",
"logout",
"mapcomplete_logo",
"mapillary",
"mapillary_black",
"mastodon",
"min",
"move-arrows",
"move_confirm",
"move_not_allowed",
"not_found",
"osm_logo_us",
"osm-logo-us",
"party",
"person",
"pin",
"plantnet_logo",
"plus",
"reload",
"ring",
"robot",
"SocialImageForeground",
"speech_bubble_black_outline",
"square",
"star",
"star_half",
"star_outline",
"teardrop",
"teardrop_with_hole_green",
"translate",
"triangle",
"Upload",
"wikidata",
"wikimedia-commons-white",
"wikimedia_commons_white",
"wikipedia",
].map((s) => s.toLowerCase())
const dir = fs.readdirSync("./assets/svg")
let module =
'import Img from "./UI/Base/Img";\nimport {FixedUiElement} from "./UI/Base/FixedUiElement";\n\n/* @deprecated */\nexport default class Svg {\n\n\n'
'import Img from "./UI/Base/Img";\n\n/* @deprecated */\nexport default class Svg {\n\n\n'
for (const path of dir) {
if (path.endsWith("license_info.json")) {
continue

View file

@ -16,9 +16,9 @@ export NODE_OPTIONS="--max-old-space-size=16384"
npm run generate:editor-layer-index &&
npm run prep:layeroverview &&
npm run generate && # includes a single "refresh:layeroverview". Resetting the files is unnecessary as they are not in there in the first place
npm run generate:mapcomplete-changes-theme &&
npm run refresh:layeroverview && # run refresh:layeroverview a second time to propagate all calls
npm run refresh:layeroverview && # run refresh:layeroverview a third time to fix some issues with the favourite layer all calls
npm run generate:mapcomplete-changes-theme &&
npm run generate:layouts

View file

@ -153,11 +153,7 @@ export default class GeoLocationHandler {
const features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([])
this.currentUserLocation = new StaticFeatureSource(features)
let i = 0
this.geolocationState.currentGPSLocation.addCallbackAndRun((location) => {
if (location === undefined) {
return
}
this.geolocationState.currentGPSLocation.addCallbackAndRunD((location) => {
const properties = {
id: "gps-" + i,
"user:location": "yes",
@ -200,7 +196,6 @@ export default class GeoLocationHandler {
)
})
features.ping()
let i = 0
this.currentUserLocation?.features?.addCallbackAndRunD(([location]: [Feature<Point>]) => {
if (location === undefined) {
return
@ -231,7 +226,6 @@ export default class GeoLocationHandler {
const feature = JSON.parse(JSON.stringify(location))
feature.properties.id = "gps/" + features.data.length
i++
features.data.push(feature)
features.ping()
})

View file

@ -1,13 +1,11 @@
import ImageProvider, { ProvidedImage } from "./ImageProvider"
import BaseUIElement from "../../UI/BaseUIElement"
import Svg from "../../Svg"
import { WikimediaImageProvider } from "./WikimediaImageProvider"
import Wikidata from "../Web/Wikidata"
import SvelteUIElement from "../../UI/Base/SvelteUIElement"
import * as Wikidata_icon from "../../assets/svg/Wikidata.svelte"
export class WikidataImageProvider extends ImageProvider {
public apiUrls(): string[] {
return Wikidata.neededUrls
}
public static readonly singleton = new WikidataImageProvider()
public readonly defaultKeyPrefixes = ["wikidata"]
@ -15,8 +13,12 @@ export class WikidataImageProvider extends ImageProvider {
super()
}
public apiUrls(): string[] {
return Wikidata.neededUrls
}
public SourceIcon(): BaseUIElement {
return Svg.wikidata_svg()
return new SvelteUIElement(Wikidata_icon)
}
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {

View file

@ -4,6 +4,8 @@ import Svg from "../../Svg"
import { Utils } from "../../Utils"
import { LicenseInfo } from "./LicenseInfo"
import Wikimedia from "../Web/Wikimedia"
import SvelteUIElement from "../../UI/Base/SvelteUIElement"
import Wikimedia_commons_white from "../../assets/svg/Wikimedia_commons_white.svelte"
/**
* This module provides endpoints for wikimedia and others
@ -70,7 +72,7 @@ export class WikimediaImageProvider extends ImageProvider {
}
SourceIcon(): BaseUIElement {
return Svg.wikimedia_commons_white_svg().SetStyle("width:2em;height: 2em")
return new SvelteUIElement(Wikimedia_commons_white).SetStyle("width:2em;height: 2em")
}
public PrepUrl(value: string): ProvidedImage {

View file

@ -399,11 +399,12 @@ export class OsmConnection {
return id
}
public static GpxTrackVisibility = ["private", "public", "trackable", "identifiable"] as const
public async uploadGpxTrack(
gpx: string,
options: {
description: string
visibility: "private" | "public" | "trackable" | "identifiable"
visibility: (typeof OsmConnection.GpxTrackVisibility)[number]
filename?: string
/**
* Some words to give some properties;
@ -425,11 +426,14 @@ export class OsmConnection {
const contents = {
file: gpx,
description: options.description ?? "",
description: options.description,
tags: options.labels?.join(",") ?? "",
visibility: options.visibility,
}
if (!contents.description) {
throw "The description of a GPS-trace cannot be the empty string, undefined or null"
}
const extras = {
file:
'; filename="' +

View file

@ -487,12 +487,6 @@ export default class SimpleMetaTaggers {
feature.properties._isOpen = "yes"
return true
}
console.log(
"Calculating opening hours for",
feature.properties.name,
":",
feature.properties.opening_hours
)
// _isOpen is calculated dynamically on every call
Object.defineProperty(feature.properties, "_isOpen", {

View file

@ -50,6 +50,11 @@ export default class ThemeViewStateHashActor {
if (!!hash) {
// There is still a hash
// We _only_ have to (at most) close the overlays in this case
if (state.previewedImage.data) {
state.previewedImage.setData(undefined)
return
}
const parts = hash.split(";")
if (parts.indexOf("background") < 0) {
state.guistate.backgroundLayerSelectionIsOpened.setData(false)
@ -176,6 +181,10 @@ export default class ThemeViewStateHashActor {
private back() {
const state = this._state
if (state.previewedImage.data) {
state.previewedImage.setData(undefined)
return
}
// history.pushState(null, null, window.location.pathname);
if (state.selectedElement.data) {
state.selectedElement.setData(undefined)

View file

@ -116,28 +116,42 @@ export default class Constants {
* These are the values that are allowed to use as 'backdrop' icon for a map pin
*/
private static readonly _defaultPinIcons = [
"pin",
"square",
"circle",
"none",
"pin",
"person",
"plus",
"ring",
"star",
"teardrop",
"triangle",
"checkmark",
"clock",
"close",
"crosshair",
"help",
"home",
"invalid",
"location",
"location_empty",
"location_locked",
"note",
"resolved",
"ring",
"scissors",
"teardrop",
"teardrop_with_hole_green",
"triangle",
"brick_wall_square",
"brick_wall_round",
"gps_arrow",
"checkmark",
"help",
"clock",
"invalid",
"close",
"invalid",
"heart",
"heart_outline",
"link",
"confirm",
"direction",
"not_found",
"mastodon",
"party",
"addSmall",
] as const
public static readonly defaultPinIcons: string[] = <any>Constants._defaultPinIcons

View file

@ -3,6 +3,7 @@ import { UIEventSource } from "../Logic/UIEventSource"
import UserRelatedState from "../Logic/State/UserRelatedState"
import { Utils } from "../Utils"
import { LocalStorageSource } from "../Logic/Web/LocalStorageSource"
import Zoomcontrol from "../UI/Zoomcontrol"
export type ThemeViewTabStates = (typeof MenuState._themeviewTabs)[number]
export type MenuViewTabStates = (typeof MenuState._menuviewTabs)[number]
@ -114,7 +115,36 @@ export class MenuState {
name: "background",
showOverOthers: true,
},
{
toggle: this.communityIndexPanelIsOpened,
name: "community",
showOverOthers: true,
},
{
toggle: this.privacyPanelIsOpened,
name: "privacy",
showOverOthers: true,
},
{
toggle: this.filtersPanelIsOpened,
name: "filters",
showOverOthers: true,
},
]
for (const toggle of this.allToggles) {
toggle.toggle.addCallback((isOpen) => {
if (!isOpen) {
this.resetZoomIfAllClosed()
}
})
}
}
private resetZoomIfAllClosed() {
if (this.isSomethingOpen()) {
return
}
Zoomcontrol.resetzoom()
}
public openFilterView(highlightLayer?: LayerConfig | string) {
@ -146,27 +176,23 @@ export class MenuState {
this.highlightedUserSetting.setData(highlightTagRendering)
}
public isSomethingOpen(): boolean {
return this.allToggles.some((t) => t.toggle.data)
}
/**
* Close all floatOvers.
* Returns 'true' if at least one menu was opened
*/
public closeAll(): boolean {
const toggles = [
this.communityIndexPanelIsOpened,
this.privacyPanelIsOpened,
this.backgroundLayerSelectionIsOpened,
this.filtersPanelIsOpened,
this.menuIsOpened,
this.themeIsOpened,
]
let somethingIsOpen = false
for (const t of toggles) {
somethingIsOpen = t.data
t.setData(false)
if (somethingIsOpen) {
let somethingWasOpen = false
for (const t of this.allToggles) {
somethingWasOpen = t.toggle.data
t.toggle.setData(false)
if (somethingWasOpen) {
break
}
}
return somethingIsOpen
return somethingWasOpen
}
}

View file

@ -1,14 +1,4 @@
import {
Concat,
Conversion,
DesugaringContext,
DesugaringStep,
Each,
Fuse,
On,
Pass,
SetDefault,
} from "./Conversion"
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
import { PrepareLayer } from "./PrepareLayer"
import { LayerConfigJson } from "../Json/LayerConfigJson"
@ -27,9 +17,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
constructor(state: DesugaringContext) {
super(
"Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form",
"Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'",
[],
"SubstituteLayer"
"SubstituteLayer",
)
this._state = state
}
@ -80,21 +70,35 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
(found["tagRenderings"] ?? []).length > 0
) {
context.err(
`When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`
`When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`,
)
}
try {
const trPlus = json["override"]["tagRenderings+"]
if(trPlus){
let index = found.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
if(index < 0){
index = found.tagRenderings.length
}
found.tagRenderings.splice(index, 0, ...trPlus)
delete json["override"]["tagRenderings+"]
}
Utils.Merge(json["override"], found)
layers.push(found)
} catch (e) {
context.err(
`Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(
json["override"]
)}`
json["override"],
)}`,
)
}
if (json["hideTagRenderingsWithLabels"]) {
if (typeof json["hideTagRenderingsWithLabels"] === "string") {
throw "At " + context + ".hideTagRenderingsWithLabels should be a list containing strings, you specified a string"
}
const hideLabels: Set<string> = new Set(json["hideTagRenderingsWithLabels"])
// These labels caused at least one deletion
const usedLabels: Set<string> = new Set<string>()
@ -107,9 +111,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
usedLabels.add(labels[forbiddenLabel])
context.info(
"Dropping tagRendering " +
tr["id"] +
" as it has a forbidden label: " +
labels[forbiddenLabel]
tr["id"] +
" as it has a forbidden label: " +
labels[forbiddenLabel],
)
continue
}
@ -118,7 +122,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
if (hideLabels.has(tr["id"])) {
usedLabels.add(tr["id"])
context.info(
"Dropping tagRendering " + tr["id"] + " as its id is a forbidden label"
"Dropping tagRendering " + tr["id"] + " as its id is a forbidden label",
)
continue
}
@ -127,10 +131,10 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
usedLabels.add(tr["group"])
context.info(
"Dropping tagRendering " +
tr["id"] +
" as its group `" +
tr["group"] +
"` is a forbidden label"
tr["id"] +
" as its group `" +
tr["group"] +
"` is a forbidden label",
)
continue
}
@ -141,8 +145,8 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
if (unused.length > 0) {
context.err(
"This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " +
unused.join(", ") +
"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore"
unused.join(", ") +
"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore",
)
}
found.tagRenderings = filtered
@ -159,7 +163,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
super(
"Adds the default layers, namely: " + Constants.added_by_default.join(", "),
["layers"],
"AddDefaultLayers"
"AddDefaultLayers",
)
this._state = state
}
@ -183,10 +187,10 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
if (alreadyLoaded.has(v.id)) {
context.warn(
"Layout " +
context +
" already has a layer with name " +
v.id +
"; skipping inclusion of this builtin layer"
context +
" already has a layer with name " +
v.id +
"; skipping inclusion of this builtin layer",
)
continue
}
@ -202,14 +206,14 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
super(
"For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)",
["layers"],
"AddImportLayers"
"AddImportLayers",
)
}
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
if (!(json.enableNoteImports ?? true)) {
context.info(
"Not creating a note import layers for theme " + json.id + " as they are disabled"
"Not creating a note import layers for theme " + json.id + " as they are disabled",
)
return json
}
@ -244,7 +248,7 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
try {
const importLayerResult = creator.convert(
layer,
context.inOperation(this.name).enter(i1)
context.inOperation(this.name).enter(i1),
)
if (importLayerResult !== undefined) {
json.layers.push(importLayerResult)
@ -263,7 +267,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
super(
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
["_context"],
"AddContextToTranlationsInLayout"
"AddContextToTranlationsInLayout",
)
}
@ -278,7 +282,7 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
super(
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
["overrideAll", "layers"],
"ApplyOverrideAll"
"ApplyOverrideAll",
)
}
@ -292,9 +296,29 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
delete json.overrideAll
const newLayers = []
let tagRenderingsPlus = undefined
if (overrideAll["tagRenderings+"] !== undefined) {
tagRenderingsPlus = overrideAll["tagRenderings+"]
delete overrideAll["tagRenderings+"]
}
for (let layer of json.layers) {
layer = Utils.Clone(<LayerConfigJson>layer)
Utils.Merge(overrideAll, layer)
if (tagRenderingsPlus) {
if (!layer.tagRenderings) {
layer.tagRenderings = tagRenderingsPlus
} else {
let index = layer.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
if (index < 0) {
index = layer.tagRenderings.length - 1
}
layer.tagRenderings.splice(index, 0, ...tagRenderingsPlus)
}
}
newLayers.push(layer)
}
json.layers = newLayers
@ -314,7 +338,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.
`,
["layers"],
"AddDependencyLayersToTheme"
"AddDependencyLayersToTheme",
)
this._state = state
}
@ -322,7 +346,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
private static CalculateDependencies(
alreadyLoaded: LayerConfigJson[],
allKnownLayers: Map<string, LayerConfigJson>,
themeId: string
themeId: string,
): { config: LayerConfigJson; reason: string }[] {
const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = []
const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l.id))
@ -345,7 +369,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
for (const layerConfig of alreadyLoaded) {
try {
const layerDeps = DependencyCalculator.getLayerDependencies(
new LayerConfig(layerConfig, themeId + "(dependencies)")
new LayerConfig(layerConfig, themeId + "(dependencies)"),
)
dependencies.push(...layerDeps)
} catch (e) {
@ -382,10 +406,10 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
if (dep === undefined) {
const message = [
"Loading a dependency failed: layer " +
unmetDependency.neededLayer +
" is not found, neither as layer of " +
themeId +
" nor as builtin layer.",
unmetDependency.neededLayer +
" is not found, neither as layer of " +
themeId +
" nor as builtin layer.",
reason,
"Loaded layers are: " + alreadyLoaded.map((l) => l.id).join(","),
]
@ -401,7 +425,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
})
loadedLayerIds.add(dep.id)
unmetDependencies = unmetDependencies.filter(
(d) => d.neededLayer !== unmetDependency.neededLayer
(d) => d.neededLayer !== unmetDependency.neededLayer,
)
}
} while (unmetDependencies.length > 0)
@ -422,14 +446,14 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
const dependencies = AddDependencyLayersToTheme.CalculateDependencies(
layers,
allKnownLayers,
theme.id
theme.id,
)
for (const dependency of dependencies) {
}
if (dependencies.length > 0) {
for (const dependency of dependencies) {
context.info(
"Added " + dependency.config.id + " to the theme. " + dependency.reason
"Added " + dependency.config.id + " to the theme. " + dependency.reason,
)
}
}
@ -471,7 +495,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
super(
"Generates a warning if a theme uses an unsubstituted layer",
["layers"],
"WarnForUnsubstitutedLayersInTheme"
"WarnForUnsubstitutedLayersInTheme",
)
}
@ -483,7 +507,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
context
.enter("layers")
.err(
"No layers are defined. You must define at least one layer to have a valid theme"
"No layers are defined. You must define at least one layer to have a valid theme",
)
return json
}
@ -507,10 +531,10 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
context.warn(
"The theme " +
json.id +
" has an inline layer: " +
layer["id"] +
". This is discouraged."
json.id +
" has an inline layer: " +
layer["id"] +
". This is discouraged.",
)
}
return json
@ -519,11 +543,12 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
export class PrepareTheme extends Fuse<LayoutConfigJson> {
private state: DesugaringContext
constructor(
state: DesugaringContext,
options?: {
skipDefaultLayers: false | boolean
}
},
) {
super(
"Fully prepares and expands a theme",
@ -536,6 +561,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
// We expand all tagrenderings first...
new On("layers", new Each(new PrepareLayer(state))),
// Then we apply the override all. We must first expand everything in case that we override something in an expanded tag
// Note that it'll cheat with tagRenderings+
new ApplyOverrideAll(),
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
new On("layers", new Each(new PrepareLayer(state))),
@ -543,7 +569,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
? new Pass("AddDefaultLayers is disabled due to the set flag")
: new AddDefaultLayers(state),
new AddDependencyLayersToTheme(state),
new AddImportLayers()
new AddImportLayers(),
)
this.state = state
}
@ -558,13 +584,13 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) =>
l.tagRenderings?.some((tr) =>
ValidationUtils.getSpecialVisualisations(<any>tr)?.some(
(special) => special.needsNodeDatabase
)
)
(special) => special.needsNodeDatabase,
),
),
)
if (needsNodeDatabase) {
context.info(
"Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes"
"Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes",
)
result.enableNodeDatabase = true
}

View file

@ -24,6 +24,7 @@ import { ConversionContext } from "./ConversionContext"
import * as eli from "../../../assets/editor-layer-index.json"
import { AvailableRasterLayers } from "../../RasterLayers"
import Back from "../../../assets/svg/Back.svelte"
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
private readonly _languages: string[]
@ -177,6 +178,9 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
if (!json.title) {
context.enter("title").err(`The theme ${json.id} does not have a title defined.`)
}
if(!json.icon){
context.enter("icon").err("A theme should have an icon")
}
if (this._isBuiltin && this._extractImages !== undefined) {
// Check images: are they local, are the licenses there, is the theme icon square, ...
const images = this._extractImages.convert(json, context.inOperation("ValidateTheme"))
@ -243,7 +247,8 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
new ValidateLanguageCompleteness("en").convert(theme, context)
}
} catch (e) {
context.err(e)
console.error(e)
context.err("Could not validate the theme due to: " + e)
}
if (theme.id !== "personal") {
@ -411,7 +416,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep<TagRenderingCo
return json
} catch (e) {
context.err(e)
context.err("Could not check for conflicting extra tags due to: " + e)
return undefined
}
}
@ -1016,6 +1021,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
*/
private readonly _path: string
private readonly _studioValidations: boolean
private readonly _validatePointRendering = new ValidatePointRendering()
constructor(path: string, isBuiltin, doesImageExist, studioValidations) {
super("Runs various checks against common mistakes for a layer", [], "PrevalidateLayer")
@ -1105,6 +1111,8 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
context.enter("pointRendering").err("There are no pointRenderings at all...")
}
json.pointRendering?.forEach((pr,i) => this._validatePointRendering.convert(pr, context.enters("pointeRendering", i)))
if (json["mapRendering"]) {
context.enter("mapRendering").err("This layer has a legacy 'mapRendering'")
}
@ -1409,13 +1417,40 @@ export class ValidateLayerConfig extends DesugaringStep<LayerConfigJson> {
}
}
class ValidatePointRendering extends DesugaringStep<PointRenderingConfigJson> {
constructor() {
super("Various checks for pointRenderings", [], "ValidatePOintRendering")
}
convert(json: PointRenderingConfigJson, context: ConversionContext): PointRenderingConfigJson {
if (json.marker === undefined && json.label === undefined) {
context.err(`A point rendering should define at least an marker or a label`)
}
if (json["markers"]) {
context.enter("markers").err(`Detected a field 'markerS' in pointRendering. It is written as a singular case`)
}
if (json.marker && !Array.isArray(json.marker)) {
context.enter("marker").err(
"The marker in a pointRendering should be an array"
)
}
if (json.location.length == 0) {
context.enter("location").err (
"A pointRendering should have at least one 'location' to defined where it should be rendered. "
)
}
return json
}
}
export class ValidateLayer extends Conversion<
LayerConfigJson,
{ parsed: LayerConfig; raw: LayerConfigJson }
> {
private readonly _skipDefaultLayers: boolean
private readonly _prevalidation: PrevalidateLayer
constructor(
path: string,
isBuiltin: boolean,

View file

@ -506,7 +506,7 @@ export interface LayerConfigJson {
* If the way is part of a relation, MapComplete will attempt to update this relation as well
* question: Should the contributor be able to split ways using this layer?
* iftrue: enable the 'split-roads'-component
* iffalse: don't enable the split-roads componenet
* iffalse: don't enable the split-roads component
* ifunset: don't enable the split-roads component
* group: editing
*/

View file

@ -5,7 +5,7 @@ export interface IconConfigJson {
/**
* question: What icon should be used?
* type: icon
* suggestions: return ["pin","square","circle","checkmark","clock","close","crosshair","help","home","invalid","location","location_empty","location_locked","note","resolved","ring","scissors","teardrop","teardrop_with_hole_green","triangle"].map(i => ({if: "value="+i, then: i, icon: i}))
* suggestions: return Constants.defaultPinIcons.map(i => ({if: "value="+i, then: i, icon: i}))
*/
icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any }
/**

View file

@ -106,8 +106,12 @@ export interface MappingConfigJson {
hideInAnswer?: boolean | TagConfigJson
/**
* question: In what other cases should this item be rendered?
*
* Also show this 'then'-option if the feature matches these tags.
* Ideal for outdated tags.
* Ideal for outdated tags or default assumptions. The tags from this options will <b>not</b> be set if the option is chosen!
*
* ifunset: No other cases when this text is shown
*/
alsoShowIf?: TagConfigJson

View file

@ -79,23 +79,7 @@ export default class PointRenderingConfig extends WithContextLoader {
}
})
if (json.marker === undefined && json.label === undefined) {
throw `At ${context}: A point rendering should define at least an marker or a label`
}
if (json["markers"]) {
throw `At ${context}.markers: detected a field 'markerS' in pointRendering. It is written as a singular case`
}
if (json.marker && !Array.isArray(json.marker)) {
throw `At ${context}.marker: the marker in a pointRendering should be an array`
}
if (this.location.size == 0) {
throw (
"A pointRendering should have at least one 'location' to defined where it should be rendered. (At " +
context +
".location)"
)
}
this.marker = (json.marker ?? []).map((m) => new IconConfig(<any>m))
if (json.css !== undefined) {
this.cssDef = this.tr("css", undefined)

View file

@ -15,7 +15,6 @@ import {
QuestionableTagRenderingConfigJson,
} from "./Json/QuestionableTagRenderingConfigJson"
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
import { Paragraph } from "../../UI/Base/Paragraph"
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
import Constants from "../Constants"
@ -371,20 +370,9 @@ export default class TagRenderingConfig {
let iconClass = commonSize
if (!!mapping.icon) {
if (typeof mapping.icon === "string" && mapping.icon !== "") {
let stripped = mapping.icon
if (stripped.endsWith(".svg")) {
stripped = stripped.substring(0, stripped.length - 4)
}
if (Constants.defaultPinIcons.indexOf(stripped) >= 0) {
icon = "./assets/svg/" + mapping.icon
if (!icon.endsWith(".svg")) {
icon += ".svg"
}
} else {
icon = mapping.icon
}
icon = mapping.icon.trim()
} else if (mapping.icon["path"]) {
icon = mapping.icon["path"]
icon = mapping.icon["path"].trim()
iconClass = mapping.icon["class"] ?? iconClass
}
}
@ -754,12 +742,10 @@ export default class TagRenderingConfig {
withRender = [
`This rendering asks information about the property `,
Link.OsmWiki(this.freeform.key),
new Paragraph(
new Combine([
"This is rendered with ",
new FixedUiElement(this.render.txt).SetClass("code font-bold"),
])
),
new Combine([
"This is rendered with ",
new FixedUiElement(this.render.txt).SetClass("code font-bold"),
]),
]
}

View file

@ -61,6 +61,7 @@ import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSou
import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource"
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
import Zoomcontrol from "../UI/Zoomcontrol"
/**
*
@ -481,6 +482,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.lastClickObject.features.setData([])
})
this.selectedElement.addCallback((selected) => {
if (selected === undefined) {
Zoomcontrol.resetzoom()
}
})
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
Utils.LoadCustomCss(this.layout.customCss)
}
@ -524,7 +531,10 @@ export default class ThemeViewState implements SpecialVisualizationState {
}
this.selectedElement.setData(undefined)
this.guistate.closeAll()
this.focusOnMap()
if (!this.guistate.isSomethingOpen()) {
Zoomcontrol.resetzoom()
this.focusOnMap()
}
})
Hotkeys.RegisterHotkey({ nomod: "f" }, docs.selectFavourites, () => {

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "svelte"
import { createEventDispatcher, onDestroy } from "svelte"
import { twMerge } from "tailwind-merge"
export let accept: string
@ -9,10 +9,52 @@
export let cls: string = ""
let drawAttention = false
let inputElement: HTMLInputElement
let id = Math.random() * 1000000000 + ""
let formElement: HTMLFormElement
let id = "fileinput_" + Math.round(Math.random() * 1000000000000)
function handleDragEvent(e: DragEvent) {
if (e.target["id"] == id) {
return
}
if(formElement.contains(e.target) || document.getElementsByClassName("selected-element-view")[0]?.contains(e.target)){
e.preventDefault()
if(e.type === "drop"){
console.log("Got a 'drop'", e)
drawAttention = false
dispatcher("submit", e.dataTransfer.files)
return
}
drawAttention = true
e.dataTransfer.dropEffect = "copy"
return
/*
drawAttention = false
dispatcher("submit", e.dataTransfer.files)
console.log("Committing")*/
}
drawAttention = false
e.preventDefault()
e.dataTransfer.effectAllowed = "none"
e.dataTransfer.dropEffect = "none"
}
window.addEventListener("dragenter", handleDragEvent)
window.addEventListener("dragover", handleDragEvent)
window.addEventListener("drop", handleDragEvent)
onDestroy(() => {
window.removeEventListener("dragenter", handleDragEvent)
window.removeEventListener("dragover", handleDragEvent)
window.removeEventListener("drop", handleDragEvent)
})
</script>
<form
bind:this={formElement}
on:change|preventDefault={() => {
drawAttention = false
dispatcher("submit", inputElement.files)
@ -24,27 +66,24 @@
on:dragenter|preventDefault|stopPropagation={(e) => {
console.log("Dragging enter")
drawAttention = true
e.dataTransfer.drop = "copy"
e.dataTransfer.dropEffect = "copy"
}}
on:dragstart={() => {
console.log("DragStart")
drawAttention = false
}}
on:drop|preventDefault|stopPropagation={(e) => {
console.log("Got a 'drop'")
drawAttention = false
dispatcher("submit", e.dataTransfer.files)
}}
>
<label
class={twMerge(cls, drawAttention ? "glowing-shadow" : "")}
style="margin-left:0"
tabindex="0"
for={"fileinput" + id}
for={id}
on:click={() => {
console.log("Clicked", inputElement)
inputElement.click()
}}
style="margin-left:0"
tabindex="0"
>
<slot />
</label>
@ -52,7 +91,7 @@
{accept}
bind:this={inputElement}
class="hidden"
id={"fileinput" + id}
{id}
{multiple}
name="file-input"
type="file"

View file

@ -28,7 +28,7 @@
style="z-index: 21"
use:trapFocus
>
<div class="content normal-background" on:click|stopPropagation={() => {}}>
<div class="h-full content normal-background" on:click|stopPropagation={() => {}}>
<div class="h-full rounded-xl">
<slot />
</div>
@ -47,7 +47,6 @@
<style>
.content {
height: 100%;
border-radius: 0.5rem;
overflow-x: hidden;
box-shadow: 0 0 1rem #00000088;

View file

@ -2,6 +2,8 @@ import { VariableUiElement } from "./VariableUIElement"
import Locale from "../i18n/Locale"
import Link from "./Link"
import Svg from "../../Svg"
import SvelteUIElement from "./SvelteUIElement"
import Translate from "../../assets/svg/Translate.svelte"
/**
* The little 'translate'-icon next to every icon + some static helper functions
@ -20,7 +22,7 @@ export default class LinkToWeblate extends VariableUiElement {
if (context === undefined || context.indexOf(":") < 0) {
return undefined
}
const icon = Svg.translate_svg().SetClass(
const icon = new SvelteUIElement(Translate).SetClass(
"rounded-full inline-block w-3 h-3 ml-1 weblate-link self-center"
)
if (availableTranslations[ln] === undefined) {

View file

@ -1,30 +0,0 @@
import BaseUIElement from "../BaseUIElement"
export class Paragraph extends BaseUIElement {
public readonly content: string | BaseUIElement
constructor(html: string | BaseUIElement) {
super()
this.content = html ?? ""
}
AsMarkdown(): string {
let c: string
if (typeof this.content !== "string") {
c = this.content.AsMarkdown()
} else {
c = this.content
}
return "\n\n" + c + "\n\n"
}
protected InnerConstructElement(): HTMLElement {
const e = document.createElement("p")
if (typeof this.content !== "string") {
e.appendChild(this.content.ConstructElement())
} else {
e.innerHTML = this.content
}
return e
}
}

View file

@ -66,32 +66,4 @@ export class SubtleButton extends UIElement {
this.SetClass(classes)
return button
}
public OnClickWithLoading(
loadingText: BaseUIElement | string,
action: () => Promise<void>
): BaseUIElement {
const state = new UIEventSource<"idle" | "running">("idle")
const button = this
button.onClick(async () => {
state.setData("running")
try {
await action()
} catch (e) {
console.error(e)
} finally {
state.setData("idle")
}
})
const loading = new Lazy(() => new Loading(loadingText))
return new VariableUiElement(
state.map((st) => {
if (st === "idle") {
return button
}
return loading
})
)
}
}

View file

@ -1,7 +1,7 @@
<script lang="ts">
/**
* A mapcontrol button which allows the user to select a different background.
* Even though the componenet is very small, it gets it's own class as it is often reused
* Even though the component is very small, it gets it's own class as it is often reused
*/
import { Square3Stack3dIcon } from "@babeard/svelte-heroicons/solid"
import type { SpecialVisualizationState } from "../SpecialVisualization"

Some files were not shown because too many files have changed in this diff Show more