forked from MapComplete/MapComplete
		
	Remove unmaintained preferences page, re-add earlier visited installed themes (only remove themes)
This commit is contained in:
		
							parent
							
								
									4b6769d601
								
							
						
					
					
						commit
						7fe79600fb
					
				
					 6 changed files with 78 additions and 282 deletions
				
			
		| 
						 | 
					@ -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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ import {FixLegacyTheme, PrepareTheme} from "../Models/ThemeConfig/LegacyJsonConv
 | 
				
			||||||
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
 | 
					import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
 | 
				
			||||||
import SharedTagRenderings from "../Customizations/SharedTagRenderings";
 | 
					import SharedTagRenderings from "../Customizations/SharedTagRenderings";
 | 
				
			||||||
import * as known_layers from "../assets/generated/known_layers.json"
 | 
					import * as known_layers from "../assets/generated/known_layers.json"
 | 
				
			||||||
 | 
					import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class DetermineLayout {
 | 
					export default class DetermineLayout {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +63,22 @@ export default class DetermineLayout {
 | 
				
			||||||
        return layoutToUse
 | 
					        return layoutToUse
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static prepCustomTheme(json: any): LayoutConfigJson{
 | 
				
			||||||
 | 
					        const knownLayersDict = new Map<string, LayerConfigJson>()
 | 
				
			||||||
 | 
					        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(
 | 
					    public static LoadLayoutFromHash(
 | 
				
			||||||
        userLayoutParam: UIEventSource<string>
 | 
					        userLayoutParam: UIEventSource<string>
 | 
				
			||||||
    ): LayoutConfig | null {
 | 
					    ): LayoutConfig | null {
 | 
				
			||||||
| 
						 | 
					@ -102,25 +119,9 @@ export default class DetermineLayout {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const knownLayersDict = new Map<string, LayerConfigJson>()
 | 
					            const layoutToUse = DetermineLayout.prepCustomTheme(json)
 | 
				
			||||||
            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);
 | 
					 | 
				
			||||||
            userLayoutParam.setData(layoutToUse.id);
 | 
					            userLayoutParam.setData(layoutToUse.id);
 | 
				
			||||||
            return layoutToUse;
 | 
					            return new LayoutConfig(layoutToUse, false);
 | 
				
			||||||
        } catch (e) {
 | 
					        } catch (e) {
 | 
				
			||||||
            console.error(e)
 | 
					            console.error(e)
 | 
				
			||||||
            if (hash === undefined || hash.length < 10) {
 | 
					            if (hash === undefined || hash.length < 10) {
 | 
				
			||||||
| 
						 | 
					@ -160,9 +161,14 @@ export default class DetermineLayout {
 | 
				
			||||||
                tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
 | 
					                tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
 | 
				
			||||||
                sharedLayers: new Map<string, LayerConfigJson>() // FIXME: actually add the layers
 | 
					                sharedLayers: new Map<string, LayerConfigJson>() // FIXME: actually add the layers
 | 
				
			||||||
            }, parsed, "While loading a dynamic theme")
 | 
					            }, parsed, "While loading a dynamic theme")
 | 
				
			||||||
            try {
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                parsed.id = link;
 | 
					                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) {
 | 
					            } catch (e) {
 | 
				
			||||||
                console.error(e)
 | 
					                console.error(e)
 | 
				
			||||||
                DetermineLayout.ShowErrorOnCustomTheme(
 | 
					                DetermineLayout.ShowErrorOnCustomTheme(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,12 +3,12 @@ import {OsmConnection} from "../Osm/OsmConnection";
 | 
				
			||||||
import {MangroveIdentity} from "../Web/MangroveReviews";
 | 
					import {MangroveIdentity} from "../Web/MangroveReviews";
 | 
				
			||||||
import {UIEventSource} from "../UIEventSource";
 | 
					import {UIEventSource} from "../UIEventSource";
 | 
				
			||||||
import {QueryParameters} from "../Web/QueryParameters";
 | 
					import {QueryParameters} from "../Web/QueryParameters";
 | 
				
			||||||
import InstalledThemes from "../Actors/InstalledThemes";
 | 
					 | 
				
			||||||
import {LocalStorageSource} from "../Web/LocalStorageSource";
 | 
					import {LocalStorageSource} from "../Web/LocalStorageSource";
 | 
				
			||||||
import {Utils} from "../../Utils";
 | 
					import {Utils} from "../../Utils";
 | 
				
			||||||
import Locale from "../../UI/i18n/Locale";
 | 
					import Locale from "../../UI/i18n/Locale";
 | 
				
			||||||
import ElementsState from "./ElementsState";
 | 
					import ElementsState from "./ElementsState";
 | 
				
			||||||
import SelectedElementTagsUpdater from "../Actors/SelectedElementTagsUpdater";
 | 
					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,
 | 
					 * 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
 | 
					     * 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}) {
 | 
					    constructor(layoutToUse: LayoutConfig, options?:{attemptLogin : true | boolean}) {
 | 
				
			||||||
| 
						 | 
					@ -69,9 +72,47 @@ export default class UserRelatedState extends ElementsState {
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.installedThemes = new InstalledThemes(
 | 
					        this.installedThemes = this.osmConnection.GetLongPreference("installed-themes").map(
 | 
				
			||||||
            this.osmConnection
 | 
					            str => {
 | 
				
			||||||
        ).installedThemes;
 | 
					                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
 | 
					        // Important: the favourite layers are initialized _after_ the installed themes, as these might contain an installedTheme
 | 
				
			||||||
        this.favouriteLayers = LocalStorageSource.Get("favouriteLayers")
 | 
					        this.favouriteLayers = LocalStorageSource.Get("favouriteLayers")
 | 
				
			||||||
| 
						 | 
					@ -82,7 +123,6 @@ export default class UserRelatedState extends ElementsState {
 | 
				
			||||||
                (layers) => Utils.Dedup(layers)?.join(";")
 | 
					                (layers) => Utils.Dedup(layers)?.join(";")
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.InitializeLanguage();
 | 
					        this.InitializeLanguage();
 | 
				
			||||||
        new SelectedElementTagsUpdater(this)
 | 
					        new SelectedElementTagsUpdater(this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
            icon: string,
 | 
					            icon: string,
 | 
				
			||||||
            title: any,
 | 
					            title: any,
 | 
				
			||||||
            shortDescription: any
 | 
					            shortDescription: any
 | 
				
			||||||
        }, customThemeDefinition: string = undefined
 | 
					        }, isCustom: boolean = false
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        BaseUIElement {
 | 
					        BaseUIElement {
 | 
				
			||||||
        if (layout === undefined) {
 | 
					        if (layout === undefined) {
 | 
				
			||||||
| 
						 | 
					@ -79,14 +79,12 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
 | 
					        let linkPrefix = `${path}/${layout.id.toLowerCase()}.html?`
 | 
				
			||||||
        let linkSuffix = ""
 | 
					 | 
				
			||||||
        if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
 | 
					        if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
 | 
				
			||||||
            linkPrefix = `${path}/theme.html?layout=${layout.id}&`
 | 
					            linkPrefix = `${path}/theme.html?layout=${layout.id}&`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (customThemeDefinition) {
 | 
					        if (isCustom) {
 | 
				
			||||||
            linkPrefix = `${path}/theme.html?userlayout=${layout.id}&`
 | 
					            linkPrefix = `${path}/theme.html?userlayout=${layout.id}&`
 | 
				
			||||||
            linkSuffix = `#${customThemeDefinition}`
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const linkText = currentLocation?.map(currentLocation => {
 | 
					        const linkText = currentLocation?.map(currentLocation => {
 | 
				
			||||||
| 
						 | 
					@ -97,8 +95,8 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
            ].filter(part => part[1] !== undefined)
 | 
					            ].filter(part => part[1] !== undefined)
 | 
				
			||||||
                .map(part => part[0] + "=" + part[1])
 | 
					                .map(part => part[0] + "=" + part[1])
 | 
				
			||||||
                .join("&")
 | 
					                .join("&")
 | 
				
			||||||
            return `${linkPrefix}${params}${linkSuffix}`;
 | 
					            return `${linkPrefix}${params}`;
 | 
				
			||||||
        }) ?? new UIEventSource<string>(`${linkPrefix}${linkSuffix}`)
 | 
					        }) ?? new UIEventSource<string>(`${linkPrefix}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new SubtleButton(layout.icon,
 | 
					        return new SubtleButton(layout.icon,
 | 
				
			||||||
| 
						 | 
					@ -117,7 +115,7 @@ export default class MoreScreen extends Combine {
 | 
				
			||||||
            if (customThemes.length <= 0) {
 | 
					            if (customThemes.length <= 0) {
 | 
				
			||||||
                return undefined;
 | 
					                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([
 | 
					            return new Combine([
 | 
				
			||||||
                Translations.t.general.customThemeIntro.Clone(),
 | 
					                Translations.t.general.customThemeIntro.Clone(),
 | 
				
			||||||
                new Combine(customThemeButtons).SetClass(themeListClasses)
 | 
					                new Combine(customThemeButtons).SetClass(themeListClasses)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,29 +0,0 @@
 | 
				
			||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html>
 | 
					 | 
				
			||||||
<head>
 | 
					 | 
				
			||||||
    <link href="index.css" rel="stylesheet"/>
 | 
					 | 
				
			||||||
    <title>Preferences editor</title>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <style>
 | 
					 | 
				
			||||||
        table {
 | 
					 | 
				
			||||||
            border-collapse: collapse;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        table, th, td {
 | 
					 | 
				
			||||||
            border: 1px solid black;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    </style>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
<h1>Preferences editor - developers only</h1>
 | 
					 | 
				
			||||||
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<br/>
 | 
					 | 
				
			||||||
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.
 | 
					 | 
				
			||||||
<div id="maindiv">'maindiv' not attached</div>
 | 
					 | 
				
			||||||
<script src="./preferences.ts"></script>
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
							
								
								
									
										154
									
								
								preferences.ts
									
										
									
									
									
								
							
							
						
						
									
										154
									
								
								preferences.ts
									
										
									
									
									
								
							| 
						 | 
					@ -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<string>();
 | 
					 | 
				
			||||||
    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))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue