forked from MapComplete/MapComplete
Performance: trim svg.ts, use Svelte-SVG-componenets where possible (WIP)
This commit is contained in:
parent
ac5c60c3f0
commit
c13d80f062
37 changed files with 367 additions and 378 deletions
|
@ -160,7 +160,7 @@
|
|||
"craft=key_cutter"
|
||||
]
|
||||
},
|
||||
"then": "./assets/layers/id_presets/fas-key.svg"
|
||||
"then": "circle:white;./assets/layers/id_presets/fas-key.svg"
|
||||
}
|
||||
],
|
||||
"label": {
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="374px" height="259px" viewBox="0 0 374 259" version="1.1">
|
||||
<g id="surface1"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 189 B |
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="375px" height="375px" viewBox="0 0 375 375" version="1.1">
|
||||
<g id="surface1"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 189 B |
|
@ -1,11 +1,47 @@
|
|||
import * as fs from "fs"
|
||||
|
||||
function genImages(dryrun = false) {
|
||||
console.log("Generating images")
|
||||
// These images are not referenced via 'Svg.ts' anymore and can be ignored
|
||||
const blacklist: string[] = [
|
||||
"SocialImageForeground",
|
||||
"wikipedia",
|
||||
"Upload",
|
||||
"pin",
|
||||
"mapillary_black",
|
||||
"plantnet_logo",
|
||||
"mastodon",
|
||||
"move-arrows",
|
||||
"mapcomplete_logo",
|
||||
"logo",
|
||||
"logout",
|
||||
"hand",
|
||||
"help",
|
||||
"home",
|
||||
"reload",
|
||||
"min",
|
||||
"plus",
|
||||
"not_found",
|
||||
"osm_logo_us",
|
||||
"party",
|
||||
"filter",
|
||||
"filter_disable",
|
||||
"floppy",
|
||||
"eye",
|
||||
"gear",
|
||||
"gender_bi",
|
||||
"compass",
|
||||
"blocked",
|
||||
"brick_wall",
|
||||
"brick_wall_raw",
|
||||
"brick_wall_round",
|
||||
"bug",
|
||||
"back",
|
||||
].map((s) => s.toLowerCase())
|
||||
const dir = fs.readdirSync("./assets/svg")
|
||||
|
||||
let module =
|
||||
'import Img from "./UI/Base/Img";\nimport {FixedUiElement} from "./UI/Base/FixedUiElement";\n\n/* @deprecated */\nexport default class Svg {\n\n\n'
|
||||
const allNames: string[] = []
|
||||
for (const path of dir) {
|
||||
if (path.endsWith("license_info.json")) {
|
||||
continue
|
||||
|
@ -21,6 +57,7 @@ function genImages(dryrun = false) {
|
|||
let svg: string = fs
|
||||
.readFileSync("./assets/svg/" + path, "utf-8")
|
||||
.replace(/<\?xml.*?>/, "")
|
||||
.replace(/<!DOCTYPE [^>]*>/, "")
|
||||
.replace(/fill: ?none;/g, "fill: none !important;") // This is such a brittle hack...
|
||||
.replace(/\n/g, " ")
|
||||
.replace(/\r/g, "")
|
||||
|
@ -37,18 +74,6 @@ function genImages(dryrun = false) {
|
|||
}
|
||||
const name = path.substring(0, path.length - 4).replace(/[ -]/g, "_")
|
||||
|
||||
if (dryrun) {
|
||||
svg = "<omitting svg - dryrun>"
|
||||
}
|
||||
|
||||
let rawName = name
|
||||
|
||||
module += ` public static ${name} = "${svg}"\n`
|
||||
module += ` public static ${name}_svg() { return new Img(Svg.${rawName}, true);}\n`
|
||||
if (!dryrun) {
|
||||
allNames.push(`"${path}": Svg.${name}`)
|
||||
}
|
||||
|
||||
const nameUC = name.toUpperCase().at(0) + name.substring(1)
|
||||
const svelteCode =
|
||||
'<script>\nexport let color = "#000000"\n</script>\n' +
|
||||
|
@ -60,8 +85,23 @@ function genImages(dryrun = false) {
|
|||
.replace(/\\"/g, '"')
|
||||
.replace(/(rgb\(0%,0%,0%\)|#000000|#000)/g, "{color}")
|
||||
fs.writeFileSync("./src/assets/svg/" + nameUC + ".svelte", svelteCode, "utf8")
|
||||
|
||||
if (blacklist.some((item) => path.toLowerCase().endsWith(item + ".svg"))) {
|
||||
continue
|
||||
}
|
||||
if (dryrun) {
|
||||
svg = "<omitting svg - dryrun>"
|
||||
}
|
||||
|
||||
let rawName = name
|
||||
|
||||
module += ` public static ${name} = "${svg}"\n`
|
||||
if (!dryrun) {
|
||||
module += ` public static ${name}_svg() { return new Img(Svg.${rawName}, true);}\n`
|
||||
} else {
|
||||
module += ` public static ${name}_svg() { return new Img("", true);}\n`
|
||||
}
|
||||
}
|
||||
module += `public static All = {${allNames.join(",")}};`
|
||||
module += "}\n"
|
||||
fs.writeFileSync("src/Svg.ts", module)
|
||||
console.log("Done")
|
||||
|
|
|
@ -92,7 +92,7 @@ export class DoesImageExist extends DesugaringStep<string> {
|
|||
return image
|
||||
}
|
||||
if (image.match(/[a-z]*/)) {
|
||||
if (Svg.All[image + ".svg"] !== undefined) {
|
||||
if (Constants.defaultPinIcons.indexOf(image) >= 0) {
|
||||
// This is a builtin img, e.g. 'checkmark' or 'crosshair'
|
||||
return image
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import { VariableUiElement } from "../../UI/Base/VariableUIElement"
|
|||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||
import SvelteUIElement from "../../UI/Base/SvelteUIElement"
|
||||
import DynamicMarker from "../../UI/Map/DynamicMarker.svelte"
|
||||
import { html } from "svelte/types/compiler/utils/namespaces"
|
||||
|
||||
export class IconConfig extends WithContextLoader {
|
||||
public static readonly defaultIcon = new IconConfig({ icon: "pin", color: "#ff9939" })
|
||||
|
@ -133,71 +134,23 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
context + ".rotationAlignment"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a single HTML spec (either a single image path OR "image_path_to_known_svg:fill-colour", returns a fixedUIElement containing that
|
||||
* The element will fill 100% and be positioned absolutely with top:0 and left: 0
|
||||
*/
|
||||
private static FromHtmlSpec(htmlSpec: string, style: string, isBadge = false): BaseUIElement {
|
||||
if (htmlSpec === undefined) {
|
||||
return undefined
|
||||
private static FromHtmlMulti(multiSpec: string, tags: Store<Record<string, string>>) {
|
||||
const icons: IconConfig[] = []
|
||||
for (const subspec of multiSpec.split(";")) {
|
||||
const [icon, color] = subspec.split(":")
|
||||
icons.push(new IconConfig({ icon, color }))
|
||||
}
|
||||
const match = htmlSpec.match(/([a-zA-Z0-9_]*):([^;]*)/)
|
||||
if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) {
|
||||
const svg = Svg.All[match[1] + ".svg"] as string
|
||||
const targetColor = match[2]
|
||||
const img = new Img(
|
||||
svg.replace(/(rgb\(0%,0%,0%\)|#000000|#000)/g, targetColor),
|
||||
true
|
||||
).SetStyle(style)
|
||||
if (isBadge) {
|
||||
img.SetClass("badge")
|
||||
}
|
||||
return img
|
||||
} else if (Svg.All[htmlSpec + ".svg"] !== undefined) {
|
||||
const svg = Svg.All[htmlSpec + ".svg"] as string
|
||||
const img = new Img(svg, true).SetStyle(style)
|
||||
if (isBadge) {
|
||||
img.SetClass("badge")
|
||||
}
|
||||
return img
|
||||
} else {
|
||||
return new FixedUiElement(`<img src="${htmlSpec}" style="${style}" />`)
|
||||
}
|
||||
}
|
||||
|
||||
private static FromHtmlMulti(
|
||||
multiSpec: string,
|
||||
rotation: string,
|
||||
isBadge: boolean,
|
||||
defaultElement: BaseUIElement = undefined,
|
||||
options?: {
|
||||
noFullWidth?: boolean
|
||||
}
|
||||
) {
|
||||
if (multiSpec === undefined) {
|
||||
return defaultElement
|
||||
}
|
||||
const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`
|
||||
|
||||
const htmlDefs = multiSpec.trim()?.split(";") ?? []
|
||||
const elements = Utils.NoEmpty(htmlDefs).map((def) =>
|
||||
PointRenderingConfig.FromHtmlSpec(def, style, isBadge)
|
||||
return new SvelteUIElement(DynamicMarker, { marker: icons, tags }).SetClass(
|
||||
"w-full h-full block absolute top-0 left-0"
|
||||
)
|
||||
if (elements.length === 0) {
|
||||
return defaultElement
|
||||
} else {
|
||||
const combine = new Combine(elements).SetClass("relative block")
|
||||
if (options?.noFullWidth) {
|
||||
return combine
|
||||
}
|
||||
combine.SetClass("w-full h-full")
|
||||
return combine
|
||||
}
|
||||
}
|
||||
|
||||
public GetBaseIcon(tags?: Record<string, string>): BaseUIElement {
|
||||
return new SvelteUIElement(DynamicMarker, { config: this, tags: new ImmutableStore(tags) })
|
||||
return new SvelteUIElement(DynamicMarker, {
|
||||
marker: this.marker,
|
||||
rotation: this.rotation,
|
||||
tags: new ImmutableStore(tags),
|
||||
})
|
||||
}
|
||||
|
||||
public RenderIcon(
|
||||
|
@ -249,9 +202,11 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
anchorH = -iconH / 2
|
||||
}
|
||||
|
||||
const icon = new SvelteUIElement(DynamicMarker, { config: this, tags }).SetClass(
|
||||
"w-full h-full"
|
||||
)
|
||||
const icon = new SvelteUIElement(DynamicMarker, {
|
||||
marker: this.marker,
|
||||
rotation: this.rotation,
|
||||
tags,
|
||||
}).SetClass("w-full h-full")
|
||||
let badges = undefined
|
||||
if (options?.includeBadges ?? true) {
|
||||
badges = this.GetBadges(tags, options?.metatags)
|
||||
|
@ -264,7 +219,6 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
tags.map((tags) => this.iconSize.GetRenderValue(tags).Subs(tags).txt ?? "[40,40]").map(
|
||||
(size) => {
|
||||
const [iconW, iconH] = size.split(",").map((x) => num(x))
|
||||
console.log("Setting size to", iconW, iconH)
|
||||
iconAndBadges.SetStyle(`width: ${iconW}px; height: ${iconH}px`)
|
||||
}
|
||||
)
|
||||
|
@ -307,9 +261,9 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
}
|
||||
return new VariableUiElement(
|
||||
tags.map(
|
||||
(tags) => {
|
||||
(tagsData) => {
|
||||
const badgeElements = this.iconBadges.map((badge) => {
|
||||
if (!badge.if.matchesProperties(tags)) {
|
||||
if (!badge.if.matchesProperties(tagsData)) {
|
||||
// Doesn't match...
|
||||
return undefined
|
||||
}
|
||||
|
@ -324,19 +278,23 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
}
|
||||
|
||||
const htmlDefs = Utils.SubstituteKeys(
|
||||
badge.then.GetRenderValue(tags)?.txt,
|
||||
tags
|
||||
badge.then.GetRenderValue(tagsData)?.txt,
|
||||
tagsData
|
||||
)
|
||||
if (htmlDefs.startsWith("<") && htmlDefs.endsWith(">")) {
|
||||
// This is probably an HTML-element
|
||||
return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tags))
|
||||
return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tagsData))
|
||||
.SetStyle("width: 1.5rem")
|
||||
.SetClass("block")
|
||||
}
|
||||
|
||||
if (!htmlDefs) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const badgeElement = PointRenderingConfig.FromHtmlMulti(
|
||||
htmlDefs,
|
||||
"0",
|
||||
true
|
||||
tags
|
||||
)?.SetClass("block relative")
|
||||
if (badgeElement === undefined) {
|
||||
return undefined
|
||||
|
|
|
@ -19,6 +19,7 @@ import { Paragraph } from "../../UI/Base/Paragraph"
|
|||
import Svg from "../../Svg"
|
||||
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
|
||||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||
import Constants from "../Constants"
|
||||
|
||||
export interface Icon {}
|
||||
|
||||
|
@ -362,7 +363,7 @@ export default class TagRenderingConfig {
|
|||
if (stripped.endsWith(".svg")) {
|
||||
stripped = stripped.substring(0, stripped.length - 4)
|
||||
}
|
||||
if (Svg.All[stripped + ".svg"] !== undefined) {
|
||||
if (Constants.defaultPinIcons.indexOf(stripped) >= 0) {
|
||||
icon = "./assets/svg/" + mapping.icon
|
||||
if (!icon.endsWith(".svg")) {
|
||||
icon += ".svg"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
import Hand from "../../assets/svg/Hand.svelte";
|
||||
|
||||
let mainElem: HTMLElement
|
||||
export let hideSignal: Store<any>
|
||||
|
@ -34,7 +35,7 @@
|
|||
|
||||
<div bind:this={mainElem} class="pointer-events-none absolute bottom-0 right-0 h-full w-full">
|
||||
<div id="hand-container">
|
||||
<img src="./assets/svg/hand.svg" />
|
||||
<Hand />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import Tr from "./Tr.svelte"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import { ImmutableStore, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Invalid from "../../assets/svg/Invalid.svelte";
|
||||
|
||||
export let state: {
|
||||
osmConnection: OsmConnection
|
||||
|
@ -35,7 +36,7 @@
|
|||
</slot>
|
||||
{:else if $loadingStatus === "error"}
|
||||
<div class="alert max-w-64 flex items-center">
|
||||
<img src="./assets/svg/invalid.svg" class="m-2 h-8 w-8 shrink-0" />
|
||||
<Invalid class="m-2 h-8 w-8 shrink-0" />
|
||||
<Tr t={offlineModes[$apiState]} />
|
||||
</div>
|
||||
{:else if $loadingStatus === "logged-in"}
|
||||
|
|
15
src/UI/Base/LogoutButton.svelte
Normal file
15
src/UI/Base/LogoutButton.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection";
|
||||
import Logout from "../../assets/svg/Logout.svelte";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Tr from "./Tr.svelte";
|
||||
|
||||
export let osmConnection: OsmConnection
|
||||
</script>
|
||||
|
||||
<button on:click={() => {
|
||||
state.osmConnection.LogOut()
|
||||
}}>
|
||||
<Logout class="w-6 h-6"/>
|
||||
<Tr t={Translations.t.general.logout}/>
|
||||
</button>
|
48
src/UI/Base/OpenJosm.svelte
Normal file
48
src/UI/Base/OpenJosm.svelte
Normal file
|
@ -0,0 +1,48 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../Logic/UIEventSource";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Tr from "./Tr.svelte";
|
||||
import Josm_logo from "../../assets/svg/Josm_logo.svelte";
|
||||
import Constants from "../../Models/Constants";
|
||||
import type { SpecialVisualizationState } from "../SpecialVisualization";
|
||||
|
||||
export let state : SpecialVisualizationState
|
||||
const t = Translations.t.general.attribution;
|
||||
const josmState = new UIEventSource<"OK" | string>(undefined);
|
||||
// Reset after 15s
|
||||
josmState.stabilized(15000).addCallbackD(() => josmState.setData(undefined));
|
||||
|
||||
const showButton = state.osmConnection.userDetails.map(
|
||||
(ud) => ud.loggedIn && ud.csCount >= Constants.userJourney.historyLinkVisible
|
||||
);
|
||||
|
||||
function openJosm() {
|
||||
const bbox = state.mapProperties. bounds.data;
|
||||
if (bbox === undefined) {
|
||||
return;
|
||||
}
|
||||
const top = bbox.getNorth();
|
||||
const bottom = bbox.getSouth();
|
||||
const right = bbox.getEast();
|
||||
const left = bbox.getWest();
|
||||
const josmLink = `http://127.0.0.1:8111/load_and_zoom?left=${left}&right=${right}&top=${top}&bottom=${bottom}`;
|
||||
Utils.download(josmLink)
|
||||
.then((answer) => josmState.setData(answer.replace(/\n/g, "").trim()))
|
||||
.catch(() => josmState.setData("ERROR"));
|
||||
}
|
||||
|
||||
</script>
|
||||
{#if $showButton}
|
||||
{#if $josmState === undefined}
|
||||
<!-- empty -->
|
||||
{:else if state === "OK"}
|
||||
<Tr cls="thanks" t={t.josmOpened} />
|
||||
{:else}
|
||||
<Tr cls="alert" t={t.josmNotOpened} />
|
||||
{/if}
|
||||
|
||||
<button class="flex items-center" on:click={openJosm}>
|
||||
<Josm_logo class="h-12 w-12 p-2 pr-4" />
|
||||
<Tr t={t.editJosm} />
|
||||
</button>
|
||||
{/if}
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import ToSvelte from "./ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
import Share from "../../assets/svg/Share.svelte";
|
||||
|
||||
export let generateShareData: () => {
|
||||
text: string
|
||||
|
@ -25,6 +26,6 @@
|
|||
|
||||
<button on:click={share} class="secondary m-0 h-8 w-8 p-0">
|
||||
<slot name="content">
|
||||
<ToSvelte construct={Svg.share_svg().SetClass("w-7 h-7 p-1")} />
|
||||
<Share class="w-7 h-7 p-1"/>
|
||||
</slot>
|
||||
</button>
|
||||
|
|
|
@ -23,10 +23,10 @@ export default class SvelteUIElement<
|
|||
private readonly _events: Events
|
||||
private readonly _slots: Slots
|
||||
|
||||
constructor(svelteElement, props: Props, events?: Events, slots?: Slots) {
|
||||
constructor(svelteElement, props?: Props, events?: Events, slots?: Slots) {
|
||||
super()
|
||||
this._svelteComponent = svelteElement
|
||||
this._props = props
|
||||
this._props = props ?? <Props>{}
|
||||
this._events = events
|
||||
this._slots = slots
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import Locale from "../i18n/Locale"
|
||||
import LinkToWeblate from "./LinkToWeblate"
|
||||
import Translate from "../../assets/svg/Translate.svelte";
|
||||
|
||||
/**
|
||||
* Shows a small icon which will open up weblate; a contributor can translate the item for 'context' there
|
||||
|
@ -19,7 +20,7 @@
|
|||
target="_blank"
|
||||
class="weblate-link mx-1"
|
||||
>
|
||||
<img src="./assets/svg/translate.svg" class="font-gray" />
|
||||
<Translate class="font-gray" />
|
||||
</a>
|
||||
{:else if $linkToWeblate}
|
||||
<a
|
||||
|
@ -27,7 +28,7 @@
|
|||
class="weblate-link hidden-on-mobile mx-1"
|
||||
target="_blank"
|
||||
>
|
||||
<img src="./assets/svg/translate.svg" class="font-gray inline-block" />
|
||||
<Translate class="font-gray inline-block" />
|
||||
</a>
|
||||
{/if}
|
||||
{/if}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import { Store } from "../../Logic/UIEventSource"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Mapillary_black from "../../assets/svg/Mapillary_black.svelte";
|
||||
|
||||
/*
|
||||
A subtleButton which opens mapillary in a new tab at the current location
|
||||
|
@ -21,7 +22,7 @@
|
|||
</script>
|
||||
|
||||
<a class="button flex items-center" href={mapillaryLink} target="_blank">
|
||||
<ToSvelte construct={() => Svg.mapillary_black_svg().SetClass("w-12 h-12 m-2 mr-4 shrink-0")} />
|
||||
<Mapillary_black class="w-12 h-12 m-2 mr-4 shrink-0"/>
|
||||
<div class="flex flex-col">
|
||||
<Tr t={Translations.t.general.attribution.openMapillary} />
|
||||
<Tr cls="subtle" t={Translations.t.general.attribution.mapillaryHelp} />
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { Utils } from "../../Utils"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import Move_arrows from "../../assets/svg/Move_arrows.svelte";
|
||||
|
||||
/**
|
||||
* An advanced location input, which has support to:
|
||||
|
@ -125,6 +126,6 @@
|
|||
maxDistanceInMeters="50"
|
||||
>
|
||||
<slot name="image" slot="image">
|
||||
<img class="h-full max-h-24" src="./assets/svg/move-arrows.svg" />
|
||||
<Move_arrows class="h-full max-h-24" />
|
||||
</slot>
|
||||
</LocationInput>
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
import Combine from "../Base/Combine"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import Translations from "../i18n/Translations"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Toggle from "../Input/Toggle"
|
||||
import { SubtleButton } from "../Base/SubtleButton"
|
||||
import Svg from "../../Svg"
|
||||
import { Utils } from "../../Utils"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
export class OpenJosm extends Combine {
|
||||
public static readonly needsUrls = ["http://127.0.0.1:8111/load_and_zoom"]
|
||||
constructor(osmConnection: OsmConnection, bounds: Store<BBox>, iconStyle?: string) {
|
||||
const t = Translations.t.general.attribution
|
||||
|
||||
const josmState = new UIEventSource<string>(undefined)
|
||||
// Reset after 15s
|
||||
josmState.stabilized(15000).addCallbackD(() => josmState.setData(undefined))
|
||||
|
||||
const stateIndication = new VariableUiElement(
|
||||
josmState.map((state) => {
|
||||
if (state === undefined) {
|
||||
return undefined
|
||||
}
|
||||
state = state.toUpperCase()
|
||||
if (state === "OK") {
|
||||
return t.josmOpened.SetClass("thanks")
|
||||
}
|
||||
return t.josmNotOpened.SetClass("alert")
|
||||
})
|
||||
)
|
||||
|
||||
const toggle = new Toggle(
|
||||
new SubtleButton(Svg.josm_logo_svg().SetStyle(iconStyle), t.editJosm)
|
||||
.onClick(() => {
|
||||
const bbox = bounds.data
|
||||
if (bbox === undefined) {
|
||||
return
|
||||
}
|
||||
const top = bbox.getNorth()
|
||||
const bottom = bbox.getSouth()
|
||||
const right = bbox.getEast()
|
||||
const left = bbox.getWest()
|
||||
const josmLink = `http://127.0.0.1:8111/load_and_zoom?left=${left}&right=${right}&top=${top}&bottom=${bottom}`
|
||||
Utils.download(josmLink)
|
||||
.then((answer) => josmState.setData(answer.replace(/\n/g, "").trim()))
|
||||
.catch(() => josmState.setData("ERROR"))
|
||||
})
|
||||
.SetClass("w-full"),
|
||||
undefined,
|
||||
osmConnection.userDetails.map(
|
||||
(ud) => ud.loggedIn && ud.csCount >= Constants.userJourney.historyLinkVisible
|
||||
)
|
||||
)
|
||||
|
||||
super([stateIndication, toggle])
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
import If from "../Base/If.svelte"
|
||||
import { ExclamationTriangleIcon } from "@babeard/svelte-heroicons/mini"
|
||||
import type { Readable } from "svelte/store"
|
||||
import Add from "../../assets/svg/Add.svelte";
|
||||
|
||||
/**
|
||||
* The theme introduction panel
|
||||
|
@ -156,7 +157,7 @@
|
|||
<div class="links-as-button links-w-full m-2 flex flex-col gap-y-1">
|
||||
<!-- bottom buttons, a bit hidden away: switch layout -->
|
||||
<a class="flex" href={Utils.HomepageLink()}>
|
||||
<img class="h-6 w-6" src="./assets/svg/add.svg" />
|
||||
<Add class="h-6 w-6"/>
|
||||
<Tr t={Translations.t.general.backToIndex} />
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -12,6 +12,8 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
|||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { LoginToggle } from "../Popup/LoginButton"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import Upload from "../../assets/svg/Upload.svelte"
|
||||
|
||||
export default class UploadTraceToOsmUI extends LoginToggle {
|
||||
constructor(
|
||||
|
@ -83,7 +85,7 @@ export default class UploadTraceToOsmUI extends LoginToggle {
|
|||
clicked.setData(false)
|
||||
})
|
||||
.SetClass(""),
|
||||
new SubtleButton(Svg.upload_svg(), t.confirm).OnClickWithLoading(
|
||||
new SubtleButton(new SvelteUIElement(Upload, {}), t.confirm).OnClickWithLoading(
|
||||
t.uploading,
|
||||
async () => {
|
||||
const titleStr = UploadTraceToOsmUI.createDefault(
|
||||
|
@ -119,7 +121,7 @@ export default class UploadTraceToOsmUI extends LoginToggle {
|
|||
]).SetClass("flex p-2 rounded-xl border-2 subtle-border items-center"),
|
||||
new Toggle(
|
||||
confirmPanel,
|
||||
new SubtleButton(Svg.upload_svg(), t.title).onClick(() =>
|
||||
new SubtleButton(new SvelteUIElement(Upload), t.title).onClick(() =>
|
||||
clicked.setData(true)
|
||||
),
|
||||
clicked
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
* Shows an 'upload'-button which will start the upload for this feature
|
||||
*/
|
||||
|
||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
|
||||
import type { OsmTags } from "../../Models/OsmFeature"
|
||||
import LoginToggle from "../Base/LoginToggle.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import UploadingImageCounter from "./UploadingImageCounter.svelte"
|
||||
import FileSelector from "../Base/FileSelector.svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
import type { SpecialVisualizationState } from "../SpecialVisualization";
|
||||
import { ImmutableStore, Store } from "../../Logic/UIEventSource";
|
||||
import type { OsmTags } from "../../Models/OsmFeature";
|
||||
import LoginToggle from "../Base/LoginToggle.svelte";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Tr from "../Base/Tr.svelte";
|
||||
import UploadingImageCounter from "./UploadingImageCounter.svelte";
|
||||
import FileSelector from "../Base/FileSelector.svelte";
|
||||
import Camera_plus from "../../assets/svg/Camera_plus.svelte";
|
||||
|
||||
export let state: SpecialVisualizationState
|
||||
|
||||
|
@ -58,7 +57,7 @@
|
|||
{#if image !== undefined}
|
||||
<img src={image} />
|
||||
{:else}
|
||||
<ToSvelte construct={Svg.camera_plus_svg().SetClass("block w-12 h-12 p-1 text-4xl ")} />
|
||||
<Camera_plus class="block w-12 h-12 p-1 text-4xl"/>
|
||||
{/if}
|
||||
{#if labelText}
|
||||
{labelText}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import * as turf from "@turf/turf"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import { createEventDispatcher, onDestroy } from "svelte"
|
||||
import Move_arrows from "../../../assets/svg/Move_arrows.svelte";
|
||||
|
||||
/**
|
||||
* A visualisation to pick a location on a map background
|
||||
|
@ -90,7 +91,7 @@
|
|||
class="pointer-events-none absolute top-0 left-0 flex h-full w-full items-center p-8 opacity-50"
|
||||
>
|
||||
<slot name="image">
|
||||
<img class="h-full max-h-24" src="./assets/svg/move-arrows.svg" />
|
||||
<Move_arrows class="h-full max-h-24"/>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<script lang="ts">
|
||||
import PointRenderingConfig, { IconConfig } from "../../Models/ThemeConfig/PointRenderingConfig"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import DynamicIcon from "./DynamicIcon.svelte"
|
||||
import { IconConfig } from "../../Models/ThemeConfig/PointRenderingConfig";
|
||||
import { ImmutableStore, Store } from "../../Logic/UIEventSource";
|
||||
import DynamicIcon from "./DynamicIcon.svelte";
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
|
||||
|
||||
/**
|
||||
* Renders a 'marker', which consists of multiple 'icons'
|
||||
*/
|
||||
export let config: PointRenderingConfig
|
||||
let icons: IconConfig[] = config.marker
|
||||
export let tags: Store<Record<string, string>>
|
||||
let rotation = tags.map(tags => config.rotation.GetRenderValue(tags).Subs(tags).txt)
|
||||
|
||||
export let marker: IconConfig[] = config?.marker;
|
||||
export let rotation: TagRenderingConfig
|
||||
export let tags: Store<Record<string, string>>;
|
||||
let _rotation = rotation ? tags.map(tags => rotation.GetRenderValue(tags).Subs(tags).txt) : new ImmutableStore(0);
|
||||
</script>
|
||||
|
||||
{#if config !== undefined}
|
||||
<div class="relative h-full w-full" style={`transform: rotate(${$rotation})`}>
|
||||
{#each icons as icon}
|
||||
{#if marker && marker}
|
||||
<div class="relative h-full w-full" style={`transform: rotate(${$_rotation})`}>
|
||||
{#each marker as icon}
|
||||
<DynamicIcon {icon} {tags} />
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import { createEventDispatcher } from "svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
import Plantnet_logo from "../../assets/svg/Plantnet_logo.svelte";
|
||||
|
||||
/**
|
||||
* The main entry point for the plantnet wizard
|
||||
|
@ -142,9 +143,7 @@
|
|||
</BackButton>
|
||||
{/if}
|
||||
<div class="low-interaction flex self-end rounded-xl p-2">
|
||||
<ToSvelte
|
||||
construct={Svg.plantnet_logo_svg().SetClass("w-8 h-8 p-1 mr-1 bg-white rounded-full")}
|
||||
/>
|
||||
<Plantnet_logo class="w-8 h-8 p-1 mr-1 bg-white rounded-full"/>
|
||||
<Tr t={t.poweredByPlantnet} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,109 +3,110 @@
|
|||
* This component ties together all the steps that are needed to create a new point.
|
||||
* There are many subcomponents which help with that
|
||||
*/
|
||||
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
import PresetList from "./PresetList.svelte"
|
||||
import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import Tr from "../../Base/Tr.svelte"
|
||||
import SubtleButton from "../../Base/SubtleButton.svelte"
|
||||
import FromHtml from "../../Base/FromHtml.svelte"
|
||||
import Translations from "../../i18n/Translations.js"
|
||||
import TagHint from "../TagHint.svelte"
|
||||
import { And } from "../../../Logic/Tags/And.js"
|
||||
import LoginToggle from "../../Base/LoginToggle.svelte"
|
||||
import Constants from "../../../Models/Constants.js"
|
||||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import { Store, UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import { EyeIcon, EyeOffIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import LoginButton from "../../Base/LoginButton.svelte"
|
||||
import NewPointLocationInput from "../../BigComponents/NewPointLocationInput.svelte"
|
||||
import CreateNewNodeAction from "../../../Logic/Osm/Actions/CreateNewNodeAction"
|
||||
import { OsmWay } from "../../../Logic/Osm/OsmObject"
|
||||
import { Tag } from "../../../Logic/Tags/Tag"
|
||||
import type { WayId } from "../../../Models/OsmFeature"
|
||||
import Loading from "../../Base/Loading.svelte"
|
||||
import type { GlobalFilter } from "../../../Models/GlobalFilter"
|
||||
import { onDestroy } from "svelte"
|
||||
import NextButton from "../../Base/NextButton.svelte"
|
||||
import BackButton from "../../Base/BackButton.svelte"
|
||||
import ToSvelte from "../../Base/ToSvelte.svelte"
|
||||
import Svg from "../../../Svg"
|
||||
import OpenBackgroundSelectorButton from "../../BigComponents/OpenBackgroundSelectorButton.svelte"
|
||||
import { twJoin } from "tailwind-merge"
|
||||
import type { SpecialVisualizationState } from "../../SpecialVisualization";
|
||||
import PresetList from "./PresetList.svelte";
|
||||
import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig";
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
|
||||
import Tr from "../../Base/Tr.svelte";
|
||||
import SubtleButton from "../../Base/SubtleButton.svelte";
|
||||
import Translations from "../../i18n/Translations.js";
|
||||
import TagHint from "../TagHint.svelte";
|
||||
import { And } from "../../../Logic/Tags/And.js";
|
||||
import LoginToggle from "../../Base/LoginToggle.svelte";
|
||||
import Constants from "../../../Models/Constants.js";
|
||||
import FilteredLayer from "../../../Models/FilteredLayer";
|
||||
import { Store, UIEventSource } from "../../../Logic/UIEventSource";
|
||||
import { EyeIcon, EyeOffIcon } from "@rgossiaux/svelte-heroicons/solid";
|
||||
import LoginButton from "../../Base/LoginButton.svelte";
|
||||
import NewPointLocationInput from "../../BigComponents/NewPointLocationInput.svelte";
|
||||
import CreateNewNodeAction from "../../../Logic/Osm/Actions/CreateNewNodeAction";
|
||||
import { OsmWay } from "../../../Logic/Osm/OsmObject";
|
||||
import { Tag } from "../../../Logic/Tags/Tag";
|
||||
import type { WayId } from "../../../Models/OsmFeature";
|
||||
import Loading from "../../Base/Loading.svelte";
|
||||
import type { GlobalFilter } from "../../../Models/GlobalFilter";
|
||||
import { onDestroy } from "svelte";
|
||||
import NextButton from "../../Base/NextButton.svelte";
|
||||
import BackButton from "../../Base/BackButton.svelte";
|
||||
import ToSvelte from "../../Base/ToSvelte.svelte";
|
||||
import Svg from "../../../Svg";
|
||||
import OpenBackgroundSelectorButton from "../../BigComponents/OpenBackgroundSelectorButton.svelte";
|
||||
import { twJoin } from "tailwind-merge";
|
||||
import Confirm from "../../../assets/svg/Confirm.svelte";
|
||||
import Close from "../../../assets/svg/Close.svelte";
|
||||
|
||||
export let coordinate: { lon: number; lat: number }
|
||||
export let state: SpecialVisualizationState
|
||||
export let coordinate: { lon: number; lat: number };
|
||||
export let state: SpecialVisualizationState;
|
||||
|
||||
let selectedPreset: {
|
||||
preset: PresetConfig
|
||||
layer: LayerConfig
|
||||
icon: string
|
||||
tags: Record<string, string>
|
||||
} = undefined
|
||||
let checkedOfGlobalFilters: number = 0
|
||||
let confirmedCategory = false
|
||||
} = undefined;
|
||||
let checkedOfGlobalFilters: number = 0;
|
||||
let confirmedCategory = false;
|
||||
$: if (selectedPreset === undefined) {
|
||||
confirmedCategory = false
|
||||
creating = false
|
||||
checkedOfGlobalFilters = 0
|
||||
confirmedCategory = false;
|
||||
creating = false;
|
||||
checkedOfGlobalFilters = 0;
|
||||
}
|
||||
|
||||
let flayer: FilteredLayer = undefined
|
||||
let layerIsDisplayed: UIEventSource<boolean> | undefined = undefined
|
||||
let layerHasFilters: Store<boolean> | undefined = undefined
|
||||
let globalFilter: UIEventSource<GlobalFilter[]> = state.layerState.globalFilters
|
||||
let _globalFilter: GlobalFilter[] = []
|
||||
let flayer: FilteredLayer = undefined;
|
||||
let layerIsDisplayed: UIEventSource<boolean> | undefined = undefined;
|
||||
let layerHasFilters: Store<boolean> | undefined = undefined;
|
||||
let globalFilter: UIEventSource<GlobalFilter[]> = state.layerState.globalFilters;
|
||||
let _globalFilter: GlobalFilter[] = [];
|
||||
onDestroy(
|
||||
globalFilter.addCallbackAndRun((globalFilter) => {
|
||||
console.log("Global filters are", globalFilter)
|
||||
_globalFilter = globalFilter ?? []
|
||||
console.log("Global filters are", globalFilter);
|
||||
_globalFilter = globalFilter ?? [];
|
||||
})
|
||||
)
|
||||
);
|
||||
$: {
|
||||
flayer = state.layerState.filteredLayers.get(selectedPreset?.layer?.id)
|
||||
layerIsDisplayed = flayer?.isDisplayed
|
||||
layerHasFilters = flayer?.hasFilter
|
||||
flayer = state.layerState.filteredLayers.get(selectedPreset?.layer?.id);
|
||||
layerIsDisplayed = flayer?.isDisplayed;
|
||||
layerHasFilters = flayer?.hasFilter;
|
||||
}
|
||||
const t = Translations.t.general.add
|
||||
const t = Translations.t.general.add;
|
||||
|
||||
const zoom = state.mapProperties.zoom
|
||||
const zoom = state.mapProperties.zoom;
|
||||
|
||||
const isLoading = state.dataIsLoading
|
||||
let preciseCoordinate: UIEventSource<{ lon: number; lat: number }> = new UIEventSource(undefined)
|
||||
let snappedToObject: UIEventSource<string> = new UIEventSource<string>(undefined)
|
||||
const isLoading = state.dataIsLoading;
|
||||
let preciseCoordinate: UIEventSource<{ lon: number; lat: number }> = new UIEventSource(undefined);
|
||||
let snappedToObject: UIEventSource<string> = new UIEventSource<string>(undefined);
|
||||
|
||||
// Small helper variable: if the map is tapped, we should let the 'Next'-button grab some attention as users have to click _that_ to continue, not the map
|
||||
let preciseInputIsTapped = false
|
||||
let preciseInputIsTapped = false;
|
||||
|
||||
let creating = false
|
||||
let creating = false;
|
||||
|
||||
/**
|
||||
* Call when the user should restart the flow by clicking on the map, e.g. because they disabled filters.
|
||||
* Will delete the lastclick-location
|
||||
*/
|
||||
function abort() {
|
||||
state.selectedElement.setData(undefined)
|
||||
state.selectedElement.setData(undefined);
|
||||
// When aborted, we force the contributors to place the pin _again_
|
||||
// This is because there might be a nearby object that was disabled; this forces them to re-evaluate the map
|
||||
state.lastClickObject.features.setData([])
|
||||
preciseInputIsTapped = false
|
||||
state.lastClickObject.features.setData([]);
|
||||
preciseInputIsTapped = false;
|
||||
}
|
||||
|
||||
async function confirm() {
|
||||
creating = true
|
||||
const location: { lon: number; lat: number } = preciseCoordinate.data
|
||||
const snapTo: WayId | undefined = <WayId>snappedToObject.data
|
||||
creating = true;
|
||||
const location: { lon: number; lat: number } = preciseCoordinate.data;
|
||||
const snapTo: WayId | undefined = <WayId>snappedToObject.data;
|
||||
const tags: Tag[] = selectedPreset.preset.tags.concat(
|
||||
..._globalFilter.map((f) => f?.onNewPoint?.tags ?? [])
|
||||
)
|
||||
console.log("Creating new point at", location, "snapped to", snapTo, "with tags", tags)
|
||||
);
|
||||
console.log("Creating new point at", location, "snapped to", snapTo, "with tags", tags);
|
||||
|
||||
let snapToWay: undefined | OsmWay = undefined
|
||||
let snapToWay: undefined | OsmWay = undefined;
|
||||
if (snapTo !== undefined && snapTo !== null) {
|
||||
const downloaded = await state.osmObjectDownloader.DownloadObjectAsync(snapTo, 0)
|
||||
const downloaded = await state.osmObjectDownloader.DownloadObjectAsync(snapTo, 0);
|
||||
if (downloaded !== "deleted") {
|
||||
snapToWay = downloaded
|
||||
snapToWay = downloaded;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,44 +114,44 @@
|
|||
theme: state.layout?.id ?? "unkown",
|
||||
changeType: "create",
|
||||
snapOnto: snapToWay,
|
||||
reusePointWithinMeters: 1,
|
||||
})
|
||||
await state.changes.applyAction(newElementAction)
|
||||
state.newFeatures.features.ping()
|
||||
reusePointWithinMeters: 1
|
||||
});
|
||||
await state.changes.applyAction(newElementAction);
|
||||
state.newFeatures.features.ping();
|
||||
// The 'changes' should have created a new point, which added this into the 'featureProperties'
|
||||
const newId = newElementAction.newElementId
|
||||
console.log("Applied pending changes, fetching store for", newId)
|
||||
const tagsStore = state.featureProperties.getStore(newId)
|
||||
const newId = newElementAction.newElementId;
|
||||
console.log("Applied pending changes, fetching store for", newId);
|
||||
const tagsStore = state.featureProperties.getStore(newId);
|
||||
if (!tagsStore) {
|
||||
console.error("Bug: no tagsStore found for", newId)
|
||||
console.error("Bug: no tagsStore found for", newId);
|
||||
}
|
||||
{
|
||||
// Set some metainfo
|
||||
const properties = tagsStore.data
|
||||
const properties = tagsStore.data;
|
||||
if (snapTo) {
|
||||
// metatags (starting with underscore) are not uploaded, so we can safely mark this
|
||||
delete properties["_referencing_ways"]
|
||||
properties["_referencing_ways"] = `["${snapTo}"]`
|
||||
delete properties["_referencing_ways"];
|
||||
properties["_referencing_ways"] = `["${snapTo}"]`;
|
||||
}
|
||||
properties["_backend"] = state.osmConnection.Backend()
|
||||
properties["_last_edit:timestamp"] = new Date().toISOString()
|
||||
const userdetails = state.osmConnection.userDetails.data
|
||||
properties["_last_edit:contributor"] = userdetails.name
|
||||
properties["_last_edit:uid"] = "" + userdetails.uid
|
||||
tagsStore.ping()
|
||||
properties["_backend"] = state.osmConnection.Backend();
|
||||
properties["_last_edit:timestamp"] = new Date().toISOString();
|
||||
const userdetails = state.osmConnection.userDetails.data;
|
||||
properties["_last_edit:contributor"] = userdetails.name;
|
||||
properties["_last_edit:uid"] = "" + userdetails.uid;
|
||||
tagsStore.ping();
|
||||
}
|
||||
const feature = state.indexedFeatures.featuresById.data.get(newId)
|
||||
console.log("Selecting feature", feature, "and opening their popup")
|
||||
abort()
|
||||
state.selectedLayer.setData(selectedPreset.layer)
|
||||
state.selectedElement.setData(feature)
|
||||
tagsStore.ping()
|
||||
const feature = state.indexedFeatures.featuresById.data.get(newId);
|
||||
console.log("Selecting feature", feature, "and opening their popup");
|
||||
abort();
|
||||
state.selectedLayer.setData(selectedPreset.layer);
|
||||
state.selectedElement.setData(feature);
|
||||
tagsStore.ping();
|
||||
}
|
||||
|
||||
function confirmSync() {
|
||||
confirm()
|
||||
.then((_) => console.debug("New point successfully handled"))
|
||||
.catch((e) => console.error("Handling the new point went wrong due to", e))
|
||||
.catch((e) => console.error("Handling the new point went wrong due to", e));
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -285,7 +286,7 @@
|
|||
<NextButton on:click={() => (confirmedCategory = true)} clss="primary w-full">
|
||||
<div slot="image" class="relative">
|
||||
<ToSvelte construct={selectedPreset.icon} />
|
||||
<img class="absolute bottom-0 right-0 h-4 w-4" src="./assets/svg/confirm.svg" />
|
||||
<Confirm class="absolute bottom-0 right-0 h-4 w-4" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<Tr t={selectedPreset.text} />
|
||||
|
@ -299,11 +300,7 @@
|
|||
checkedOfGlobalFilters = checkedOfGlobalFilters + 1
|
||||
}}
|
||||
>
|
||||
<img
|
||||
slot="image"
|
||||
src={_globalFilter[checkedOfGlobalFilters].onNewPoint?.icon ?? "./assets/svg/confirm.svg"}
|
||||
class="h-12 w-12"
|
||||
/>
|
||||
<Confirm slot="image" class="h-12 w-12" />
|
||||
<Tr
|
||||
slot="message"
|
||||
t={_globalFilter[checkedOfGlobalFilters].onNewPoint?.confirmAddNew.Subs({
|
||||
|
@ -317,7 +314,7 @@
|
|||
abort()
|
||||
}}
|
||||
>
|
||||
<img slot="image" src="./assets/svg/close.svg" class="h-8 w-8" />
|
||||
<Close slot="image" class="h-8 w-8" />
|
||||
<Tr slot="message" t={Translations.t.general.cancel} />
|
||||
</SubtleButton>
|
||||
{:else if !creating}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
import NewPointLocationInput from "../BigComponents/NewPointLocationInput.svelte"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
import Layers from "../../assets/svg/Layers.svelte";
|
||||
import AddSmall from "../../assets/svg/AddSmall.svelte";
|
||||
|
||||
export let coordinate: UIEventSource<{ lon: number; lat: number }>
|
||||
export let state: SpecialVisualizationState
|
||||
|
@ -97,7 +99,7 @@
|
|||
<Tr t={Translations.t.notes.noteLayerHasFilters} />
|
||||
</div>
|
||||
<SubtleButton on:click={() => notelayer.disableAllFilters()}>
|
||||
<img slot="image" src="./assets/svg/filter.svg" class="mr-4 h-8 w-8" />
|
||||
<Layers class="mr-4 h-8 w-8"/>
|
||||
<Tr slot="message" t={Translations.t.notes.disableAllNoteFilters} />
|
||||
</SubtleButton>
|
||||
</div>
|
||||
|
@ -126,7 +128,7 @@
|
|||
|
||||
{#if $comment?.length >= 3}
|
||||
<SubtleButton on:click={uploadNote}>
|
||||
<img slot="image" src="./assets/svg/addSmall.svg" class="mr-4 h-8 w-8" />
|
||||
<AddSmall slot="image" class="mr-4 h-8 w-8" />
|
||||
<Tr slot="message" t={Translations.t.notes.createNote} />
|
||||
</SubtleButton>
|
||||
{:else}
|
||||
|
@ -143,7 +145,7 @@
|
|||
<Tr t={Translations.t.notes.noteLayerNotEnabled} />
|
||||
</div>
|
||||
<SubtleButton on:click={enableNoteLayer}>
|
||||
<img slot="image" src="./assets/svg/layers.svg" class="mr-4 h-8 w-8" />
|
||||
<Layers slot="image" class="mr-4 h-8 w-8" />
|
||||
<Tr slot="message" t={Translations.t.notes.noteLayerDoEnable} />
|
||||
</SubtleButton>
|
||||
</div>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import { XCircleIcon } from "@babeard/svelte-heroicons/solid"
|
||||
import exp from "constants"
|
||||
import Camera_plus from "../../assets/svg/Camera_plus.svelte";
|
||||
|
||||
export let tags: Store<OsmTags>
|
||||
export let state: SpecialVisualizationState
|
||||
|
@ -42,7 +43,7 @@
|
|||
expanded = true
|
||||
}}
|
||||
>
|
||||
<ToSvelte construct={Svg.camera_plus_svg().SetClass("block w-8 h-8 p-1 mr-2 ")} />
|
||||
<Camera_plus class="block w-8 h-8 p-1 mr-2"/>
|
||||
<Tr t={t.seeNearby} />
|
||||
</button>
|
||||
{/if}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
import UserRelatedState from "../../../Logic/State/UserRelatedState"
|
||||
import { twJoin } from "tailwind-merge"
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import Search from "../../../assets/svg/Search.svelte";
|
||||
import Login from "../../../assets/svg/Login.svelte";
|
||||
|
||||
export let config: TagRenderingConfig
|
||||
export let tags: UIEventSource<Record<string, string>>
|
||||
|
@ -217,7 +219,7 @@
|
|||
|
||||
{#if config.mappings?.length >= 8}
|
||||
<div class="sticky flex w-full">
|
||||
<img src="./assets/svg/search.svg" class="h-6 w-6" />
|
||||
<Search class="h-6 w-6"/>
|
||||
<input type="text" bind:value={$searchTerm} class="w-full" />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -324,7 +326,7 @@
|
|||
<LoginToggle {state}>
|
||||
<Loading slot="loading" />
|
||||
<SubtleButton slot="not-logged-in" on:click={() => state?.osmConnection?.AttemptLogin()}>
|
||||
<img slot="image" src="./assets/svg/login.svg" class="h-8 w-8" />
|
||||
<Login slot="image" class="h-8 w-8" />
|
||||
<Tr t={Translations.t.general.loginToStart} slot="message" />
|
||||
</SubtleButton>
|
||||
{#if $feedback !== undefined}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
import Mangrove_logo from "../../assets/svg/Mangrove_logo.svelte";
|
||||
|
||||
/**
|
||||
* An element showing all reviews
|
||||
|
@ -40,7 +41,7 @@
|
|||
<Tr t={Translations.t.reviews.no_reviews_yet} />
|
||||
{/if}
|
||||
<div class="flex justify-end">
|
||||
<ToSvelte construct={Svg.mangrove_logo_svg().SetClass("w-12 h-12 shrink-0 p-1 ")} />
|
||||
<Mangrove_logo class="w-12 h-12 shrink-0 p-1"/>
|
||||
<Tr cls="text-sm subtle" t={Translations.t.reviews.attribution} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -58,7 +58,6 @@ import { PointImportButtonViz } from "./Popup/ImportButtons/PointImportButtonViz
|
|||
import WayImportButtonViz from "./Popup/ImportButtons/WayImportButtonViz"
|
||||
import ConflateImportButtonViz from "./Popup/ImportButtons/ConflateImportButtonViz"
|
||||
import DeleteWizard from "./Popup/DeleteFlow/DeleteWizard.svelte"
|
||||
import { OpenJosm } from "./BigComponents/OpenJosm"
|
||||
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"
|
||||
import FediverseValidator from "./InputElement/Validators/FediverseValidator"
|
||||
import SendEmail from "./Popup/SendEmail.svelte"
|
||||
|
@ -78,6 +77,8 @@ import { TagUtils } from "../Logic/Tags/TagUtils"
|
|||
import Giggity from "./BigComponents/Giggity.svelte"
|
||||
import ThemeViewState from "../Models/ThemeViewState"
|
||||
import LanguagePicker from "./InputElement/LanguagePicker.svelte"
|
||||
import LogoutButton from "./Base/LogoutButton.svelte"
|
||||
import OpenJosm from "./Base/OpenJosm.svelte"
|
||||
|
||||
class NearbyImageVis implements SpecialVisualization {
|
||||
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||
|
@ -465,11 +466,7 @@ export default class SpecialVisualizations {
|
|||
needsUrls: [Constants.osmAuthConfig.url],
|
||||
docs: "Shows a button where the user can log out",
|
||||
constr(state: SpecialVisualizationState): BaseUIElement {
|
||||
return new SubtleButton(Svg.logout_svg(), Translations.t.general.logout, {
|
||||
imgSize: "w-6 h-6",
|
||||
}).onClick(() => {
|
||||
state.osmConnection.LogOut()
|
||||
})
|
||||
return new SvelteUIElement(LogoutButton, { osmConnection: state.osmConnection })
|
||||
},
|
||||
},
|
||||
new HistogramViz(),
|
||||
|
@ -903,10 +900,10 @@ export default class SpecialVisualizations {
|
|||
funcName: "open_in_josm",
|
||||
docs: "Opens the current view in the JOSM-editor",
|
||||
args: [],
|
||||
needsUrls: OpenJosm.needsUrls,
|
||||
needsUrls: ["http://127.0.0.1:8111/load_and_zoom"],
|
||||
|
||||
constr: (state) => {
|
||||
return new OpenJosm(state.osmConnection, state.mapProperties.bounds)
|
||||
return new SvelteUIElement(OpenJosm, { state })
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1099,12 +1096,6 @@ export default class SpecialVisualizations {
|
|||
if (maproulette_id_key === "" || maproulette_id_key === undefined) {
|
||||
maproulette_id_key = "mr_taskId"
|
||||
}
|
||||
if (Svg.All[image] !== undefined || Svg.All[image + ".svg"] !== undefined) {
|
||||
if (image.endsWith(".svg")) {
|
||||
image = image.substring(0, image.length - 4)
|
||||
}
|
||||
image = Svg[image + "_svg"]()
|
||||
}
|
||||
const failed = new UIEventSource(false)
|
||||
|
||||
const closeButton = new SubtleButton(image, message).OnClickWithLoading(
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
import { Utils } from "../Utils";
|
||||
import Translations from "./i18n/Translations";
|
||||
import Tr from "./Base/Tr.svelte";
|
||||
import Add from "../assets/svg/Add.svelte";
|
||||
|
||||
export let studioUrl =
|
||||
window.location.hostname === "127.0.0.2"
|
||||
|
@ -197,7 +198,7 @@
|
|||
Show the introduction again
|
||||
</button>
|
||||
<a class="flex button" href={Utils.HomepageLink()}>
|
||||
<img class="h-6 w-6" src="./assets/svg/add.svg" />
|
||||
<Add class="h-6 w-6" />
|
||||
<Tr t={Translations.t.general.backToIndex} />
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -43,18 +43,25 @@
|
|||
import RasterLayerOverview from "./Map/RasterLayerOverview.svelte";
|
||||
import IfHidden from "./Base/IfHidden.svelte";
|
||||
import { onDestroy } from "svelte";
|
||||
import { OpenJosm } from "./BigComponents/OpenJosm";
|
||||
import MapillaryLink from "./BigComponents/MapillaryLink.svelte";
|
||||
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte";
|
||||
import OpenBackgroundSelectorButton from "./BigComponents/OpenBackgroundSelectorButton.svelte";
|
||||
import StateIndicator from "./BigComponents/StateIndicator.svelte";
|
||||
import Locale from "./i18n/Locale";
|
||||
import ShareScreen from "./BigComponents/ShareScreen.svelte";
|
||||
import UploadingImageCounter from "./Image/UploadingImageCounter.svelte";
|
||||
import PendingChangesIndicator from "./BigComponents/PendingChangesIndicator.svelte";
|
||||
import Cross from "../assets/svg/Cross.svelte";
|
||||
import Summary from "./BigComponents/Summary.svelte";
|
||||
import LanguagePicker from "./InputElement/LanguagePicker.svelte";
|
||||
import Mastodon from "../assets/svg/Mastodon.svelte";
|
||||
import Bug from "../assets/svg/Bug.svelte";
|
||||
import Liberapay from "../assets/svg/Liberapay.svelte";
|
||||
import OpenJosm from "./Base/OpenJosm.svelte";
|
||||
import Min from "../assets/svg/Min.svelte";
|
||||
import Plus from "../assets/svg/Plus.svelte";
|
||||
import Filter from "../assets/svg/Filter.svelte";
|
||||
import Add from "../assets/svg/Add.svelte";
|
||||
import Statistics from "../assets/svg/Statistics.svelte";
|
||||
|
||||
export let state: ThemeViewState;
|
||||
let layout = state.layout;
|
||||
|
@ -205,7 +212,7 @@
|
|||
<!-- bottom left elements -->
|
||||
<If condition={state.featureSwitches.featureSwitchFilter}>
|
||||
<MapControlButton on:click={() => state.guistate.openFilterView()}>
|
||||
<ToSvelte construct={Svg.filter_svg().SetClass("h-6 w-6")} />
|
||||
<Filter class="h-6 w-6"/>
|
||||
</MapControlButton>
|
||||
</If>
|
||||
<If condition={state.featureSwitches.featureSwitchBackgroundSelection}>
|
||||
|
@ -244,10 +251,10 @@
|
|||
</div>
|
||||
</If>
|
||||
<MapControlButton on:click={() => mapproperties.zoom.update((z) => z + 1)}>
|
||||
<ToSvelte construct={Svg.plus_svg().SetClass("w-8 h-8")} />
|
||||
<Plus class="w-8 h-8" />
|
||||
</MapControlButton>
|
||||
<MapControlButton on:click={() => mapproperties.zoom.update((z) => z - 1)}>
|
||||
<ToSvelte construct={Svg.min_svg().SetClass("w-8 h-8")} />
|
||||
<Min class="w-8 h-8"/>
|
||||
</MapControlButton>
|
||||
<If condition={featureSwitches.featureSwitchGeolocation}>
|
||||
<MapControlButton>
|
||||
|
@ -340,7 +347,7 @@
|
|||
</div>
|
||||
|
||||
<div class="flex" slot="title1">
|
||||
<ToSvelte construct={Svg.filter_svg().SetClass("w-4 h-4")} />
|
||||
<Filter class="w-4 h-4"/>
|
||||
<Tr t={Translations.t.general.menu.filter} />
|
||||
</div>
|
||||
|
||||
|
@ -431,27 +438,27 @@
|
|||
<Tr t={Translations.t.general.aboutMapComplete.intro} />
|
||||
|
||||
<a class="flex" href={Utils.HomepageLink()}>
|
||||
<img class="h-6 w-6" src="./assets/svg/add.svg" />
|
||||
<Add class="h-6 w-6"/>
|
||||
<Tr t={Translations.t.general.backToIndex} />
|
||||
</a>
|
||||
|
||||
<a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank">
|
||||
<img class="h-6 w-6" src="./assets/svg/bug.svg" />
|
||||
<Bug class="h-6 w-6"/>
|
||||
<Tr t={Translations.t.general.attribution.openIssueTracker} />
|
||||
</a>
|
||||
|
||||
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">
|
||||
<img class="h-6 w-6" src="./assets/svg/mastodon.svg" />
|
||||
<Mastodon class="w-6 h-6" />
|
||||
<Tr t={Translations.t.general.attribution.followOnMastodon} />
|
||||
</a>
|
||||
|
||||
<a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank">
|
||||
<img class="h-6 w-6" src="./assets/svg/liberapay.svg" />
|
||||
<Liberapay class="h-6 w-6" />
|
||||
<Tr t={Translations.t.general.attribution.donate} />
|
||||
</a>
|
||||
|
||||
<a class="flex" href={Utils.OsmChaLinkFor(7)} target="_blank">
|
||||
<img class="h-6 w-6" src="./assets/svg/statistics.svg" />
|
||||
<Statistics class="h-6 w-6" />
|
||||
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: "MapComplete" })} />
|
||||
</a>
|
||||
{Constants.vNumber}
|
||||
|
@ -503,10 +510,7 @@
|
|||
<div class="m-2 flex flex-col" slot="content4">
|
||||
<If condition={featureSwitches.featureSwitchEnableLogin}>
|
||||
<OpenIdEditor mapProperties={state.mapProperties} />
|
||||
<ToSvelte
|
||||
construct={() =>
|
||||
new OpenJosm(state.osmConnection, state.mapProperties.bounds).SetClass("w-full")}
|
||||
/>
|
||||
<OpenJosm {state}/>
|
||||
<MapillaryLink mapProperties={state.mapProperties} />
|
||||
</If>
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import WikidataPreviewBox from "./WikidataPreviewBox"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Wikipedia from "../../assets/svg/Wikipedia.svelte";
|
||||
|
||||
/**
|
||||
* Shows a wikipedia-article + wikidata preview for the given item
|
||||
|
@ -18,7 +19,7 @@
|
|||
|
||||
{#if $wikipediaDetails.articleUrl}
|
||||
<a class="flex" href={$wikipediaDetails.articleUrl} rel="noreferrer" target="_blank">
|
||||
<img class="h-6 w-6" src="./assets/svg/wikipedia.svg" />
|
||||
<Wikipedia class="h-6 w-6"/>
|
||||
<Tr t={Translations.t.general.wikipedia.fromWikipedia} />
|
||||
</a>
|
||||
{/if}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<script>
|
||||
export let color = "#000000"
|
||||
</script>
|
||||
<svg {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave on:keydown xmlns="http://www.w3.org/2000/svg" width="374px" height="259px" viewBox="0 0 374 259" version="1.1"> <g id="surface1"/> </svg>
|
|
@ -1,4 +0,0 @@
|
|||
<script>
|
||||
export let color = "#000000"
|
||||
</script>
|
||||
<svg {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave on:keydown xmlns="http://www.w3.org/2000/svg" width="375px" height="375px" viewBox="0 0 375 375" version="1.1"> <g id="surface1"/> </svg>
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"374px\" height=\"374px\" viewBox=\"0 0 374 374\" version=\"1.1\"> <g id=\"surface1\"> <path style=\"fill: none !important;stroke-width:107.38591;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:4;\" d=\"M 674.316761 62.954545 C 661.244886 65.427807 645.489205 78.502674 631.082102 98.743316 C 611.320739 126.71123 594.430114 160.307487 554.52017 251.283422 C 521.406534 326.684492 508.134375 353.42246 490.856534 378.903743 C 470.721307 408.582888 456.781534 414.505348 407.044318 414.59893 C 378.123295 414.59893 352.353409 412.5 281.532955 404.47861 C 251.930966 401.042781 217.949432 397.513369 192.753693 395.227273 C 174.527841 393.596257 117.153125 393.596257 106.364489 395.227273 C 72.102557 400.574866 56.253409 411.831551 55.011648 431.684492 C 54.344034 443.903743 59.124148 456.97861 70.380114 473.877005 C 89.193466 501.938503 119.449716 532.299465 196.091761 600.160428 C 287.26108 680.828877 315.127273 712.23262 319.22642 738.770053 C 322.764773 761.096257 310.160227 801.377005 275.991761 877.941176 C 241.249148 955.828877 234.946875 969.852941 229.21875 983.890374 C 205.157955 1042.219251 195.624432 1079.157754 198.869034 1101.871658 C 201.819886 1123.061497 212.701989 1133.663102 232.944034 1134.893048 C 262.626136 1136.898396 306.248011 1118.770053 395.120739 1067.700535 C 466.608807 1026.564171 479.600568 1019.21123 495.436364 1010.802139 C 538.484091 987.90107 563.97358 978.542781 583.641477 978.262032 C 595.191193 978.168449 599.009943 979.21123 613.230114 986.283422 C 638.519318 998.970588 668.027841 1022.553476 737.326136 1085.548128 C 833.34233 1172.981283 871.436364 1200.668449 904.55 1207.352941 C 914.297159 1209.358289 921.066761 1208.596257 928.891193 1204.772727 C 938.731818 1200 944.166193 1191.885027 948.372159 1175.748663 C 950.375 1168.02139 950.561932 1165.160428 950.561932 1145.681818 C 950.561932 1133.756684 950.094602 1120.200535 949.413636 1115.13369 C 944.553409 1078.957219 939.2125 1050.802139 925.272727 987.713904 C 903.415057 889.010695 898.634943 861.042781 898.634943 830.494652 C 898.634943 815.026738 900.170455 805.681818 903.882386 797.473262 C 913.522727 776.377005 947.984943 750.695187 1025.588352 706.590909 C 1088.691193 670.802139 1104.914205 661.44385 1121.524432 651.417112 C 1192.064489 608.850267 1223.188636 578.783422 1223.188636 553.395722 C 1223.188636 538.596257 1214.015625 527.339572 1193.973864 517.312834 C 1165.333239 502.994652 1122.579261 494.786096 1025.588352 484.665775 C 925.179261 474.358289 898.26108 470.534759 869.340057 463.181818 C 832.394318 453.636364 820.270455 443.997326 807.478977 414.024064 C 796.316477 387.687166 787.34375 353.983957 770.159375 272.566845 C 757.274432 211.096257 749.91733 179.692513 742.57358 154.491979 C 731.598011 116.497326 719.66108 90.721925 706.295455 75.828877 C 697.322727 65.815508 685.198864 60.949198 674.316761 62.954545 Z M 674.316761 62.954545 \" transform=\"matrix(0.292553,0,0,0.292188,0.0585106,0)\"/> <path style=\" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;\" d=\"M 197.332031 18.394531 C 193.507812 19.117188 188.898438 22.9375 184.683594 28.851562 C 178.902344 37.023438 173.960938 46.839844 162.285156 73.421875 C 152.597656 95.453125 148.714844 103.265625 143.660156 110.710938 C 137.769531 119.382812 133.691406 121.113281 119.140625 121.140625 C 110.679688 121.140625 103.140625 120.527344 82.421875 118.183594 C 73.761719 117.179688 63.820312 116.148438 56.449219 115.480469 C 51.117188 115.003906 34.332031 115.003906 31.175781 115.480469 C 21.152344 117.042969 16.515625 120.332031 16.152344 126.132812 C 15.957031 129.703125 17.355469 133.523438 20.648438 138.460938 C 26.152344 146.660156 35.003906 155.53125 57.425781 175.359375 C 84.097656 198.929688 92.25 208.105469 93.449219 215.859375 C 94.484375 222.382812 90.796875 234.152344 80.800781 256.523438 C 70.636719 279.28125 68.792969 283.378906 67.117188 287.480469 C 60.078125 304.523438 57.289062 315.316406 58.238281 321.953125 C 59.101562 328.144531 62.285156 331.242188 68.207031 331.601562 C 76.890625 332.1875 89.652344 326.890625 115.652344 311.96875 C 136.566406 299.949219 140.367188 297.800781 145 295.34375 C 157.996094 288.640625 172.394531 285.695312 170.804688 285.835938 Z M 197.332031 18.394531 \"/> </g> </svg>
|
Before Width: | Height: | Size: 4.3 KiB |
File diff suppressed because one or more lines are too long
|
@ -4,14 +4,16 @@ import { describe, it } from "vitest"
|
|||
import { parse as parse_html } from "node-html-parser"
|
||||
import { readFileSync } from "fs"
|
||||
import ScriptUtils from "../scripts/ScriptUtils"
|
||||
|
||||
function detectInCode(forbidden: string, reason: string) {
|
||||
return wrap(detectInCodeUnwrapped(forbidden, reason))
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param forbidden: a GREP-regex. This means that '.' is a wildcard and should be escaped to match a literal dot
|
||||
* @param reason
|
||||
* @private
|
||||
*/
|
||||
function detectInCode(forbidden: string, reason: string): Promise<void> {
|
||||
function detectInCodeUnwrapped(forbidden: string, reason: string): Promise<void> {
|
||||
return new Promise<void>((done) => {
|
||||
const excludedDirs = [
|
||||
".git",
|
||||
|
@ -24,15 +26,16 @@ function detectInCode(forbidden: string, reason: string): Promise<void> {
|
|||
".idea/",
|
||||
]
|
||||
|
||||
exec(
|
||||
const command =
|
||||
'grep -n "' +
|
||||
forbidden +
|
||||
'" -r . ' +
|
||||
excludedDirs.map((d) => "--exclude-dir=" + d).join(" "),
|
||||
(error, stdout, stderr) => {
|
||||
excludedDirs.map((d) => "--exclude-dir=" + d).join(" ")
|
||||
console.log(command)
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if (error?.message?.startsWith("Command failed: grep")) {
|
||||
console.warn("Command failed!", error)
|
||||
return
|
||||
throw error
|
||||
}
|
||||
if (error !== null) {
|
||||
throw error
|
||||
|
@ -46,15 +49,12 @@ function detectInCode(forbidden: string, reason: string): Promise<void> {
|
|||
.filter((s) => s !== "")
|
||||
.filter((s) => !s.startsWith("./test/"))
|
||||
if (found.length > 0) {
|
||||
const msg = `Found a '${forbidden}' at \n ${found.join(
|
||||
"\n "
|
||||
)}.\n ${reason}`
|
||||
const msg = `Found a '${forbidden}' at \n ${found.join("\n ")}.\n ${reason}`
|
||||
console.error(msg)
|
||||
console.error(found.length, "issues found")
|
||||
throw msg
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -64,10 +64,6 @@ function wrap(promise: Promise<void>): (done: () => void) => void {
|
|||
}
|
||||
}
|
||||
|
||||
function itAsync(name: string, promise: Promise<void>) {
|
||||
it(name, wrap(promise))
|
||||
}
|
||||
|
||||
function validateScriptIntegrityOf(path: string) {
|
||||
const htmlContents = readFileSync(path, "utf8")
|
||||
const doc = parse_html(htmlContents)
|
||||
|
@ -95,7 +91,7 @@ function validateScriptIntegrityOf(path: string) {
|
|||
}
|
||||
|
||||
describe("Code quality", () => {
|
||||
itAsync(
|
||||
it(
|
||||
"should not contain reverse",
|
||||
detectInCode(
|
||||
"reverse()",
|
||||
|
@ -103,12 +99,12 @@ describe("Code quality", () => {
|
|||
)
|
||||
)
|
||||
|
||||
itAsync(
|
||||
it(
|
||||
"should not contain 'constructor.name'",
|
||||
detectInCode("constructor\\.name", "This is not allowed, as minification does erase names.")
|
||||
)
|
||||
|
||||
itAsync(
|
||||
it(
|
||||
"should not contain 'innerText'",
|
||||
detectInCode(
|
||||
"innerText",
|
||||
|
|
Loading…
Reference in a new issue