diff --git a/Logic/Actors/InstalledThemes.ts b/Logic/Actors/InstalledThemes.ts deleted file mode 100644 index 06c696a77..000000000 --- a/Logic/Actors/InstalledThemes.ts +++ /dev/null @@ -1,65 +0,0 @@ -import {UIEventSource} from "../UIEventSource"; -import {OsmConnection} from "../Osm/OsmConnection"; -import {Utils} from "../../Utils"; -import LZString from "lz-string"; -import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"; - -/** - * Gives an overview of themes that are installed in the user preferences - */ -export default class InstalledThemes { - public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; - - - constructor(osmConnection: OsmConnection) { - this.installedThemes = osmConnection.preferencesHandler.preferences.map<{ layout: LayoutConfig, definition: string }[]>(allPreferences => { - const installedThemes: { layout: LayoutConfig, definition: string }[] = []; - if (allPreferences === undefined) { - console.log("All prefs is undefined"); - return installedThemes; - } - const invalidThemes = [] - for (const allPreferencesKey in allPreferences) { - const themename = allPreferencesKey.match(/^mapcomplete-installed-theme-(.*)-combined-length$/); - if (themename && themename[1] !== "") { - const customLayout = osmConnection.GetLongPreference("installed-theme-" + themename[1]); - if (customLayout.data === undefined) { - console.log("No data defined for ", themename[1]); - continue; - } - try { - let layoutJson; - try { - layoutJson = JSON.parse(atob(customLayout.data)) - } catch (e) { - layoutJson = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(customLayout.data))) - } - const layout = new LayoutConfig(layoutJson, false); - installedThemes.push({ - layout: layout, - definition: customLayout.data - }); - } catch (e) { - console.warn("Could not parse custom layout from preferences - deleting: ", allPreferencesKey, e, customLayout.data); - invalidThemes.push(themename[1]) - } - } - } - - InstalledThemes.DeleteInvalid(osmConnection, invalidThemes); - - return installedThemes; - - }); - } - - private static DeleteInvalid(osmConnection: OsmConnection, invalidThemes: any[]) { - for (const invalid of invalidThemes) { - console.error("Attempting to remove ", invalid) - osmConnection.GetLongPreference( - "installed-theme-" + invalid - ).setData(null); - } - } - -} \ No newline at end of file diff --git a/Logic/DetermineLayout.ts b/Logic/DetermineLayout.ts index 0026499f1..5f9c1f0e6 100644 --- a/Logic/DetermineLayout.ts +++ b/Logic/DetermineLayout.ts @@ -14,6 +14,7 @@ import {FixLegacyTheme, PrepareTheme} from "../Models/ThemeConfig/LegacyJsonConv import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; import SharedTagRenderings from "../Customizations/SharedTagRenderings"; import * as known_layers from "../assets/generated/known_layers.json" +import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; export default class DetermineLayout { @@ -62,6 +63,22 @@ export default class DetermineLayout { return layoutToUse } + private static prepCustomTheme(json: any): LayoutConfigJson{ + const knownLayersDict = new Map() + for (const key in known_layers["default"]) { + const layer = known_layers["default"][key] + knownLayersDict.set(layer.id, layer) + } + const converState = { + tagRenderings: SharedTagRenderings.SharedTagRenderingJson, + sharedLayers: knownLayersDict + } + json = new FixLegacyTheme().convertStrict(converState, json, "While loading a dynamic theme") + json = new PrepareTheme().convertStrict(converState, json, "While preparing a dynamic theme") + console.log("The layoutconfig is ", json) + return json + } + public static LoadLayoutFromHash( userLayoutParam: UIEventSource ): LayoutConfig | null { @@ -102,25 +119,9 @@ export default class DetermineLayout { } } - const knownLayersDict = new Map() - for (const key in known_layers["default"]) { - const layer = known_layers["default"][key] - console.log("Found shared layer "+layer.id) - knownLayersDict.set(layer.id, layer) - } - - const converState = { - tagRenderings: SharedTagRenderings.SharedTagRenderingJson, - sharedLayers: knownLayersDict - } - - json = new FixLegacyTheme().convertStrict(converState, json, "While loading a dynamic theme") - - json = new PrepareTheme().convertStrict(converState, json, "While preparing a dynamic theme") - - const layoutToUse = new LayoutConfig(json, false); + const layoutToUse = DetermineLayout.prepCustomTheme(json) userLayoutParam.setData(layoutToUse.id); - return layoutToUse; + return new LayoutConfig(layoutToUse, false); } catch (e) { console.error(e) if (hash === undefined || hash.length < 10) { @@ -160,9 +161,14 @@ export default class DetermineLayout { tagRenderings: SharedTagRenderings.SharedTagRenderingJson, sharedLayers: new Map() // FIXME: actually add the layers }, parsed, "While loading a dynamic theme") - try { + + parsed.id = link; - return new LayoutConfig(parsed, false).patchImages(link, JSON.stringify(parsed)); + + + try { + const layoutToUse = DetermineLayout.prepCustomTheme(parsed) + return new LayoutConfig(layoutToUse,false).patchImages(link, JSON.stringify(layoutToUse)); } catch (e) { console.error(e) DetermineLayout.ShowErrorOnCustomTheme( diff --git a/Logic/State/UserRelatedState.ts b/Logic/State/UserRelatedState.ts index ca69006ac..37deb04dc 100644 --- a/Logic/State/UserRelatedState.ts +++ b/Logic/State/UserRelatedState.ts @@ -3,12 +3,12 @@ import {OsmConnection} from "../Osm/OsmConnection"; import {MangroveIdentity} from "../Web/MangroveReviews"; import {UIEventSource} from "../UIEventSource"; import {QueryParameters} from "../Web/QueryParameters"; -import InstalledThemes from "../Actors/InstalledThemes"; import {LocalStorageSource} from "../Web/LocalStorageSource"; import {Utils} from "../../Utils"; import Locale from "../../UI/i18n/Locale"; import ElementsState from "./ElementsState"; import SelectedElementTagsUpdater from "../Actors/SelectedElementTagsUpdater"; +import {log} from "util"; /** * The part of the state which keeps track of user-related stuff, e.g. the OSM-connection, @@ -33,7 +33,10 @@ export default class UserRelatedState extends ElementsState { /** * WHich other themes the user previously visited */ - public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; + public installedThemes: UIEventSource<{ id: string, // The id doubles as the URL + icon: string, + title: any, + shortDescription: any}[]>; constructor(layoutToUse: LayoutConfig, options?:{attemptLogin : true | boolean}) { @@ -69,9 +72,47 @@ export default class UserRelatedState extends ElementsState { }) } - this.installedThemes = new InstalledThemes( - this.osmConnection - ).installedThemes; + this.installedThemes = this.osmConnection.GetLongPreference("installed-themes").map( + str => { + if(str === undefined || str === ""){ + return [] + } + try{ + return JSON.parse(str) + }catch(e){ + console.warn("Could not parse preference with installed themes due to ", e,"\nThe offending string is",str) + return [] + } + }, [],(installed => JSON.stringify(installed)) + ) + + + const self = this; + this.osmConnection.isLoggedIn.addCallbackAndRunD(loggedIn => { + if(!loggedIn){ + return + } + + if(this.layoutToUse.id.startsWith("http")){ + if(!this.installedThemes.data.some(installed => installed.id === this.layoutToUse.id)){ + + this.installedThemes.data.push({ + id: this.layoutToUse.id, + icon: this.layoutToUse.icon, + title: this.layoutToUse.title.translations, + shortDescription: this.layoutToUse.shortDescription.translations + }) + } + this.installedThemes.ping() + console.log("Registered "+this.layoutToUse.id+" as installed themes") + } + + + + + return true; + }) + // Important: the favourite layers are initialized _after_ the installed themes, as these might contain an installedTheme this.favouriteLayers = LocalStorageSource.Get("favouriteLayers") @@ -81,8 +122,7 @@ export default class UserRelatedState extends ElementsState { [], (layers) => Utils.Dedup(layers)?.join(";") ); - - + this.InitializeLanguage(); new SelectedElementTagsUpdater(this) diff --git a/UI/BigComponents/MoreScreen.ts b/UI/BigComponents/MoreScreen.ts index 066f39964..5cde4729f 100644 --- a/UI/BigComponents/MoreScreen.ts +++ b/UI/BigComponents/MoreScreen.ts @@ -53,7 +53,7 @@ export default class MoreScreen extends Combine { icon: string, title: any, shortDescription: any - }, customThemeDefinition: string = undefined + }, isCustom: boolean = false ): BaseUIElement { if (layout === undefined) { @@ -79,14 +79,12 @@ export default class MoreScreen extends Combine { } let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?` - let linkSuffix = "" if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { linkPrefix = `${path}/theme.html?layout=${layout.id}&` } - if (customThemeDefinition) { + if (isCustom) { linkPrefix = `${path}/theme.html?userlayout=${layout.id}&` - linkSuffix = `#${customThemeDefinition}` } const linkText = currentLocation?.map(currentLocation => { @@ -97,8 +95,8 @@ export default class MoreScreen extends Combine { ].filter(part => part[1] !== undefined) .map(part => part[0] + "=" + part[1]) .join("&") - return `${linkPrefix}${params}${linkSuffix}`; - }) ?? new UIEventSource(`${linkPrefix}${linkSuffix}`) + return `${linkPrefix}${params}`; + }) ?? new UIEventSource(`${linkPrefix}`) return new SubtleButton(layout.icon, @@ -117,7 +115,7 @@ export default class MoreScreen extends Combine { if (customThemes.length <= 0) { return undefined; } - const customThemeButtons = customThemes.map(theme => MoreScreen.createLinkButton(state, theme.layout, theme.definition)?.SetClass(buttonClass)) + const customThemeButtons = customThemes.map(theme => MoreScreen.createLinkButton(state, theme, true)?.SetClass(buttonClass)) return new Combine([ Translations.t.general.customThemeIntro.Clone(), new Combine(customThemeButtons).SetClass(themeListClasses) diff --git a/preferences.html b/preferences.html deleted file mode 100644 index 10250978c..000000000 --- a/preferences.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Preferences editor - - - - - - -

Preferences editor - developers only

-Only use if you know what you're doing. To prevent newbies to make mistakes here, editing a mapcomplete-preference is -only available if over 500 changes
-Editing any preference -including non-mapcomplete ones- is available when you have more then 2500 changesets. Until that -point, only editing mapcomplete-preferences is possible. -
'maindiv' not attached
- - - \ No newline at end of file diff --git a/preferences.ts b/preferences.ts deleted file mode 100644 index bef8b6d5d..000000000 --- a/preferences.ts +++ /dev/null @@ -1,154 +0,0 @@ -import {OsmConnection} from "./Logic/Osm/OsmConnection"; -import Combine from "./UI/Base/Combine"; -import {Button} from "./UI/Base/Button"; -import {TextField} from "./UI/Input/TextField"; -import {FixedUiElement} from "./UI/Base/FixedUiElement"; -import {Utils} from "./Utils"; -import {SubtleButton} from "./UI/Base/SubtleButton"; -import LZString from "lz-string"; -import BaseUIElement from "./UI/BaseUIElement"; -import Table from "./UI/Base/Table"; -import {LayoutConfigJson} from "./Models/ThemeConfig/Json/LayoutConfigJson"; -import {Changes} from "./Logic/Osm/Changes"; -import {ElementStorage} from "./Logic/ElementStorage"; - - -const connection = new OsmConnection({ - osmConfiguration: 'osm', - changes: new Changes(), - layoutName: '', - allElements: new ElementStorage() -}); - - -let rendered = false; - -function salvageThemes(preferences: any) { - const knownThemeNames = new Set(); - const correctThemeNames = [] - for (const key in preferences) { - try { - if (!(typeof key === "string")) { - continue; - } - const prefix = "mapcomplete-installed-theme-"; - // mapcomplete-installed-theme-arbres_llefia-combined-11 - //mapcomplete-installed-theme-1roadAlllanes-combined-length - if (!key.startsWith(prefix)) { - continue; - } - const theme = key.substring(prefix.length, key.indexOf("-combined-")) - - if (key.endsWith("-length")) { - correctThemeNames.push(theme) - } else { - knownThemeNames.add(theme); - } - } catch (e) { - console.error(e) - } - } - - for (const correctThemeName of correctThemeNames) { - knownThemeNames.delete(correctThemeName); - } - - const missingValues = Array.from(knownThemeNames).map(failedTheme => { - - let i = 0; - let foundValue = undefined - let combined = "" - do { - const prefix = "mapcomplete-installed-theme-"; - const key = prefix + failedTheme + "-combined-" + i; - foundValue = preferences[key] - console.log(key, "-->", foundValue) - i++; - combined += foundValue ?? "" - } while (foundValue !== undefined); - - if (combined === "") { - return null; - } - - console.log("COmbined value is", combined) - let jsonObject; - try { - jsonObject = JSON.parse(atob(combined)); - } catch (e) { - try { - - // We try to decode with lz-string - jsonObject = JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(combined))) as LayoutConfigJson; - } catch (e0) { - console.log("Could not salvage theme. Initial parsing failed due to:", e, "\nWith LZ failed due ", e0) - } - - } - - return { - themeName: failedTheme, - contents: JSON.stringify(jsonObject, null, " ") - } - }) - return Utils.NoNull(missingValues); -} - -function clearAll(preferences) { - for (const key in preferences) { - const pref = connection.GetPreference(key, ""); - if (key.startsWith("mapcomplete")) { - pref.setData("") - } - } -} - -function SalvageButton(theme: { themeName: string, contents: string }) { - return new SubtleButton("./assets/svg/bug.svg", "Download broken theme " + theme.themeName).onClick( - () => { - Utils.offerContentsAsDownloadableFile(theme.contents, theme.themeName + ".json") - } - ) -} - -function createTable(preferences: any) { - if (rendered) { - return; - } - rendered = true; - const prefs: (BaseUIElement | string)[][] = []; - for (const key in preferences) { - if (!preferences.hasOwnProperty(key)) { - continue; - } - const pref = connection.GetPreference(key, ""); - - let value: BaseUIElement = new FixedUiElement(pref.data); - if (connection.userDetails.data.csCount > 500 && - (key.startsWith("mapcomplete") || connection.userDetails.data.csCount > 2500)) { - value = new TextField({ - value: pref - }); - } - - const row = [ - key, - new Button("delete", () => pref.setData(null)), - value - ]; - prefs.push(row); - } - - new Combine( - [ - ...salvageThemes(preferences).map(theme => SalvageButton(theme)), - new Table( - ["Key", "", "Value"], - prefs - ), - new SubtleButton("./assets/svg/delete_icon.svg", "Delete all mapcomplete preferences (mangrove identies are preserved)").onClick(() => clearAll(preferences))] - ).AttachTo("maindiv"); -} - -connection.preferencesHandler.preferences.addCallback((prefs) => createTable(prefs)) -