forked from MapComplete/MapComplete
Fix rendering of multianswers without explicit 'render'-field
This commit is contained in:
parent
52d9b2f452
commit
a35b80afbb
11 changed files with 195 additions and 97 deletions
|
@ -101,6 +101,14 @@ export default class MetaTagging {
|
|||
// AUtomatically triggered on the next change
|
||||
const updateTags = () => {
|
||||
const oldValueIsOpen = tags["_isOpen"];
|
||||
const oldNextChange =tags["_isOpen:nextTrigger"] ?? 0;
|
||||
|
||||
if(oldNextChange > (new Date()).getTime() &&
|
||||
tags["_isOpen:oldvalue"] === tags["opening_hours"]){
|
||||
// Already calculated and should not yet be triggered
|
||||
return;
|
||||
}
|
||||
|
||||
tags["_isOpen"] = oh.getState() ? "yes" : "no";
|
||||
const comment = oh.getComment();
|
||||
if (comment) {
|
||||
|
@ -113,10 +121,16 @@ export default class MetaTagging {
|
|||
|
||||
const nextChange = oh.getNextChange();
|
||||
if (nextChange !== undefined) {
|
||||
const timeout = nextChange.getTime() - (new Date()).getTime();
|
||||
tags["_isOpen:nextTrigger"] = nextChange.getTime();
|
||||
tags["_isOpen:oldvalue"] = tags.opening_hours
|
||||
window.setTimeout(
|
||||
updateTags,
|
||||
(nextChange.getTime() - (new Date()).getTime())
|
||||
)
|
||||
() => {
|
||||
console.log("Updating the _isOpen tag for ", tags.id);
|
||||
updateTags();
|
||||
},
|
||||
timeout
|
||||
)
|
||||
}
|
||||
}
|
||||
updateTags();
|
||||
|
|
116
Logic/Tags.ts
116
Logic/Tags.ts
|
@ -2,8 +2,11 @@ import {Utils} from "../Utils";
|
|||
|
||||
export abstract class TagsFilter {
|
||||
abstract matches(tags: { k: string, v: string }[]): boolean
|
||||
|
||||
abstract asOverpass(): string[]
|
||||
abstract substituteValues(tags: any) : TagsFilter;
|
||||
|
||||
abstract substituteValues(tags: any): TagsFilter;
|
||||
|
||||
abstract isUsableAsAnswer(): boolean;
|
||||
|
||||
abstract isEquivalent(other: TagsFilter): boolean;
|
||||
|
@ -28,15 +31,8 @@ export class RegexTag extends TagsFilter {
|
|||
this.invert = invert;
|
||||
}
|
||||
|
||||
asOverpass(): string[] {
|
||||
if (typeof this.key === "string") {
|
||||
return [`['${this.key}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
|
||||
}
|
||||
return [`[~'${this.key.source}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
|
||||
}
|
||||
|
||||
private static doesMatch(fromTag: string, possibleRegex: string | RegExp): boolean {
|
||||
if(typeof possibleRegex === "string"){
|
||||
if (typeof possibleRegex === "string") {
|
||||
return fromTag === possibleRegex;
|
||||
}
|
||||
return fromTag.match(possibleRegex) !== null;
|
||||
|
@ -48,14 +44,21 @@ export class RegexTag extends TagsFilter {
|
|||
}
|
||||
return r.source;
|
||||
}
|
||||
|
||||
|
||||
asOverpass(): string[] {
|
||||
if (typeof this.key === "string") {
|
||||
return [`['${this.key}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
|
||||
}
|
||||
return [`[~'${this.key.source}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
|
||||
}
|
||||
|
||||
isUsableAsAnswer(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
matches(tags: { k: string; v: string }[]): boolean {
|
||||
for (const tag of tags) {
|
||||
if (RegexTag.doesMatch(tag.k, this.key)){
|
||||
if (RegexTag.doesMatch(tag.k, this.key)) {
|
||||
return RegexTag.doesMatch(tag.v, this.value) != this.invert;
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +81,7 @@ export class RegexTag extends TagsFilter {
|
|||
if (other instanceof RegexTag) {
|
||||
return other.asHumanString() == this.asHumanString();
|
||||
}
|
||||
if(other instanceof Tag){
|
||||
if (other instanceof Tag) {
|
||||
return RegexTag.doesMatch(other.key, this.key) && RegexTag.doesMatch(other.value, this.value);
|
||||
}
|
||||
return false;
|
||||
|
@ -94,27 +97,27 @@ export class Tag extends TagsFilter {
|
|||
super()
|
||||
this.key = key
|
||||
this.value = value
|
||||
if(key === undefined || key === ""){
|
||||
if (key === undefined || key === "") {
|
||||
throw "Invalid key: undefined or empty";
|
||||
}
|
||||
if(value === undefined){
|
||||
if (value === undefined) {
|
||||
throw "Invalid value: value is undefined";
|
||||
}
|
||||
if(value === "*"){
|
||||
console.warn(`Got suspicious tag ${key}=* ; did you mean ${key}~* ?`)
|
||||
if (value === "*") {
|
||||
console.warn(`Got suspicious tag ${key}=* ; did you mean ${key}~* ?`)
|
||||
}
|
||||
}
|
||||
|
||||
matches(tags: { k: string; v: string }[]): boolean {
|
||||
|
||||
|
||||
for (const tag of tags) {
|
||||
if (this.key == tag.k) {
|
||||
return this.value === tag.v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The tag was not found
|
||||
if(this.value === ""){
|
||||
if (this.value === "") {
|
||||
// and it shouldn't be found!
|
||||
return true;
|
||||
}
|
||||
|
@ -146,16 +149,16 @@ export class Tag extends TagsFilter {
|
|||
}
|
||||
return this.key + "=" + v;
|
||||
}
|
||||
|
||||
|
||||
isUsableAsAnswer(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
isEquivalent(other: TagsFilter): boolean {
|
||||
if(other instanceof Tag){
|
||||
if (other instanceof Tag) {
|
||||
return this.key === other.key && this.value === other.value;
|
||||
}
|
||||
if(other instanceof RegexTag){
|
||||
if (other instanceof RegexTag) {
|
||||
other.isEquivalent(this);
|
||||
}
|
||||
return false;
|
||||
|
@ -185,7 +188,7 @@ export class Or extends TagsFilter {
|
|||
const choices = [];
|
||||
for (const tagsFilter of this.or) {
|
||||
const subChoices = tagsFilter.asOverpass();
|
||||
for(const subChoice of subChoices){
|
||||
for (const subChoice of subChoices) {
|
||||
choices.push(subChoice)
|
||||
}
|
||||
}
|
||||
|
@ -203,21 +206,21 @@ export class Or extends TagsFilter {
|
|||
asHumanString(linkToWiki: boolean, shorten: boolean) {
|
||||
return this.or.map(t => t.asHumanString(linkToWiki, shorten)).join("|");
|
||||
}
|
||||
|
||||
|
||||
isUsableAsAnswer(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
isEquivalent(other: TagsFilter): boolean {
|
||||
if(other instanceof Or){
|
||||
if (other instanceof Or) {
|
||||
|
||||
for (const selfTag of this.or) {
|
||||
let matchFound = false;
|
||||
for (let i = 0; i < other.or.length && !matchFound; i++){
|
||||
for (let i = 0; i < other.or.length && !matchFound; i++) {
|
||||
let otherTag = other.or[i];
|
||||
matchFound = selfTag.isEquivalent(otherTag);
|
||||
}
|
||||
if(!matchFound){
|
||||
if (!matchFound) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -236,6 +239,14 @@ export class And extends TagsFilter {
|
|||
this.and = and;
|
||||
}
|
||||
|
||||
private static combine(filter: string, choices: string[]): string[] {
|
||||
const values = [];
|
||||
for (const or of choices) {
|
||||
values.push(filter + or);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
matches(tags: { k: string; v: string }[]): boolean {
|
||||
for (const tagsFilter of this.and) {
|
||||
if (!tagsFilter.matches(tags)) {
|
||||
|
@ -246,14 +257,6 @@ export class And extends TagsFilter {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static combine(filter: string, choices: string[]): string[] {
|
||||
const values = [];
|
||||
for (const or of choices) {
|
||||
values.push(filter + or);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
asOverpass(): string[] {
|
||||
let allChoices: string[] = null;
|
||||
for (const andElement of this.and) {
|
||||
|
@ -285,16 +288,16 @@ export class And extends TagsFilter {
|
|||
asHumanString(linkToWiki: boolean, shorten: boolean) {
|
||||
return this.and.map(t => t.asHumanString(linkToWiki, shorten)).join("&");
|
||||
}
|
||||
|
||||
|
||||
isUsableAsAnswer(): boolean {
|
||||
for (const t of this.and) {
|
||||
if(!t.isUsableAsAnswer()){
|
||||
if (!t.isUsableAsAnswer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
isEquivalent(other: TagsFilter): boolean {
|
||||
if (!(other instanceof And)) {
|
||||
return false;
|
||||
|
@ -343,7 +346,6 @@ export class And extends TagsFilter {
|
|||
}
|
||||
|
||||
|
||||
|
||||
export class TagUtils {
|
||||
static proprtiesToKV(properties: any): { k: string, v: string }[] {
|
||||
const result = [];
|
||||
|
@ -374,13 +376,13 @@ export class TagUtils {
|
|||
/**
|
||||
* Given two hashes of {key --> values[]}, makes sure that every neededTag is present in availableTags
|
||||
*/
|
||||
static AllKeysAreContained(availableTags: any, neededTags: any){
|
||||
static AllKeysAreContained(availableTags: any, neededTags: any) {
|
||||
for (const neededKey in neededTags) {
|
||||
const availableValues : string[] = availableTags[neededKey]
|
||||
if(availableValues === undefined){
|
||||
const availableValues: string[] = availableTags[neededKey]
|
||||
if (availableValues === undefined) {
|
||||
return false;
|
||||
}
|
||||
const neededValues : string[] = neededTags[neededKey];
|
||||
const neededValues: string[] = neededTags[neededKey];
|
||||
for (const neededValue of neededValues) {
|
||||
if (availableValues.indexOf(neededValue) < 0) {
|
||||
return false;
|
||||
|
@ -392,11 +394,11 @@ export class TagUtils {
|
|||
|
||||
/***
|
||||
* Creates a hash {key --> [values]}, with all the values present in the tagsfilter
|
||||
*
|
||||
*
|
||||
* @param tagsFilters
|
||||
* @constructor
|
||||
*/
|
||||
static SplitKeys(tagsFilters: TagsFilter[]){
|
||||
static SplitKeys(tagsFilters: TagsFilter[]) {
|
||||
const keyValues = {} // Map string -> string[]
|
||||
tagsFilters = [...tagsFilters] // copy all
|
||||
while (tagsFilters.length > 0) {
|
||||
|
@ -425,6 +427,7 @@ export class TagUtils {
|
|||
}
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
||||
* E.g:
|
||||
|
@ -449,4 +452,21 @@ export class TagUtils {
|
|||
return new And(and);
|
||||
}
|
||||
|
||||
}
|
||||
static MatchesMultiAnswer(tag: TagsFilter, tags: any): boolean {
|
||||
const splitted = TagUtils.SplitKeys([tag]);
|
||||
console.log("Matching multianswer", tag, tags)
|
||||
for (const splitKey in splitted) {
|
||||
const neededValues = splitted[splitKey];
|
||||
const actualValue = tags[splitKey].split(";");
|
||||
for (const neededValue of neededValues) {
|
||||
console.log("needed", neededValue, "have: ", actualValue, actualValue.indexOf(neededValue) )
|
||||
if (actualValue.indexOf(neededValue) < 0) {
|
||||
console.log("NOT FOUND")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log("OK")
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue