forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
827d9ae685
664 changed files with 33303 additions and 29790 deletions
125
src/Utils.ts
125
src/Utils.ts
|
@ -1,4 +1,6 @@
|
|||
import DOMPurify from "dompurify"
|
||||
import { Lists } from "./Utils/Lists"
|
||||
import { Strings } from "./Utils/Strings"
|
||||
|
||||
export class Utils {
|
||||
/**
|
||||
|
@ -55,6 +57,8 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
>()
|
||||
|
||||
public static readonly empty: ReadonlyArray<any>
|
||||
|
||||
public static readonly isIframe = !Utils.runningFromConsole && window !== window.top
|
||||
|
||||
public static initDomPurify() {
|
||||
|
@ -107,7 +111,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
return <T>parsed
|
||||
}
|
||||
|
||||
static EncodeXmlValue(str) {
|
||||
static encodeXmlValue(str) {
|
||||
if (typeof str !== "string") {
|
||||
str = "" + str
|
||||
}
|
||||
|
@ -120,26 +124,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
.replace(/'/g, "'")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a clean float, or undefined if parsing fails
|
||||
* @param str
|
||||
*/
|
||||
static asFloat(str): number {
|
||||
if (str) {
|
||||
const i = parseFloat(str)
|
||||
if (isNaN(i)) {
|
||||
return undefined
|
||||
}
|
||||
return i
|
||||
}
|
||||
return undefined
|
||||
public static upper(str: string) {
|
||||
return str.substring(0, 1).toUpperCase() + str.substring(1)
|
||||
}
|
||||
|
||||
public static Upper(str: string) {
|
||||
return str.substr(0, 1).toUpperCase() + str.substr(1)
|
||||
}
|
||||
|
||||
public static TwoDigits(i: number) {
|
||||
public static twoDigits(i: number) {
|
||||
if (i < 10) {
|
||||
return "0" + i
|
||||
}
|
||||
|
@ -149,16 +138,16 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
/**
|
||||
* Converts a number to a number with precisely 7 decimals
|
||||
*
|
||||
* Utils.Round7(12.123456789) // => 12.1234568
|
||||
* Utils.round7(12.123456789) // => 12.1234568
|
||||
*/
|
||||
public static Round7(i: number): number {
|
||||
public static round7(i: number): number {
|
||||
if (i == undefined) {
|
||||
return undefined
|
||||
}
|
||||
return Math.round(i * 10000000) / 10000000
|
||||
}
|
||||
|
||||
public static Times(f: (i: number) => string, count: number): string {
|
||||
public static times(f: (i: number) => string, count: number): string {
|
||||
let res = ""
|
||||
for (let i = 0; i < count; i++) {
|
||||
res += f(i)
|
||||
|
@ -166,7 +155,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
return res
|
||||
}
|
||||
|
||||
public static TimesT<T>(count: number, f: (i: number) => T): T[] {
|
||||
public static timesT<T>(count: number, f: (i: number) => T): T[] {
|
||||
const res: T[] = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
res.push(f(i))
|
||||
|
@ -174,16 +163,8 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow copy of the array. All elements that are not undefined/null will be in the new list
|
||||
* @param array
|
||||
* @constructor
|
||||
*/
|
||||
public static NoNull<T>(array: ReadonlyArray<T> | undefined): T[] | 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 <NonNullable<T>[]>(<unknown>array?.filter((o) => o !== undefined && o !== null))
|
||||
public static noNull<T>(array: ReadonlyArray<T>): NonNullable<T>[] {
|
||||
return Lists.noNull(array)
|
||||
}
|
||||
|
||||
public static Hist(array: ReadonlyArray<string>): Map<string, number> {
|
||||
|
@ -193,29 +174,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
return hist
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all empty strings from this list
|
||||
* If undefined or null is given, an empty list is returned
|
||||
*
|
||||
* Utils.NoEmpty(undefined) // => []
|
||||
* Utils.NoEmpty(["abc","","def", null]) // => ["abc","def", null]
|
||||
*
|
||||
*/
|
||||
public static NoEmpty(array: string[]): string[] {
|
||||
const ls: string[] = []
|
||||
if (!array) {
|
||||
return ls
|
||||
}
|
||||
for (const t of array) {
|
||||
if (t === "") {
|
||||
continue
|
||||
}
|
||||
ls.push(t)
|
||||
}
|
||||
return ls
|
||||
}
|
||||
|
||||
public static EllipsesAfter(str: string, l: number = 100) {
|
||||
if (str === undefined || str === null) {
|
||||
return undefined
|
||||
|
@ -295,28 +253,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with all elements from 'arr' in such a way that every element will be kept only once
|
||||
* Elements are returned in the same order as they appear in the lists.
|
||||
* Null/Undefined is returned as is. If an emtpy array is given, a new empty array will be returned
|
||||
*/
|
||||
public static Dedup(arr: NonNullable<string[]>): NonNullable<string[]>
|
||||
public static Dedup(arr: undefined): undefined
|
||||
public static Dedup(arr: string[] | undefined): string[] | undefined
|
||||
public static Dedup(arr: string[]): string[] {
|
||||
if (arr === undefined || arr === null) {
|
||||
return arr
|
||||
}
|
||||
const newArr = []
|
||||
for (const string of arr) {
|
||||
if (newArr.indexOf(string) < 0) {
|
||||
newArr.push(string)
|
||||
}
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
public static DedupT<T>(arr: T[]): T[] {
|
||||
if (!arr) {
|
||||
return arr
|
||||
|
@ -357,7 +293,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
uniq.push(img)
|
||||
}
|
||||
} else {
|
||||
const ksNoNull = Utils.NoNull(ks)
|
||||
const ksNoNull = Lists.noNull(ks)
|
||||
const hasBeenSeen = ksNoNull.some((k) => seen.has(k))
|
||||
if (!hasBeenSeen) {
|
||||
uniq.push(img)
|
||||
|
@ -1211,7 +1147,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
if (days > 0) {
|
||||
return days + "days" + " " + hours + "h"
|
||||
}
|
||||
return hours + ":" + Utils.TwoDigits(minutes) + ":" + Utils.TwoDigits(seconds)
|
||||
return hours + ":" + Utils.twoDigits(minutes) + ":" + Utils.twoDigits(seconds)
|
||||
}
|
||||
|
||||
public static toHumanByteSize(bytes: number): string {
|
||||
|
@ -1245,9 +1181,9 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
const date =
|
||||
lastWeek.getFullYear() +
|
||||
"-" +
|
||||
Utils.TwoDigits(lastWeek.getMonth() + 1) +
|
||||
Utils.twoDigits(lastWeek.getMonth() + 1) +
|
||||
"-" +
|
||||
Utils.TwoDigits(lastWeek.getDate())
|
||||
Utils.twoDigits(lastWeek.getDate())
|
||||
let osmcha_link = `"date__gte":[{"label":"${date}","value":"${date}"}],"editor":[{"label":"mapcomplete","value":"mapcomplete"}]`
|
||||
if (theme !== undefined) {
|
||||
osmcha_link =
|
||||
|
@ -1831,16 +1767,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
return 50 * Math.round(number / 50)
|
||||
}
|
||||
|
||||
public static NoNullInplace<T>(items: T[]): T[] {
|
||||
for (let i = items.length - 1; i >= 0; i--) {
|
||||
if (items[i] === null || items[i] === undefined || items[i] === "") {
|
||||
items.splice(i, 1)
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes or rewrites some characters in links, as some blink/chromium based browsers are picky about them
|
||||
*
|
||||
|
@ -1858,8 +1784,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
return href
|
||||
}
|
||||
|
||||
private static emojiRegex = /[\p{Extended_Pictographic}🛰️]/u
|
||||
|
||||
/**
|
||||
* Returns 'true' if the given string contains at least one and only emoji characters
|
||||
*
|
||||
|
@ -1868,19 +1792,9 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
* Utils.isEmoji("🍕") // => true
|
||||
*/
|
||||
public static isEmoji(string: string) {
|
||||
return Utils.emojiRegex.test(string) || Utils.isEmojiFlag(string)
|
||||
return Strings.isEmoji(string)
|
||||
}
|
||||
|
||||
/**
|
||||
* Utils.isEmojiFlag("🇧🇪") // => true
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
public static sum(list: number[]): number {
|
||||
let total = 0
|
||||
|
@ -1910,4 +1824,5 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
}
|
||||
return <T>copy
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue