Small tweaks, stabilizing local source cache
This commit is contained in:
parent
f33fe081d0
commit
fa4fb71e06
8 changed files with 53 additions and 37 deletions
|
@ -91,7 +91,6 @@ export default class LayoutConfig {
|
||||||
if (layer.builtin !== undefined) {
|
if (layer.builtin !== undefined) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const name = layer.builtin;
|
const name = layer.builtin;
|
||||||
console.warn("Overwriting!")
|
|
||||||
const shared = SharedLayers.sharedLayersJson[name];
|
const shared = SharedLayers.sharedLayersJson[name];
|
||||||
if (shared === undefined) {
|
if (shared === undefined) {
|
||||||
throw "Unkown fixed layer " + name;
|
throw "Unkown fixed layer " + name;
|
||||||
|
|
|
@ -45,7 +45,7 @@ export class InitUiElements {
|
||||||
layoutDefinition: string = "") {
|
layoutDefinition: string = "") {
|
||||||
if (layoutToUse === undefined) {
|
if (layoutToUse === undefined) {
|
||||||
console.log("Incorrect layout")
|
console.log("Incorrect layout")
|
||||||
new FixedUiElement(`Error: incorrect layout <i>${layoutName}</i><br/><a href='https://${window.location.host}/index.html'>Go back</a>`).AttachTo("centermessage").onClick(() => {
|
new FixedUiElement(`Error: incorrect layout <i>${layoutName}</i><br/><a href='https://${window.location.host}/'>Go back</a>`).AttachTo("centermessage").onClick(() => {
|
||||||
});
|
});
|
||||||
throw "Incorrect layout"
|
throw "Incorrect layout"
|
||||||
}
|
}
|
||||||
|
@ -400,10 +400,13 @@ export class InitUiElements {
|
||||||
|
|
||||||
const updater = new LoadFromOverpass(state.locationControl, state.layoutToUse, state.leafletMap);
|
const updater = new LoadFromOverpass(state.locationControl, state.layoutToUse, state.leafletMap);
|
||||||
State.state.layerUpdater = updater;
|
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);
|
let features = featuresFreshness.map(ff => ff.feature);
|
||||||
features.forEach(feature => {
|
features.forEach(feature => {
|
||||||
State.state.allElements.addElement(feature);
|
State.state.allElements.addElement(feature);
|
||||||
|
|
|
@ -10,38 +10,41 @@ import {UIEventSource} from "../UIEventSource";
|
||||||
import LocalStorageSaver from "./LocalStorageSaver";
|
import LocalStorageSaver from "./LocalStorageSaver";
|
||||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||||
import LocalStorageSource from "./LocalStorageSource";
|
import LocalStorageSource from "./LocalStorageSource";
|
||||||
|
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||||
|
|
||||||
export default class FeaturePipeline implements FeatureSource {
|
export default class FeaturePipeline implements FeatureSource {
|
||||||
|
|
||||||
public features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
public features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
||||||
|
|
||||||
constructor(flayers: { isDisplayed: UIEventSource<boolean>, layerDef: LayerConfig }[], updater: FeatureSource) {
|
constructor(flayers: { isDisplayed: UIEventSource<boolean>, layerDef: LayerConfig }[],
|
||||||
|
updater: FeatureSource,
|
||||||
const overpassSource = new WayHandlingApplyingFeatureSource(flayers,
|
layout: UIEventSource<LayoutConfig>) {
|
||||||
new NoOverlapSource(flayers, new FeatureDuplicatorPerLayer(flayers, updater))
|
|
||||||
);
|
|
||||||
|
|
||||||
const amendedOverpassSource =
|
const amendedOverpassSource =
|
||||||
new RememberingSource(new LocalStorageSaver(
|
new RememberingSource(
|
||||||
overpassSource
|
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([
|
const merged = new FeatureSourceMerger([
|
||||||
amendedOverpassSource,
|
amendedOverpassSource,
|
||||||
new FeatureDuplicatorPerLayer(flayers, State.state.changes),
|
new FeatureDuplicatorPerLayer(flayers, State.state.changes),
|
||||||
new LocalStorageSource()
|
amendedLocalStorageSource
|
||||||
]);
|
]);
|
||||||
merged.features.addCallbackAndRun(feats => console.log("Merged has",feats?.length))
|
|
||||||
|
|
||||||
const source =
|
const source =
|
||||||
new FilteringFeatureSource(
|
new FilteringFeatureSource(
|
||||||
flayers,
|
flayers,
|
||||||
State.state.locationControl,
|
State.state.locationControl,
|
||||||
merged
|
merged
|
||||||
);
|
);
|
||||||
source.features.addCallbackAndRun(feats => console.log("Filtered has",feats?.length))
|
|
||||||
|
|
||||||
|
|
||||||
this.features = source.features;
|
this.features = source.features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
*/
|
*/
|
||||||
import FeatureSource from "./FeatureSource";
|
import FeatureSource from "./FeatureSource";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
|
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||||
|
|
||||||
export default class LocalStorageSaver implements FeatureSource {
|
export default class LocalStorageSaver implements FeatureSource {
|
||||||
public static readonly storageKey: string = "cached-features";
|
public static readonly storageKey: string = "cached-features";
|
||||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
||||||
|
|
||||||
constructor(source: FeatureSource) {
|
constructor(source: FeatureSource, layout: UIEventSource<LayoutConfig>) {
|
||||||
this.features = source.features;
|
this.features = source.features;
|
||||||
|
|
||||||
this.features.addCallbackAndRun(features => {
|
this.features.addCallbackAndRun(features => {
|
||||||
|
@ -22,7 +23,9 @@ export default class LocalStorageSaver implements FeatureSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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) {
|
} catch (e) {
|
||||||
console.warn("Could not save the features to local storage:", e)
|
console.warn("Could not save the features to local storage:", e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
import FeatureSource from "./FeatureSource";
|
import FeatureSource from "./FeatureSource";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
import LocalStorageSaver from "./LocalStorageSaver";
|
import LocalStorageSaver from "./LocalStorageSaver";
|
||||||
|
import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||||
|
|
||||||
export default class LocalStorageSource implements FeatureSource {
|
export default class LocalStorageSource implements FeatureSource {
|
||||||
public features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
public features: UIEventSource<{ feature: any; freshness: Date }[]>;
|
||||||
|
|
||||||
constructor() {
|
constructor(layout: UIEventSource<LayoutConfig>) {
|
||||||
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([])
|
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([])
|
||||||
|
const key = LocalStorageSaver.storageKey + layout.data.id
|
||||||
try {
|
try {
|
||||||
const fromStorage = localStorage.getItem(LocalStorageSaver.storageKey);
|
const fromStorage = localStorage.getItem(key);
|
||||||
if (fromStorage == null) {
|
if (fromStorage == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const loaded = JSON.parse(fromStorage);
|
const loaded = JSON.parse(fromStorage);
|
||||||
this.features.setData(loaded);
|
this.features.setData(loaded);
|
||||||
|
console.log("Loaded ",loaded.length," features from localstorage as cache")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not load features from localStorage:", e)
|
console.log("Could not load features from localStorage:", e)
|
||||||
|
localStorage.removeItem(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ class BBox{
|
||||||
}
|
}
|
||||||
|
|
||||||
static get(feature) {
|
static get(feature) {
|
||||||
if (feature.bbox === undefined) {
|
if (feature.bbox?.overlapsWith === undefined) {
|
||||||
|
|
||||||
if (feature.geometry.type === "MultiPolygon") {
|
if (feature.geometry.type === "MultiPolygon") {
|
||||||
let coordinates = [];
|
let coordinates = [];
|
||||||
|
|
|
@ -4,11 +4,11 @@ import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export class OsmPreferences {
|
export class OsmPreferences {
|
||||||
|
|
||||||
private auth: any;
|
|
||||||
private userDetails: UIEventSource<UserDetails>;
|
|
||||||
|
|
||||||
public preferences = new UIEventSource<any>({});
|
public preferences = new UIEventSource<any>({});
|
||||||
public preferenceSources: any = {}
|
public preferenceSources: any = {}
|
||||||
|
private auth: any;
|
||||||
|
private userDetails: UIEventSource<UserDetails>;
|
||||||
|
private longPreferences = {};
|
||||||
|
|
||||||
constructor(auth, osmConnection: OsmConnection) {
|
constructor(auth, osmConnection: OsmConnection) {
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
|
@ -17,8 +17,6 @@ export class OsmPreferences {
|
||||||
osmConnection.OnLoggedIn(() => self.UpdatePreferences());
|
osmConnection.OnLoggedIn(() => self.UpdatePreferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
private longPreferences = {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OSM preferences can be at most 255 chars
|
* OSM preferences can be at most 255 chars
|
||||||
* @param key
|
* @param key
|
||||||
|
@ -43,8 +41,8 @@ export class OsmPreferences {
|
||||||
if (str === undefined || str === "") {
|
if (str === undefined || str === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(str === null){
|
if (str === null) {
|
||||||
console.error("Deleting "+allStartWith);
|
console.error("Deleting " + allStartWith);
|
||||||
let count = parseInt(length.data);
|
let count = parseInt(length.data);
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// Delete all the preferences
|
// Delete all the preferences
|
||||||
|
@ -99,7 +97,7 @@ export class OsmPreferences {
|
||||||
|
|
||||||
public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
|
public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
|
||||||
key = prefix + key;
|
key = prefix + key;
|
||||||
if(key.length >= 255){
|
if (key.length >= 255) {
|
||||||
throw "Preferences: key length to big";
|
throw "Preferences: key length to big";
|
||||||
}
|
}
|
||||||
if (this.preferenceSources[key] !== undefined) {
|
if (this.preferenceSources[key] !== undefined) {
|
||||||
|
@ -158,14 +156,14 @@ export class OsmPreferences {
|
||||||
if (v === undefined || v === "") {
|
if (v === undefined || v === "") {
|
||||||
this.auth.xhr({
|
this.auth.xhr({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: '/api/0.6/user/preferences/' + k,
|
path: '/api/0.6/user/preferences/' + encodeURIComponent(k),
|
||||||
options: {header: {'Content-Type': 'text/plain'}},
|
options: {header: {'Content-Type': 'text/plain'}},
|
||||||
}, function (error) {
|
}, function (error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log("Could not remove preference", error);
|
console.log("Could not remove preference", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("Preference ",k,"removed!");
|
console.log("Preference ", k, "removed!");
|
||||||
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -174,7 +172,7 @@ export class OsmPreferences {
|
||||||
|
|
||||||
this.auth.xhr({
|
this.auth.xhr({
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
path: '/api/0.6/user/preferences/' + k,
|
path: '/api/0.6/user/preferences/' + encodeURIComponent(k),
|
||||||
options: {header: {'Content-Type': 'text/plain'}},
|
options: {header: {'Content-Type': 'text/plain'}},
|
||||||
content: v
|
content: v
|
||||||
}, function (error) {
|
}, function (error) {
|
||||||
|
|
12
index.ts
12
index.ts
|
@ -65,6 +65,7 @@ if (layoutFromBase64.startsWith("wiki:")) {
|
||||||
.AttachTo("centermessage");
|
.AttachTo("centermessage");
|
||||||
const cleanUrl = `https://wiki.openstreetmap.org/wiki/${themeName}`;
|
const cleanUrl = `https://wiki.openstreetmap.org/wiki/${themeName}`;
|
||||||
const url = `https://cors-anywhere.herokuapp.com/` + cleanUrl; // ~NOT~ VERY SAFE AND HACKER-PROOF!
|
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! //*/
|
const url = cleanUrl; // MUCH SAFER! //*/
|
||||||
|
|
||||||
|
@ -81,7 +82,8 @@ if (layoutFromBase64.startsWith("wiki:")) {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(data);
|
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);
|
const layout = new LayoutConfig(parsed);
|
||||||
InitUiElements.InitAll(layout, layoutFromBase64, testing, layoutFromBase64, btoa(data));
|
InitUiElements.InitAll(layout, layoutFromBase64, testing, layoutFromBase64, btoa(data));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -92,8 +94,11 @@ if (layoutFromBase64.startsWith("wiki:")) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}).fail(() => {
|
}).fail((_, textstatus, error) => {
|
||||||
new FixedUiElement(`<a href="${cleanUrl}">${themeName}</a> is invalid:<br/>Could not download - wrong URL?`)
|
console.error("Could not download the wiki theme:", textstatus, error)
|
||||||
|
new FixedUiElement(`<a href="${cleanUrl}">${themeName}</a> is invalid:<br/>Could not download - wrong URL?<br/>`+
|
||||||
|
error +
|
||||||
|
"<a href='https://${window.location.host}/'>Go back</a>")
|
||||||
.SetClass("clickable")
|
.SetClass("clickable")
|
||||||
.AttachTo("centermessage");
|
.AttachTo("centermessage");
|
||||||
});
|
});
|
||||||
|
@ -105,6 +110,7 @@ if (layoutFromBase64.startsWith("wiki:")) {
|
||||||
// This is the default case: a builtin theme
|
// This is the default case: a builtin theme
|
||||||
InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout);
|
InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout);
|
||||||
} else {
|
} else {
|
||||||
|
// We fall through: no theme loaded: just show a few buttons
|
||||||
document.getElementById("decoration-desktop").remove();
|
document.getElementById("decoration-desktop").remove();
|
||||||
State.state = new State(undefined);
|
State.state = new State(undefined);
|
||||||
document.getElementById("messagesboxmobile").remove();
|
document.getElementById("messagesboxmobile").remove();
|
||||||
|
|
Loading…
Reference in a new issue