Add the possibility to load a custom layout with base64-encoded jsons

This commit is contained in:
Pieter Vander Vennet 2020-08-08 17:50:43 +02:00
parent 31ec3a7755
commit 14930e2f93
10 changed files with 296 additions and 74 deletions

View file

@ -0,0 +1,221 @@
import {TagRenderingOptions} from "../TagRenderingOptions";
import {LayerDefinition, Preset} from "../LayerDefinition";
import {Layout} from "../Layout";
import Translation from "../../UI/i18n/Translation";
import {type} from "os";
import Combine from "../../UI/Base/Combine";
import {UIElement} from "../../UI/UIElement";
import {And, Tag, TagsFilter} from "../../Logic/TagsFilter";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
export class CustomLayoutFromJSON {
public static exampleLayer = {
id: "bookcase",
icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgaWQ9InN2ZzExMzgyIgogICBoZWlnaHQ9IjkwMCIKICAgd2lkdGg9IjkwMCIKICAgdmVyc2lvbj0iMS4wIj4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGExMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGRlZnMKICAgICBpZD0iZGVmczExMzg0IiAvPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjkwMTAzMjU4LDAsMCwwLjkwMTAzMjU4LDExMi44NDA1OCwtMS45MDYwMTc3KSI+CiAgICA8ZwogICAgICAgaWQ9ImcxMTQ3NiI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMTE0NzIiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjEyMDEuOTI0OTI2NzZweDtmb250LWZhbWlseTonQml0c3RyZWFtIFZlcmEgU2Fucyc7dGV4dC1hbGlnbjpjZW50ZXI7dGV4dC1hbmNob3I6bWlkZGxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Ik0gNDc0LjUwODg4LDcxOC4yMjg0MSBIIDMwMy40OTU0NyB2IC0yMi4zMDEzNCBjIC0yLjRlLTQsLTM3Ljk1MTA4IDQuMzAzNTIsLTY4Ljc2MjExIDEyLjkxMTMsLTkyLjQzMzE5IDguNjA3MjgsLTIzLjY3MDMyIDIzLjYzMzUyLC00NS4yODY5NSA0MC42NTMyNCwtNjQuODQ5OTYgMTcuMDE5MTQsLTE5LjU2MjExIDQxLjk4NzM0LC0yNi4zMzI2NCAxMDEuNDU3OTMsLTc1LjYzMDg1IDMxLjY5MDk1LC0yNS44MjIwMyA1NS4yODEzLC03Ny4xNTIzIDU1LjI4MTc1LC05OC42NzE3NCAyLjIxMjMyLC01Ni45MjI0NSAtMTMuOTM5ODMsLTc5LjM0MjIgLTM0LjU2Mjg3LC05OS45NjUyNCAtMjIuNjczNTUsLTE5LjY3NzE3IC02MC42NzAyNywtMzAuMDY5OTggLTkwLjk5ODkyLC0zMC4wNjk5OCAtMjcuNzc5MjEsNi45ZS00IC02OC40NjczNSw4LjA4ODcxIC04Ny43NjY2LDI1LjM3MDQ3IC0yNS45MzgxNywxNy4yODMwOCAtNjUuMjM3NDcsNzMuNzA2MTEgLTU3LjA0Njg3LDEzMC41NDU3NyBsIC0xOTQuNTE2OTQzLDEuNzAyMjIgYyAwLC0xNTcuMjEzOTkgMjkuMzkzNjk5LC0xOTguNjk0NjUgOTkuMDA0MTEzLC0yNjMuMDMwMzIgNjcuMzk3MzksLTU0LjM3NjY0MyAxMjYuNTMxMjgsLTczLjI2ODM2NSAyNDMuODQ3NTcsLTczLjI2ODM2NSA4OS43MTc5MSwwIDE2MS44OTcyOCwxNy44MDI4MSAyMTQuMzI1NTIsNTMuNDA1ODU1IDcxLjIwNzE0LDQ4LjEyNDcyIDEyMi4zMDEwNSwxMTEuMTgzNTQgMTIyLjMwMTA1LDIzMC4xMTI4MSAtNi45ZS00LDQ0LjMyMDgxIC0xOS4xNTI1Myw5MC43ODYzOCAtNDMuMDcyNiwxMjguMzMyOTkgLTE4LjM4OTQ3LDMwLjkwOTM4IC02MC4zNzUxMSw2Ni40NTIzNiAtMTE4LjIxMjM3LDEwNC40MTYyOCAtNDIuODM2MDcsMjUuNzY4NiAtNjYuNjcxOTYsNTMuMTE5MjYgLTc3LjAzOTY0LDcyLjA5NDYgLTEwLjM2ODYzLDE4Ljk3NjAzIC0xNS41NTI3MSw0My43MjI2NyAtMTUuNTUyMjUsNzQuMjM5OTkgeiIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgxMTQ3NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMS4xMDYzODMsLTUuNTMxOTE0OSkiCiAgICAgICAgIGQ9Im0gNDgyLjM4Mjk4LDg2OS44MDkwMiBhIDk0LjA0MjU1Nyw3My4wMjEyNzggMCAxIDEgLTE4OC4wODUxMSwwIDk0LjA0MjU1Nyw3My4wMjEyNzggMCAxIDEgMTg4LjA4NTExLDAgeiIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=",
title: "Bookcase",
description: "A small, public cabinet with books. Anyone can leave or take a book",
minzoom: 12,
color: "#0000ff",
overpassTags: "amenity=public_bookcase",
presets: [
{
// icon: optional. Uses the layer icon by default
// title: optional. Uses the layer title by default
// description: optional. Uses the layer description by default
// tags: optional list {k:string, v:string}[]
}
],
tagRenderings: [
{
// If this key is present, then...
key: "name",
// Use this string to render
render: "{name}",
// One of string, int, nat, float, pfloat, email, phone. Default: string
type: "string",
// If it is not known (and no mapping below matches), this question is asked; a textfield is inserted in the rendering above
question: "Wat is de naam van dit boekenruilkastje?",
// If a value is added with the textfield, this extra tag is addded. Optional field
addExtraTags: [{
"k": "fixme",
"v": "Added with mapcomplete, to be checked"
}],
// Alternatively, these tags are shown if they match - even if the key above is not there
// If unknown, these become a radio button
mappings: [
{
if: "noname=yes",
then: "Dit boekenruilkastje heeft geen naam"
}
]
}
]
}
public static exampleLayout = {
name: "bookcases",
title: "Custom Open bookcases map",
description: "Welcome to a custom layout",
language: "en",
layers: [CustomLayoutFromJSON.exampleLayer],
startZoom: 12,
startLat: 0,
startLon: 0,
icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgaWQ9InN2ZzExMzgyIgogICBoZWlnaHQ9IjkwMCIKICAgd2lkdGg9IjkwMCIKICAgdmVyc2lvbj0iMS4wIj4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGExMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGRlZnMKICAgICBpZD0iZGVmczExMzg0IiAvPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjkwMTAzMjU4LDAsMCwwLjkwMTAzMjU4LDExMi44NDA1OCwtMS45MDYwMTc3KSI+CiAgICA8ZwogICAgICAgaWQ9ImcxMTQ3NiI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMTE0NzIiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjEyMDEuOTI0OTI2NzZweDtmb250LWZhbWlseTonQml0c3RyZWFtIFZlcmEgU2Fucyc7dGV4dC1hbGlnbjpjZW50ZXI7dGV4dC1hbmNob3I6bWlkZGxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Ik0gNDc0LjUwODg4LDcxOC4yMjg0MSBIIDMwMy40OTU0NyB2IC0yMi4zMDEzNCBjIC0yLjRlLTQsLTM3Ljk1MTA4IDQuMzAzNTIsLTY4Ljc2MjExIDEyLjkxMTMsLTkyLjQzMzE5IDguNjA3MjgsLTIzLjY3MDMyIDIzLjYzMzUyLC00NS4yODY5NSA0MC42NTMyNCwtNjQuODQ5OTYgMTcuMDE5MTQsLTE5LjU2MjExIDQxLjk4NzM0LC0yNi4zMzI2NCAxMDEuNDU3OTMsLTc1LjYzMDg1IDMxLjY5MDk1LC0yNS44MjIwMyA1NS4yODEzLC03Ny4xNTIzIDU1LjI4MTc1LC05OC42NzE3NCAyLjIxMjMyLC01Ni45MjI0NSAtMTMuOTM5ODMsLTc5LjM0MjIgLTM0LjU2Mjg3LC05OS45NjUyNCAtMjIuNjczNTUsLTE5LjY3NzE3IC02MC42NzAyNywtMzAuMDY5OTggLTkwLjk5ODkyLC0zMC4wNjk5OCAtMjcuNzc5MjEsNi45ZS00IC02OC40NjczNSw4LjA4ODcxIC04Ny43NjY2LDI1LjM3MDQ3IC0yNS45MzgxNywxNy4yODMwOCAtNjUuMjM3NDcsNzMuNzA2MTEgLTU3LjA0Njg3LDEzMC41NDU3NyBsIC0xOTQuNTE2OTQzLDEuNzAyMjIgYyAwLC0xNTcuMjEzOTkgMjkuMzkzNjk5LC0xOTguNjk0NjUgOTkuMDA0MTEzLC0yNjMuMDMwMzIgNjcuMzk3MzksLTU0LjM3NjY0MyAxMjYuNTMxMjgsLTczLjI2ODM2NSAyNDMuODQ3NTcsLTczLjI2ODM2NSA4OS43MTc5MSwwIDE2MS44OTcyOCwxNy44MDI4MSAyMTQuMzI1NTIsNTMuNDA1ODU1IDcxLjIwNzE0LDQ4LjEyNDcyIDEyMi4zMDEwNSwxMTEuMTgzNTQgMTIyLjMwMTA1LDIzMC4xMTI4MSAtNi45ZS00LDQ0LjMyMDgxIC0xOS4xNTI1Myw5MC43ODYzOCAtNDMuMDcyNiwxMjguMzMyOTkgLTE4LjM4OTQ3LDMwLjkwOTM4IC02MC4zNzUxMSw2Ni40NTIzNiAtMTE4LjIxMjM3LDEwNC40MTYyOCAtNDIuODM2MDcsMjUuNzY4NiAtNjYuNjcxOTYsNTMuMTE5MjYgLTc3LjAzOTY0LDcyLjA5NDYgLTEwLjM2ODYzLDE4Ljk3NjAzIC0xNS41NTI3MSw0My43MjI2NyAtMTUuNTUyMjUsNzQuMjM5OTkgeiIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgxMTQ3NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMS4xMDYzODMsLTUuNTMxOTE0OSkiCiAgICAgICAgIGQ9Im0gNDgyLjM4Mjk4LDg2OS44MDkwMiBhIDk0LjA0MjU1Nyw3My4wMjEyNzggMCAxIDEgLTE4OC4wODUxMSwwIDk0LjA0MjU1Nyw3My4wMjEyNzggMCAxIDEgMTg4LjA4NTExLDAgeiIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo="
}
public static FromQueryParam(layoutFromBase64: string): Layout {
if(layoutFromBase64 === "test"){
console.log(btoa(JSON.stringify(CustomLayoutFromJSON.exampleLayout)));
return CustomLayoutFromJSON.LayoutFromJSON(CustomLayoutFromJSON.exampleLayout);
}
const spec = JSON.parse(atob(layoutFromBase64));
return CustomLayoutFromJSON.LayoutFromJSON(spec);
}
private static TagRenderingFromJson(json: any): TagRenderingOptions {
if (typeof (json) === "string") {
return new FixedText(json);
}
let freeform = undefined;
if (json.key !== undefined && json.render !== undefined) {
const type = json.type ?? "text";
freeform = {
key: json.key,
template: json.render.replace("{" + json.key + "}", "$" + type + "$"),
renderTemplate: json.render,
extraTags: CustomLayoutFromJSON.TagsFromJson(json.addExtraTags),
}
}
let mappings = undefined;
if (json.mappings !== undefined) {
mappings = [];
for (const mapping of json.mappings) {
mappings.push({
k: new And(CustomLayoutFromJSON.TagsFromJson(mapping.if)), txt: mapping.then
})
}
}
return new TagRenderingOptions({
question: json.question,
freeform: freeform,
mappings: mappings
})
}
private static PresetFromJson(layout: any, preset: any): Preset {
const t = CustomLayoutFromJSON.MaybeTranslation;
const tags = CustomLayoutFromJSON.TagsFromJson;
return {
icon: preset.icon ?? layout.icon,
tags: tags(preset.tags) ?? tags(layout.overpassTags),
title: t(preset.title) ?? t(layout.title),
description: t(preset.description) ?? t(layout.description)
}
}
private static StyleFromJson(layout: any, styleJson: any): ((tags) => {
color: string,
weight?: number,
icon: {
iconUrl: string,
iconSize: number[],
},
}) {
return (tags) => {
return {
color: layout.color,
weight: 10,
icon: {
iconUrl: layout.icon,
iconSize: [40, 40],
},
}
};
}
private static TagFromJson(json: any): Tag {
if (json === undefined) {
return undefined;
}
if (typeof (json) === "string") {
const kv = json.split("=");
return new Tag(kv[0].trim(), kv[1].trim());
}
return new Tag(json.k.trim(), json.v.trim())
}
private static TagsFromJson(json: any): Tag[] {
if (json === undefined) {
return undefined;
}
if (typeof (json) === "string") {
return json.split(",").map(CustomLayoutFromJSON.TagFromJson);
}
return json.map(CustomLayoutFromJSON.TagFromJson)
}
private static LayerFromJson(json: any): LayerDefinition {
const t = CustomLayoutFromJSON.MaybeTranslation;
const tr = CustomLayoutFromJSON.TagRenderingFromJson;
return new LayerDefinition(
json.id,
{
description: t(json.description),
name: t(json.title),
icon: json.icon,
minzoom: json.minzoom,
title: tr(json.title),
presets: json.presets.map((preset) => {
return CustomLayoutFromJSON.PresetFromJson(json, preset)
}),
elementsToShow:
[new ImageCarouselWithUploadConstructor()].concat(json.tagRenderings.map(tr)),
overpassFilter: new And(CustomLayoutFromJSON.TagsFromJson(json.overpassTags)),
wayHandling: LayerDefinition.WAYHANDLING_CENTER_AND_WAY,
maxAllowedOverlapPercentage: 0,
style: CustomLayoutFromJSON.StyleFromJson(json, json.style)
}
)
}
private static MaybeTranslation(json: any): Translation | string {
if (json === undefined) {
return undefined;
}
if (typeof (json) === "string") {
return json;
}
return new Translation(json);
}
private static LayoutFromJSON(json: any) {
const t = CustomLayoutFromJSON.MaybeTranslation;
const layout = new Layout(json.name,
[json.language],
t(json.title),
json.layers.map(CustomLayoutFromJSON.LayerFromJson),
json.startZoom,
json.startLat,
json.startLon,
new Combine(['<h3>', t(json.title), '</h3><br/>', t(json.description)])
);
layout.icon = json.icon;
return layout;
}
public static TagRenderingOptionsFromJson(spec: any): TagRenderingOptions {
return new TagRenderingOptions(spec);
}
}

View file

@ -1,24 +0,0 @@
import {TagRenderingOptions} from "../TagRenderingOptions";
import {LayerDefinition} from "../LayerDefinition";
export class CustomizationFromJSON {
public exampleLayer = {
id: "bookcases",
}
/*
public static LayerFromJson(spec: any) : LayerDefinition{
return new LayerDefinition(spec.id,{
})
}
*/
public static TagRenderingOptionsFromJson(spec: any) : TagRenderingOptions{
return new TagRenderingOptions(spec);
}
}

View file

@ -94,14 +94,9 @@ export class LayerDefinition {
static WAYHANDLING_CENTER_AND_WAY = 2; static WAYHANDLING_CENTER_AND_WAY = 2;
constructor(id: string, options: { constructor(id: string, options: {
name: string, name: string | UIElement,
description: string | UIElement, description: string | UIElement,
presets: { presets: Preset[],
tags: Tag[],
title: string | UIElement,
description?: string | UIElement,
icon?: string
}[],
icon: string, icon: string,
minzoom: number, minzoom: number,
overpassFilter: TagsFilter, overpassFilter: TagsFilter,

View file

@ -55,7 +55,7 @@ export class InitUiElements {
} }
const tabs = [ const tabs = [
{header: `<img src='${layoutToUse.icon}'>`, content: welcome}, {header: Img.AsImageElement(layoutToUse.icon), content: welcome},
{header: `<img src='${'./assets/osm-logo.svg'}'>`, content: Translations.t.general.openStreetMapIntro}, {header: `<img src='${'./assets/osm-logo.svg'}'>`, content: Translations.t.general.openStreetMapIntro},
] ]

View file

@ -1,4 +1,19 @@
export class Img { export class Img {
/**
* If the source is an svg element, it is returned as is.
* If not, the source is wrapped into a 'img'-tag
* @param source
* @constructor
*/
static AsImageElement(source: string): string{
if(source.startsWith("<svg")){
return `<img src="data:image/svg+xml;base64,${(btoa(source))}">`;
}else{
return `<img src="${source}">`
}
}
static readonly checkmark = `<svg width="26" height="18" viewBox="0 0 26 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 7.28571L10.8261 15L23 3" stroke="black" stroke-width="4" stroke-linejoin="round"/></svg>`; static readonly checkmark = `<svg width="26" height="18" viewBox="0 0 26 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 7.28571L10.8261 15L23 3" stroke="black" stroke-width="4" stroke-linejoin="round"/></svg>`;
static readonly no_checkmark = `<svg width="26" height="18" viewBox="0 0 26 18" fill="none" xmlns="http://www.w3.org/2000/svg"></svg>`; static readonly no_checkmark = `<svg width="26" height="18" viewBox="0 0 26 18" fill="none" xmlns="http://www.w3.org/2000/svg"></svg>`;

View file

@ -1,20 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
width="900"
height="900"
id="svg11382" id="svg11382"
sodipodi:docname="help.svg" height="900"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"> width="900"
version="1.0">
<metadata <metadata
id="metadata10"> id="metadata10">
<rdf:RDF> <rdf:RDF>
@ -27,45 +21,22 @@
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1001"
id="namedview8"
showgrid="false"
units="px"
inkscape:zoom="0.26767309"
inkscape:cx="339.73914"
inkscape:cy="440.83624"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg11382" />
<defs <defs
id="defs11384" /> id="defs11384" />
<g <g
transform="matrix(0.90103258,0,0,0.90103258,112.84058,-1.9060177)" id="layer1"
id="layer1"> transform="matrix(0.90103258,0,0,0.90103258,112.84058,-1.9060177)">
<g <g
id="g11476"> id="g11476">
<path <path
d="M 474.50888,718.22841 H 303.49547 v -22.30134 c -2.4e-4,-37.95108 4.30352,-68.76211 12.9113,-92.43319 8.60728,-23.67032 23.63352,-45.28695 40.65324,-64.84996 17.01914,-19.56211 41.98734,-26.33264 101.45793,-75.63085 31.69095,-25.82203 55.2813,-77.1523 55.28175,-98.67174 2.21232,-56.92245 -13.93983,-79.3422 -34.56287,-99.96524 -22.67355,-19.67717 -60.67027,-30.06998 -90.99892,-30.06998 -27.77921,6.9e-4 -68.46735,8.08871 -87.7666,25.37047 -25.93817,17.28308 -65.23747,73.70611 -57.04687,130.54577 l -194.516943,1.70222 c 0,-157.21399 29.393699,-198.69465 99.004113,-263.03032 67.39739,-54.376643 126.53128,-73.268365 243.84757,-73.268365 89.71791,0 161.89728,17.80281 214.32552,53.405855 71.20714,48.12472 122.30105,111.18354 122.30105,230.11281 -6.9e-4,44.32081 -19.15253,90.78638 -43.0726,128.33299 -18.38947,30.90938 -60.37511,66.45236 -118.21237,104.41628 -42.83607,25.7686 -66.67196,53.11926 -77.03964,72.0946 -10.36863,18.97603 -15.55271,43.72267 -15.55225,74.23999 z"
style="font-style:normal;font-weight:normal;font-size:1201.92492676px;font-family:'Bitstream Vera Sans';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path11472" id="path11472"
inkscape:connector-curvature="0" /> style="font-style:normal;font-weight:normal;font-size:1201.92492676px;font-family:'Bitstream Vera Sans';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 474.50888,718.22841 H 303.49547 v -22.30134 c -2.4e-4,-37.95108 4.30352,-68.76211 12.9113,-92.43319 8.60728,-23.67032 23.63352,-45.28695 40.65324,-64.84996 17.01914,-19.56211 41.98734,-26.33264 101.45793,-75.63085 31.69095,-25.82203 55.2813,-77.1523 55.28175,-98.67174 2.21232,-56.92245 -13.93983,-79.3422 -34.56287,-99.96524 -22.67355,-19.67717 -60.67027,-30.06998 -90.99892,-30.06998 -27.77921,6.9e-4 -68.46735,8.08871 -87.7666,25.37047 -25.93817,17.28308 -65.23747,73.70611 -57.04687,130.54577 l -194.516943,1.70222 c 0,-157.21399 29.393699,-198.69465 99.004113,-263.03032 67.39739,-54.376643 126.53128,-73.268365 243.84757,-73.268365 89.71791,0 161.89728,17.80281 214.32552,53.405855 71.20714,48.12472 122.30105,111.18354 122.30105,230.11281 -6.9e-4,44.32081 -19.15253,90.78638 -43.0726,128.33299 -18.38947,30.90938 -60.37511,66.45236 -118.21237,104.41628 -42.83607,25.7686 -66.67196,53.11926 -77.03964,72.0946 -10.36863,18.97603 -15.55271,43.72267 -15.55225,74.23999 z" />
<path <path
d="m 482.38298,869.80902 a 94.042557,73.021278 0 1 1 -188.08511,0 94.042557,73.021278 0 1 1 188.08511,0 z"
transform="translate(1.106383,-5.5319149)"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path11474" id="path11474"
inkscape:connector-curvature="0" /> style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
transform="translate(1.106383,-5.5319149)"
d="m 482.38298,869.80902 a 94.042557,73.021278 0 1 1 -188.08511,0 94.042557,73.021278 0 1 1 188.08511,0 z" />
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -16,7 +16,7 @@ rm q*.html
rm assets/generated/* rm assets/generated/*
for f in ./*.html; do for f in ./*.html; do
if [[ "$f" == "./index.html" ]] || [[ "$f" == "./land.html" ]] || [[ "$f" == "./test.html" ]] if [[ "$f" == "./index.html" ]] || [[ "$f" == "./land.html" ]] || [[ "$f" == "./test.html" ]] || [[ "$f" == "./preferences.html" ]] || [[ "$f" == "./customGenerator.html" ]]
then then
echo "Not removing $f" echo "Not removing $f"
else else

View file

@ -462,6 +462,12 @@ form {
margin: 0 10px 0 18px; margin: 0 10px 0 18px;
} }
#filter__selection ul svg {
width: 20px;
height: auto;
margin: 0 10px 0 18px;
}
.filter__label { .filter__label {
font-size: 16px; font-size: 16px;
transform: translateY(75px); transform: translateY(75px);
@ -1149,6 +1155,7 @@ form {
padding: 0.5em; padding: 0.5em;
} }
.tab-content { .tab-content {
padding: 1em; padding: 1em;
z-index: 5002; z-index: 5002;

View file

@ -18,6 +18,7 @@ import {TagRenderingOptions} from "./Customizations/TagRenderingOptions";
import {TagRendering} from "./Customizations/TagRendering"; import {TagRendering} from "./Customizations/TagRendering";
import {Img} from "./UI/Img"; import {Img} from "./UI/Img";
import Combine from "./UI/Base/Combine"; import Combine from "./UI/Base/Combine";
import {CustomLayoutFromJSON} from "./Customizations/JSON/CustomLayoutFromJSON";
// --------------------- Special actions based on the parameters ----------------- // --------------------- Special actions based on the parameters -----------------
@ -41,6 +42,7 @@ if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
// ----------------- SELECT THE RIGHT QUESTSET ----------------- // ----------------- SELECT THE RIGHT QUESTSET -----------------
let defaultLayout = "bookcases" let defaultLayout = "bookcases"
let hash = window.location.hash;
const path = window.location.pathname.split("/").slice(-1)[0]; const path = window.location.pathname.split("/").slice(-1)[0];
if (path !== "index.html") { if (path !== "index.html") {
@ -64,7 +66,15 @@ for (const k in AllKnownLayouts.allSets) {
defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout).data; defaultLayout = QueryParameters.GetQueryParameter("layout", defaultLayout).data;
const layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout] ?? AllKnownLayouts["all"]; let layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout] ?? AllKnownLayouts["all"];
const layoutFromBase64 = QueryParameters.GetQueryParameter("userlayout", "false").data;
if(layoutFromBase64 === "true"){
layoutToUse = CustomLayoutFromJSON.FromQueryParam(hash.substr(1));
}
if (layoutToUse === undefined) { if (layoutToUse === undefined) {
console.log("Incorrect layout") console.log("Incorrect layout")
new FixedUiElement("Error: incorrect layout <i>" + defaultLayout + "</i><br/><a href='https://pietervdvn.github.io/MapComplete/index.html'>Go back</a>").AttachTo("centermessage").onClick(() => { new FixedUiElement("Error: incorrect layout <i>" + defaultLayout + "</i><br/><a href='https://pietervdvn.github.io/MapComplete/index.html'>Go back</a>").AttachTo("centermessage").onClick(() => {
@ -73,8 +83,8 @@ if (layoutToUse === undefined) {
} }
console.log("Using layout: ", layoutToUse.name); console.log("Using layout: ", layoutToUse.name);
TagRendering.injectFunction();
TagRendering.injectFunction();
State.state = new State(layoutToUse); State.state = new State(layoutToUse);
InitUiElements.InitBaseMap(); InitUiElements.InitBaseMap();

27
preferences.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<link href="index.css" rel="stylesheet"/>
<title>Preferences editor</title>
<style>
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>Preferences editor - developers only</h1>
Only use if you know what you're doing. To prevent newbies to make mistakes here, editing a mapcomplete-preference is only available if over 500 changes<br/>
Editing any preference -including non-mapcomplete ones- is available when you have more then 2500 changesets. Until that point, only editing mapcomplete-preferences is possible.
<div id="maindiv">'maindiv' not attached</div>
<script src="./preferences.ts"></script>
</body>
</html>