forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			156 lines
		
	
	
		
			No EOL
		
	
	
		
			5.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			No EOL
		
	
	
		
			5.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import {Store} from "../../Logic/UIEventSource";
 | 
						|
import BaseUIElement from "../BaseUIElement";
 | 
						|
import Combine from "../Base/Combine";
 | 
						|
import {SubtleButton} from "../Base/SubtleButton";
 | 
						|
import {Changes} from "../../Logic/Osm/Changes";
 | 
						|
import {FixedUiElement} from "../Base/FixedUiElement";
 | 
						|
import Translations from "../i18n/Translations";
 | 
						|
import {VariableUiElement} from "../Base/VariableUIElement";
 | 
						|
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction";
 | 
						|
import {Tag} from "../../Logic/Tags/Tag";
 | 
						|
import {ElementStorage} from "../../Logic/ElementStorage";
 | 
						|
import {And} from "../../Logic/Tags/And";
 | 
						|
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
 | 
						|
import Toggle from "../Input/Toggle";
 | 
						|
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
 | 
						|
 | 
						|
 | 
						|
export interface MultiApplyParams {
 | 
						|
    featureIds: Store<string[]>,
 | 
						|
    keysToApply: string[],
 | 
						|
    text: string,
 | 
						|
    autoapply: boolean,
 | 
						|
    overwrite: boolean,
 | 
						|
    tagsSource: Store<any>,
 | 
						|
    state: {
 | 
						|
        changes: Changes,
 | 
						|
        allElements: ElementStorage,
 | 
						|
        layoutToUse: LayoutConfig,
 | 
						|
        osmConnection: OsmConnection
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class MultiApplyExecutor {
 | 
						|
 | 
						|
    private static executorCache = new Map<string, MultiApplyExecutor>()
 | 
						|
    private readonly originalValues = new Map<string, string>()
 | 
						|
    private readonly params: MultiApplyParams;
 | 
						|
 | 
						|
    private constructor(params: MultiApplyParams) {
 | 
						|
        this.params = params;
 | 
						|
        const p = params
 | 
						|
 | 
						|
        for (const key of p.keysToApply) {
 | 
						|
            this.originalValues.set(key, p.tagsSource.data[key])
 | 
						|
        }
 | 
						|
 | 
						|
        if (p.autoapply) {
 | 
						|
 | 
						|
            const self = this;
 | 
						|
            const relevantValues = p.tagsSource.map(tags => {
 | 
						|
                const currentValues = p.keysToApply.map(key => tags[key])
 | 
						|
                // By stringifying, we have a very clear ping when they changec
 | 
						|
                return JSON.stringify(currentValues);
 | 
						|
            })
 | 
						|
            relevantValues.addCallbackD(_ => {
 | 
						|
                self.applyTaggingOnOtherFeatures()
 | 
						|
            })
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static GetApplicator(id: string, params: MultiApplyParams): MultiApplyExecutor {
 | 
						|
        if (MultiApplyExecutor.executorCache.has(id)) {
 | 
						|
            return MultiApplyExecutor.executorCache.get(id)
 | 
						|
        }
 | 
						|
        const applicator = new MultiApplyExecutor(params)
 | 
						|
        MultiApplyExecutor.executorCache.set(id, applicator)
 | 
						|
        return applicator
 | 
						|
    }
 | 
						|
 | 
						|
    public applyTaggingOnOtherFeatures() {
 | 
						|
        console.log("Multi-applying changes...")
 | 
						|
        const featuresToChange = this.params.featureIds.data
 | 
						|
        const changes = this.params.state.changes
 | 
						|
        const allElements = this.params.state.allElements
 | 
						|
        const keysToChange = this.params.keysToApply
 | 
						|
        const overwrite = this.params.overwrite
 | 
						|
        const selfTags = this.params.tagsSource.data;
 | 
						|
        const theme = this.params.state.layoutToUse.id
 | 
						|
        for (const id of featuresToChange) {
 | 
						|
            const tagsToApply: Tag[] = []
 | 
						|
            const otherFeatureTags = allElements.getEventSourceById(id).data
 | 
						|
            for (const key of keysToChange) {
 | 
						|
                const newValue = selfTags[key]
 | 
						|
                if (newValue === undefined) {
 | 
						|
                    continue
 | 
						|
                }
 | 
						|
                const otherValue = otherFeatureTags[key]
 | 
						|
                if (newValue === otherValue) {
 | 
						|
                    continue;// No changes to be made
 | 
						|
                }
 | 
						|
 | 
						|
                if (overwrite) {
 | 
						|
                    tagsToApply.push(new Tag(key, newValue))
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
                if (otherValue === undefined || otherValue === "" || otherValue === this.originalValues.get(key)) {
 | 
						|
                    tagsToApply.push(new Tag(key, newValue))
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (tagsToApply.length == 0) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            changes.applyAction(
 | 
						|
                new ChangeTagAction(id, new And(tagsToApply), otherFeatureTags, {
 | 
						|
                    theme,
 | 
						|
                    changeType: "answer"
 | 
						|
                }))
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
export default class MultiApply extends Toggle {
 | 
						|
 | 
						|
    constructor(params: MultiApplyParams) {
 | 
						|
        const p = params
 | 
						|
        const t = Translations.t.multi_apply
 | 
						|
 | 
						|
        
 | 
						|
        const featureId = p.tagsSource.data.id
 | 
						|
 | 
						|
        if (featureId === undefined) {
 | 
						|
            throw "MultiApply needs a feature id"
 | 
						|
        }
 | 
						|
 | 
						|
        const applicator = MultiApplyExecutor.GetApplicator(featureId, params)
 | 
						|
 | 
						|
        const elems: (string | BaseUIElement)[] = []
 | 
						|
        if (p.autoapply) {
 | 
						|
            elems.push(new FixedUiElement(p.text).SetClass("block"))
 | 
						|
            elems.push(new VariableUiElement(p.featureIds.map(featureIds =>
 | 
						|
                t.autoApply.Subs({
 | 
						|
                    attr_names: p.keysToApply.join(", "),
 | 
						|
                    count: "" + featureIds.length
 | 
						|
                }))).SetClass("block subtle text-sm"))
 | 
						|
        } else {
 | 
						|
            elems.push(
 | 
						|
                new SubtleButton(undefined, p.text).onClick(() => applicator.applyTaggingOnOtherFeatures())
 | 
						|
            )
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        const isShown: Store<boolean> = p.state.osmConnection.isLoggedIn.map(loggedIn => {
 | 
						|
            return loggedIn && p.featureIds.data.length > 0
 | 
						|
        }, [p.featureIds])
 | 
						|
        super(new Combine(elems), undefined, isShown);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
} |