forked from MapComplete/MapComplete
Refacotring: move themeConfig into models
This commit is contained in:
parent
0a01561d37
commit
647100bee5
79 changed files with 603 additions and 629 deletions
|
@ -1,6 +1,6 @@
|
|||
import LayerConfig from "./JSON/LayerConfig";
|
||||
import * as known_layers from "../assets/generated/known_layers_and_themes.json"
|
||||
import {Utils} from "../Utils";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export default class AllKnownLayers {
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import LayoutConfig from "./JSON/LayoutConfig";
|
||||
import AllKnownLayers from "./AllKnownLayers";
|
||||
import * as known_themes from "../assets/generated/known_layers_and_themes.json"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export class AllKnownLayouts {
|
||||
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import UnitConfigJson from "./UnitConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import BaseUIElement from "../../UI/BaseUIElement";
|
||||
import Combine from "../../UI/Base/Combine";
|
||||
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
|
||||
|
||||
export class Unit {
|
||||
public readonly appliesToKeys: Set<string>;
|
||||
public readonly denominations: Denomination[];
|
||||
public readonly denominationsSorted: Denomination[];
|
||||
public readonly defaultDenom: Denomination;
|
||||
public readonly eraseInvalid: boolean;
|
||||
private readonly possiblePostFixes: string[] = []
|
||||
|
||||
constructor(appliesToKeys: string[], applicableUnits: Denomination[], eraseInvalid: boolean) {
|
||||
this.appliesToKeys = new Set(appliesToKeys);
|
||||
this.denominations = applicableUnits;
|
||||
this.defaultDenom = applicableUnits.filter(denom => denom.default)[0]
|
||||
this.eraseInvalid = eraseInvalid
|
||||
|
||||
const seenUnitExtensions = new Set<string>();
|
||||
for (const denomination of this.denominations) {
|
||||
if(seenUnitExtensions.has(denomination.canonical)){
|
||||
throw "This canonical unit is already defined in another denomination: "+denomination.canonical
|
||||
}
|
||||
const duplicate = denomination.alternativeDenominations.filter(denom => seenUnitExtensions.has(denom))
|
||||
if(duplicate.length > 0){
|
||||
throw "A denomination is used multiple times: "+duplicate.join(", ")
|
||||
}
|
||||
|
||||
seenUnitExtensions.add(denomination.canonical)
|
||||
denomination.alternativeDenominations.forEach(d => seenUnitExtensions.add(d))
|
||||
}
|
||||
this.denominationsSorted = [...this.denominations]
|
||||
this.denominationsSorted.sort((a, b) => b.canonical.length - a.canonical.length)
|
||||
|
||||
|
||||
const possiblePostFixes = new Set<string>()
|
||||
function addPostfixesOf(str){
|
||||
str = str.toLowerCase()
|
||||
for (let i = 0; i < str.length + 1; i++) {
|
||||
const substr = str.substring(0,i)
|
||||
possiblePostFixes.add(substr)
|
||||
}
|
||||
}
|
||||
|
||||
for (const denomination of this.denominations) {
|
||||
addPostfixesOf(denomination.canonical)
|
||||
denomination.alternativeDenominations.forEach(addPostfixesOf)
|
||||
}
|
||||
this.possiblePostFixes = Array.from(possiblePostFixes)
|
||||
this.possiblePostFixes.sort((a, b) => b.length - a .length)
|
||||
}
|
||||
|
||||
isApplicableToKey(key: string | undefined): boolean {
|
||||
if (key === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.appliesToKeys.has(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds which denomination is applicable and gives the stripped value back
|
||||
*/
|
||||
findDenomination(valueWithDenom: string): [string, Denomination] {
|
||||
if(valueWithDenom === undefined){
|
||||
return undefined;
|
||||
}
|
||||
for (const denomination of this.denominationsSorted) {
|
||||
const bare = denomination.StrippedValue(valueWithDenom)
|
||||
if (bare !== null) {
|
||||
return [bare, denomination]
|
||||
}
|
||||
}
|
||||
return [undefined, undefined]
|
||||
}
|
||||
|
||||
asHumanLongValue(value: string): BaseUIElement {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const [stripped, denom] = this.findDenomination(value)
|
||||
const human = denom?.human
|
||||
if(human === undefined){
|
||||
return new FixedUiElement(stripped ?? value);
|
||||
}
|
||||
|
||||
const elems = denom.prefix ? [human, stripped] : [stripped, human];
|
||||
return new Combine(elems)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value without any (sub)parts of any denomination - usefull as preprocessing step for validating inputs.
|
||||
* E.g.
|
||||
* if 'megawatt' is a possible denomination, then '5 Meg' will be rewritten to '5' (which can then be validated as a valid pnat)
|
||||
*
|
||||
* Returns the original string if nothign matches
|
||||
*/
|
||||
stripUnitParts(str: string) {
|
||||
if(str === undefined){
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const denominationPart of this.possiblePostFixes) {
|
||||
if(str.endsWith(denominationPart)){
|
||||
return str.substring(0, str.length - denominationPart.length).trim()
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
export class Denomination {
|
||||
public readonly canonical: string;
|
||||
readonly default: boolean;
|
||||
readonly prefix: boolean;
|
||||
private readonly _human: Translation;
|
||||
public readonly alternativeDenominations: string [];
|
||||
|
||||
constructor(json: UnitConfigJson, context: string) {
|
||||
context = `${context}.unit(${json.canonicalDenomination})`
|
||||
this.canonical = json.canonicalDenomination.trim()
|
||||
if (this.canonical === undefined) {
|
||||
throw `${context}: this unit has no decent canonical value defined`
|
||||
}
|
||||
|
||||
json.alternativeDenomination.forEach((v, i) => {
|
||||
if (((v?.trim() ?? "") === "")) {
|
||||
throw `${context}.alternativeDenomination.${i}: invalid alternative denomination: undefined, null or only whitespace`
|
||||
}
|
||||
})
|
||||
|
||||
this.alternativeDenominations = json.alternativeDenomination?.map(v => v.trim()) ?? []
|
||||
|
||||
this.default = json.default ?? false;
|
||||
|
||||
this._human = Translations.T(json.human, context + "human")
|
||||
|
||||
this.prefix = json.prefix ?? false;
|
||||
|
||||
}
|
||||
|
||||
get human(): Translation {
|
||||
return this._human.Clone()
|
||||
}
|
||||
|
||||
public canonicalValue(value: string, actAsDefault?: boolean) {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const stripped = this.StrippedValue(value, actAsDefault)
|
||||
if (stripped === null) {
|
||||
return null;
|
||||
}
|
||||
return (stripped + " " + this.canonical.trim()).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the core value (without unit) if:
|
||||
* - the value ends with the canonical or an alternative value (or begins with if prefix is set)
|
||||
* - the value is a Number (without unit) and default is set
|
||||
*
|
||||
* Returns null if it doesn't match this unit
|
||||
*/
|
||||
public StrippedValue(value: string, actAsDefault?: boolean): string {
|
||||
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
value = value.toLowerCase()
|
||||
if (this.prefix) {
|
||||
if (value.startsWith(this.canonical) && this.canonical !== "") {
|
||||
return value.substring(this.canonical.length).trim();
|
||||
}
|
||||
for (const alternativeValue of this.alternativeDenominations) {
|
||||
if (value.startsWith(alternativeValue)) {
|
||||
return value.substring(alternativeValue.length).trim();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value.endsWith(this.canonical.toLowerCase()) && this.canonical !== "") {
|
||||
return value.substring(0, value.length - this.canonical.length).trim();
|
||||
}
|
||||
for (const alternativeValue of this.alternativeDenominations) {
|
||||
if (value.endsWith(alternativeValue.toLowerCase())) {
|
||||
return value.substring(0, value.length - alternativeValue.length).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.default || actAsDefault) {
|
||||
const parsed = Number(value.trim())
|
||||
if (!isNaN(parsed)) {
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import { TagsFilter } from "../../Logic/Tags/TagsFilter";
|
||||
import { Translation } from "../../UI/i18n/Translation";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import FilterConfigJson from "./FilterConfigJson";
|
||||
import { FromJSON } from "./FromJSON";
|
||||
|
||||
export default class FilterConfig {
|
||||
readonly options: {
|
||||
question: Translation;
|
||||
osmTags: TagsFilter;
|
||||
}[];
|
||||
|
||||
constructor(json: FilterConfigJson, context: string) {
|
||||
this.options = json.options.map((option, i) => {
|
||||
const question = Translations.T(
|
||||
option.question,
|
||||
context + ".options-[" + i + "].question"
|
||||
);
|
||||
const osmTags = FromJSON.Tag(
|
||||
option.osmTags ?? {and:[]},
|
||||
`${context}.options-[${i}].osmTags`
|
||||
);
|
||||
|
||||
return { question: question, osmTags: osmTags };
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import { AndOrTagConfigJson } from "./TagConfigJson";
|
||||
|
||||
export default interface FilterConfigJson {
|
||||
/**
|
||||
* The options for a filter
|
||||
* If there are multiple options these will be a list of radio buttons
|
||||
* If there is only one option this will be a checkbox
|
||||
* Filtering is done based on the given osmTags that are compared to the objects in that layer.
|
||||
*/
|
||||
options: { question: string | any; osmTags?: AndOrTagConfigJson | string }[];
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
import {AndOrTagConfigJson} from "./TagConfigJson";
|
||||
import {Utils} from "../../Utils";
|
||||
import {RegexTag} from "../../Logic/Tags/RegexTag";
|
||||
import {Or} from "../../Logic/Tags/Or";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import SubstitutingTag from "../../Logic/Tags/SubstitutingTag";
|
||||
import ComparingTag from "../../Logic/Tags/ComparingTag";
|
||||
|
||||
export class FromJSON {
|
||||
|
||||
public static SimpleTag(json: string, context?: string): Tag {
|
||||
const tag = Utils.SplitFirst(json, "=");
|
||||
if (tag.length !== 2) {
|
||||
throw `Invalid tag: no (or too much) '=' found (in ${context ?? "unkown context"})`
|
||||
}
|
||||
return new Tag(tag[0], tag[1]);
|
||||
}
|
||||
|
||||
public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
|
||||
try {
|
||||
return this.TagUnsafe(json, context);
|
||||
} catch (e) {
|
||||
console.error("Could not parse tag", json, "in context", context, "due to ", e)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static comparators
|
||||
: [string, (a: number, b: number) => boolean][]
|
||||
= [
|
||||
["<=", (a, b) => a <= b],
|
||||
[">=", (a, b) => a >= b],
|
||||
["<", (a, b) => a < b],
|
||||
[">", (a, b) => a > b],
|
||||
]
|
||||
|
||||
private static TagUnsafe(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
|
||||
|
||||
if (json === undefined) {
|
||||
throw `Error while parsing a tag: 'json' is undefined in ${context}. Make sure all the tags are defined and at least one tag is present in a complex expression`
|
||||
}
|
||||
if (typeof (json) == "string") {
|
||||
const tag = json as string;
|
||||
|
||||
for (const [operator, comparator] of FromJSON.comparators) {
|
||||
if (tag.indexOf(operator) >= 0) {
|
||||
const split = Utils.SplitFirst(tag, operator);
|
||||
|
||||
const val = Number(split[1].trim())
|
||||
if (isNaN(val)) {
|
||||
throw `Error: not a valid value for a comparison: ${split[1]}, make sure it is a number and nothing more (at ${context})`
|
||||
}
|
||||
|
||||
const f = (value: string | undefined) => {
|
||||
const b = Number(value?.replace(/[^\d.]/g,''))
|
||||
if (isNaN(b)) {
|
||||
return false;
|
||||
}
|
||||
return comparator(b, val)
|
||||
}
|
||||
return new ComparingTag(split[0], f, operator + val)
|
||||
}
|
||||
}
|
||||
|
||||
if (tag.indexOf("!~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "!~");
|
||||
if (split[1] === "*") {
|
||||
throw `Don't use 'key!~*' - use 'key=' instead (empty string as value (in the tag ${tag} while parsing ${context})`
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$"),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("~~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "~~");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
new RegExp("^" + split[0] + "$"),
|
||||
new RegExp("^" + split[1] + "$")
|
||||
);
|
||||
}
|
||||
if (tag.indexOf(":=") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, ":=");
|
||||
return new SubstitutingTag(split[0], split[1]);
|
||||
}
|
||||
|
||||
if (tag.indexOf("!=") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "!=");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$"),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("!~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "!~");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$"),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "~");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$")
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("=") >= 0) {
|
||||
|
||||
|
||||
const split = Utils.SplitFirst(tag, "=");
|
||||
if (split[1] == "*") {
|
||||
throw `Error while parsing tag '${tag}' in ${context}: detected a wildcard on a normal value. Use a regex pattern instead`
|
||||
}
|
||||
return new Tag(split[0], split[1])
|
||||
}
|
||||
throw `Error while parsing tag '${tag}' in ${context}: no key part and value part were found`
|
||||
|
||||
}
|
||||
if (json.and !== undefined) {
|
||||
return new And(json.and.map(t => FromJSON.Tag(t, context)));
|
||||
}
|
||||
if (json.or !== undefined) {
|
||||
return new Or(json.or.map(t => FromJSON.Tag(t, context)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import TagRenderingConfig from "./JSON/TagRenderingConfig";
|
||||
import * as questions from "../assets/tagRenderings/questions.json";
|
||||
import * as icons from "../assets/tagRenderings/icons.json";
|
||||
import {Utils} from "../Utils";
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
|
||||
|
||||
export default class SharedTagRenderings {
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import {Utils} from "./Utils";
|
|||
import Svg from "./Svg";
|
||||
import Link from "./UI/Base/Link";
|
||||
import * as personal from "./assets/themes/personal/personal.json";
|
||||
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
|
||||
import * as L from "leaflet";
|
||||
import Img from "./UI/Base/Img";
|
||||
import UserDetails from "./Logic/Osm/OsmConnection";
|
||||
|
@ -30,14 +29,15 @@ import Translations from "./UI/i18n/Translations";
|
|||
import MapControlButton from "./UI/MapControlButton";
|
||||
import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler";
|
||||
import LZString from "lz-string";
|
||||
import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson";
|
||||
import FeatureSource from "./Logic/FeatureSource/FeatureSource";
|
||||
import AllKnownLayers from "./Customizations/AllKnownLayers";
|
||||
import LayerConfig from "./Customizations/JSON/LayerConfig";
|
||||
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
|
||||
import {TagsFilter} from "./Logic/Tags/TagsFilter";
|
||||
import LeftControls from "./UI/BigComponents/LeftControls";
|
||||
import RightControls from "./UI/BigComponents/RightControls";
|
||||
import {LayoutConfigJson} from "./Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
||||
import LayerConfig from "./Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export class InitUiElements {
|
||||
static InitAll(
|
||||
|
|
|
@ -3,9 +3,9 @@ import {UIEventSource} from "../UIEventSource";
|
|||
import Svg from "../../Svg";
|
||||
import Img from "../../UI/Base/Img";
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import {VariableUiElement} from "../../UI/Base/VariableUIElement";
|
||||
import BaseUIElement from "../../UI/BaseUIElement";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class GeoLocationHandler extends VariableUiElement {
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {UIEventSource} from "../UIEventSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import {OsmConnection} from "../Osm/OsmConnection";
|
||||
import {Utils} from "../../Utils";
|
||||
import LZString from "lz-string";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class InstalledThemes {
|
||||
public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import {UIEventSource} from "../UIEventSource";
|
||||
import Loc from "../../Models/Loc";
|
||||
import {Or} from "../Tags/Or";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import {Overpass} from "../Osm/Overpass";
|
||||
import Bounds from "../../Models/Bounds";
|
||||
import FeatureSource from "../FeatureSource/FeatureSource";
|
||||
import {Utils} from "../../Utils";
|
||||
import {TagsFilter} from "../Tags/TagsFilter";
|
||||
import SimpleMetaTagger from "../SimpleMetaTagger";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
|
||||
export default class OverpassFeatureSource implements FeatureSource {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {UIEventSource} from "../UIEventSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import Locale from "../../UI/i18n/Locale";
|
||||
import TagRenderingAnswer from "../../UI/Popup/TagRenderingAnswer";
|
||||
import {ElementStorage} from "../ElementStorage";
|
||||
import Combine from "../../UI/Base/Combine";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
class TitleElement extends UIEventSource<string> {
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import FeatureSource from "../FeatureSource/FeatureSource";
|
|||
import {UIEventSource} from "../UIEventSource";
|
||||
import LocalStorageSaver from "./LocalStorageSaver";
|
||||
import LocalStorageSource from "./LocalStorageSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import Loc from "../../Models/Loc";
|
||||
import GeoJsonSource from "./GeoJsonSource";
|
||||
import MetaTaggingFeatureSource from "./MetaTaggingFeatureSource";
|
||||
|
@ -15,6 +14,7 @@ import RegisteringFeatureSource from "./RegisteringFeatureSource";
|
|||
import FilteredLayer from "../../Models/FilteredLayer";
|
||||
import {Changes} from "../Osm/Changes";
|
||||
import ChangeApplicator from "./ChangeApplicator";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class FeaturePipeline implements FeatureSource {
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import FeatureSource from "./FeatureSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import Loc from "../../Models/Loc";
|
||||
import Hash from "../Web/Hash";
|
||||
import {TagsFilter} from "../Tags/TagsFilter";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export default class FilteringFeatureSource implements FeatureSource {
|
||||
public features: UIEventSource<{ feature: any; freshness: Date }[]> =
|
||||
|
|
|
@ -3,7 +3,7 @@ import {UIEventSource} from "../UIEventSource";
|
|||
import Loc from "../../Models/Loc";
|
||||
import State from "../../State";
|
||||
import {Utils} from "../../Utils";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
import FeatureSource from "./FeatureSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class LocalStorageSaver implements FeatureSource {
|
||||
public static readonly storageKey: string = "cached-features";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import FeatureSource from "./FeatureSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import LocalStorageSaver from "./LocalStorageSaver";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class LocalStorageSource implements FeatureSource {
|
||||
public features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import FeatureSource from "./FeatureSource";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import {GeoOperations} from "../GeoOperations";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
/**
|
||||
* This is the part of the pipeline which introduces extra points at the center of an area (but only if this is demanded by the wayhandling)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import SimpleMetaTagger from "./SimpleMetaTagger";
|
||||
import {ExtraFunction} from "./ExtraFunction";
|
||||
import {Relation} from "./Osm/ExtractRelations";
|
||||
import {UIEventSource} from "./UIEventSource";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
|
||||
interface Params {
|
||||
|
|
|
@ -5,9 +5,9 @@ import {UIEventSource} from "../UIEventSource";
|
|||
import {ElementStorage} from "../ElementStorage";
|
||||
import State from "../../State";
|
||||
import Locale from "../../UI/i18n/Locale";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import Constants from "../../Models/Constants";
|
||||
import {OsmObject} from "./OsmObject";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export class ChangesetHandler {
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ import {OsmPreferences} from "./OsmPreferences";
|
|||
import {ChangesetHandler} from "./ChangesetHandler";
|
||||
import {ElementStorage} from "../ElementStorage";
|
||||
import Svg from "../../Svg";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import Img from "../../UI/Base/Img";
|
||||
import {Utils} from "../../Utils";
|
||||
import {OsmObject} from "./OsmObject";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class UserDetails {
|
||||
|
||||
|
|
|
@ -2,6 +2,11 @@ import {Tag} from "./Tag";
|
|||
import {TagsFilter} from "./TagsFilter";
|
||||
import {And} from "./And";
|
||||
import {Utils} from "../../Utils";
|
||||
import ComparingTag from "./ComparingTag";
|
||||
import {RegexTag} from "./RegexTag";
|
||||
import SubstitutingTag from "./SubstitutingTag";
|
||||
import {Or} from "./Or";
|
||||
import {AndOrTagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson";
|
||||
|
||||
export class TagUtils {
|
||||
static ApplyTemplate(template: string, tags: any): string {
|
||||
|
@ -118,4 +123,136 @@ export class TagUtils {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static SimpleTag(json: string, context?: string): Tag {
|
||||
const tag = Utils.SplitFirst(json, "=");
|
||||
if (tag.length !== 2) {
|
||||
throw `Invalid tag: no (or too much) '=' found (in ${context ?? "unkown context"})`
|
||||
}
|
||||
return new Tag(tag[0], tag[1]);
|
||||
}
|
||||
|
||||
public static Tag(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
|
||||
try {
|
||||
return this.TagUnsafe(json, context);
|
||||
} catch (e) {
|
||||
console.error("Could not parse tag", json, "in context", context, "due to ", e)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static comparators
|
||||
: [string, (a: number, b: number) => boolean][]
|
||||
= [
|
||||
["<=", (a, b) => a <= b],
|
||||
[">=", (a, b) => a >= b],
|
||||
["<", (a, b) => a < b],
|
||||
[">", (a, b) => a > b],
|
||||
]
|
||||
|
||||
private static TagUnsafe(json: AndOrTagConfigJson | string, context: string = ""): TagsFilter {
|
||||
|
||||
if (json === undefined) {
|
||||
throw `Error while parsing a tag: 'json' is undefined in ${context}. Make sure all the tags are defined and at least one tag is present in a complex expression`
|
||||
}
|
||||
if (typeof (json) == "string") {
|
||||
const tag = json as string;
|
||||
|
||||
for (const [operator, comparator] of TagUtils.comparators) {
|
||||
if (tag.indexOf(operator) >= 0) {
|
||||
const split = Utils.SplitFirst(tag, operator);
|
||||
|
||||
const val = Number(split[1].trim())
|
||||
if (isNaN(val)) {
|
||||
throw `Error: not a valid value for a comparison: ${split[1]}, make sure it is a number and nothing more (at ${context})`
|
||||
}
|
||||
|
||||
const f = (value: string | undefined) => {
|
||||
const b = Number(value?.replace(/[^\d.]/g, ''))
|
||||
if (isNaN(b)) {
|
||||
return false;
|
||||
}
|
||||
return comparator(b, val)
|
||||
}
|
||||
return new ComparingTag(split[0], f, operator + val)
|
||||
}
|
||||
}
|
||||
|
||||
if (tag.indexOf("!~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "!~");
|
||||
if (split[1] === "*") {
|
||||
throw `Don't use 'key!~*' - use 'key=' instead (empty string as value (in the tag ${tag} while parsing ${context})`
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$"),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("~~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "~~");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
new RegExp("^" + split[0] + "$"),
|
||||
new RegExp("^" + split[1] + "$")
|
||||
);
|
||||
}
|
||||
if (tag.indexOf(":=") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, ":=");
|
||||
return new SubstitutingTag(split[0], split[1]);
|
||||
}
|
||||
|
||||
if (tag.indexOf("!=") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "!=");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$"),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("!~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "!~");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$"),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("~") >= 0) {
|
||||
const split = Utils.SplitFirst(tag, "~");
|
||||
if (split[1] === "*") {
|
||||
split[1] = "..*"
|
||||
}
|
||||
return new RegexTag(
|
||||
split[0],
|
||||
new RegExp("^" + split[1] + "$")
|
||||
);
|
||||
}
|
||||
if (tag.indexOf("=") >= 0) {
|
||||
|
||||
|
||||
const split = Utils.SplitFirst(tag, "=");
|
||||
if (split[1] == "*") {
|
||||
throw `Error while parsing tag '${tag}' in ${context}: detected a wildcard on a normal value. Use a regex pattern instead`
|
||||
}
|
||||
return new Tag(split[0], split[1])
|
||||
}
|
||||
throw `Error while parsing tag '${tag}' in ${context}: no key part and value part were found`
|
||||
|
||||
}
|
||||
if (json.and !== undefined) {
|
||||
return new And(json.and.map(t => TagUtils.Tag(t, context)));
|
||||
}
|
||||
if (json.or !== undefined) {
|
||||
return new Or(json.or.map(t => TagUtils.Tag(t, context)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import { Utils } from "../Utils";
|
|||
|
||||
export default class Constants {
|
||||
|
||||
public static vNumber = "0.9.0-rc2";
|
||||
public static vNumber = "0.9.0-rc3";
|
||||
|
||||
// The user journey states thresholds when a new feature gets unlocked
|
||||
public static userJourney = {
|
||||
|
|
96
Models/Denomination.ts
Normal file
96
Models/Denomination.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
import {Translation} from "../UI/i18n/Translation";
|
||||
import UnitConfigJson from "./ThemeConfig/Json/UnitConfigJson";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
|
||||
export class Denomination {
|
||||
public readonly canonical: string;
|
||||
readonly default: boolean;
|
||||
readonly prefix: boolean;
|
||||
private readonly _human: Translation;
|
||||
public readonly alternativeDenominations: string [];
|
||||
|
||||
constructor(json: UnitConfigJson, context: string) {
|
||||
context = `${context}.unit(${json.canonicalDenomination})`
|
||||
this.canonical = json.canonicalDenomination.trim()
|
||||
if (this.canonical === undefined) {
|
||||
throw `${context}: this unit has no decent canonical value defined`
|
||||
}
|
||||
|
||||
json.alternativeDenomination.forEach((v, i) => {
|
||||
if (((v?.trim() ?? "") === "")) {
|
||||
throw `${context}.alternativeDenomination.${i}: invalid alternative denomination: undefined, null or only whitespace`
|
||||
}
|
||||
})
|
||||
|
||||
this.alternativeDenominations = json.alternativeDenomination?.map(v => v.trim()) ?? []
|
||||
|
||||
this.default = json.default ?? false;
|
||||
|
||||
this._human = Translations.T(json.human, context + "human")
|
||||
|
||||
this.prefix = json.prefix ?? false;
|
||||
|
||||
}
|
||||
|
||||
get human(): Translation {
|
||||
return this._human.Clone()
|
||||
}
|
||||
|
||||
public canonicalValue(value: string, actAsDefault?: boolean) {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const stripped = this.StrippedValue(value, actAsDefault)
|
||||
if (stripped === null) {
|
||||
return null;
|
||||
}
|
||||
return (stripped + " " + this.canonical.trim()).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the core value (without unit) if:
|
||||
* - the value ends with the canonical or an alternative value (or begins with if prefix is set)
|
||||
* - the value is a Number (without unit) and default is set
|
||||
*
|
||||
* Returns null if it doesn't match this unit
|
||||
*/
|
||||
public StrippedValue(value: string, actAsDefault?: boolean): string {
|
||||
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
value = value.toLowerCase()
|
||||
if (this.prefix) {
|
||||
if (value.startsWith(this.canonical) && this.canonical !== "") {
|
||||
return value.substring(this.canonical.length).trim();
|
||||
}
|
||||
for (const alternativeValue of this.alternativeDenominations) {
|
||||
if (value.startsWith(alternativeValue)) {
|
||||
return value.substring(alternativeValue.length).trim();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value.endsWith(this.canonical.toLowerCase()) && this.canonical !== "") {
|
||||
return value.substring(0, value.length - this.canonical.length).trim();
|
||||
}
|
||||
for (const alternativeValue of this.alternativeDenominations) {
|
||||
if (value.endsWith(alternativeValue.toLowerCase())) {
|
||||
return value.substring(0, value.length - alternativeValue.length).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.default || actAsDefault) {
|
||||
const parsed = Number(value.trim())
|
||||
if (!isNaN(parsed)) {
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import {TagsFilter} from "../Logic/Tags/TagsFilter";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import LayerConfig from "./ThemeConfig/LayerConfig";
|
||||
|
||||
export default interface FilteredLayer {
|
||||
readonly isDisplayed: UIEventSource<boolean>;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {DeleteConfigJson} from "./DeleteConfigJson";
|
||||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import {DeleteConfigJson} from "./Json/DeleteConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {FromJSON} from "./FromJSON";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
|
||||
export default class DeleteConfig {
|
||||
public readonly extraDeleteReasons?: {
|
||||
|
@ -30,14 +30,14 @@ export default class DeleteConfig {
|
|||
this.nonDeleteMappings = json.nonDeleteMappings?.map((nonDelete, i) => {
|
||||
const ctx = `${context}.extraDeleteReasons[${i}]`
|
||||
return {
|
||||
if: FromJSON.Tag(nonDelete.if, ctx + ".if"),
|
||||
if: TagUtils.Tag(nonDelete.if, ctx + ".if"),
|
||||
then: Translations.T(nonDelete.then, ctx + ".then")
|
||||
}
|
||||
})
|
||||
|
||||
this.softDeletionTags = undefined;
|
||||
if (json.softDeletionTags !== undefined) {
|
||||
this.softDeletionTags = FromJSON.Tag(json.softDeletionTags,`${context}.softDeletionTags`)
|
||||
this.softDeletionTags = TagUtils.Tag(json.softDeletionTags, `${context}.softDeletionTags`)
|
||||
|
||||
}
|
||||
|
27
Models/ThemeConfig/FilterConfig.ts
Normal file
27
Models/ThemeConfig/FilterConfig.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import FilterConfigJson from "./Json/FilterConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
|
||||
export default class FilterConfig {
|
||||
readonly options: {
|
||||
question: Translation;
|
||||
osmTags: TagsFilter;
|
||||
}[];
|
||||
|
||||
constructor(json: FilterConfigJson, context: string) {
|
||||
this.options = json.options.map((option, i) => {
|
||||
const question = Translations.T(
|
||||
option.question,
|
||||
context + ".options-[" + i + "].question"
|
||||
);
|
||||
const osmTags = TagUtils.Tag(
|
||||
option.osmTags ?? {and: []},
|
||||
`${context}.options-[${i}].osmTags`
|
||||
);
|
||||
|
||||
return {question: question, osmTags: osmTags};
|
||||
});
|
||||
}
|
||||
}
|
11
Models/ThemeConfig/Json/FilterConfigJson.ts
Normal file
11
Models/ThemeConfig/Json/FilterConfigJson.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import {AndOrTagConfigJson} from "./TagConfigJson";
|
||||
|
||||
export default interface FilterConfigJson {
|
||||
/**
|
||||
* The options for a filter
|
||||
* If there are multiple options these will be a list of radio buttons
|
||||
* If there is only one option this will be a checkbox
|
||||
* Filtering is done based on the given osmTags that are compared to the objects in that layer.
|
||||
*/
|
||||
options: { question: string | any; osmTags?: AndOrTagConfigJson | string }[];
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||
import {AndOrTagConfigJson} from "./TagConfigJson";
|
||||
import {DeleteConfigJson} from "./DeleteConfigJson";
|
||||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||
import FilterConfigJson from "./FilterConfigJson";
|
||||
import {DeleteConfigJson} from "./DeleteConfigJson";
|
||||
|
||||
/**
|
||||
* Configuration for a single layer
|
|
@ -1,6 +1,6 @@
|
|||
import {LayerConfigJson} from "./LayerConfigJson";
|
||||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||
import UnitConfigJson from "./UnitConfigJson";
|
||||
import {LayerConfigJson} from "./LayerConfigJson";
|
||||
|
||||
/**
|
||||
* Defines the entire theme.
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
export interface AndOrTagConfigJson {
|
||||
and?: (string | AndOrTagConfigJson)[]
|
||||
or?: (string | AndOrTagConfigJson)[]
|
|
@ -1,24 +1,23 @@
|
|||
import Translations from "../../UI/i18n/Translations";
|
||||
import TagRenderingConfig from "./TagRenderingConfig";
|
||||
import {LayerConfigJson} from "./LayerConfigJson";
|
||||
import {FromJSON} from "./FromJSON";
|
||||
import SharedTagRenderings from "../SharedTagRenderings";
|
||||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import Svg from "../../Svg";
|
||||
|
||||
import SourceConfig from "./SourceConfig";
|
||||
import TagRenderingConfig from "./TagRenderingConfig";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import PresetConfig from "./PresetConfig";
|
||||
import {LayerConfigJson} from "./Json/LayerConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
import SharedTagRenderings from "../../Customizations/SharedTagRenderings";
|
||||
import {TagRenderingConfigJson} from "./Json/TagRenderingConfigJson";
|
||||
import {Utils} from "../../Utils";
|
||||
import Svg from "../../Svg";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import BaseUIElement from "../../UI/BaseUIElement";
|
||||
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
|
||||
import Combine from "../../UI/Base/Combine";
|
||||
import {VariableUiElement} from "../../UI/Base/VariableUIElement";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
|
||||
import SourceConfig from "./SourceConfig";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import BaseUIElement from "../../UI/BaseUIElement";
|
||||
import {Unit} from "./Denomination";
|
||||
import DeleteConfig from "./DeleteConfig";
|
||||
import FilterConfig from "./FilterConfig";
|
||||
import PresetConfig from "./PresetConfig";
|
||||
import {Unit} from "../Unit";
|
||||
import DeleteConfig from "./DeleteConfig";
|
||||
|
||||
export default class LayerConfig {
|
||||
static WAYHANDLING_DEFAULT = 0;
|
||||
|
@ -83,7 +82,7 @@ export default class LayerConfig {
|
|||
let legacy = undefined;
|
||||
if (json["overpassTags"] !== undefined) {
|
||||
// @ts-ignore
|
||||
legacy = FromJSON.Tag(json["overpassTags"], context + ".overpasstags");
|
||||
legacy = TagUtils.Tag(json["overpassTags"], context + ".overpasstags");
|
||||
}
|
||||
if (json.source !== undefined) {
|
||||
if (legacy !== undefined) {
|
||||
|
@ -95,7 +94,7 @@ export default class LayerConfig {
|
|||
|
||||
let osmTags: TagsFilter = legacy;
|
||||
if (json.source["osmTags"]) {
|
||||
osmTags = FromJSON.Tag(
|
||||
osmTags = TagUtils.Tag(
|
||||
json.source["osmTags"],
|
||||
context + "source.osmTags"
|
||||
);
|
||||
|
@ -174,7 +173,7 @@ export default class LayerConfig {
|
|||
|
||||
const config: PresetConfig = {
|
||||
title: Translations.T(pr.title, `${context}.presets[${i}].title`),
|
||||
tags: pr.tags.map((t) => FromJSON.SimpleTag(t)),
|
||||
tags: pr.tags.map((t) => TagUtils.SimpleTag(t)),
|
||||
description: Translations.T(pr.description, `${context}.presets[${i}].description`),
|
||||
preciseInput: preciseInput,
|
||||
}
|
||||
|
@ -301,7 +300,7 @@ export default class LayerConfig {
|
|||
tr = SharedTagRenderings.SharedIcons.get(overlay.then);
|
||||
}
|
||||
return {
|
||||
if: FromJSON.Tag(overlay.if),
|
||||
if: TagUtils.Tag(overlay.if),
|
||||
then: tr,
|
||||
badge: overlay.badge ?? false,
|
||||
};
|
|
@ -1,11 +1,12 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import TagRenderingConfig from "./TagRenderingConfig";
|
||||
import LayerConfig from "./LayerConfig";
|
||||
import {LayoutConfigJson} from "./LayoutConfigJson";
|
||||
import AllKnownLayers from "../AllKnownLayers";
|
||||
import SharedTagRenderings from "../SharedTagRenderings";
|
||||
import {LayoutConfigJson} from "./Json/LayoutConfigJson";
|
||||
import SharedTagRenderings from "../../Customizations/SharedTagRenderings";
|
||||
import AllKnownLayers from "../../Customizations/AllKnownLayers";
|
||||
import {Utils} from "../../Utils";
|
||||
import {Denomination, Unit} from "./Denomination";
|
||||
import LayerConfig from "./LayerConfig";
|
||||
import {Unit} from "../Unit";
|
||||
import {Denomination} from "../Denomination";
|
||||
|
||||
export default class LayoutConfig {
|
||||
public readonly id: string;
|
|
@ -1,15 +1,13 @@
|
|||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {FromJSON} from "./FromJSON";
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
|
||||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import {Utils} from "../../Utils";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import {TagRenderingConfigJson} from "./Json/TagRenderingConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
|
||||
import {Utils} from "../../Utils";
|
||||
import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation";
|
||||
|
||||
|
||||
/***
|
||||
* The parsed version of TagRenderingConfigJSON
|
||||
* Identical data, but with some methods and validation
|
||||
|
@ -62,7 +60,7 @@ export default class TagRenderingConfig {
|
|||
this.render = Translations.T(json.render, context + ".render");
|
||||
this.question = Translations.T(json.question, context + ".question");
|
||||
this.roaming = json.roaming ?? false;
|
||||
const condition = FromJSON.Tag(json.condition ?? {"and": []}, `${context}.condition`);
|
||||
const condition = TagUtils.Tag(json.condition ?? {"and": []}, `${context}.condition`);
|
||||
if (this.roaming && conditionIfRoaming !== undefined) {
|
||||
this.condition = new And([condition, conditionIfRoaming]);
|
||||
} else {
|
||||
|
@ -75,7 +73,7 @@ export default class TagRenderingConfig {
|
|||
key: json.freeform.key,
|
||||
type: json.freeform.type ?? "string",
|
||||
addExtraTags: json.freeform.addExtraTags?.map((tg, i) =>
|
||||
FromJSON.Tag(tg, `${context}.extratag[${i}]`)) ?? [],
|
||||
TagUtils.Tag(tg, `${context}.extratag[${i}]`)) ?? [],
|
||||
inline: json.freeform.inline ?? false,
|
||||
default: json.freeform.default,
|
||||
helperArgs: json.freeform.helperArgs
|
||||
|
@ -134,12 +132,12 @@ export default class TagRenderingConfig {
|
|||
if (typeof mapping.hideInAnswer === "boolean") {
|
||||
hideInAnswer = mapping.hideInAnswer;
|
||||
} else if (mapping.hideInAnswer !== undefined) {
|
||||
hideInAnswer = FromJSON.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`);
|
||||
hideInAnswer = TagUtils.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`);
|
||||
}
|
||||
const mappingContext = `${context}.mapping[${i}]`
|
||||
const mp = {
|
||||
if: FromJSON.Tag(mapping.if, `${mappingContext}.if`),
|
||||
ifnot: (mapping.ifnot !== undefined ? FromJSON.Tag(mapping.ifnot, `${mappingContext}.ifnot`) : undefined),
|
||||
if: TagUtils.Tag(mapping.if, `${mappingContext}.if`),
|
||||
ifnot: (mapping.ifnot !== undefined ? TagUtils.Tag(mapping.ifnot, `${mappingContext}.ifnot`) : undefined),
|
||||
then: Translations.T(mapping.then, `{mappingContext}.then`),
|
||||
hideInAnswer: hideInAnswer
|
||||
};
|
||||
|
@ -336,25 +334,5 @@ export default class TagRenderingConfig {
|
|||
return usedIcons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this tag rendering has a minimap in some language.
|
||||
* Note: this might be hidden by conditions
|
||||
*/
|
||||
public hasMinimap(): boolean {
|
||||
const translations: Translation[] = Utils.NoNull([this.render, ...(this.mappings ?? []).map(m => m.then)]);
|
||||
for (const translation of translations) {
|
||||
for (const key in translation.translations) {
|
||||
if (!translation.translations.hasOwnProperty(key)) {
|
||||
continue
|
||||
}
|
||||
const template = translation.translations[key]
|
||||
const parts = SubstitutedTranslation.ExtractSpecialComponents(template)
|
||||
const hasMiniMap = parts.filter(part => part.special !== undefined).some(special => special.special.func.funcName === "minimap")
|
||||
if (hasMiniMap) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
114
Models/Unit.ts
Normal file
114
Models/Unit.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
import BaseUIElement from "../UI/BaseUIElement";
|
||||
import {FixedUiElement} from "../UI/Base/FixedUiElement";
|
||||
import Combine from "../UI/Base/Combine";
|
||||
import {Denomination} from "./Denomination";
|
||||
|
||||
export class Unit {
|
||||
public readonly appliesToKeys: Set<string>;
|
||||
public readonly denominations: Denomination[];
|
||||
public readonly denominationsSorted: Denomination[];
|
||||
public readonly defaultDenom: Denomination;
|
||||
public readonly eraseInvalid: boolean;
|
||||
private readonly possiblePostFixes: string[] = []
|
||||
|
||||
constructor(appliesToKeys: string[], applicableUnits: Denomination[], eraseInvalid: boolean) {
|
||||
this.appliesToKeys = new Set(appliesToKeys);
|
||||
this.denominations = applicableUnits;
|
||||
this.defaultDenom = applicableUnits.filter(denom => denom.default)[0]
|
||||
this.eraseInvalid = eraseInvalid
|
||||
|
||||
const seenUnitExtensions = new Set<string>();
|
||||
for (const denomination of this.denominations) {
|
||||
if (seenUnitExtensions.has(denomination.canonical)) {
|
||||
throw "This canonical unit is already defined in another denomination: " + denomination.canonical
|
||||
}
|
||||
const duplicate = denomination.alternativeDenominations.filter(denom => seenUnitExtensions.has(denom))
|
||||
if (duplicate.length > 0) {
|
||||
throw "A denomination is used multiple times: " + duplicate.join(", ")
|
||||
}
|
||||
|
||||
seenUnitExtensions.add(denomination.canonical)
|
||||
denomination.alternativeDenominations.forEach(d => seenUnitExtensions.add(d))
|
||||
}
|
||||
this.denominationsSorted = [...this.denominations]
|
||||
this.denominationsSorted.sort((a, b) => b.canonical.length - a.canonical.length)
|
||||
|
||||
|
||||
const possiblePostFixes = new Set<string>()
|
||||
|
||||
function addPostfixesOf(str) {
|
||||
str = str.toLowerCase()
|
||||
for (let i = 0; i < str.length + 1; i++) {
|
||||
const substr = str.substring(0, i)
|
||||
possiblePostFixes.add(substr)
|
||||
}
|
||||
}
|
||||
|
||||
for (const denomination of this.denominations) {
|
||||
addPostfixesOf(denomination.canonical)
|
||||
denomination.alternativeDenominations.forEach(addPostfixesOf)
|
||||
}
|
||||
this.possiblePostFixes = Array.from(possiblePostFixes)
|
||||
this.possiblePostFixes.sort((a, b) => b.length - a.length)
|
||||
}
|
||||
|
||||
isApplicableToKey(key: string | undefined): boolean {
|
||||
if (key === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.appliesToKeys.has(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds which denomination is applicable and gives the stripped value back
|
||||
*/
|
||||
findDenomination(valueWithDenom: string): [string, Denomination] {
|
||||
if (valueWithDenom === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
for (const denomination of this.denominationsSorted) {
|
||||
const bare = denomination.StrippedValue(valueWithDenom)
|
||||
if (bare !== null) {
|
||||
return [bare, denomination]
|
||||
}
|
||||
}
|
||||
return [undefined, undefined]
|
||||
}
|
||||
|
||||
asHumanLongValue(value: string): BaseUIElement {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const [stripped, denom] = this.findDenomination(value)
|
||||
const human = denom?.human
|
||||
if (human === undefined) {
|
||||
return new FixedUiElement(stripped ?? value);
|
||||
}
|
||||
|
||||
const elems = denom.prefix ? [human, stripped] : [stripped, human];
|
||||
return new Combine(elems)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value without any (sub)parts of any denomination - usefull as preprocessing step for validating inputs.
|
||||
* E.g.
|
||||
* if 'megawatt' is a possible denomination, then '5 Meg' will be rewritten to '5' (which can then be validated as a valid pnat)
|
||||
*
|
||||
* Returns the original string if nothign matches
|
||||
*/
|
||||
stripUnitParts(str: string) {
|
||||
if (str === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const denominationPart of this.possiblePostFixes) {
|
||||
if (str.endsWith(denominationPart)) {
|
||||
return str.substring(0, str.length - denominationPart.length).trim()
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
2
State.ts
2
State.ts
|
@ -6,7 +6,6 @@ import Locale from "./UI/i18n/Locale";
|
|||
import {UIEventSource} from "./Logic/UIEventSource";
|
||||
import {LocalStorageSource} from "./Logic/Web/LocalStorageSource";
|
||||
import {QueryParameters} from "./Logic/Web/QueryParameters";
|
||||
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
|
||||
import {MangroveIdentity} from "./Logic/Web/MangroveReviews";
|
||||
import InstalledThemes from "./Logic/Actors/InstalledThemes";
|
||||
import BaseLayer from "./Models/BaseLayer";
|
||||
|
@ -21,6 +20,7 @@ import OsmApiFeatureSource from "./Logic/FeatureSource/OsmApiFeatureSource";
|
|||
import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline";
|
||||
import FilteredLayer from "./Models/FilteredLayer";
|
||||
import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor";
|
||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
/**
|
||||
* Contains the global state: a bunch of UI-event sources
|
||||
|
|
|
@ -4,10 +4,10 @@ import Combine from "../Base/Combine";
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import UserDetails from "../../Logic/Osm/OsmConnection";
|
||||
import Constants from "../../Models/Constants";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import Loc from "../../Models/Loc";
|
||||
import * as L from "leaflet"
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
/**
|
||||
* The bottom right attribution panel in the leaflet map
|
||||
|
|
|
@ -3,7 +3,6 @@ import Translations from "../i18n/Translations";
|
|||
import Attribution from "./Attribution";
|
||||
import State from "../../State";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import * as licenses from "../../assets/generated/license_info.json"
|
||||
import SmallLicense from "../../Models/smallLicense";
|
||||
|
@ -12,6 +11,7 @@ import Link from "../Base/Link";
|
|||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import * as contributors from "../../assets/contributors.json"
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
/**
|
||||
* The attribution panel shown on mobile
|
||||
|
|
|
@ -5,10 +5,8 @@ import {VariableUiElement} from "../Base/VariableUIElement";
|
|||
import Toggle from "../Input/Toggle";
|
||||
import Combine from "../Base/Combine";
|
||||
import Translations from "../i18n/Translations";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
import Svg from "../../Svg";
|
||||
import FilterConfig from "../../Customizations/JSON/FilterConfig";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
|
@ -16,6 +14,8 @@ import BaseUIElement from "../BaseUIElement";
|
|||
import State from "../../State";
|
||||
import FilteredLayer from "../../Models/FilteredLayer";
|
||||
import BackgroundSelector from "./BackgroundSelector";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
import FilterConfig from "../../Models/ThemeConfig/FilterConfig";
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,11 +10,11 @@ import Constants from "../../Models/Constants";
|
|||
import Combine from "../Base/Combine";
|
||||
import {TabbedComponent} from "../Base/TabbedComponent";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import UserDetails from "../../Logic/Osm/OsmConnection";
|
||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import Toggle from "../Input/Toggle";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import {AllKnownLayouts} from "../../Customizations/AllKnownLayouts";
|
||||
import Svg from "../../Svg";
|
||||
import State from "../../State";
|
||||
|
@ -11,6 +10,7 @@ import Constants from "../../Models/Constants";
|
|||
import LanguagePicker from "../LanguagePicker";
|
||||
import IndexText from "./IndexText";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class MoreScreen extends Combine {
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import {SubtleButton} from "../Base/SubtleButton";
|
|||
import Translations from "../i18n/Translations";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import Img from "../Base/Img";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export default class PersonalLayersPanel extends VariableUiElement {
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import Svg from "../../Svg";
|
||||
import Combine from "../Base/Combine";
|
||||
import {SubtleButton} from "../Base/SubtleButton";
|
||||
|
@ -11,8 +10,9 @@ import Toggle from "../Input/Toggle";
|
|||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Constants from "../../Models/Constants";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export default class ShareScreen extends Combine {
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import State from "../../State";
|
|||
import Combine from "../Base/Combine";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Constants from "../../Models/Constants";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
|
@ -17,8 +16,9 @@ import UserDetails from "../../Logic/Osm/OsmConnection";
|
|||
import LocationInput from "../Input/LocationInput";
|
||||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
|
||||
import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction";
|
||||
import PresetConfig from "../../Customizations/JSON/PresetConfig";
|
||||
import {OsmObject, OsmWay} from "../../Logic/Osm/OsmObject";
|
||||
import PresetConfig from "../../Models/ThemeConfig/PresetConfig";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
/*
|
||||
* The SimpleAddUI is a single panel, which can have multiple states:
|
||||
|
|
|
@ -17,11 +17,11 @@ import Loc from "../Models/Loc";
|
|||
import {BBox} from "../Logic/GeoOperations";
|
||||
import ShowDataLayer from "./ShowDataLayer";
|
||||
import BaseLayer from "../Models/BaseLayer";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import {FixedUiElement} from "./Base/FixedUiElement";
|
||||
import Translations from "./i18n/Translations";
|
||||
import State from "../State";
|
||||
import Constants from "../Models/Constants";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class ExportPDF {
|
||||
// dimensions of the map in milimeter
|
||||
|
|
|
@ -10,8 +10,8 @@ import Toggle from "../Input/Toggle";
|
|||
import FileSelectorButton from "../Input/FileSelectorButton";
|
||||
import ImgurUploader from "../../Logic/ImageProviders/ImgurUploader";
|
||||
import UploadFlowStateUI from "../BigComponents/UploadFlowStateUI";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export class ImageUploadFlow extends Toggle {
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ import Svg from "../../Svg";
|
|||
import State from "../../State";
|
||||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
|
||||
import {GeoOperations} from "../../Logic/GeoOperations";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import ShowDataLayer from "../ShowDataLayer";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class LocationInput extends InputElement<Loc> {
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ import DirectionInput from "./DirectionInput";
|
|||
import ColorPicker from "./ColorPicker";
|
||||
import {Utils} from "../../Utils";
|
||||
import Loc from "../../Models/Loc";
|
||||
import {Unit} from "../../Customizations/JSON/Denomination";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import LengthInput from "./LengthInput";
|
||||
import {GeoOperations} from "../../Logic/GeoOperations";
|
||||
import {Unit} from "../../Models/Unit";
|
||||
|
||||
interface TextFieldDef {
|
||||
name: string,
|
||||
|
|
|
@ -8,18 +8,18 @@ import {Tag} from "../../Logic/Tags/Tag";
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion";
|
||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import Combine from "../Base/Combine";
|
||||
import {SubtleButton} from "../Base/SubtleButton";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
import {AndOrTagConfigJson} from "../../Customizations/JSON/TagConfigJson";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {Changes} from "../../Logic/Osm/Changes";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import Constants from "../../Models/Constants";
|
||||
import DeleteConfig from "../../Customizations/JSON/DeleteConfig";
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
import {AndOrTagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson";
|
||||
import DeleteConfig from "../../Models/ThemeConfig/DeleteConfig";
|
||||
|
||||
export default class DeleteWizard extends Toggle {
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Combine from "../Base/Combine";
|
||||
|
@ -8,7 +7,8 @@ import State from "../../State";
|
|||
import Svg from "../../Svg";
|
||||
import Toggle from "../Input/Toggle";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {Unit} from "../../Customizations/JSON/Denomination";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
import {Unit} from "../../Models/Unit";
|
||||
|
||||
export default class EditableTagRendering extends Toggle {
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import EditableTagRendering from "./EditableTagRendering";
|
||||
import QuestionBox from "./QuestionBox";
|
||||
import Combine from "../Base/Combine";
|
||||
import TagRenderingAnswer from "./TagRenderingAnswer";
|
||||
import State from "../../State";
|
||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
import Constants from "../../Models/Constants";
|
||||
|
@ -14,6 +12,11 @@ import BaseUIElement from "../BaseUIElement";
|
|||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import DeleteWizard from "./DeleteWizard";
|
||||
import SplitRoadWizard from "./SplitRoadWizard";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
import {Utils} from "../../Utils";
|
||||
import {SubstitutedTranslation} from "../SubstitutedTranslation";
|
||||
|
||||
export default class FeatureInfoBox extends ScrollableFullScreen {
|
||||
|
||||
|
@ -88,7 +91,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
|
|||
}
|
||||
|
||||
|
||||
const hasMinimap = layerConfig.tagRenderings.some(tr => tr.hasMinimap())
|
||||
const hasMinimap = layerConfig.tagRenderings.some(tr => FeatureInfoBox.hasMinimap(tr))
|
||||
if (!hasMinimap) {
|
||||
renderings.push(new TagRenderingAnswer(tags, SharedTagRenderings.SharedTagRendering.get("minimap")))
|
||||
}
|
||||
|
@ -136,4 +139,26 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this tag rendering has a minimap in some language.
|
||||
* Note: this might be hidden by conditions
|
||||
*/
|
||||
private static hasMinimap(renderingConfig: TagRenderingConfig): boolean {
|
||||
const translations: Translation[] = Utils.NoNull([renderingConfig.render, ...(renderingConfig.mappings ?? []).map(m => m.then)]);
|
||||
for (const translation of translations) {
|
||||
for (const key in translation.translations) {
|
||||
if (!translation.translations.hasOwnProperty(key)) {
|
||||
continue
|
||||
}
|
||||
const template = translation.translations[key]
|
||||
const parts = SubstitutedTranslation.ExtractSpecialComponents(template)
|
||||
const hasMiniMap = parts.filter(part => part.special !== undefined).some(special => special.special.func.funcName === "minimap")
|
||||
if (hasMiniMap) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion";
|
||||
import Translations from "../i18n/Translations";
|
||||
import State from "../../State";
|
||||
import Combine from "../Base/Combine";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {Unit} from "../../Customizations/JSON/Denomination";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
import {Unit} from "../../Models/Unit";
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,10 +10,10 @@ import {LeafletMouseEvent} from "leaflet";
|
|||
import Combine from "../Base/Combine";
|
||||
import {Button} from "../Base/Button";
|
||||
import Translations from "../i18n/Translations";
|
||||
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||
import SplitAction from "../../Logic/Osm/Actions/SplitAction";
|
||||
import {OsmObject, OsmWay} from "../../Logic/Osm/OsmObject";
|
||||
import Title from "../Base/Title";
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class SplitRoadWizard extends Toggle {
|
||||
private static splitLayout = new UIEventSource(SplitRoadWizard.GetSplitLayout())
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import {Utils} from "../../Utils";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import List from "../Base/List";
|
||||
import {SubstitutedTranslation} from "../SubstitutedTranslation";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
|
||||
/***
|
||||
* Displays the correct value for a known tagrendering
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import Combine from "../Base/Combine";
|
||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import {InputElement} from "../Input/InputElement";
|
||||
import ValidatedTextField from "../Input/ValidatedTextField";
|
||||
import {FixedInputElement} from "../Input/FixedInputElement";
|
||||
|
@ -23,9 +22,10 @@ import {And} from "../../Logic/Tags/And";
|
|||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {DropDown} from "../Input/DropDown";
|
||||
import {Unit} from "../../Customizations/JSON/Denomination";
|
||||
import InputElementWrapper from "../Input/InputElementWrapper";
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
import {Unit} from "../../Models/Unit";
|
||||
|
||||
/**
|
||||
* Shows the question element.
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import * as L from "leaflet"
|
||||
import "leaflet.markercluster"
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import State from "../State";
|
||||
import FeatureInfoBox from "./Popup/FeatureInfoBox";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
|
||||
export default class ShowDataLayer {
|
||||
|
|
|
@ -17,13 +17,13 @@ import OpeningHoursVisualization from "./OpeningHours/OpeningHoursVisualization"
|
|||
import State from "../State";
|
||||
import {ImageSearcher} from "../Logic/Actors/ImageSearcher";
|
||||
import BaseUIElement from "./BaseUIElement";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import Title from "./Base/Title";
|
||||
import Table from "./Base/Table";
|
||||
import Histogram from "./BigComponents/Histogram";
|
||||
import Loc from "../Models/Loc";
|
||||
import {Utils} from "../Utils";
|
||||
import BaseLayer from "../Models/BaseLayer";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export interface SpecialVisualization {
|
||||
funcName: string,
|
||||
|
|
2
index.ts
2
index.ts
|
@ -4,7 +4,6 @@ import {InitUiElements} from "./InitUiElements";
|
|||
import {QueryParameters} from "./Logic/Web/QueryParameters";
|
||||
import {UIEventSource} from "./Logic/UIEventSource";
|
||||
import * as $ from "jquery";
|
||||
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
|
||||
import MoreScreen from "./UI/BigComponents/MoreScreen";
|
||||
import State from "./State";
|
||||
import Combine from "./UI/Base/Combine";
|
||||
|
@ -21,6 +20,7 @@ import ShowDataLayer from "./UI/ShowDataLayer";
|
|||
import * as L from "leaflet";
|
||||
import ValidatedTextField from "./UI/Input/ValidatedTextField";
|
||||
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
|
||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
// Workaround for a stupid crash: inject some functions which would give stupid circular dependencies or crash the other nodejs scripts
|
||||
SimpleMetaTagger.coder = new CountryCoder("https://pietervdvn.github.io/latlon2country/");
|
||||
|
|
|
@ -7,9 +7,9 @@ import {UIEventSource} from "./Logic/UIEventSource";
|
|||
import {Utils} from "./Utils";
|
||||
import {SubtleButton} from "./UI/Base/SubtleButton";
|
||||
import LZString from "lz-string";
|
||||
import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson";
|
||||
import BaseUIElement from "./UI/BaseUIElement";
|
||||
import Table from "./UI/Base/Table";
|
||||
import {LayoutConfigJson} from "./Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
|
||||
|
||||
const connection = new OsmConnection(false, false, new UIEventSource<string>(undefined), "");
|
||||
|
|
|
@ -2,9 +2,9 @@ import {lstatSync, readdirSync, readFileSync} from "fs";
|
|||
import {Utils} from "../Utils";
|
||||
Utils.runningFromConsole = true
|
||||
import * as https from "https";
|
||||
import {LayerConfigJson} from "../Customizations/JSON/LayerConfigJson";
|
||||
import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson";
|
||||
import * as fs from "fs";
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
|
||||
|
||||
export default class ScriptUtils {
|
||||
|
|
|
@ -5,12 +5,12 @@ import {Utils} from "../Utils"
|
|||
Utils.runningFromConsole = true;
|
||||
|
||||
import {readFileSync, writeFileSync} from "fs";
|
||||
import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import SmallLicense from "../Models/smallLicense";
|
||||
import AllKnownLayers from "../Customizations/AllKnownLayers";
|
||||
import ScriptUtils from "./ScriptUtils";
|
||||
import AllImageProviders from "../Logic/ImageProviders/AllImageProviders";
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
|
||||
ScriptUtils.fixUtils()
|
||||
|
|
|
@ -8,17 +8,17 @@ import {Overpass} from "../Logic/Osm/Overpass";
|
|||
import {existsSync, readFileSync, writeFileSync} from "fs";
|
||||
import {TagsFilter} from "../Logic/Tags/TagsFilter";
|
||||
import {Or} from "../Logic/Tags/Or";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
|
||||
import ScriptUtils from "./ScriptUtils";
|
||||
import ExtractRelations from "../Logic/Osm/ExtractRelations";
|
||||
import * as OsmToGeoJson from "osmtogeojson";
|
||||
import MetaTagging from "../Logic/MetaTagging";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import {GeoOperations} from "../Logic/GeoOperations";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import * as fs from "fs";
|
||||
import {TileRange} from "../Models/TileRange";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
|
||||
function createOverpassObject(theme: LayoutConfig) {
|
||||
|
|
|
@ -8,9 +8,9 @@ import ValidatedTextField from "../UI/Input/ValidatedTextField";
|
|||
import BaseUIElement from "../UI/BaseUIElement";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import {writeFileSync} from "fs";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import State from "../State";
|
||||
import {QueryParameters} from "../Logic/Web/QueryParameters";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import ScriptUtils from "./ScriptUtils";
|
||||
import {writeFileSync} from "fs";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import * as licenses from "../assets/generated/license_info.json"
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import {LayerConfigJson} from "../Customizations/JSON/LayerConfigJson";
|
||||
import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson";
|
||||
import AllKnownLayers from "../Customizations/AllKnownLayers";
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
// This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
|
||||
// It spits out an overview of those to be used to load them
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
import {Utils} from "../Utils";
|
||||
Utils.runningFromConsole = true;
|
||||
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import {existsSync, mkdirSync, readFileSync, writeFile, writeFileSync} from "fs";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import Constants from "../Models/Constants";
|
||||
import * as all_known_layouts from "../assets/generated/known_layers_and_themes.json"
|
||||
import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson";
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
const sharp = require('sharp');
|
||||
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ import {Utils} from "../Utils";
|
|||
|
||||
Utils.runningFromConsole = true;
|
||||
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import {readFileSync, writeFileSync} from "fs";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
/**
|
||||
* Generates all the files in "Docs/TagInfo". These are picked up by the taginfo project, showing a link to the mapcomplete theme if the key is used
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {Utils} from "../Utils";
|
||||
Utils.runningFromConsole = true;
|
||||
import {writeFile} from "fs";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
|
||||
function generateWikiEntry(layout: LayoutConfig) {
|
||||
|
|
2
test.ts
2
test.ts
|
@ -1,11 +1,11 @@
|
|||
import {UIEventSource} from "./Logic/UIEventSource";
|
||||
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
|
||||
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
||||
import State from "./State";
|
||||
import LocationInput from "./UI/Input/LocationInput";
|
||||
import Loc from "./Models/Loc";
|
||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
||||
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
|
||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
const layout = new UIEventSource<LayoutConfig>(AllKnownLayouts.allKnownLayouts.get("cycle_infra"))
|
||||
State.state = new State(layout.data)
|
||||
|
|
|
@ -1,22 +1,9 @@
|
|||
import {Utils} from "../Utils";
|
||||
import * as Assert from "assert";
|
||||
import T from "./TestHelper";
|
||||
import {GeoOperations} from "../Logic/GeoOperations";
|
||||
|
||||
Utils.runningFromConsole = true;
|
||||
import {equal} from "assert";
|
||||
import T from "./TestHelper";
|
||||
import {FromJSON} from "../Customizations/JSON/FromJSON";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
||||
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
|
||||
import PublicHolidayInput from "../UI/OpeningHours/PublicHolidayInput";
|
||||
import {SubstitutedTranslation} from "../UI/SubstitutedTranslation";
|
||||
import {Tag} from "../Logic/Tags/Tag";
|
||||
import {And} from "../Logic/Tags/And";
|
||||
import * as Assert from "assert";
|
||||
import {GeoOperations} from "../Logic/GeoOperations";
|
||||
|
||||
export default class GeoOperationsSpec extends T {
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ import {equal} from "assert";
|
|||
import T from "./TestHelper";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import AllKnownLayers from "../Customizations/AllKnownLayers";
|
||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||
import * as bike_repair_station from "../assets/layers/bike_repair_station/bike_repair_station.json"
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
|
||||
export default class ImageAttributionSpec extends T {
|
||||
constructor() {
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
import {Utils} from "../Utils";
|
||||
|
||||
Utils.runningFromConsole = true;
|
||||
import {equal} from "assert";
|
||||
import T from "./TestHelper";
|
||||
import {FromJSON} from "../Customizations/JSON/FromJSON";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
||||
import EditableTagRendering from "../UI/Popup/EditableTagRendering";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
|
||||
import PublicHolidayInput from "../UI/OpeningHours/PublicHolidayInput";
|
||||
import {SubstitutedTranslation} from "../UI/SubstitutedTranslation";
|
||||
import {Tag} from "../Logic/Tags/Tag";
|
||||
import {And} from "../Logic/Tags/And";
|
||||
import {ImageSearcher} from "../Logic/Actors/ImageSearcher";
|
||||
|
||||
Utils.runningFromConsole = true;
|
||||
export default class ImageSearcherSpec extends T {
|
||||
|
||||
constructor() {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import {Utils} from "../Utils";
|
||||
import {equal} from "assert";
|
||||
import T from "./TestHelper";
|
||||
import {FromJSON} from "../Customizations/JSON/FromJSON";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
||||
import {Translation} from "../UI/i18n/Translation";
|
||||
import {OH, OpeningHour} from "../UI/OpeningHours/OpeningHours";
|
||||
import {Tag} from "../Logic/Tags/Tag";
|
||||
import {And} from "../Logic/Tags/And";
|
||||
import {TagUtils} from "../Logic/Tags/TagUtils";
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
|
||||
|
||||
|
||||
Utils.runningFromConsole = true;
|
||||
|
@ -25,7 +25,7 @@ export default class TagSpec extends T {
|
|||
|
||||
}],
|
||||
["Parse tag config", (() => {
|
||||
const tag = FromJSON.Tag("key=value") as Tag;
|
||||
const tag = TagUtils.Tag("key=value") as Tag;
|
||||
equal(tag.key, "key");
|
||||
equal(tag.value, "value");
|
||||
equal(tag.matchesProperties({"key": "value"}), true)
|
||||
|
@ -34,13 +34,13 @@ export default class TagSpec extends T {
|
|||
equal(tag.matchesProperties({"other_key": ""}), false)
|
||||
equal(tag.matchesProperties({"other_key": "value"}), false)
|
||||
|
||||
const isEmpty = FromJSON.Tag("key=") as Tag;
|
||||
const isEmpty = TagUtils.Tag("key=") as Tag;
|
||||
equal(isEmpty.matchesProperties({"key": "value"}), false)
|
||||
equal(isEmpty.matchesProperties({"key": ""}), true)
|
||||
equal(isEmpty.matchesProperties({"other_key": ""}), true)
|
||||
equal(isEmpty.matchesProperties({"other_key": "value"}), true)
|
||||
|
||||
const isNotEmpty = FromJSON.Tag("key!=");
|
||||
const isNotEmpty = TagUtils.Tag("key!=");
|
||||
equal(isNotEmpty.matchesProperties({"key": "value"}), true)
|
||||
equal(isNotEmpty.matchesProperties({"key": "other_value"}), true)
|
||||
equal(isNotEmpty.matchesProperties({"key": ""}), false)
|
||||
|
@ -48,68 +48,68 @@ export default class TagSpec extends T {
|
|||
equal(isNotEmpty.matchesProperties({"other_key": "value"}), false)
|
||||
|
||||
|
||||
const and = FromJSON.Tag({"and": ["key=value", "x=y"]}) as And;
|
||||
const and = TagUtils.Tag({"and": ["key=value", "x=y"]}) as And;
|
||||
equal((and.and[0] as Tag).key, "key");
|
||||
equal((and.and[1] as Tag).value, "y");
|
||||
|
||||
|
||||
const notReg = FromJSON.Tag("x!~y") as And;
|
||||
const notReg = TagUtils.Tag("x!~y") as And;
|
||||
equal(notReg.matchesProperties({"x": "y"}), false)
|
||||
equal(notReg.matchesProperties({"x": "z"}), true)
|
||||
equal(notReg.matchesProperties({"x": ""}), true)
|
||||
equal(notReg.matchesProperties({}), true)
|
||||
|
||||
const noMatch = FromJSON.Tag("key!=value") as Tag;
|
||||
const noMatch = TagUtils.Tag("key!=value") as Tag;
|
||||
equal(noMatch.matchesProperties({"key": "value"}), false)
|
||||
equal(noMatch.matchesProperties({"key": "otherValue"}), true)
|
||||
equal(noMatch.matchesProperties({"key": ""}), true)
|
||||
equal(noMatch.matchesProperties({"otherKey": ""}), true)
|
||||
|
||||
|
||||
const multiMatch = FromJSON.Tag("vending~.*bicycle_tube.*") as Tag;
|
||||
const multiMatch = TagUtils.Tag("vending~.*bicycle_tube.*") as Tag;
|
||||
equal(multiMatch.matchesProperties({"vending": "bicycle_tube"}), true)
|
||||
equal(multiMatch.matchesProperties({"vending": "something;bicycle_tube"}), true)
|
||||
equal(multiMatch.matchesProperties({"vending": "bicycle_tube;something"}), true)
|
||||
equal(multiMatch.matchesProperties({"vending": "xyz;bicycle_tube;something"}), true)
|
||||
|
||||
const nameStartsWith = FromJSON.Tag("name~[sS]peelbos.*")
|
||||
const nameStartsWith = TagUtils.Tag("name~[sS]peelbos.*")
|
||||
equal(nameStartsWith.matchesProperties({"name": "Speelbos Sint-Anna"}), true)
|
||||
equal(nameStartsWith.matchesProperties({"name": "speelbos Sint-Anna"}), true)
|
||||
equal(nameStartsWith.matchesProperties({"name": "Sint-Anna"}), false)
|
||||
equal(nameStartsWith.matchesProperties({"name": ""}), false)
|
||||
|
||||
|
||||
const assign = FromJSON.Tag("survey:date:={_date:now}")
|
||||
const assign = TagUtils.Tag("survey:date:={_date:now}")
|
||||
equal(assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-03-29"}), true);
|
||||
equal(assign.matchesProperties({"survey:date": "2021-03-29", "_date:now": "2021-01-01"}), false);
|
||||
equal(assign.matchesProperties({"survey:date": "2021-03-29"}), false);
|
||||
equal(assign.matchesProperties({"_date:now": "2021-03-29"}), false);
|
||||
equal(assign.matchesProperties({"some_key": "2021-03-29"}), false);
|
||||
|
||||
const notEmptyList = FromJSON.Tag("xyz!~\\[\\]")
|
||||
const notEmptyList = TagUtils.Tag("xyz!~\\[\\]")
|
||||
equal(notEmptyList.matchesProperties({"xyz": undefined}), true);
|
||||
equal(notEmptyList.matchesProperties({"xyz": "[]"}), false);
|
||||
equal(notEmptyList.matchesProperties({"xyz": "[\"abc\"]"}), true);
|
||||
|
||||
let compare = FromJSON.Tag("key<=5")
|
||||
let compare = TagUtils.Tag("key<=5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), false);
|
||||
equal(compare.matchesProperties({"key": "5"}), true);
|
||||
equal(compare.matchesProperties({"key": "4"}), true);
|
||||
|
||||
|
||||
compare = FromJSON.Tag("key<5")
|
||||
compare = TagUtils.Tag("key<5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), false);
|
||||
equal(compare.matchesProperties({"key": "5"}), false);
|
||||
equal(compare.matchesProperties({"key": "4.2"}), true);
|
||||
|
||||
compare = FromJSON.Tag("key>5")
|
||||
compare = TagUtils.Tag("key>5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), true);
|
||||
equal(compare.matchesProperties({"key": "5"}), false);
|
||||
equal(compare.matchesProperties({"key": "4.2"}), false);
|
||||
compare = FromJSON.Tag("key>=5")
|
||||
compare = TagUtils.Tag("key>=5")
|
||||
equal(compare.matchesProperties({"key": undefined}), false);
|
||||
equal(compare.matchesProperties({"key": "6"}), true);
|
||||
equal(compare.matchesProperties({"key": "5"}), true);
|
||||
|
@ -190,7 +190,7 @@ export default class TagSpec extends T {
|
|||
"protect_class!=98"
|
||||
]
|
||||
}
|
||||
const filter = FromJSON.Tag(t)
|
||||
const filter = TagUtils.Tag(t)
|
||||
const overpass = filter.asOverpass();
|
||||
console.log(overpass)
|
||||
equal(overpass[0], "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]")
|
||||
|
@ -201,7 +201,7 @@ export default class TagSpec extends T {
|
|||
t
|
||||
]
|
||||
}
|
||||
const overpassOr = FromJSON.Tag(or).asOverpass()
|
||||
const overpassOr = TagUtils.Tag(or).asOverpass()
|
||||
equal(2, overpassOr.length)
|
||||
equal(overpassOr[1], "[\"boundary\"=\"protected_area\"][\"protect_class\"!~\"^98$\"]")
|
||||
|
||||
|
@ -209,7 +209,7 @@ export default class TagSpec extends T {
|
|||
"amenity=drinking_water",
|
||||
or
|
||||
]}
|
||||
const overpassOrInor = FromJSON.Tag(orInOr).asOverpass()
|
||||
const overpassOrInor = TagUtils.Tag(orInOr).asOverpass()
|
||||
equal(3, overpassOrInor.length)
|
||||
}
|
||||
], [
|
||||
|
|
|
@ -4,10 +4,10 @@ import {Utils} from "../Utils";
|
|||
Utils.runningFromConsole = true;
|
||||
import TagRenderingQuestion from "../UI/Popup/TagRenderingQuestion";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import TagRenderingConfig from "../Customizations/JSON/TagRenderingConfig";
|
||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||
import {LayoutConfigJson} from "../Customizations/JSON/LayoutConfigJson";
|
||||
import * as assert from "assert";
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
|
||||
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
|
||||
export default class ThemeSpec extends T{
|
||||
constructor() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import T from "./TestHelper";
|
||||
import {Denomination, Unit} from "../Customizations/JSON/Denomination";
|
||||
import {equal} from "assert";
|
||||
import {Unit} from "../Models/Unit";
|
||||
import {Denomination} from "../Models/Denomination";
|
||||
|
||||
export default class UnitsSpec extends T {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue