Update to the import viewers
This commit is contained in:
parent
fa179af601
commit
f09134c3be
26 changed files with 303 additions and 413 deletions
|
@ -289,12 +289,15 @@ export class OsmConnection {
|
|||
},
|
||||
content: JSON.stringify(content)
|
||||
|
||||
}, function (err, response) {
|
||||
}, function (
|
||||
err,
|
||||
response: string) {
|
||||
console.log("RESPONSE IS", response)
|
||||
if (err !== null) {
|
||||
error(err)
|
||||
} else {
|
||||
|
||||
const id = response.properties.id
|
||||
const parsed = JSON.parse(response)
|
||||
const id = parsed.properties.id
|
||||
console.log("OPENED NOTE", id)
|
||||
ok({id})
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import LayerConfig from "../LayerConfig";
|
|||
import {LayerConfigJson} from "../Json/LayerConfigJson";
|
||||
import Translations from "../../../UI/i18n/Translations";
|
||||
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson";
|
||||
import {Translation} from "../../../UI/i18n/Translation";
|
||||
|
||||
export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, LayerConfigJson> {
|
||||
/**
|
||||
|
@ -46,6 +47,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
|||
const firstRender = <PointRenderingConfigJson>(pointRenderings [0])
|
||||
const icon = firstRender.icon
|
||||
const iconBadges = []
|
||||
const title = layer.presets[0].title
|
||||
if(icon !== undefined){
|
||||
iconBadges.push({
|
||||
if: {and:[]},
|
||||
|
@ -61,6 +63,14 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
|||
}
|
||||
}
|
||||
|
||||
function embed(prefix, translation: Translation, postfix){
|
||||
const result = {}
|
||||
for (const language in translation.translations) {
|
||||
result[language] = prefix+translation.translations[language] + postfix
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const result : LayerConfigJson = {
|
||||
"id": "note_import_"+layer.id,
|
||||
// By disabling the name, the import-layers won't pollute the filter view "name": t.layerName.Subs({title: layer.title.render}).translations,
|
||||
|
@ -77,13 +87,13 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
|||
},
|
||||
"minzoom": 12,
|
||||
"title": {
|
||||
"render": t.popupTitle.Subs({title: layer.presets[0].title}).translations
|
||||
"render": t.popupTitle.Subs({title}).translations
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_first_comment=feat.get('comments')[0].text.toLowerCase()",
|
||||
"_trigger_index=(() => {const lines = feat.properties['_first_comment'].split('\\n'); const matchesMapCompleteURL = lines.map(l => l.match(\".*https://mapcomplete.osm.be/\\([a-zA-Z_-]+\\)\\(.html\\).*#import\")); const matchedIndexes = matchesMapCompleteURL.map((doesMatch, i) => [doesMatch !== null, i]).filter(v => v[0]).map(v => v[1]); return matchedIndexes[0] })()",
|
||||
"_comments_count=feat.get('comments').length",
|
||||
"_intro=(() => {const lines = feat.properties['_first_comment'].split('\\n'); lines.splice(feat.get('_trigger_index')-1, lines.length); return lines.filter(l => l !== '').join('<br/>');})()",
|
||||
"_intro=(() => {const lines = feat.get('comments')[0].text.split('\\n'); lines.splice(feat.get('_trigger_index')-1, lines.length); return lines.filter(l => l !== '').join('<br/>');})()",
|
||||
"_tags=(() => {let lines = feat.properties['_first_comment'].split('\\n').map(l => l.trim()); lines.splice(0, feat.get('_trigger_index') + 1); lines = lines.filter(l => l != ''); return lines.join(';');})()"
|
||||
],
|
||||
"isShown": {
|
||||
|
@ -124,12 +134,13 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
|||
},
|
||||
{
|
||||
"id": "close_note_",
|
||||
"render": "{close_note(Does not exist<br/>, ./assets/svg/close.svg, id, This feature does not exist)}",
|
||||
"render": embed(
|
||||
"{close_note(", t.notFound.Subs({title}),", ./assets/svg/close.svg, id, This feature does not exist)}" ),
|
||||
condition: "closed_at="
|
||||
},
|
||||
{
|
||||
"id": "close_note_mapped",
|
||||
"render": "{close_note(Already mapped, ./assets/svg/checkmark.svg, id, Already mapped)}",
|
||||
"render": embed("{close_note(",t.alreadyMapped.Subs({title}), ", ./assets/svg/checkmark.svg, id, Already mapped)}"),
|
||||
condition: "closed_at="
|
||||
},
|
||||
{
|
||||
|
@ -144,10 +155,6 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
|||
{
|
||||
"id": "add_image",
|
||||
"render": "{add_image_to_note()}"
|
||||
},
|
||||
{
|
||||
id:"alltags",
|
||||
render:"{all_tags()}"
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
|
|
|
@ -10,6 +10,9 @@ import IndexText from "./BigComponents/IndexText";
|
|||
import FeaturedMessage from "./BigComponents/FeaturedMessage";
|
||||
import Toggle from "./Input/Toggle";
|
||||
import {SubtleButton} from "./Base/SubtleButton";
|
||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
import Title from "./Base/Title";
|
||||
import Svg from "../Svg";
|
||||
|
||||
export default class AllThemesGui {
|
||||
constructor() {
|
||||
|
@ -26,12 +29,21 @@ export default class AllThemesGui {
|
|||
]);
|
||||
new Combine([
|
||||
intro,
|
||||
new FeaturedMessage(),
|
||||
new FeaturedMessage().SetClass("mb-4 block"),
|
||||
new MoreScreen(state, true),
|
||||
new Toggle(
|
||||
undefined,
|
||||
new SubtleButton(undefined, Translations.t.index.logIn).SetStyle("height:min-content").onClick(() => state.osmConnection.AttemptLogin()),
|
||||
state.osmConnection.isLoggedIn),
|
||||
new VariableUiElement(state.osmConnection.userDetails.map(ud => {
|
||||
if(ud.csCount < Constants.userJourney.importHelperUnlock){
|
||||
return undefined;
|
||||
}
|
||||
return new Combine([
|
||||
new SubtleButton( undefined, Translations.t.importHelper.title, {url: "import_helper.html"}),
|
||||
new SubtleButton( Svg.note_svg(), Translations.t.importInspector.title, {url: "import_viewer.html"})
|
||||
]).SetClass("p-4 border-2 border-gray-500 m-4 block")
|
||||
})),
|
||||
Translations.t.general.aboutMapcomplete
|
||||
.Subs({"osmcha_link": Utils.OsmChaLinkFor(7)})
|
||||
.SetClass("link-underline"),
|
||||
|
|
|
@ -8,7 +8,9 @@ export default class Loading extends Combine {
|
|||
const t = Translations.W(msg) ?? Translations.t.general.loading;
|
||||
t.SetClass("pl-2")
|
||||
super([
|
||||
Svg.loading_svg().SetClass("animate-spin").SetStyle("width: 1.5rem; height: 1.5rem;"),
|
||||
Svg.loading_svg()
|
||||
.SetClass("animate-spin self-center")
|
||||
.SetStyle("width: 1.5rem; height: 1.5rem; min-width: 1.5rem;"),
|
||||
t
|
||||
])
|
||||
this.SetClass("flex p-1")
|
||||
|
|
|
@ -55,8 +55,8 @@ export default class MinimapImplementation extends BaseUIElement implements Mini
|
|||
this.leafletMap.addCallbackD(leaflet => {
|
||||
let bounds;
|
||||
if (typeof factor === "number") {
|
||||
bounds = leaflet.getBounds()
|
||||
leaflet.setMaxBounds(bounds.pad(factor))
|
||||
bounds = leaflet.getBounds().pad(factor)
|
||||
leaflet.setMaxBounds(bounds)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
leaflet.setMaxBounds(factor.toLeaflet())
|
||||
|
@ -99,9 +99,9 @@ export default class MinimapImplementation extends BaseUIElement implements Mini
|
|||
// @ts-ignore
|
||||
L.geoJSON(data, {
|
||||
style: {
|
||||
color: "#f00",
|
||||
weight: 2,
|
||||
opacity: 0.4
|
||||
color: "#f44",
|
||||
weight: 4,
|
||||
opacity: 0.7
|
||||
}
|
||||
}).addTo(leaflet)
|
||||
}
|
||||
|
|
|
@ -18,22 +18,26 @@ export default class TableOfContents extends Combine {
|
|||
}) {
|
||||
let titles: Title[]
|
||||
if (elements instanceof Combine) {
|
||||
titles = TableOfContents.getTitles(elements.getElements())
|
||||
titles = TableOfContents.getTitles(elements.getElements()) ?? []
|
||||
} else {
|
||||
titles = elements
|
||||
titles = elements ?? []
|
||||
}
|
||||
|
||||
|
||||
let els: { level: number, content: BaseUIElement }[] = []
|
||||
for (const title of titles) {
|
||||
let content: BaseUIElement
|
||||
console.log("Constructing content for ", title)
|
||||
if (title.title instanceof Translation) {
|
||||
content = title.title.Clone()
|
||||
} else if (title.title instanceof FixedUiElement) {
|
||||
content = title.title
|
||||
content = new FixedUiElement(title.title.content)
|
||||
} else if (Utils.runningFromConsole) {
|
||||
content = new FixedUiElement(title.AsMarkdown())
|
||||
} else {
|
||||
} else if(title["title"] !== undefined) {
|
||||
content = new FixedUiElement(title.title.ConstructElement().innerText)
|
||||
}else{
|
||||
console.log("Not generating a title for ", title)
|
||||
continue
|
||||
}
|
||||
|
||||
const vis = new Link(content, "#" + title.id)
|
||||
|
|
|
@ -25,17 +25,36 @@ export class Accordeon extends Combine {
|
|||
export default class Toggleable extends Combine {
|
||||
public readonly isVisible = new UIEventSource(false)
|
||||
|
||||
constructor(title: Title | BaseUIElement, content: BaseUIElement) {
|
||||
constructor(title: Title | Combine | BaseUIElement, content: BaseUIElement, options?: {
|
||||
closeOnClick: true | boolean
|
||||
}) {
|
||||
super([title, content])
|
||||
content.SetClass("animate-height border-l-4 pl-2 block")
|
||||
title.SetClass("background-subtle rounded-lg")
|
||||
const self = this
|
||||
this.onClick(() => self.isVisible.setData(!self.isVisible.data))
|
||||
this.onClick(() => {
|
||||
if(self.isVisible.data){
|
||||
if(options?.closeOnClick ?? true){
|
||||
self.isVisible.setData(false)
|
||||
}
|
||||
}else{
|
||||
self.isVisible.setData(true)
|
||||
}
|
||||
})
|
||||
const contentElement = content.ConstructElement()
|
||||
|
||||
if(title instanceof Combine){
|
||||
for(const el of title.getElements()){
|
||||
if(el instanceof Title){
|
||||
title = el;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (title instanceof Title) {
|
||||
Hash.hash.addCallbackAndRun(h => {
|
||||
if (h === title.id) {
|
||||
if (h === (<Title> title).id) {
|
||||
self.isVisible.setData(true)
|
||||
content.RemoveClass("border-gray-300")
|
||||
content.SetClass("border-red-300")
|
||||
|
@ -46,14 +65,14 @@ export default class Toggleable extends Combine {
|
|||
})
|
||||
this.isVisible.addCallbackAndRun(isVis => {
|
||||
if (isVis) {
|
||||
Hash.hash.setData(title.id)
|
||||
Hash.hash.setData((<Title>title).id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.isVisible.addCallbackAndRun(isVisible => {
|
||||
if (isVisible) {
|
||||
contentElement.style.maxHeight = "50vh"
|
||||
contentElement.style.maxHeight = "100vh"
|
||||
contentElement.style.overflowY = "auto"
|
||||
contentElement.style["-webkit-mask-image"] = "unset"
|
||||
} else {
|
||||
|
|
|
@ -23,6 +23,7 @@ import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline";
|
|||
import {ElementStorage} from "../../Logic/ElementStorage";
|
||||
import ConfirmLocationOfPoint from "../NewPoint/ConfirmLocationOfPoint";
|
||||
import BaseLayer from "../../Models/BaseLayer";
|
||||
import Loading from "../Base/Loading";
|
||||
|
||||
/*
|
||||
* The SimpleAddUI is a single panel, which can have multiple states:
|
||||
|
@ -35,7 +36,8 @@ import BaseLayer from "../../Models/BaseLayer";
|
|||
export interface PresetInfo extends PresetConfig {
|
||||
name: string | BaseUIElement,
|
||||
icon: () => BaseUIElement,
|
||||
layerToAddTo: FilteredLayer
|
||||
layerToAddTo: FilteredLayer,
|
||||
boundsFactor?: 0.25 | number
|
||||
}
|
||||
|
||||
export default class SimpleAddUI extends Toggle {
|
||||
|
@ -124,7 +126,7 @@ export default class SimpleAddUI extends Toggle {
|
|||
new Toggle(
|
||||
new Toggle(
|
||||
new Toggle(
|
||||
Translations.t.general.add.stillLoading.Clone().SetClass("alert"),
|
||||
new Loading(Translations.t.general.add.stillLoading).SetClass("alert"),
|
||||
addUi,
|
||||
state.featurePipeline.runningQuery
|
||||
),
|
||||
|
|
|
@ -2,7 +2,6 @@ import Combine from "../Base/Combine";
|
|||
import UserRelatedState from "../../Logic/State/UserRelatedState";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import {Utils} from "../../Utils";
|
||||
import UserDetails from "../../Logic/Osm/OsmConnection";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import Title from "../Base/Title";
|
||||
import Translations from "../i18n/Translations";
|
||||
|
@ -21,6 +20,7 @@ import Toggleable, {Accordeon} from "../Base/Toggleable";
|
|||
import TableOfContents from "../Base/TableOfContents";
|
||||
import LoginButton from "../Popup/LoginButton";
|
||||
import BackToIndex from "../BigComponents/BackToIndex";
|
||||
import {QueryParameters} from "../../Logic/Web/QueryParameters";
|
||||
|
||||
interface NoteProperties {
|
||||
"id": number,
|
||||
|
@ -32,7 +32,8 @@ interface NoteProperties {
|
|||
date: string,
|
||||
uid: number,
|
||||
user: string,
|
||||
text: string
|
||||
text: string,
|
||||
html: string
|
||||
}[]
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,7 @@ interface NoteState {
|
|||
theme: string,
|
||||
intro: string,
|
||||
dateStr: string,
|
||||
status: "imported" | "already_mapped" | "invalid" | "closed" | "not_found" | "open"
|
||||
status: "imported" | "already_mapped" | "invalid" | "closed" | "not_found" | "open" | "has_comments"
|
||||
}
|
||||
|
||||
class MassAction extends Combine {
|
||||
|
@ -127,16 +128,50 @@ class MassAction extends Combine {
|
|||
|
||||
|
||||
class BatchView extends Toggleable {
|
||||
constructor(state: UserRelatedState, noteStates: NoteState[]) {
|
||||
|
||||
private static icons = {
|
||||
open: Svg.compass_svg,
|
||||
has_comments: Svg.speech_bubble_svg,
|
||||
imported: Svg.addSmall_svg,
|
||||
already_mapped: Svg.checkmark_svg,
|
||||
invalid: Svg.invalid_svg,
|
||||
closed: Svg.close_svg,
|
||||
not_found: Svg.not_found_svg,
|
||||
}
|
||||
|
||||
constructor(noteStates: NoteState[], state?: UserRelatedState) {
|
||||
|
||||
noteStates.sort((a, b) => a.props.id - b.props.id)
|
||||
|
||||
const {theme, intro, dateStr} = noteStates[0]
|
||||
console.log("Creating a batchview for ", noteStates)
|
||||
|
||||
const statusHist = new Map<string, number>()
|
||||
for (const noteState of noteStates) {
|
||||
const st = noteState.status
|
||||
const c = statusHist.get(st) ?? 0
|
||||
statusHist.set(st, c + 1)
|
||||
}
|
||||
|
||||
const badges: (BaseUIElement)[] = [new FixedUiElement(dateStr).SetClass("literal-code rounded-full")]
|
||||
statusHist.forEach((count, status) => {
|
||||
const icon = BatchView.icons[status]().SetClass("h-6 m-1")
|
||||
badges.push(new Combine([icon, count + " " + status])
|
||||
.SetClass("flex ml-1 mb-1 pl-1 pr-3 items-center rounded-full border border-black"))
|
||||
})
|
||||
|
||||
const typicalComment = noteStates[0].props.comments[0].html
|
||||
|
||||
|
||||
super(
|
||||
new Title(theme + ": " + intro, 2),
|
||||
new Combine([
|
||||
new FixedUiElement(dateStr),
|
||||
new FixedUiElement("Click to expand/collapse table"),
|
||||
|
||||
|
||||
new Title(theme + ": " + intro, 2),
|
||||
new Combine(badges).SetClass("flex flex-wrap"),
|
||||
]),
|
||||
new Combine([
|
||||
new Title("Example note", 4),
|
||||
new FixedUiElement(typicalComment).SetClass("literal-code link-underline"),
|
||||
new Title("Mass apply an action"),
|
||||
state !== undefined ? new MassAction(state, noteStates.map(ns => ns.props)).SetClass("block") : undefined,
|
||||
new Table(
|
||||
["id", "status", "last comment"],
|
||||
noteStates.map(ns => {
|
||||
|
@ -144,30 +179,39 @@ class BatchView extends Toggleable {
|
|||
"" + ns.props.id,
|
||||
"https://openstreetmap.org/note/" + ns.props.id, true
|
||||
)
|
||||
const last_comment = ns.props.comments[ns.props.comments.length - 1].text
|
||||
return [link, ns.status, last_comment]
|
||||
let last_comment = "";
|
||||
if (ns.props.comments.length > 1) {
|
||||
last_comment = ns.props.comments[ns.props.comments.length - 1].text
|
||||
}
|
||||
const statusIcon = BatchView.icons[ns.status]().SetClass("h-4 w-4 shrink-0")
|
||||
return [link, new Combine([statusIcon, ns.status]).SetClass("flex"), last_comment]
|
||||
})
|
||||
).SetClass("zebra-table link-underline"),
|
||||
).SetClass("zebra-table link-underline")
|
||||
]).SetClass("flex flex-col"),
|
||||
{
|
||||
closeOnClick: false
|
||||
})
|
||||
|
||||
|
||||
new Title("Mass apply an action"),
|
||||
new MassAction(state, noteStates.map(ns => ns.props)).SetClass("block")]).SetClass("flex flex-col"))
|
||||
}
|
||||
}
|
||||
|
||||
class ImportInspector extends VariableUiElement {
|
||||
|
||||
constructor(userDetails: UserDetails, state: UserRelatedState) {
|
||||
const t = Translations.t.importInspector;
|
||||
constructor(userDetails: { uid: number } | { display_name: string, search?: string }, state: UserRelatedState) {
|
||||
let url;
|
||||
if (userDetails["uid"] !== undefined) {
|
||||
url = "https://api.openstreetmap.org/api/0.6/notes/search.json?user=" + userDetails["uid"] + "&limit=10000&sort=created_at&q=%23import"
|
||||
} else {
|
||||
url = "https://api.openstreetmap.org/api/0.6/notes/search.json?display_name=" +
|
||||
encodeURIComponent(userDetails["display_name"]) + "&limit=10000&sort=created_at&q=" + encodeURIComponent(userDetails["search"] ?? "#import")
|
||||
}
|
||||
|
||||
|
||||
const url = "https://api.openstreetmap.org/api/0.6/notes/search.json?user=" + userDetails.uid + "&limit=10000&sort=created_at&q=%23import"
|
||||
const notes: UIEventSource<{ error: string } | { success: { features: { properties: NoteProperties }[] } }> = UIEventSource.FromPromiseWithErr(Utils.downloadJson(url))
|
||||
notes.addCallbackAndRun(n => console.log("Notes are:", n))
|
||||
super(notes.map(notes => {
|
||||
|
||||
if (notes === undefined) {
|
||||
return new Loading("Loading your notes which mention '#import'")
|
||||
return new Loading("Loading notes which mention '#import'")
|
||||
}
|
||||
if (notes["error"] !== undefined) {
|
||||
return new FixedUiElement("Something went wrong: " + notes["error"]).SetClass("alert")
|
||||
|
@ -175,13 +219,18 @@ class ImportInspector extends VariableUiElement {
|
|||
// We only care about the properties here
|
||||
const props: NoteProperties[] = notes["success"].features.map(f => f.properties)
|
||||
const perBatch: NoteState[][] = Array.from(ImportInspector.SplitNotesIntoBatches(props).values());
|
||||
const els: Toggleable[] = perBatch.map(noteStates => new BatchView(state, noteStates))
|
||||
const els: Toggleable[] = perBatch.map(noteStates => new BatchView(noteStates, state))
|
||||
|
||||
const accordeon = new Accordeon(els)
|
||||
const content = new Combine([
|
||||
new Title(Translations.t.importInspector.title, 1),
|
||||
new SubtleButton(undefined, "Create a new batch of imports",{url:'import_helper.html'}),
|
||||
accordeon])
|
||||
let contents = [];
|
||||
if (state?.osmConnection?.isLoggedIn?.data) {
|
||||
contents =
|
||||
[
|
||||
new Title(Translations.t.importInspector.title, 1),
|
||||
new SubtleButton(undefined, "Create a new batch of imports", {url: 'import_helper.html'})]
|
||||
}
|
||||
contents.push(accordeon)
|
||||
const content = new Combine(contents)
|
||||
return new LeftIndex(
|
||||
[new TableOfContents(content, {noTopLevel: true, maxDepth: 1}).SetClass("subtle")],
|
||||
content
|
||||
|
@ -205,12 +254,12 @@ class ImportInspector extends VariableUiElement {
|
|||
let theme = lines[trigger].substr(prefix.length)
|
||||
theme = theme.substr(0, theme.indexOf("."))
|
||||
const date = Utils.ParseDate(prop.date_created)
|
||||
const dateStr = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate()
|
||||
const dateStr = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate()
|
||||
const key = theme + lines[0] + dateStr
|
||||
if (!perBatch.has(key)) {
|
||||
perBatch.set(key, [])
|
||||
}
|
||||
let status: "open" | "closed" | "imported" | "invalid" | "already_mapped" | "not_found" = "open"
|
||||
let status: "open" | "closed" | "imported" | "invalid" | "already_mapped" | "not_found" | "has_comments" = "open"
|
||||
if (prop.closed_at !== undefined) {
|
||||
const lastComment = prop.comments[prop.comments.length - 1].text.toLowerCase()
|
||||
if (lastComment.indexOf("does not exist") >= 0) {
|
||||
|
@ -224,6 +273,8 @@ class ImportInspector extends VariableUiElement {
|
|||
} else {
|
||||
status = "closed"
|
||||
}
|
||||
} else if (prop.comments.length > 1) {
|
||||
status = "has_comments"
|
||||
}
|
||||
|
||||
perBatch.get(key).push({
|
||||
|
@ -242,15 +293,23 @@ class ImportViewerGui extends Combine {
|
|||
|
||||
constructor() {
|
||||
const state = new UserRelatedState(undefined)
|
||||
const displayNameParam = QueryParameters.GetQueryParameter("user", "", "The username of the person whom you want to see the notes for");
|
||||
const searchParam = QueryParameters.GetQueryParameter("search", "", "A text that should be included in the first comment of the note to be shown")
|
||||
super([
|
||||
new VariableUiElement(state.osmConnection.userDetails.map(ud => {
|
||||
const display_name = displayNameParam.data;
|
||||
const search = searchParam.data;
|
||||
if (display_name !== "" && search !== "") {
|
||||
return new ImportInspector({display_name, search}, state);
|
||||
}
|
||||
|
||||
if (ud === undefined || ud.loggedIn === false) {
|
||||
return new Combine([new LoginButton("Login to inspect your import flows", state),
|
||||
new BackToIndex()
|
||||
new BackToIndex()
|
||||
])
|
||||
}
|
||||
return new ImportInspector(ud, state);
|
||||
}))
|
||||
}, [displayNameParam, searchParam]))
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ export default class ConfirmLocationOfPoint extends Combine {
|
|||
maxSnapDistance: preset.preciseInput.maxSnapDistance,
|
||||
bounds: mapBounds
|
||||
})
|
||||
preciseInput.installBounds(0.15, true)
|
||||
preciseInput.installBounds(preset.boundsFactor ?? 0.25, true)
|
||||
preciseInput.SetClass("h-32 rounded-xl overflow-hidden border border-gray").SetStyle("height: 12rem;")
|
||||
|
||||
|
||||
|
@ -78,7 +78,7 @@ export default class ConfirmLocationOfPoint extends Combine {
|
|||
// return;
|
||||
}
|
||||
|
||||
bbox = bbox.pad(2);
|
||||
bbox = bbox.pad(Math.max(preset.boundsFactor , 2), Math.max(preset.boundsFactor , 2));
|
||||
loadedBbox = bbox;
|
||||
const allFeatures: { feature: any }[] = []
|
||||
preset.preciseInput.snapToLayers.forEach(layerId => {
|
||||
|
|
|
@ -40,7 +40,7 @@ import {LoginToggle} from "./LoginButton";
|
|||
|
||||
/**
|
||||
* A helper class for the various import-flows.
|
||||
* An import-flow always starts with a 'Import this'-button. Upon click, a custom confirmation panel is provided
|
||||
* An import-flow always starts with a 'Import this'-button. Upon click, a custom confirmation panel is provided
|
||||
*/
|
||||
abstract class AbstractImportButton implements SpecialVisualizations {
|
||||
public readonly funcName: string
|
||||
|
@ -136,12 +136,12 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
|
||||
|
||||
// Explanation of the tags that will be applied onto the imported/conflated object
|
||||
|
||||
|
||||
let tagSpec = args.tags;
|
||||
if(tagSpec.indexOf(" ")< 0 && tagSpec.indexOf(";") < 0 && tagSource.data[args.tags] !== undefined){
|
||||
if (tagSpec.indexOf(" ") < 0 && tagSpec.indexOf(";") < 0 && tagSource.data[args.tags] !== undefined) {
|
||||
// This is probably a key
|
||||
tagSpec = tagSource.data[args.tags]
|
||||
console.debug("The import button is using tags from properties["+args.tags+"] of this object, namely ",tagSpec)
|
||||
console.debug("The import button is using tags from properties[" + args.tags + "] of this object, namely ", tagSpec)
|
||||
}
|
||||
|
||||
const importClicked = new UIEventSource(false);
|
||||
|
@ -193,23 +193,6 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
|
||||
}
|
||||
|
||||
private parseArgs(argsRaw: string[], originalFeatureTags: UIEventSource<any>): { minzoom: string, max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, tags: string, targetLayer: string, newTags: UIEventSource<Tag[]> } {
|
||||
const baseArgs = Utils.ParseVisArgs(this.args, argsRaw)
|
||||
if (originalFeatureTags !== undefined) {
|
||||
|
||||
const tags = baseArgs.tags
|
||||
if(tags.indexOf(" ") < 0 && tags.indexOf(";") < 0 && originalFeatureTags.data[tags] !== undefined){
|
||||
// This might be a property to expand...
|
||||
const items : string = originalFeatureTags.data[tags]
|
||||
console.debug("The import button is using tags from properties["+tags+"] of this object, namely ",items)
|
||||
baseArgs["newTags"] = TagApplyButton.generateTagsToApply(items, originalFeatureTags)
|
||||
}else{
|
||||
baseArgs["newTags"] = TagApplyButton.generateTagsToApply(tags, originalFeatureTags)
|
||||
}
|
||||
}
|
||||
return baseArgs
|
||||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]) {
|
||||
const args = this.parseArgs(argsRaw, undefined)
|
||||
|
||||
|
@ -226,7 +209,6 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
return dependsOnLayers
|
||||
}
|
||||
|
||||
|
||||
protected abstract canBeImported(feature: any)
|
||||
|
||||
protected createConfirmPanelForWay(
|
||||
|
@ -286,6 +268,23 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
const cancel = new SubtleButton(Svg.close_ui(), Translations.t.general.cancel).onClick(onCancel)
|
||||
return new Combine([confirmationMap, confirmButton, cancel]).SetClass("flex flex-col")
|
||||
}
|
||||
|
||||
private parseArgs(argsRaw: string[], originalFeatureTags: UIEventSource<any>): { minzoom: string, max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, tags: string, targetLayer: string, newTags: UIEventSource<Tag[]> } {
|
||||
const baseArgs = Utils.ParseVisArgs(this.args, argsRaw)
|
||||
if (originalFeatureTags !== undefined) {
|
||||
|
||||
const tags = baseArgs.tags
|
||||
if (tags.indexOf(" ") < 0 && tags.indexOf(";") < 0 && originalFeatureTags.data[tags] !== undefined) {
|
||||
// This might be a property to expand...
|
||||
const items: string = originalFeatureTags.data[tags]
|
||||
console.debug("The import button is using tags from properties[" + tags + "] of this object, namely ", items)
|
||||
baseArgs["newTags"] = TagApplyButton.generateTagsToApply(items, originalFeatureTags)
|
||||
} else {
|
||||
baseArgs["newTags"] = TagApplyButton.generateTagsToApply(tags, originalFeatureTags)
|
||||
}
|
||||
}
|
||||
return baseArgs
|
||||
}
|
||||
}
|
||||
|
||||
export class ConflateButton extends AbstractImportButton {
|
||||
|
@ -299,10 +298,6 @@ export class ConflateButton extends AbstractImportButton {
|
|||
);
|
||||
}
|
||||
|
||||
protected canBeImported(feature: any) {
|
||||
return feature.geometry.type === "LineString" || (feature.geometry.type === "Polygon" && feature.geometry.coordinates.length === 1)
|
||||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]): string[] {
|
||||
const deps = super.getLayerDependencies(argsRaw);
|
||||
// Force 'type_node' as dependency
|
||||
|
@ -350,6 +345,10 @@ export class ConflateButton extends AbstractImportButton {
|
|||
)
|
||||
}
|
||||
|
||||
protected canBeImported(feature: any) {
|
||||
return feature.geometry.type === "LineString" || (feature.geometry.type === "Polygon" && feature.geometry.coordinates.length === 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ImportWayButton extends AbstractImportButton {
|
||||
|
@ -498,29 +497,14 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
name: "max_snap_distance",
|
||||
doc: "The maximum distance that the imported point will be moved to snap onto a way in an already existing layer (in meters). This is previewed to the contributor, similar to the 'add new point'-action of MapComplete",
|
||||
defaultValue: "5"
|
||||
},{
|
||||
name:"note_id",
|
||||
doc:"If given, this key will be read. The corresponding note on OSM will be closed, stating 'imported'"
|
||||
}],
|
||||
}, {
|
||||
name: "note_id",
|
||||
doc: "If given, this key will be read. The corresponding note on OSM will be closed, stating 'imported'"
|
||||
}],
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
canBeImported(feature: any) {
|
||||
return feature.geometry.type === "Point"
|
||||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]): string[] {
|
||||
const deps = super.getLayerDependencies(argsRaw);
|
||||
const layerSnap = argsRaw["snap_onto_layers"] ?? ""
|
||||
if (layerSnap === "") {
|
||||
return deps
|
||||
}
|
||||
|
||||
deps.push(...layerSnap.split(";"))
|
||||
return deps
|
||||
}
|
||||
|
||||
private static createConfirmPanelForPoint(
|
||||
args: { max_snap_distance: string, snap_onto_layers: string, icon: string, text: string, newTags: UIEventSource<any>, targetLayer: string, note_id: string },
|
||||
state: FeaturePipelineState,
|
||||
|
@ -539,8 +523,8 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
snapOnto = await OsmObject.DownloadObjectAsync(snapOntoWayId)
|
||||
}
|
||||
let specialMotivation = undefined
|
||||
if(args.note_id !== undefined){
|
||||
specialMotivation = "source: https://osm.org/note/"+args.note_id
|
||||
if (args.note_id !== undefined) {
|
||||
specialMotivation = "source: https://osm.org/note/" + args.note_id
|
||||
}
|
||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
||||
theme: state.layoutToUse.id,
|
||||
|
@ -553,8 +537,13 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
state.selectedElement.setData(state.allElements.ContainingFeatures.get(
|
||||
newElementAction.newElementId
|
||||
))
|
||||
if(args.note_id !== undefined){
|
||||
state.osmConnection.closeNote(args.note_id, "imported")
|
||||
if (args.note_id !== undefined) {
|
||||
let note_id = args.note_id
|
||||
if (isNaN(Number(args.note_id))) {
|
||||
note_id = originalFeatureTags.data[args.note_id]
|
||||
}
|
||||
|
||||
state.osmConnection.closeNote(note_id, "imported")
|
||||
originalFeatureTags.data["closed_at"] = new Date().toISOString()
|
||||
originalFeatureTags.ping()
|
||||
}
|
||||
|
@ -569,7 +558,8 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
preciseInput: {
|
||||
snapToLayers: args.snap_onto_layers?.split(";"),
|
||||
maxSnapDistance: Number(args.max_snap_distance)
|
||||
}
|
||||
},
|
||||
boundsFactor: 3
|
||||
}
|
||||
|
||||
const [lon, lat] = feature.geometry.coordinates
|
||||
|
@ -580,6 +570,21 @@ export class ImportPointButton extends AbstractImportButton {
|
|||
|
||||
}
|
||||
|
||||
canBeImported(feature: any) {
|
||||
return feature.geometry.type === "Point"
|
||||
}
|
||||
|
||||
getLayerDependencies(argsRaw: string[]): string[] {
|
||||
const deps = super.getLayerDependencies(argsRaw);
|
||||
const layerSnap = argsRaw["snap_onto_layers"] ?? ""
|
||||
if (layerSnap === "") {
|
||||
return deps
|
||||
}
|
||||
|
||||
deps.push(...layerSnap.split(";"))
|
||||
return deps
|
||||
}
|
||||
|
||||
constructElement(state, args,
|
||||
originalFeatureTags,
|
||||
guiState,
|
||||
|
|
|
@ -1,73 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="375px" height="375px" viewBox="0 0 375 375" version="1.1">
|
||||
<defs>
|
||||
<g>
|
||||
<symbol overflow="visible" id="glyph0-0">
|
||||
<path style="stroke:none;" d="M 9.515625 0 L 9.515625 -72.296875 L 51.140625 -72.296875 L 51.140625 0 Z M 14.6875 -5.171875 L 45.96875 -5.171875 L 45.96875 -67.140625 L 14.6875 -67.140625 Z M 14.6875 -5.171875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M 67.140625 0 L 56.5 0 L 17.828125 -60.046875 L 17.421875 -60.046875 C 17.554688 -57.679688 17.722656 -54.742188 17.921875 -51.234375 C 18.128906 -47.722656 18.234375 -44.113281 18.234375 -40.40625 L 18.234375 0 L 9.828125 0 L 9.828125 -72.296875 L 20.359375 -72.296875 L 58.9375 -12.453125 L 59.34375 -12.453125 C 59.269531 -13.535156 59.179688 -15.15625 59.078125 -17.3125 C 58.984375 -19.476562 58.882812 -21.84375 58.78125 -24.40625 C 58.6875 -26.96875 58.640625 -29.332031 58.640625 -31.5 L 58.640625 -72.296875 L 67.140625 -72.296875 Z M 67.140625 0 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-0">
|
||||
<path style="stroke:none;" d="M 9.296875 0 L 9.296875 -70.625 L 49.953125 -70.625 L 49.953125 0 Z M 14.34375 -5.046875 L 44.90625 -5.046875 L 44.90625 -65.578125 L 14.34375 -65.578125 Z M 14.34375 -5.046875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-1">
|
||||
<path style="stroke:none;" d="M 49.65625 -18.890625 C 49.65625 -12.628906 47.378906 -7.75 42.828125 -4.25 C 38.273438 -0.757812 32.144531 0.984375 24.4375 0.984375 C 20.476562 0.984375 16.816406 0.6875 13.453125 0.09375 C 10.085938 -0.5 7.285156 -1.320312 5.046875 -2.375 L 5.046875 -10.875 C 7.421875 -9.820312 10.367188 -8.867188 13.890625 -8.015625 C 17.421875 -7.160156 21.066406 -6.734375 24.828125 -6.734375 C 30.109375 -6.734375 34.082031 -7.753906 36.75 -9.796875 C 39.414062 -11.835938 40.75 -14.609375 40.75 -18.109375 C 40.75 -20.410156 40.253906 -22.351562 39.265625 -23.9375 C 38.273438 -25.519531 36.578125 -26.988281 34.171875 -28.34375 C 31.765625 -29.695312 28.421875 -31.128906 24.140625 -32.640625 C 18.140625 -34.816406 13.601562 -37.488281 10.53125 -40.65625 C 7.46875 -43.820312 5.9375 -48.140625 5.9375 -53.609375 C 5.9375 -57.367188 6.890625 -60.582031 8.796875 -63.25 C 10.710938 -65.925781 13.367188 -67.988281 16.765625 -69.4375 C 20.160156 -70.894531 24.066406 -71.625 28.484375 -71.625 C 32.378906 -71.625 35.941406 -71.257812 39.171875 -70.53125 C 42.398438 -69.800781 45.335938 -68.84375 47.984375 -67.65625 L 45.203125 -60.046875 C 42.765625 -61.097656 40.109375 -61.984375 37.234375 -62.703125 C 34.367188 -63.429688 31.390625 -63.796875 28.296875 -63.796875 C 23.867188 -63.796875 20.535156 -62.859375 18.296875 -60.984375 C 16.054688 -59.109375 14.9375 -56.617188 14.9375 -53.515625 C 14.9375 -51.140625 15.429688 -49.160156 16.421875 -47.578125 C 17.410156 -45.992188 19.023438 -44.578125 21.265625 -43.328125 C 23.503906 -42.078125 26.539062 -40.722656 30.375 -39.265625 C 34.519531 -37.753906 38.023438 -36.125 40.890625 -34.375 C 43.765625 -32.625 45.941406 -30.53125 47.421875 -28.09375 C 48.910156 -25.65625 49.65625 -22.585938 49.65625 -18.890625 Z M 49.65625 -18.890625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-2">
|
||||
<path style="stroke:none;" d="M 49.0625 0 L 9.59375 0 L 9.59375 -70.625 L 49.0625 -70.625 L 49.0625 -62.8125 L 18.5 -62.8125 L 18.5 -40.75 L 47.28125 -40.75 L 47.28125 -33.046875 L 18.5 -33.046875 L 18.5 -7.8125 L 49.0625 -7.8125 Z M 49.0625 0 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-0">
|
||||
<path style="stroke:none;" d="M 7.484375 0 L 7.484375 -70.625 L 40.1875 -70.625 L 40.1875 0 Z M 11.546875 -5.046875 L 36.140625 -5.046875 L 36.140625 -65.578125 L 11.546875 -65.578125 Z M 11.546875 -5.046875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-1">
|
||||
<path style="stroke:none;" d="M 72.984375 -70.625 L 57.859375 0 L 50.625 0 L 39.5625 -46.296875 C 39.132812 -48.210938 38.707031 -50.125 38.28125 -52.03125 C 37.851562 -53.945312 37.507812 -55.644531 37.25 -57.125 C 36.988281 -58.613281 36.800781 -59.65625 36.6875 -60.25 C 36.632812 -59.382812 36.351562 -57.550781 35.84375 -54.75 C 35.34375 -51.945312 34.722656 -49.03125 33.984375 -46 L 23.234375 0 L 16 0 L 0.953125 -70.625 L 8.4375 -70.625 L 17.265625 -27.5 C 17.910156 -24.46875 18.457031 -21.53125 18.90625 -18.6875 C 19.351562 -15.851562 19.710938 -13.1875 19.984375 -10.6875 C 20.242188 -13.257812 20.640625 -16.0625 21.171875 -19.09375 C 21.703125 -22.125 22.3125 -25.09375 23 -28 L 33.03125 -70.625 L 40.4375 -70.625 L 50.859375 -27.703125 C 51.597656 -24.660156 52.234375 -21.640625 52.765625 -18.640625 C 53.296875 -15.640625 53.695312 -12.988281 53.96875 -10.6875 C 54.226562 -13.125 54.597656 -15.773438 55.078125 -18.640625 C 55.554688 -21.515625 56.113281 -24.5 56.75 -27.59375 L 65.5 -70.625 Z M 72.984375 -70.625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-0">
|
||||
<path style="stroke:none;" d="M 2.9375 0 L 2.9375 -27.765625 L 15.8125 -27.765625 L 15.8125 0 Z M 4.53125 -1.984375 L 14.203125 -1.984375 L 14.203125 -25.78125 L 4.53125 -25.78125 Z M 4.53125 -1.984375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-1">
|
||||
<path style="stroke:none;" d="M 20.75 0 L 17.46875 0 L 5.515625 -23.0625 L 5.390625 -23.0625 C 5.429688 -22.15625 5.484375 -21.023438 5.546875 -19.671875 C 5.609375 -18.328125 5.640625 -16.941406 5.640625 -15.515625 L 5.640625 0 L 3.03125 0 L 3.03125 -27.765625 L 6.296875 -27.765625 L 18.21875 -4.78125 L 18.34375 -4.78125 C 18.320312 -5.195312 18.296875 -5.816406 18.265625 -6.640625 C 18.234375 -7.472656 18.203125 -8.378906 18.171875 -9.359375 C 18.140625 -10.347656 18.125 -11.257812 18.125 -12.09375 L 18.125 -27.765625 L 20.75 -27.765625 Z M 20.75 0 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-2">
|
||||
<path style="stroke:none;" d="M 28.703125 -27.765625 L 22.75 0 L 19.90625 0 L 15.546875 -18.203125 C 15.378906 -18.953125 15.210938 -19.703125 15.046875 -20.453125 C 14.878906 -21.203125 14.742188 -21.867188 14.640625 -22.453125 C 14.535156 -23.035156 14.460938 -23.445312 14.421875 -23.6875 C 14.398438 -23.34375 14.289062 -22.617188 14.09375 -21.515625 C 13.894531 -20.421875 13.648438 -19.273438 13.359375 -18.078125 L 9.140625 0 L 6.296875 0 L 0.375 -27.765625 L 3.3125 -27.765625 L 6.796875 -10.8125 C 7.046875 -9.613281 7.257812 -8.457031 7.4375 -7.34375 C 7.613281 -6.226562 7.753906 -5.179688 7.859375 -4.203125 C 7.960938 -5.210938 8.117188 -6.3125 8.328125 -7.5 C 8.535156 -8.695312 8.773438 -9.863281 9.046875 -11 L 12.984375 -27.765625 L 15.90625 -27.765625 L 20 -10.890625 C 20.289062 -9.691406 20.539062 -8.503906 20.75 -7.328125 C 20.957031 -6.148438 21.113281 -5.109375 21.21875 -4.203125 C 21.320312 -5.160156 21.46875 -6.203125 21.65625 -7.328125 C 21.84375 -8.453125 22.0625 -9.625 22.3125 -10.84375 L 25.75 -27.765625 Z M 28.703125 -27.765625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-3">
|
||||
<path style="stroke:none;" d="M 15.71875 -7.421875 C 15.71875 -4.960938 14.992188 -3.046875 13.546875 -1.671875 C 12.109375 -0.296875 10.171875 0.390625 7.734375 0.390625 C 6.484375 0.390625 5.320312 0.269531 4.25 0.03125 C 3.1875 -0.195312 2.300781 -0.519531 1.59375 -0.9375 L 1.59375 -4.28125 C 2.34375 -3.863281 3.273438 -3.484375 4.390625 -3.140625 C 5.515625 -2.804688 6.671875 -2.640625 7.859375 -2.640625 C 9.523438 -2.640625 10.78125 -3.039062 11.625 -3.84375 C 12.46875 -4.65625 12.890625 -5.742188 12.890625 -7.109375 C 12.890625 -8.023438 12.734375 -8.789062 12.421875 -9.40625 C 12.109375 -10.03125 11.570312 -10.609375 10.8125 -11.140625 C 10.050781 -11.671875 8.992188 -12.234375 7.640625 -12.828125 C 5.734375 -13.691406 4.296875 -14.742188 3.328125 -15.984375 C 2.359375 -17.222656 1.875 -18.921875 1.875 -21.078125 C 1.875 -22.554688 2.175781 -23.820312 2.78125 -24.875 C 3.382812 -25.925781 4.222656 -26.734375 5.296875 -27.296875 C 6.378906 -27.867188 7.617188 -28.15625 9.015625 -28.15625 C 10.242188 -28.15625 11.367188 -28.007812 12.390625 -27.71875 C 13.410156 -27.4375 14.335938 -27.0625 15.171875 -26.59375 L 14.296875 -23.609375 C 13.523438 -24.023438 12.6875 -24.375 11.78125 -24.65625 C 10.875 -24.9375 9.929688 -25.078125 8.953125 -25.078125 C 7.554688 -25.078125 6.5 -24.707031 5.78125 -23.96875 C 5.070312 -23.238281 4.71875 -22.265625 4.71875 -21.046875 C 4.71875 -20.109375 4.875 -19.328125 5.1875 -18.703125 C 5.507812 -18.078125 6.023438 -17.519531 6.734375 -17.03125 C 7.441406 -16.539062 8.398438 -16.007812 9.609375 -15.4375 C 10.921875 -14.84375 12.03125 -14.203125 12.9375 -13.515625 C 13.84375 -12.828125 14.53125 -12.003906 15 -11.046875 C 15.476562 -10.085938 15.71875 -8.878906 15.71875 -7.421875 Z M 15.71875 -7.421875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-4">
|
||||
<path style="stroke:none;" d="M 15.515625 0 L 3.03125 0 L 3.03125 -27.765625 L 15.515625 -27.765625 L 15.515625 -24.703125 L 5.859375 -24.703125 L 5.859375 -16.015625 L 14.953125 -16.015625 L 14.953125 -12.984375 L 5.859375 -12.984375 L 5.859375 -3.078125 L 15.515625 -3.078125 Z M 15.515625 0 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g style="fill:rgb(94.117647%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="147.339844" y="96.294922"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="155.941406" y="338.013184"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="284.886719" y="222.810059"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-1" x="30.878906" y="229.168989"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph3-1" x="63.152344" y="123.663464"/>
|
||||
<use xlink:href="#glyph3-2" x="93.428585" y="123.663464"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph3-3" x="69.964844" y="295.132214"/>
|
||||
<use xlink:href="#glyph3-2" x="90.149004" y="295.132214"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph3-1" x="251.796875" y="124.987683"/>
|
||||
<use xlink:href="#glyph3-4" x="282.073116" y="124.987683"/>
|
||||
</g>
|
||||
<g style="fill:rgb(100%,100%,100%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph3-3" x="258.613281" y="296.456433"/>
|
||||
<use xlink:href="#glyph3-4" x="278.797442" y="296.456433"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><circle fill="#F4900C" cx="18" cy="18" r="18"/><circle fill="#FFD983" cx="18" cy="18" r="14.5"/><circle fill="#F5F8FA" cx="18" cy="18" r="13"/><path fill="#CCD6DD" d="M18 8l1.531 6.304 5.54-3.375-3.375 5.54L28 18l-6.304 1.531 3.375 5.54-5.54-3.375L18 28l-1.531-6.304-5.54 3.375 3.375-5.54L8 18l6.304-1.531-3.375-5.54 5.54 3.375z"/><path fill="#292F33" d="M17.343 20.748l8.777 5.381-5.379-8.778z"/><path fill="#DD2E44" d="M18.657 15.267L9.879 9.886l5.38 8.779z"/><circle fill="#8899A6" cx="18" cy="18.008" r="3.055"/><circle fill="#F5F8FA" cx="18" cy="18.008" r="1.648"/></svg>
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 636 B |
|
@ -575,6 +575,16 @@
|
|||
"https://commons.wikimedia.org/wiki/File:Home-icon.svg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "invalid.svg",
|
||||
"license": "CC-BY 4.0",
|
||||
"authors": [
|
||||
"Twemoji"
|
||||
],
|
||||
"sources": [
|
||||
"https://github.com/twitter/twemoji"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "josm_logo.svg",
|
||||
"license": "CC0",
|
||||
|
@ -823,6 +833,16 @@
|
|||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"path": "not_found.svg",
|
||||
"license": "CC-BY 4.0",
|
||||
"authors": [
|
||||
"Twemoji"
|
||||
],
|
||||
"sources": [
|
||||
"https://github.com/twitter/twemoji"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "note.svg",
|
||||
"license": "CC0",
|
||||
|
@ -1069,6 +1089,16 @@
|
|||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"path": "speech_bubble.svg",
|
||||
"license": "CC-BY 4.0",
|
||||
"authors": [
|
||||
"Twemoji"
|
||||
],
|
||||
"sources": [
|
||||
"https://github.com/twitter/twemoji"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "square.svg",
|
||||
"license": "CC0; trivial",
|
||||
|
|
|
@ -409,7 +409,7 @@
|
|||
{
|
||||
"id": "preview",
|
||||
"render": {
|
||||
"en": "To send a letter to this address, you would write:<div style='background: #fcdf94; border: 2px solid black; border-radius: 1rem; padding: 1.5rem 0.5rem 2rem 8rem; margin: 1rem' class='flex flex-col'><img src='./assets/themes/uk_addresses/stamp.jpg' class='self-end w-16'/><div class='subtle'>Name of the inhabitant</div><div>{addr:unit} {addr:housename}</div><div>{addr:housenumber} {addr:street}</div><div class='subtle'>Suburb</div><div class='subtle'>Town</div><div class='subtle'>Postal code</div></div>"
|
||||
"en": "To send a letter to this addres, you would write:<div style='background: #fcdf94; border: 2px solid black; border-radius: 1rem; padding: 1.5rem 0.5rem 2rem 8rem; margin: 1rem' class='flex flex-col'><img src='./assets/themes/uk_addresses/stamp.jpg' class='self-end w-16'/><div class='subtle'>Name of the inhabitant</div><div>{addr:housename}</div><div>{addr:unit} {addr:housenumber} {addr:street}</div><div>{addr:place}</div><div class='subtle'>Suburb</div><div class='subtle'>Town</div><div class='subtle'>Postal code</div></div>"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
|
|
|
@ -804,14 +804,14 @@ video {
|
|||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
.m-5 {
|
||||
margin: 1.25rem;
|
||||
}
|
||||
|
||||
.m-4 {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.m-5 {
|
||||
margin: 1.25rem;
|
||||
}
|
||||
|
||||
.m-0\.5 {
|
||||
margin: 0.125rem;
|
||||
}
|
||||
|
@ -860,6 +860,10 @@ video {
|
|||
margin-left: 0.75rem;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
@ -908,10 +912,6 @@ video {
|
|||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mb-8 {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
@ -1060,14 +1060,18 @@ video {
|
|||
height: 4rem;
|
||||
}
|
||||
|
||||
.h-0 {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.h-6 {
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.h-4 {
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.h-0 {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.h-3 {
|
||||
height: 0.75rem;
|
||||
}
|
||||
|
@ -1252,6 +1256,10 @@ video {
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.content-around {
|
||||
align-content: space-around;
|
||||
}
|
||||
|
||||
.items-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
@ -1366,14 +1374,14 @@ video {
|
|||
border-bottom-left-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.border-2 {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.border-4 {
|
||||
border-width: 4px;
|
||||
}
|
||||
|
@ -1386,6 +1394,11 @@ video {
|
|||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.border-gray-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgba(107, 114, 128, var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-black {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgba(0, 0, 0, var(--tw-border-opacity));
|
||||
|
@ -1545,6 +1558,10 @@ video {
|
|||
padding-left: 0.75rem;
|
||||
}
|
||||
|
||||
.pr-2 {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.pr-0 {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
@ -1561,10 +1578,6 @@ video {
|
|||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pr-2 {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.pl-6 {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
|
|
@ -318,11 +318,11 @@
|
|||
"importLayer": {
|
||||
"layerName": "Hier is misschien een {title}",
|
||||
"description": "Deze laag toont kaart-nota's die wijzen op een {title}",
|
||||
"popupTitle": "Mogelijkse {title}",
|
||||
"popupTitle": "Is hier een {title}?",
|
||||
"importButton": "import_button({layerId}, _tags, Ik heb hier een {title} gevonden - voeg deze toe aan de kaart...,./assets/svg/addSmall.svg,,,id)",
|
||||
"importHandled": "<div class='thanks'>Dit punt is afgehandeld. Bedankt om mee te helpen!</div>",
|
||||
|
||||
"notFound": "Ik kon geen {title} vinden hier - verwijder deze van de kaart",
|
||||
"notFound": "Ik kon hier geen {title} vinden - verwijder deze van de kaart",
|
||||
"alreadyMapped": "Er staat hier reeds een {title} op de kaart; dit punt is een duplicaat. Verwijder deze van de kaart"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1074,43 +1074,6 @@
|
|||
"shortDescription": "Kartieren Sie alle Bäume",
|
||||
"title": "Bäume"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"description": "Tragen Sie zu OpenStreetMap bei, indem Sie Adressinformationen ausfüllen",
|
||||
"layers": {
|
||||
"2": {
|
||||
"description": "Adressen",
|
||||
"name": "Bekannte Adressen in OSM",
|
||||
"tagRenderings": {
|
||||
"uk_addresses_explanation_osm": {
|
||||
"render": "Diese Adresse ist in OpenStreetMap gespeichert"
|
||||
},
|
||||
"uk_addresses_housenumber": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Dieses Gebäude hat keine Hausnummer"
|
||||
}
|
||||
},
|
||||
"question": "Wie lautet die Nummer dieses Hauses?",
|
||||
"render": "Die Hausnummer ist <b>{addr:housenumber}</b>"
|
||||
},
|
||||
"uk_addresses_street": {
|
||||
"question": "In welcher Straße befindet sich diese Adresse?",
|
||||
"render": "Diese Adresse befindet sich in der Straße <b>{addr:street}</b>"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Bekannte Adresse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shortDescription": "Helfen Sie beim Aufbau eines offenen Datensatzes britischer Adressen",
|
||||
"tileLayerSources": {
|
||||
"0": {
|
||||
"name": "Grenzverläufe gemäß osmuk.org"
|
||||
}
|
||||
},
|
||||
"title": "Adressen in Großbritannien"
|
||||
},
|
||||
"waste_basket": {
|
||||
"description": "Auf dieser Karte finden Sie Abfalleimer in Ihrer Nähe. Wenn ein Abfalleimer auf dieser Karte fehlt, können Sie ihn selbst hinzufügen",
|
||||
"shortDescription": "Eine Karte mit Abfalleimern",
|
||||
|
|
|
@ -1263,87 +1263,6 @@
|
|||
"shortDescription": "Map all the trees",
|
||||
"title": "Trees"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"description": "Contribute to OpenStreetMap by filling out address information",
|
||||
"layers": {
|
||||
"0": {
|
||||
"name": "Inspire polygons"
|
||||
},
|
||||
"1": {
|
||||
"tagRenderings": {
|
||||
"uk_addresses_embedding_outline": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The INSPIRE-polygon containing this point has at least one address contained"
|
||||
},
|
||||
"1": {
|
||||
"then": "The INSPIRE-polygon containing this point has <b>no</b> addresses contained"
|
||||
}
|
||||
}
|
||||
},
|
||||
"uk_addresses_explanation": {
|
||||
"render": "There probably is an address here"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Address to be determined"
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"description": "Addresses",
|
||||
"name": "Known addresses in OSM",
|
||||
"tagRenderings": {
|
||||
"address-sign-image": {
|
||||
"render": "{image_carousel(image:address)}<br/>{image_upload(image:address, Add image of the address)}"
|
||||
},
|
||||
"fixme": {
|
||||
"question": "What should be fixed here? Please explain what the address is"
|
||||
},
|
||||
"preview": {
|
||||
"render": "To send a letter to this addres, you would write:<div style='background: #fcdf94; border: 2px solid black; border-radius: 1rem; padding: 1.5rem 0.5rem 2rem 8rem; margin: 1rem' class='flex flex-col'><img src='./assets/themes/uk_addresses/stamp.jpg' class='self-end w-16'/><div class='subtle'>Name of the inhabitant</div><div>{addr:housename}</div><div>{addr:unit} {addr:housenumber} {addr:street}</div><div>{addr:place}</div><div class='subtle'>Suburb</div><div class='subtle'>Town</div><div class='subtle'>Postal code</div></div>"
|
||||
},
|
||||
"uk_addresses_explanation_osm": {
|
||||
"render": "This address is saved in OpenStreetMap"
|
||||
},
|
||||
"uk_addresses_housenumber": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This building has no house number"
|
||||
}
|
||||
},
|
||||
"question": "What is the number of this house?",
|
||||
"render": "The housenumber is <b>{addr:housenumber}</b>"
|
||||
},
|
||||
"uk_addresses_placename": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "No extra placename is given or needed"
|
||||
}
|
||||
},
|
||||
"question": "What is the place or locality?<div class='subtle'>This is additional information if the streetname alone isn't enough to find this address. Typical examples are 'Technology Park', 'XYZ Terrace', ...</div>",
|
||||
"render": "The placename is <b>{addr:place}</b>"
|
||||
},
|
||||
"uk_addresses_street": {
|
||||
"question": "What street is this address located in?",
|
||||
"render": "This address is in street <b>{addr:street}</b>"
|
||||
},
|
||||
"uk_addresses_unit": {
|
||||
"question": "What is the unit indication of this address? <div class='subtle'>This is the letter or number of the letterbox here, if multiple letterboxes share the same street and housenumber. If there are multiple at the same location, add them here with a <b>;</b> between them</div>"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Known address"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shortDescription": "Help to build an open dataset of UK addresses",
|
||||
"tileLayerSources": {
|
||||
"0": {
|
||||
"name": "Property boundaries by osmuk.org"
|
||||
}
|
||||
},
|
||||
"title": "UK Addresses"
|
||||
},
|
||||
"waste_basket": {
|
||||
"description": "On this map, you'll find waste baskets near you. If a waste basket is missing on this map, you can add it yourself",
|
||||
"shortDescription": "A map with waste baskets",
|
||||
|
|
|
@ -104,17 +104,6 @@
|
|||
"shortDescription": "Az összes fa feltérképezése",
|
||||
"title": "Fatérkép"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"layers": {
|
||||
"2": {
|
||||
"description": "Címek",
|
||||
"name": "Ismert címek az OSM-en",
|
||||
"title": {
|
||||
"render": "Ismert cím"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"waste_basket": {
|
||||
"description": "Ezen a térképen megtalálhatod a közeledben lévő szemeteskosarakat. Ha hiányzik egy kuka a térképről, te is felrajzolhatod",
|
||||
"shortDescription": "Szemeteskosarakat ábrázoló térkép",
|
||||
|
|
|
@ -117,16 +117,5 @@
|
|||
},
|
||||
"trees": {
|
||||
"title": "Pohon"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"description": "Berkontribusi untuk OpenStreetMap dengan mengisi informasi alamat",
|
||||
"layers": {
|
||||
"1": {
|
||||
"title": {
|
||||
"render": "Alamat yang diketahui"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Alamat Inggris"
|
||||
}
|
||||
}
|
|
@ -916,11 +916,6 @@
|
|||
"shortDescription": "Mappa tutti gli alberi",
|
||||
"title": "Alberi"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"description": "Contribuisci a OpenStreetMap inserendo le informazioni sull’indirizzo",
|
||||
"shortDescription": "Aiuta a costruire un dataset libero per gli indirizzi nel Regno Unito",
|
||||
"title": "Indirizzi UK"
|
||||
},
|
||||
"waste_basket": {
|
||||
"description": "In questa cartina troverai i cestini dei rifiuti nei tuoi paraggi. Se manca un cestino, puoi inserirlo tu stesso",
|
||||
"shortDescription": "Una cartina dei cestini dei rifiuti",
|
||||
|
|
|
@ -1045,28 +1045,6 @@
|
|||
"shortDescription": "Breng bomen in kaart",
|
||||
"title": "Bomen"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"description": "Draag bij aan OpenStreetMap door adresinformatie in te vullen",
|
||||
"layers": {
|
||||
"2": {
|
||||
"description": "Adressen",
|
||||
"name": "Bekende adressen in OSM",
|
||||
"tagRenderings": {
|
||||
"uk_addresses_housenumber": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Dit gebouw heeft geen huisnummer"
|
||||
}
|
||||
},
|
||||
"render": "Het huisnummer is <b>{addr:housenumber}</b>"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Bekend adres"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"waste_basket": {
|
||||
"description": "Op deze kaart vind je vuilnisbakken waar je afval in kan smijten. Ontbreekt er een vuilnisbak? Dan kan je die zelf toevoegen",
|
||||
"shortDescription": "Een kaart met vuilnisbakken",
|
||||
|
|
|
@ -530,12 +530,5 @@
|
|||
"description": "Нанесите все деревья на карту!",
|
||||
"shortDescription": "Карта деревьев",
|
||||
"title": "Деревья"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"layers": {
|
||||
"2": {
|
||||
"description": "Адреса"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -652,14 +652,6 @@
|
|||
"shortDescription": "所有樹木的地圖",
|
||||
"title": "樹木"
|
||||
},
|
||||
"uk_addresses": {
|
||||
"layers": {
|
||||
"2": {
|
||||
"description": "地址",
|
||||
"name": "OSM 上已知的地址"
|
||||
}
|
||||
}
|
||||
},
|
||||
"waste_basket": {
|
||||
"description": "在這份地圖當中,你可以找到你附近的垃圾筒。如果地圖有遺漏垃圾筒,你可以自己加上去",
|
||||
"shortDescription": "垃圾筒的地圖",
|
||||
|
|
|
@ -91,6 +91,14 @@ knownLicenses.set("na", {
|
|||
sources: []
|
||||
})
|
||||
|
||||
knownLicenses.set("twemoji", {
|
||||
authors: ["Twemoji"],
|
||||
path: undefined,
|
||||
license: "CC-BY 4.0",
|
||||
sources: ["https://github.com/twitter/twemoji"]
|
||||
})
|
||||
|
||||
|
||||
|
||||
function promptLicenseFor(path): SmallLicense {
|
||||
console.log("License abbreviations:")
|
||||
|
|
26
test.ts
26
test.ts
|
@ -1,24 +1,4 @@
|
|||
import {Utils} from "./Utils";
|
||||
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
||||
import Loading from "./UI/Base/Loading";
|
||||
|
||||
const features = []
|
||||
for (let lat = 49; lat < 52; lat+=0.05) {
|
||||
for (let lon = 2.5; lon < 6.5; lon+=0.025) {
|
||||
features.push({
|
||||
type:"Feature",
|
||||
properties: {},
|
||||
geometry:{
|
||||
type:"Point",
|
||||
coordinates: [lon, lat]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const geojson = {
|
||||
type:"FeatureCollection",
|
||||
features
|
||||
}
|
||||
|
||||
Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson, null, " "), "raster.geojson",{
|
||||
mimetype:"application/geo+json"
|
||||
})
|
||||
new Loading(new FixedUiElement("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")).AttachTo("maindiv")
|
Loading…
Reference in a new issue