forked from MapComplete/MapComplete
		
	Add the possibility to define a postfix and prefix for opening hours
This commit is contained in:
		
							parent
							
								
									9c147b6ec6
								
							
						
					
					
						commit
						a2306c2c6f
					
				
					 10 changed files with 281 additions and 81 deletions
				
			
		| 
						 | 
					@ -100,7 +100,7 @@ Adds the time that the data got loaded - pretty much the time of downloading fro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### _last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number 
 | 
					### _last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number, _backend 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,40 @@ A geographical length in meters (rounded at two points). Will give an extra mini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## wikidata
 | 
					## wikidata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A wikidata identifier, e.g. Q42. Input helper arguments: [ key: the value of this tag will initialize search (default: name), options: { removePrefixes: string[], removePostfixes: string[] }  these prefixes and postfixes will be removed from the initial search value]
 | 
					A wikidata identifier, e.g. Q42. 
 | 
				
			||||||
 | 
					### Helper arguments 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					name | doc
 | 
				
			||||||
 | 
					------ | -----
 | 
				
			||||||
 | 
					key | the value of this tag will initialize search (default: name)
 | 
				
			||||||
 | 
					options | A JSON-object of type `{ removePrefixes: string[], removePostfixes: string[] }`. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					subarg | doc
 | 
				
			||||||
 | 
					-------- | -----
 | 
				
			||||||
 | 
					removePrefixes | remove these snippets of text from the start of the passed string to search
 | 
				
			||||||
 | 
					removePostfixes | remove these snippets of text from the end of the passed string to search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					### Example usage 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 The following is the 'freeform'-part of a layer config which will trigger a search for the wikidata item corresponding with the name of the selected feature. It will also remove '-street', '-square', ... if found at the end of the name```"freeform": {
 | 
				
			||||||
 | 
					                "key": "name:etymology:wikidata",
 | 
				
			||||||
 | 
					                "type": "wikidata",
 | 
				
			||||||
 | 
					                "helperArgs": [
 | 
				
			||||||
 | 
					                    "name",
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "removePostfixes": [
 | 
				
			||||||
 | 
					                            "street",
 | 
				
			||||||
 | 
					                            "boulevard",
 | 
				
			||||||
 | 
					                            "path",
 | 
				
			||||||
 | 
					                            "square",
 | 
				
			||||||
 | 
					                            "plaza",
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            },```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## int
 | 
					## int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,7 +93,38 @@ A phone number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## opening_hours
 | 
					## opening_hours
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Has extra elements to easily input when a POI is opened
 | 
					Has extra elements to easily input when a POI is opened. 
 | 
				
			||||||
 | 
					### Helper arguments 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					name | doc
 | 
				
			||||||
 | 
					------ | -----
 | 
				
			||||||
 | 
					options | A JSON-object of type `{ prefix: string, postfix: string }`.  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					subarg | doc
 | 
				
			||||||
 | 
					-------- | -----
 | 
				
			||||||
 | 
					prefix | Piece of text that will always be added to the front of the generated opening hours. If the OSM-data does not start with this, it will fail to parse
 | 
				
			||||||
 | 
					postfix | Piece of text that will always be added to the end of the generated opening hours
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					### Example usage 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 To add a conditional (based on time) access restriction:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					            "freeform": {
 | 
				
			||||||
 | 
					                "key": "access:conditional",
 | 
				
			||||||
 | 
					                "type": "opening_hours",
 | 
				
			||||||
 | 
					                "helperArgs": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "prefix":"no @ (",
 | 
				
			||||||
 | 
					                      "postfix":")"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            },```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*Don't forget to pass these in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## color
 | 
					## color
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,11 +14,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
name | default | description
 | 
					name | default | description
 | 
				
			||||||
------ | --------- | -------------
 | 
					------ | --------- | -------------
 | 
				
			||||||
image key/prefix (multiple values allowed if comma-seperated) | image | The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... 
 | 
					image key/prefix (multiple values allowed if comma-seperated) | image,mapillary,image,wikidata,wikimedia_commons,image,image | The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... 
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
#### Example usage 
 | 
					#### Example usage 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 `{image_carousel(image)}` 
 | 
					 `{image_carousel(image,mapillary,image,wikidata,wikimedia_commons,image,image)}` 
 | 
				
			||||||
### image_upload 
 | 
					### image_upload 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 Creates a button where a user can upload an image to IMGUR 
 | 
					 Creates a button where a user can upload an image to IMGUR 
 | 
				
			||||||
| 
						 | 
					@ -73,10 +73,12 @@ fallback | undefined | The identifier to use, if <i>tags[subjectKey]</i> as spec
 | 
				
			||||||
name | default | description
 | 
					name | default | description
 | 
				
			||||||
------ | --------- | -------------
 | 
					------ | --------- | -------------
 | 
				
			||||||
key | opening_hours | The tagkey from which the table is constructed.
 | 
					key | opening_hours | The tagkey from which the table is constructed.
 | 
				
			||||||
 | 
					prefix |  | Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__
 | 
				
			||||||
 | 
					postfix |  | Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
#### Example usage 
 | 
					#### Example usage 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 `{opening_hours_table(opening_hours)}` 
 | 
					 A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}` 
 | 
				
			||||||
### live 
 | 
					### live 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 Downloads a JSON from the given URL, e.g. '{live(example.org/data.json, shorthand:x.y.z, other:a.b.c, shorthand)}' will download the given file, will create an object {shorthand: json[x][y][z], other: json[a][b][c] out of it and will return 'other' or 'json[a][b][c]. This is made to use in combination with tags, e.g. {live({url}, {url:format}, needed_value)} 
 | 
					 Downloads a JSON from the given URL, e.g. '{live(example.org/data.json, shorthand:x.y.z, other:a.b.c, shorthand)}' will download the given file, will create an object {shorthand: json[x][y][z], other: json[a][b][c] out of it and will return 'other' or 'json[a][b][c]. This is made to use in combination with tags, e.g. {live({url}, {url:format}, needed_value)} 
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,8 +25,8 @@ export default class InputElementMap<T, X> extends InputElement<X> {
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
        this._value = inputElement.GetValue().map(
 | 
					        this._value = inputElement.GetValue().map(
 | 
				
			||||||
            (t => {
 | 
					            (t => {
 | 
				
			||||||
                const currentX = self.GetValue()?.data;
 | 
					 | 
				
			||||||
                const newX = toX(t);
 | 
					                const newX = toX(t);
 | 
				
			||||||
 | 
					                const currentX = self.GetValue()?.data;
 | 
				
			||||||
                if (isSame(currentX, newX)) {
 | 
					                if (isSame(currentX, newX)) {
 | 
				
			||||||
                    return currentX;
 | 
					                    return currentX;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,9 @@ import {FixedInputElement} from "./FixedInputElement";
 | 
				
			||||||
import WikidataSearchBox from "../Wikipedia/WikidataSearchBox";
 | 
					import WikidataSearchBox from "../Wikipedia/WikidataSearchBox";
 | 
				
			||||||
import Wikidata from "../../Logic/Web/Wikidata";
 | 
					import Wikidata from "../../Logic/Web/Wikidata";
 | 
				
			||||||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
 | 
					import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
 | 
				
			||||||
 | 
					import Table from "../Base/Table";
 | 
				
			||||||
 | 
					import Combine from "../Base/Combine";
 | 
				
			||||||
 | 
					import Title from "../Base/Title";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface TextFieldDef {
 | 
					interface TextFieldDef {
 | 
				
			||||||
    name: string,
 | 
					    name: string,
 | 
				
			||||||
| 
						 | 
					@ -28,12 +31,159 @@ interface TextFieldDef {
 | 
				
			||||||
    inputHelper?: (value: UIEventSource<string>, options?: {
 | 
					    inputHelper?: (value: UIEventSource<string>, options?: {
 | 
				
			||||||
        location: [number, number],
 | 
					        location: [number, number],
 | 
				
			||||||
        mapBackgroundLayer?: UIEventSource<any>,
 | 
					        mapBackgroundLayer?: UIEventSource<any>,
 | 
				
			||||||
        args: (string | number | boolean)[]
 | 
					        args: (string | number | boolean | any)[]
 | 
				
			||||||
        feature?: any
 | 
					        feature?: any
 | 
				
			||||||
    }) => InputElement<string>,
 | 
					    }) => InputElement<string>,
 | 
				
			||||||
    inputmode?: string
 | 
					    inputmode?: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WikidataTextField implements TextFieldDef {
 | 
				
			||||||
 | 
					    name = "wikidata"
 | 
				
			||||||
 | 
					    explanation =
 | 
				
			||||||
 | 
					        new Combine([
 | 
				
			||||||
 | 
					            "A wikidata identifier, e.g. Q42.",
 | 
				
			||||||
 | 
					            new Title("Helper arguments"),
 | 
				
			||||||
 | 
					            new Table(["name", "doc"],
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    ["key", "the value of this tag will initialize search (default: name)"],
 | 
				
			||||||
 | 
					                    ["options", new Combine(["A JSON-object of type `{ removePrefixes: string[], removePostfixes: string[] }`.",
 | 
				
			||||||
 | 
					                        new Table(
 | 
				
			||||||
 | 
					                            ["subarg", "doc"],
 | 
				
			||||||
 | 
					                            [["removePrefixes", "remove these snippets of text from the start of the passed string to search"],
 | 
				
			||||||
 | 
					                                ["removePostfixes", "remove these snippets of text from the end of the passed string to search"],
 | 
				
			||||||
 | 
					                            ]
 | 
				
			||||||
 | 
					                        )])
 | 
				
			||||||
 | 
					                    ]]),
 | 
				
			||||||
 | 
					            new Title("Example usage"),
 | 
				
			||||||
 | 
					            "The following is the 'freeform'-part of a layer config which will trigger a search for the wikidata item corresponding with the name of the selected feature. It will also remove '-street', '-square', ... if found at the end of the name```" + `"freeform": {
 | 
				
			||||||
 | 
					                "key": "name:etymology:wikidata",
 | 
				
			||||||
 | 
					                "type": "wikidata",
 | 
				
			||||||
 | 
					                "helperArgs": [
 | 
				
			||||||
 | 
					                    "name",
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        "removePostfixes": [
 | 
				
			||||||
 | 
					                            "street",
 | 
				
			||||||
 | 
					                            "boulevard",
 | 
				
			||||||
 | 
					                            "path",
 | 
				
			||||||
 | 
					                            "square",
 | 
				
			||||||
 | 
					                            "plaza",
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            },` + "```"
 | 
				
			||||||
 | 
					        ]).AsMarkdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public isValid(str) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (str === undefined) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (str.length <= 2) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return !str.split(";").some(str => Wikidata.ExtractKey(str) === undefined)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public reformat(str) {
 | 
				
			||||||
 | 
					        if (str === undefined) {
 | 
				
			||||||
 | 
					            return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let out = str.split(";").map(str => Wikidata.ExtractKey(str)).join("; ")
 | 
				
			||||||
 | 
					        if (str.endsWith(";")) {
 | 
				
			||||||
 | 
					            out = out + ";"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public inputHelper(currentValue, inputHelperOptions) {
 | 
				
			||||||
 | 
					        const args = inputHelperOptions.args ?? []
 | 
				
			||||||
 | 
					        const searchKey = args[0] ?? "name"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let searchFor = <string>inputHelperOptions.feature?.properties[searchKey]?.toLowerCase()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const options = args[1]
 | 
				
			||||||
 | 
					        if (searchFor !== undefined && options !== undefined) {
 | 
				
			||||||
 | 
					            const prefixes = <string[]>options["removePrefixes"]
 | 
				
			||||||
 | 
					            const postfixes = <string[]>options["removePostfixes"]
 | 
				
			||||||
 | 
					            for (const postfix of postfixes ?? []) {
 | 
				
			||||||
 | 
					                if (searchFor.endsWith(postfix)) {
 | 
				
			||||||
 | 
					                    searchFor = searchFor.substring(0, searchFor.length - postfix.length)
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (const prefix of prefixes ?? []) {
 | 
				
			||||||
 | 
					                if (searchFor.startsWith(prefix)) {
 | 
				
			||||||
 | 
					                    searchFor = searchFor.substring(prefix.length)
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new WikidataSearchBox({
 | 
				
			||||||
 | 
					            value: currentValue,
 | 
				
			||||||
 | 
					            searchText: new UIEventSource<string>(searchFor)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OpeningHoursTextField implements TextFieldDef {
 | 
				
			||||||
 | 
					    name = "opening_hours"
 | 
				
			||||||
 | 
					    explanation =
 | 
				
			||||||
 | 
					        new Combine([
 | 
				
			||||||
 | 
					            "Has extra elements to easily input when a POI is opened.",
 | 
				
			||||||
 | 
					            new Title("Helper arguments"),
 | 
				
			||||||
 | 
					            new Table(["name", "doc"],
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    ["options", new Combine([
 | 
				
			||||||
 | 
					                        "A JSON-object of type `{ prefix: string, postfix: string }`. ",
 | 
				
			||||||
 | 
					                        new Table(["subarg", "doc"],
 | 
				
			||||||
 | 
					                            [
 | 
				
			||||||
 | 
					                                ["prefix", "Piece of text that will always be added to the front of the generated opening hours. If the OSM-data does not start with this, it will fail to parse"],
 | 
				
			||||||
 | 
					                                ["postfix", "Piece of text that will always be added to the end of the generated opening hours"],
 | 
				
			||||||
 | 
					                            ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    ])
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                ]),
 | 
				
			||||||
 | 
					            new Title("Example usage"),
 | 
				
			||||||
 | 
					            "To add a conditional (based on time) access restriction:\n\n```" + `
 | 
				
			||||||
 | 
					            "freeform": {
 | 
				
			||||||
 | 
					                "key": "access:conditional",
 | 
				
			||||||
 | 
					                "type": "opening_hours",
 | 
				
			||||||
 | 
					                "helperArgs": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "prefix":"no @ (",
 | 
				
			||||||
 | 
					                      "postfix":")"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            },` + "```\n\n*Don't forget to pass these in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )`"]).AsMarkdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    isValid() {
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reformat(str) {
 | 
				
			||||||
 | 
					        return str
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inputHelper(value: UIEventSource<string>, inputHelperOptions: {
 | 
				
			||||||
 | 
					        location: [number, number],
 | 
				
			||||||
 | 
					        mapBackgroundLayer?: UIEventSource<any>,
 | 
				
			||||||
 | 
					        args: (string | number | boolean | any)[]
 | 
				
			||||||
 | 
					        feature?: any
 | 
				
			||||||
 | 
					    }) {
 | 
				
			||||||
 | 
					        const args = (inputHelperOptions.args ?? [])[0]
 | 
				
			||||||
 | 
					        const prefix = <string>args?.prefix ?? ""
 | 
				
			||||||
 | 
					        const postfix = <string>args?.postfix ?? ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new OpeningHoursInput(value, prefix, postfix)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class ValidatedTextField {
 | 
					export default class ValidatedTextField {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static tpList: TextFieldDef[] = [
 | 
					    public static tpList: TextFieldDef[] = [
 | 
				
			||||||
| 
						 | 
					@ -146,60 +296,7 @@ export default class ValidatedTextField {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "decimal"
 | 
					            "decimal"
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        ValidatedTextField.tp(
 | 
					        new WikidataTextField(),
 | 
				
			||||||
            "wikidata",
 | 
					 | 
				
			||||||
            "A wikidata identifier, e.g. Q42. Input helper arguments: [ key: the value of this tag will initialize search (default: name), options: { removePrefixes: string[], removePostfixes: string[] }  these prefixes and postfixes will be removed from the initial search value]",
 | 
					 | 
				
			||||||
            (str) => {
 | 
					 | 
				
			||||||
                if (str === undefined) {
 | 
					 | 
				
			||||||
                    return false;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if(str.length <= 2){
 | 
					 | 
				
			||||||
                    return false;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return !str.split(";").some(str => Wikidata.ExtractKey(str) === undefined)
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            (str) => {
 | 
					 | 
				
			||||||
                if (str === undefined) {
 | 
					 | 
				
			||||||
                    return undefined;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                let out = str.split(";").map(str => Wikidata.ExtractKey(str)).join("; ")
 | 
					 | 
				
			||||||
                if(str.endsWith(";")){
 | 
					 | 
				
			||||||
                    out = out + ";"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return out;
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            (currentValue, inputHelperOptions) => {
 | 
					 | 
				
			||||||
                const args = inputHelperOptions.args ?? []
 | 
					 | 
				
			||||||
                const searchKey = args[0] ?? "name"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let searchFor = <string>inputHelperOptions.feature?.properties[searchKey]?.toLowerCase()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const options = args[1]
 | 
					 | 
				
			||||||
                if (searchFor !== undefined && options !== undefined) {
 | 
					 | 
				
			||||||
                    const prefixes = <string[]>options["removePrefixes"]
 | 
					 | 
				
			||||||
                    const postfixes = <string[]>options["removePostfixes"]
 | 
					 | 
				
			||||||
                    for (const postfix of postfixes ?? []) {
 | 
					 | 
				
			||||||
                        if (searchFor.endsWith(postfix)) {
 | 
					 | 
				
			||||||
                            searchFor = searchFor.substring(0, searchFor.length - postfix.length)
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (const prefix of prefixes ?? []) {
 | 
					 | 
				
			||||||
                        if (searchFor.startsWith(prefix)) {
 | 
					 | 
				
			||||||
                            searchFor = searchFor.substring(prefix.length)
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return new WikidataSearchBox({
 | 
					 | 
				
			||||||
                    value: currentValue,
 | 
					 | 
				
			||||||
                    searchText: new UIEventSource<string>(searchFor)
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ValidatedTextField.tp(
 | 
					        ValidatedTextField.tp(
 | 
				
			||||||
            "int",
 | 
					            "int",
 | 
				
			||||||
| 
						 | 
					@ -299,15 +396,7 @@ export default class ValidatedTextField {
 | 
				
			||||||
            undefined,
 | 
					            undefined,
 | 
				
			||||||
            "tel"
 | 
					            "tel"
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        ValidatedTextField.tp(
 | 
					        new OpeningHoursTextField(),
 | 
				
			||||||
            "opening_hours",
 | 
					 | 
				
			||||||
            "Has extra elements to easily input when a POI is opened",
 | 
					 | 
				
			||||||
            () => true,
 | 
					 | 
				
			||||||
            str => str,
 | 
					 | 
				
			||||||
            (value) => {
 | 
					 | 
				
			||||||
                return new OpeningHoursInput(value);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        ValidatedTextField.tp(
 | 
					        ValidatedTextField.tp(
 | 
				
			||||||
            "color",
 | 
					            "color",
 | 
				
			||||||
            "Shows a color picker",
 | 
					            "Shows a color picker",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,11 +23,39 @@ export default class OpeningHoursInput extends InputElement<string> {
 | 
				
			||||||
    private readonly _value: UIEventSource<string>;
 | 
					    private readonly _value: UIEventSource<string>;
 | 
				
			||||||
    private readonly _element: BaseUIElement;
 | 
					    private readonly _element: BaseUIElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(value: UIEventSource<string> = new UIEventSource<string>("")) {
 | 
					    constructor(value: UIEventSource<string> = new UIEventSource<string>(""), prefix = "", postfix = "") {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
        this._value = value;
 | 
					        this._value = value;
 | 
				
			||||||
 | 
					        let valueWithoutPrefix = value
 | 
				
			||||||
 | 
					        if (prefix !== "" && postfix !== "") {
 | 
				
			||||||
       
 | 
					       
 | 
				
			||||||
        const leftoverRules = value.map<string[]>(str => {
 | 
					            valueWithoutPrefix = value.map(str => {
 | 
				
			||||||
 | 
					                if (str === undefined) {
 | 
				
			||||||
 | 
					                    return undefined;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if(str === ""){
 | 
				
			||||||
 | 
					                    return ""
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (str.startsWith(prefix) && str.endsWith(postfix)) {
 | 
				
			||||||
 | 
					                    return str.substring(prefix.length, str.length - postfix.length)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return str
 | 
				
			||||||
 | 
					            }, [], noPrefix => {
 | 
				
			||||||
 | 
					                if (noPrefix === undefined) {
 | 
				
			||||||
 | 
					                    return undefined;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if(noPrefix === ""){
 | 
				
			||||||
 | 
					                    return ""
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (noPrefix.startsWith(prefix) && noPrefix.endsWith(postfix)) {
 | 
				
			||||||
 | 
					                    return noPrefix
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return prefix + noPrefix + postfix
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const leftoverRules = valueWithoutPrefix.map<string[]>(str => {
 | 
				
			||||||
            if (str === undefined) {
 | 
					            if (str === undefined) {
 | 
				
			||||||
                return []
 | 
					                return []
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -45,9 +73,9 @@ export default class OpeningHoursInput extends InputElement<string> {
 | 
				
			||||||
            return leftOvers;
 | 
					            return leftOvers;
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        // Note: MUST be bound AFTER the leftover rules!
 | 
					        // Note: MUST be bound AFTER the leftover rules!
 | 
				
			||||||
        const rulesFromOhPicker = value.map(OH.Parse);
 | 
					        const rulesFromOhPicker = valueWithoutPrefix.map(OH.Parse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const ph = value.map<string>(str => {
 | 
					        const ph = valueWithoutPrefix.map<string>(str => {
 | 
				
			||||||
            if (str === undefined) {
 | 
					            if (str === undefined) {
 | 
				
			||||||
                return ""
 | 
					                return ""
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -68,7 +96,7 @@ export default class OpeningHoursInput extends InputElement<string> {
 | 
				
			||||||
                ...leftoverRules.data,
 | 
					                ...leftoverRules.data,
 | 
				
			||||||
                ph.data
 | 
					                ph.data
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
            value.setData(Utils.NoEmpty(rules).join(";"));
 | 
					            valueWithoutPrefix.setData(Utils.NoEmpty(rules).join(";"));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        rulesFromOhPicker.addCallback(update);
 | 
					        rulesFromOhPicker.addCallback(update);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,10 +23,16 @@ export default class OpeningHoursVisualization extends Toggle {
 | 
				
			||||||
        Translations.t.general.weekdays.abbreviations.sunday,
 | 
					        Translations.t.general.weekdays.abbreviations.sunday,
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(tags: UIEventSource<any>, key: string) {
 | 
					    constructor(tags: UIEventSource<any>, key: string, prefix = "", postfix = "") {
 | 
				
			||||||
        const tagsDirect = tags.data;
 | 
					        const tagsDirect = tags.data;
 | 
				
			||||||
        const ohTable = new VariableUiElement(tags
 | 
					        const ohTable = new VariableUiElement(tags
 | 
				
			||||||
            .map(tags => tags[key]) // This mapping will absorb all other changes to tags in order to prevent regeneration
 | 
					            .map(tags => {
 | 
				
			||||||
 | 
					                const value : string = tags[key];
 | 
				
			||||||
 | 
					                if(value.startsWith(prefix) && value.endsWith(postfix)){
 | 
				
			||||||
 | 
					                    return value.substring(prefix.length, value.length - postfix.length)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return value;
 | 
				
			||||||
 | 
					            }) // This mapping will absorb all other changes to tags in order to prevent regeneration
 | 
				
			||||||
            .map(ohtext => {
 | 
					            .map(ohtext => {
 | 
				
			||||||
                    try {
 | 
					                    try {
 | 
				
			||||||
                        // noinspection JSPotentiallyInvalidConstructorUsage
 | 
					                        // noinspection JSPotentiallyInvalidConstructorUsage
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,9 +253,18 @@ export default class SpecialVisualizations {
 | 
				
			||||||
                    name: "key",
 | 
					                    name: "key",
 | 
				
			||||||
                    defaultValue: "opening_hours",
 | 
					                    defaultValue: "opening_hours",
 | 
				
			||||||
                    doc: "The tagkey from which the table is constructed."
 | 
					                    doc: "The tagkey from which the table is constructed."
 | 
				
			||||||
 | 
					                },{
 | 
				
			||||||
 | 
					                    name: "prefix",
 | 
				
			||||||
 | 
					                    defaultValue: "",
 | 
				
			||||||
 | 
					                    doc:"Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__"
 | 
				
			||||||
 | 
					                },{
 | 
				
			||||||
 | 
					                    name: "postfix",
 | 
				
			||||||
 | 
					                    defaultValue: "",
 | 
				
			||||||
 | 
					                    doc:"Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__"
 | 
				
			||||||
                }],
 | 
					                }],
 | 
				
			||||||
 | 
					                example: "A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`",
 | 
				
			||||||
                constr: (state: State, tagSource: UIEventSource<any>, args) => {
 | 
					                constr: (state: State, tagSource: UIEventSource<any>, args) => {
 | 
				
			||||||
                    return new OpeningHoursVisualization(tagSource, args[0])
 | 
					                    return new OpeningHoursVisualization(tagSource, args[0], args[1], args[2])
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,7 +85,9 @@ export class SubstitutedTranslation extends VariableUiElement {
 | 
				
			||||||
                const partAfter = SubstitutedTranslation.ExtractSpecialComponents(matched[4], extraMappings);
 | 
					                const partAfter = SubstitutedTranslation.ExtractSpecialComponents(matched[4], extraMappings);
 | 
				
			||||||
                const args = knownSpecial.args.map(arg => arg.defaultValue ?? "");
 | 
					                const args = knownSpecial.args.map(arg => arg.defaultValue ?? "");
 | 
				
			||||||
                if (argument.length > 0) {
 | 
					                if (argument.length > 0) {
 | 
				
			||||||
                    const realArgs = argument.split(",").map(str => str.trim());
 | 
					                    const realArgs = argument.split(",").map(str => str.trim()
 | 
				
			||||||
 | 
					                        .replace(/&LPARENS/g, '(')
 | 
				
			||||||
 | 
					                        .replace(/&RPARENS/g, ')'));
 | 
				
			||||||
                    for (let i = 0; i < realArgs.length; i++) {
 | 
					                    for (let i = 0; i < realArgs.length; i++) {
 | 
				
			||||||
                        if (args.length <= i) {
 | 
					                        if (args.length <= i) {
 | 
				
			||||||
                            args.push(realArgs[i]);
 | 
					                            args.push(realArgs[i]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,7 +298,7 @@
 | 
				
			||||||
            "id": "bike_shop-email"
 | 
					            "id": "bike_shop-email"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "render": "{opening_hours_table(opening_hours)}",
 | 
					            "render": "{opening_hours_table()}",
 | 
				
			||||||
            "question": "When is this shop opened?",
 | 
					            "question": "When is this shop opened?",
 | 
				
			||||||
            "freeform": {
 | 
					            "freeform": {
 | 
				
			||||||
                "key": "opening_hours",
 | 
					                "key": "opening_hours",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue