forked from MapComplete/MapComplete
Merge branch 'develop' into alpha
This commit is contained in:
commit
3be0dbd22f
8 changed files with 3754 additions and 3629 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,3 +17,4 @@ missing_translations.txt
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Svg.ts
|
Svg.ts
|
||||||
data/
|
data/
|
||||||
|
Folder.DotSettings.user
|
||||||
|
|
100
Logic/Actors/SelectedElementTagsUpdater.ts
Normal file
100
Logic/Actors/SelectedElementTagsUpdater.ts
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/**
|
||||||
|
* This actor will download the latest version of the selected element from OSM and update the tags if necessary.
|
||||||
|
*/
|
||||||
|
import {UIEventSource} from "../UIEventSource";
|
||||||
|
import {ElementStorage} from "../ElementStorage";
|
||||||
|
import {Changes} from "../Osm/Changes";
|
||||||
|
import {OsmObject} from "../Osm/OsmObject";
|
||||||
|
import {OsmConnection} from "../Osm/OsmConnection";
|
||||||
|
|
||||||
|
export default class SelectedElementTagsUpdater {
|
||||||
|
|
||||||
|
constructor(state: {
|
||||||
|
selectedElement: UIEventSource<any>,
|
||||||
|
allElements: ElementStorage,
|
||||||
|
changes: Changes,
|
||||||
|
osmConnection: OsmConnection
|
||||||
|
}) {
|
||||||
|
|
||||||
|
|
||||||
|
state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => {
|
||||||
|
if(isLoggedIn){
|
||||||
|
SelectedElementTagsUpdater.installCallback(state)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static installCallback(state: {
|
||||||
|
selectedElement: UIEventSource<any>,
|
||||||
|
allElements: ElementStorage,
|
||||||
|
changes: Changes,
|
||||||
|
osmConnection: OsmConnection
|
||||||
|
}) {
|
||||||
|
|
||||||
|
|
||||||
|
state.selectedElement.addCallbackAndRunD(s => {
|
||||||
|
const id = s.properties?.id
|
||||||
|
OsmObject.DownloadObjectAsync(id).then(obj => {
|
||||||
|
SelectedElementTagsUpdater.applyUpdate(state, obj, id)
|
||||||
|
}).catch(e => {
|
||||||
|
console.error("Could not update tags of ", id, "due to", e)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static applyUpdate(state: {
|
||||||
|
selectedElement: UIEventSource<any>,
|
||||||
|
allElements: ElementStorage,
|
||||||
|
changes: Changes,
|
||||||
|
osmConnection: OsmConnection
|
||||||
|
}, obj: OsmObject, id: string
|
||||||
|
) {
|
||||||
|
const pendingChanges = state.changes.pendingChanges.data
|
||||||
|
.filter(change => change.type === obj.type && change.id === obj.id)
|
||||||
|
.filter(change => change.tags !== undefined);
|
||||||
|
const latestTags = obj.tags
|
||||||
|
console.log("Applying updates of ", id, " got tags", latestTags, "and still have to apply changes: ", pendingChanges)
|
||||||
|
|
||||||
|
for (const pendingChange of pendingChanges) {
|
||||||
|
const tagChanges = pendingChange.tags;
|
||||||
|
for (const tagChange of tagChanges) {
|
||||||
|
const key = tagChange.k
|
||||||
|
const v = tagChange.v
|
||||||
|
if (v === undefined || v === "") {
|
||||||
|
delete latestTags[key]
|
||||||
|
} else {
|
||||||
|
latestTags[key] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the changes applied, we merge them onto the upstream object
|
||||||
|
let somethingChanged = false;
|
||||||
|
const currentTagsSource = state.allElements.getEventSourceById(id);
|
||||||
|
const currentTags = currentTagsSource.data
|
||||||
|
for (const key in latestTags) {
|
||||||
|
let osmValue = latestTags[key]
|
||||||
|
|
||||||
|
if(typeof osmValue === "number"){
|
||||||
|
osmValue = ""+osmValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const localValue = currentTags[key]
|
||||||
|
if (localValue !== osmValue) {
|
||||||
|
console.log("Local value:", localValue, "upstream", osmValue)
|
||||||
|
somethingChanged = true;
|
||||||
|
currentTags[key] = osmValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (somethingChanged) {
|
||||||
|
console.log("Detected upstream changes to the object when opening it, updating...")
|
||||||
|
currentTagsSource.ping()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -7,12 +7,14 @@ export default class ImgurUploader {
|
||||||
public readonly failed: UIEventSource<string[]> = new UIEventSource<string[]>([]);
|
public readonly failed: UIEventSource<string[]> = new UIEventSource<string[]>([]);
|
||||||
public readonly success: UIEventSource<string[]> = new UIEventSource<string[]>([]);
|
public readonly success: UIEventSource<string[]> = new UIEventSource<string[]>([]);
|
||||||
private readonly _handleSuccessUrl: (string) => void;
|
private readonly _handleSuccessUrl: (string) => void;
|
||||||
|
|
||||||
|
public maxFileSizeInMegabytes = 10;
|
||||||
|
|
||||||
constructor(handleSuccessUrl: (string) => void) {
|
constructor(handleSuccessUrl: (string) => void) {
|
||||||
this._handleSuccessUrl = handleSuccessUrl;
|
this._handleSuccessUrl = handleSuccessUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uploadMany(title: string, description: string, files: FileList) {
|
public uploadMany(title: string, description: string, files: FileList): void {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
this.queue.data.push(files.item(i).name)
|
this.queue.data.push(files.item(i).name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ export interface ChangeDescription {
|
||||||
/**
|
/**
|
||||||
* All changes to tags
|
* All changes to tags
|
||||||
* v = "" or v = undefined to erase this tag
|
* v = "" or v = undefined to erase this tag
|
||||||
|
*
|
||||||
|
* Note that this list will only contain the _changes_ to the tags, not the full set of tags
|
||||||
*/
|
*/
|
||||||
tags?: { k: string, v: string }[],
|
tags?: { k: string, v: string }[],
|
||||||
|
|
||||||
|
|
3
State.ts
3
State.ts
|
@ -18,6 +18,7 @@ import FilteredLayer from "./Models/FilteredLayer";
|
||||||
import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor";
|
import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor";
|
||||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
||||||
import {BBox} from "./Logic/BBox";
|
import {BBox} from "./Logic/BBox";
|
||||||
|
import SelectedElementTagsUpdater from "./Logic/Actors/SelectedElementTagsUpdater";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the global state: a bunch of UI-event sources
|
* Contains the global state: a bunch of UI-event sources
|
||||||
|
@ -376,6 +377,8 @@ export default class State {
|
||||||
new ChangeToElementsActor(this.changes, this.allElements)
|
new ChangeToElementsActor(this.changes, this.allElements)
|
||||||
|
|
||||||
new PendingChangesUploader(this.changes, this.selectedElement);
|
new PendingChangesUploader(this.changes, this.selectedElement);
|
||||||
|
|
||||||
|
new SelectedElementTagsUpdater(this)
|
||||||
|
|
||||||
this.mangroveIdentity = new MangroveIdentity(
|
this.mangroveIdentity = new MangroveIdentity(
|
||||||
this.osmConnection.GetLongPreference("identity", "mangrove")
|
this.osmConnection.GetLongPreference("identity", "mangrove")
|
||||||
|
|
|
@ -39,7 +39,10 @@ export class ImageUploadFlow extends Toggle {
|
||||||
}
|
}
|
||||||
)))
|
)))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
uploader.queue.addCallbackD(q => console.log("Image upload queue is ", q))
|
||||||
|
uploader.failed.addCallbackD(q => console.log("Image upload fail list is ", q))
|
||||||
|
uploader.success.addCallbackD(q => console.log("Image upload success list is ", q))
|
||||||
|
|
||||||
const licensePicker = new LicensePicker()
|
const licensePicker = new LicensePicker()
|
||||||
|
|
||||||
|
@ -58,10 +61,23 @@ export class ImageUploadFlow extends Toggle {
|
||||||
|
|
||||||
const fileSelector = new FileSelectorButton(label)
|
const fileSelector = new FileSelectorButton(label)
|
||||||
fileSelector.GetValue().addCallback(filelist => {
|
fileSelector.GetValue().addCallback(filelist => {
|
||||||
if (filelist === undefined) {
|
if (filelist === undefined || filelist.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < filelist.length; i++) {
|
||||||
|
const sizeInBytes= filelist[i].size
|
||||||
|
console.log(filelist[i].name + " has a size of " + sizeInBytes + " Bytes");
|
||||||
|
if(sizeInBytes > uploader.maxFileSizeInMegabytes * 1000000){
|
||||||
|
alert(Translations.t.image.toBig.Subs({
|
||||||
|
actual_size: (Math.floor(sizeInBytes / 1000000)) + "MB",
|
||||||
|
max_size: uploader.maxFileSizeInMegabytes+"MB"
|
||||||
|
}).txt)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Received images from the user, starting upload")
|
console.log("Received images from the user, starting upload")
|
||||||
const license = licensePicker.GetValue()?.data ?? "CC0"
|
const license = licensePicker.GetValue()?.data ?? "CC0"
|
||||||
|
|
||||||
|
@ -77,7 +93,7 @@ export class ImageUploadFlow extends Toggle {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const title = matchingLayer?.title?.GetRenderValue(tags)?.ConstructElement().innerText ?? tags.name ?? "Unknown area";
|
const title = matchingLayer?.title?.GetRenderValue(tags)?.ConstructElement()?.innerText ?? tags.name ?? "Unknown area";
|
||||||
const description = [
|
const description = [
|
||||||
"author:" + State.state.osmConnection.userDetails.data.name,
|
"author:" + State.state.osmConnection.userDetails.data.name,
|
||||||
"license:" + license,
|
"license:" + license,
|
||||||
|
@ -92,10 +108,10 @@ export class ImageUploadFlow extends Toggle {
|
||||||
const uploadStateUi = new UploadFlowStateUI(uploader.queue, uploader.failed, uploader.success)
|
const uploadStateUi = new UploadFlowStateUI(uploader.queue, uploader.failed, uploader.success)
|
||||||
|
|
||||||
const uploadFlow: BaseUIElement = new Combine([
|
const uploadFlow: BaseUIElement = new Combine([
|
||||||
|
uploadStateUi,
|
||||||
fileSelector,
|
fileSelector,
|
||||||
Translations.t.image.respectPrivacy.Clone().SetStyle("font-size:small;"),
|
Translations.t.image.respectPrivacy.Clone().SetStyle("font-size:small;"),
|
||||||
licensePicker,
|
licensePicker
|
||||||
uploadStateUi
|
|
||||||
]).SetClass("flex flex-col image-upload-flow mt-4 mb-8 text-center")
|
]).SetClass("flex flex-col image-upload-flow mt-4 mb-8 text-center")
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,8 @@
|
||||||
"uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>",
|
"uploadDone": "<span class='thanks'>Your picture has been added. Thanks for helping out!</span>",
|
||||||
"dontDelete": "Cancel",
|
"dontDelete": "Cancel",
|
||||||
"doDelete": "Remove image",
|
"doDelete": "Remove image",
|
||||||
"isDeleted": "Deleted"
|
"isDeleted": "Deleted",
|
||||||
|
"toBig": "Your image is too large as it is {actual_size}. Please use images of at most {max_size}"
|
||||||
},
|
},
|
||||||
"centerMessage": {
|
"centerMessage": {
|
||||||
"loadingData": "Loading data…",
|
"loadingData": "Loading data…",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue