Merge master
|
@ -533,10 +533,10 @@ function stackHists<K, V>(hists: [V, Histogram<K>][]): [V, Histogram<K>][] {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function createGraphs(allFeatures: ChangeSetData[], appliedFilterDescription: string) {
|
function createGraphs(allFeatures: ChangeSetData[], appliedFilterDescription: string, cutoff = undefined) {
|
||||||
const hist = new Histogram<string>(allFeatures.map(f => f.properties.metadata.theme))
|
const hist = new Histogram<string>(allFeatures.map(f => f.properties.metadata.theme))
|
||||||
hist
|
hist
|
||||||
.createOthersCategory("other", 20)
|
.createOthersCategory("other", cutoff ?? 20)
|
||||||
.addCountToName()
|
.addCountToName()
|
||||||
.asBar({name: "Changesets per theme (bar)" + appliedFilterDescription})
|
.asBar({name: "Changesets per theme (bar)" + appliedFilterDescription})
|
||||||
.render()
|
.render()
|
||||||
|
@ -545,7 +545,7 @@ function createGraphs(allFeatures: ChangeSetData[], appliedFilterDescription: st
|
||||||
new Histogram<string>(allFeatures.map(f => f.properties.user))
|
new Histogram<string>(allFeatures.map(f => f.properties.user))
|
||||||
.binPerCount()
|
.binPerCount()
|
||||||
.stringifyName()
|
.stringifyName()
|
||||||
.createOthersCategory("25 or more", (key, _) => Number(key) >= 25).asBar(
|
.createOthersCategory("25 or more", (key, _) => Number(key) >=(cutoff ?? 25)).asBar(
|
||||||
{
|
{
|
||||||
compare: (a, b) => Number(a) - Number(b),
|
compare: (a, b) => Number(a) - Number(b),
|
||||||
name: "Contributors per changeset count" + appliedFilterDescription
|
name: "Contributors per changeset count" + appliedFilterDescription
|
||||||
|
@ -598,7 +598,7 @@ function createGraphs(allFeatures: ChangeSetData[], appliedFilterDescription: st
|
||||||
}).render()
|
}).render()
|
||||||
|
|
||||||
new Histogram<string>(allFeatures.map(f => f.properties.metadata.theme))
|
new Histogram<string>(allFeatures.map(f => f.properties.metadata.theme))
|
||||||
.createOthersCategory("< 25 changesets", 25)
|
.createOthersCategory("< 25 changesets", (cutoff ?? 25))
|
||||||
.addCountToName()
|
.addCountToName()
|
||||||
.asPie({
|
.asPie({
|
||||||
name: "Changesets per theme (pie)" + appliedFilterDescription
|
name: "Changesets per theme (pie)" + appliedFilterDescription
|
||||||
|
@ -608,14 +608,14 @@ function createGraphs(allFeatures: ChangeSetData[], appliedFilterDescription: st
|
||||||
"Changesets per theme" + appliedFilterDescription,
|
"Changesets per theme" + appliedFilterDescription,
|
||||||
allFeatures,
|
allFeatures,
|
||||||
f => f.properties.metadata.theme,
|
f => f.properties.metadata.theme,
|
||||||
25
|
cutoff ?? 25
|
||||||
)
|
)
|
||||||
|
|
||||||
Group.createStackedBarChartPerDay(
|
Group.createStackedBarChartPerDay(
|
||||||
"Changesets per version number" + appliedFilterDescription,
|
"Changesets per version number" + appliedFilterDescription,
|
||||||
allFeatures,
|
allFeatures,
|
||||||
f => f.properties.editor.substr("MapComplete ".length, 6).replace(/[a-zA-Z-/]/g, ''),
|
f => f.properties.editor.substr("MapComplete ".length, 6).replace(/[a-zA-Z-/]/g, ''),
|
||||||
1
|
cutoff ?? 1
|
||||||
)
|
)
|
||||||
|
|
||||||
Group.createStackedBarChartPerDay(
|
Group.createStackedBarChartPerDay(
|
||||||
|
@ -627,14 +627,14 @@ function createGraphs(allFeatures: ChangeSetData[], appliedFilterDescription: st
|
||||||
return major+"."+minor
|
return major+"."+minor
|
||||||
|
|
||||||
},
|
},
|
||||||
1
|
cutoff ??1
|
||||||
)
|
)
|
||||||
|
|
||||||
Group.createStackedBarChartPerDay(
|
Group.createStackedBarChartPerDay(
|
||||||
"Deletion-changesets per theme" + appliedFilterDescription,
|
"Deletion-changesets per theme" + appliedFilterDescription,
|
||||||
allFeatures.filter(f => f.properties.delete > 0),
|
allFeatures.filter(f => f.properties.delete > 0),
|
||||||
f => f.properties.metadata.theme,
|
f => f.properties.metadata.theme,
|
||||||
1
|
cutoff ?? 1
|
||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -715,7 +715,8 @@ async function main(): Promise<void>{
|
||||||
createGraphs(allFeatures, "")
|
createGraphs(allFeatures, "")
|
||||||
// createGraphs(allFeatures.filter(f => f.properties.date.startsWith("2020")), " in 2020")
|
// createGraphs(allFeatures.filter(f => f.properties.date.startsWith("2020")), " in 2020")
|
||||||
// createGraphs(allFeatures.filter(f => f.properties.date.startsWith("2021")), " in 2021")
|
// createGraphs(allFeatures.filter(f => f.properties.date.startsWith("2021")), " in 2021")
|
||||||
createGraphs(allFeatures.filter(f => f.properties.date.startsWith("2022")), " in 2022")
|
createGraphs(allFeatures.filter(f => f.properties.date.startsWith("2022")), " in 2022"),
|
||||||
|
createGraphs(allFeatures.filter(f => f.properties.metadata.theme==="toerisme_vlaanderen"), " met pin je punt", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
main().then(_ => console.log("All done!"))
|
main().then(_ => console.log("All done!"))
|
||||||
|
|
Before Width: | Height: | Size: 500 KiB After Width: | Height: | Size: 562 KiB |
BIN
Docs/Tools/graphs/Changesets per day (line) met pin je punt.png
Normal file
After Width: | Height: | Size: 298 KiB |
Before Width: | Height: | Size: 370 KiB After Width: | Height: | Size: 368 KiB |
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 578 KiB |
BIN
Docs/Tools/graphs/Changesets per host met pin je punt.png
Normal file
After Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 213 KiB After Width: | Height: | Size: 330 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 181 KiB |
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 280 KiB |
Before Width: | Height: | Size: 646 KiB After Width: | Height: | Size: 652 KiB |
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 332 KiB |
Before Width: | Height: | Size: 887 KiB After Width: | Height: | Size: 890 KiB |
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 213 KiB |
BIN
Docs/Tools/graphs/Changesets per theme met pin je punt.png
Normal file
After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 580 KiB After Width: | Height: | Size: 582 KiB |
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 208 KiB |
After Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 671 KiB After Width: | Height: | Size: 687 KiB |
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 125 KiB |
BIN
Docs/Tools/graphs/Contributors per day met pin je punt.png
Normal file
After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 227 KiB |
After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 262 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 98 KiB |
13168
Docs/Tools/stats/stats.2022-3.json
Normal file
|
@ -2,7 +2,7 @@ import {Utils} from "../Utils";
|
||||||
|
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
|
|
||||||
public static vNumber = "0.17.0-alpha";
|
public static vNumber = "0.17.0-alpha-1";
|
||||||
|
|
||||||
public static ImgurApiKey = '7070e7167f0a25a'
|
public static ImgurApiKey = '7070e7167f0a25a'
|
||||||
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
||||||
|
|
|
@ -46,15 +46,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
||||||
if(firstRender === undefined){
|
if(firstRender === undefined){
|
||||||
throw `Layer ${layerJson.id} does not have a pointRendering: `+context
|
throw `Layer ${layerJson.id} does not have a pointRendering: `+context
|
||||||
}
|
}
|
||||||
const icon = firstRender.icon
|
|
||||||
const iconBadges = []
|
|
||||||
const title = layer.presets[0].title
|
const title = layer.presets[0].title
|
||||||
if (icon !== undefined) {
|
|
||||||
iconBadges.push({
|
|
||||||
if: {and: []},
|
|
||||||
then: icon
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const importButton = {}
|
const importButton = {}
|
||||||
{
|
{
|
||||||
|
@ -123,7 +115,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
{
|
{
|
||||||
"id": "Intro",
|
"id": "Intro",
|
||||||
"render": "{_intro}"
|
render: "{_intro}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "conversation",
|
"id": "conversation",
|
||||||
|
@ -138,12 +130,12 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
||||||
{
|
{
|
||||||
"id": "close_note_",
|
"id": "close_note_",
|
||||||
"render": embed(
|
"render": embed(
|
||||||
"{close_note(", t.notFound.Subs({title}), ", ./assets/svg/close.svg, id, This feature does not exist)}"),
|
"{close_note(", t.notFound.Subs({title}), ", ./assets/svg/close.svg, id, This feature does not exist, 18)}"),
|
||||||
condition: "closed_at="
|
condition: "closed_at="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "close_note_mapped",
|
"id": "close_note_mapped",
|
||||||
"render": embed("{close_note(", t.alreadyMapped.Subs({title}), ", ./assets/svg/checkmark.svg, id, Already mapped)}"),
|
"render": embed("{close_note(", t.alreadyMapped.Subs({title}), ", ./assets/svg/duplicate.svg, id, Already mapped, 18)}"),
|
||||||
condition: "closed_at="
|
condition: "closed_at="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -172,7 +164,6 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
||||||
then: "circle:white;checkmark:black"
|
then: "circle:white;checkmark:black"
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
iconBadges,
|
|
||||||
"iconSize": "40,40,center"
|
"iconSize": "40,40,center"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,46 +2,48 @@ import {UIElement} from "../UIElement";
|
||||||
import BaseUIElement from "../BaseUIElement";
|
import BaseUIElement from "../BaseUIElement";
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
import ExtraLinkConfig from "../../Models/ThemeConfig/ExtraLinkConfig";
|
import ExtraLinkConfig from "../../Models/ThemeConfig/ExtraLinkConfig";
|
||||||
import MapControlButton from "../MapControlButton";
|
|
||||||
import Link from "../Base/Link";
|
|
||||||
import Img from "../Base/Img";
|
import Img from "../Base/Img";
|
||||||
import {SubtleButton} from "../Base/SubtleButton";
|
import {SubtleButton} from "../Base/SubtleButton";
|
||||||
import Toggle from "../Input/Toggle";
|
import Toggle from "../Input/Toggle";
|
||||||
import Loc from "../../Models/Loc";
|
import Loc from "../../Models/Loc";
|
||||||
import Locale from "../i18n/Locale";
|
import Locale from "../i18n/Locale";
|
||||||
import {Utils} from "../../Utils";
|
import {Utils} from "../../Utils";
|
||||||
|
import Svg from "../../Svg";
|
||||||
|
import Translations from "../i18n/Translations";
|
||||||
|
import {Translation} from "../i18n/Translation";
|
||||||
|
|
||||||
export default class ExtraLinkButton extends UIElement{
|
export default class ExtraLinkButton extends UIElement {
|
||||||
private readonly _config: ExtraLinkConfig;
|
private readonly _config: ExtraLinkConfig;
|
||||||
private readonly state: {
|
private readonly state: {
|
||||||
layoutToUse: {id: string};
|
layoutToUse: { id: string, title: Translation };
|
||||||
featureSwitchWelcomeMessage: UIEventSource<boolean>, locationControl: UIEventSource<Loc>};
|
featureSwitchWelcomeMessage: UIEventSource<boolean>, locationControl: UIEventSource<Loc>
|
||||||
|
};
|
||||||
|
|
||||||
constructor(state: {featureSwitchWelcomeMessage: UIEventSource<boolean>, locationControl: UIEventSource<Loc>, layoutToUse: {id: string}},
|
constructor(state: { featureSwitchWelcomeMessage: UIEventSource<boolean>, locationControl: UIEventSource<Loc>, layoutToUse: { id: string, title: Translation } },
|
||||||
config: ExtraLinkConfig) {
|
config: ExtraLinkConfig) {
|
||||||
super();
|
super();
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this._config = config;
|
this._config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerRender(): BaseUIElement {
|
protected InnerRender(): BaseUIElement {
|
||||||
if(this._config === undefined){
|
if (this._config === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const c = this._config;
|
const c = this._config;
|
||||||
|
|
||||||
const isIframe = window !== window.top
|
const isIframe = window !== window.top
|
||||||
|
|
||||||
if(c.requirements.has("iframe") && !isIframe){
|
if (c.requirements.has("iframe") && !isIframe) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.requirements.has("no-iframe") && isIframe){
|
if (c.requirements.has("no-iframe") && isIframe) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
let link : BaseUIElement
|
let link: BaseUIElement
|
||||||
const theme = this.state.layoutToUse?.id ?? ""
|
const theme = this.state.layoutToUse?.id ?? ""
|
||||||
const href = this.state.locationControl.map(loc => {
|
const href = this.state.locationControl.map(loc => {
|
||||||
const subs = {
|
const subs = {
|
||||||
|
@ -51,31 +53,35 @@ export default class ExtraLinkButton extends UIElement{
|
||||||
}
|
}
|
||||||
return Utils.SubstituteKeys(c.href, subs)
|
return Utils.SubstituteKeys(c.href, subs)
|
||||||
})
|
})
|
||||||
|
|
||||||
if(c.text === undefined){
|
|
||||||
link = new MapControlButton(
|
let img: BaseUIElement = Svg.pop_out_ui()
|
||||||
new Link(new Img(c.icon), href, c.newTab).SetClass("block w-full h-full p-1.5")
|
if (c.icon !== undefined) {
|
||||||
)
|
img = new Img(c.icon).SetClass("h-6")
|
||||||
}else {
|
|
||||||
let img : BaseUIElement = undefined
|
|
||||||
if(c.icon !== undefined){
|
|
||||||
img = new Img(c.icon).SetClass("h-6")
|
|
||||||
}
|
|
||||||
|
|
||||||
link = new SubtleButton(img,c.text, {url:
|
|
||||||
href,
|
|
||||||
newTab: c.newTab})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.requirements.has("no-welcome-message")){
|
let text: Translation
|
||||||
|
if (c.text === undefined) {
|
||||||
|
text = Translations.t.general.screenToSmall.Fuse(this.state.layoutToUse.title, "{theme}")
|
||||||
|
} else {
|
||||||
|
text = c.text.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
link = new SubtleButton(img, text, {
|
||||||
|
url:
|
||||||
|
href,
|
||||||
|
newTab: c.newTab
|
||||||
|
})
|
||||||
|
|
||||||
|
if (c.requirements.has("no-welcome-message")) {
|
||||||
link = new Toggle(undefined, link, this.state.featureSwitchWelcomeMessage)
|
link = new Toggle(undefined, link, this.state.featureSwitchWelcomeMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.requirements.has("welcome-message")){
|
if (c.requirements.has("welcome-message")) {
|
||||||
link = new Toggle(link, undefined, this.state.featureSwitchWelcomeMessage)
|
link = new Toggle(link, undefined, this.state.featureSwitchWelcomeMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -168,6 +168,11 @@ export default class DefaultGUI {
|
||||||
]).SetClass("flex flex-col")
|
]).SetClass("flex flex-col")
|
||||||
.AttachTo("userbadge")
|
.AttachTo("userbadge")
|
||||||
|
|
||||||
|
new Combine([
|
||||||
|
new ExtraLinkButton(state, {...state.layoutToUse.extraLink, newTab: true, requirements: new Set<"iframe" | "no-iframe" | "welcome-message" | "no-welcome-message">( ) })
|
||||||
|
]).SetClass("flex items-center justify-center normal-background h-full")
|
||||||
|
.AttachTo("on-small-screen")
|
||||||
|
|
||||||
Toggle.If(state.featureSwitchSearch,
|
Toggle.If(state.featureSwitchSearch,
|
||||||
() => new SearchAndGo(state))
|
() => new SearchAndGo(state))
|
||||||
.AttachTo("searchbox");
|
.AttachTo("searchbox");
|
||||||
|
|
|
@ -191,7 +191,7 @@ ${Utils.special_visualizations_importRequirementDocs}
|
||||||
importFlow,
|
importFlow,
|
||||||
isImported
|
isImported
|
||||||
),
|
),
|
||||||
t.zoomInMore,
|
t.zoomInMore.SetClass("alert"),
|
||||||
state.locationControl.map(l => l.zoom >= 18)
|
state.locationControl.map(l => l.zoom >= 18)
|
||||||
),
|
),
|
||||||
pleaseLoginButton,
|
pleaseLoginButton,
|
||||||
|
|
|
@ -71,7 +71,7 @@ export default class NewNoteUi extends Toggle {
|
||||||
new Combine([new Toggle(undefined, t.warnAnonymous.SetClass("alert"), state?.osmConnection?.isLoggedIn),
|
new Combine([new Toggle(undefined, t.warnAnonymous.SetClass("alert"), state?.osmConnection?.isLoggedIn),
|
||||||
new Toggle(postNote,
|
new Toggle(postNote,
|
||||||
t.textNeeded.SetClass("alert"),
|
t.textNeeded.SetClass("alert"),
|
||||||
text.GetValue().map(txt => txt.length > 3)
|
text.GetValue().map(txt => txt?.length > 3)
|
||||||
)
|
)
|
||||||
|
|
||||||
]).SetClass("flex justify-end items-center")
|
]).SetClass("flex justify-end items-center")
|
||||||
|
|
|
@ -46,6 +46,7 @@ import FileSelectorButton from "./Input/FileSelectorButton";
|
||||||
import {LoginToggle} from "./Popup/LoginButton";
|
import {LoginToggle} from "./Popup/LoginButton";
|
||||||
import {start} from "repl";
|
import {start} from "repl";
|
||||||
import {SubstitutedTranslation} from "./SubstitutedTranslation";
|
import {SubstitutedTranslation} from "./SubstitutedTranslation";
|
||||||
|
import {Feature} from "@turf/turf";
|
||||||
|
|
||||||
export interface SpecialVisualization {
|
export interface SpecialVisualization {
|
||||||
funcName: string,
|
funcName: string,
|
||||||
|
@ -95,6 +96,88 @@ export class AllTagsPanel extends VariableUiElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CloseNoteButton implements SpecialVisualization {
|
||||||
|
public readonly funcName = "close_note"
|
||||||
|
public readonly docs = "Button to close a note. A predifined text can be defined to close the note with. If the note is already closed, will show a small text."
|
||||||
|
public readonly args = [
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
doc: "Text to show on this button",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "icon",
|
||||||
|
doc: "Icon to show",
|
||||||
|
defaultValue: "checkmark.svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "idkey",
|
||||||
|
doc: "The property name where the ID of the note to close can be found",
|
||||||
|
defaultValue: "id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "comment",
|
||||||
|
doc: "Text to add onto the note when closing",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "minZoom",
|
||||||
|
doc: "If set, only show the closenote button if zoomed in enough"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "zoomButton",
|
||||||
|
doc: "Text to show if not zoomed in enough"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
public constr(state: FeaturePipelineState, tags, args): BaseUIElement {
|
||||||
|
const t = Translations.t.notes;
|
||||||
|
|
||||||
|
const params: {
|
||||||
|
text: string,
|
||||||
|
icon: string,
|
||||||
|
idkey: string,
|
||||||
|
comment: string,
|
||||||
|
minZoom: string,
|
||||||
|
zoomButton: string
|
||||||
|
} = Utils.ParseVisArgs(this.args, args)
|
||||||
|
|
||||||
|
let icon = Svg.checkmark_svg()
|
||||||
|
if (params.icon !== "checkmark.svg" && (args[2] ?? "") !== "") {
|
||||||
|
icon = new Img(args[1])
|
||||||
|
}
|
||||||
|
let textToShow = t.closeNote;
|
||||||
|
if ((params.text ?? "") !== "") {
|
||||||
|
textToShow = Translations.T(args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
let closeButton: BaseUIElement = new SubtleButton(icon, textToShow)
|
||||||
|
const isClosed = tags.map(tags => (tags["closed_at"] ?? "") !== "");
|
||||||
|
closeButton.onClick(() => {
|
||||||
|
const id = tags.data[args[2] ?? "id"]
|
||||||
|
state.osmConnection.closeNote(id, args[3])
|
||||||
|
?.then(_ => {
|
||||||
|
tags.data["closed_at"] = new Date().toISOString();
|
||||||
|
tags.ping()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if((params.minZoom??"") !== "" && !isNaN(Number(params.minZoom))){
|
||||||
|
closeButton = new Toggle(
|
||||||
|
closeButton,
|
||||||
|
params.zoomButton ?? "",
|
||||||
|
state. locationControl.map(l => l.zoom >= Number(params.minZoom))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LoginToggle(new Toggle(
|
||||||
|
t.isClosed.SetClass("thanks"),
|
||||||
|
closeButton,
|
||||||
|
|
||||||
|
isClosed
|
||||||
|
), t.loginToClose, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export default class SpecialVisualizations {
|
export default class SpecialVisualizations {
|
||||||
|
|
||||||
public static specialVisualizations = SpecialVisualizations.init()
|
public static specialVisualizations = SpecialVisualizations.init()
|
||||||
|
@ -655,58 +738,7 @@ export default class SpecialVisualizations {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
new CloseNoteButton(),
|
||||||
funcName: "close_note",
|
|
||||||
docs: "Button to close a note. A predifined text can be defined to close the note with. If the note is already closed, will show a small text.",
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
name: "text",
|
|
||||||
doc: "Text to show on this button",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "icon",
|
|
||||||
doc: "Icon to show",
|
|
||||||
defaultValue: "checkmark.svg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Id-key",
|
|
||||||
doc: "The property name where the ID of the note to close can be found",
|
|
||||||
defaultValue: "id"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "comment",
|
|
||||||
doc: "Text to add onto the note when closing",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
constr: (state, tags, args) => {
|
|
||||||
const t = Translations.t.notes;
|
|
||||||
|
|
||||||
let icon = Svg.checkmark_svg()
|
|
||||||
if (args[1] !== "checkmark.svg" && (args[2] ?? "") !== "") {
|
|
||||||
icon = new Img(args[1])
|
|
||||||
}
|
|
||||||
let textToShow = t.closeNote;
|
|
||||||
if ((args[0] ?? "") !== "") {
|
|
||||||
textToShow = Translations.T(args[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeButton = new SubtleButton(icon, textToShow)
|
|
||||||
const isClosed = tags.map(tags => (tags["closed_at"] ?? "") !== "");
|
|
||||||
closeButton.onClick(() => {
|
|
||||||
const id = tags.data[args[2] ?? "id"]
|
|
||||||
state.osmConnection.closeNote(id, args[3])
|
|
||||||
?.then(_ => {
|
|
||||||
tags.data["closed_at"] = new Date().toISOString();
|
|
||||||
tags.ping()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return new LoginToggle(new Toggle(
|
|
||||||
t.isClosed.SetClass("thanks"),
|
|
||||||
closeButton,
|
|
||||||
isClosed
|
|
||||||
), t.loginToClose, state)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
funcName: "add_note_comment",
|
funcName: "add_note_comment",
|
||||||
docs: "A textfield to add a comment to a node (with the option to close the note).",
|
docs: "A textfield to add a comment to a node (with the option to close the note).",
|
||||||
|
@ -778,7 +810,7 @@ export default class SpecialVisualizations {
|
||||||
new Title("Add a comment"),
|
new Title("Add a comment"),
|
||||||
textField,
|
textField,
|
||||||
new Combine([
|
new Combine([
|
||||||
new Toggle(addCommentButton, undefined, textField.GetValue().map(t => t !==undefined && t.length > 1)).SetClass("mr-2")
|
new Toggle(addCommentButton, undefined, textField.GetValue().map(t => t !== undefined && t.length > 1)).SetClass("mr-2")
|
||||||
, stateButtons]).SetClass("flex justify-end")
|
, stateButtons]).SetClass("flex justify-end")
|
||||||
]).SetClass("border-2 border-black rounded-xl p-4 block"),
|
]).SetClass("border-2 border-black rounded-xl p-4 block"),
|
||||||
t.loginToAddComment, state)
|
t.loginToAddComment, state)
|
||||||
|
@ -860,15 +892,15 @@ export default class SpecialVisualizations {
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
funcName:"title",
|
funcName: "title",
|
||||||
args: [],
|
args: [],
|
||||||
docs:"Shows the title of the popup. Useful for some cases, e.g. 'What is phone number of {title()}?'",
|
docs: "Shows the title of the popup. Useful for some cases, e.g. 'What is phone number of {title()}?'",
|
||||||
example:"`What is the phone number of {title()}`, which might automatically become `What is the phone number of XYZ`.",
|
example: "`What is the phone number of {title()}`, which might automatically become `What is the phone number of XYZ`.",
|
||||||
constr: (state, tagsSource, args, guistate) =>
|
constr: (state, tagsSource, args, guistate) =>
|
||||||
new VariableUiElement(tagsSource.map(tags => {
|
new VariableUiElement(tagsSource.map(tags => {
|
||||||
const layer = state.layoutToUse.getMatchingLayer(tags)
|
const layer = state.layoutToUse.getMatchingLayer(tags)
|
||||||
const title = layer?.title?.GetRenderValue(tags)
|
const title = layer?.title?.GetRenderValue(tags)
|
||||||
if(title === undefined){
|
if (title === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return new SubstitutedTranslation(title, tagsSource, state)
|
return new SubstitutedTranslation(title, tagsSource, state)
|
||||||
|
|
|
@ -171,6 +171,13 @@
|
||||||
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "access=key",
|
||||||
|
"then": {
|
||||||
|
"en": "A <b>key</b> must be requested to access this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station</span>",
|
||||||
|
"nl": "Een <b>sleutel</b> is nodig om dit oplaadpunt te gebruiken<br/><span class='subtle'>Bv. voor klanten van een hotel of een bar, die de sleutel aan de receptie kunnen krijgen</span>"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "access=private",
|
"if": "access=private",
|
||||||
"then": {
|
"then": {
|
||||||
|
|
|
@ -162,6 +162,13 @@
|
||||||
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
"nl": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "access=key",
|
||||||
|
"then": {
|
||||||
|
"en": "A <b>key</b> must be requested to access this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station</span>",
|
||||||
|
"nl": "Een <b>sleutel</b> is nodig om dit oplaadpunt te gebruiken<br/><span class='subtle'>Bv. voor klanten van een hotel of een bar, die de sleutel aan de receptie kunnen krijgen</span>"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "access=private",
|
"if": "access=private",
|
||||||
"then": {
|
"then": {
|
||||||
|
|
8868
assets/svg/duplicate.svg
Normal file
After Width: | Height: | Size: 273 KiB |
|
@ -381,6 +381,14 @@
|
||||||
"https://commons.wikimedia.org/wiki/File:Download-icon.svg"
|
"https://commons.wikimedia.org/wiki/File:Download-icon.svg"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "duplicate.svg",
|
||||||
|
"license": "CC0",
|
||||||
|
"authors": [
|
||||||
|
"Pieter Vander Vennet"
|
||||||
|
],
|
||||||
|
"sources": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "envelope.svg",
|
"path": "envelope.svg",
|
||||||
"license": "CC0; trivial",
|
"license": "CC0; trivial",
|
||||||
|
|
|
@ -1103,10 +1103,6 @@ video {
|
||||||
max-height: 2rem;
|
max-height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.max-h-6 {
|
|
||||||
max-height: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -1504,10 +1500,6 @@ video {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-1\.5 {
|
|
||||||
padding: 0.375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-0\.5 {
|
.p-0\.5 {
|
||||||
padding: 0.125rem;
|
padding: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,29 @@ Contains tweaks for small screens
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (min-height: 300px) and (min-width: 225px) {
|
||||||
|
.very-small-screen {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.hidden-on-very-small-screen {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media not screen and (min-height: 300px) and (min-width: 225px) {
|
||||||
|
.very-small-screen {
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-on-very-small-screen {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 768px), only screen and (max-height: 768px) {
|
@media only screen and (max-width: 768px), only screen and (max-height: 768px) {
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,7 @@
|
||||||
"removeLocationHistory": "Delete the location history",
|
"removeLocationHistory": "Delete the location history",
|
||||||
"returnToTheMap": "Return to the map",
|
"returnToTheMap": "Return to the map",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
"screenToSmall": "Open {theme} in a new window",
|
||||||
"search": {
|
"search": {
|
||||||
"error": "Something went wrong…",
|
"error": "Something went wrong…",
|
||||||
"nothing": "Nothing found…",
|
"nothing": "Nothing found…",
|
||||||
|
|
|
@ -1584,6 +1584,9 @@
|
||||||
"then": "Only customers of the place this station belongs to can use this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests</span>"
|
"then": "Only customers of the place this station belongs to can use this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests</span>"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
|
"then": "A <b>key</b> must be requested to access this charging station<br/><span class='subtle'>E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station</span>"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
"then": "Not accessible to the general public (e.g. only accessible to the owners, employees, ...)"
|
"then": "Not accessible to the general public (e.g. only accessible to the owners, employees, ...)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1593,6 +1593,9 @@
|
||||||
"then": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
"then": "Enkel <b>klanten van de bijhorende plaats</b> mogen dit oplaadpunt gebruiken<br/><span class='subtle'>Bv. op de parking van een hotel en enkel toegankelijk voor klanten van dit hotel</span>"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
|
"then": "Een <b>sleutel</b> is nodig om dit oplaadpunt te gebruiken<br/><span class='subtle'>Bv. voor klanten van een hotel of een bar, die de sleutel aan de receptie kunnen krijgen</span>"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
"then": "Niet toegankelijk voor het publiek <br/><span class='subtle'>Bv. enkel toegankelijk voor de eigenaar, medewerkers ,...</span> "
|
"then": "Niet toegankelijk voor het publiek <br/><span class='subtle'>Bv. enkel toegankelijk voor de eigenaar, medewerkers ,...</span> "
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
"importTags": "Het element zal deze tags krijgen: {tags}",
|
"importTags": "Het element zal deze tags krijgen: {tags}",
|
||||||
"officialThemesOnly": "In onofficiële thema's is de importeerknop uitgeschakeld om ongelukjes te vermijden",
|
"officialThemesOnly": "In onofficiële thema's is de importeerknop uitgeschakeld om ongelukjes te vermijden",
|
||||||
"wrongType": "Dit object is geen punt of lijn, en kan daarom niet geïmporteerd worden",
|
"wrongType": "Dit object is geen punt of lijn, en kan daarom niet geïmporteerd worden",
|
||||||
"zoomInMore": "Zoom verder in om dit kaart-object te kunnen importeren"
|
"zoomInMore": "Zoom verder in om dit object af te handelen"
|
||||||
},
|
},
|
||||||
"importTags": "Het object zal deze tags krijgen: {tags}",
|
"importTags": "Het object zal deze tags krijgen: {tags}",
|
||||||
"intro": "Kies hieronder welk punt je wilt toevoegen<br/>",
|
"intro": "Kies hieronder welk punt je wilt toevoegen<br/>",
|
||||||
|
|
|
@ -13,12 +13,8 @@
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"then": "Anjing diperbolehkan, tetapi mereka harus diikat"
|
"then": "Anjing diperbolehkan, tetapi mereka harus diikat"
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"then": "Anjing diperbolehkan dan dapat berkeliaran dengan bebas"
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"question": "Apakah anjing diperbolehkan dalam bisnis ini?"
|
|
||||||
},
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"question": "Apa alamat surel dari {title()}?"
|
"question": "Apa alamat surel dari {title()}?"
|
||||||
|
|
|
@ -47,8 +47,9 @@
|
||||||
<!-- DECORATION 0 END -->
|
<!-- DECORATION 0 END -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hidden md:hidden fixed inset-0 block z-above-controls" id="fullscreen"></div>
|
<div class="very-small-screen fixed inset-0 block z-above-controls" id="on-small-screen"></div>
|
||||||
<div class="z-index-above-map pointer-events-none" id="topleft-tools">
|
<div class="hidden md:hidden fixed inset-0 block z-above-controls hidden-on-very-small-screen" id="fullscreen"></div>
|
||||||
|
<div class="z-index-above-map pointer-events-none" id="topleft-tools">'
|
||||||
<div class="p-3 flex flex-col items-end sm:items-start sm:flex-row sm:flex-wrap w-full sm:justify-between">
|
<div class="p-3 flex flex-col items-end sm:items-start sm:flex-row sm:flex-wrap w-full sm:justify-between">
|
||||||
<div class="shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto"
|
<div class="shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto"
|
||||||
id="searchbox"></div>
|
id="searchbox"></div>
|
||||||
|
@ -83,7 +84,6 @@
|
||||||
<div id="leafletDiv"></div>
|
<div id="leafletDiv"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="./index.ts"></script>
|
<script src="./index.ts"></script>
|
||||||
<script async data-goatcounter="https://pietervdvn.goatcounter.com/count" src="//gc.zgo.at/count.js"></script>
|
<script async data-goatcounter="https://pietervdvn.goatcounter.com/count" src="//gc.zgo.at/count.js"></script>
|
||||||
|
|
||||||
|
|