Themes: improve note theme, fix #2088
This commit is contained in:
parent
70117ac687
commit
e8099b9081
5 changed files with 266 additions and 189 deletions
|
@ -18,13 +18,16 @@
|
|||
"calculatedTags": [
|
||||
"_total_comments:=get(feat)('comments').length",
|
||||
"_first_comment:=get(feat)('comments')[0].text",
|
||||
"_all_comments:=get(feat)('comments').map(c => c.text ?? '').join('\\n')",
|
||||
"_all_usernames:=get(feat)('comments').map(c => c.user ?? 'Anonymous').join('\\n')",
|
||||
"_opened_by_anonymous_user:=get(feat)('comments')[0].user === undefined",
|
||||
"_first_user:=get(feat)('comments')[0].user",
|
||||
"_last_user:=(() => {const comms = get(feat)('comments'); return comms[comms.length - 1].user})()",
|
||||
"_last_change_date:=(() => {const comms = get(feat)('comments'); return comms[comms.length - 1].date})()",
|
||||
"_first_user_id:=get(feat)('comments')[0].uid",
|
||||
"_is_import_note:=(() => {const lines = feat.properties['_first_comment'].split('\\n'); const matchesMapCompleteURL = lines.map(l => l.match(\".*https://mapcomplete.\\(osm.be|org\\)/\\([a-zA-Z_-]+\\)\\(.html\\).*#import\")); const matchedIndexes = matchesMapCompleteURL.map((doesMatch, i) => [doesMatch !== null, i]).filter(v => v[0]).map(v => v[1]); return matchedIndexes[0] })()"
|
||||
],
|
||||
"minzoom": 10,
|
||||
"minzoom": 7,
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "Note",
|
||||
|
@ -158,183 +161,6 @@
|
|||
}
|
||||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "search",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_comment~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Should mention {search} in the first comment",
|
||||
"nl": "Moet in de eerste opmerking \"{search}\" bevatten",
|
||||
"de": "Sollte {search} im ersten Kommentar erwähnen",
|
||||
"es": "Debe mencionar {search} en el primer comentario",
|
||||
"ca": "Has de mencionar {search} en el primer comentari",
|
||||
"cs": "Měl by se zmínit {search} v prvním komentáři"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "not",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_comment!~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Should <b>not</b> mention {search} in the first comment",
|
||||
"nl": "Mag in de eerste opmerking <b>niet</b> \"{search}\" bevatten",
|
||||
"de": "Sollte <b>nicht</b> {search} im ersten Kommentar erwähnen",
|
||||
"es": "<b>No</b> debe mencionar {search} en el primer comentario",
|
||||
"ca": "<b>No</b> s'ha de mencionar {search} al primer comentari",
|
||||
"cs": "V prvním komentáři by jste <b>neměli</b> zmiňovat {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "opened_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_user~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Opened by contributor {search}",
|
||||
"nl": "Geopend door bijdrager {search}",
|
||||
"de": "Erstellt von {search}",
|
||||
"es": "Abierto por el contributor {search}",
|
||||
"fr": "Ouverte par {search}",
|
||||
"ca": "Obert pel contribuïdor {search}",
|
||||
"cs": "Otevřeno přispěvatelem {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "not_opened_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_user!~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "<b>Not</b> opened by contributor {search}",
|
||||
"nl": "<b>Niet</b> geopend door bijdrager {search}",
|
||||
"de": "<b>Nicht</b> erstellt von {search}",
|
||||
"es": "<b>No</b> abierto por el contributor {search}",
|
||||
"ca": "<b>No</b> obert pel contribuïdor {search}",
|
||||
"cs": "<b>Není</b> otevřeno přispěvatelem {search}",
|
||||
"fr": "<b>Exclure</b>les notes ouvertes par {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "edited_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_user~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Last edited by contributor {search}",
|
||||
"nl": "Laatst bewerkt door bijdrager {search}",
|
||||
"de": "Zuletzt bearbeitet von {search}",
|
||||
"es": "Editada por última vez por el contributor {search}",
|
||||
"ca": "Editat per última vega pel contribuïdor {search}",
|
||||
"cs": "Naposledy upravil přispěvatel {search}",
|
||||
"da": "Senest redigeret af bidragsyder {search}",
|
||||
"fr": "Dernière modification par {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "not_edited_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_user!~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Opened after {search}",
|
||||
"nl": "Geopend na {search}",
|
||||
"de": "Zuletzt bearbeitet nach dem {search}",
|
||||
"es": "Abierta después de {search}",
|
||||
"ca": "Oberta després de {search}",
|
||||
"cs": "Otevřeno po {search}",
|
||||
"fr": "Ouverte après le {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "opened_before",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "date_created<{search}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search",
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Created before {search}",
|
||||
"nl": "Aangemaakt voor {search}",
|
||||
"de": "Erstellt vor dem {search}",
|
||||
"es": "Creada antes de {search}",
|
||||
"ca": "Creada abans de {search}",
|
||||
"cs": "Vytvořeno před {search}",
|
||||
"fr": "Créée avant le {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "opened_after",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "date_created>{search}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search",
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Created after {search}",
|
||||
"nl": "Aangemaakt na {search}",
|
||||
"de": "Erstellt nach dem {search}",
|
||||
"es": "Creada después de {search}",
|
||||
"ca": "Creada després de {search}",
|
||||
"cs": "Vytvořeno po {search}",
|
||||
"fr": "Créée après le {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "anonymous",
|
||||
"options": [
|
||||
|
@ -406,6 +232,244 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "search",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_comment~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Should mention {search} in the first comment",
|
||||
"nl": "Moet in de eerste opmerking \"{search}\" bevatten",
|
||||
"de": "Sollte {search} im ersten Kommentar erwähnen",
|
||||
"es": "Debe mencionar {search} en el primer comentario",
|
||||
"ca": "Has de mencionar {search} en el primer comentari",
|
||||
"cs": "Měl by se zmínit {search} v prvním komentáři"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "search_any",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_all_comments~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Should mention {search} in any comment"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "not",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_comment!~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Should <b>not</b> mention {search} in the first comment",
|
||||
"nl": "Mag in de eerste opmerking <b>niet</b> \"{search}\" bevatten",
|
||||
"de": "Sollte <b>nicht</b> {search} im ersten Kommentar erwähnen",
|
||||
"es": "<b>No</b> debe mencionar {search} en el primer comentario",
|
||||
"ca": "<b>No</b> s'ha de mencionar {search} al primer comentari",
|
||||
"cs": "V prvním komentáři by jste <b>neměli</b> zmiňovat {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "opened_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_user~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Opened by contributor {search}",
|
||||
"nl": "Geopend door bijdrager {search}",
|
||||
"de": "Erstellt von {search}",
|
||||
"es": "Abierto por el contributor {search}",
|
||||
"fr": "Ouverte par {search}",
|
||||
"ca": "Obert pel contribuïdor {search}",
|
||||
"cs": "Otevřeno přispěvatelem {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "not_opened_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_first_user!~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "<b>Not</b> opened by contributor {search}",
|
||||
"nl": "<b>Niet</b> geopend door bijdrager {search}",
|
||||
"de": "<b>Nicht</b> erstellt von {search}",
|
||||
"es": "<b>No</b> abierto por el contributor {search}",
|
||||
"ca": "<b>No</b> obert pel contribuïdor {search}",
|
||||
"cs": "<b>Není</b> otevřeno přispěvatelem {search}",
|
||||
"fr": "<b>Exclure</b>les notes ouvertes par {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "edited_by_any",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_all_usernames~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Edited or commented on by any user with name {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "last_edited_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_user~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Last edited by contributor {search}",
|
||||
"nl": "Laatst bewerkt door bijdrager {search}",
|
||||
"de": "Zuletzt bearbeitet von {search}",
|
||||
"es": "Editada por última vez por el contributor {search}",
|
||||
"ca": "Editat per última vega pel contribuïdor {search}",
|
||||
"cs": "Naposledy upravil přispěvatel {search}",
|
||||
"da": "Senest redigeret af bidragsyder {search}",
|
||||
"fr": "Dernière modification par {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "not_last_edited_by",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_user!~i~.*{search}.*",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Not edited as last by {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "opened_before",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "date_created<{search}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search",
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Created before {search}",
|
||||
"nl": "Aangemaakt voor {search}",
|
||||
"de": "Erstellt vor dem {search}",
|
||||
"es": "Creada antes de {search}",
|
||||
"ca": "Creada abans de {search}",
|
||||
"cs": "Vytvořeno před {search}",
|
||||
"fr": "Créée avant le {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "opened_after",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "date_created>{search}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search",
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Created after {search}",
|
||||
"nl": "Aangemaakt na {search}",
|
||||
"de": "Erstellt nach dem {search}",
|
||||
"es": "Creada después de {search}",
|
||||
"ca": "Creada després de {search}",
|
||||
"cs": "Vytvořeno po {search}",
|
||||
"fr": "Créée après le {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "last_edited_before",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_change_date<{search}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search",
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Last edited before {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "last_edited_after",
|
||||
"options": [
|
||||
{
|
||||
"osmTags": "_last_change_date>{search}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "search",
|
||||
"type": "date"
|
||||
}
|
||||
],
|
||||
"question": {
|
||||
"en": "Last edited after {search}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"allowMove": false
|
||||
|
|
|
@ -12,12 +12,14 @@ import BaseUIElement from "../../UI/BaseUIElement"
|
|||
import Table from "../../UI/Base/Table"
|
||||
import Combine from "../../UI/Base/Combine"
|
||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
|
||||
|
||||
export type FilterConfigOption = {
|
||||
question: Translation
|
||||
osmTags: TagsFilter | undefined
|
||||
/* Only set if fields are present. Used to create `osmTags` (which are used to _actually_ filter) when the field is written*/
|
||||
readonly originalTagsSpec: TagConfigJson
|
||||
fields: { name: string; type: string }[]
|
||||
fields: { name: string; type: ValidatorType }[]
|
||||
}
|
||||
export default class FilterConfig {
|
||||
public readonly id: string
|
||||
|
@ -57,8 +59,11 @@ export default class FilterConfig {
|
|||
throw `Invalid filter: no question given at ${ctx}`
|
||||
}
|
||||
|
||||
const fields: { name: string; type: string }[] = (option.fields ?? []).map((f, i) => {
|
||||
const type = f.type ?? "string"
|
||||
const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => {
|
||||
const type = <ValidatorType> f.type ?? "string"
|
||||
if(Validators.availableTypes.indexOf(type) < 0){
|
||||
throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, <any>Validators.availableTypes, x => x).slice(0, 3)}`
|
||||
}
|
||||
// Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig
|
||||
if (f.name === undefined || f.name === "" || f.name.match(/[a-z0-9_-]+/) == null) {
|
||||
throw `Invalid filter: a variable name should match [a-z0-9_-]+ at ${ctx}.fields[${i}]`
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
import { Utils } from "../../Utils"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import type { ValidatorType } from "../InputElement/Validators"
|
||||
import InputHelper from "../InputElement/InputHelper.svelte"
|
||||
|
||||
export let filteredLayer: FilteredLayer
|
||||
export let option: FilterConfigOption
|
||||
|
@ -18,7 +19,7 @@
|
|||
parts = Utils.splitIntoSubstitutionParts(template)
|
||||
}
|
||||
let fieldValues: Record<string, UIEventSource<string>> = {}
|
||||
let fieldTypes: Record<string, string> = {}
|
||||
let fieldTypes: Record<string, ValidatorType> = {}
|
||||
let appliedFilter = <UIEventSource<string>>filteredLayer.appliedFilters.get(id)
|
||||
let initialState: Record<string, string> = JSON.parse(appliedFilter?.data ?? "{}")
|
||||
|
||||
|
@ -35,25 +36,30 @@
|
|||
appliedFilter?.setData(FilteredLayer.fieldsToString(properties))
|
||||
}
|
||||
|
||||
let firstValue : UIEventSource<string>
|
||||
for (const field of option.fields) {
|
||||
// A bit of cheating: the 'parts' will have '}' suffixed for fields
|
||||
const src = new UIEventSource<string>(initialState[field.name] ?? "")
|
||||
firstValue ??= src
|
||||
fieldTypes[field.name] = field.type
|
||||
console.log(field.name, "-->", field.type)
|
||||
fieldValues[field.name] = src
|
||||
onDestroy(
|
||||
src.stabilized(200).addCallback(() => {
|
||||
setFields()
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="low-interaction p-1 rounded-2xl px-3" class:interactive={$firstValue?.length > 0}>
|
||||
{#each parts as part, i}
|
||||
{#if part["subs"]}
|
||||
<!-- This is a field! -->
|
||||
<span class="mx-1">
|
||||
<ValidatedInput value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]} />
|
||||
<InputHelper value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]}>
|
||||
<ValidatedInput slot="fallback" value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]} />
|
||||
</InputHelper>
|
||||
</span>
|
||||
{:else}
|
||||
{@html part["message"]}
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
export let type: ValidatorType
|
||||
export let value: UIEventSource<string | object>
|
||||
|
||||
export let feature: Feature
|
||||
export let feature: Feature = undefined
|
||||
export let args: (string | number | boolean)[] = undefined
|
||||
export let state: SpecialVisualizationState
|
||||
export let state: SpecialVisualizationState = undefined
|
||||
</script>
|
||||
|
||||
{#if type === "translation"}
|
||||
|
@ -51,4 +51,6 @@
|
|||
<SlopeInput {value} {feature} {state} />
|
||||
{:else if type === "wikidata"}
|
||||
<WikidataInputHelper {value} {feature} {state} {args} />
|
||||
{:else}
|
||||
<slot name="fallback" />
|
||||
{/if}
|
||||
|
|
|
@ -1272,7 +1272,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
|
||||
public static sortedByLevenshteinDistance<T>(
|
||||
reference: string,
|
||||
ts: T[],
|
||||
ts: ReadonlyArray<T>,
|
||||
getName: (t: T) => string
|
||||
): T[] {
|
||||
const withDistance: [T, number][] = ts.map((t) => [
|
||||
|
|
Loading…
Reference in a new issue