Add custom theme for advanced users
This commit is contained in:
parent
004eead4ee
commit
9c42839f01
44 changed files with 635 additions and 326 deletions
|
@ -11,55 +11,53 @@ import {StreetWidth} from "./Layouts/StreetWidth";
|
||||||
import {Natuurpunt} from "./Layouts/Natuurpunt";
|
import {Natuurpunt} from "./Layouts/Natuurpunt";
|
||||||
import {ClimbingTrees} from "./Layouts/ClimbingTrees";
|
import {ClimbingTrees} from "./Layouts/ClimbingTrees";
|
||||||
import {Smoothness} from "./Layouts/Smoothness";
|
import {Smoothness} from "./Layouts/Smoothness";
|
||||||
|
import {LayerDefinition} from "./LayerDefinition";
|
||||||
|
import {CustomLayers} from "../Logic/CustomLayers";
|
||||||
|
|
||||||
export class AllKnownLayouts {
|
export class AllKnownLayouts {
|
||||||
public static allSets = AllKnownLayouts.AllLayouts();
|
|
||||||
|
public static allLayers: Map<string, LayerDefinition> = undefined;
|
||||||
|
|
||||||
|
public static layoutsList: Layout[] = [
|
||||||
|
new Groen(),
|
||||||
|
new GRB(),
|
||||||
|
new Cyclofix(),
|
||||||
|
new Bookcases(),
|
||||||
|
new WalkByBrussels(),
|
||||||
|
new MetaMap(),
|
||||||
|
new StreetWidth(),
|
||||||
|
new Natuurpunt(),
|
||||||
|
new ClimbingTrees(),
|
||||||
|
new Artworks(),
|
||||||
|
new Smoothness(),
|
||||||
|
new CustomLayers()
|
||||||
|
/*new Toilets(),
|
||||||
|
*/
|
||||||
|
];
|
||||||
|
|
||||||
|
public static allSets: Map<string, Layout> = AllKnownLayouts.AllLayouts();
|
||||||
|
|
||||||
private static AllLayouts(): Map<string, Layout> {
|
private static AllLayouts(): Map<string, Layout> {
|
||||||
const layouts: Layout[] = [
|
|
||||||
new Groen(),
|
|
||||||
new GRB(),
|
|
||||||
new Cyclofix(),
|
|
||||||
new Bookcases(),
|
|
||||||
new WalkByBrussels(),
|
|
||||||
new MetaMap(),
|
|
||||||
new StreetWidth(),
|
|
||||||
new Natuurpunt(),
|
|
||||||
new ClimbingTrees(),
|
|
||||||
new Artworks(),
|
|
||||||
new Smoothness()
|
|
||||||
/*new Toilets(),
|
|
||||||
*/
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
const all = new All();
|
const all = new All();
|
||||||
const knownKeys = []
|
this.allLayers = new Map<string, LayerDefinition>();
|
||||||
for (const layout of layouts) {
|
for (const layout of this.layoutsList) {
|
||||||
for (const layer of layout.layers) {
|
for (const layer of layout.layers) {
|
||||||
const key = layer.overpassFilter.asOverpass().join("");
|
const key = layer.id;
|
||||||
if (knownKeys.indexOf(key) >= 0) {
|
if (this.allLayers[layer.id] !== undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
knownKeys.push(key);
|
this.allLayers[layer.id] = layer;
|
||||||
all.layers.push(layer);
|
all.layers.push(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layouts.push(all)
|
|
||||||
|
|
||||||
const allSets: Map<string, Layout> = new Map();
|
const allSets: Map<string, Layout> = new Map();
|
||||||
for (const layout of layouts) {
|
for (const layout of this.layoutsList) {
|
||||||
allSets[layout.name] = layout;
|
allSets[layout.name] = layout;
|
||||||
}
|
}
|
||||||
|
allSets[all.name] = all;
|
||||||
return allSets;
|
return allSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GetSets(layoutNames): any {
|
|
||||||
const all = new All();
|
|
||||||
for (const name of layoutNames) {
|
|
||||||
all.layers = all.layers.concat(AllKnownLayouts.allSets[name].layers);
|
|
||||||
}
|
|
||||||
|
|
||||||
return all;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ export class LayerDefinition {
|
||||||
* ])
|
* ])
|
||||||
*/
|
*/
|
||||||
overpassFilter: TagsFilter;
|
overpassFilter: TagsFilter;
|
||||||
|
public readonly id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This UIElement is rendered as title element in the popup
|
* This UIElement is rendered as title element in the popup
|
||||||
|
@ -90,7 +91,7 @@ export class LayerDefinition {
|
||||||
static WAYHANDLING_CENTER_ONLY = 1;
|
static WAYHANDLING_CENTER_ONLY = 1;
|
||||||
static WAYHANDLING_CENTER_AND_WAY = 2;
|
static WAYHANDLING_CENTER_AND_WAY = 2;
|
||||||
|
|
||||||
constructor(options: {
|
constructor(id: string, options: {
|
||||||
name: string,
|
name: string,
|
||||||
description: string | UIElement,
|
description: string | UIElement,
|
||||||
presets: {
|
presets: {
|
||||||
|
@ -111,6 +112,7 @@ export class LayerDefinition {
|
||||||
icon: any
|
icon: any
|
||||||
}
|
}
|
||||||
} = undefined) {
|
} = undefined) {
|
||||||
|
this.id = id;
|
||||||
if (options === undefined) {
|
if (options === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -127,6 +129,4 @@ export class LayerDefinition {
|
||||||
this.wayHandling = options.wayHandling ?? LayerDefinition.WAYHANDLING_DEFAULT;
|
this.wayHandling = options.wayHandling ?? LayerDefinition.WAYHANDLING_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ import FixedText from "../Questions/FixedText";
|
||||||
export class Artwork extends LayerDefinition {
|
export class Artwork extends LayerDefinition {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("artwork");
|
||||||
this.name = "artwork";
|
this.name = "artwork";
|
||||||
const t = Translations.t.artwork;
|
const t = Translations.t.artwork;
|
||||||
this.title = t.title;
|
this.title = t.title;
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default class BikeCafes extends LayerDefinition {
|
||||||
private readonly to = Translations.t.cyclofix.cafe
|
private readonly to = Translations.t.cyclofix.cafe
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super("bikecafe")
|
||||||
this.name = this.to.name
|
this.name = this.to.name
|
||||||
this.icon = "./assets/bike/cafe.svg"
|
this.icon = "./assets/bike/cafe.svg"
|
||||||
this.overpassFilter = new And([
|
this.overpassFilter = new And([
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default class BikeOtherShops extends LayerDefinition {
|
||||||
private readonly to = Translations.t.cyclofix.nonBikeShop
|
private readonly to = Translations.t.cyclofix.nonBikeShop
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("bikeOtherShop");
|
||||||
this.name = this.to.name
|
this.name = this.to.name
|
||||||
this.icon = "./assets/bike/non_bike_repair_shop.svg"
|
this.icon = "./assets/bike/non_bike_repair_shop.svg"
|
||||||
this.overpassFilter = new And([
|
this.overpassFilter = new And([
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class BikeParkings extends LayerDefinition {
|
||||||
private readonly accessCargoDesignated = new Tag("cargo_bike", "designated");
|
private readonly accessCargoDesignated = new Tag("cargo_bike", "designated");
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("bikeparking");
|
||||||
this.name = Translations.t.cyclofix.parking.name;
|
this.name = Translations.t.cyclofix.parking.name;
|
||||||
this.icon = "./assets/bike/parking.svg";
|
this.icon = "./assets/bike/parking.svg";
|
||||||
this.overpassFilter = new Tag("amenity", "bicycle_parking");
|
this.overpassFilter = new Tag("amenity", "bicycle_parking");
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default class BikeShops extends LayerDefinition {
|
||||||
private readonly repairsBikes = new Tag("service:bicycle:repair", "yes")
|
private readonly repairsBikes = new Tag("service:bicycle:repair", "yes")
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("bikeshop");
|
||||||
this.name = Translations.t.cyclofix.shop.name
|
this.name = Translations.t.cyclofix.shop.name
|
||||||
this.icon = "./assets/bike/repair_shop.svg"
|
this.icon = "./assets/bike/repair_shop.svg"
|
||||||
this.overpassFilter = new Tag("shop", "bicycle");
|
this.overpassFilter = new Tag("shop", "bicycle");
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default class BikeStations extends LayerDefinition {
|
||||||
private readonly to = Translations.t.cyclofix.station
|
private readonly to = Translations.t.cyclofix.station
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("bikestation");
|
||||||
this.name = Translations.t.cyclofix.station.name;
|
this.name = Translations.t.cyclofix.station.name;
|
||||||
this.icon = "./assets/bike/repair_station_pump.svg";
|
this.icon = "./assets/bike/repair_station_pump.svg";
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ export class Birdhide extends LayerDefinition {
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super("birdhide",{
|
||||||
name: "vogelkijkplaats",
|
name: "vogelkijkplaats",
|
||||||
description: "Een plaats om vogels te kijken, zoals een vogelkijkhut of kijkwand",
|
description: "Een plaats om vogels te kijken, zoals een vogelkijkhut of kijkwand",
|
||||||
overpassFilter: Birdhide.birdhide,
|
overpassFilter: Birdhide.birdhide,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import T from "../../UI/i18n/Translation";
|
||||||
export class Bookcases extends LayerDefinition {
|
export class Bookcases extends LayerDefinition {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("bookcases");
|
||||||
|
|
||||||
this.name = "boekenkast";
|
this.name = "boekenkast";
|
||||||
this.presets = [{
|
this.presets = [{
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi
|
||||||
export class Bos extends LayerDefinition {
|
export class Bos extends LayerDefinition {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("bos");
|
||||||
this.name = "Bos";
|
this.name = "Bos";
|
||||||
this.icon = "";
|
this.icon = "";
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ export class ClimbingTree extends LayerDefinition {
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("climbingtree");
|
||||||
const t = Translations.t.climbingTrees.layer;
|
const t = Translations.t.climbingTrees.layer;
|
||||||
this.title = new FixedText(t.title);
|
this.title = new FixedText(t.title);
|
||||||
const icon = "assets/walkbybrussels/tree.svg";
|
const icon = "assets/walkbybrussels/tree.svg";
|
||||||
|
|
|
@ -10,7 +10,7 @@ import Translations from "../../UI/i18n/Translations";
|
||||||
export class DrinkingWater extends LayerDefinition {
|
export class DrinkingWater extends LayerDefinition {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("drinkingwater");
|
||||||
this.name = Translations.t.cyclofix.drinking_water.title;
|
this.name = Translations.t.cyclofix.drinking_water.title;
|
||||||
this.icon = "./assets/bike/drinking_water.svg";
|
this.icon = "./assets/bike/drinking_water.svg";
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import L from "leaflet";
|
||||||
|
|
||||||
export class GhostBike extends LayerDefinition {
|
export class GhostBike extends LayerDefinition {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("ghost bike");
|
||||||
this.name = "ghost bike";
|
this.name = "ghost bike";
|
||||||
this.overpassFilter = new Tag("memorial", "ghost_bike")
|
this.overpassFilter = new Tag("memorial", "ghost_bike")
|
||||||
this.title = new FixedText("Ghost bike");
|
this.title = new FixedText("Ghost bike");
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {TagRenderingOptions} from "../TagRendering";
|
||||||
export class GrbToFix extends LayerDefinition {
|
export class GrbToFix extends LayerDefinition {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("grb");
|
||||||
|
|
||||||
this.name = "grb";
|
this.name = "grb";
|
||||||
this.presets = [];
|
this.presets = [];
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {And, Tag} from "../../Logic/TagsFilter";
|
||||||
|
|
||||||
export class InformationBoard extends LayerDefinition {
|
export class InformationBoard extends LayerDefinition {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super("informationBoard",{
|
||||||
name: "Informatiebord",
|
name: "Informatiebord",
|
||||||
description: "Een informatiebord of kaart",
|
description: "Een informatiebord of kaart",
|
||||||
minzoom: 12,
|
minzoom: 12,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {And, Tag} from "../../Logic/TagsFilter";
|
||||||
|
|
||||||
export class Map extends LayerDefinition {
|
export class Map extends LayerDefinition {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("map");
|
||||||
this.name = "Map";
|
this.name = "Map";
|
||||||
this.title = new FixedText("Map");
|
this.title = new FixedText("Map");
|
||||||
this.minzoom = 12;
|
this.minzoom = 12;
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi
|
||||||
export class NatureReserves extends LayerDefinition {
|
export class NatureReserves extends LayerDefinition {
|
||||||
|
|
||||||
constructor(moreQuests: boolean = false) {
|
constructor(moreQuests: boolean = false) {
|
||||||
super();
|
super("natureReserve");
|
||||||
this.name = "Natuurgebied";
|
this.name = "Natuurgebied";
|
||||||
this.icon = "";
|
this.icon = "";
|
||||||
this.overpassFilter =
|
this.overpassFilter =
|
||||||
|
|
|
@ -45,7 +45,7 @@ export class Park extends LayerDefinition {
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("park");
|
||||||
this.name = "Park";
|
this.name = "Park";
|
||||||
this.icon = undefined;
|
this.icon = undefined;
|
||||||
this.overpassFilter =
|
this.overpassFilter =
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {LayerDefinition} from "../LayerDefinition";
|
import {LayerDefinition} from "../LayerDefinition";
|
||||||
import {Quests} from "../../Quests";
|
|
||||||
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
|
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
|
||||||
import L from "leaflet";
|
import L from "leaflet";
|
||||||
import {Tag} from "../../Logic/TagsFilter";
|
import {Tag} from "../../Logic/TagsFilter";
|
||||||
|
@ -7,7 +6,7 @@ import {Tag} from "../../Logic/TagsFilter";
|
||||||
export class Toilets extends LayerDefinition{
|
export class Toilets extends LayerDefinition{
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super("toilets");
|
||||||
|
|
||||||
this.name="toilet";
|
this.name="toilet";
|
||||||
this.newElementTags = [new Tag( "amenity", "toilets")];
|
this.newElementTags = [new Tag( "amenity", "toilets")];
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {TagRenderingOptions} from "../TagRendering";
|
||||||
export class Viewpoint extends LayerDefinition {
|
export class Viewpoint extends LayerDefinition {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super("viewpoint",{
|
||||||
name: "Bezienswaardigheid",
|
name: "Bezienswaardigheid",
|
||||||
description: "Wil je een foto toevoegen van iets dat geen park, bos of natuurgebied is? Dit kan hiermee",
|
description: "Wil je een foto toevoegen van iets dat geen park, bos of natuurgebied is? Dit kan hiermee",
|
||||||
presets: [{
|
presets: [{
|
||||||
|
|
|
@ -113,7 +113,7 @@ export class Widths extends LayerDefinition {
|
||||||
constructor(carWidth: number,
|
constructor(carWidth: number,
|
||||||
cyclistWidth: number,
|
cyclistWidth: number,
|
||||||
pedestrianWidth: number) {
|
pedestrianWidth: number) {
|
||||||
super();
|
super("width");
|
||||||
this.carWidth = carWidth;
|
this.carWidth = carWidth;
|
||||||
this.cyclistWidth = cyclistWidth;
|
this.cyclistWidth = cyclistWidth;
|
||||||
this.pedestrianWidth = pedestrianWidth;
|
this.pedestrianWidth = pedestrianWidth;
|
||||||
|
|
93
Helpers.ts
93
Helpers.ts
|
@ -1,93 +0,0 @@
|
||||||
import {UIEventSource} from "./UI/UIEventSource";
|
|
||||||
import {Changes} from "./Logic/Osm/Changes";
|
|
||||||
import {State} from "./State";
|
|
||||||
|
|
||||||
export class Helpers {
|
|
||||||
|
|
||||||
static DoEvery(millis: number, f: (() => void)) {
|
|
||||||
window.setTimeout(
|
|
||||||
function () {
|
|
||||||
f();
|
|
||||||
Helpers.DoEvery(millis, f);
|
|
||||||
}
|
|
||||||
, millis)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static SetupAutoSave() {
|
|
||||||
|
|
||||||
const changes = State.state.changes;
|
|
||||||
const millisTillChangesAreSaved = State.state.secondsTillChangesAreSaved;
|
|
||||||
const saveAfterXMillis = State.state.secondsTillChangesAreSaved.data * 1000;
|
|
||||||
changes.pendingChangesES.addCallback(function () {
|
|
||||||
|
|
||||||
var c = changes.pendingChangesES.data;
|
|
||||||
if (c > 10) {
|
|
||||||
millisTillChangesAreSaved.setData(0);
|
|
||||||
changes.uploadAll(undefined);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c > 0) {
|
|
||||||
millisTillChangesAreSaved.setData(saveAfterXMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
millisTillChangesAreSaved.addCallback((time) => {
|
|
||||||
if (time <= 0 && changes.pendingChangesES.data > 0) {
|
|
||||||
changes.uploadAll(undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Helpers.DoEvery(
|
|
||||||
1000,
|
|
||||||
() => {
|
|
||||||
millisTillChangesAreSaved
|
|
||||||
.setData(millisTillChangesAreSaved.data - 1000)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Registers an action that:
|
|
||||||
* -> Upload everything to OSM
|
|
||||||
* -> Asks the user not to close. The 'not to close' dialog should profide enough time to upload
|
|
||||||
* -> WHen uploading is done, the window is closed anyway
|
|
||||||
*/
|
|
||||||
static LastEffortSave() {
|
|
||||||
const changes = State.state.changes;
|
|
||||||
window.addEventListener("beforeunload", function (e) {
|
|
||||||
// Quickly save everyting!
|
|
||||||
if (changes.pendingChangesES.data == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
changes.uploadAll(function () {
|
|
||||||
window.close()
|
|
||||||
});
|
|
||||||
var confirmationMessage = "Nog even geduld - je laatset wijzigingen worden opgeslaan!";
|
|
||||||
|
|
||||||
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
|
||||||
return confirmationMessage; //Webkit, Safari, Chrome
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('visibilitychange',() => {
|
|
||||||
if(document.visibilityState === "visible"){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (changes.pendingChangesES.data == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Upmoading: loss of focus")
|
|
||||||
changes.uploadAll(function () {
|
|
||||||
window.close()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,9 +16,13 @@ import {ElementStorage} from "./Logic/ElementStorage";
|
||||||
import {Preset} from "./UI/SimpleAddUI";
|
import {Preset} from "./UI/SimpleAddUI";
|
||||||
import {Changes} from "./Logic/Osm/Changes";
|
import {Changes} from "./Logic/Osm/Changes";
|
||||||
import {OsmConnection} from "./Logic/Osm/OsmConnection";
|
import {OsmConnection} from "./Logic/Osm/OsmConnection";
|
||||||
import {Basemap} from "./Logic/Leaflet/Basemap";
|
import {BaseLayers, Basemap} from "./Logic/Leaflet/Basemap";
|
||||||
import {State} from "./State";
|
import {State} from "./State";
|
||||||
import {WelcomeMessage} from "./UI/WelcomeMessage";
|
import {WelcomeMessage} from "./UI/WelcomeMessage";
|
||||||
|
import {Img} from "./UI/Img";
|
||||||
|
import {DropDown} from "./UI/Input/DropDown";
|
||||||
|
import {LayerSelection} from "./UI/LayerSelection";
|
||||||
|
import {CustomLayersPanel} from "./Logic/CustomLayersPanel";
|
||||||
|
|
||||||
export class InitUiElements {
|
export class InitUiElements {
|
||||||
|
|
||||||
|
@ -47,7 +51,8 @@ export class InitUiElements {
|
||||||
{header: `<img src='${layoutToUse.icon}'>`, content: welcome},
|
{header: `<img src='${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},
|
||||||
{header: `<img src='${'./assets/share.svg'}'>`, content: new ShareScreen()},
|
{header: `<img src='${'./assets/share.svg'}'>`, content: new ShareScreen()},
|
||||||
{header: `<img src='${'./assets/add.svg'}'>`, content: new MoreScreen()}
|
{header: `<img src='${'./assets/add.svg'}'>`, content: new MoreScreen()},
|
||||||
|
{header: `<img src='${'./assets/star.svg'}'>`, content: new CustomLayersPanel()},
|
||||||
])
|
])
|
||||||
|
|
||||||
return fullOptions;
|
return fullOptions;
|
||||||
|
@ -89,14 +94,38 @@ export class InitUiElements {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static InitLayerSelection(layerSetup) {
|
||||||
|
const closedFilterButton = `<button id="filter__button" class="filter__button shadow">${Img.closedFilterButton}</button>`;
|
||||||
|
|
||||||
|
const openFilterButton = `<button id="filter__button" class="filter__button">${Img.openFilterButton}</button>`;
|
||||||
|
|
||||||
|
let baseLayerOptions = BaseLayers.baseLayers.map((layer) => {
|
||||||
|
return {value: layer, shown: layer.name}
|
||||||
|
});
|
||||||
|
const backgroundMapPicker = new Combine([new DropDown(`Background map`, baseLayerOptions, State.state.bm.CurrentLayer), openFilterButton]);
|
||||||
|
const layerSelection = new Combine([`<p class="filter__label">Maplayers</p>`, new LayerSelection(layerSetup.flayers)]);
|
||||||
|
let layerControl = backgroundMapPicker;
|
||||||
|
if (layerSetup.flayers.length > 1) {
|
||||||
|
layerControl = new Combine([layerSelection, backgroundMapPicker]);
|
||||||
|
}
|
||||||
|
|
||||||
|
InitUiElements.OnlyIf(State.state.featureSwitchLayers, () => {
|
||||||
|
|
||||||
|
const checkbox = new CheckBox(layerControl, closedFilterButton);
|
||||||
|
checkbox.AttachTo("filter__selection");
|
||||||
|
State.state.bm.Location.addCallback(() => {
|
||||||
|
checkbox.isEnabled.setData(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static InitLayers(): {
|
static InitLayers(): {
|
||||||
minZoom: number
|
minZoom: number
|
||||||
flayers: FilteredLayer[],
|
flayers: FilteredLayer[],
|
||||||
presets: Preset[]
|
presets: Preset[]
|
||||||
} {
|
} {
|
||||||
const addButtons: Preset[]
|
const addButtons: Preset[] = [];
|
||||||
= [];
|
|
||||||
|
|
||||||
const flayers: FilteredLayer[] = []
|
const flayers: FilteredLayer[] = []
|
||||||
|
|
||||||
|
|
26
Logic/CustomLayers.ts
Normal file
26
Logic/CustomLayers.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import {Layout} from "../Customizations/Layout";
|
||||||
|
import Translations from "../UI/i18n/Translations";
|
||||||
|
|
||||||
|
export class CustomLayers extends Layout {
|
||||||
|
|
||||||
|
public static NAME: string = "personal";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(
|
||||||
|
CustomLayers.NAME,
|
||||||
|
["en"],
|
||||||
|
Translations.t.favourite.title,
|
||||||
|
[],
|
||||||
|
12,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
Translations.t.favourite.description,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.icon = "./assets/star.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
96
Logic/CustomLayersPanel.ts
Normal file
96
Logic/CustomLayersPanel.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import {UIElement} from "../UI/UIElement";
|
||||||
|
import {State} from "../State";
|
||||||
|
import Translations from "../UI/i18n/Translations";
|
||||||
|
import {UIEventSource} from "../UI/UIEventSource";
|
||||||
|
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
|
||||||
|
import Combine from "../UI/Base/Combine";
|
||||||
|
import {Img} from "../UI/Img";
|
||||||
|
import {CheckBox} from "../UI/Input/CheckBox";
|
||||||
|
import {CustomLayersState} from "./CustomLayersState";
|
||||||
|
import {VerticalCombine} from "../UI/Base/VerticalCombine";
|
||||||
|
import {FixedUiElement} from "../UI/Base/FixedUiElement";
|
||||||
|
|
||||||
|
export class CustomLayersPanel extends UIElement {
|
||||||
|
private checkboxes: UIElement[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(State.state.favourteLayers);
|
||||||
|
this.ListenTo(State.state.osmConnection.userDetails);
|
||||||
|
|
||||||
|
|
||||||
|
const t = Translations.t.favourite;
|
||||||
|
|
||||||
|
this.checkboxes = [];
|
||||||
|
const controls = new Map<string, UIEventSource<boolean>>();
|
||||||
|
const favs = State.state.favourteLayers.data;
|
||||||
|
for (const layout of AllKnownLayouts.layoutsList) {
|
||||||
|
|
||||||
|
const header =
|
||||||
|
new Combine([
|
||||||
|
`<div class="custom-layer-panel-header-img"><img src='${layout.icon}'></div>`,
|
||||||
|
"<span><b>",
|
||||||
|
layout.title,
|
||||||
|
"</b><br/>",
|
||||||
|
layout.description ?? "",
|
||||||
|
"</span>",
|
||||||
|
], 'custom-layer-panel-header')
|
||||||
|
this.checkboxes.push(header);
|
||||||
|
|
||||||
|
for (const layer of layout.layers) {
|
||||||
|
const image = (layer.icon ? `<img src='${layer.icon}'>` : Img.checkmark);
|
||||||
|
const cb = new CheckBox(
|
||||||
|
new Combine([
|
||||||
|
image,
|
||||||
|
"<b>", layer.name ?? "", "</b> ", layer.description ?? ""
|
||||||
|
]),
|
||||||
|
new Combine([
|
||||||
|
"<span style='opacity: 0'>",
|
||||||
|
image, "</span>", "<b>", layer.name ?? "", "</b> ", layer.description ?? ""
|
||||||
|
]),
|
||||||
|
controls[layer.id] ?? (favs.indexOf(layer.id) >= 0)
|
||||||
|
);
|
||||||
|
cb.clss = "custom-layer-checkbox"
|
||||||
|
controls[layer.id] = cb.isEnabled;
|
||||||
|
|
||||||
|
cb.isEnabled.addCallback((isEnabled) => {
|
||||||
|
if (isEnabled) {
|
||||||
|
CustomLayersState.AddFavouriteLayer(layer.id)
|
||||||
|
} else {
|
||||||
|
CustomLayersState.RemoveFavouriteLayer(layer.id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.checkboxes.push(cb);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
State.state.favourteLayers.addCallback((layers) => {
|
||||||
|
for (const layerId of layers) {
|
||||||
|
controls[layerId].setData(true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerRender(): string {
|
||||||
|
const t = Translations.t.favourite;
|
||||||
|
const userDetails = State.state.osmConnection.userDetails.data;
|
||||||
|
if(!userDetails.loggedIn){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(userDetails.csCount <= 100){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VerticalCombine([
|
||||||
|
t.panelIntro,
|
||||||
|
new FixedUiElement("<a href='./index.html?layout=personal'>GO</a>"),
|
||||||
|
...this.checkboxes
|
||||||
|
], "custom-layer-panel").Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
94
Logic/CustomLayersState.ts
Normal file
94
Logic/CustomLayersState.ts
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import {State} from "../State";
|
||||||
|
|
||||||
|
export class CustomLayersState {
|
||||||
|
static RemoveFavouriteLayer(layer: string) {
|
||||||
|
|
||||||
|
const favs = State.state.favourteLayers.data;
|
||||||
|
const ind = favs.indexOf(layer);
|
||||||
|
if (ind < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("REmovign fav layer", layer);
|
||||||
|
favs.splice(ind, 1);
|
||||||
|
State.state.favourteLayers.ping();
|
||||||
|
|
||||||
|
const osmConnection = State.state.osmConnection;
|
||||||
|
const count = osmConnection.GetPreference("mapcomplete-custom-layer-count");
|
||||||
|
if (favs.length === 0) {
|
||||||
|
count.setData("0")
|
||||||
|
} else if (count.data === undefined || isNaN(Number(count.data))) {
|
||||||
|
count.data = "0";
|
||||||
|
}
|
||||||
|
const lastId = Number(count.data);
|
||||||
|
|
||||||
|
for (let i = 0; i < lastId; i++) {
|
||||||
|
const layerIDescr = osmConnection.GetPreference("mapcomplete-custom-layer-" + i);
|
||||||
|
if (layerIDescr.data === layer) {
|
||||||
|
// We found the value to remove - mark with a tombstone
|
||||||
|
layerIDescr.setData("-");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AddFavouriteLayer(layer: string) {
|
||||||
|
const favs = State.state.favourteLayers.data;
|
||||||
|
const ind = favs.indexOf(layer);
|
||||||
|
if (ind >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("Adding fav layer", layer);
|
||||||
|
favs.push(layer);
|
||||||
|
State.state.favourteLayers.ping();
|
||||||
|
|
||||||
|
|
||||||
|
const osmConnection = State.state.osmConnection;
|
||||||
|
const count = osmConnection.GetPreference("mapcomplete-custom-layer-count");
|
||||||
|
if (count.data === undefined || isNaN(Number(count.data))) {
|
||||||
|
count.data = "0";
|
||||||
|
}
|
||||||
|
const lastId = Number(count.data);
|
||||||
|
|
||||||
|
for (let i = 0; i < lastId; i++) {
|
||||||
|
const layerIDescr = osmConnection.GetPreference("mapcomplete-custom-layer-" + i);
|
||||||
|
if (layerIDescr.data === undefined || layerIDescr.data === "-") {
|
||||||
|
// An earlier item was removed -> overwrite it
|
||||||
|
layerIDescr.setData(layer);
|
||||||
|
count.ping();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No empty slot found -> create a new one
|
||||||
|
const layerIDescr = osmConnection.GetPreference("mapcomplete-custom-layer-" + lastId);
|
||||||
|
layerIDescr.setData(layer);
|
||||||
|
count.setData((lastId + 1) + "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static InitFavouriteLayer() {
|
||||||
|
const osmConnection = State.state.osmConnection;
|
||||||
|
const count = osmConnection.GetPreference("mapcomplete-custom-layer-count");
|
||||||
|
const favs = State.state.favourteLayers.data;
|
||||||
|
let changed = false;
|
||||||
|
count.addCallback((countStr) => {
|
||||||
|
if (countStr === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let countI = Number(countStr);
|
||||||
|
if (isNaN(countI)) {
|
||||||
|
countI = 999;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < countI; i++) {
|
||||||
|
const layerId = osmConnection.GetPreference("mapcomplete-custom-layer-" + i).data;
|
||||||
|
if (layerId !== undefined && layerId !== "-" && favs.indexOf(layerId) < 0) {
|
||||||
|
State.state.favourteLayers.data.push(layerId);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
State.state.favourteLayers.ping();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import L from "leaflet";
|
import L from "leaflet";
|
||||||
import {UIEventSource} from "../../UI/UIEventSource";
|
import {UIEventSource} from "../../UI/UIEventSource";
|
||||||
import {UIElement} from "../../UI/UIElement";
|
import {UIElement} from "../../UI/UIElement";
|
||||||
import {Helpers} from "../../Helpers";
|
|
||||||
import {State} from "../../State";
|
import {State} from "../../State";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export class GeoLocationHandler extends UIElement {
|
export class GeoLocationHandler extends UIElement {
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ export class GeoLocationHandler extends UIElement {
|
||||||
|
|
||||||
if (!self._isActive.data) {
|
if (!self._isActive.data) {
|
||||||
self._isActive.setData(true);
|
self._isActive.setData(true);
|
||||||
Helpers.DoEvery(60000, () => {
|
Utils.DoEvery(60000, () => {
|
||||||
|
|
||||||
if (document.visibilityState !== "visible") {
|
if (document.visibilityState !== "visible") {
|
||||||
console.log("Not starting gps: document not visible")
|
console.log("Not starting gps: document not visible")
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {OsmNode, OsmObject} from "./OsmObject";
|
||||||
import {And, Tag, TagsFilter} from "../TagsFilter";
|
import {And, Tag, TagsFilter} from "../TagsFilter";
|
||||||
import {ElementStorage} from "../ElementStorage";
|
import {ElementStorage} from "../ElementStorage";
|
||||||
import {State} from "../../State";
|
import {State} from "../../State";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export class Changes {
|
export class Changes {
|
||||||
|
|
||||||
|
@ -22,9 +23,11 @@ export class Changes {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
changesetComment: string,
|
changesetComment: string,
|
||||||
login: OsmConnection,
|
state: State) {
|
||||||
allElements: ElementStorage) {
|
|
||||||
this._changesetComment = changesetComment;
|
this._changesetComment = changesetComment;
|
||||||
|
|
||||||
|
this.SetupAutoSave(state);
|
||||||
|
this.LastEffortSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
addTag(elementId: string, tagsFilter : TagsFilter){
|
addTag(elementId: string, tagsFilter : TagsFilter){
|
||||||
|
@ -52,7 +55,6 @@ export class Changes {
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
addChange(elementId: string, key: string, value: string) {
|
addChange(elementId: string, key: string, value: string) {
|
||||||
console.log("Received change",key, value)
|
|
||||||
if (key === undefined || key === null) {
|
if (key === undefined || key === null) {
|
||||||
console.log("Invalid key");
|
console.log("Invalid key");
|
||||||
return;
|
return;
|
||||||
|
@ -256,5 +258,78 @@ console.log("Received change",key, value)
|
||||||
optionalContinuationWrapped);
|
optionalContinuationWrapped);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registers an action that:
|
||||||
|
* -> Upload everything to OSM
|
||||||
|
* -> Asks the user not to close. The 'not to close' dialog should profide enough time to upload
|
||||||
|
* -> WHen uploading is done, the window is closed anyway
|
||||||
|
*/
|
||||||
|
private LastEffortSave() {
|
||||||
|
const self = this;
|
||||||
|
window.addEventListener("beforeunload", function (e) {
|
||||||
|
// Quickly save everyting!
|
||||||
|
if (self.pendingChangesES.data == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
self.uploadAll(function () {
|
||||||
|
window.close()
|
||||||
|
});
|
||||||
|
var confirmationMessage = "Nog even geduld - je laatset wijzigingen worden opgeslaan!";
|
||||||
|
|
||||||
|
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
||||||
|
return confirmationMessage; //Webkit, Safari, Chrome
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (document.visibilityState === "visible") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.pendingChangesES.data == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Upmoading: loss of focus")
|
||||||
|
this.uploadAll(function () {
|
||||||
|
window.close()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private SetupAutoSave(state: State) {
|
||||||
|
|
||||||
|
const millisTillChangesAreSaved = state.secondsTillChangesAreSaved;
|
||||||
|
const saveAfterXMillis = state.secondsTillChangesAreSaved.data * 1000;
|
||||||
|
this.pendingChangesES.addCallback(function () {
|
||||||
|
|
||||||
|
var c = this.pendingChangesES.data;
|
||||||
|
if (c > 10) {
|
||||||
|
millisTillChangesAreSaved.setData(0);
|
||||||
|
this.uploadAll(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c > 0) {
|
||||||
|
millisTillChangesAreSaved.setData(saveAfterXMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
millisTillChangesAreSaved.addCallback((time) => {
|
||||||
|
if (time <= 0 && this.pendingChangesES.data > 0) {
|
||||||
|
this.uploadAll(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Utils.DoEvery(
|
||||||
|
1000,
|
||||||
|
() => {
|
||||||
|
millisTillChangesAreSaved
|
||||||
|
.setData(millisTillChangesAreSaved.data - 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import osmAuth from "osm-auth";
|
import osmAuth from "osm-auth";
|
||||||
import {UIEventSource} from "../../UI/UIEventSource";
|
import {UIEventSource} from "../../UI/UIEventSource";
|
||||||
|
import {CustomLayersState} from "../CustomLayersState";
|
||||||
|
|
||||||
export class UserDetails {
|
export class UserDetails {
|
||||||
|
|
||||||
|
@ -215,6 +216,7 @@ export class OsmConnection {
|
||||||
self.preferences.data[k] = v;
|
self.preferences.data[k] = v;
|
||||||
}
|
}
|
||||||
self.preferences.ping();
|
self.preferences.ping();
|
||||||
|
CustomLayersState.InitFavouriteLayer();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ export class QueryParameters {
|
||||||
|
|
||||||
public static GetQueryParameter(key: string, deflt: string): UIEventSource<string> {
|
public static GetQueryParameter(key: string, deflt: string): UIEventSource<string> {
|
||||||
if (deflt !== undefined) {
|
if (deflt !== undefined) {
|
||||||
console.log(key, "-->", deflt)
|
|
||||||
QueryParameters.defaults[key] = deflt;
|
QueryParameters.defaults[key] = deflt;
|
||||||
}
|
}
|
||||||
if (QueryParameters.knownSources[key] !== undefined) {
|
if (QueryParameters.knownSources[key] !== undefined) {
|
||||||
|
|
61
State.ts
61
State.ts
|
@ -9,6 +9,10 @@ import {ElementStorage} from "./Logic/ElementStorage";
|
||||||
import {Changes} from "./Logic/Osm/Changes";
|
import {Changes} from "./Logic/Osm/Changes";
|
||||||
import {Basemap} from "./Logic/Leaflet/Basemap";
|
import {Basemap} from "./Logic/Leaflet/Basemap";
|
||||||
import {OsmConnection} from "./Logic/Osm/OsmConnection";
|
import {OsmConnection} from "./Logic/Osm/OsmConnection";
|
||||||
|
import Locale from "./UI/i18n/Locale";
|
||||||
|
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
||||||
|
import Translations from "./UI/i18n/Translations";
|
||||||
|
import {CustomLayersState} from "./Logic/CustomLayersState";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the global state: a bunch of UI-event sources
|
* Contains the global state: a bunch of UI-event sources
|
||||||
|
@ -95,6 +99,11 @@ export class State {
|
||||||
// After this many milliseconds without changes, saves are sent of to OSM
|
// After this many milliseconds without changes, saves are sent of to OSM
|
||||||
public readonly saveTimeout = new UIEventSource<number>(30 * 1000);
|
public readonly saveTimeout = new UIEventSource<number>(30 * 1000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layers can be marked as favourites, they show up in a custom layout
|
||||||
|
*/
|
||||||
|
public favourteLayers: UIEventSource<string[]> = new UIEventSource<string[]>([])
|
||||||
|
|
||||||
|
|
||||||
constructor(layoutToUse: Layout) {
|
constructor(layoutToUse: Layout) {
|
||||||
this.layoutToUse = new UIEventSource<Layout>(layoutToUse);
|
this.layoutToUse = new UIEventSource<Layout>(layoutToUse);
|
||||||
|
@ -130,5 +139,57 @@ export class State {
|
||||||
this.featureSwitchIframe = featSw("fs-iframe", () => false);
|
this.featureSwitchIframe = featSw("fs-iframe", () => false);
|
||||||
|
|
||||||
|
|
||||||
|
this.osmConnection = new OsmConnection(
|
||||||
|
QueryParameters.GetQueryParameter("test", "false").data === "true",
|
||||||
|
QueryParameters.GetQueryParameter("oauth_token", undefined)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
Locale.language.syncWith(this.osmConnection.GetPreference("language"));
|
||||||
|
|
||||||
|
|
||||||
|
Locale.language.addCallback((currentLanguage) => {
|
||||||
|
if (layoutToUse.supportedLanguages.indexOf(currentLanguage) < 0) {
|
||||||
|
console.log("Resetting languate to", layoutToUse.supportedLanguages[0], "as", currentLanguage, " is unsupported")
|
||||||
|
// The current language is not supported -> switch to a supported one
|
||||||
|
Locale.language.setData(layoutToUse.supportedLanguages[0]);
|
||||||
|
}
|
||||||
|
}).ping()
|
||||||
|
|
||||||
|
document.title = Translations.W(layoutToUse.title).InnerRender();
|
||||||
|
Locale.language.addCallback(e => {
|
||||||
|
document.title = Translations.W(layoutToUse.title).InnerRender();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
this.allElements = new ElementStorage();
|
||||||
|
this.changes = new Changes(
|
||||||
|
"Beantwoorden van vragen met #MapComplete voor vragenset #" + this.layoutToUse.data.name,
|
||||||
|
this);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (document.getElementById("leafletDiv") === null) {
|
||||||
|
console.warn("leafletDiv not found - not initializing map. Assuming test.html");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bm = new Basemap("leafletDiv", this.locationControl, new VariableUiElement(
|
||||||
|
this.locationControl.map((location) => {
|
||||||
|
const mapComplete = "<a href='https://github.com/pietervdvn/MapComplete' target='_blank'>Mapcomple</a> " +
|
||||||
|
" " +
|
||||||
|
"<a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'><img src='./assets/bug.svg' alt='Report bug' class='small-userbadge-icon'></a>";
|
||||||
|
let editHere = "";
|
||||||
|
if (location !== undefined) {
|
||||||
|
editHere = " | " +
|
||||||
|
"<a href='https://www.openstreetmap.org/edit?editor=id#map=" + location.zoom + "/" + location.lat + "/" + location.lon + "' target='_blank'>" +
|
||||||
|
"<img src='./assets/pencil.svg' alt='edit here' class='small-userbadge-icon'>" +
|
||||||
|
"</a>"
|
||||||
|
}
|
||||||
|
return mapComplete + editHere;
|
||||||
|
|
||||||
|
})
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,10 +3,12 @@ import Translations from "../i18n/Translations";
|
||||||
|
|
||||||
export default class Combine extends UIElement {
|
export default class Combine extends UIElement {
|
||||||
private uiElements: (string | UIElement)[];
|
private uiElements: (string | UIElement)[];
|
||||||
|
private className: string = undefined;
|
||||||
private clas: string = undefined;
|
private clas: string = undefined;
|
||||||
|
|
||||||
constructor(uiElements: (string | UIElement)[]) {
|
constructor(uiElements: (string | UIElement)[], className: string = undefined) {
|
||||||
super(undefined);
|
super(undefined);
|
||||||
|
this.className = className;
|
||||||
this.uiElements = uiElements;
|
this.uiElements = uiElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +21,10 @@ export default class Combine extends UIElement {
|
||||||
elements += element;
|
elements += element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(this.className !== undefined){
|
||||||
|
elements = `<span class='${this.className}'>${elements}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
UI/Base/Image.ts
Normal file
20
UI/Base/Image.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import {UIElement} from "../UIElement";
|
||||||
|
|
||||||
|
|
||||||
|
export class Image extends UIElement{
|
||||||
|
private src: string;
|
||||||
|
private style: string = "";
|
||||||
|
constructor(src: string, style: string = "") {
|
||||||
|
super(undefined);
|
||||||
|
this.style = style;
|
||||||
|
this.src = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerRender(): string {
|
||||||
|
if(this.src === undefined){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return `<img src='${this.src}' style='${this.style}'>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -27,8 +27,10 @@ export class TabbedComponent extends UIElement {
|
||||||
for (let i = 0; i < this.headers.length; i++) {
|
for (let i = 0; i < this.headers.length; i++) {
|
||||||
let header = this.headers[i];
|
let header = this.headers[i];
|
||||||
|
|
||||||
headerBar += `<div class=\'tab-single-header ${i == this._source.data ? 'tab-active' : 'tab-non-active'}\'>` +
|
if (!this.content[i].IsEmpty()) {
|
||||||
header.Render() + "</div>"
|
headerBar += `<div class=\'tab-single-header ${i == this._source.data ? 'tab-active' : 'tab-non-active'}\'>` +
|
||||||
|
header.Render() + "</div>"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ export class SimpleAddUI extends UIElement {
|
||||||
const self = this;
|
const self = this;
|
||||||
return () => {
|
return () => {
|
||||||
|
|
||||||
const loc = State.state.bm.lastClickLocation.data;
|
const loc = State.state.bm.LastClickLocation.data;
|
||||||
let feature = State.state.changes.createElement(option.tags, loc.lat, loc.lon);
|
let feature = State.state.changes.createElement(option.tags, loc.lat, loc.lon);
|
||||||
option.layerToAddTo.AddNewElement(feature);
|
option.layerToAddTo.AddNewElement(feature);
|
||||||
State.state.selectedElement.setData({feature: feature});
|
State.state.selectedElement.setData({feature: feature});
|
||||||
|
@ -107,7 +107,7 @@ export class SimpleAddUI extends UIElement {
|
||||||
|
|
||||||
if(userDetails.data.dryRun){
|
if(userDetails.data.dryRun){
|
||||||
this.CreatePoint(this._confirmPreset.data)();
|
this.CreatePoint(this._confirmPreset.data)();
|
||||||
return;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Combine([
|
return new Combine([
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {Basemap} from "../Logic/Leaflet/Basemap";
|
||||||
import {State} from "../State";
|
import {State} from "../State";
|
||||||
import {PendingChanges} from "./PendingChanges";
|
import {PendingChanges} from "./PendingChanges";
|
||||||
import Locale from "./i18n/Locale";
|
import Locale from "./i18n/Locale";
|
||||||
|
import {Utils} from "../Utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles and updates the user badge
|
* Handles and updates the user badge
|
||||||
|
@ -25,7 +26,7 @@ export class UserBadge extends UIElement {
|
||||||
super(State.state.osmConnection.userDetails);
|
super(State.state.osmConnection.userDetails);
|
||||||
this._userDetails = State.state.osmConnection.userDetails;
|
this._userDetails = State.state.osmConnection.userDetails;
|
||||||
this._pendingChanges = new PendingChanges();
|
this._pendingChanges = new PendingChanges();
|
||||||
this._languagePicker = Locale.CreateLanguagePicker();
|
this._languagePicker = Utils.CreateLanguagePicker();
|
||||||
|
|
||||||
this._logout = new FixedUiElement("<img src='assets/logout.svg' class='small-userbadge-icon' alt='logout'>")
|
this._logout = new FixedUiElement("<img src='assets/logout.svg' class='small-userbadge-icon' alt='logout'>")
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {State} from "../State";
|
||||||
import {Layout} from "../Customizations/Layout";
|
import {Layout} from "../Customizations/Layout";
|
||||||
import Translations from "./i18n/Translations";
|
import Translations from "./i18n/Translations";
|
||||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||||
|
import {Utils} from "../Utils";
|
||||||
|
|
||||||
export class WelcomeMessage extends UIElement {
|
export class WelcomeMessage extends UIElement {
|
||||||
private readonly layout: Layout;
|
private readonly layout: Layout;
|
||||||
|
@ -20,7 +21,7 @@ export class WelcomeMessage extends UIElement {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(State.state.osmConnection.userDetails);
|
super(State.state.osmConnection.userDetails);
|
||||||
this.languagePicker = Locale.CreateLanguagePicker(Translations.t.general.pickLanguage);
|
this.languagePicker = Utils.CreateLanguagePicker(Translations.t.general.pickLanguage);
|
||||||
this.ListenTo(Locale.language);
|
this.ListenTo(Locale.language);
|
||||||
|
|
||||||
function fromLayout(f: (layout: Layout) => (string | UIElement)): UIElement {
|
function fromLayout(f: (layout: Layout) => (string | UIElement)): UIElement {
|
||||||
|
|
|
@ -7,15 +7,17 @@ import {State} from "../../State";
|
||||||
|
|
||||||
|
|
||||||
export default class Locale {
|
export default class Locale {
|
||||||
public static language: UIEventSource<string> = LocalStorageSource.Get('language', "en");
|
|
||||||
|
|
||||||
public static CreateLanguagePicker(label: string | UIElement = "") {
|
public static language: UIEventSource<string> = Locale.setup();
|
||||||
|
private static setup() {
|
||||||
return new DropDown(label, State.state.layoutToUse.data.supportedLanguages.map(lang => {
|
const source = LocalStorageSource.Get('language', "en");
|
||||||
return {value: lang, shown: lang}
|
// @ts-ignore
|
||||||
}
|
window.setLanguage = function (language: string) {
|
||||||
), Locale.language);
|
source.setData(language)
|
||||||
|
}
|
||||||
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -793,8 +793,8 @@ export default class Translations {
|
||||||
|
|
||||||
}),
|
}),
|
||||||
header: new T({
|
header: new T({
|
||||||
en: "<h2>No data</h2>You clicked somewhere where no data is known yet.<br/>",
|
en: "<h2>Add a point?</h2>You clicked somewhere where no data is known yet.<br/>",
|
||||||
nl: "<h2>Geen selectie</h2>Je klikte ergens waar er nog geen data is.<br/>",
|
nl: "<h2>Punt toevoegen?</h2>Je klikte ergens waar er nog geen data is.<br/>",
|
||||||
fr: "<h2>Pas de données</h2> vous avez cliqué sur un endroit ou il n'y a pas encore de données. <br/>"
|
fr: "<h2>Pas de données</h2> vous avez cliqué sur un endroit ou il n'y a pas encore de données. <br/>"
|
||||||
|
|
||||||
}),
|
}),
|
||||||
|
@ -814,8 +814,8 @@ export default class Translations {
|
||||||
fr: "Chargement des donnés. Patientez un instant avant d'ajouter un nouveau point"
|
fr: "Chargement des donnés. Patientez un instant avant d'ajouter un nouveau point"
|
||||||
}),
|
}),
|
||||||
confirmIntro: new T({
|
confirmIntro: new T({
|
||||||
en: "<h3>Add a {title} here?</h3>The point you create here will be visible for everyone. Please, only add things on to the map if they truly exist. A lot of applications use this data.",
|
en: "<h3>Add a {title} here?</h3>The point you create here will be <b>visible for everyone</b>. Please, only add things on to the map if they truly exist. A lot of applications use this data.",
|
||||||
nl: "<h3>Voeg hier een {title} toe?</h3>Het punt dat je hier toevoegt, is zichtbaar voor iedereen. Veel applicaties gebruiken deze data, voeg dus enkel punten toe die echt bestaan.",
|
nl: "<h3>Voeg hier een {title} toe?</h3>Het punt dat je hier toevoegt, is <b>zichtbaar voor iedereen</b>. Veel applicaties gebruiken deze data, voeg dus enkel punten toe die echt bestaan.",
|
||||||
fr: "<h3>Ajouter un/une {title} ici?</h3>Le point que vous ajouter sera visible par tout le monde. Merci d'etre sûr que ce point existe réellement. Beaucoup d'autres applications reposent sur ces données.",
|
fr: "<h3>Ajouter un/une {title} ici?</h3>Le point que vous ajouter sera visible par tout le monde. Merci d'etre sûr que ce point existe réellement. Beaucoup d'autres applications reposent sur ces données.",
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -952,6 +952,16 @@ export default class Translations {
|
||||||
nl: "Ga naar de berichten",
|
nl: "Ga naar de berichten",
|
||||||
fr: "Ouvrir les messages"
|
fr: "Ouvrir les messages"
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
favourite: {
|
||||||
|
title: "Custom",
|
||||||
|
description: new T({
|
||||||
|
en: "<h3>Your custom theme</h3>In your custom theme, you can add some favourite layers from other themes to create a custom theme."
|
||||||
|
}),
|
||||||
|
panelIntro: new T({
|
||||||
|
en:"<h3>Your custom theme</h3>Create your own theme here by picking your favourite layers"
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
Utils.ts
23
Utils.ts
|
@ -1,3 +1,8 @@
|
||||||
|
import {UIElement} from "./UI/UIElement";
|
||||||
|
import {DropDown} from "./UI/Input/DropDown";
|
||||||
|
import {State} from "./State";
|
||||||
|
import Locale from "./UI/i18n/Locale";
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,4 +23,22 @@ export class Utils {
|
||||||
public static Upper(str : string){
|
public static Upper(str : string){
|
||||||
return str.substr(0,1).toUpperCase() + str.substr(1);
|
return str.substr(0,1).toUpperCase() + str.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DoEvery(millis: number, f: (() => void)) {
|
||||||
|
window.setTimeout(
|
||||||
|
function () {
|
||||||
|
f();
|
||||||
|
Utils.DoEvery(millis, f);
|
||||||
|
}
|
||||||
|
, millis)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CreateLanguagePicker(label: string | UIElement = "") {
|
||||||
|
|
||||||
|
return new DropDown(label, State.state.layoutToUse.data.supportedLanguages.map(lang => {
|
||||||
|
return {value: lang, shown: lang}
|
||||||
|
}
|
||||||
|
), Locale.language);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
61
index.css
61
index.css
|
@ -1241,4 +1241,65 @@ form {
|
||||||
|
|
||||||
.add-ui {
|
.add-ui {
|
||||||
font-size: large;
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.custom-layer-panel {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.custom-layer-panel-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: large;
|
||||||
|
margin: 0.5em;
|
||||||
|
background-color: white;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-layer-panel-header-img img {
|
||||||
|
max-width: 3em;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 3em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-layer-panel-header-img {
|
||||||
|
width: 4em;
|
||||||
|
height: 4em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-layer-checkbox {
|
||||||
|
font-size: larger;
|
||||||
|
height: 2em;
|
||||||
|
background-color: #e5f5ff;
|
||||||
|
margin:0.3em;
|
||||||
|
margin-left: 2em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
.custom-layer-checkbox img {
|
||||||
|
max-width: 1.5em;
|
||||||
|
max-height: 1.5em;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.2em;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-layer-checkbox svg {
|
||||||
|
max-width: 1.5em;
|
||||||
|
max-height: 1.5em;
|
||||||
|
padding: 0.2em;
|
||||||
|
padding-right: 0.5em;
|
||||||
}
|
}
|
156
index.ts
156
index.ts
|
@ -1,37 +1,21 @@
|
||||||
import {ElementStorage} from "./Logic/ElementStorage";
|
|
||||||
import {UIEventSource} from "./UI/UIEventSource";
|
|
||||||
import {UserBadge} from "./UI/UserBadge";
|
import {UserBadge} from "./UI/UserBadge";
|
||||||
import {PendingChanges} from "./UI/PendingChanges";
|
|
||||||
import {CenterMessageBox} from "./UI/CenterMessageBox";
|
import {CenterMessageBox} from "./UI/CenterMessageBox";
|
||||||
import {Helpers} from "./Helpers";
|
|
||||||
import {TagUtils} from "./Logic/TagsFilter";
|
import {TagUtils} from "./Logic/TagsFilter";
|
||||||
import {LayerUpdater} from "./Logic/LayerUpdater";
|
import {LayerUpdater} from "./Logic/LayerUpdater";
|
||||||
import {UIElement} from "./UI/UIElement";
|
|
||||||
import {FullScreenMessageBoxHandler} from "./UI/FullScreenMessageBoxHandler";
|
import {FullScreenMessageBoxHandler} from "./UI/FullScreenMessageBoxHandler";
|
||||||
import {FeatureInfoBox} from "./UI/FeatureInfoBox";
|
import {FeatureInfoBox} from "./UI/FeatureInfoBox";
|
||||||
import {SimpleAddUI} from "./UI/SimpleAddUI";
|
import {SimpleAddUI} from "./UI/SimpleAddUI";
|
||||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
|
||||||
import {SearchAndGo} from "./UI/SearchAndGo";
|
import {SearchAndGo} from "./UI/SearchAndGo";
|
||||||
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
||||||
import {CheckBox} from "./UI/Input/CheckBox";
|
|
||||||
import Translations from "./UI/i18n/Translations";
|
|
||||||
import Locale from "./UI/i18n/Locale";
|
|
||||||
import {Layout} from "./Customizations/Layout";
|
import {Layout} from "./Customizations/Layout";
|
||||||
import {DropDown} from "./UI/Input/DropDown";
|
|
||||||
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
||||||
import {LayerSelection} from "./UI/LayerSelection";
|
|
||||||
import Combine from "./UI/Base/Combine";
|
|
||||||
import {Img} from "./UI/Img";
|
|
||||||
import {QueryParameters} from "./Logic/QueryParameters";
|
import {QueryParameters} from "./Logic/QueryParameters";
|
||||||
import {Utils} from "./Utils";
|
|
||||||
import {LocalStorageSource} from "./Logic/LocalStorageSource";
|
|
||||||
import {InitUiElements} from "./InitUiElements";
|
import {InitUiElements} from "./InitUiElements";
|
||||||
import {StrayClickHandler} from "./Logic/Leaflet/StrayClickHandler";
|
import {StrayClickHandler} from "./Logic/Leaflet/StrayClickHandler";
|
||||||
import {BaseLayers, Basemap} from "./Logic/Leaflet/Basemap";
|
|
||||||
import {GeoLocationHandler} from "./Logic/Leaflet/GeoLocationHandler";
|
import {GeoLocationHandler} from "./Logic/Leaflet/GeoLocationHandler";
|
||||||
import {OsmConnection} from "./Logic/Osm/OsmConnection";
|
|
||||||
import {Changes} from "./Logic/Osm/Changes";
|
|
||||||
import {State} from "./State";
|
import {State} from "./State";
|
||||||
|
import {All} from "./Customizations/Layouts/All";
|
||||||
|
import {CustomLayers} from "./Logic/CustomLayers";
|
||||||
|
|
||||||
|
|
||||||
// --------------------- Special actions based on the parameters -----------------
|
// --------------------- Special actions based on the parameters -----------------
|
||||||
|
@ -79,114 +63,59 @@ 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"];
|
const layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout] ?? AllKnownLayouts["all"];
|
||||||
console.log("Using layout: ", layoutToUse.name);
|
|
||||||
if (layoutToUse === undefined) {
|
if (layoutToUse === undefined) {
|
||||||
console.log("Incorrect layout")
|
console.log("Incorrect layout")
|
||||||
|
new FixedUiElement("Error: incorrect layout " + defaultLayout + "<a href='https://pietervdvn.github.io/MapComplete/index.html'>Go to MapComplete</a>").AttachTo("centermessage").onClick(() => {
|
||||||
|
});
|
||||||
|
throw "Incorrect layout"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the global state
|
console.log("Using layout: ", layoutToUse.name);
|
||||||
|
|
||||||
State.state = new State(layoutToUse);
|
State.state = new State(layoutToUse);
|
||||||
const state = State.state;
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------- Prepare the important objects -----------------
|
|
||||||
state.osmConnection = new OsmConnection(
|
|
||||||
QueryParameters.GetQueryParameter("test", "false").data === "true",
|
|
||||||
QueryParameters.GetQueryParameter("oauth_token", undefined)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
Locale.language.syncWith(state.osmConnection.GetPreference("language"));
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
window.setLanguage = function (language: string) {
|
|
||||||
Locale.language.setData(language)
|
|
||||||
}
|
|
||||||
|
|
||||||
Locale.language.addCallback((currentLanguage) => {
|
|
||||||
if (layoutToUse.supportedLanguages.indexOf(currentLanguage) < 0) {
|
|
||||||
console.log("Resetting languate to", layoutToUse.supportedLanguages[0], "as", currentLanguage, " is unsupported")
|
|
||||||
// The current language is not supported -> switch to a supported one
|
|
||||||
Locale.language.setData(layoutToUse.supportedLanguages[0]);
|
|
||||||
}
|
|
||||||
}).ping()
|
|
||||||
|
|
||||||
|
|
||||||
state.allElements = new ElementStorage();
|
|
||||||
state.changes = new Changes(
|
|
||||||
"Beantwoorden van vragen met #MapComplete voor vragenset #" + state.layoutToUse.data.name,
|
|
||||||
state.osmConnection, state.allElements);
|
|
||||||
state.bm = new Basemap("leafletDiv", state.locationControl, new VariableUiElement(
|
|
||||||
state.locationControl.map((location) => {
|
|
||||||
const mapComplete = "<a href='https://github.com/pietervdvn/MapComplete' target='_blank'>Mapcomple</a> " +
|
|
||||||
" " +
|
|
||||||
"<a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'><img src='./assets/bug.svg' alt='Report bug' class='small-userbadge-icon'></a>";
|
|
||||||
let editHere = "";
|
|
||||||
if (location !== undefined) {
|
|
||||||
editHere = " | " +
|
|
||||||
"<a href='https://www.openstreetmap.org/edit?editor=id#map=" + location.zoom + "/" + location.lat + "/" + location.lon + "' target='_blank'>" +
|
|
||||||
"<img src='./assets/pencil.svg' alt='edit here' class='small-userbadge-icon'>" +
|
|
||||||
"</a>"
|
|
||||||
}
|
|
||||||
return mapComplete + editHere;
|
|
||||||
|
|
||||||
})
|
|
||||||
));
|
|
||||||
|
|
||||||
|
|
||||||
|
function setupAllLayerElements() {
|
||||||
|
|
||||||
// ------------- Setup the layers -------------------------------
|
// ------------- Setup the layers -------------------------------
|
||||||
|
|
||||||
const layerSetup = InitUiElements.InitLayers();
|
const layerSetup = InitUiElements.InitLayers();
|
||||||
|
|
||||||
const layerUpdater = new LayerUpdater(layerSetup.minZoom, layoutToUse.widenFactor, layerSetup.flayers);
|
const layerUpdater = new LayerUpdater(layerSetup.minZoom, layoutToUse.widenFactor, layerSetup.flayers);
|
||||||
|
InitUiElements.InitLayerSelection(layerSetup)
|
||||||
|
|
||||||
// --------------- Setting up layer selection ui --------
|
|
||||||
|
|
||||||
const closedFilterButton = `<button id="filter__button" class="filter__button shadow">${Img.closedFilterButton}</button>`;
|
|
||||||
|
|
||||||
const openFilterButton = `
|
|
||||||
<button id="filter__button" class="filter__button">${Img.openFilterButton}</button>`;
|
|
||||||
|
|
||||||
let baseLayerOptions = BaseLayers.baseLayers.map((layer) => {
|
|
||||||
return {value: layer, shown: layer.name}
|
|
||||||
});
|
|
||||||
const backgroundMapPicker = new Combine([new DropDown(`Background map`, baseLayerOptions, State.state.bm.CurrentLayer), openFilterButton]);
|
|
||||||
const layerSelection = new Combine([`<p class="filter__label">Maplayers</p>`, new LayerSelection(layerSetup.flayers)]);
|
|
||||||
let layerControl = backgroundMapPicker;
|
|
||||||
if (layerSetup.flayers.length > 1) {
|
|
||||||
layerControl = new Combine([layerSelection, backgroundMapPicker]);
|
|
||||||
}
|
|
||||||
|
|
||||||
InitUiElements.OnlyIf(State.state.featureSwitchLayers, () => {
|
|
||||||
|
|
||||||
const checkbox = new CheckBox(layerControl, closedFilterButton);
|
|
||||||
checkbox.AttachTo("filter__selection");
|
|
||||||
State.state.bm.Location.addCallback(() => {
|
|
||||||
checkbox.isEnabled.setData(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------ Setup various other UI elements ------------
|
// ------------------ Setup various other UI elements ------------
|
||||||
|
|
||||||
document.title = Translations.W(layoutToUse.title).InnerRender();
|
|
||||||
|
|
||||||
Locale.language.addCallback(e => {
|
InitUiElements.OnlyIf(State.state.featureSwitchAddNew, () => {
|
||||||
document.title = Translations.W(layoutToUse.title).InnerRender();
|
new StrayClickHandler(() => {
|
||||||
})
|
return new SimpleAddUI(
|
||||||
|
layerUpdater.runningQuery,
|
||||||
|
layerSetup.presets);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
new CenterMessageBox(
|
||||||
|
layerSetup.minZoom,
|
||||||
|
layerUpdater.runningQuery)
|
||||||
|
.AttachTo("centermessage");
|
||||||
|
|
||||||
InitUiElements.OnlyIf(State.state.featureSwitchAddNew, () => {
|
}
|
||||||
new StrayClickHandler(() => {
|
|
||||||
return new SimpleAddUI(
|
setupAllLayerElements();
|
||||||
layerUpdater.runningQuery,
|
|
||||||
layerSetup.presets);
|
if (layoutToUse === AllKnownLayouts.allSets[CustomLayers.NAME]) {
|
||||||
|
State.state.favourteLayers.addCallback((favs) => {
|
||||||
|
for (const fav of favs) {
|
||||||
|
const layer = AllKnownLayouts.allLayers[fav];
|
||||||
|
if (!!layer) {
|
||||||
|
layoutToUse.layers.push(layer);
|
||||||
|
}
|
||||||
|
setupAllLayerElements();
|
||||||
}
|
}
|
||||||
);
|
})
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -219,7 +148,6 @@ State.state.selectedElement.addCallback((feature) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Enable new:",State.state.featureSwitchAddNew.data,"deafult", layoutToUse.enableAdd)
|
|
||||||
InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => {
|
InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => {
|
||||||
new UserBadge().AttachTo('userbadge');
|
new UserBadge().AttachTo('userbadge');
|
||||||
});
|
});
|
||||||
|
@ -241,16 +169,6 @@ if ((window != window.top && !State.state.featureSwitchWelcomeMessage) || State.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
new CenterMessageBox(
|
|
||||||
layerSetup.minZoom,
|
|
||||||
layerUpdater.runningQuery)
|
|
||||||
.AttachTo("centermessage");
|
|
||||||
|
|
||||||
|
|
||||||
Helpers.SetupAutoSave();
|
|
||||||
Helpers.LastEffortSave();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
new GeoLocationHandler().AttachTo("geolocate-button");
|
new GeoLocationHandler().AttachTo("geolocate-button");
|
||||||
|
|
||||||
|
|
37
test.ts
37
test.ts
|
@ -1,32 +1,11 @@
|
||||||
import {ImageUploadFlow} from "./UI/ImageUploadFlow";
|
import {State} from "./State";
|
||||||
import {OsmConnection, UserDetails} from "./Logic/Osm/OsmConnection";
|
import Cyclofix from "./Customizations/Layouts/Cyclofix";
|
||||||
import {OsmImageUploadHandler} from "./Logic/Osm/OsmImageUploadHandler";
|
import {CustomLayersPanel} from "./Logic/CustomLayersPanel";
|
||||||
import {UIEventSource} from "./UI/UIEventSource";
|
|
||||||
import {Changes} from "./Logic/Osm/Changes";
|
|
||||||
import {SlideShow} from "./UI/SlideShow";
|
|
||||||
import {ElementStorage} from "./Logic/ElementStorage";
|
|
||||||
import {isNullOrUndefined} from "util";
|
|
||||||
import Locale from "./UI/i18n/Locale";
|
|
||||||
|
|
||||||
const osmConnection = new OsmConnection(true, new UIEventSource<string>(undefined));
|
State.state= new State(new Cyclofix());
|
||||||
const uploadHandler = new OsmImageUploadHandler(
|
|
||||||
new UIEventSource<any>({}),
|
|
||||||
osmConnection.userDetails,
|
|
||||||
new UIEventSource<string>("cc0"),
|
|
||||||
new Changes("blabla", osmConnection, new ElementStorage()),
|
|
||||||
undefined);
|
|
||||||
|
|
||||||
new ImageUploadFlow(
|
new CustomLayersPanel().AttachTo("maindiv");
|
||||||
osmConnection.userDetails,
|
|
||||||
new UIEventSource<string>("cc0"),
|
|
||||||
(license: string) => {
|
|
||||||
return {
|
|
||||||
title: "test",
|
|
||||||
description: "test",
|
|
||||||
handleURL: console.log,
|
|
||||||
allDone: () => {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).AttachTo("maindiv")
|
|
||||||
|
|
||||||
Locale.language.setData("nl")
|
State.state.osmConnection.GetPreference("mapcomplete-custom-layer-count").addCallback((count) => console.log("Count: ", count))
|
||||||
|
|
||||||
|
State.state.favourteLayers.addCallback(console.log)
|
Loading…
Reference in a new issue