forked from MapComplete/MapComplete
Merge branch 'develop' into feature/velopark
This commit is contained in:
commit
59e76b9c6f
30 changed files with 963 additions and 654 deletions
|
|
@ -1,26 +0,0 @@
|
|||
import BaseUIElement from "../BaseUIElement"
|
||||
import { VariableUiElement } from "./VariableUIElement"
|
||||
import { Stores } from "../../Logic/UIEventSource"
|
||||
import Loading from "./Loading"
|
||||
|
||||
export default class AsyncLazy extends BaseUIElement {
|
||||
private readonly _f: () => Promise<BaseUIElement>
|
||||
|
||||
constructor(f: () => Promise<BaseUIElement>) {
|
||||
super()
|
||||
this._f = f
|
||||
}
|
||||
|
||||
protected InnerConstructElement(): HTMLElement {
|
||||
// The caching of the BaseUIElement will guarantee that _f will only be called once
|
||||
|
||||
return new VariableUiElement(
|
||||
Stores.FromPromise(this._f()).map((el) => {
|
||||
if (el === undefined) {
|
||||
return new Loading()
|
||||
}
|
||||
return el
|
||||
})
|
||||
).ConstructElement()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
import BaseUIElement from "../BaseUIElement"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { VariableUiElement } from "./VariableUIElement"
|
||||
import Combine from "./Combine"
|
||||
import Locale from "../i18n/Locale"
|
||||
import { Utils } from "../../Utils"
|
||||
|
||||
export default class FilteredCombine extends VariableUiElement {
|
||||
/**
|
||||
* Only shows item matching the search
|
||||
* If predicate of an item is undefined, it will be filtered out as soon as a non-null or non-empty search term is given
|
||||
* @param entries
|
||||
* @param searchedValue
|
||||
* @param options
|
||||
*/
|
||||
constructor(
|
||||
entries: {
|
||||
element: BaseUIElement | string
|
||||
predicate?: (s: string) => boolean
|
||||
}[],
|
||||
searchedValue: UIEventSource<string>,
|
||||
options?: {
|
||||
onEmpty?: BaseUIElement | string
|
||||
innerClasses: string
|
||||
}
|
||||
) {
|
||||
entries = Utils.NoNull(entries)
|
||||
super(
|
||||
searchedValue.map(
|
||||
(searchTerm) => {
|
||||
if (searchTerm === undefined || searchTerm === "") {
|
||||
return new Combine(entries.map((e) => e.element)).SetClass(
|
||||
options?.innerClasses ?? ""
|
||||
)
|
||||
}
|
||||
const kept = entries.filter(
|
||||
(entry) => entry?.predicate !== undefined && entry.predicate(searchTerm)
|
||||
)
|
||||
if (kept.length === 0) {
|
||||
return options?.onEmpty
|
||||
}
|
||||
return new Combine(kept.map((entry) => entry.element)).SetClass(
|
||||
options?.innerClasses ?? ""
|
||||
)
|
||||
},
|
||||
[Locale.language]
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,14 @@
|
|||
import ToSvelte from "./ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import Loading from "../../assets/svg/Loading.svelte"
|
||||
|
||||
export let cls: string = undefined
|
||||
</script>
|
||||
|
||||
<div class={twMerge("flex p-1 pl-2", cls)}>
|
||||
<div class="min-w-6 h-6 w-6 shrink-0 animate-spin self-center">
|
||||
<ToSvelte construct={Svg.loading_svg()} />
|
||||
<Loading/>
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import BaseUIElement from "../BaseUIElement"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { UIElement } from "../UIElement"
|
||||
import { VariableUiElement } from "./VariableUIElement"
|
||||
import Lazy from "./Lazy"
|
||||
import Loading from "./Loading"
|
||||
import SvelteUIElement from "./SvelteUIElement"
|
||||
import SubtleLink from "./SubtleLink.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
export let layer: LayerConfig
|
||||
|
||||
export let linkable = true
|
||||
let isLinked = Object.values(tags.data).some((v) => image.pictureUrl === v)
|
||||
|
||||
let targetValue = Object.values(image.osmTags)[0]
|
||||
let isLinked = new UIEventSource(Object.values(tags.data).some((v) => targetValue === v))
|
||||
const t = Translations.t.image.nearby
|
||||
const providedImage: ProvidedImage = {
|
||||
url: image.thumbUrl ?? image.pictureUrl,
|
||||
|
|
@ -33,10 +33,11 @@
|
|||
id: Object.values(image.osmTags)[0],
|
||||
}
|
||||
|
||||
$: {
|
||||
function applyLink(isLinked :boolean) {
|
||||
console.log("Applying linked image", isLinked, targetValue)
|
||||
const currentTags = tags.data
|
||||
const key = Object.keys(image.osmTags)[0]
|
||||
const url = image.osmTags[key]
|
||||
const url = targetValue
|
||||
if (isLinked) {
|
||||
const action = new LinkImageAction(currentTags.id, key, url, tags, {
|
||||
theme: tags.data._orig_theme ?? state.layout.id,
|
||||
|
|
@ -56,6 +57,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
isLinked.addCallback(isLinked => applyLink(isLinked))
|
||||
</script>
|
||||
|
||||
<div class="flex w-fit shrink-0 flex-col">
|
||||
|
|
@ -68,7 +70,7 @@
|
|||
</div>
|
||||
{#if linkable}
|
||||
<label>
|
||||
<input bind:checked={isLinked} type="checkbox" />
|
||||
<input bind:checked={$isLinked} type="checkbox" />
|
||||
<SpecialTranslation t={t.link} {tags} {state} {layer} {feature} />
|
||||
</label>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ export default class PhoneValidator extends Validator {
|
|||
if (country !== undefined) {
|
||||
countryCode = country()?.toUpperCase()
|
||||
}
|
||||
if (this.isShortCode(str, countryCode)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return parsePhoneNumberFromString(str, countryCode)?.isValid() ?? false
|
||||
}
|
||||
|
||||
|
|
@ -46,9 +50,28 @@ export default class PhoneValidator extends Validator {
|
|||
if (country) {
|
||||
countryCode = country()
|
||||
}
|
||||
if (this.isShortCode(str, countryCode?.toUpperCase())) {
|
||||
return str
|
||||
}
|
||||
return parsePhoneNumberFromString(
|
||||
str,
|
||||
countryCode?.toUpperCase() as any
|
||||
)?.formatInternational()
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the given string is a special 'short code' valid in the given country
|
||||
* see https://nl.wikipedia.org/wiki/Short_code
|
||||
* @param str a possible phone number
|
||||
* @param country the upper case, two-letter code for a country
|
||||
* @private
|
||||
*/
|
||||
private isShortCode(str: string, country: string) {
|
||||
if (country == "BE" && str.length === 4 && str.match(/[0-9]{4}/)) {
|
||||
return true
|
||||
}
|
||||
if (country == "NL" && str.length === 4 && str.match(/14[0-9]{3}/)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { Feature, Point } from "geojson"
|
|||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import Confirm from "../../assets/svg/Confirm.svelte"
|
||||
import Relocation from "../../assets/svg/Relocation.svelte"
|
||||
import Location from "../../assets/svg/Location.svelte"
|
||||
|
||||
export interface MoveReason {
|
||||
text: Translation | string
|
||||
|
|
@ -62,7 +63,7 @@ export class MoveWizardState {
|
|||
reasons.push({
|
||||
text: t.reasons.reasonInaccurate,
|
||||
invitingText: t.inviteToMove.reasonInaccurate,
|
||||
icon: new SvelteUIElement(Confirm),
|
||||
icon: new SvelteUIElement(Location),
|
||||
changesetCommentValue: "improve_accuracy",
|
||||
lockBounds: true,
|
||||
includeSearch: false,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Combine from "../../Base/Combine"
|
||||
import BaseUIElement from "../../BaseUIElement"
|
||||
import Svg from "../../../Svg"
|
||||
import Link from "../../Base/Link"
|
||||
import { FixedUiElement } from "../../Base/FixedUiElement"
|
||||
import Translations from "../../i18n/Translations"
|
||||
|
|
@ -11,6 +10,10 @@ import { Stores, UIEventSource } from "../../../Logic/UIEventSource"
|
|||
import { OsmConnection } from "../../../Logic/Osm/OsmConnection"
|
||||
import { VariableUiElement } from "../../Base/VariableUIElement"
|
||||
import { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
import SvelteUIElement from "../../Base/SvelteUIElement"
|
||||
import Note from "../../../assets/svg/Note.svelte"
|
||||
import Resolved from "../../../assets/svg/Resolved.svelte"
|
||||
import Speech_bubble from "../../../assets/svg/Speech_bubble.svelte"
|
||||
|
||||
export default class NoteCommentElement extends Combine {
|
||||
constructor(
|
||||
|
|
@ -32,11 +35,11 @@ export default class NoteCommentElement extends Combine {
|
|||
|
||||
let actionIcon: BaseUIElement
|
||||
if (comment.action === "opened" || comment.action === "reopened") {
|
||||
actionIcon = Svg.note_svg()
|
||||
actionIcon = new SvelteUIElement(Note)
|
||||
} else if (comment.action === "closed") {
|
||||
actionIcon = Svg.resolved_svg()
|
||||
actionIcon = new SvelteUIElement(Resolved)
|
||||
} else {
|
||||
actionIcon = Svg.speech_bubble_svg()
|
||||
actionIcon = new SvelteUIElement(Speech_bubble)
|
||||
}
|
||||
|
||||
let user: BaseUIElement
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
import type { Feature } from "geojson"
|
||||
import { Store, UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
|
|
@ -24,7 +23,7 @@
|
|||
throw "Config is undefined in tagRenderingAnswer"
|
||||
}
|
||||
let trs: Store<{ then: Translation; icon?: string; iconClass?: string }[]> = tags.mapD((tags) =>
|
||||
Utils.NoNull(config?.GetRenderValues(tags))
|
||||
Utils.NoNull(config?.GetRenderValues(tags)),
|
||||
)
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,9 +29,6 @@ export default class Zoomcontrol {
|
|||
this._allowZooming.addCallback((allowed) => {
|
||||
this.apply(allowed ? Zoomcontrol.initialValue : Zoomcontrol.noZoom)
|
||||
})
|
||||
Stores.Chronic(1000).addCallback((_) =>
|
||||
console.log(this.viewportElement.getAttribute("content"))
|
||||
)
|
||||
}
|
||||
|
||||
private _resetZoom() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue