From fa4fb71e0610a7afbd34d1d273d252f9a0717f85 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 15 Jan 2021 01:57:46 +0100 Subject: [PATCH] Small tweaks, stabilizing local source cache --- Customizations/JSON/LayoutConfig.ts | 1 - InitUiElements.ts | 9 ++++--- Logic/FeatureSource/FeaturePipeline.ts | 31 +++++++++++++---------- Logic/FeatureSource/LocalStorageSaver.ts | 7 +++-- Logic/FeatureSource/LocalStorageSource.ts | 8 ++++-- Logic/GeoOperations.ts | 2 +- Logic/Osm/OsmPreferences.ts | 20 +++++++-------- index.ts | 12 ++++++--- 8 files changed, 53 insertions(+), 37 deletions(-) diff --git a/Customizations/JSON/LayoutConfig.ts b/Customizations/JSON/LayoutConfig.ts index a1f58c7d6e..fb22a66c69 100644 --- a/Customizations/JSON/LayoutConfig.ts +++ b/Customizations/JSON/LayoutConfig.ts @@ -91,7 +91,6 @@ export default class LayoutConfig { if (layer.builtin !== undefined) { // @ts-ignore const name = layer.builtin; - console.warn("Overwriting!") const shared = SharedLayers.sharedLayersJson[name]; if (shared === undefined) { throw "Unkown fixed layer " + name; diff --git a/InitUiElements.ts b/InitUiElements.ts index 5f2eb40fc7..fb558632bf 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -45,7 +45,7 @@ export class InitUiElements { layoutDefinition: string = "") { if (layoutToUse === undefined) { console.log("Incorrect layout") - new FixedUiElement(`Error: incorrect layout ${layoutName}
Go back`).AttachTo("centermessage").onClick(() => { + new FixedUiElement(`Error: incorrect layout ${layoutName}
Go back`).AttachTo("centermessage").onClick(() => { }); throw "Incorrect layout" } @@ -400,10 +400,13 @@ export class InitUiElements { const updater = new LoadFromOverpass(state.locationControl, state.layoutToUse, state.leafletMap); State.state.layerUpdater = updater; - const source = new FeaturePipeline(flayers, updater); + const source = new FeaturePipeline(flayers, updater, state.layoutToUse); - source.features.addCallback((featuresFreshness: { feature: any, freshness: Date }[]) => { + source.features.addCallbackAndRun((featuresFreshness: { feature: any, freshness: Date }[]) => { + if(featuresFreshness === undefined){ + return; + } let features = featuresFreshness.map(ff => ff.feature); features.forEach(feature => { State.state.allElements.addElement(feature); diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index a9794c14a9..ea2e9b2e91 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -10,38 +10,41 @@ import {UIEventSource} from "../UIEventSource"; import LocalStorageSaver from "./LocalStorageSaver"; import LayerConfig from "../../Customizations/JSON/LayerConfig"; import LocalStorageSource from "./LocalStorageSource"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; export default class FeaturePipeline implements FeatureSource { public features: UIEventSource<{ feature: any; freshness: Date }[]>; - constructor(flayers: { isDisplayed: UIEventSource, layerDef: LayerConfig }[], updater: FeatureSource) { - - const overpassSource = new WayHandlingApplyingFeatureSource(flayers, - new NoOverlapSource(flayers, new FeatureDuplicatorPerLayer(flayers, updater)) - ); + constructor(flayers: { isDisplayed: UIEventSource, layerDef: LayerConfig }[], + updater: FeatureSource, + layout: UIEventSource) { const amendedOverpassSource = - new RememberingSource(new LocalStorageSaver( - overpassSource - )); + new RememberingSource( + new WayHandlingApplyingFeatureSource(flayers, + new NoOverlapSource(flayers, new FeatureDuplicatorPerLayer(flayers, + new LocalStorageSaver(updater, layout))) + ) + ); + + const amendedLocalStorageSource = + new RememberingSource( + new WayHandlingApplyingFeatureSource(flayers, + new NoOverlapSource(flayers, new FeatureDuplicatorPerLayer(flayers, new LocalStorageSource(layout))) + )); const merged = new FeatureSourceMerger([ amendedOverpassSource, new FeatureDuplicatorPerLayer(flayers, State.state.changes), - new LocalStorageSource() + amendedLocalStorageSource ]); - merged.features.addCallbackAndRun(feats => console.log("Merged has",feats?.length)) - const source = new FilteringFeatureSource( flayers, State.state.locationControl, merged ); - source.features.addCallbackAndRun(feats => console.log("Filtered has",feats?.length)) - - this.features = source.features; } diff --git a/Logic/FeatureSource/LocalStorageSaver.ts b/Logic/FeatureSource/LocalStorageSaver.ts index 82aab778a3..6dc4630981 100644 --- a/Logic/FeatureSource/LocalStorageSaver.ts +++ b/Logic/FeatureSource/LocalStorageSaver.ts @@ -5,12 +5,13 @@ */ import FeatureSource from "./FeatureSource"; import {UIEventSource} from "../UIEventSource"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; export default class LocalStorageSaver implements FeatureSource { public static readonly storageKey: string = "cached-features"; public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>; - constructor(source: FeatureSource) { + constructor(source: FeatureSource, layout: UIEventSource) { this.features = source.features; this.features.addCallbackAndRun(features => { @@ -22,7 +23,9 @@ export default class LocalStorageSaver implements FeatureSource { } try { - localStorage.setItem(LocalStorageSaver.storageKey, JSON.stringify(features)); + const key = LocalStorageSaver.storageKey+layout.data.id + localStorage.setItem(key, JSON.stringify(features)); + console.log("Saved ",features.length, "elements to",key) } catch (e) { console.warn("Could not save the features to local storage:", e) } diff --git a/Logic/FeatureSource/LocalStorageSource.ts b/Logic/FeatureSource/LocalStorageSource.ts index 1cbcaca161..41711f8ded 100644 --- a/Logic/FeatureSource/LocalStorageSource.ts +++ b/Logic/FeatureSource/LocalStorageSource.ts @@ -1,21 +1,25 @@ import FeatureSource from "./FeatureSource"; import {UIEventSource} from "../UIEventSource"; import LocalStorageSaver from "./LocalStorageSaver"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; export default class LocalStorageSource implements FeatureSource { public features: UIEventSource<{ feature: any; freshness: Date }[]>; - constructor() { + constructor(layout: UIEventSource) { this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([]) + const key = LocalStorageSaver.storageKey + layout.data.id try { - const fromStorage = localStorage.getItem(LocalStorageSaver.storageKey); + const fromStorage = localStorage.getItem(key); if (fromStorage == null) { return; } const loaded = JSON.parse(fromStorage); this.features.setData(loaded); + console.log("Loaded ",loaded.length," features from localstorage as cache") } catch (e) { console.log("Could not load features from localStorage:", e) + localStorage.removeItem(key) } } diff --git a/Logic/GeoOperations.ts b/Logic/GeoOperations.ts index b97ad5e6d8..86bc694c3a 100644 --- a/Logic/GeoOperations.ts +++ b/Logic/GeoOperations.ts @@ -161,7 +161,7 @@ class BBox{ } static get(feature) { - if (feature.bbox === undefined) { + if (feature.bbox?.overlapsWith === undefined) { if (feature.geometry.type === "MultiPolygon") { let coordinates = []; diff --git a/Logic/Osm/OsmPreferences.ts b/Logic/Osm/OsmPreferences.ts index 7b82c2180b..8914ae1cd7 100644 --- a/Logic/Osm/OsmPreferences.ts +++ b/Logic/Osm/OsmPreferences.ts @@ -4,11 +4,11 @@ import {Utils} from "../../Utils"; export class OsmPreferences { - private auth: any; - private userDetails: UIEventSource; - public preferences = new UIEventSource({}); public preferenceSources: any = {} + private auth: any; + private userDetails: UIEventSource; + private longPreferences = {}; constructor(auth, osmConnection: OsmConnection) { this.auth = auth; @@ -17,8 +17,6 @@ export class OsmPreferences { osmConnection.OnLoggedIn(() => self.UpdatePreferences()); } - private longPreferences = {}; - /** * OSM preferences can be at most 255 chars * @param key @@ -43,8 +41,8 @@ export class OsmPreferences { if (str === undefined || str === "") { return; } - if(str === null){ - console.error("Deleting "+allStartWith); + if (str === null) { + console.error("Deleting " + allStartWith); let count = parseInt(length.data); for (let i = 0; i < count; i++) { // Delete all the preferences @@ -99,7 +97,7 @@ export class OsmPreferences { public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource { key = prefix + key; - if(key.length >= 255){ + if (key.length >= 255) { throw "Preferences: key length to big"; } if (this.preferenceSources[key] !== undefined) { @@ -158,14 +156,14 @@ export class OsmPreferences { if (v === undefined || v === "") { this.auth.xhr({ method: 'DELETE', - path: '/api/0.6/user/preferences/' + k, + path: '/api/0.6/user/preferences/' + encodeURIComponent(k), options: {header: {'Content-Type': 'text/plain'}}, }, function (error) { if (error) { console.log("Could not remove preference", error); return; } - console.log("Preference ",k,"removed!"); + console.log("Preference ", k, "removed!"); }); return; @@ -174,7 +172,7 @@ export class OsmPreferences { this.auth.xhr({ method: 'PUT', - path: '/api/0.6/user/preferences/' + k, + path: '/api/0.6/user/preferences/' + encodeURIComponent(k), options: {header: {'Content-Type': 'text/plain'}}, content: v }, function (error) { diff --git a/index.ts b/index.ts index 18061dc34a..3514213af8 100644 --- a/index.ts +++ b/index.ts @@ -65,6 +65,7 @@ if (layoutFromBase64.startsWith("wiki:")) { .AttachTo("centermessage"); const cleanUrl = `https://wiki.openstreetmap.org/wiki/${themeName}`; const url = `https://cors-anywhere.herokuapp.com/` + cleanUrl; // ~NOT~ VERY SAFE AND HACKER-PROOF! + // We use cors-anywhere because the wiki from openstreetmap is locked-down :( /*/ const url = cleanUrl; // MUCH SAFER! //*/ @@ -81,7 +82,8 @@ if (layoutFromBase64.startsWith("wiki:")) { console.log(data) try { const parsed = JSON.parse(data); - parsed["id"] = layoutFromBase64 + // Overwrite the id to the wiki:value + parsed.id = layoutFromBase64.replace(/[: \/]/g, '-') const layout = new LayoutConfig(parsed); InitUiElements.InitAll(layout, layoutFromBase64, testing, layoutFromBase64, btoa(data)); } catch (e) { @@ -92,8 +94,11 @@ if (layoutFromBase64.startsWith("wiki:")) { throw e; } }, - }).fail(() => { - new FixedUiElement(`${themeName} is invalid:
Could not download - wrong URL?`) + }).fail((_, textstatus, error) => { + console.error("Could not download the wiki theme:", textstatus, error) + new FixedUiElement(`${themeName} is invalid:
Could not download - wrong URL?
`+ + error + + "Go back") .SetClass("clickable") .AttachTo("centermessage"); }); @@ -105,6 +110,7 @@ if (layoutFromBase64.startsWith("wiki:")) { // This is the default case: a builtin theme InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout); } else { + // We fall through: no theme loaded: just show a few buttons document.getElementById("decoration-desktop").remove(); State.state = new State(undefined); document.getElementById("messagesboxmobile").remove();