Refactoring: LayoutToUse is a simple value now
This commit is contained in:
parent
41a2a79fe9
commit
a78d33112b
22 changed files with 133 additions and 153 deletions
|
@ -323,9 +323,7 @@ export class InitUiElements {
|
||||||
State.state.backgroundLayer,
|
State.state.backgroundLayer,
|
||||||
State.state.locationControl,
|
State.state.locationControl,
|
||||||
State.state.availableBackgroundLayers,
|
State.state.availableBackgroundLayers,
|
||||||
State.state.layoutToUse.map(
|
State.state.layoutToUse.defaultBackgroundId
|
||||||
(layout: LayoutConfig) => layout.defaultBackgroundId
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const attr = new Attribution(
|
const attr = new Attribution(
|
||||||
|
@ -345,7 +343,7 @@ export class InitUiElements {
|
||||||
}).SetClass("w-full h-full")
|
}).SetClass("w-full h-full")
|
||||||
.AttachTo("leafletDiv")
|
.AttachTo("leafletDiv")
|
||||||
|
|
||||||
const layout = State.state.layoutToUse.data;
|
const layout = State.state.layoutToUse;
|
||||||
if (layout.lockLocation) {
|
if (layout.lockLocation) {
|
||||||
if (layout.lockLocation === true) {
|
if (layout.lockLocation === true) {
|
||||||
const tile = Tiles.embedded_tile(
|
const tile = Tiles.embedded_tile(
|
||||||
|
@ -375,66 +373,66 @@ export class InitUiElements {
|
||||||
const state = State.state;
|
const state = State.state;
|
||||||
const empty = []
|
const empty = []
|
||||||
|
|
||||||
state.filteredLayers = state.layoutToUse.map((layoutToUse) => {
|
const flayers: FilteredLayer[] = [];
|
||||||
const flayers: FilteredLayer[] = [];
|
|
||||||
|
|
||||||
for (const layer of layoutToUse.layers) {
|
for (const layer of state.layoutToUse.layers) {
|
||||||
let defaultShown = "true"
|
let defaultShown = "true"
|
||||||
if(layoutToUse.id === personal.id){
|
if(state.layoutToUse.id === personal.id){
|
||||||
defaultShown = "false"
|
defaultShown = "false"
|
||||||
}
|
|
||||||
|
|
||||||
let isDisplayed: UIEventSource<boolean>
|
|
||||||
if(layoutToUse.id === personal.id){
|
|
||||||
isDisplayed = State.state.osmConnection.GetPreference("personal-theme-layer-" + layer.id + "-enabled")
|
|
||||||
.map(value => value === "yes", [], enabled => {
|
|
||||||
return enabled ? "yes" : "";
|
|
||||||
})
|
|
||||||
isDisplayed.addCallbackAndRun(d =>console.log("IsDisplayed for layer", layer.id, "is currently", d) )
|
|
||||||
}else{
|
|
||||||
isDisplayed = QueryParameters.GetQueryParameter(
|
|
||||||
"layer-" + layer.id,
|
|
||||||
defaultShown,
|
|
||||||
"Wether or not layer " + layer.id + " is shown"
|
|
||||||
).map<boolean>(
|
|
||||||
(str) => str !== "false",
|
|
||||||
[],
|
|
||||||
(b) => b.toString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const flayer = {
|
|
||||||
isDisplayed: isDisplayed,
|
|
||||||
layerDef: layer,
|
|
||||||
appliedFilters: new UIEventSource<{ filter: FilterConfig, selected: number }[]>([]),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (layer.filters.length > 0) {
|
|
||||||
const filtersPerName = new Map<string, FilterConfig>()
|
|
||||||
layer.filters.forEach(f => filtersPerName.set(f.id, f))
|
|
||||||
const qp = QueryParameters.GetQueryParameter("filter-" + layer.id, "","Filtering state for a layer")
|
|
||||||
flayer.appliedFilters.map(filters => {
|
|
||||||
filters = filters ?? []
|
|
||||||
return filters.map(f => f.filter.id + "." + f.selected).join(",")
|
|
||||||
}, [], textual => {
|
|
||||||
if(textual.length === 0){
|
|
||||||
return empty
|
|
||||||
}
|
|
||||||
return textual.split(",").map(part => {
|
|
||||||
const [filterId, selected] = part.split(".");
|
|
||||||
return {filter: filtersPerName.get(filterId), selected: Number(selected)}
|
|
||||||
}).filter(f => f.filter !== undefined && !isNaN(f.selected))
|
|
||||||
}).syncWith(qp, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
flayers.push(flayer);
|
|
||||||
}
|
}
|
||||||
return flayers;
|
|
||||||
});
|
let isDisplayed: UIEventSource<boolean>
|
||||||
|
if(state.layoutToUse.id === personal.id){
|
||||||
|
isDisplayed = State.state.osmConnection.GetPreference("personal-theme-layer-" + layer.id + "-enabled")
|
||||||
|
.map(value => value === "yes", [], enabled => {
|
||||||
|
return enabled ? "yes" : "";
|
||||||
|
})
|
||||||
|
isDisplayed.addCallbackAndRun(d =>console.log("IsDisplayed for layer", layer.id, "is currently", d) )
|
||||||
|
}else{
|
||||||
|
isDisplayed = QueryParameters.GetQueryParameter(
|
||||||
|
"layer-" + layer.id,
|
||||||
|
defaultShown,
|
||||||
|
"Wether or not layer " + layer.id + " is shown"
|
||||||
|
).map<boolean>(
|
||||||
|
(str) => str !== "false",
|
||||||
|
[],
|
||||||
|
(b) => b.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const flayer = {
|
||||||
|
isDisplayed: isDisplayed,
|
||||||
|
layerDef: layer,
|
||||||
|
appliedFilters: new UIEventSource<{ filter: FilterConfig, selected: number }[]>([]),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (layer.filters.length > 0) {
|
||||||
|
const filtersPerName = new Map<string, FilterConfig>()
|
||||||
|
layer.filters.forEach(f => filtersPerName.set(f.id, f))
|
||||||
|
const qp = QueryParameters.GetQueryParameter("filter-" + layer.id, "","Filtering state for a layer")
|
||||||
|
flayer.appliedFilters.map(filters => {
|
||||||
|
filters = filters ?? []
|
||||||
|
return filters.map(f => f.filter.id + "." + f.selected).join(",")
|
||||||
|
}, [], textual => {
|
||||||
|
if(textual.length === 0){
|
||||||
|
return empty
|
||||||
|
}
|
||||||
|
return textual.split(",").map(part => {
|
||||||
|
const [filterId, selected] = part.split(".");
|
||||||
|
return {filter: filtersPerName.get(filterId), selected: Number(selected)}
|
||||||
|
}).filter(f => f.filter !== undefined && !isNaN(f.selected))
|
||||||
|
}).syncWith(qp, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
flayers.push(flayer);
|
||||||
|
}
|
||||||
|
state.filteredLayers = new UIEventSource<FilteredLayer[]>(flayers);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const clusterCounter = TileHierarchyAggregator.createHierarchy()
|
const clusterCounter = TileHierarchyAggregator.createHierarchy()
|
||||||
new ShowDataLayer({
|
new ShowDataLayer({
|
||||||
features: clusterCounter.getCountsForZoom(State.state.locationControl, State.state.layoutToUse.data.clustering.minNeededElements),
|
features: clusterCounter.getCountsForZoom(State.state.locationControl, State.state.layoutToUse.clustering.minNeededElements),
|
||||||
leafletMap: State.state.leafletMap,
|
leafletMap: State.state.leafletMap,
|
||||||
layerToShow: ShowTileInfo.styling,
|
layerToShow: ShowTileInfo.styling,
|
||||||
})
|
})
|
||||||
|
@ -444,7 +442,7 @@ export class InitUiElements {
|
||||||
|
|
||||||
clusterCounter.addTile(source)
|
clusterCounter.addTile(source)
|
||||||
|
|
||||||
const clustering = State.state.layoutToUse.data.clustering
|
const clustering = State.state.layoutToUse.clustering
|
||||||
const doShowFeatures = source.features.map(
|
const doShowFeatures = source.features.map(
|
||||||
f => {
|
f => {
|
||||||
const z = State.state.locationControl.data.zoom
|
const z = State.state.locationControl.data.zoom
|
||||||
|
|
|
@ -11,8 +11,8 @@ export default class BackgroundLayerResetter {
|
||||||
constructor(currentBackgroundLayer: UIEventSource<BaseLayer>,
|
constructor(currentBackgroundLayer: UIEventSource<BaseLayer>,
|
||||||
location: UIEventSource<Loc>,
|
location: UIEventSource<Loc>,
|
||||||
availableLayers: UIEventSource<BaseLayer[]>,
|
availableLayers: UIEventSource<BaseLayer[]>,
|
||||||
defaultLayerId: UIEventSource<string> = undefined) {
|
defaultLayerId: string = undefined) {
|
||||||
defaultLayerId = defaultLayerId ?? new UIEventSource<string>(AvailableBaseLayers.osmCarto.id);
|
defaultLayerId = defaultLayerId ?? AvailableBaseLayers.osmCarto.id;
|
||||||
|
|
||||||
// Change the baselayer back to OSM if we go out of the current range of the layer
|
// Change the baselayer back to OSM if we go out of the current range of the layer
|
||||||
availableLayers.addCallbackAndRun(availableLayers => {
|
availableLayers.addCallbackAndRun(availableLayers => {
|
||||||
|
@ -28,7 +28,7 @@ export default class BackgroundLayerResetter {
|
||||||
if (availableLayer.min_zoom > location.data.zoom) {
|
if (availableLayer.min_zoom > location.data.zoom) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (availableLayer.id === defaultLayerId.data) {
|
if (availableLayer.id === defaultLayerId) {
|
||||||
defaultLayer = availableLayer;
|
defaultLayer = availableLayer;
|
||||||
}
|
}
|
||||||
return; // All good - the current layer still works!
|
return; // All good - the current layer still works!
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Loc from "../../Models/Loc";
|
||||||
import {Or} from "../Tags/Or";
|
import {Or} from "../Tags/Or";
|
||||||
import {Overpass} from "../Osm/Overpass";
|
import {Overpass} from "../Osm/Overpass";
|
||||||
import Bounds from "../../Models/Bounds";
|
import Bounds from "../../Models/Bounds";
|
||||||
import FeatureSource, {FeatureSourceState} from "../FeatureSource/FeatureSource";
|
import FeatureSource from "../FeatureSource/FeatureSource";
|
||||||
import {Utils} from "../../Utils";
|
import {Utils} from "../../Utils";
|
||||||
import {TagsFilter} from "../Tags/TagsFilter";
|
import {TagsFilter} from "../Tags/TagsFilter";
|
||||||
import SimpleMetaTagger from "../SimpleMetaTagger";
|
import SimpleMetaTagger from "../SimpleMetaTagger";
|
||||||
|
@ -39,7 +39,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
private readonly _previousBounds: Map<number, Bounds[]> = new Map<number, Bounds[]>();
|
private readonly _previousBounds: Map<number, Bounds[]> = new Map<number, Bounds[]>();
|
||||||
private readonly state: {
|
private readonly state: {
|
||||||
readonly locationControl: UIEventSource<Loc>,
|
readonly locationControl: UIEventSource<Loc>,
|
||||||
readonly layoutToUse: UIEventSource<LayoutConfig>,
|
readonly layoutToUse: LayoutConfig,
|
||||||
readonly overpassUrl: UIEventSource<string>;
|
readonly overpassUrl: UIEventSource<string>;
|
||||||
readonly overpassTimeout: UIEventSource<number>;
|
readonly overpassTimeout: UIEventSource<number>;
|
||||||
readonly currentBounds :UIEventSource<BBox>
|
readonly currentBounds :UIEventSource<BBox>
|
||||||
|
@ -52,7 +52,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
constructor(
|
constructor(
|
||||||
state: {
|
state: {
|
||||||
readonly locationControl: UIEventSource<Loc>,
|
readonly locationControl: UIEventSource<Loc>,
|
||||||
readonly layoutToUse: UIEventSource<LayoutConfig>,
|
readonly layoutToUse: LayoutConfig,
|
||||||
readonly overpassUrl: UIEventSource<string>;
|
readonly overpassUrl: UIEventSource<string>;
|
||||||
readonly overpassTimeout: UIEventSource<number>;
|
readonly overpassTimeout: UIEventSource<number>;
|
||||||
readonly overpassMaxZoom: UIEventSource<number>,
|
readonly overpassMaxZoom: UIEventSource<number>,
|
||||||
|
@ -76,9 +76,6 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
this._previousBounds.set(i, []);
|
this._previousBounds.set(i, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.layoutToUse.addCallback(() => {
|
|
||||||
self.update()
|
|
||||||
});
|
|
||||||
location.addCallback(() => {
|
location.addCallback(() => {
|
||||||
self.update()
|
self.update()
|
||||||
});
|
});
|
||||||
|
@ -92,7 +89,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
private GetFilter(): Overpass {
|
private GetFilter(): Overpass {
|
||||||
let filters: TagsFilter[] = [];
|
let filters: TagsFilter[] = [];
|
||||||
let extraScripts: string[] = [];
|
let extraScripts: string[] = [];
|
||||||
for (const layer of this.state.layoutToUse.data.layers) {
|
for (const layer of this.state.layoutToUse.layers) {
|
||||||
if (typeof (layer) === "string") {
|
if (typeof (layer) === "string") {
|
||||||
throw "A layer was not expanded!"
|
throw "A layer was not expanded!"
|
||||||
}
|
}
|
||||||
|
@ -164,7 +161,7 @@ export default class OverpassFeatureSource implements FeatureSource {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.data.widenFactor)?.expandToTileBounds(14);
|
const bounds = this.state.currentBounds.data?.pad(this.state.layoutToUse.widenFactor)?.expandToTileBounds(14);
|
||||||
|
|
||||||
if (bounds === undefined) {
|
if (bounds === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -3,12 +3,18 @@ import Translations from "../../UI/i18n/Translations";
|
||||||
import Locale from "../../UI/i18n/Locale";
|
import Locale from "../../UI/i18n/Locale";
|
||||||
import TagRenderingAnswer from "../../UI/Popup/TagRenderingAnswer";
|
import TagRenderingAnswer from "../../UI/Popup/TagRenderingAnswer";
|
||||||
import Combine from "../../UI/Base/Combine";
|
import Combine from "../../UI/Base/Combine";
|
||||||
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
|
import {ElementStorage} from "../ElementStorage";
|
||||||
|
|
||||||
export default class TitleHandler {
|
export default class TitleHandler {
|
||||||
constructor(state) {
|
constructor(state : {
|
||||||
|
selectedElement: UIEventSource<any>,
|
||||||
|
layoutToUse: LayoutConfig,
|
||||||
|
allElements: ElementStorage
|
||||||
|
}) {
|
||||||
const currentTitle: UIEventSource<string> = state.selectedElement.map(
|
const currentTitle: UIEventSource<string> = state.selectedElement.map(
|
||||||
selected => {
|
selected => {
|
||||||
const layout = state.layoutToUse.data
|
const layout = state.layoutToUse
|
||||||
const defaultTitle = Translations.WT(layout?.title)?.txt ?? "MapComplete"
|
const defaultTitle = Translations.WT(layout?.title)?.txt ?? "MapComplete"
|
||||||
|
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
|
@ -27,7 +33,7 @@ export default class TitleHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaultTitle
|
return defaultTitle
|
||||||
}, [Locale.language, state.layoutToUse]
|
}, [Locale.language]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
||||||
import FilteringFeatureSource from "./Sources/FilteringFeatureSource";
|
import FilteringFeatureSource from "./Sources/FilteringFeatureSource";
|
||||||
import PerLayerFeatureSourceSplitter from "./PerLayerFeatureSourceSplitter";
|
import PerLayerFeatureSourceSplitter from "./PerLayerFeatureSourceSplitter";
|
||||||
import FeatureSource, {FeatureSourceForLayer, FeatureSourceState, IndexedFeatureSource, Tiled} from "./FeatureSource";
|
import FeatureSource, {FeatureSourceForLayer, IndexedFeatureSource, Tiled} from "./FeatureSource";
|
||||||
import TiledFeatureSource from "./TiledFeatureSource/TiledFeatureSource";
|
import TiledFeatureSource from "./TiledFeatureSource/TiledFeatureSource";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
import {TileHierarchyTools} from "./TiledFeatureSource/TileHierarchy";
|
import {TileHierarchyTools} from "./TiledFeatureSource/TileHierarchy";
|
||||||
|
@ -48,7 +48,7 @@ export default class FeaturePipeline {
|
||||||
readonly locationControl: UIEventSource<Loc>,
|
readonly locationControl: UIEventSource<Loc>,
|
||||||
readonly selectedElement: UIEventSource<any>,
|
readonly selectedElement: UIEventSource<any>,
|
||||||
readonly changes: Changes,
|
readonly changes: Changes,
|
||||||
readonly layoutToUse: UIEventSource<LayoutConfig>,
|
readonly layoutToUse: LayoutConfig,
|
||||||
readonly leafletMap: any,
|
readonly leafletMap: any,
|
||||||
readonly overpassUrl: UIEventSource<string>;
|
readonly overpassUrl: UIEventSource<string>;
|
||||||
readonly overpassTimeout: UIEventSource<number>;
|
readonly overpassTimeout: UIEventSource<number>;
|
||||||
|
@ -86,7 +86,7 @@ export default class FeaturePipeline {
|
||||||
if (location?.zoom === undefined) {
|
if (location?.zoom === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let minzoom = Math.min(...state.layoutToUse.data.layers.map(layer => layer.minzoom ?? 18));
|
let minzoom = Math.min(...state.layoutToUse.layers.map(layer => layer.minzoom ?? 18));
|
||||||
return location.zoom >= minzoom;
|
return location.zoom >= minzoom;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -223,8 +223,8 @@ export default class FeaturePipeline {
|
||||||
layer: source.layer,
|
layer: source.layer,
|
||||||
minZoomLevel: 14,
|
minZoomLevel: 14,
|
||||||
dontEnforceMinZoom: true,
|
dontEnforceMinZoom: true,
|
||||||
maxFeatureCount: state.layoutToUse.data.clustering.minNeededElements,
|
maxFeatureCount: state.layoutToUse.clustering.minNeededElements,
|
||||||
maxZoomLevel: state.layoutToUse.data.clustering.maxZoom,
|
maxZoomLevel: state.layoutToUse.clustering.maxZoom,
|
||||||
registerTile: (tile) => {
|
registerTile: (tile) => {
|
||||||
// We save the tile data for the given layer to local storage
|
// We save the tile data for the given layer to local storage
|
||||||
new SaveTileToLocalStorageActor(tile, tile.tileIndex)
|
new SaveTileToLocalStorageActor(tile, tile.tileIndex)
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default class OsmFeatureSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async LoadTile(z, x, y): Promise<void> {
|
private async LoadTile(z, x, y): Promise<void> {
|
||||||
if (z > 18) {
|
if (z > 20) {
|
||||||
throw "This is an absurd high zoom level"
|
throw "This is an absurd high zoom level"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class DeleteAction {
|
||||||
}
|
}
|
||||||
State.state.osmConnection.changesetHandler.DeleteElement(
|
State.state.osmConnection.changesetHandler.DeleteElement(
|
||||||
obj,
|
obj,
|
||||||
State.state.layoutToUse.data,
|
State.state.layoutToUse,
|
||||||
reason,
|
reason,
|
||||||
State.state.allElements,
|
State.state.allElements,
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -131,7 +131,7 @@ export class Changes {
|
||||||
}
|
}
|
||||||
|
|
||||||
await State.state.osmConnection.UploadChangeset(
|
await State.state.osmConnection.UploadChangeset(
|
||||||
State.state.layoutToUse.data,
|
State.state.layoutToUse,
|
||||||
State.state.allElements,
|
State.state.allElements,
|
||||||
(csId) => Changes.createChangesetFor(csId, changes),
|
(csId) => Changes.createChangesetFor(csId, changes),
|
||||||
)
|
)
|
||||||
|
|
|
@ -87,7 +87,7 @@ export default class SimpleMetaTagger {
|
||||||
|
|
||||||
},
|
},
|
||||||
(feature => {
|
(feature => {
|
||||||
const units = Utils.NoNull([].concat(...State.state?.layoutToUse?.data?.layers?.map(layer => layer.units ?? [])));
|
const units = Utils.NoNull([].concat(...State.state?.layoutToUse?.layers?.map(layer => layer.units ?? [])));
|
||||||
if (units.length == 0) {
|
if (units.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
46
State.ts
46
State.ts
|
@ -27,7 +27,7 @@ export default class State {
|
||||||
// The singleton of the global state
|
// The singleton of the global state
|
||||||
public static state: State;
|
public static state: State;
|
||||||
|
|
||||||
public readonly layoutToUse = new UIEventSource<LayoutConfig>(undefined, "layoutToUse");
|
public readonly layoutToUse : LayoutConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The mapping from id -> UIEventSource<properties>
|
The mapping from id -> UIEventSource<properties>
|
||||||
|
@ -83,7 +83,9 @@ export default class State {
|
||||||
public readonly featureSwitchExportAsPdf: UIEventSource<boolean>;
|
public readonly featureSwitchExportAsPdf: UIEventSource<boolean>;
|
||||||
public readonly overpassUrl: UIEventSource<string>;
|
public readonly overpassUrl: UIEventSource<string>;
|
||||||
public readonly overpassTimeout: UIEventSource<number>;
|
public readonly overpassTimeout: UIEventSource<number>;
|
||||||
public readonly overpassMaxZoom: UIEventSource<number> = new UIEventSource<number>(20);
|
|
||||||
|
|
||||||
|
public readonly overpassMaxZoom: UIEventSource<number> = new UIEventSource<number>(17, "overpass-max-zoom: point to switch between OSM-api and overpass");
|
||||||
|
|
||||||
public featurePipeline: FeaturePipeline;
|
public featurePipeline: FeaturePipeline;
|
||||||
|
|
||||||
|
@ -155,7 +157,7 @@ export default class State {
|
||||||
|
|
||||||
constructor(layoutToUse: LayoutConfig) {
|
constructor(layoutToUse: LayoutConfig) {
|
||||||
const self = this;
|
const self = this;
|
||||||
this.layoutToUse.setData(layoutToUse);
|
this.layoutToUse = layoutToUse;
|
||||||
|
|
||||||
// -- Location control initialization
|
// -- Location control initialization
|
||||||
{
|
{
|
||||||
|
@ -192,14 +194,7 @@ export default class State {
|
||||||
lat.setData(latlonz.lat);
|
lat.setData(latlonz.lat);
|
||||||
lon.setData(latlonz.lon);
|
lon.setData(latlonz.lon);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.layoutToUse.addCallback((layoutToUse) => {
|
|
||||||
const lcd = self.locationControl.data;
|
|
||||||
lcd.zoom = lcd.zoom ?? layoutToUse?.startZoom;
|
|
||||||
lcd.lat = lcd.lat ?? layoutToUse?.startLat;
|
|
||||||
lcd.lon = lcd.lon ?? layoutToUse?.startLon;
|
|
||||||
self.locationControl.ping();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to initialize feature switches
|
// Helper function to initialize feature switches
|
||||||
|
@ -208,28 +203,19 @@ export default class State {
|
||||||
deflt: (layout: LayoutConfig) => boolean,
|
deflt: (layout: LayoutConfig) => boolean,
|
||||||
documentation: string
|
documentation: string
|
||||||
): UIEventSource<boolean> {
|
): UIEventSource<boolean> {
|
||||||
const queryParameterSource = QueryParameters.GetQueryParameter(
|
|
||||||
|
const defaultValue = deflt(self.layoutToUse);
|
||||||
|
const queryParam = QueryParameters.GetQueryParameter(
|
||||||
key,
|
key,
|
||||||
undefined,
|
"" + defaultValue,
|
||||||
documentation
|
documentation
|
||||||
);
|
);
|
||||||
// I'm so sorry about someone trying to decipher this
|
|
||||||
|
|
||||||
// It takes the current layout, extracts the default value for this query parameter. A query parameter event source is then retrieved and flattened
|
// It takes the current layout, extracts the default value for this query parameter. A query parameter event source is then retrieved and flattened
|
||||||
return UIEventSource.flatten(
|
return queryParam.map((str) =>
|
||||||
self.layoutToUse.map((layout) => {
|
str === undefined ? defaultValue : str !== "false"
|
||||||
const defaultValue = deflt(layout);
|
)
|
||||||
const queryParam = QueryParameters.GetQueryParameter(
|
|
||||||
key,
|
|
||||||
"" + defaultValue,
|
|
||||||
documentation
|
|
||||||
);
|
|
||||||
return queryParam.map((str) =>
|
|
||||||
str === undefined ? defaultValue : str !== "false"
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
[queryParameterSource]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feature switch initialization - not as a function as the UIEventSources are readonly
|
// Feature switch initialization - not as a function as the UIEventSources are readonly
|
||||||
|
@ -412,11 +398,11 @@ export default class State {
|
||||||
|
|
||||||
Locale.language
|
Locale.language
|
||||||
.addCallback((currentLanguage) => {
|
.addCallback((currentLanguage) => {
|
||||||
const layoutToUse = self.layoutToUse.data;
|
const layoutToUse = self.layoutToUse;
|
||||||
if (layoutToUse === undefined) {
|
if (layoutToUse === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.layoutToUse.data.language.indexOf(currentLanguage) < 0) {
|
if (this.layoutToUse.language.indexOf(currentLanguage) < 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"Resetting language to",
|
"Resetting language to",
|
||||||
layoutToUse.language[0],
|
layoutToUse.language[0],
|
||||||
|
|
|
@ -16,13 +16,13 @@ export default class Attribution extends Combine {
|
||||||
|
|
||||||
constructor(location: UIEventSource<Loc>,
|
constructor(location: UIEventSource<Loc>,
|
||||||
userDetails: UIEventSource<UserDetails>,
|
userDetails: UIEventSource<UserDetails>,
|
||||||
layoutToUse: UIEventSource<LayoutConfig>,
|
layoutToUse: LayoutConfig,
|
||||||
currentBounds: UIEventSource<BBox>) {
|
currentBounds: UIEventSource<BBox>) {
|
||||||
|
|
||||||
const mapComplete = new Link(`Mapcomplete ${Constants.vNumber}`, 'https://github.com/pietervdvn/MapComplete', true);
|
const mapComplete = new Link(`Mapcomplete ${Constants.vNumber}`, 'https://github.com/pietervdvn/MapComplete', true);
|
||||||
const reportBug = new Link(Svg.bug_ui().SetClass("small-image"), "https://github.com/pietervdvn/MapComplete/issues", true);
|
const reportBug = new Link(Svg.bug_ui().SetClass("small-image"), "https://github.com/pietervdvn/MapComplete/issues", true);
|
||||||
|
|
||||||
const layoutId = layoutToUse?.data?.id;
|
const layoutId = layoutToUse?.id;
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
// Note: getMonth is zero-index, we want 1-index but with one substracted, so it checks out!
|
// Note: getMonth is zero-index, we want 1-index but with one substracted, so it checks out!
|
||||||
const startDate = now.getFullYear() + "-" + now.getMonth() + "-" + now.getDate()
|
const startDate = now.getFullYear() + "-" + now.getMonth() + "-" + now.getDate()
|
||||||
|
|
|
@ -20,11 +20,11 @@ export default class AttributionPanel extends Combine {
|
||||||
|
|
||||||
private static LicenseObject = AttributionPanel.GenerateLicenses();
|
private static LicenseObject = AttributionPanel.GenerateLicenses();
|
||||||
|
|
||||||
constructor(layoutToUse: UIEventSource<LayoutConfig>, contributions: UIEventSource<Map<string, number>>) {
|
constructor(layoutToUse: LayoutConfig, contributions: UIEventSource<Map<string, number>>) {
|
||||||
super([
|
super([
|
||||||
Translations.t.general.attribution.attributionContent,
|
Translations.t.general.attribution.attributionContent,
|
||||||
((layoutToUse.data.maintainer ?? "") == "") ? "" : Translations.t.general.attribution.themeBy.Subs({author: layoutToUse.data.maintainer}),
|
((layoutToUse.maintainer ?? "") == "") ? "" : Translations.t.general.attribution.themeBy.Subs({author: layoutToUse.maintainer}),
|
||||||
layoutToUse.data.credits,
|
layoutToUse.credits,
|
||||||
"<br/>",
|
"<br/>",
|
||||||
new Attribution(State.state.locationControl, State.state.osmConnection.userDetails, State.state.layoutToUse, State.state.currentBounds),
|
new Attribution(State.state.locationControl, State.state.osmConnection.userDetails, State.state.layoutToUse, State.state.currentBounds),
|
||||||
"<br/>",
|
"<br/>",
|
||||||
|
@ -65,7 +65,7 @@ export default class AttributionPanel extends Combine {
|
||||||
"<br/>",
|
"<br/>",
|
||||||
AttributionPanel.CodeContributors(),
|
AttributionPanel.CodeContributors(),
|
||||||
"<h3>", Translations.t.general.attribution.iconAttribution.title.Clone().SetClass("pt-6 pb-3"), "</h3>",
|
"<h3>", Translations.t.general.attribution.iconAttribution.title.Clone().SetClass("pt-6 pb-3"), "</h3>",
|
||||||
...Utils.NoNull(Array.from(layoutToUse.data.ExtractImages()))
|
...Utils.NoNull(Array.from(layoutToUse.ExtractImages()))
|
||||||
.map(AttributionPanel.IconAttribution)
|
.map(AttributionPanel.IconAttribution)
|
||||||
]);
|
]);
|
||||||
this.SetClass("flex flex-col link-underline overflow-hidden")
|
this.SetClass("flex flex-col link-underline overflow-hidden")
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class DownloadPanel extends Toggle {
|
||||||
|
|
||||||
|
|
||||||
const t = Translations.t.general.download
|
const t = Translations.t.general.download
|
||||||
const name = State.state.layoutToUse.data.id;
|
const name = State.state.layoutToUse.id;
|
||||||
|
|
||||||
const includeMetaToggle = new CheckBoxes([t.includeMetaData.Clone()])
|
const includeMetaToggle = new CheckBoxes([t.includeMetaData.Clone()])
|
||||||
const metaisIncluded = includeMetaToggle.GetValue().map(selected => selected.length > 0)
|
const metaisIncluded = includeMetaToggle.GetValue().map(selected => selected.length > 0)
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
|
||||||
|
|
||||||
|
|
||||||
constructor(isShown: UIEventSource<boolean>) {
|
constructor(isShown: UIEventSource<boolean>) {
|
||||||
const layoutToUse = State.state.layoutToUse.data;
|
const layoutToUse = State.state.layoutToUse;
|
||||||
super(
|
super(
|
||||||
() => layoutToUse.title.Clone(),
|
() => layoutToUse.title.Clone(),
|
||||||
() => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails, isShown),
|
() => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails, isShown),
|
||||||
|
|
|
@ -126,7 +126,7 @@ export default class MoreScreen extends Combine {
|
||||||
if (layout.hideFromOverview) {
|
if (layout.hideFromOverview) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (layout.id === State.state.layoutToUse.data?.id) {
|
if (layout.id === State.state.layoutToUse?.id) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||||
export default class ShareScreen extends Combine {
|
export default class ShareScreen extends Combine {
|
||||||
|
|
||||||
constructor(layout: LayoutConfig = undefined, layoutDefinition: string = undefined) {
|
constructor(layout: LayoutConfig = undefined, layoutDefinition: string = undefined) {
|
||||||
layout = layout ?? State.state?.layoutToUse?.data;
|
layout = layout ?? State.state?.layoutToUse;
|
||||||
layoutDefinition = layoutDefinition ?? State.state?.layoutDefinition;
|
layoutDefinition = layoutDefinition ?? State.state?.layoutDefinition;
|
||||||
const tr = Translations.t.general.sharescreen;
|
const tr = Translations.t.general.sharescreen;
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,17 @@ import State from "../../State";
|
||||||
import Combine from "../Base/Combine";
|
import Combine from "../Base/Combine";
|
||||||
import LanguagePicker from "../LanguagePicker";
|
import LanguagePicker from "../LanguagePicker";
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
|
||||||
import Toggle from "../Input/Toggle";
|
import Toggle from "../Input/Toggle";
|
||||||
import {SubtleButton} from "../Base/SubtleButton";
|
import {SubtleButton} from "../Base/SubtleButton";
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg";
|
||||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
|
|
||||||
export default class ThemeIntroductionPanel extends VariableUiElement {
|
export default class ThemeIntroductionPanel extends Combine {
|
||||||
|
|
||||||
constructor(isShown: UIEventSource<boolean>) {
|
constructor(isShown: UIEventSource<boolean>) {
|
||||||
|
const layout = State.state.layoutToUse
|
||||||
|
|
||||||
const languagePicker =
|
const languagePicker = LanguagePicker.CreateLanguagePicker(layout.language, Translations.t.general.pickLanguage.Clone())
|
||||||
new VariableUiElement(
|
|
||||||
State.state.layoutToUse.map(layout => LanguagePicker.CreateLanguagePicker(layout.language, Translations.t.general.pickLanguage.Clone()))
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
const toTheMap = new SubtleButton(
|
const toTheMap = new SubtleButton(
|
||||||
undefined,
|
undefined,
|
||||||
|
@ -53,8 +49,7 @@ export default class ThemeIntroductionPanel extends VariableUiElement {
|
||||||
State.state.featureSwitchUserbadge
|
State.state.featureSwitchUserbadge
|
||||||
)
|
)
|
||||||
|
|
||||||
|
super([
|
||||||
super(State.state.layoutToUse.map(layout => new Combine([
|
|
||||||
layout.description.Clone(),
|
layout.description.Clone(),
|
||||||
"<br/><br/>",
|
"<br/><br/>",
|
||||||
toTheMap,
|
toTheMap,
|
||||||
|
@ -63,7 +58,7 @@ export default class ThemeIntroductionPanel extends VariableUiElement {
|
||||||
"<br/>",
|
"<br/>",
|
||||||
languagePicker,
|
languagePicker,
|
||||||
...layout.CustomCodeSnippets()
|
...layout.CustomCodeSnippets()
|
||||||
])))
|
])
|
||||||
|
|
||||||
this.SetClass("link-underline")
|
this.SetClass("link-underline")
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default class UserBadge extends Toggle {
|
||||||
});
|
});
|
||||||
|
|
||||||
const linkStyle = "flex items-baseline"
|
const linkStyle = "flex items-baseline"
|
||||||
const languagePicker = (LanguagePicker.CreateLanguagePicker(State.state.layoutToUse.data.language) ?? new FixedUiElement(""))
|
const languagePicker = (LanguagePicker.CreateLanguagePicker(State.state.layoutToUse.language) ?? new FixedUiElement(""))
|
||||||
.SetStyle("width:min-content;");
|
.SetStyle("width:min-content;");
|
||||||
|
|
||||||
let messageSpan =
|
let messageSpan =
|
||||||
|
|
|
@ -55,7 +55,7 @@ export class ImageUploadFlow extends Toggle {
|
||||||
|
|
||||||
const tags = tagsSource.data;
|
const tags = tagsSource.data;
|
||||||
|
|
||||||
const layout = State.state?.layoutToUse?.data
|
const layout = State.state?.layoutToUse
|
||||||
let matchingLayer: LayerConfig = undefined
|
let matchingLayer: LayerConfig = undefined
|
||||||
for (const layer of layout?.layers ?? []) {
|
for (const layer of layout?.layers ?? []) {
|
||||||
if (layer.source.osmTags.matchesProperties(tags)) {
|
if (layer.source.osmTags.matchesProperties(tags)) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ export class DropDown<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
options = options ?? {}
|
options = options ?? {}
|
||||||
options.select_class = options.select_class ?? 'bg-indigo-100 p-1 rounded hover:bg-indigo-200'
|
options.select_class = options.select_class ?? 'bg-indigo-100 p-1 rounded hover:bg-indigo-200 w-full'
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default class LocationInput extends InputElement<Loc> {
|
||||||
private readonly _maxSnapDistance: number
|
private readonly _maxSnapDistance: number
|
||||||
private readonly _snappedPointTags: any;
|
private readonly _snappedPointTags: any;
|
||||||
private readonly _bounds: UIEventSource<BBox>;
|
private readonly _bounds: UIEventSource<BBox>;
|
||||||
public readonly _matching_layer: UIEventSource<LayerConfig>;
|
public readonly _matching_layer: LayerConfig;
|
||||||
|
|
||||||
constructor(options: {
|
constructor(options: {
|
||||||
mapBackground?: UIEventSource<BaseLayer>,
|
mapBackground?: UIEventSource<BaseLayer>,
|
||||||
|
@ -63,18 +63,17 @@ export default class LocationInput extends InputElement<Loc> {
|
||||||
|
|
||||||
|
|
||||||
if (self._snappedPointTags !== undefined) {
|
if (self._snappedPointTags !== undefined) {
|
||||||
this._matching_layer = State.state.layoutToUse.map(layout => {
|
const layout = State.state.layoutToUse
|
||||||
|
|
||||||
for (const layer of layout.layers) {
|
let matchingLayer = LocationInput.matchLayer
|
||||||
if (layer.source.osmTags.matchesProperties(self._snappedPointTags)) {
|
for (const layer of layout.layers) {
|
||||||
return layer
|
if (layer.source.osmTags.matchesProperties(self._snappedPointTags)) {
|
||||||
}
|
matchingLayer = layer
|
||||||
}
|
}
|
||||||
console.error("No matching layer found for tags ", self._snappedPointTags)
|
}
|
||||||
return LocationInput.matchLayer
|
this._matching_layer = matchingLayer;
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
this._matching_layer = new UIEventSource<LayerConfig>(LocationInput.matchLayer)
|
this._matching_layer = LocationInput.matchLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
this._snappedPoint = options.centerLocation.map(loc => {
|
this._snappedPoint = options.centerLocation.map(loc => {
|
||||||
|
@ -176,7 +175,7 @@ export default class LocationInput extends InputElement<Loc> {
|
||||||
enablePopups: false,
|
enablePopups: false,
|
||||||
zoomToFeatures: false,
|
zoomToFeatures: false,
|
||||||
leafletMap: map.leafletMap,
|
leafletMap: map.leafletMap,
|
||||||
layerToShow: this._matching_layer.data
|
layerToShow: this._matching_layer
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,10 +316,10 @@ export default class SpecialVisualizations {
|
||||||
const generateShareData = () => {
|
const generateShareData = () => {
|
||||||
|
|
||||||
|
|
||||||
const title = state?.layoutToUse?.data?.title?.txt ?? "MapComplete";
|
const title = state?.layoutToUse?.title?.txt ?? "MapComplete";
|
||||||
|
|
||||||
let matchingLayer: LayerConfig = undefined;
|
let matchingLayer: LayerConfig = undefined;
|
||||||
for (const layer of (state?.layoutToUse?.data?.layers ?? [])) {
|
for (const layer of (state?.layoutToUse?.layers ?? [])) {
|
||||||
if (layer.source.osmTags.matchesProperties(tagSource?.data)) {
|
if (layer.source.osmTags.matchesProperties(tagSource?.data)) {
|
||||||
matchingLayer = layer
|
matchingLayer = layer
|
||||||
}
|
}
|
||||||
|
@ -337,7 +337,7 @@ export default class SpecialVisualizations {
|
||||||
return {
|
return {
|
||||||
title: name,
|
title: name,
|
||||||
url: url,
|
url: url,
|
||||||
text: state?.layoutToUse?.data?.shortDescription?.txt ?? "MapComplete"
|
text: state?.layoutToUse?.shortDescription?.txt ?? "MapComplete"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,15 +363,14 @@ export default class SpecialVisualizations {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const allUnits = [].concat(...state.layoutToUse.data.layers.map(lyr => lyr.units))
|
const allUnits = [].concat(...state.layoutToUse.layers.map(lyr => lyr.units))
|
||||||
const unit = allUnits.filter(unit => unit.isApplicableToKey(key))[0]
|
const unit = allUnits.filter(unit => unit.isApplicableToKey(key))[0]
|
||||||
if (unit === undefined) {
|
if (unit === undefined) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return unit.asHumanLongValue(value);
|
return unit.asHumanLongValue(value);
|
||||||
|
|
||||||
},
|
})
|
||||||
[state.layoutToUse])
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -410,7 +409,7 @@ There are also some technicalities in your theme to keep in mind:
|
||||||
A reference number to the original dataset is an excellen way to do this
|
A reference number to the original dataset is an excellen way to do this
|
||||||
`,
|
`,
|
||||||
constr: (state, tagSource, args) => {
|
constr: (state, tagSource, args) => {
|
||||||
if (!state.layoutToUse.data.official && !state.featureSwitchIsTesting.data) {
|
if (!state.layoutToUse.official && !state.featureSwitchIsTesting.data) {
|
||||||
return new Combine([new FixedUiElement("The import button is disabled for unofficial themes to prevent accidents.").SetClass("alert"),
|
return new Combine([new FixedUiElement("The import button is disabled for unofficial themes to prevent accidents.").SetClass("alert"),
|
||||||
new FixedUiElement("To test, add 'test=true' to the URL. The changeset will be printed in the console. Please open a PR to officialize this theme to actually enable the import button.")])
|
new FixedUiElement("To test, add 'test=true' to the URL. The changeset will be printed in the console. Please open a PR to officialize this theme to actually enable the import button.")])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue