Mapillary bugfix
This commit is contained in:
parent
895aa132ec
commit
ab2e9425c2
5 changed files with 114 additions and 111 deletions
|
@ -130,7 +130,12 @@ export class ImageSearcher extends UIEventSource<{key: string, url: string}[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._tags.data.mapillary) {
|
if (this._tags.data.mapillary) {
|
||||||
this.AddImage(undefined,"https://www.mapillary.com/map/im/" + this._tags.data.mapillary)
|
let mapillary = this._tags.data.mapillary;
|
||||||
|
const prefix = "https://www.mapillary.com/map/im/";
|
||||||
|
if(mapillary.indexOf(prefix) < 0){
|
||||||
|
mapillary = prefix + mapillary;
|
||||||
|
}
|
||||||
|
this.AddImage(undefined, mapillary)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
130
Logic/Tags.ts
130
Logic/Tags.ts
|
@ -1,4 +1,6 @@
|
||||||
import {Utils} from "../Utils";
|
import {Utils} from "../Utils";
|
||||||
|
import {Util} from "leaflet";
|
||||||
|
import indexOf = Util.indexOf;
|
||||||
|
|
||||||
export abstract class TagsFilter {
|
export abstract class TagsFilter {
|
||||||
abstract matches(tags: { k: string, v: string }[]): boolean
|
abstract matches(tags: { k: string, v: string }[]): boolean
|
||||||
|
@ -344,20 +346,31 @@ export class TagUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
* Given two hashes of {key --> values[]}, makes sure that every neededTag is present in availableTags
|
||||||
* E.g:
|
*/
|
||||||
*
|
static AllKeysAreContained(availableTags: any, neededTags: any){
|
||||||
* FlattenMultiAnswer([and: [ "x=a", "y=0;1"], and: ["x=b", "y=2"], and: ["x=", "y=3"]])
|
for (const neededKey in neededTags) {
|
||||||
* will result in
|
const availableValues : string[] = availableTags[neededKey]
|
||||||
* ["x=a;b", "y=0;1;2;3"]
|
if(availableValues === undefined){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const neededValues : string[] = neededTags[neededKey];
|
||||||
|
for (const neededValue of neededValues) {
|
||||||
|
if(indexOf(availableValues, neededValue) < 0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Creates a hash {key --> [values]}, with all the values present in the tagsfilter
|
||||||
*
|
*
|
||||||
* @param tagsFilters
|
* @param tagsFilters
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
static FlattenMultiAnswer(tagsFilters: TagsFilter[]): And {
|
static SplitKeys(tagsFilters: TagsFilter[]){
|
||||||
if (tagsFilters === undefined) {
|
|
||||||
return new And([]);
|
|
||||||
}
|
|
||||||
const keyValues = {} // Map string -> string[]
|
const keyValues = {} // Map string -> string[]
|
||||||
tagsFilters = [...tagsFilters] // copy all
|
tagsFilters = [...tagsFilters] // copy all
|
||||||
while (tagsFilters.length > 0) {
|
while (tagsFilters.length > 0) {
|
||||||
|
@ -384,91 +397,30 @@ export class TagUtils {
|
||||||
console.error("Invalid type to flatten the multiAnswer", tagsFilter);
|
console.error("Invalid type to flatten the multiAnswer", tagsFilter);
|
||||||
throw "Invalid type to FlattenMultiAnswer"
|
throw "Invalid type to FlattenMultiAnswer"
|
||||||
}
|
}
|
||||||
|
return keyValues;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
||||||
|
* E.g:
|
||||||
|
*
|
||||||
|
* FlattenMultiAnswer([and: [ "x=a", "y=0;1"], and: ["x=b", "y=2"], and: ["x=", "y=3"]])
|
||||||
|
* will result in
|
||||||
|
* ["x=a;b", "y=0;1;2;3"]
|
||||||
|
*
|
||||||
|
* @param tagsFilters
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
static FlattenMultiAnswer(tagsFilters: TagsFilter[]): And {
|
||||||
|
if (tagsFilters === undefined) {
|
||||||
|
return new And([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let keyValues = TagUtils.SplitKeys(tagsFilters);
|
||||||
const and: TagsFilter[] = []
|
const and: TagsFilter[] = []
|
||||||
for (const key in keyValues) {
|
for (const key in keyValues) {
|
||||||
and.push(new Tag(key, Utils.Dedup(keyValues[key]).join(";")));
|
and.push(new Tag(key, Utils.Dedup(keyValues[key]).join(";")));
|
||||||
}
|
}
|
||||||
return new And(and);
|
return new And(and);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the actualTags onto a list of which the values are the same as the tagsFilters.
|
|
||||||
* Leftovers are returned in the list too if there is an 'undefined' value
|
|
||||||
*/
|
|
||||||
static SplitMultiAnswer(actualTags: TagsFilter, possibleTags: TagsFilter[], freeformKey: string, freeformExtraTags: TagsFilter): TagsFilter[] {
|
|
||||||
|
|
||||||
const queue: TagsFilter[] = [actualTags]
|
|
||||||
|
|
||||||
const keyValues = {} // key ==> value[]
|
|
||||||
|
|
||||||
while (queue.length > 0) {
|
|
||||||
const tf = queue.pop();
|
|
||||||
if (tf instanceof And) {
|
|
||||||
queue.push(...tf.and);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (tf instanceof Tag) {
|
|
||||||
if (keyValues[tf.key] === undefined) {
|
|
||||||
keyValues[tf.key] = []
|
|
||||||
}
|
|
||||||
keyValues[tf.key].push(...tf.value.split(";"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tf === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw "Invalid tagfilter: " + JSON.stringify(tf)
|
|
||||||
}
|
|
||||||
|
|
||||||
const foundValues = [];
|
|
||||||
for (const possibleTag of possibleTags) {
|
|
||||||
if (possibleTag === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (possibleTag instanceof Tag) {
|
|
||||||
const key = possibleTag.key;
|
|
||||||
const actualValues: string[] = keyValues[key] ?? [];
|
|
||||||
const possibleValues = possibleTag.value.split(";");
|
|
||||||
|
|
||||||
let allPossibleValuesFound = true;
|
|
||||||
for (const possibleValue of possibleValues) {
|
|
||||||
if (actualValues.indexOf(possibleValue) < 0) {
|
|
||||||
allPossibleValuesFound = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!allPossibleValuesFound) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we know that 'possibleTag' is completely present in the tagset
|
|
||||||
// we add the possibleTag to the found values
|
|
||||||
foundValues.push(possibleTag);
|
|
||||||
|
|
||||||
for (const possibleValue of possibleValues) {
|
|
||||||
actualValues.splice(actualValues.indexOf(possibleValue), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw "Unsupported possibletag: " + JSON.stringify(possibleTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
let leftoverTag = undefined;
|
|
||||||
if (keyValues[freeformKey] !== undefined && keyValues[freeformKey].length !== 0) {
|
|
||||||
leftoverTag = new Tag(freeformKey, keyValues[freeformKey].join(";"));
|
|
||||||
if (freeformExtraTags !== undefined) {
|
|
||||||
leftoverTag = new And([
|
|
||||||
leftoverTag,
|
|
||||||
freeformExtraTags
|
|
||||||
])
|
|
||||||
}
|
|
||||||
foundValues.push(leftoverTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return foundValues;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ import {Changes} from "../../Logic/Osm/Changes";
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
|
import {Util} from "leaflet";
|
||||||
|
import indexOf = Util.indexOf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the question element.
|
* Shows the question element.
|
||||||
|
@ -112,6 +114,10 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SplitMultiAnswer(tags: TagsFilter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private GenerateMultiAnswer(elements: InputElement<TagsFilter>[], freeformField: InputElement<TagsFilter>): InputElement<TagsFilter> {
|
private GenerateMultiAnswer(elements: InputElement<TagsFilter>[], freeformField: InputElement<TagsFilter>): InputElement<TagsFilter> {
|
||||||
const possibleTags = elements.map(el => el.GetValue().data);
|
const possibleTags = elements.map(el => el.GetValue().data);
|
||||||
const checkBoxes = new CheckBoxes(elements);
|
const checkBoxes = new CheckBoxes(elements);
|
||||||
|
@ -128,22 +134,50 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
return TagUtils.FlattenMultiAnswer(tags);
|
return TagUtils.FlattenMultiAnswer(tags);
|
||||||
},
|
},
|
||||||
(tags: TagsFilter) => {
|
(tags: TagsFilter) => {
|
||||||
const splitUpValues = TagUtils.SplitMultiAnswer(tags, possibleTags, this._configuration.freeform?.key, new And(this._configuration.freeform?.addExtraTags));
|
// {key --> values[]}
|
||||||
|
const presentTags = TagUtils.SplitKeys([tags]);
|
||||||
const indices: number[] = []
|
const indices: number[] = []
|
||||||
|
// We also collect the values that have to be added to the freeform field
|
||||||
|
let freeformExtras: string[] = []
|
||||||
|
if (this._configuration.freeform?.key) {
|
||||||
|
freeformExtras = [...(presentTags[this._configuration.freeform.key] ?? [])]
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < splitUpValues.length; i++) {
|
for (let j = 0; j < elements.length; j++) {
|
||||||
let splitUpValue = splitUpValues[i];
|
const inputElement = elements[j];
|
||||||
|
if (inputElement === freeformField) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const val = inputElement.GetValue();
|
||||||
|
const neededTags = TagUtils.SplitKeys([val.data]);
|
||||||
|
|
||||||
for (let j = 0; j < elements.length; j++) {
|
// if every 'neededKeys'-value is present in presentKeys, we have a match and enable the index
|
||||||
let inputElement = elements[j];
|
if (TagUtils.AllKeysAreContained(presentTags, neededTags)) {
|
||||||
if (inputElement.IsValid(splitUpValue)) {
|
indices.push(j);
|
||||||
indices.push(j);
|
if (freeformExtras.length > 0) {
|
||||||
inputElement.GetValue().setData(splitUpValue);
|
const freeformsToRemove: string[] = (neededTags[this._configuration.freeform.key] ?? []);
|
||||||
break;
|
for (const toRm of freeformsToRemove) {
|
||||||
|
const i = freeformExtras.indexOf(toRm);
|
||||||
|
if (i >= 0) {
|
||||||
|
freeformExtras.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
console.log(indices)
|
console.log(indices, freeformExtras);
|
||||||
|
|
||||||
|
if (freeformField) {
|
||||||
|
if (freeformExtras.length > 0) {
|
||||||
|
freeformField.GetValue().setData(new Tag(this._configuration.freeform.key, freeformExtras.join(";")));
|
||||||
|
indices.push(indexOf(elements, freeformField))
|
||||||
|
} else {
|
||||||
|
freeformField.GetValue().setData(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return indices;
|
return indices;
|
||||||
},
|
},
|
||||||
elements.map(el => el.GetValue())
|
elements.map(el => el.GetValue())
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
.featureinfobox-title {
|
.featureinfobox-title {
|
||||||
background-color: deeppink;
|
font-size: xx-large;
|
||||||
}
|
}
|
||||||
.featureinfobox-icons img{
|
.featureinfobox-icons img{
|
||||||
max-height: 1.5em;
|
max-height: 1.5em;
|
||||||
}
|
}
|
||||||
.featureinfobox-icons {
|
.featureinfobox-icons {
|
||||||
background-color: red;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.featureinfobox-titlebar{
|
.featureinfobox-titlebar{
|
||||||
|
|
29
test.ts
29
test.ts
|
@ -6,29 +6,42 @@ import {TagRenderingConfigJson} from "./Customizations/JSON/TagRenderingConfigJs
|
||||||
import TagRenderingConfig from "./Customizations/JSON/TagRenderingConfig";
|
import TagRenderingConfig from "./Customizations/JSON/TagRenderingConfig";
|
||||||
import Locale from "./UI/i18n/Locale";
|
import Locale from "./UI/i18n/Locale";
|
||||||
import EditableTagRendering from "./UI/Popup/EditableTagRendering";
|
import EditableTagRendering from "./UI/Popup/EditableTagRendering";
|
||||||
|
import TagRenderingQuestion from "./UI/Popup/TagRenderingQuestion";
|
||||||
|
|
||||||
const tagRendering: TagRenderingConfigJson = {
|
const tagRendering: TagRenderingConfigJson = {
|
||||||
question: {"en": "What is the name of?", nl: "Wat is de naam van?", fr: "C'est quoi le nom"},
|
question: {"en": "What is the name of?", nl: "Wat is de naam van?", fr: "C'est quoi le nom"},
|
||||||
mappings: [
|
mappings: [
|
||||||
{
|
{
|
||||||
if: "noname=yes",
|
if: "valves=A",
|
||||||
then: "Has no name"
|
then: "A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: "valves=B",
|
||||||
|
then: "B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: "valves=C",
|
||||||
|
then: "C"
|
||||||
|
}, {
|
||||||
|
if: "valves:special=A",
|
||||||
|
then: "SPecial"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
render: "The name is {name}",
|
render: "Valves: {valves}",
|
||||||
|
multiAnswer: true,
|
||||||
freeform: {
|
freeform: {
|
||||||
key: "name",
|
key: "valves",
|
||||||
type: "string",
|
type: "string",
|
||||||
addExtraTags: ["noname="]
|
addExtraTags: ["fixme=valves"]
|
||||||
}//*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = new TagRenderingConfig(tagRendering)
|
const config = new TagRenderingConfig(tagRendering)
|
||||||
|
|
||||||
const tags = new UIEventSource({id: "node/-1", "amenity": "bench", name: "pietervdvn"})
|
const tags = new UIEventSource({id: "node/-1", "amenity": "bench", name: "pietervdvn"})
|
||||||
|
|
||||||
// new TagRenderingQuestion(tags, config).AttachTo("maindiv")
|
new TagRenderingQuestion(tags, config).AttachTo("maindiv")
|
||||||
new EditableTagRendering(tags, config).AttachTo('maindiv')
|
// new EditableTagRendering(tags, config).AttachTo('maindiv')
|
||||||
Locale.CreateLanguagePicker(["nl", "en", "fr"]).AttachTo("extradiv")
|
Locale.CreateLanguagePicker(["nl", "en", "fr"]).AttachTo("extradiv")
|
||||||
/*/
|
/*/
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue