diff --git a/Docs/BuiltinLayers.md b/Docs/BuiltinLayers.md index 48d5d0047..7ce567ec0 100644 --- a/Docs/BuiltinLayers.md +++ b/Docs/BuiltinLayers.md @@ -5,8 +5,8 @@ ## Table of contents -1. [Special and other useful layers](#Special_and_other_useful_layers) -1. [Priviliged layers](#Priviliged_layers) +1. [Special and other useful layers](#special-and-other-useful-layers) +1. [Priviliged layers](#priviliged-layers) + [gps_location](#gps_location) + [gps_location_history](#gps_location_history) + [home_location](#home_location) @@ -14,17 +14,17 @@ + [type_node](#type_node) + [conflation](#conflation) + [left_right_style](#left_right_style) -1. [Frequently reused layers](#Frequently_reused_layers) +1. [Frequently reused layers](#frequently-reused-layers) + [bicycle_library](#bicycle_library) - * [Themes using this layer](#Themes_using_this_layer) + * [Themes using this layer](#themes-using-this-layer) + [drinking_water](#drinking_water) - * [Themes using this layer](#Themes_using_this_layer) + * [Themes using this layer](#themes-using-this-layer) + [food](#food) - * [Themes using this layer](#Themes_using_this_layer) + * [Themes using this layer](#themes-using-this-layer) + [map](#map) - * [Themes using this layer](#Themes_using_this_layer) + * [Themes using this layer](#themes-using-this-layer) + [all_streets](#all_streets) - * [Themes using this layer](#Themes_using_this_layer) + * [Themes using this layer](#themes-using-this-layer) MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here. diff --git a/Docs/CalculatedTags.md b/Docs/CalculatedTags.md index 57a50626f..8e19bdc03 100644 --- a/Docs/CalculatedTags.md +++ b/Docs/CalculatedTags.md @@ -5,21 +5,21 @@ ## Table of contents -1. [Metatags](#Metatags) - - [Metatags calculated by MapComplete](#Metatags_calculated_by_MapComplete) - + [_lat, _lon](#_lat,__lon) +1. [Metatags](#metatags) + - [Metatags calculated by MapComplete](#metatags-calculated-by-mapcomplete) + + [_lat, _lon](#_lat,-_lon) + [_layer](#_layer) - + [_surface, _surface:ha](#_surface,__surface:ha) - + [_length, _length:km](#_length,__length:km) - + [Theme-defined keys](#Theme-defined_keys) + + [_surface, _surface:ha](#_surface,-_surfaceha) + + [_length, _length:km](#_length,-_lengthkm) + + [Theme-defined keys](#theme-defined-keys) + [_country](#_country) - + [_isOpen, _isOpen:description](#_isOpen,__isOpen:description) - + [_direction:numerical, _direction:leftright](#_direction:numerical,__direction:leftright) - + [_now:date, _now:datetime, _loaded:date, _loaded:_datetime](#_now:date,__now:datetime,__loaded:date,__loaded:_datetime) - + [_last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number, _backend](#_last_edit:contributor,__last_edit:contributor:uid,__last_edit:changeset,__last_edit:timestamp,__version_number,__backend) - + [sidewalk:left, sidewalk:right, generic_key:left:property, generic_key:right:property](#sidewalk:left,_sidewalk:right,_generic_key:left:property,_generic_key:right:property) - + [distanceTo](#distanceTo) - + [overlapWith](#overlapWith) + + [_isOpen, _isOpen:description](#_isopen,-_isopendescription) + + [_direction:numerical, _direction:leftright](#_directionnumerical,-_direction:leftright) + + [_now:date, _now:datetime, _loaded:date, _loaded:_datetime](#_nowdate,-_now:datetime,-_loaded:date,-_loaded:_datetime) + + [_last_edit:contributor, _last_edit:contributor:uid, _last_edit:changeset, _last_edit:timestamp, _version_number, _backend](#_last_editcontributor,-_last_edit:contributor:uid,-_last_edit:changeset,-_last_edit:timestamp,-_version_number,-_backend) + + [sidewalk:left, sidewalk:right, generic_key:left:property, generic_key:right:property](#sidewalkleft,-sidewalk:right,-generic_key:left:property,-generic_key:right:property) + + [distanceTo](#distanceto) + + [overlapWith](#overlapwith) + [closest](#closest) + [closestn](#closestn) + [memberships](#memberships) diff --git a/Docs/SpecialInputElements.md b/Docs/SpecialInputElements.md index 0517ff371..0209e28d0 100644 --- a/Docs/SpecialInputElements.md +++ b/Docs/SpecialInputElements.md @@ -5,29 +5,59 @@ ## Table of contents -1. [Available types for text fields](#Available_types_for_text_fields) +1. [Available types for text fields](#available-types-for-text-fields) + + [string](#string) + + [text](#text) + + [date](#date) + + [direction](#direction) + + [length](#length) + + [wikidata](#wikidata) + + [int](#int) + + [nat](#nat) + + [pnat](#pnat) + + [float](#float) + + [pfloat](#pfloat) + + [email](#email) + + [url](#url) + + [phone](#phone) + + [opening_hours](#opening_hours) + + [color](#color) - The listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them ## string + The listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them -A basic string +### string -## text -A string, but allows input of longer strings more comfortably and supports newlines (a text area) -## date +A basic string -A date +### text -## direction -A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl) -## length +A string, but allows input of longer strings more comfortably and supports newlines (a text area) + +### date + + + +A date + +### direction + + + +A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl) + +### length + + + +A geographical length in meters (rounded at two points). Will give an extra minimap with a measurement tool. Arguments: [ zoomlevel, preferredBackgroundMapType (comma separated) ], e.g. `["21", "map,photo"] + +### wikidata -A geographical length in meters (rounded at two points). Will give an extra minimap with a measurement tool. Arguments: [ zoomlevel, preferredBackgroundMapType (comma separated) ], e.g. `["21", "map,photo"] -## wikidata A wikidata identifier, e.g. Q42. @@ -68,41 +98,59 @@ removePostfixes | remove these snippets of text from the end of the passed strin } ] } -``` +``` -## int +### int -A number -## nat -A positive number or zero +A number -## pnat +### nat -A strict positive number -## float -A decimal +A positive number or zero -## pfloat +### pnat -A positive decimal (incl zero) -## email -An email adress +A strict positive number -## url +### float -A url -## phone -A phone number +A decimal + +### pfloat + + + +A positive decimal (incl zero) + +### email + + + +An email adress + +### url + + + +A url + +### phone + + + +A phone number + +### opening_hours + -## opening_hours Has extra elements to easily input when a POI is opened. @@ -139,9 +187,11 @@ postfix | Piece of text that will always be added to the end of the generated op } ``` -*Don't forget to pass the prefix and postfix in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )` +*Don't forget to pass the prefix and postfix in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )` + +### color + -## color Shows a color picker diff --git a/Docs/SpecialRenderings.md b/Docs/SpecialRenderings.md index fd1c5d266..096d0cce1 100644 --- a/Docs/SpecialRenderings.md +++ b/Docs/SpecialRenderings.md @@ -5,41 +5,41 @@ ## Table of contents -1. [Special tag renderings](#Special_tag_renderings) +1. [Special tag renderings](#special-tag-renderings) + [all_tags](#all_tags) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [image_carousel](#image_carousel) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [image_upload](#image_upload) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [wikipedia](#wikipedia) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [minimap](#minimap) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [sided_minimap](#sided_minimap) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [reviews](#reviews) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [opening_hours_table](#opening_hours_table) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [live](#live) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [histogram](#histogram) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [share_link](#share_link) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [canonical](#canonical) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [import_button](#import_button) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [multi_apply](#multi_apply) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [tag_apply](#tag_apply) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [export_as_gpx](#export_as_gpx) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) + [clear_location_history](#clear_location_history) - * [Example usage](#Example_usage) + * [Example usage](#example-usage) In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's. General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_name(args):cssStyle}`. Note that you _do not_ need to use quotes around your arguments, the comma is enough to separate them. This also implies you cannot use a comma in your args diff --git a/Docs/URL_Parameters.md b/Docs/URL_Parameters.md index a2d830a91..ecc8fec5c 100644 --- a/Docs/URL_Parameters.md +++ b/Docs/URL_Parameters.md @@ -5,8 +5,8 @@ ## Table of contents -1. [URL-parameters and URL-hash](#URL-parameters_and_URL-hash) - - [What is a URL parameter?](#what_is_a_url_parameter) +1. [URL-parameters and URL-hash](#url-parameters-and-url-hash) + - [What is a URL parameter?](#what-is-a-url-parameter) - [fs-userbadge](#fs-userbadge) - [fs-search](#fs-search) - [fs-background](#fs-background) @@ -24,10 +24,10 @@ - [test](#test) - [debug](#debug) - [fake-user](#fake-user) - - [overpassUrl](#overpassUrl) - - [overpassTimeout](#overpassTimeout) - - [overpassMaxZoom](#overpassMaxZoom) - - [osmApiTileSize](#osmApiTileSize) + - [overpassUrl](#overpassurl) + - [overpassTimeout](#overpasstimeout) + - [overpassMaxZoom](#overpassmaxzoom) + - [osmApiTileSize](#osmapitilesize) - [background](#background) - [layer-](#layer-) diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts index c27240cf9..802772d9d 100644 --- a/Logic/SimpleMetaTagger.ts +++ b/Logic/SimpleMetaTagger.ts @@ -485,7 +485,6 @@ export default class SimpleMetaTagger { public static HelpText(): BaseUIElement { const subElements: (string | BaseUIElement)[] = [ new Combine([ - new Title("Metatags", 1), "Metatags are extra tags available, in order to display more data or to give better questions.", "The are calculated automatically on every feature when the data arrives in the webbrowser. This document gives an overview of the available metatags.", "**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object" diff --git a/Logic/Web/QueryParameters.ts b/Logic/Web/QueryParameters.ts index 6a34e46bb..9824145c5 100644 --- a/Logic/Web/QueryParameters.ts +++ b/Logic/Web/QueryParameters.ts @@ -4,8 +4,6 @@ import {UIEventSource} from "../UIEventSource"; import Hash from "./Hash"; import {Utils} from "../../Utils"; -import Title from "../../UI/Base/Title"; -import Combine from "../../UI/Base/Combine"; export class QueryParameters { @@ -13,29 +11,11 @@ export class QueryParameters { private static _wasInitialized: Set = new Set() private static knownSources = {}; private static initialized = false; - private static defaults = {} + static defaults = {} + + static documentation = {} + - private static documentation = {} - private static QueryParamDocsIntro = "\n" + - "URL-parameters and URL-hash\n" + - "============================\n" + - "\n" + - "This document gives an overview of which URL-parameters can be used to influence MapComplete.\n" + - "\n" + - "What is a URL parameter?\n" + - "------------------------\n" + - "\n" + - "URL-parameters are extra parts of the URL used to set the state.\n" + - "\n" + - "For example, if the url is `https://mapcomplete.osm.be/cyclofix?lat=51.0&lon=4.3&z=5&test=true#node/1234`,\n" + - "the URL-parameters are stated in the part between the `?` and the `#`. There are multiple, all separated by `&`, namely:\n" + - "\n" + - "- The url-parameter `lat` is `51.0` in this instance\n" + - "- The url-parameter `lon` is `4.3` in this instance\n" + - "- The url-parameter `z` is `5` in this instance\n" + - "- The url-parameter `test` is `true` in this instance\n" + - "\n" + - "Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case." public static GetQueryParameter(key: string, deflt: string, documentation?: string): UIEventSource { if (!this.initialized) { @@ -59,19 +39,7 @@ export class QueryParameters { return QueryParameters.GetQueryParameter(key, deflt, documentation).map(str => str === "true", [], b => "" + b) } - public static GenerateQueryParameterDocs(): string { - const docs = [QueryParameters.QueryParamDocsIntro]; - for (const key in QueryParameters.documentation) { - const c = new Combine([ - new Title(key, 2), - QueryParameters.documentation[key], - QueryParameters.defaults[key] === undefined ? "No default value set" : `The default value is _${QueryParameters.defaults[key]}_` - ]) - docs.push(c.AsMarkdown()) - } - return docs.join("\n\n"); - } public static wasInitialized(key: string): boolean { return QueryParameters._wasInitialized.has(key) @@ -108,9 +76,6 @@ export class QueryParameters { } } - window["mapcomplete_query_parameter_overview"] = () => { - console.log(QueryParameters.GenerateQueryParameterDocs()) - } } private static Serialize() { diff --git a/UI/Base/Combine.ts b/UI/Base/Combine.ts index a9e1a90bb..434644b6a 100644 --- a/UI/Base/Combine.ts +++ b/UI/Base/Combine.ts @@ -47,18 +47,10 @@ export default class Combine extends BaseUIElement { return el; } - public getToC(): Title[]{ - const titles = [] - for (const uiElement of this.uiElements) { - if(uiElement instanceof Combine){ - titles.push(...uiElement.getToC()) - }else if(uiElement instanceof Title){ - titles.push(uiElement) - } - } - return titles - - + public getElements(): BaseUIElement[]{ + return this.uiElements } + + } \ No newline at end of file diff --git a/UI/Base/FixedUiElement.ts b/UI/Base/FixedUiElement.ts index f221ba7ed..14b1860dc 100644 --- a/UI/Base/FixedUiElement.ts +++ b/UI/Base/FixedUiElement.ts @@ -1,25 +1,26 @@ import BaseUIElement from "../BaseUIElement"; export class FixedUiElement extends BaseUIElement { - private _html: string; + public readonly content: string; constructor(html: string) { super(); - this._html = html ?? ""; + this.content = html ?? ""; } InnerRender(): string { - return this._html; + return this.content; } AsMarkdown(): string { - return this._html; + return this.content; } protected InnerConstructElement(): HTMLElement { const e = document.createElement("span") - e.innerHTML = this._html + e.innerHTML = this.content return e; } + } \ No newline at end of file diff --git a/UI/Base/List.ts b/UI/Base/List.ts index 248d21083..b2e4e8f26 100644 --- a/UI/Base/List.ts +++ b/UI/Base/List.ts @@ -10,7 +10,7 @@ export default class List extends BaseUIElement { super(); this._ordered = ordered; this.uiElements = Utils.NoNull(uiElements) - .map(Translations.W); + .map(s => Translations.W(s)); } AsMarkdown(): string { diff --git a/UI/Base/TableOfContents.ts b/UI/Base/TableOfContents.ts new file mode 100644 index 000000000..f49a0076d --- /dev/null +++ b/UI/Base/TableOfContents.ts @@ -0,0 +1,123 @@ +import Combine from "./Combine"; +import BaseUIElement from "../BaseUIElement"; +import {Translation} from "../i18n/Translation"; +import {FixedUiElement} from "./FixedUiElement"; +import Title from "./Title"; +import List from "./List"; +import Hash from "../../Logic/Web/Hash"; +import Link from "./Link"; +import {Utils} from "../../Utils"; + +export default class TableOfContents extends Combine { + +private readonly titles: Title[] + + constructor(elements: Combine | Title[], options?: { + noTopLevel: false | boolean, + maxDepth?: number + }) { + let titles: Title[] + if (elements instanceof Combine) { + titles = TableOfContents.getTitles(elements.getElements()) + } else { + titles = elements + } + + let els: { level: number, content: BaseUIElement }[] = [] + for (const title of titles) { + let content: BaseUIElement + if (title.title instanceof Translation) { + content = title.title.Clone() + }else if(title.title instanceof FixedUiElement){ + content = title.title + }else if(Utils.runningFromConsole){ + content = new FixedUiElement(title.AsMarkdown()) + } else { + content = new FixedUiElement(title.title.ConstructElement().innerText) + } + + const vis = new Link(content, "#" + title.id) + + Hash.hash.addCallbackAndRun(h => { + if (h === title.id) { + vis.SetClass("font-bold") + } else { + vis.RemoveClass("font-bold") + } + }) + els.push({level: title.level, content: vis}) + + } + const minLevel = Math.min(...els.map(e => e.level)) + if (options?.noTopLevel) { + els = els.filter(e => e.level !== minLevel ) + } + + if(options?.maxDepth){ + els = els.filter(e => e.level <= (options.maxDepth + minLevel)) + } + + + super(TableOfContents.mergeLevel(els).map(el => el.SetClass("mt-2"))); + this.SetClass("flex flex-col") + this.titles = titles; + } + + private static getTitles(elements: BaseUIElement[]): Title[]{ + const titles = [] + for (const uiElement of elements){ + if(uiElement instanceof Combine){ + titles.push(...TableOfContents.getTitles(uiElement.getElements())) + }else if(uiElement instanceof Title){ + titles.push(uiElement) + } + } + return titles + } + + private static mergeLevel(elements: { level: number, content: BaseUIElement }[]): BaseUIElement[] { + const maxLevel = Math.max(...elements.map(e => e.level)) + const minLevel = Math.min(...elements.map(e => e.level)) + if (maxLevel === minLevel) { + return elements.map(e => e.content) + } + const result: { level: number, content: BaseUIElement } [] = [] + let running: BaseUIElement[] = [] + for (const element of elements) { + if (element.level === maxLevel) { + running.push(element.content) + continue + } + if (running.length !== undefined) { + result.push({ + content: new List(running), + level: maxLevel - 1 + }) + running = [] + } + result.push(element) + } + if (running.length !== undefined) { + result.push({ + content: new List(running), + level: maxLevel - 1 + }) + } + + return TableOfContents.mergeLevel(result) + } + + AsMarkdown(): string { + const depthIcons = ["1."," -"," +"," *"] + const lines = ["## Table of contents\n"]; + const minLevel = Math.min(...this.titles.map(t => t.level)) + for (const title of this.titles) { + const prefix = depthIcons[title.level - minLevel] ?? " ~" + const text = title.title.AsMarkdown().replace("\n","") + const link = title.id + lines.push(prefix + " ["+text+"](#"+link+")") + } + + return lines.join("\n")+"\n\n" + } +} \ No newline at end of file diff --git a/UI/Base/Title.ts b/UI/Base/Title.ts index f69764053..e926bd746 100644 --- a/UI/Base/Title.ts +++ b/UI/Base/Title.ts @@ -1,6 +1,5 @@ import BaseUIElement from "../BaseUIElement"; import {FixedUiElement} from "./FixedUiElement"; -import Hash from "../../Logic/Web/Hash"; export default class Title extends BaseUIElement { public readonly title: BaseUIElement; @@ -17,7 +16,19 @@ export default class Title extends BaseUIElement { this.title = embedded } this.level = level; - this.id = this.title.ConstructElement()?.innerText?.replace(/ /g, '_') ?? "" + + let innerText : string = undefined; + if(typeof embedded === "string" ) { + innerText = embedded + }else if(embedded instanceof FixedUiElement){ + innerText = embedded.content + }else{ + this.title.ConstructElement()?.innerText + } + + this.id = innerText?.replace(/ /g, '-') + ?.replace(/[?#.;:/]/, "") + ?.toLowerCase() ?? "" this.SetClass(Title.defaultClassesPerLevel[level] ?? "") } diff --git a/UI/Input/ValidatedTextField.ts b/UI/Input/ValidatedTextField.ts index 181cd5ea6..24f843567 100644 --- a/UI/Input/ValidatedTextField.ts +++ b/UI/Input/ValidatedTextField.ts @@ -553,13 +553,15 @@ export default class ValidatedTextField { return input; } - public static HelpText(): string { - const explanations = ValidatedTextField.tpList.map(type => ["## " + type.name, "", type.explanation].join("\n")).join("\n\n") + public static HelpText(): BaseUIElement { + const explanations : BaseUIElement[]= + ValidatedTextField.tpList.map(type => + new Combine([new Title(type.name,3), type.explanation]).SetClass("flex flex-col")) return new Combine([ new Title("Available types for text fields", 1), "The listed types here trigger a special input element. Use them in `tagrendering.freeform.type` of your tagrendering to activate them", - explanations - ]).SetClass("flex flex-col").AsMarkdown() + ...explanations + ]).SetClass("flex flex-col") } private static tp(name: string, diff --git a/UI/ProfessionalGui.ts b/UI/ProfessionalGui.ts index 4b972f446..4e305c524 100644 --- a/UI/ProfessionalGui.ts +++ b/UI/ProfessionalGui.ts @@ -5,97 +5,10 @@ import Title from "./Base/Title"; import Toggleable, {Accordeon} from "./Base/Toggleable"; import List from "./Base/List"; import BaseUIElement from "./BaseUIElement"; -import Link from "./Base/Link"; import LanguagePicker from "./LanguagePicker"; -import Hash from "../Logic/Web/Hash"; -import {Translation} from "./i18n/Translation"; import {SubtleButton} from "./Base/SubtleButton"; import Svg from "../Svg"; - -class TableOfContents extends Combine { - - private readonly titles: Title[] - - constructor(elements: Combine | Title[], options: { - noTopLevel: false | boolean, - maxDepth?: number - }) { - let titles: Title[] - if (elements instanceof Combine) { - titles = elements.getToC() - } else { - titles = elements - } - - let els: { level: number, content: BaseUIElement }[] = [] - for (const title of titles) { - let content: BaseUIElement - if (title.title instanceof Translation) { - content = title.title.Clone() - } else { - content = new FixedUiElement(title.title.ConstructElement().innerText) - } - - const vis = new Link(content, "#" + title.id) - - Hash.hash.addCallbackAndRun(h => { - if (h === title.id) { - vis.SetClass("font-bold") - } else { - vis.RemoveClass("font-bold") - } - }) - els.push({level: title.level, content: vis}) - - } - if (options.noTopLevel) { - const minLevel = Math.min(...els.map(e => e.level)) - els = els.filter(e => e.level !== minLevel && e.level <= (options.maxDepth + minLevel)) - } - - - super(TableOfContents.mergeLevel(els).map(el => el.SetClass("mt-2"))); - this.SetClass("flex flex-col") - this.titles = titles; - } - - private static mergeLevel(elements: { level: number, content: BaseUIElement }[]): BaseUIElement[] { - const maxLevel = Math.max(...elements.map(e => e.level)) - const minLevel = Math.min(...elements.map(e => e.level)) - if (maxLevel === minLevel) { - return elements.map(e => e.content) - } - const result: { level: number, content: BaseUIElement } [] = [] - let running: BaseUIElement[] = [] - for (const element of elements) { - if (element.level === maxLevel) { - running.push(element.content) - continue - } - if (running.length !== undefined) { - result.push({ - content: new List(running), - level: maxLevel - 1 - }) - running = [] - } - result.push(element) - } - if (running.length !== undefined) { - result.push({ - content: new List(running), - level: maxLevel - 1 - }) - } - - return TableOfContents.mergeLevel(result) - - } - - AsMarkdown(): string { - return super.AsMarkdown(); - } -} +import TableOfContents from "./Base/TableOfContents"; class Snippet extends Toggleable { constructor(translations, ...extraContent: BaseUIElement[]) { diff --git a/UI/QueryParameterDocumentation.ts b/UI/QueryParameterDocumentation.ts new file mode 100644 index 000000000..684fcb32b --- /dev/null +++ b/UI/QueryParameterDocumentation.ts @@ -0,0 +1,40 @@ +import BaseUIElement from "./BaseUIElement"; +import Combine from "./Base/Combine"; +import Title from "./Base/Title"; +import List from "./Base/List"; +import Translations from "./i18n/Translations"; +import {QueryParameters} from "../Logic/Web/QueryParameters"; + +export default class QueryParameterDocumentation { + + private static QueryParamDocsIntro = ([ + new Title("URL-parameters and URL-hash", 1), + "This document gives an overview of which URL-parameters can be used to influence MapComplete.", + new Title("What is a URL parameter?", 2), + "\"URL-parameters are extra parts of the URL used to set the state.", + "For example, if the url is `https://mapcomplete.osm.be/cyclofix?lat=51.0&lon=4.3&z=5&test=true#node/1234`, " + + "the URL-parameters are stated in the part between the `?` and the `#`. There are multiple, all separated by `&`, namely: ", + new List([ + "The url-parameter `lat` is `51.0` in this instance", + "The url-parameter `lon` is `4.3` in this instance", + "The url-parameter `z` is `5` in this instance", + "The url-parameter `test` is `true` in this instance" + ].map(s => Translations.W(s)) + ), + "Finally, the URL-hash is the part after the `#`. It is `node/1234` in this case." + ]) + + public static GenerateQueryParameterDocs(): BaseUIElement { + const docs : (string | BaseUIElement)[] = [...QueryParameterDocumentation.QueryParamDocsIntro]; + for (const key in QueryParameters.documentation) { + const c = new Combine([ + new Title(key, 2), + QueryParameters.documentation[key], + QueryParameters.defaults[key] === undefined ? "No default value set" : `The default value is _${QueryParameters.defaults[key]}_` + + ]) + docs.push(c) + } + return new Combine(docs).SetClass("flex flex-col") + } +} \ No newline at end of file diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index bcce130a1..7839803f9 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -698,16 +698,10 @@ export default class SpecialVisualizations { ] )); - - const toc = new List( - SpecialVisualizations.specialVisualizations.map(viz => new Link(viz.funcName, "#" + viz.funcName)) - ) - return new Combine([ - new Title("Special tag renderings", 3), + new Title("Special tag renderings", 1), "In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's.", "General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_name(args):cssStyle}`. Note that you _do not_ need to use quotes around your arguments, the comma is enough to separate them. This also implies you cannot use a comma in your args", - toc, ...helpTexts ] ).SetClass("flex flex-col"); diff --git a/index.ts b/index.ts index 0d0802b5b..5fd9804e2 100644 --- a/index.ts +++ b/index.ts @@ -15,8 +15,6 @@ import AvailableBaseLayersImplementation from "./Logic/Actors/AvailableBaseLayer import ShowOverlayLayerImplementation from "./UI/ShowDataLayer/ShowOverlayLayerImplementation"; import {DefaultGuiState} from "./UI/DefaultGuiState"; import {Browser} from "leaflet"; -import win = Browser.win; -import ProfessionalGui from "./UI/ProfessionalGui"; // Workaround for a stupid crash: inject some functions which would give stupid circular dependencies or crash the other nodejs scripts running from console MinimapImplementation.initialize() diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index 7061896be..fa79ed9d7 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -11,20 +11,35 @@ import {QueryParameters} from "../Logic/Web/QueryParameters"; import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"; import Minimap from "../UI/Base/Minimap"; import FeatureSwitchState from "../Logic/State/FeatureSwitchState"; -import AllKnownLayers from "../Customizations/AllKnownLayers"; import {AllKnownLayouts} from "../Customizations/AllKnownLayouts"; +import TableOfContents from "../UI/Base/TableOfContents"; +import Title from "../UI/Base/Title"; +import QueryParameterDocumentation from "../UI/QueryParameterDocumentation"; Utils.runningFromConsole = true; -function WriteFile(filename, html: string | BaseUIElement, autogenSource: string[]): void { +function WriteFile(filename, html: BaseUIElement, autogenSource: string[]): void { + + if (html instanceof Combine) { + + const toc = new TableOfContents(html); + const els = html.getElements(); + html = new Combine( + [els.shift(), + toc, + ...els + ] + ) + } + writeFileSync(filename, new Combine([Translations.W(html), "\n\nThis document is autogenerated from " + autogenSource.join(", ") ]).AsMarkdown()); } WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage(), ["UI/SpecialVisualisations.ts"]) -WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"), +WriteFile("./Docs/CalculatedTags.md", new Combine([new Title("Metatags", 1), SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"), ["SimpleMetaTagger", "ExtraFunction"]) WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(), ["ValidatedTextField.ts"]); WriteFile("./Docs/BuiltinLayers.md", AllKnownLayouts.GenLayerOverviewText(), ["AllKnownLayers.ts"]) @@ -52,7 +67,7 @@ const dummyLayout = new LayoutConfig({ source: { osmTags: "id~*" }, - mapRendering: [] + mapRendering: null, } ] @@ -62,7 +77,7 @@ new FeatureSwitchState(dummyLayout) QueryParameters.GetQueryParameter("layer-", "true", "Wether or not the layer with id is shown") -WriteFile("./Docs/URL_Parameters.md", QueryParameters.GenerateQueryParameterDocs(), ["QueryParameters"]) +WriteFile("./Docs/URL_Parameters.md", QueryParameterDocumentation.GenerateQueryParameterDocs(), ["QueryParameters"]) console.log("Generated docs")