forked from MapComplete/MapComplete
Huge refactoring of state and initial UI setup
This commit is contained in:
parent
4e43673de5
commit
eff6b5bfad
37 changed files with 5232 additions and 4907 deletions
168
Logic/DetermineLayout.ts
Normal file
168
Logic/DetermineLayout.ts
Normal file
|
@ -0,0 +1,168 @@
|
|||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
|
||||
import {QueryParameters} from "./Web/QueryParameters";
|
||||
import {AllKnownLayouts} from "../Customizations/AllKnownLayouts";
|
||||
import {FixedUiElement} from "../UI/Base/FixedUiElement";
|
||||
import {Utils} from "../Utils";
|
||||
import Combine from "../UI/Base/Combine";
|
||||
import {SubtleButton} from "../UI/Base/SubtleButton";
|
||||
import BaseUIElement from "../UI/BaseUIElement";
|
||||
import {UIEventSource} from "./UIEventSource";
|
||||
import {LocalStorageSource} from "./Web/LocalStorageSource";
|
||||
import LZString from "lz-string";
|
||||
import * as personal from "../assets/themes/personal/personal.json";
|
||||
|
||||
export default class DetermineLayout {
|
||||
|
||||
/**
|
||||
* Gets the correct layout for this website
|
||||
*/
|
||||
public static async GetLayout(): Promise<[LayoutConfig, string]> {
|
||||
|
||||
|
||||
const loadCustomThemeParam = QueryParameters.GetQueryParameter("userlayout", "false", "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme")
|
||||
const layoutFromBase64 = decodeURIComponent(loadCustomThemeParam.data);
|
||||
|
||||
if (layoutFromBase64.startsWith("http")) {
|
||||
// The userLayout is actually an url
|
||||
const layout = await DetermineLayout.LoadRemoteTheme(layoutFromBase64)
|
||||
return [layout, undefined]
|
||||
}
|
||||
|
||||
if (layoutFromBase64 !== "false") {
|
||||
// We have to load something from the hash (or from disk)
|
||||
let loaded = DetermineLayout.LoadLayoutFromHash(loadCustomThemeParam);
|
||||
if (loaded === null) {
|
||||
return [null, undefined]
|
||||
}
|
||||
return loaded
|
||||
}
|
||||
|
||||
let layoutId: string = undefined
|
||||
if (location.href.indexOf("buurtnatuur.be") >= 0) {
|
||||
layoutId = "buurtnatuur"
|
||||
}
|
||||
|
||||
|
||||
const path = window.location.pathname.split("/").slice(-1)[0];
|
||||
if (path !== "index.html" && path !== "") {
|
||||
layoutId = path;
|
||||
if (path.endsWith(".html")) {
|
||||
layoutId = path.substr(0, path.length - 5);
|
||||
}
|
||||
console.log("Using layout", layoutId);
|
||||
}
|
||||
layoutId = QueryParameters.GetQueryParameter("layout", layoutId, "The layout to load into MapComplete").data;
|
||||
const layoutToUse: LayoutConfig = AllKnownLayouts.allKnownLayouts.get(layoutId?.toLowerCase());
|
||||
|
||||
if (layoutToUse?.id === personal.id) {
|
||||
layoutToUse.layers = AllKnownLayouts.AllPublicLayers()
|
||||
for (const layer of layoutToUse.layers) {
|
||||
layer.minzoomVisible = Math.max(layer.minzoomVisible, layer.minzoom)
|
||||
layer.minzoom = Math.max(16, layer.minzoom)
|
||||
}
|
||||
}
|
||||
|
||||
return [layoutToUse, undefined]
|
||||
}
|
||||
|
||||
private static async LoadRemoteTheme(link: string): Promise<LayoutConfig | null> {
|
||||
console.log("Downloading map theme from ", link);
|
||||
|
||||
new FixedUiElement(`Downloading the theme from the <a href="${link}">link</a>...`)
|
||||
.AttachTo("centermessage");
|
||||
|
||||
try {
|
||||
|
||||
const data = await Utils.downloadJson(link)
|
||||
try {
|
||||
let parsed = data;
|
||||
if (typeof parsed == "string") {
|
||||
parsed = JSON.parse(parsed);
|
||||
}
|
||||
// Overwrite the id to the url
|
||||
parsed.id = link;
|
||||
return new LayoutConfig(parsed, false).patchImages(link, data);
|
||||
} catch (e) {
|
||||
|
||||
DetermineLayout.ShowErrorOnCustomTheme(
|
||||
`<a href="${link}">${link}</a> is invalid:`,
|
||||
new FixedUiElement(e)
|
||||
)
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
DetermineLayout.ShowErrorOnCustomTheme(
|
||||
`<a href="${link}">${link}</a> is invalid - probably not found or invalid JSON:`,
|
||||
new FixedUiElement(e)
|
||||
)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static LoadLayoutFromHash(
|
||||
userLayoutParam: UIEventSource<string>
|
||||
): [LayoutConfig, string] | null {
|
||||
let hash = location.hash.substr(1);
|
||||
try {
|
||||
// layoutFromBase64 contains the name of the theme. This is partly to do tracking with goat counter
|
||||
const dedicatedHashFromLocalStorage = LocalStorageSource.Get(
|
||||
"user-layout-" + userLayoutParam.data.replace(" ", "_")
|
||||
);
|
||||
if (dedicatedHashFromLocalStorage.data?.length < 10) {
|
||||
dedicatedHashFromLocalStorage.setData(undefined);
|
||||
}
|
||||
|
||||
const hashFromLocalStorage = LocalStorageSource.Get(
|
||||
"last-loaded-user-layout"
|
||||
);
|
||||
if (hash.length < 10) {
|
||||
hash =
|
||||
dedicatedHashFromLocalStorage.data ??
|
||||
hashFromLocalStorage.data;
|
||||
} else {
|
||||
console.log("Saving hash to local storage");
|
||||
hashFromLocalStorage.setData(hash);
|
||||
dedicatedHashFromLocalStorage.setData(hash);
|
||||
}
|
||||
|
||||
let json: any;
|
||||
try {
|
||||
json = JSON.parse(atob(hash));
|
||||
} catch (e) {
|
||||
// We try to decode with lz-string
|
||||
try {
|
||||
json = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(hash)))
|
||||
} catch (e) {
|
||||
DetermineLayout.ShowErrorOnCustomTheme("Could not decode the hash", new FixedUiElement("Not a valid (LZ-compressed) JSON"))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const layoutToUse = new LayoutConfig(json, false);
|
||||
userLayoutParam.setData(layoutToUse.id);
|
||||
return [layoutToUse, btoa(Utils.MinifyJSON(JSON.stringify(json)))];
|
||||
} catch (e) {
|
||||
if (hash === undefined || hash.length < 10) {
|
||||
DetermineLayout.ShowErrorOnCustomTheme("Could not load a theme from the hash", new FixedUiElement("Hash does not contain data"))
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ShowErrorOnCustomTheme(
|
||||
intro: string = "Error: could not parse the custom layout:",
|
||||
error: BaseUIElement) {
|
||||
new Combine([
|
||||
intro,
|
||||
error.SetClass("alert"),
|
||||
new SubtleButton("./assets/svg/mapcomplete_logo.svg",
|
||||
"Go back to the theme overview",
|
||||
{url: window.location.protocol + "//" + window.location.hostname + "/index.html", newTab: false})
|
||||
|
||||
])
|
||||
.SetClass("flex flex-col clickable")
|
||||
.AttachTo("centermessage");
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue