forked from MapComplete/MapComplete
UX: fix #2416, small code cleanup
This commit is contained in:
parent
9392da0dbb
commit
7b466a1d53
8 changed files with 57 additions and 66 deletions
|
@ -85,9 +85,9 @@ export default class AllImageProviders {
|
|||
let count = 0
|
||||
|
||||
const sources = [
|
||||
Panoramax.singleton,
|
||||
Imgur.singleton,
|
||||
Mapillary.singleton,
|
||||
Panoramax.singleton,
|
||||
AllImageProviders.genericImageProvider,
|
||||
]
|
||||
const allPrefixes = Utils.Dedup(
|
||||
|
@ -138,8 +138,8 @@ export default class AllImageProviders {
|
|||
allSources.push(singleSource)
|
||||
}
|
||||
const source = Stores.fromStoresArray(allSources).map((result) => {
|
||||
const all = [].concat(...result)
|
||||
return Utils.DedupOnId(all, (i) => i?.id ?? i?.url)
|
||||
const all = Utils.concat(result)
|
||||
return Utils.DedupOnId(all, (i) => [i?.id, i?.url, i?.alt_id])
|
||||
})
|
||||
this._cachedImageStores[cachekey] = source
|
||||
return source
|
||||
|
|
|
@ -10,6 +10,10 @@ export interface ProvidedImage {
|
|||
key: string
|
||||
provider: ImageProvider
|
||||
id: string
|
||||
/**
|
||||
* An alternative ID, used to deduplicate some images
|
||||
*/
|
||||
alt_id?: string,
|
||||
date?: Date
|
||||
status?: string | "ready"
|
||||
/**
|
||||
|
|
|
@ -47,10 +47,11 @@ export default class ImageUploadQueue {
|
|||
applyRemapping(oldId: string, newId: string) {
|
||||
let hasChange = false
|
||||
for (const img of this._imagesInQueue.data) {
|
||||
if (img.featureId === oldId) {
|
||||
img.featureId = newId
|
||||
hasChange = true
|
||||
if (img.featureId !== oldId) {
|
||||
continue
|
||||
}
|
||||
img.featureId = newId
|
||||
hasChange = true
|
||||
}
|
||||
if (hasChange) {
|
||||
this._imagesInQueue.ping()
|
||||
|
|
|
@ -22,7 +22,15 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
3000
|
||||
)
|
||||
|
||||
public defaultKeyPrefixes: string[] = ["panoramax"]
|
||||
/**
|
||||
*
|
||||
* const url = "https://panoramax.mapcomplete.org/api/pictures/e931ce57-4591-4dd5-aa4c-595e89c37e84/hd.jpg"
|
||||
* const match = url.match(PanoramaxImageProvider.isDirectLink)
|
||||
* match[1] // => "e931ce57-4591-4dd5-aa4c-595e89c37e84"
|
||||
*/
|
||||
public static readonly isDirectLink = /https:\/\/panoramax.mapcomplete.org\/api\/pictures\/([0-9a-f-]+)\/(hd)|(sd)|(thumb).jpg/
|
||||
|
||||
public defaultKeyPrefixes: string[] = ["panoramax", "image"]
|
||||
public readonly name: string = "panoramax"
|
||||
|
||||
private static knownMeta: Record<
|
||||
|
@ -154,10 +162,18 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
}
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<ProvidedImage[]> {
|
||||
const match = value.match(PanoramaxImageProvider.isDirectLink)
|
||||
let alt_id = undefined
|
||||
if (match) {
|
||||
alt_id = value
|
||||
value = match[1] // The ID
|
||||
}
|
||||
if (!Panoramax.isId(value)) {
|
||||
return undefined
|
||||
}
|
||||
return [await this.getInfo(value)]
|
||||
const providedImage = await this.getInfo(value)
|
||||
providedImage.alt_id = alt_id
|
||||
return [providedImage]
|
||||
}
|
||||
|
||||
public async getInfo(hash: string): Promise<ProvidedImage> {
|
||||
|
|
|
@ -359,6 +359,9 @@ export class ChangesetHandler {
|
|||
}
|
||||
for (const mapping of mappings) {
|
||||
const [oldId, newId] = mapping
|
||||
if (oldId === newId) {
|
||||
continue
|
||||
}
|
||||
this.allElements?.addAlias(oldId, newId)
|
||||
if (newId !== undefined) {
|
||||
this._remappings.set(oldId, newId)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Utils } from "../../Utils"
|
||||
import Locale from "../../UI/i18n/Locale"
|
||||
import Constants from "../../Models/Constants"
|
||||
import FilterConfig, { FilterConfigOption } from "../../Models/ThemeConfig/FilterConfig"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import LayerState from "../State/LayerState"
|
||||
|
@ -89,41 +88,6 @@ export default class FilterSearch {
|
|||
}
|
||||
return possibleFilters
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random list of filters
|
||||
*/
|
||||
getSuggestions(): FilterSearchResult[] {
|
||||
const result: FilterSearchResult[] = []
|
||||
for (const [id, filteredLayer] of this._state.layerState.filteredLayers) {
|
||||
if (!Array.isArray(filteredLayer.layerDef.filters)) {
|
||||
continue
|
||||
}
|
||||
if (Constants.isPriviliged(id)) {
|
||||
continue
|
||||
}
|
||||
for (const filter of filteredLayer.layerDef.filters) {
|
||||
const singleFilterResults: FilterSearchResult[] = []
|
||||
for (let i = 0; i < Math.min(filter.options.length, 5); i++) {
|
||||
const option = filter.options[i]
|
||||
if (option.osmTags === undefined) {
|
||||
continue
|
||||
}
|
||||
singleFilterResults.push({
|
||||
option,
|
||||
filter,
|
||||
index: i,
|
||||
layer: filteredLayer.layerDef,
|
||||
})
|
||||
}
|
||||
Utils.shuffle(singleFilterResults)
|
||||
result.push(...singleFilterResults.slice(0, 3))
|
||||
}
|
||||
}
|
||||
Utils.shuffle(result)
|
||||
return result.slice(0, 6)
|
||||
}
|
||||
|
||||
/**
|
||||
* Partitions the list of filters in such a way that identically appearing filters will be in the same sublist.
|
||||
*
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
<div
|
||||
class="my-2 flex flex-col border-b border-gray-500"
|
||||
class:border-interactive={comment.highlighted}
|
||||
class:px-2={comment.highlighted}
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<!-- Action icon, e.g. 'created', 'commented', 'closed' -->
|
||||
|
@ -101,7 +102,7 @@
|
|||
{:else}
|
||||
<a href={comment.user_url} target="_blank">{comment.user}</a>
|
||||
{/if}
|
||||
{comment.date}
|
||||
{comment.date ?? new Date().toISOString()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
44
src/Utils.ts
44
src/Utils.ts
|
@ -175,10 +175,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
|
||||
public static NoNull<T>(array: ReadonlyArray<T> | undefined): T[] | undefined
|
||||
public static NoNull<T>(array: undefined): undefined
|
||||
public static NoNull(array: undefined): undefined
|
||||
public static NoNull<T>(array: ReadonlyArray<T>): T[]
|
||||
public static NoNull<T>(array: ReadonlyArray<T>): NonNullable<T>[] {
|
||||
return <any>array?.filter((o) => o !== undefined && o !== null)
|
||||
return <NonNullable<T>[]><unknown>array?.filter((o) => o !== undefined && o !== null)
|
||||
}
|
||||
|
||||
public static Hist(array: ReadonlyArray<string>): Map<string, number> {
|
||||
|
@ -332,7 +332,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
* @param toKey
|
||||
* @constructor
|
||||
*/
|
||||
public static DedupOnId<T = { id: string }>(arr: T[], toKey?: (t: T) => string): T[] {
|
||||
public static DedupOnId<T = { id: string }>(arr: T[], toKey?: (t: T) => string | string[]): T[] {
|
||||
const uniq: T[] = []
|
||||
const seen = new Set<string>()
|
||||
if (toKey === undefined) {
|
||||
|
@ -342,10 +342,21 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
if (!img) {
|
||||
continue
|
||||
}
|
||||
const k = toKey(img)
|
||||
if (!seen.has(k)) {
|
||||
seen.add(k)
|
||||
uniq.push(img)
|
||||
const ks = toKey(img)
|
||||
if (typeof ks === "string") {
|
||||
if (!seen.has(ks)) {
|
||||
seen.add(ks)
|
||||
uniq.push(img)
|
||||
}
|
||||
} else {
|
||||
const ksNoNull = Utils.NoNull(ks)
|
||||
const hasBeenSeen = ksNoNull.some(k => seen.has(k))
|
||||
if (!hasBeenSeen) {
|
||||
uniq.push(img)
|
||||
}
|
||||
for (const k of ksNoNull) {
|
||||
seen.add(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return uniq
|
||||
|
@ -1657,7 +1668,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
return obj
|
||||
}
|
||||
const newObj = {}
|
||||
for (let objKey in obj) {
|
||||
for (const objKey in obj) {
|
||||
let cleanKey = objKey
|
||||
if (objKey.startsWith("+") || objKey.startsWith("=")) {
|
||||
cleanKey = objKey.substring(1)
|
||||
|
@ -1794,19 +1805,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
href = href.replaceAll(/ /g, "%20")
|
||||
return href
|
||||
}
|
||||
|
||||
/** Randomize array in-place using Durstenfeld shuffle algorithm
|
||||
* Source: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
|
||||
* */
|
||||
static shuffle(array: any[]) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1))
|
||||
const temp = array[i]
|
||||
array[i] = array[j]
|
||||
array[j] = temp
|
||||
}
|
||||
}
|
||||
|
||||
private static emojiRegex = /[\p{Extended_Pictographic}🛰️]/u
|
||||
|
||||
/**
|
||||
|
@ -1826,4 +1824,8 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
public static isEmojiFlag(string: string) {
|
||||
return /[🇦-🇿]{2}/u.test(string) // flags, see https://stackoverflow.com/questions/53360006/detect-with-regex-if-emoji-is-country-flag
|
||||
}
|
||||
|
||||
public static concat<T>(param: T[][]): T[] {
|
||||
return [].concat(...param)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue