forked from MapComplete/MapComplete
		
	Also pickup wikimedia categories in the image tags, fix #433
This commit is contained in:
		
							parent
							
								
									8cbb693c98
								
							
						
					
					
						commit
						32cbd6e2c1
					
				
					 6 changed files with 55 additions and 31 deletions
				
			
		| 
						 | 
					@ -5,7 +5,6 @@ import GenericImageProvider from "./GenericImageProvider";
 | 
				
			||||||
import {UIEventSource} from "../UIEventSource";
 | 
					import {UIEventSource} from "../UIEventSource";
 | 
				
			||||||
import ImageProvider, {ProvidedImage} from "./ImageProvider";
 | 
					import ImageProvider, {ProvidedImage} from "./ImageProvider";
 | 
				
			||||||
import {WikidataImageProvider} from "./WikidataImageProvider";
 | 
					import {WikidataImageProvider} from "./WikidataImageProvider";
 | 
				
			||||||
import {Utils} from "../../Utils";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A generic 'from the interwebz' image picker, without attribution
 | 
					 * A generic 'from the interwebz' image picker, without attribution
 | 
				
			||||||
| 
						 | 
					@ -17,12 +16,12 @@ export default class AllImageProviders {
 | 
				
			||||||
        Mapillary.singleton,
 | 
					        Mapillary.singleton,
 | 
				
			||||||
        WikidataImageProvider.singleton,
 | 
					        WikidataImageProvider.singleton,
 | 
				
			||||||
        WikimediaImageProvider.singleton,
 | 
					        WikimediaImageProvider.singleton,
 | 
				
			||||||
        new GenericImageProvider(Imgur.defaultValuePrefix)]
 | 
					        new GenericImageProvider([].concat(...Imgur.defaultValuePrefix, WikimediaImageProvider.commonsPrefix))]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
 | 
					    private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static LoadImagesFor(tags: UIEventSource<any>, imagePrefix: string, loadSpecialSource: boolean): UIEventSource<ProvidedImage[]> {
 | 
					    public static LoadImagesFor(tags: UIEventSource<any>, imagePrefix?: string): UIEventSource<ProvidedImage[]> {
 | 
				
			||||||
        const id = tags.data.id
 | 
					        const id = tags.data.id
 | 
				
			||||||
        if (id === undefined) {
 | 
					        if (id === undefined) {
 | 
				
			||||||
            return undefined;
 | 
					            return undefined;
 | 
				
			||||||
| 
						 | 
					@ -33,11 +32,14 @@ export default class AllImageProviders {
 | 
				
			||||||
            return cached
 | 
					            return cached
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const source = new UIEventSource([])
 | 
					        const source = new UIEventSource([])
 | 
				
			||||||
        this._cache.set(id, source)
 | 
					        this._cache.set(id, source)
 | 
				
			||||||
        const allSources = []
 | 
					        const allSources = []
 | 
				
			||||||
        for (const imageProvider of AllImageProviders.ImageAttributionSource) {
 | 
					        for (const imageProvider of AllImageProviders.ImageAttributionSource) {
 | 
				
			||||||
            const singleSource = imageProvider.GetRelevantUrls(tags)
 | 
					            const singleSource = imageProvider.GetRelevantUrls(tags, {
 | 
				
			||||||
 | 
					                prefixes: imagePrefix !== undefined ? [imagePrefix] : undefined
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
            allSources.push(singleSource)
 | 
					            allSources.push(singleSource)
 | 
				
			||||||
            singleSource.addCallbackAndRunD(_ => {
 | 
					            singleSource.addCallbackAndRunD(_ => {
 | 
				
			||||||
                const all : ProvidedImage[] = [].concat(...allSources.map(source => source.data))
 | 
					                const all : ProvidedImage[] = [].concat(...allSources.map(source => source.data))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,12 +11,15 @@ import {LicenseInfo} from "./LicenseInfo";
 | 
				
			||||||
export class WikimediaImageProvider extends ImageProvider {
 | 
					export class WikimediaImageProvider extends ImageProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public readonly defaultKeyPrefixes = ["wikimedia_commons"]
 | 
					    private readonly commons_key = "wikimedia_commons"
 | 
				
			||||||
 | 
					    public readonly defaultKeyPrefixes = [this.commons_key,"image"]
 | 
				
			||||||
    public static readonly singleton = new WikimediaImageProvider();
 | 
					    public static readonly singleton = new WikimediaImageProvider();
 | 
				
			||||||
 | 
					    public static readonly commonsPrefix = "https://commons.wikimedia.org/wiki/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private constructor() {
 | 
					    private constructor() {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Recursively walks a wikimedia commons category in order to search for (image) files
 | 
					     * Recursively walks a wikimedia commons category in order to search for (image) files
 | 
				
			||||||
     * Returns (a promise of) a list of URLS
 | 
					     * Returns (a promise of) a list of URLS
 | 
				
			||||||
| 
						 | 
					@ -132,9 +135,13 @@ export class WikimediaImageProvider extends ImageProvider {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
 | 
					    public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
 | 
				
			||||||
        const commonsPrefix = "https://commons.wikimedia.org/wiki/"
 | 
					        
 | 
				
			||||||
        if(value.startsWith(commonsPrefix)){
 | 
					        if(key !== this.commons_key && !value.startsWith(WikimediaImageProvider.commonsPrefix)){
 | 
				
			||||||
            value = value.substring(commonsPrefix.length)
 | 
					            return []
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (value.startsWith(WikimediaImageProvider.commonsPrefix)) {
 | 
				
			||||||
 | 
					            value = value.substring(WikimediaImageProvider.commonsPrefix.length)
 | 
				
			||||||
        } else if (value.startsWith("https://upload.wikimedia.org")) {
 | 
					        } else if (value.startsWith("https://upload.wikimedia.org")) {
 | 
				
			||||||
            const result: ProvidedImage = {
 | 
					            const result: ProvidedImage = {
 | 
				
			||||||
                key: undefined,
 | 
					                key: undefined,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,5 +42,9 @@ export default class FilterConfig {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return {question: question, osmTags: osmTags};
 | 
					            return {question: question, osmTags: osmTags};
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if(this.options.length > 1 && this.options[0].osmTags["and"]?.length !== 0){
 | 
				
			||||||
 | 
					            throw "Error in "+context+"."+this.id+": the first option of a multi-filter should always be the 'reset' option and not have any filters"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,6 @@ import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction";
 | 
				
			||||||
import {OsmObject, OsmWay} from "../../Logic/Osm/OsmObject";
 | 
					import {OsmObject, OsmWay} from "../../Logic/Osm/OsmObject";
 | 
				
			||||||
import PresetConfig from "../../Models/ThemeConfig/PresetConfig";
 | 
					import PresetConfig from "../../Models/ThemeConfig/PresetConfig";
 | 
				
			||||||
import FilteredLayer from "../../Models/FilteredLayer";
 | 
					import FilteredLayer from "../../Models/FilteredLayer";
 | 
				
			||||||
import {And} from "../../Logic/Tags/And";
 | 
					 | 
				
			||||||
import {BBox} from "../../Logic/BBox";
 | 
					import {BBox} from "../../Logic/BBox";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -230,7 +229,25 @@ export default class SimpleAddUI extends Toggle {
 | 
				
			||||||
        const disableFiltersOrConfirm = new Toggle(
 | 
					        const disableFiltersOrConfirm = new Toggle(
 | 
				
			||||||
            openLayerOrConfirm,
 | 
					            openLayerOrConfirm,
 | 
				
			||||||
            disableFilter,
 | 
					            disableFilter,
 | 
				
			||||||
            preset.layerToAddTo.appliedFilters.map(filters => filters === undefined || filters.length === 0)
 | 
					            preset.layerToAddTo.appliedFilters.map(filters => {
 | 
				
			||||||
 | 
					                if(filters === undefined || filters.length === 0){
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                for (const filter of filters) {
 | 
				
			||||||
 | 
					                    if(filter.selected === 0 && filter.filter.options.length === 1){
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if(filter.selected !== undefined){
 | 
				
			||||||
 | 
					                        const tags = filter.filter.options[filter.selected].osmTags
 | 
				
			||||||
 | 
					                        if(tags !== undefined && tags["and"]?.length !== 0){
 | 
				
			||||||
 | 
					                            // This actually doesn't filter anything at all
 | 
				
			||||||
 | 
					                            return false;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return true
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,16 +66,10 @@ export default class SpecialVisualizations {
 | 
				
			||||||
                    name: "image key/prefix",
 | 
					                    name: "image key/prefix",
 | 
				
			||||||
                    defaultValue: "image",
 | 
					                    defaultValue: "image",
 | 
				
			||||||
                    doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... "
 | 
					                    doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... "
 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        name: "smart search",
 | 
					 | 
				
			||||||
                        defaultValue: "true",
 | 
					 | 
				
			||||||
                        doc: "Also include images given via 'Wikidata', 'wikimedia_commons' and 'mapillary"
 | 
					 | 
				
			||||||
                }],
 | 
					                }],
 | 
				
			||||||
                constr: (state: State, tags, args) => {
 | 
					                constr: (state: State, tags, args) => {
 | 
				
			||||||
                    const imagePrefix = args[0];
 | 
					                    const imagePrefix = args[0];
 | 
				
			||||||
                    const loadSpecial = args[1].toLowerCase() === "true";
 | 
					                    return new ImageCarousel(AllImageProviders.LoadImagesFor(tags, imagePrefix), tags);
 | 
				
			||||||
                    return new ImageCarousel(AllImageProviders.LoadImagesFor(tags, imagePrefix, loadSpecial), tags);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -465,9 +465,9 @@
 | 
				
			||||||
            "id": "inside",
 | 
					            "id": "inside",
 | 
				
			||||||
            "options": [
 | 
					            "options": [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    "question": "Binnen of buiten",
 | 
					                    "question": {
 | 
				
			||||||
                    "osmTags": {
 | 
					                        "nl": "Binnen of buiten",
 | 
				
			||||||
                        "and": []
 | 
					                        "en": "Indoor or outdoor"
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue