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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +93,38 @@ A phone number
 | 
			
		|||
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,11 +14,11 @@
 | 
			
		|||
 | 
			
		||||
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 
 | 
			
		||||
 | 
			
		||||
 `{image_carousel(image)}` 
 | 
			
		||||
 `{image_carousel(image,mapillary,image,wikidata,wikimedia_commons,image,image)}` 
 | 
			
		||||
### image_upload 
 | 
			
		||||
 | 
			
		||||
 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
 | 
			
		||||
------ | --------- | -------------
 | 
			
		||||
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 
 | 
			
		||||
 | 
			
		||||
 `{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 
 | 
			
		||||
 | 
			
		||||
 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;
 | 
			
		||||
        this._value = inputElement.GetValue().map(
 | 
			
		||||
            (t => {
 | 
			
		||||
                const currentX = self.GetValue()?.data;
 | 
			
		||||
                const newX = toX(t);
 | 
			
		||||
                const currentX = self.GetValue()?.data;
 | 
			
		||||
                if (isSame(currentX, newX)) {
 | 
			
		||||
                    return currentX;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,9 @@ import {FixedInputElement} from "./FixedInputElement";
 | 
			
		|||
import WikidataSearchBox from "../Wikipedia/WikidataSearchBox";
 | 
			
		||||
import Wikidata from "../../Logic/Web/Wikidata";
 | 
			
		||||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
 | 
			
		||||
import Table from "../Base/Table";
 | 
			
		||||
import Combine from "../Base/Combine";
 | 
			
		||||
import Title from "../Base/Title";
 | 
			
		||||
 | 
			
		||||
interface TextFieldDef {
 | 
			
		||||
    name: string,
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +31,159 @@ interface TextFieldDef {
 | 
			
		|||
    inputHelper?: (value: UIEventSource<string>, options?: {
 | 
			
		||||
        location: [number, number],
 | 
			
		||||
        mapBackgroundLayer?: UIEventSource<any>,
 | 
			
		||||
        args: (string | number | boolean)[]
 | 
			
		||||
        args: (string | number | boolean | any)[]
 | 
			
		||||
        feature?: any
 | 
			
		||||
    }) => InputElement<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 {
 | 
			
		||||
 | 
			
		||||
    public static tpList: TextFieldDef[] = [
 | 
			
		||||
| 
						 | 
				
			
			@ -146,60 +296,7 @@ export default class ValidatedTextField {
 | 
			
		|||
            },
 | 
			
		||||
            "decimal"
 | 
			
		||||
        ),
 | 
			
		||||
        ValidatedTextField.tp(
 | 
			
		||||
            "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)
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
        ),
 | 
			
		||||
        new WikidataTextField(),
 | 
			
		||||
 | 
			
		||||
        ValidatedTextField.tp(
 | 
			
		||||
            "int",
 | 
			
		||||
| 
						 | 
				
			
			@ -299,15 +396,7 @@ export default class ValidatedTextField {
 | 
			
		|||
            undefined,
 | 
			
		||||
            "tel"
 | 
			
		||||
        ),
 | 
			
		||||
        ValidatedTextField.tp(
 | 
			
		||||
            "opening_hours",
 | 
			
		||||
            "Has extra elements to easily input when a POI is opened",
 | 
			
		||||
            () => true,
 | 
			
		||||
            str => str,
 | 
			
		||||
            (value) => {
 | 
			
		||||
                return new OpeningHoursInput(value);
 | 
			
		||||
            }
 | 
			
		||||
        ),
 | 
			
		||||
        new OpeningHoursTextField(),
 | 
			
		||||
        ValidatedTextField.tp(
 | 
			
		||||
            "color",
 | 
			
		||||
            "Shows a color picker",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,11 +23,39 @@ export default class OpeningHoursInput extends InputElement<string> {
 | 
			
		|||
    private readonly _value: UIEventSource<string>;
 | 
			
		||||
    private readonly _element: BaseUIElement;
 | 
			
		||||
 | 
			
		||||
    constructor(value: UIEventSource<string> = new UIEventSource<string>("")) {
 | 
			
		||||
    constructor(value: UIEventSource<string> = new UIEventSource<string>(""), prefix = "", postfix = "") {
 | 
			
		||||
        super();
 | 
			
		||||
        this._value = value;
 | 
			
		||||
        let valueWithoutPrefix = value
 | 
			
		||||
        if (prefix !== "" && postfix !== "") {
 | 
			
		||||
       
 | 
			
		||||
            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
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
        const leftoverRules = value.map<string[]>(str => {
 | 
			
		||||
                return prefix + noPrefix + postfix
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const leftoverRules = valueWithoutPrefix.map<string[]>(str => {
 | 
			
		||||
            if (str === undefined) {
 | 
			
		||||
                return []
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -45,9 +73,9 @@ export default class OpeningHoursInput extends InputElement<string> {
 | 
			
		|||
            return leftOvers;
 | 
			
		||||
        })
 | 
			
		||||
        // 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) {
 | 
			
		||||
                return ""
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +96,7 @@ export default class OpeningHoursInput extends InputElement<string> {
 | 
			
		|||
                ...leftoverRules.data,
 | 
			
		||||
                ph.data
 | 
			
		||||
            ]
 | 
			
		||||
            value.setData(Utils.NoEmpty(rules).join(";"));
 | 
			
		||||
            valueWithoutPrefix.setData(Utils.NoEmpty(rules).join(";"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        rulesFromOhPicker.addCallback(update);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,10 +23,16 @@ export default class OpeningHoursVisualization extends Toggle {
 | 
			
		|||
        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 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 => {
 | 
			
		||||
                    try {
 | 
			
		||||
                        // noinspection JSPotentiallyInvalidConstructorUsage
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -253,9 +253,18 @@ export default class SpecialVisualizations {
 | 
			
		|||
                    name: "key",
 | 
			
		||||
                    defaultValue: "opening_hours",
 | 
			
		||||
                    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) => {
 | 
			
		||||
                    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 args = knownSpecial.args.map(arg => arg.defaultValue ?? "");
 | 
			
		||||
                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++) {
 | 
			
		||||
                        if (args.length <= i) {
 | 
			
		||||
                            args.push(realArgs[i]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -298,7 +298,7 @@
 | 
			
		|||
            "id": "bike_shop-email"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "render": "{opening_hours_table(opening_hours)}",
 | 
			
		||||
            "render": "{opening_hours_table()}",
 | 
			
		||||
            "question": "When is this shop opened?",
 | 
			
		||||
            "freeform": {
 | 
			
		||||
                "key": "opening_hours",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue