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
|
@ -21,7 +21,7 @@ export default class TagRenderingConfig {
|
||||||
addExtraTags: TagsFilter[];
|
addExtraTags: TagsFilter[];
|
||||||
};
|
};
|
||||||
|
|
||||||
multiAnswer: boolean;
|
readonly multiAnswer: boolean;
|
||||||
|
|
||||||
mappings?: {
|
mappings?: {
|
||||||
if: TagsFilter,
|
if: TagsFilter,
|
||||||
|
@ -69,7 +69,7 @@ export default class TagRenderingConfig {
|
||||||
if (mapping.then === undefined) {
|
if (mapping.then === undefined) {
|
||||||
throw "Invalid mapping: if without body"
|
throw "Invalid mapping: if without body"
|
||||||
}
|
}
|
||||||
let hideInAnswer : boolean | TagsFilter = false;
|
let hideInAnswer: boolean | TagsFilter = false;
|
||||||
if (typeof mapping.hideInAnswer === "boolean") {
|
if (typeof mapping.hideInAnswer === "boolean") {
|
||||||
hideInAnswer = mapping.hideInAnswer;
|
hideInAnswer = mapping.hideInAnswer;
|
||||||
} else if (mapping.hideInAnswer !== undefined) {
|
} else if (mapping.hideInAnswer !== undefined) {
|
||||||
|
@ -111,7 +111,8 @@ export default class TagRenderingConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.freeform?.key === undefined){
|
|
||||||
|
if (this.freeform?.key === undefined) {
|
||||||
return this.render;
|
return this.render;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,14 @@ export default class MetaTagging {
|
||||||
// AUtomatically triggered on the next change
|
// AUtomatically triggered on the next change
|
||||||
const updateTags = () => {
|
const updateTags = () => {
|
||||||
const oldValueIsOpen = tags["_isOpen"];
|
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";
|
tags["_isOpen"] = oh.getState() ? "yes" : "no";
|
||||||
const comment = oh.getComment();
|
const comment = oh.getComment();
|
||||||
if (comment) {
|
if (comment) {
|
||||||
|
@ -113,10 +121,16 @@ export default class MetaTagging {
|
||||||
|
|
||||||
const nextChange = oh.getNextChange();
|
const nextChange = oh.getNextChange();
|
||||||
if (nextChange !== undefined) {
|
if (nextChange !== undefined) {
|
||||||
|
const timeout = nextChange.getTime() - (new Date()).getTime();
|
||||||
|
tags["_isOpen:nextTrigger"] = nextChange.getTime();
|
||||||
|
tags["_isOpen:oldvalue"] = tags.opening_hours
|
||||||
window.setTimeout(
|
window.setTimeout(
|
||||||
updateTags,
|
() => {
|
||||||
(nextChange.getTime() - (new Date()).getTime())
|
console.log("Updating the _isOpen tag for ", tags.id);
|
||||||
)
|
updateTags();
|
||||||
|
},
|
||||||
|
timeout
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateTags();
|
updateTags();
|
||||||
|
|
116
Logic/Tags.ts
116
Logic/Tags.ts
|
@ -2,8 +2,11 @@ import {Utils} from "../Utils";
|
||||||
|
|
||||||
export abstract class TagsFilter {
|
export abstract class TagsFilter {
|
||||||
abstract matches(tags: { k: string, v: string }[]): boolean
|
abstract matches(tags: { k: string, v: string }[]): boolean
|
||||||
|
|
||||||
abstract asOverpass(): string[]
|
abstract asOverpass(): string[]
|
||||||
abstract substituteValues(tags: any) : TagsFilter;
|
|
||||||
|
abstract substituteValues(tags: any): TagsFilter;
|
||||||
|
|
||||||
abstract isUsableAsAnswer(): boolean;
|
abstract isUsableAsAnswer(): boolean;
|
||||||
|
|
||||||
abstract isEquivalent(other: TagsFilter): boolean;
|
abstract isEquivalent(other: TagsFilter): boolean;
|
||||||
|
@ -28,15 +31,8 @@ export class RegexTag extends TagsFilter {
|
||||||
this.invert = invert;
|
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 {
|
private static doesMatch(fromTag: string, possibleRegex: string | RegExp): boolean {
|
||||||
if(typeof possibleRegex === "string"){
|
if (typeof possibleRegex === "string") {
|
||||||
return fromTag === possibleRegex;
|
return fromTag === possibleRegex;
|
||||||
}
|
}
|
||||||
return fromTag.match(possibleRegex) !== null;
|
return fromTag.match(possibleRegex) !== null;
|
||||||
|
@ -48,14 +44,21 @@ export class RegexTag extends TagsFilter {
|
||||||
}
|
}
|
||||||
return r.source;
|
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 {
|
isUsableAsAnswer(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
matches(tags: { k: string; v: string }[]): boolean {
|
matches(tags: { k: string; v: string }[]): boolean {
|
||||||
for (const tag of tags) {
|
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;
|
return RegexTag.doesMatch(tag.v, this.value) != this.invert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +81,7 @@ export class RegexTag extends TagsFilter {
|
||||||
if (other instanceof RegexTag) {
|
if (other instanceof RegexTag) {
|
||||||
return other.asHumanString() == this.asHumanString();
|
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 RegexTag.doesMatch(other.key, this.key) && RegexTag.doesMatch(other.value, this.value);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,27 +97,27 @@ export class Tag extends TagsFilter {
|
||||||
super()
|
super()
|
||||||
this.key = key
|
this.key = key
|
||||||
this.value = value
|
this.value = value
|
||||||
if(key === undefined || key === ""){
|
if (key === undefined || key === "") {
|
||||||
throw "Invalid key: undefined or empty";
|
throw "Invalid key: undefined or empty";
|
||||||
}
|
}
|
||||||
if(value === undefined){
|
if (value === undefined) {
|
||||||
throw "Invalid value: value is undefined";
|
throw "Invalid value: value is undefined";
|
||||||
}
|
}
|
||||||
if(value === "*"){
|
if (value === "*") {
|
||||||
console.warn(`Got suspicious tag ${key}=* ; did you mean ${key}~* ?`)
|
console.warn(`Got suspicious tag ${key}=* ; did you mean ${key}~* ?`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matches(tags: { k: string; v: string }[]): boolean {
|
matches(tags: { k: string; v: string }[]): boolean {
|
||||||
|
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
if (this.key == tag.k) {
|
if (this.key == tag.k) {
|
||||||
return this.value === tag.v;
|
return this.value === tag.v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The tag was not found
|
// The tag was not found
|
||||||
if(this.value === ""){
|
if (this.value === "") {
|
||||||
// and it shouldn't be found!
|
// and it shouldn't be found!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -146,16 +149,16 @@ export class Tag extends TagsFilter {
|
||||||
}
|
}
|
||||||
return this.key + "=" + v;
|
return this.key + "=" + v;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUsableAsAnswer(): boolean {
|
isUsableAsAnswer(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEquivalent(other: TagsFilter): boolean {
|
isEquivalent(other: TagsFilter): boolean {
|
||||||
if(other instanceof Tag){
|
if (other instanceof Tag) {
|
||||||
return this.key === other.key && this.value === other.value;
|
return this.key === other.key && this.value === other.value;
|
||||||
}
|
}
|
||||||
if(other instanceof RegexTag){
|
if (other instanceof RegexTag) {
|
||||||
other.isEquivalent(this);
|
other.isEquivalent(this);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -185,7 +188,7 @@ export class Or extends TagsFilter {
|
||||||
const choices = [];
|
const choices = [];
|
||||||
for (const tagsFilter of this.or) {
|
for (const tagsFilter of this.or) {
|
||||||
const subChoices = tagsFilter.asOverpass();
|
const subChoices = tagsFilter.asOverpass();
|
||||||
for(const subChoice of subChoices){
|
for (const subChoice of subChoices) {
|
||||||
choices.push(subChoice)
|
choices.push(subChoice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,21 +206,21 @@ export class Or extends TagsFilter {
|
||||||
asHumanString(linkToWiki: boolean, shorten: boolean) {
|
asHumanString(linkToWiki: boolean, shorten: boolean) {
|
||||||
return this.or.map(t => t.asHumanString(linkToWiki, shorten)).join("|");
|
return this.or.map(t => t.asHumanString(linkToWiki, shorten)).join("|");
|
||||||
}
|
}
|
||||||
|
|
||||||
isUsableAsAnswer(): boolean {
|
isUsableAsAnswer(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEquivalent(other: TagsFilter): boolean {
|
isEquivalent(other: TagsFilter): boolean {
|
||||||
if(other instanceof Or){
|
if (other instanceof Or) {
|
||||||
|
|
||||||
for (const selfTag of this.or) {
|
for (const selfTag of this.or) {
|
||||||
let matchFound = false;
|
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];
|
let otherTag = other.or[i];
|
||||||
matchFound = selfTag.isEquivalent(otherTag);
|
matchFound = selfTag.isEquivalent(otherTag);
|
||||||
}
|
}
|
||||||
if(!matchFound){
|
if (!matchFound) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +239,14 @@ export class And extends TagsFilter {
|
||||||
this.and = and;
|
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 {
|
matches(tags: { k: string; v: string }[]): boolean {
|
||||||
for (const tagsFilter of this.and) {
|
for (const tagsFilter of this.and) {
|
||||||
if (!tagsFilter.matches(tags)) {
|
if (!tagsFilter.matches(tags)) {
|
||||||
|
@ -246,14 +257,6 @@ export class And extends TagsFilter {
|
||||||
return true;
|
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[] {
|
asOverpass(): string[] {
|
||||||
let allChoices: string[] = null;
|
let allChoices: string[] = null;
|
||||||
for (const andElement of this.and) {
|
for (const andElement of this.and) {
|
||||||
|
@ -285,16 +288,16 @@ export class And extends TagsFilter {
|
||||||
asHumanString(linkToWiki: boolean, shorten: boolean) {
|
asHumanString(linkToWiki: boolean, shorten: boolean) {
|
||||||
return this.and.map(t => t.asHumanString(linkToWiki, shorten)).join("&");
|
return this.and.map(t => t.asHumanString(linkToWiki, shorten)).join("&");
|
||||||
}
|
}
|
||||||
|
|
||||||
isUsableAsAnswer(): boolean {
|
isUsableAsAnswer(): boolean {
|
||||||
for (const t of this.and) {
|
for (const t of this.and) {
|
||||||
if(!t.isUsableAsAnswer()){
|
if (!t.isUsableAsAnswer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEquivalent(other: TagsFilter): boolean {
|
isEquivalent(other: TagsFilter): boolean {
|
||||||
if (!(other instanceof And)) {
|
if (!(other instanceof And)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -343,7 +346,6 @@ export class And extends TagsFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class TagUtils {
|
export class TagUtils {
|
||||||
static proprtiesToKV(properties: any): { k: string, v: string }[] {
|
static proprtiesToKV(properties: any): { k: string, v: string }[] {
|
||||||
const result = [];
|
const result = [];
|
||||||
|
@ -374,13 +376,13 @@ export class TagUtils {
|
||||||
/**
|
/**
|
||||||
* Given two hashes of {key --> values[]}, makes sure that every neededTag is present in availableTags
|
* 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) {
|
for (const neededKey in neededTags) {
|
||||||
const availableValues : string[] = availableTags[neededKey]
|
const availableValues: string[] = availableTags[neededKey]
|
||||||
if(availableValues === undefined){
|
if (availableValues === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const neededValues : string[] = neededTags[neededKey];
|
const neededValues: string[] = neededTags[neededKey];
|
||||||
for (const neededValue of neededValues) {
|
for (const neededValue of neededValues) {
|
||||||
if (availableValues.indexOf(neededValue) < 0) {
|
if (availableValues.indexOf(neededValue) < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -392,11 +394,11 @@ export class TagUtils {
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Creates a hash {key --> [values]}, with all the values present in the tagsfilter
|
* Creates a hash {key --> [values]}, with all the values present in the tagsfilter
|
||||||
*
|
*
|
||||||
* @param tagsFilters
|
* @param tagsFilters
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
static SplitKeys(tagsFilters: TagsFilter[]){
|
static SplitKeys(tagsFilters: TagsFilter[]) {
|
||||||
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) {
|
||||||
|
@ -425,6 +427,7 @@ export class TagUtils {
|
||||||
}
|
}
|
||||||
return keyValues;
|
return keyValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
||||||
* E.g:
|
* E.g:
|
||||||
|
@ -449,4 +452,21 @@ export class TagUtils {
|
||||||
return new And(and);
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { Utils } from "../Utils";
|
import { Utils } from "../Utils";
|
||||||
|
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
public static vNumber = "0.3.0a";
|
public static vNumber = "0.3.0c";
|
||||||
|
|
||||||
// The user journey states thresholds when a new feature gets unlocked
|
// The user journey states thresholds when a new feature gets unlocked
|
||||||
public static userJourney = {
|
public static userJourney = {
|
||||||
|
|
|
@ -40,15 +40,22 @@ export default class MoreScreen extends UIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentLocation = State.state.locationControl.data;
|
const currentLocation = State.state.locationControl.data;
|
||||||
|
let path = window.location.pathname;
|
||||||
|
// Path starts with a '/' and contains everything, e.g. '/dir/dir/page.html'
|
||||||
|
path = path.substr(0, path.lastIndexOf("/"));
|
||||||
|
// Path will now contain '/dir/dir', or empty string in case of nothing
|
||||||
|
if(path === ""){
|
||||||
|
path = "."
|
||||||
|
}
|
||||||
let linkText =
|
let linkText =
|
||||||
`./${layout.id.toLowerCase()}.html?z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}`
|
`${path}/${layout.id.toLowerCase()}?z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}`
|
||||||
|
|
||||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
|
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
|
||||||
linkText = `./index.html?layout=${layout.id}&z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}`
|
linkText = `${path}/index.html?layout=${layout.id}&z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customThemeDefinition) {
|
if (customThemeDefinition) {
|
||||||
linkText = `./index.html?userlayout=${layout.id}&z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}#${customThemeDefinition}`
|
linkText = `${path}/?userlayout=${layout.id}&z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}#${customThemeDefinition}`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,13 +147,15 @@ export default class ShareScreen extends UIElement {
|
||||||
const url = (currentLocation ?? new UIEventSource(undefined)).map(() => {
|
const url = (currentLocation ?? new UIEventSource(undefined)).map(() => {
|
||||||
|
|
||||||
const host = window.location.host;
|
const host = window.location.host;
|
||||||
let literalText = `https://${host}/${layout.id.toLowerCase()}.html`
|
let path = window.location.pathname;
|
||||||
|
path = path.substr(0, path.lastIndexOf("/"));
|
||||||
|
let literalText = `https://${host}${path}/${layout.id.toLowerCase()}`
|
||||||
|
|
||||||
const parts = Utils.NoEmpty(Utils.NoNull(optionParts.map((eventSource) => eventSource.data)));
|
const parts = Utils.NoEmpty(Utils.NoNull(optionParts.map((eventSource) => eventSource.data)));
|
||||||
|
|
||||||
let hash = "";
|
let hash = "";
|
||||||
if (layoutDefinition !== undefined) {
|
if (layoutDefinition !== undefined) {
|
||||||
literalText = `https://${host}/index.html`
|
literalText = `https://${host}${path}/`
|
||||||
if (layout.id.startsWith("wiki:")) {
|
if (layout.id.startsWith("wiki:")) {
|
||||||
parts.push("userlayout=" + encodeURIComponent(layout.id))
|
parts.push("userlayout=" + encodeURIComponent(layout.id))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -196,7 +196,7 @@ export default class OpeningHoursVisualization extends UIElement {
|
||||||
// Closed!
|
// Closed!
|
||||||
const opensAtDate = oh.getNextChange();
|
const opensAtDate = oh.getNextChange();
|
||||||
if(opensAtDate === undefined){
|
if(opensAtDate === undefined){
|
||||||
const comm = oh.getComment();
|
const comm = oh.getComment() ?? oh.getUnknown();
|
||||||
if(comm !== undefined){
|
if(comm !== undefined){
|
||||||
return new FixedUiElement(comm).SetClass("ohviz-closed").Render();
|
return new FixedUiElement(comm).SetClass("ohviz-closed").Render();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Combine from "../Base/Combine";
|
||||||
import TagRenderingAnswer from "./TagRenderingAnswer";
|
import TagRenderingAnswer from "./TagRenderingAnswer";
|
||||||
import State from "../../State";
|
import State from "../../State";
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg";
|
||||||
|
import {TagUtils} from "../../Logic/Tags";
|
||||||
|
|
||||||
export default class EditableTagRendering extends UIElement {
|
export default class EditableTagRendering extends UIElement {
|
||||||
private readonly _tags: UIEventSource<any>;
|
private readonly _tags: UIEventSource<any>;
|
||||||
|
@ -45,6 +46,29 @@ export default class EditableTagRendering extends UIElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InnerRender(): string {
|
||||||
|
if (!this._configuration?.condition?.matchesProperties(this._tags.data)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (this._editMode.data) {
|
||||||
|
return this._question.Render();
|
||||||
|
}
|
||||||
|
if (this._configuration.multiAnswer) {
|
||||||
|
const atLeastOneMatch = this._configuration.mappings.some(mp =>TagUtils.MatchesMultiAnswer(mp.if, this._tags.data));
|
||||||
|
console.log("SOME MATCH?", atLeastOneMatch)
|
||||||
|
if (!atLeastOneMatch) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} else if (this._configuration.GetRenderValue(this._tags.data) === undefined) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Combine([this._answer,
|
||||||
|
(State.state?.osmConnection?.userDetails?.data?.loggedIn ?? true) ? this._editButton : undefined
|
||||||
|
]).SetClass("answer")
|
||||||
|
.Render();
|
||||||
|
}
|
||||||
|
|
||||||
private GenerateQuestion() {
|
private GenerateQuestion() {
|
||||||
const self = this;
|
const self = this;
|
||||||
if (this._configuration.question !== undefined) {
|
if (this._configuration.question !== undefined) {
|
||||||
|
@ -64,25 +88,4 @@ export default class EditableTagRendering extends UIElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InnerRender(): string {
|
|
||||||
|
|
||||||
if (this._editMode.data) {
|
|
||||||
return this._question.Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this._configuration.GetRenderValue(this._tags.data)=== undefined){
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this._configuration?.condition?.matchesProperties(this._tags.data)){
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Combine([this._answer,
|
|
||||||
(State.state?.osmConnection?.userDetails?.data?.loggedIn ?? true) ? this._editButton : undefined
|
|
||||||
]).SetClass("answer")
|
|
||||||
.Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||||
import TagRenderingQuestion from "./TagRenderingQuestion";
|
import TagRenderingQuestion from "./TagRenderingQuestion";
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
|
import {TagUtils} from "../../Logic/Tags";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,20 +47,39 @@ export default class QuestionBox extends UIElement {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if it is known or not shown, false if the question should be asked
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
IsKnown(tagRendering: TagRenderingConfig): boolean {
|
||||||
|
if (tagRendering.condition &&
|
||||||
|
!tagRendering.condition.matchesProperties(this._tags.data)) {
|
||||||
|
// Filtered away by the condition
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(tagRendering.multiAnswer){
|
||||||
|
for (const m of tagRendering.mappings) {
|
||||||
|
if(TagUtils.MatchesMultiAnswer(m.if, this._tags.data)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagRendering.GetRenderValue(this._tags.data) !== undefined) {
|
||||||
|
// This value is known and can be rendered
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
InnerRender(): string {
|
InnerRender(): string {
|
||||||
for (let i = 0; i < this._tagRenderingQuestions.length; i++) {
|
for (let i = 0; i < this._tagRenderingQuestions.length; i++) {
|
||||||
let tagRendering = this._tagRenderings[i];
|
let tagRendering = this._tagRenderings[i];
|
||||||
if(tagRendering.condition &&
|
|
||||||
!tagRendering.condition.matchesProperties(this._tags.data)){
|
if(this.IsKnown(tagRendering)){
|
||||||
// Filtered away by the condition
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagRendering.GetRenderValue(this._tags.data) !== undefined) {
|
|
||||||
// This value is known
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (this._skippedQuestions.data.indexOf(i) >= 0) {
|
if (this._skippedQuestions.data.indexOf(i) >= 0) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -2,6 +2,9 @@ import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||||
import {UIElement} from "../UIElement";
|
import {UIElement} from "../UIElement";
|
||||||
import {SubstitutedTranslation} from "../SpecialVisualizations";
|
import {SubstitutedTranslation} from "../SpecialVisualizations";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
import Combine from "../Base/Combine";
|
||||||
|
import {TagUtils} from "../../Logic/Tags";
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Displays the correct value for a known tagrendering
|
* Displays the correct value for a known tagrendering
|
||||||
|
@ -15,7 +18,7 @@ export default class TagRenderingAnswer extends UIElement {
|
||||||
super(tags);
|
super(tags);
|
||||||
this._tags = tags;
|
this._tags = tags;
|
||||||
this._configuration = configuration;
|
this._configuration = configuration;
|
||||||
if(configuration === undefined){
|
if (configuration === undefined) {
|
||||||
throw "Trying to generate a tagRenderingAnswer without configuration..."
|
throw "Trying to generate a tagRenderingAnswer without configuration..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,12 +35,38 @@ export default class TagRenderingAnswer extends UIElement {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const tr = this._configuration.GetRenderValue(tags);
|
const tr = this._configuration.GetRenderValue(tags);
|
||||||
if (tr === undefined) {
|
if (tr !== undefined) {
|
||||||
return "";
|
this._content = new SubstitutedTranslation(tr, this._tags);
|
||||||
|
return this._content.Render();
|
||||||
}
|
}
|
||||||
// Bit of a hack; remember that the fields are updated
|
|
||||||
this._content = new SubstitutedTranslation(tr, this._tags);
|
// The render value doesn't work well with multi-answers (checkboxes), so we have to check for them manually
|
||||||
return this._content.Render();
|
if (this._configuration.multiAnswer) {
|
||||||
|
const applicableThens = Utils.NoNull(this._configuration.mappings.map(mapping => {
|
||||||
|
if (mapping.if === undefined) {
|
||||||
|
return mapping.then;
|
||||||
|
}
|
||||||
|
if (TagUtils.MatchesMultiAnswer(mapping.if, tags)) {
|
||||||
|
return mapping.then;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}))
|
||||||
|
if (applicableThens.length >= 0) {
|
||||||
|
if (applicableThens.length === 1) {
|
||||||
|
this._content = applicableThens[0];
|
||||||
|
} else {
|
||||||
|
this._content = new Combine(["<ul>",
|
||||||
|
...applicableThens.map(tr => new Combine(["<li>", tr, "</li>"]))
|
||||||
|
,
|
||||||
|
"</ul>"
|
||||||
|
])
|
||||||
|
|
||||||
|
}
|
||||||
|
return this._content.Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -53,7 +53,9 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
this._inputElement = this.GenerateInputElement()
|
this._inputElement = this.GenerateInputElement()
|
||||||
const self = this;
|
const self = this;
|
||||||
const save = () => {
|
const save = () => {
|
||||||
|
console.log("Save clicked!")
|
||||||
const selection = self._inputElement.GetValue().data;
|
const selection = self._inputElement.GetValue().data;
|
||||||
|
console.log("Selection is", selection)
|
||||||
if (selection) {
|
if (selection) {
|
||||||
(State.state?.changes ?? new Changes())
|
(State.state?.changes ?? new Changes())
|
||||||
.addTag(tags.data.id, selection, tags);
|
.addTag(tags.data.id, selection, tags);
|
||||||
|
|
Loading…
Reference in a new issue