Refactoring: add metatagging, add 'last edited by' element, add 'metacondition'

This commit is contained in:
Pieter Vander Vennet 2023-04-15 02:28:24 +02:00
parent 771783a31c
commit 105120060d
31 changed files with 217 additions and 142 deletions

View file

@ -18,6 +18,11 @@
onDestroy(tags.addCallbackAndRun(tags => {
_tags = tags;
}));
let _metatags: Record<string, string>
onDestroy(state.userRelatedState.preferencesAsTags .addCallbackAndRun(tags => {
_metatags = tags;
}));
</script>
<div>
@ -40,7 +45,7 @@
<div class="flex flex-col">
{#each layer.tagRenderings as config (config.id)}
{#if config.condition === undefined || config.condition.matchesProperties(_tags)}
{#if (config.condition === undefined || config.condition.matchesProperties(_tags)) && (config.metacondition === undefined || config.metacondition.matchesProperties(_metatags))}
{#if config.IsKnown(_tags)}
<TagRenderingEditable {tags} {config} {state} {selectedElement} {layer} {highlightedRendering}></TagRenderingEditable>
{/if}

View file

@ -91,6 +91,7 @@ export class MapLibreAdaptor implements MapProperties {
// Workaround, 'ShowPointLayer' sets this flag
return
}
console.log(e)
const lon = e.lngLat.lng
const lat = e.lngLat.lat
lastClickLocation.setData({ lon, lat })

View file

@ -96,14 +96,15 @@
}
});
state.newFeatures.features.ping();
const tagsStore = state.featureProperties.getStore(newId);
{
// Set some metainfo
const tagsStore = state.featureProperties.getStore(newId);
const properties = tagsStore.data;
if (snapTo) {
// metatags (starting with underscore) are not uploaded, so we can safely mark this
properties["_referencing_ways"] = `["${snapTo}"]`;
}
properties["_backend"] = state.osmConnection.Backend()
properties["_last_edit:timestamp"] = new Date().toISOString();
const userdetails = state.osmConnection.userDetails.data;
properties["_last_edit:contributor"] = userdetails.name;
@ -112,8 +113,9 @@
}
const feature = state.indexedFeatures.featuresById.data.get(newId);
abort();
state.selectedElement.setData(feature);
state.selectedLayer.setData(selectedPreset.layer);
state.selectedElement.setData(feature);
tagsStore.ping()
}

View file

@ -1,46 +1,63 @@
<script lang="ts">
import ToSvelte from "../Base/ToSvelte.svelte"
import Table from "../Base/Table"
import { UIEventSource } from "../../Logic/UIEventSource"
import ToSvelte from "../Base/ToSvelte.svelte";
import Table from "../Base/Table";
import { UIEventSource } from "../../Logic/UIEventSource";
import SimpleMetaTaggers from "../../Logic/SimpleMetaTagger";
import { FixedUiElement } from "../Base/FixedUiElement";
import { onDestroy } from "svelte";
import Toggle, { ClickableToggle } from "../Input/Toggle";
import Lazy from "../Base/Lazy";
import BaseUIElement from "../BaseUIElement";
//Svelte props
export let tags: UIEventSource<any>
export let state: any
export let tags: UIEventSource<any>;
export let state: any;
const calculatedTags = [].concat(
// SimpleMetaTagger.lazyTags,
...(state?.layoutToUse?.layers?.map((l) => l.calculatedTags?.map((c) => c[0]) ?? []) ?? [])
)
);
const allTags = tags.map((tags) => {
const parts = []
const parts: (string | BaseUIElement)[][] = [];
for (const key in tags) {
if (!tags.hasOwnProperty(key)) {
continue
}
let v = tags[key]
let v = tags[key];
if (v === "") {
v = "<b>empty string</b>"
v = "<b>empty string</b>";
}
parts.push([key, v ?? "<b>undefined</b>"])
parts.push([key, v ?? "<b>undefined</b>"]);
}
for (const key of calculatedTags) {
const value = tags[key]
const value = tags[key];
if (value === undefined) {
continue
continue;
}
let type = ""
let type = "";
if (typeof value !== "string") {
type = " <i>" + typeof value + "</i>"
type = " <i>" + typeof value + "</i>";
}
parts.push(["<i>" + key + "</i>", value])
parts.push(["<i>" + key + "</i>", value]);
}
return parts
})
for (const metatag of SimpleMetaTaggers.metatags.filter(mt => mt.isLazy)) {
const title = "<i>" + metatag.keys.join(";") + "</i> (lazy)";
const toggleState = new UIEventSource(false)
const toggle: BaseUIElement = new Toggle(
new Lazy(() => new FixedUiElement(metatag.keys.map(key => tags[key]).join(";"))),
new FixedUiElement("Evaluate").onClick(() => toggleState.setData(true)) ,
toggleState
);
parts.push([title, toggle]);
}
const tagsTable = new Table(["Key", "Value"], $allTags).SetClass("zebra-table")
return parts;
});
let _allTags = [];
onDestroy(allTags.addCallbackAndRunD(allTags => {
_allTags = allTags;
}));
const tagsTable = new Table(["Key", "Value"], _allTags).SetClass("zebra-table");
</script>
<section>

View file

@ -99,63 +99,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
})
),
]
allRenderings.push(
new Toggle(
new Lazy(() =>
FeatureInfoBox.createEditElements(questionBoxes, layerConfig, tags, state)
),
undefined,
state.featureSwitchUserbadge
)
)
return new Combine(allRenderings).SetClass("block")
}
/**
* All the edit elements, together (note that the question boxes are passed though)
* @param questionBoxes
* @param layerConfig
* @param tags
* @param state
* @private
*/
private static createEditElements(
questionBoxes: Map<string, QuestionBox>,
layerConfig: LayerConfig,
tags: UIEventSource<any>,
state: FeaturePipelineState
): BaseUIElement {
let editElements: BaseUIElement[] = []
questionBoxes.forEach((questionBox) => {
editElements.push(questionBox)
})
editElements.push(
new VariableUiElement(
state.osmConnection.userDetails
.map((ud) => ud.csCount)
.map(
(csCount) => {
if (
csCount <= Constants.userJourney.historyLinkVisible &&
state.featureSwitchIsDebugging.data == false &&
state.featureSwitchIsTesting.data === false
) {
return undefined
}
return new TagRenderingAnswer(
tags,
SharedTagRenderings.SharedTagRendering.get("last_edit"),
state
)
},
[state.featureSwitchIsDebugging, state.featureSwitchIsTesting]
)
)
)
return new Combine(editElements).SetClass("flex flex-col")
}
}

View file

@ -41,7 +41,10 @@
return true;
}
const baseQuestions = (layer.tagRenderings ?? [])?.filter(tr => allowed(tr.labels) && tr.question !== undefined);
let baseQuestions = []
$: {
baseQuestions = (layer.tagRenderings ?? [])?.filter(tr => allowed(tr.labels) && tr.question !== undefined);
}
let skippedQuestions = new UIEventSource<Set<string>>(new Set<string>());
let questionsToAsk = tags.map(tags => {
@ -80,6 +83,7 @@
skipped++;
}
}
$: console.log("Current questionbox state:", {answered, skipped, questionsToAsk, layer, selectedElement, tags})
</script>
{#if _questionsToAsk.length === 0}

View file

@ -32,7 +32,6 @@
checkedMappings = [...config.mappings.map(_ => false), false /*One element extra in case a freeform value is added*/];
}
}
$: console.log("Checked mappings:", checkedMappings)
let selectedTags: TagsFilter = undefined;
function mappingIsHidden(mapping: Mapping): boolean {

View file

@ -63,6 +63,7 @@ export interface SpecialVisualizationState {
readonly userRelatedState: {
readonly mangroveIdentity: MangroveIdentity
readonly showAllQuestionsAtOnce: UIEventSource<boolean>
readonly preferencesAsTags: Store<Record<string, string>>
}
readonly lastClickObject: WritableFeatureSource
}

View file

@ -1265,21 +1265,24 @@ export default class SpecialVisualizations {
doc: "The URL to link to",
required: true,
},
{
name: "class",
doc: "CSS-classes to add to the element",
},
],
constr(
state: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>,
args: string[]
): BaseUIElement {
const [text, href] = args
const [text, href, classnames] = args
return new VariableUiElement(
tagSource.map(
(tags) =>
new Link(
Utils.SubstituteKeys(text, tags),
Utils.SubstituteKeys(href, tags),
true
)
tagSource.map((tags) =>
new Link(
Utils.SubstituteKeys(text, tags),
Utils.SubstituteKeys(href, tags),
true
).SetClass(classnames)
)
)
},

View file

@ -29,7 +29,14 @@ export class Translation extends BaseUIElement {
}
count++
if (typeof translations[translationsKey] != "string") {
console.error("Non-string object in translation: ", translations[translationsKey])
console.error(
"Non-string object at",
context,
"in translation: ",
translations[translationsKey],
"\n current translations are: ",
translations
)
throw (
"Error in an object depicting a translation: a non-string object was found. (" +
context +