Translations
This commit is contained in:
parent
615bbec05d
commit
369c19a58a
34 changed files with 287 additions and 173 deletions
|
@ -1,6 +1,6 @@
|
||||||
import {TagRenderingOptions} from "../TagRendering";
|
import {TagRenderingOptions} from "../TagRendering";
|
||||||
import {LayerDefinition} from "../LayerDefinition";
|
import {LayerDefinition} from "../LayerDefinition";
|
||||||
import {Tag} from "../../Logic/TagsFilter";
|
import {And, Tag} from "../../Logic/TagsFilter";
|
||||||
import L from "leaflet";
|
import L from "leaflet";
|
||||||
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
|
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
|
||||||
import {NameQuestion} from "../Questions/NameQuestion";
|
import {NameQuestion} from "../Questions/NameQuestion";
|
||||||
|
@ -24,6 +24,16 @@ export class BikeShop extends LayerDefinition {
|
||||||
|
|
||||||
this.title = new TagRenderingOptions({
|
this.title = new TagRenderingOptions({
|
||||||
mappings: [
|
mappings: [
|
||||||
|
{k: new And([new Tag("name", "*"), this.sellsBikes]), txt: "Bicycle shop {name}"},
|
||||||
|
{
|
||||||
|
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "no")]),
|
||||||
|
txt: "Bicycle repair {name}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "")]),
|
||||||
|
txt: "Bicycle repair {name}"
|
||||||
|
},
|
||||||
|
|
||||||
{k: this.sellsBikes, txt: "Bicycle shop"},
|
{k: this.sellsBikes, txt: "Bicycle shop"},
|
||||||
{k: new Tag("service:bicycle:retail", "no"), txt: "Bicycle repair"},
|
{k: new Tag("service:bicycle:retail", "no"), txt: "Bicycle repair"},
|
||||||
{k: new Tag("service:bicycle:retail", ""), txt: "Bicycle repair/shop"},
|
{k: new Tag("service:bicycle:retail", ""), txt: "Bicycle repair/shop"},
|
||||||
|
|
|
@ -14,6 +14,7 @@ export class Layout {
|
||||||
public welcomeBackMessage: string;
|
public welcomeBackMessage: string;
|
||||||
|
|
||||||
public startzoom: number;
|
public startzoom: number;
|
||||||
|
public supportedLanguages: string[];
|
||||||
public startLon: number;
|
public startLon: number;
|
||||||
public startLat: number;
|
public startLat: number;
|
||||||
public welcomeTail: string;
|
public welcomeTail: string;
|
||||||
|
@ -35,6 +36,7 @@ export class Layout {
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
|
supportedLanguages: string[],
|
||||||
title: UIElement | string,
|
title: UIElement | string,
|
||||||
layers: LayerDefinition[],
|
layers: LayerDefinition[],
|
||||||
startzoom: number,
|
startzoom: number,
|
||||||
|
@ -45,6 +47,7 @@ export class Layout {
|
||||||
welcomeBackMessage: string = "You are logged in. Welcome back!",
|
welcomeBackMessage: string = "You are logged in. Welcome back!",
|
||||||
welcomeTail: string = ""
|
welcomeTail: string = ""
|
||||||
) {
|
) {
|
||||||
|
this.supportedLanguages = supportedLanguages;
|
||||||
this.title = typeof(title) === 'string' ? new FixedUiElement(title) : title;
|
this.title = typeof(title) === 'string' ? new FixedUiElement(title) : title;
|
||||||
this.startLon = startLon;
|
this.startLon = startLon;
|
||||||
this.startLat = startLat;
|
this.startLat = startLat;
|
||||||
|
|
|
@ -4,6 +4,7 @@ export class All extends Layout{
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"all",
|
"all",
|
||||||
|
["en"],
|
||||||
"All quest layers",
|
"All quest layers",
|
||||||
[],
|
[],
|
||||||
15,
|
15,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as Layer from "../Layers/Bookcases";
|
||||||
export class Bookcases extends Layout{
|
export class Bookcases extends Layout{
|
||||||
constructor() {
|
constructor() {
|
||||||
super( "bookcases",
|
super( "bookcases",
|
||||||
|
["nl"],
|
||||||
"Open Bookcase Map",
|
"Open Bookcase Map",
|
||||||
[new Layer.Bookcases()],
|
[new Layer.Bookcases()],
|
||||||
14,
|
14,
|
||||||
|
|
|
@ -4,21 +4,22 @@ import BikeServices from "../Layers/BikeStations";
|
||||||
import {GhostBike} from "../Layers/GhostBike";
|
import {GhostBike} from "../Layers/GhostBike";
|
||||||
import Translations from "../../UI/i18n/Translations";
|
import Translations from "../../UI/i18n/Translations";
|
||||||
import {DrinkingWater} from "../Layers/DrinkingWater";
|
import {DrinkingWater} from "../Layers/DrinkingWater";
|
||||||
import {BikeShop} from "../Layers/BikeShop";
|
import {BikeShop} from "../Layers/BikeShop"
|
||||||
|
|
||||||
|
|
||||||
export default class Cyclofix extends Layout {
|
export default class Cyclofix extends Layout {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"pomp",
|
"pomp",
|
||||||
Translations.t.cylofix.title,
|
["en", "nl", "fr"],
|
||||||
|
Translations.cylofix.title,
|
||||||
[new BikeServices(), new BikeShop(), new DrinkingWater(), new BikeParkings()],
|
[new BikeServices(), new BikeShop(), new DrinkingWater(), new BikeParkings()],
|
||||||
16,
|
16,
|
||||||
50.8465573,
|
50.8465573,
|
||||||
4.3516970,
|
4.3516970,
|
||||||
"<h3>" + Translations.t.cylofix.title.Render() + "</h3>\n" +
|
"<h3>" + Translations.cylofix.title.Render() + "</h3>\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
`<p>${Translations.t.cylofix.description.Render()}</p>`
|
`<p>${Translations.cylofix.description.Render()}</p>`
|
||||||
,
|
,
|
||||||
"", "");
|
"", "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {GrbToFix} from "../Layers/GrbToFix";
|
||||||
export class GRB extends Layout {
|
export class GRB extends Layout {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("grb",
|
super("grb",
|
||||||
|
["en"],
|
||||||
"Grb import fix tool",
|
"Grb import fix tool",
|
||||||
[new GrbToFix()],
|
[new GrbToFix()],
|
||||||
15,
|
15,
|
||||||
|
|
|
@ -7,6 +7,7 @@ export class Groen extends Layout {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("buurtnatuur",
|
super("buurtnatuur",
|
||||||
|
["nl"],
|
||||||
"Buurtnatuur",
|
"Buurtnatuur",
|
||||||
[new NatureReserves(), new Park(), new Bos()],
|
[new NatureReserves(), new Park(), new Bos()],
|
||||||
10,
|
10,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {Map} from "../Layers/Map";
|
||||||
export class MetaMap extends Layout{
|
export class MetaMap extends Layout{
|
||||||
constructor() {
|
constructor() {
|
||||||
super( "metamap",
|
super( "metamap",
|
||||||
|
["en"],
|
||||||
"Open Map Map",
|
"Open Map Map",
|
||||||
[new Map()],
|
[new Map()],
|
||||||
1,
|
1,
|
||||||
|
|
|
@ -7,6 +7,7 @@ export class Natuurpunt extends Layout{
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"natuurpunt",
|
"natuurpunt",
|
||||||
|
["nl"],
|
||||||
"De natuur in",
|
"De natuur in",
|
||||||
[new Birdhide(), new InformationBoard(), new NatureReserves(true)],
|
[new Birdhide(), new InformationBoard(), new NatureReserves(true)],
|
||||||
12,
|
12,
|
||||||
|
|
|
@ -5,6 +5,7 @@ export class Statues extends Layout{
|
||||||
constructor() {
|
constructor() {
|
||||||
super( "statues",
|
super( "statues",
|
||||||
"Open Artwork Map",
|
"Open Artwork Map",
|
||||||
|
["en"],
|
||||||
[new Artwork()],
|
[new Artwork()],
|
||||||
10,
|
10,
|
||||||
50.8435,
|
50.8435,
|
||||||
|
|
|
@ -7,6 +7,7 @@ export class StreetWidth extends Layout{
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super( "width",
|
super( "width",
|
||||||
|
["nl"],
|
||||||
"Straatbreedtes in Brugge",
|
"Straatbreedtes in Brugge",
|
||||||
[new Widths(
|
[new Widths(
|
||||||
2,
|
2,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as Layer from "../Layers/Toilets";
|
||||||
export class Toilets extends Layout{
|
export class Toilets extends Layout{
|
||||||
constructor() {
|
constructor() {
|
||||||
super( "toilets",
|
super( "toilets",
|
||||||
|
["en"],
|
||||||
"Open Toilet Map",
|
"Open Toilet Map",
|
||||||
[new Layer.Toilets()],
|
[new Layer.Toilets()],
|
||||||
12,
|
12,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { Park } from "../Layers/Park";
|
||||||
export class WalkByBrussels extends Layout {
|
export class WalkByBrussels extends Layout {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("walkbybrussels",
|
super("walkbybrussels",
|
||||||
|
["en","fr","nl"],
|
||||||
"Drinking Water Spots",
|
"Drinking Water Spots",
|
||||||
[new DrinkingWater(), new Park(), new NatureReserves()],
|
[new DrinkingWater(), new Park(), new NatureReserves()],
|
||||||
10,
|
10,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {InputElement} from "../UI/Input/InputElement";
|
||||||
import {InputElementWrapper} from "../UI/Input/InputElementWrapper";
|
import {InputElementWrapper} from "../UI/Input/InputElementWrapper";
|
||||||
import {FixedInputElement} from "../UI/Input/FixedInputElement";
|
import {FixedInputElement} from "../UI/Input/FixedInputElement";
|
||||||
import {RadioButton} from "../UI/Input/RadioButton";
|
import {RadioButton} from "../UI/Input/RadioButton";
|
||||||
|
import Translations from "../UI/i18n/Translations";
|
||||||
|
|
||||||
export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
||||||
|
|
||||||
|
@ -21,8 +22,17 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public options: {
|
public options: {
|
||||||
priority?: number; question?: string; primer?: string;
|
priority?: number;
|
||||||
freeform?: { key: string; tagsPreprocessor?: (tags: any) => any; template: string; renderTemplate: string; placeholder?: string; extraTags?: TagsFilter }; mappings?: { k: TagsFilter; txt: string; priority?: number, substitute?: boolean }[]
|
question?: string | UIElement;
|
||||||
|
freeform?: {
|
||||||
|
key: string;
|
||||||
|
tagsPreprocessor?: (tags: any) => any;
|
||||||
|
template: string;
|
||||||
|
renderTemplate: string;
|
||||||
|
placeholder?: string;
|
||||||
|
extraTags?: TagsFilter
|
||||||
|
};
|
||||||
|
mappings?: { k: TagsFilter; txt: string | UIElement; priority?: number, substitute?: boolean }[]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,12 +83,6 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional:
|
|
||||||
* if defined, this a common piece of tag that is shown in front of every mapping (except freeform)
|
|
||||||
*/
|
|
||||||
primer?: string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In some very rare cases, tags have to be rewritten before displaying
|
* In some very rare cases, tags have to be rewritten before displaying
|
||||||
* This function can be used for that.
|
* This function can be used for that.
|
||||||
|
@ -86,6 +90,7 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
||||||
*/
|
*/
|
||||||
tagsPreprocessor?: ((tags: any) => void)
|
tagsPreprocessor?: ((tags: any) => void)
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,10 +139,9 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
private _priority: number;
|
private _priority: number;
|
||||||
|
|
||||||
|
|
||||||
private _question: string;
|
private _question: UIElement;
|
||||||
private _primer: string;
|
private _mapping: { k: TagsFilter, txt: UIElement, priority?: number }[];
|
||||||
private _mapping: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[];
|
private _renderMapping: { k: TagsFilter, txt: UIElement, priority?: number }[];
|
||||||
private _renderMapping: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[];
|
|
||||||
|
|
||||||
private _tagsPreprocessor?: ((tags: any) => any);
|
private _tagsPreprocessor?: ((tags: any) => any);
|
||||||
private _freeform: {
|
private _freeform: {
|
||||||
|
@ -163,8 +167,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
constructor(tags: UIEventSource<any>, changes: Changes, options: {
|
constructor(tags: UIEventSource<any>, changes: Changes, options: {
|
||||||
priority?: number
|
priority?: number
|
||||||
|
|
||||||
question?: string,
|
question?: string | UIElement,
|
||||||
primer?: string,
|
|
||||||
|
|
||||||
freeform?: {
|
freeform?: {
|
||||||
key: string, template: string,
|
key: string, template: string,
|
||||||
|
@ -173,7 +176,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
extraTags?: TagsFilter,
|
extraTags?: TagsFilter,
|
||||||
},
|
},
|
||||||
tagsPreprocessor?: ((tags: any) => any),
|
tagsPreprocessor?: ((tags: any) => any),
|
||||||
mappings?: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[]
|
mappings?: { k: TagsFilter, txt: string | UIElement, priority?: number, substitute?: boolean }[]
|
||||||
}) {
|
}) {
|
||||||
super(tags);
|
super(tags);
|
||||||
const self = this;
|
const self = this;
|
||||||
|
@ -183,9 +186,10 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
this._userDetails = changes.login.userDetails;
|
this._userDetails = changes.login.userDetails;
|
||||||
this.ListenTo(this._userDetails);
|
this.ListenTo(this._userDetails);
|
||||||
|
|
||||||
this._question = options.question;
|
if (options.question !== undefined) {
|
||||||
|
this._question = Translations.W(options.question);
|
||||||
|
}
|
||||||
this._priority = options.priority ?? 0;
|
this._priority = options.priority ?? 0;
|
||||||
this._primer = options.primer ?? "";
|
|
||||||
this._tagsPreprocessor = function (properties) {
|
this._tagsPreprocessor = function (properties) {
|
||||||
if (options.tagsPreprocessor === undefined) {
|
if (options.tagsPreprocessor === undefined) {
|
||||||
return properties;
|
return properties;
|
||||||
|
@ -202,38 +206,28 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
this._renderMapping = [];
|
this._renderMapping = [];
|
||||||
this._freeform = options.freeform;
|
this._freeform = options.freeform;
|
||||||
|
|
||||||
// Prepare the choices for the Radio buttons
|
|
||||||
const choices: UIElement[] = [];
|
|
||||||
const usedChoices: string [] = [];
|
|
||||||
|
|
||||||
for (const choice of options.mappings ?? []) {
|
for (const choice of options.mappings ?? []) {
|
||||||
if (choice.k === null) {
|
let choiceSubbed = {
|
||||||
this._mapping.push(choice);
|
k: choice.k,
|
||||||
continue;
|
txt: this.ApplyTemplate(choice.txt),
|
||||||
}
|
priority: choice.priority
|
||||||
let choiceSubbed = choice;
|
};
|
||||||
|
|
||||||
if (choice.substitute) {
|
if (choice.substitute) {
|
||||||
choiceSubbed = {
|
choiceSubbed = {
|
||||||
k: choice.k.substituteValues(
|
k: choice.k.substituteValues(
|
||||||
options.tagsPreprocessor(this._source.data)),
|
options.tagsPreprocessor(this._source.data)),
|
||||||
txt: this.ApplyTemplate(choice.txt),
|
txt: this.ApplyTemplate(choice.txt),
|
||||||
substitute: false,
|
|
||||||
priority: choice.priority
|
priority: choice.priority
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const txt = choiceSubbed.txt
|
this._mapping.push({
|
||||||
// Choices is what is shown in the radio buttons
|
k: choiceSubbed.k,
|
||||||
if (usedChoices.indexOf(txt) < 0) {
|
txt: choiceSubbed.txt
|
||||||
|
});
|
||||||
choices.push(new FixedUiElement(txt));
|
|
||||||
usedChoices.push(txt);
|
|
||||||
// This is used to convert the radio button index into tags needed to add
|
|
||||||
this._mapping.push(choiceSubbed);
|
|
||||||
} else {
|
|
||||||
this._renderMapping.push(choiceSubbed); // only used while rendering
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,7 +281,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
placeholder?: string,
|
placeholder?: string,
|
||||||
extraTags?: TagsFilter,
|
extraTags?: TagsFilter,
|
||||||
},
|
},
|
||||||
mappings?: { k: TagsFilter, txt: string, priority?: number, substitute?: boolean }[]
|
mappings?: { k: TagsFilter, txt: string | UIElement, priority?: number, substitute?: boolean }[]
|
||||||
}):
|
}):
|
||||||
InputElement<TagsFilter> {
|
InputElement<TagsFilter> {
|
||||||
|
|
||||||
|
@ -315,7 +309,8 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
|
|
||||||
|
|
||||||
if (elements.length == 0) {
|
if (elements.length == 0) {
|
||||||
throw "NO TAGRENDERINGS!"
|
console.warn("WARNING: no tagrendering with following options:", options);
|
||||||
|
return new FixedInputElement("This should not happen: no tag renderings defined", undefined);
|
||||||
}
|
}
|
||||||
if (elements.length == 1) {
|
if (elements.length == 1) {
|
||||||
return elements[0];
|
return elements[0];
|
||||||
|
@ -326,7 +321,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private InputElementForMapping(mapping: { k: TagsFilter, txt: string }) {
|
private InputElementForMapping(mapping: { k: TagsFilter, txt: string | UIElement }) {
|
||||||
return new FixedInputElement(mapping.txt, mapping.k);
|
return new FixedInputElement(mapping.txt, mapping.k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,10 +416,10 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RenderAnwser(): string {
|
private RenderAnwser(): UIElement {
|
||||||
const tags = TagUtils.proprtiesToKV(this._source.data);
|
const tags = TagUtils.proprtiesToKV(this._source.data);
|
||||||
|
|
||||||
let freeform = "";
|
let freeform: UIElement = new FixedUiElement("");
|
||||||
let freeformScore = -10;
|
let freeformScore = -10;
|
||||||
if (this._freeform !== undefined && this._source.data[this._freeform.key] !== undefined) {
|
if (this._freeform !== undefined && this._source.data[this._freeform.key] !== undefined) {
|
||||||
freeform = this.ApplyTemplate(this._freeform.renderTemplate);
|
freeform = this.ApplyTemplate(this._freeform.renderTemplate);
|
||||||
|
@ -432,30 +427,30 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let highestScore = -100;
|
let highestScore = -100;
|
||||||
let highestTemplate = undefined;
|
let highestTemplate = undefined;
|
||||||
for (const oneOnOneElement of this._mapping.concat(this._renderMapping)) {
|
for (const oneOnOneElement of this._mapping.concat(this._renderMapping)) {
|
||||||
if (oneOnOneElement.k == null ||
|
if (oneOnOneElement.k == null ||
|
||||||
oneOnOneElement.k.matches(tags)) {
|
oneOnOneElement.k.matches(tags)) {
|
||||||
// We have found a matching key -> we use the template, but only if it scores better
|
// We have found a matching key -> we use the template, but only if it scores better
|
||||||
let score = oneOnOneElement.priority ??
|
let score = oneOnOneElement.priority ??
|
||||||
(oneOnOneElement.k === null ? -1 : 0);
|
(oneOnOneElement.k === null ? -1 : 0);
|
||||||
if (score > highestScore) {
|
if (score > highestScore) {
|
||||||
highestScore = score;
|
highestScore = score;
|
||||||
highestTemplate = oneOnOneElement.txt
|
highestTemplate = oneOnOneElement.txt
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (freeformScore > highestScore) {
|
if (freeformScore > highestScore) {
|
||||||
return freeform;
|
return freeform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (highestTemplate !== undefined) {
|
||||||
|
// we render the found template
|
||||||
|
return this.ApplyTemplate(highestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
if (highestTemplate !== undefined) {
|
|
||||||
// we render the found template
|
|
||||||
return this._primer + this.ApplyTemplate(highestTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,23 +459,24 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
if (this.IsQuestioning() || this._editMode.data) {
|
if (this.IsQuestioning() || this._editMode.data) {
|
||||||
// Not yet known or questioning, we have to ask a question
|
// Not yet known or questioning, we have to ask a question
|
||||||
|
|
||||||
|
const question = this._question.Render();
|
||||||
|
|
||||||
return "<div class='question'>" +
|
return "<div class='question'>" +
|
||||||
"<span class='question-text'>" + this._question + "</span>" +
|
"<span class='question-text'>" + question + "</span>" +
|
||||||
(this._question !== "" ? "<br/>" : "") +
|
(question !== "" ? "<br/>" : "") +
|
||||||
"<div>"+ this._questionElement.Render() +"</div>"+
|
"<div>" + this._questionElement.Render() + "</div>" +
|
||||||
this._skipButton.Render() +
|
this._skipButton.Render() +
|
||||||
this._saveButton.Render() +
|
this._saveButton.Render() +
|
||||||
"</div>"
|
"</div>"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.IsKnown()) {
|
if (this.IsKnown()) {
|
||||||
const html = this.RenderAnwser();
|
const html = this.RenderAnwser().Render();
|
||||||
if (html == "") {
|
if (html == "") {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
let editButton = "";
|
let editButton = "";
|
||||||
if(this._userDetails.data.loggedIn){
|
if (this._userDetails.data.loggedIn && this._question !== undefined) {
|
||||||
editButton = this._editButton.Render();
|
editButton = this._editButton.Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,12 +495,15 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
return this._priority;
|
return this._priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApplyTemplate(template: string): string {
|
private ApplyTemplate(template: string | UIElement): UIElement {
|
||||||
|
if (template instanceof UIElement) {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
const tags = this._tagsPreprocessor(this._source.data);
|
const tags = this._tagsPreprocessor(this._source.data);
|
||||||
return TagUtils.ApplyTemplate(template, tags);
|
return new FixedUiElement(TagUtils.ApplyTemplate(template, tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InnerUpdate(htmlElement: HTMLElement) {
|
InnerUpdate(htmlElement: HTMLElement) {
|
||||||
super.InnerUpdate(htmlElement);
|
super.InnerUpdate(htmlElement);
|
||||||
this._questionElement.Update(); // Another manual update for them
|
this._questionElement.Update(); // Another manual update for them
|
||||||
|
|
|
@ -123,6 +123,7 @@ export class OsmConnection {
|
||||||
public preferenceSources : any = {}
|
public preferenceSources : any = {}
|
||||||
|
|
||||||
public GetPreference(key: string) : UIEventSource<string>{
|
public GetPreference(key: string) : UIEventSource<string>{
|
||||||
|
key = "mapcomplete-"+key;
|
||||||
if (this.preferenceSources[key] !== undefined) {
|
if (this.preferenceSources[key] !== undefined) {
|
||||||
return this.preferenceSources[key];
|
return this.preferenceSources[key];
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,16 @@ import {UIElement} from "../UI/UIElement";
|
||||||
export class StrayClickHandler {
|
export class StrayClickHandler {
|
||||||
private _basemap: Basemap;
|
private _basemap: Basemap;
|
||||||
private _lastMarker;
|
private _lastMarker;
|
||||||
private _leftMessage: UIEventSource<() => UIElement>;
|
private _fullScreenMessage: UIEventSource<UIElement>;
|
||||||
private _uiToShow: (() => UIElement);
|
private _uiToShow: (() => UIElement);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
basemap: Basemap,
|
basemap: Basemap,
|
||||||
selectElement: UIEventSource<any>,
|
selectElement: UIEventSource<any>,
|
||||||
leftMessage: UIEventSource<() => UIElement>,
|
fullScreenMessage: UIEventSource<UIElement>,
|
||||||
uiToShow: (() => UIElement)) {
|
uiToShow: (() => UIElement)) {
|
||||||
this._basemap = basemap;
|
this._basemap = basemap;
|
||||||
this._leftMessage = leftMessage;
|
this._fullScreenMessage = fullScreenMessage;
|
||||||
this._uiToShow = uiToShow;
|
this._uiToShow = uiToShow;
|
||||||
const self = this;
|
const self = this;
|
||||||
const map = basemap.map;
|
const map = basemap.map;
|
||||||
|
@ -38,7 +38,7 @@ export class StrayClickHandler {
|
||||||
self._lastMarker.bindPopup(popup).openPopup();
|
self._lastMarker.bindPopup(popup).openPopup();
|
||||||
|
|
||||||
self._lastMarker.on("click", () => {
|
self._lastMarker.on("click", () => {
|
||||||
leftMessage.setData(self._uiToShow);
|
fullScreenMessage.setData(self._uiToShow());
|
||||||
});
|
});
|
||||||
uiElement.Update();
|
uiElement.Update();
|
||||||
uiElement.Activate();
|
uiElement.Activate();
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class CenterMessageBox extends UIElement {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerRender(): string {
|
InnerRender(): string {
|
||||||
|
|
||||||
if (this._centermessage.data != "") {
|
if (this._centermessage.data != "") {
|
||||||
return this._centermessage.data;
|
return this._centermessage.data;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {TagRenderingOptions} from "../Customizations/TagRendering";
|
||||||
import {OsmLink} from "../Customizations/Questions/OsmLink";
|
import {OsmLink} from "../Customizations/Questions/OsmLink";
|
||||||
import {WikipediaLink} from "../Customizations/Questions/WikipediaLink";
|
import {WikipediaLink} from "../Customizations/Questions/WikipediaLink";
|
||||||
import {And} from "../Logic/TagsFilter";
|
import {And} from "../Logic/TagsFilter";
|
||||||
import {TagDependantUIElement} from "../Customizations/UIElementConstructor";
|
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../Customizations/UIElementConstructor";
|
||||||
|
|
||||||
export class FeatureInfoBox extends UIElement {
|
export class FeatureInfoBox extends UIElement {
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export class FeatureInfoBox extends UIElement {
|
||||||
constructor(
|
constructor(
|
||||||
tagsES: UIEventSource<any>,
|
tagsES: UIEventSource<any>,
|
||||||
title: TagRenderingOptions,
|
title: TagRenderingOptions,
|
||||||
elementsToShow: TagRenderingOptions[],
|
elementsToShow: TagDependantUIElementConstructor[],
|
||||||
changes: Changes,
|
changes: Changes,
|
||||||
userDetails: UIEventSource<UserDetails>
|
userDetails: UIEventSource<UserDetails>
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -34,14 +34,14 @@ class ImageCarouselWithUpload extends TagDependantUIElement {
|
||||||
const changes = dependencies.changes;
|
const changes = dependencies.changes;
|
||||||
this._imageElement = new ImageCarousel(tags, changes);
|
this._imageElement = new ImageCarousel(tags, changes);
|
||||||
const userDetails = changes.login.userDetails;
|
const userDetails = changes.login.userDetails;
|
||||||
const license = changes.login.GetPreference( "mapcomplete-pictures-license");
|
const license = changes.login.GetPreference( "pictures-license");
|
||||||
this._pictureUploader = new OsmImageUploadHandler(tags,
|
this._pictureUploader = new OsmImageUploadHandler(tags,
|
||||||
userDetails, license,
|
userDetails, license,
|
||||||
changes, this._imageElement.slideshow).getUI();
|
changes, this._imageElement.slideshow).getUI();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerRender(): string {
|
InnerRender(): string {
|
||||||
return this._imageElement.Render() +
|
return this._imageElement.Render() +
|
||||||
this._pictureUploader.Render();
|
this._pictureUploader.Render();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {Imgur} from "../Logic/Imgur";
|
||||||
import {UserDetails} from "../Logic/OsmConnection";
|
import {UserDetails} from "../Logic/OsmConnection";
|
||||||
import {DropDown} from "./Input/DropDown";
|
import {DropDown} from "./Input/DropDown";
|
||||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||||
|
import Translations from "./i18n/Translations";
|
||||||
|
|
||||||
export class ImageUploadFlow extends UIElement {
|
export class ImageUploadFlow extends UIElement {
|
||||||
private _licensePicker: UIElement;
|
private _licensePicker: UIElement;
|
||||||
|
@ -66,7 +67,7 @@ export class ImageUploadFlow extends UIElement {
|
||||||
|
|
||||||
"<div class='imageflow-file-input-wrapper'>" +
|
"<div class='imageflow-file-input-wrapper'>" +
|
||||||
"<img src='./assets/camera-plus.svg' alt='upload image'/> " +
|
"<img src='./assets/camera-plus.svg' alt='upload image'/> " +
|
||||||
"<span class='imageflow-add-picture'>Add a picture</span>" +
|
"<span class='imageflow-add-picture'>"+Translations.general.uploadAPicture.R()+"</span>" +
|
||||||
"<div class='break'></div>" +
|
"<div class='break'></div>" +
|
||||||
"</div>" +
|
"</div>" +
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,10 @@ export class DropDown<T> extends InputElement<T> {
|
||||||
|
|
||||||
|
|
||||||
InnerRender(): string {
|
InnerRender(): string {
|
||||||
|
if(this._values.length <=1){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
let options = "";
|
let options = "";
|
||||||
for (let i = 0; i < this._values.length; i++) {
|
for (let i = 0; i < this._values.length; i++) {
|
||||||
options += "<option value='" + i + "'>" + this._values[i].shown.InnerRender() + "</option>"
|
options += "<option value='" + i + "'>" + this._values[i].shown.InnerRender() + "</option>"
|
||||||
|
@ -65,8 +68,12 @@ export class DropDown<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerUpdate(element) {
|
protected InnerUpdate(element) {
|
||||||
|
|
||||||
|
|
||||||
var e = document.getElementById("dropdown-" + this.id);
|
var e = document.getElementById("dropdown-" + this.id);
|
||||||
|
if(e === null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
const self = this;
|
const self = this;
|
||||||
e.onchange = (() => {
|
e.onchange = (() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
@ -105,7 +105,6 @@ export class TextField<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
IsValid(t: T): boolean {
|
IsValid(t: T): boolean {
|
||||||
console.log("TXT IS valid?",t,this._toString(t))
|
|
||||||
if(t === undefined || t === null){
|
if(t === undefined || t === null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ import {UIElement} from "./UIElement";
|
||||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||||
|
|
||||||
export class MessageBoxHandler {
|
export class MessageBoxHandler {
|
||||||
private _uielement: UIEventSource<() => UIElement>;
|
private _uielement: UIEventSource<UIElement>;
|
||||||
|
|
||||||
constructor(uielement: UIEventSource<() => UIElement>,
|
constructor(uielement: UIEventSource<UIElement>,
|
||||||
onClear: (() => void)) {
|
onClear: (() => void)) {
|
||||||
this._uielement = uielement;
|
this._uielement = uielement;
|
||||||
this.listenTo(uielement);
|
this.listenTo(uielement);
|
||||||
|
@ -22,14 +22,13 @@ export class MessageBoxHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new VariableUiElement(new UIEventSource<string>("<h2>Return to the map</h2>"),
|
new VariableUiElement(new UIEventSource<string>("<h2>Return to the map</h2>"))
|
||||||
() => {
|
.onClick(() => {
|
||||||
document.getElementById("to-the-map").onclick = function () {
|
console.log("Clicked 'return to the map'")
|
||||||
uielement.setData(undefined);
|
uielement.setData(undefined);
|
||||||
onClear();
|
onClear();
|
||||||
}
|
})
|
||||||
}
|
.AttachTo("to-the-map");
|
||||||
).AttachTo("to-the-map");
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,7 +54,7 @@ export class MessageBoxHandler {
|
||||||
location.hash = "#element"
|
location.hash = "#element"
|
||||||
wrapper.classList.remove("hidden");
|
wrapper.classList.remove("hidden");
|
||||||
|
|
||||||
gen()
|
gen
|
||||||
?.HideOnEmpty(true)
|
?.HideOnEmpty(true)
|
||||||
?.AttachTo("messagesboxmobile")
|
?.AttachTo("messagesboxmobile")
|
||||||
?.Activate();
|
?.Activate();
|
||||||
|
|
|
@ -21,7 +21,7 @@ export class PendingChanges extends UIElement {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerRender(): string {
|
InnerRender(): string {
|
||||||
if (this._isSaving.data) {
|
if (this._isSaving.data) {
|
||||||
return "<span class='alert'>Saving</span>";
|
return "<span class='alert'>Saving</span>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,10 @@ export abstract class UIElement {
|
||||||
|
|
||||||
Update(): void {
|
Update(): void {
|
||||||
let element = document.getElementById(this.id);
|
let element = document.getElementById(this.id);
|
||||||
if (element === null || element === undefined) {
|
if (element === undefined || element === null) {
|
||||||
// The element is not painted
|
// The element is not painted
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
element.innerHTML = this.InnerRender();
|
element.innerHTML = this.InnerRender();
|
||||||
if (this._hideIfEmpty) {
|
if (this._hideIfEmpty) {
|
||||||
if (element.innerHTML === "") {
|
if (element.innerHTML === "") {
|
||||||
|
|
|
@ -66,5 +66,16 @@ export class UIEventSource<T>{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public syncWith(otherSource: UIEventSource<T>){
|
||||||
|
this.addCallback((latest) => otherSource.setData(latest));
|
||||||
|
const self = this;
|
||||||
|
otherSource.addCallback((latest) => self.setData(latest));
|
||||||
|
if(this.data === undefined){
|
||||||
|
this.setData(otherSource.data);
|
||||||
|
}else{
|
||||||
|
otherSource.setData(this.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import {Basemap} from "../Logic/Basemap";
|
||||||
import L from "leaflet";
|
import L from "leaflet";
|
||||||
import {FixedUiElement} from "./Base/FixedUiElement";
|
import {FixedUiElement} from "./Base/FixedUiElement";
|
||||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||||
|
import Translations from "./i18n/Translations";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles and updates the user badge
|
* Handles and updates the user badge
|
||||||
|
@ -15,13 +16,15 @@ export class UserBadge extends UIElement {
|
||||||
private _logout: UIElement;
|
private _logout: UIElement;
|
||||||
private _basemap: Basemap;
|
private _basemap: Basemap;
|
||||||
private _homeButton: UIElement;
|
private _homeButton: UIElement;
|
||||||
|
private _languagePicker: UIElement;
|
||||||
|
|
||||||
|
|
||||||
constructor(userDetails: UIEventSource<UserDetails>,
|
constructor(userDetails: UIEventSource<UserDetails>,
|
||||||
pendingChanges: UIElement,
|
pendingChanges: UIElement,
|
||||||
|
languagePicker: UIElement,
|
||||||
basemap: Basemap) {
|
basemap: Basemap) {
|
||||||
super(userDetails);
|
super(userDetails);
|
||||||
|
this._languagePicker = languagePicker;
|
||||||
this._userDetails = userDetails;
|
this._userDetails = userDetails;
|
||||||
this._pendingChanges = pendingChanges;
|
this._pendingChanges = pendingChanges;
|
||||||
this._basemap = basemap;
|
this._basemap = basemap;
|
||||||
|
@ -61,7 +64,7 @@ export class UserBadge extends UIElement {
|
||||||
InnerRender(): string {
|
InnerRender(): string {
|
||||||
const user = this._userDetails.data;
|
const user = this._userDetails.data;
|
||||||
if (!user.loggedIn) {
|
if (!user.loggedIn) {
|
||||||
return "<div class='activate-osm-authentication'>Login with OpenStreetMap</div>";
|
return "<div class='activate-osm-authentication'>" + Translations.general.loginWithOpenStreetMap.R()+ "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,6 +117,7 @@ export class UserBadge extends UIElement {
|
||||||
" <a href='https://www.openstreetmap.org/user/" + user.name + "/history' target='_blank'><img class='small-userbadge-icon' src='./assets/star.svg' alt='star'/> " + user.csCount +
|
" <a href='https://www.openstreetmap.org/user/" + user.name + "/history' target='_blank'><img class='small-userbadge-icon' src='./assets/star.svg' alt='star'/> " + user.csCount +
|
||||||
"</a></span> " +
|
"</a></span> " +
|
||||||
this._logout.Render() +
|
this._logout.Render() +
|
||||||
|
this._languagePicker.Render() +
|
||||||
this._pendingChanges.Render() +
|
this._pendingChanges.Render() +
|
||||||
"</p>" +
|
"</p>" +
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,24 @@
|
||||||
import { UIEventSource } from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
|
import {OsmConnection} from "../../Logic/OsmConnection";
|
||||||
|
|
||||||
|
|
||||||
const LANGUAGE_KEY = 'language'
|
|
||||||
|
|
||||||
export default class Locale {
|
export default class Locale {
|
||||||
public static language: UIEventSource<string> = new UIEventSource(Locale.getInitialLanguage())
|
public static language: UIEventSource<string> = Locale.getInitialLanguage()
|
||||||
|
|
||||||
public static init() {
|
|
||||||
Locale.language.addCallback(data => {
|
|
||||||
localStorage.setItem(LANGUAGE_KEY, data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private static getInitialLanguage() {
|
private static getInitialLanguage() {
|
||||||
return localStorage.getItem(LANGUAGE_KEY)
|
// The key to save in local storage
|
||||||
|
const LANGUAGE_KEY = 'language'
|
||||||
|
|
||||||
|
const lng = new UIEventSource("en");
|
||||||
|
const saved = localStorage.getItem(LANGUAGE_KEY);
|
||||||
|
lng.setData(saved);
|
||||||
|
|
||||||
|
|
||||||
|
lng.addCallback(data => {
|
||||||
|
console.log("Selected language", data);
|
||||||
|
localStorage.setItem(LANGUAGE_KEY, data)
|
||||||
|
});
|
||||||
|
|
||||||
|
return lng;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,30 @@
|
||||||
import { UIElement } from "../UIElement"
|
import { UIElement } from "../UIElement"
|
||||||
import Locale from "./Locale"
|
import Locale from "./Locale"
|
||||||
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
|
|
||||||
|
|
||||||
export default class Translation extends UIElement{
|
export default class Translation extends UIElement {
|
||||||
protected InnerRender(): string {
|
|
||||||
return this.translations[Locale.language.data]
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly translations: object
|
public readonly translations: object
|
||||||
|
|
||||||
constructor(translations: object) {
|
constructor(translations: object) {
|
||||||
super(Locale.language)
|
super(Locale.language)
|
||||||
this.translations = translations
|
this.translations = translations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public R(): string {
|
||||||
|
return new Translation(this.translations).Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerRender(): string {
|
||||||
|
const txt = this.translations[Locale.language.data];
|
||||||
|
if (txt !== undefined) {
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
const en = this.translations["en"];
|
||||||
|
console.warn("No translation for language ", Locale.language.data, "for",en);
|
||||||
|
return en;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,42 @@
|
||||||
import Translation from "./Translation";
|
import Translation from "./Translation";
|
||||||
|
import {UIElement} from "../UIElement";
|
||||||
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
|
|
||||||
|
|
||||||
export default class Translations {
|
export default class Translations {
|
||||||
static t = {
|
static cylofix = {
|
||||||
cylofix: {
|
title: new Translation({
|
||||||
title: new Translation({en: 'Cyclofix bicycle infrastructure', nl: 'Cyclofix fietsinfrastructuur', fr: 'TODO: FRENCH TRANSLATION'}),
|
en: 'Cyclofix bicycle infrastructure',
|
||||||
description: new Translation({
|
nl: 'Cyclofix fietsinfrastructuur',
|
||||||
en: "On this map we want to collect data about the whereabouts of bicycle pumps and public racks in Brussels." +
|
fr: 'TODO: FRENCH TRANSLATION'
|
||||||
"As a result, cyclists will be able to quickly find the nearest infrastructure for their needs.",
|
}),
|
||||||
nl: "Op deze kaart willen we gegevens verzamelen over de locatie van fietspompen en openbare stelplaatsen in Brussel." +
|
description: new Translation({
|
||||||
"Hierdoor kunnen fietsers snel de dichtstbijzijnde infrastructuur vinden die voldoet aan hun behoeften.",
|
en: "On this map we want to collect data about the whereabouts of bicycle pumps and public racks in Brussels." +
|
||||||
fr: "Sur cette carte, nous voulons collecter des données sur la localisation des pompes à vélo et des supports publics à Bruxelles." +
|
"As a result, cyclists will be able to quickly find the nearest infrastructure for their needs.",
|
||||||
"Les cyclistes pourront ainsi trouver rapidement l'infrastructure la plus proche de leurs besoins."
|
nl: "Op deze kaart willen we gegevens verzamelen over de locatie van fietspompen en openbare stelplaatsen in Brussel." +
|
||||||
})
|
"Hierdoor kunnen fietsers snel de dichtstbijzijnde infrastructuur vinden die voldoet aan hun behoeften.",
|
||||||
}
|
fr: "Sur cette carte, nous voulons collecter des données sur la localisation des pompes à vélo et des supports publics à Bruxelles." +
|
||||||
|
"Les cyclistes pourront ainsi trouver rapidement l'infrastructure la plus proche de leurs besoins."
|
||||||
|
})
|
||||||
|
};
|
||||||
|
static general = {
|
||||||
|
loginWithOpenStreetMap: new Translation({
|
||||||
|
en: "Click here to login with OpenStreetMap",
|
||||||
|
nl: "Klik hier op je aan te melden met OpenStreetMap"
|
||||||
|
}),
|
||||||
|
uploadAPicture: new Translation({
|
||||||
|
en: "Add a picture",
|
||||||
|
nl: "Voeg een foto toe"
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static W(s: string | UIElement):
|
||||||
|
UIElement {
|
||||||
|
if (s instanceof UIElement) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return new FixedUiElement(s);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
15
index.css
15
index.css
|
@ -307,23 +307,26 @@ form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#to-the-map {
|
#to-the-map {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#to-the-map h2{
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
height: 4em;
|
height: 4em;
|
||||||
|
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
padding-right: 2em;
|
padding-right: 2em;
|
||||||
|
padding-top: 1em;
|
||||||
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: right;
|
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #7ebc6f;
|
background-color: #7ebc6f;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,17 +28,13 @@
|
||||||
Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is
|
Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is
|
||||||
blocking it.
|
blocking it.
|
||||||
</div>
|
</div>
|
||||||
|
<div id="language-select"></div>
|
||||||
<br/>
|
<br/>
|
||||||
<div id="searchbox"></div>
|
<div id="searchbox"></div>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<div id="messagesbox-wrapper">
|
<div id="messagesbox-wrapper">
|
||||||
<div id="collapseButton"></div>
|
<div id="collapseButton"></div>
|
||||||
<select id="language-select">
|
|
||||||
<option>EN</option>
|
|
||||||
<option>NL</option>
|
|
||||||
<option>FR</option>
|
|
||||||
</select>
|
|
||||||
<div id="messagesbox"></div>
|
<div id="messagesbox"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
79
index.ts
79
index.ts
|
@ -25,7 +25,10 @@ import {All} from "./Customizations/Layouts/All";
|
||||||
import Translations from "./UI/i18n/Translations";
|
import Translations from "./UI/i18n/Translations";
|
||||||
import Translation from "./UI/i18n/Translation";
|
import Translation from "./UI/i18n/Translation";
|
||||||
import Locale from "./UI/i18n/Locale";
|
import Locale from "./UI/i18n/Locale";
|
||||||
import { Layout } from "./Customizations/Layout";
|
import {Layout} from "./Customizations/Layout";
|
||||||
|
import {DropDown} from "./UI/Input/DropDown";
|
||||||
|
import {FixedInputElement} from "./UI/Input/FixedInputElement";
|
||||||
|
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
||||||
|
|
||||||
|
|
||||||
// --------------------- Read the URL parameters -----------------
|
// --------------------- Read the URL parameters -----------------
|
||||||
|
@ -90,22 +93,29 @@ if (paramDict.test) {
|
||||||
const layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout];
|
const layoutToUse: Layout = AllKnownLayouts.allSets[defaultLayout];
|
||||||
console.log("Using layout: ", layoutToUse.name);
|
console.log("Using layout: ", layoutToUse.name);
|
||||||
|
|
||||||
document.title = layoutToUse.title.Render();
|
document.title = layoutToUse.title.InnerRender();
|
||||||
Locale.language.addCallback(e => {
|
Locale.language.addCallback(e => {
|
||||||
document.title = layoutToUse.title.Render();
|
document.title = layoutToUse.title.InnerRender();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// ----------------- Setup a few event sources -------------
|
// ----------------- Setup a few event sources -------------
|
||||||
|
|
||||||
|
|
||||||
|
// const LanguageSelect = document.getElementById('language-select') as HTMLOptionElement
|
||||||
|
// eLanguageSelect.addEventListener('selectionchange')
|
||||||
|
|
||||||
|
|
||||||
// The message that should be shown at the center of the screen
|
// The message that should be shown at the center of the screen
|
||||||
const centerMessage = new UIEventSource<string>("");
|
const centerMessage = new UIEventSource<string>("");
|
||||||
|
|
||||||
// The countdown: if set to e.g. ten, it'll start counting down. When reaching zero, changes will be saved. NB: this is implemented later, not in the eventSource
|
// The countdown: if set to e.g. ten, it'll start counting down. When reaching zero, changes will be saved. NB: this is implemented later, not in the eventSource
|
||||||
const secondsTillChangesAreSaved = new UIEventSource<number>(0);
|
const secondsTillChangesAreSaved = new UIEventSource<number>(0);
|
||||||
|
|
||||||
const leftMessage = new UIEventSource<() => UIElement>(undefined);
|
// const leftMessage = new UIEventSource<() => UIElement>(undefined);
|
||||||
|
|
||||||
|
// This message is shown full screen on mobile devices
|
||||||
|
const fullScreenMessage = new UIEventSource<UIElement>(undefined);
|
||||||
|
|
||||||
const selectedElement = new UIEventSource<any>(undefined);
|
const selectedElement = new UIEventSource<any>(undefined);
|
||||||
|
|
||||||
|
@ -119,9 +129,18 @@ const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: numb
|
||||||
|
|
||||||
// ----------------- Prepare the important objects -----------------
|
// ----------------- Prepare the important objects -----------------
|
||||||
|
|
||||||
|
const osmConnection = new OsmConnection(dryRun);
|
||||||
|
|
||||||
|
|
||||||
|
Locale.language.syncWith(osmConnection.GetPreference("language"));
|
||||||
|
|
||||||
|
window.setLanguage = function (language: string) {
|
||||||
|
Locale.language.setData(language)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const saveTimeout = 30000; // After this many milliseconds without changes, saves are sent of to OSM
|
const saveTimeout = 30000; // After this many milliseconds without changes, saves are sent of to OSM
|
||||||
const allElements = new ElementStorage();
|
const allElements = new ElementStorage();
|
||||||
const osmConnection = new OsmConnection(dryRun);
|
|
||||||
const changes = new Changes(
|
const changes = new Changes(
|
||||||
"Beantwoorden van vragen met #MapComplete voor vragenset #" + layoutToUse.name,
|
"Beantwoorden van vragen met #MapComplete voor vragenset #" + layoutToUse.name,
|
||||||
osmConnection, allElements);
|
osmConnection, allElements);
|
||||||
|
@ -191,8 +210,13 @@ const layerUpdater = new LayerUpdater(bm, minZoom, flayers);
|
||||||
|
|
||||||
// ------------------ Setup various UI elements ------------
|
// ------------------ Setup various UI elements ------------
|
||||||
|
|
||||||
|
let languagePicker = new DropDown(" ", layoutToUse.supportedLanguages.map(lang => {
|
||||||
|
return {value: lang, shown: lang}
|
||||||
|
}
|
||||||
|
), Locale.language).AttachTo("language-select");
|
||||||
|
|
||||||
new StrayClickHandler(bm, selectedElement, leftMessage, () => {
|
|
||||||
|
new StrayClickHandler(bm, selectedElement, fullScreenMessage, () => {
|
||||||
return new SimpleAddUI(bm.Location,
|
return new SimpleAddUI(bm.Location,
|
||||||
bm.LastClickLocation,
|
bm.LastClickLocation,
|
||||||
changes,
|
changes,
|
||||||
|
@ -204,7 +228,7 @@ new StrayClickHandler(bm, selectedElement, leftMessage, () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the questions and information for the selected element on the leftMessage
|
* Show the questions and information for the selected element on the fullScreen
|
||||||
*/
|
*/
|
||||||
selectedElement.addCallback((data) => {
|
selectedElement.addCallback((data) => {
|
||||||
// Which is the applicable set?
|
// Which is the applicable set?
|
||||||
|
@ -213,14 +237,16 @@ selectedElement.addCallback((data) => {
|
||||||
const applicable = layer.overpassFilter.matches(TagUtils.proprtiesToKV(data));
|
const applicable = layer.overpassFilter.matches(TagUtils.proprtiesToKV(data));
|
||||||
if (applicable) {
|
if (applicable) {
|
||||||
// This layer is the layer that gives the questions
|
// This layer is the layer that gives the questions
|
||||||
leftMessage.setData(() =>
|
|
||||||
new FeatureInfoBox(
|
const featureBox = new FeatureInfoBox(
|
||||||
allElements.getElement(data.id),
|
allElements.getElement(data.id),
|
||||||
layer.title,
|
layer.title,
|
||||||
layer.elementsToShow,
|
layer.elementsToShow,
|
||||||
changes,
|
changes,
|
||||||
osmConnection.userDetails
|
osmConnection.userDetails
|
||||||
));
|
);
|
||||||
|
|
||||||
|
fullScreenMessage.setData(featureBox);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +257,10 @@ selectedElement.addCallback((data) => {
|
||||||
const pendingChanges = new PendingChanges(
|
const pendingChanges = new PendingChanges(
|
||||||
changes, secondsTillChangesAreSaved,);
|
changes, secondsTillChangesAreSaved,);
|
||||||
|
|
||||||
new UserBadge(osmConnection.userDetails, pendingChanges, bm)
|
new UserBadge(osmConnection.userDetails,
|
||||||
|
pendingChanges,
|
||||||
|
new FixedUiElement(""),
|
||||||
|
bm)
|
||||||
.AttachTo('userbadge');
|
.AttachTo('userbadge');
|
||||||
|
|
||||||
new SearchAndGo(bm).AttachTo("searchbox");
|
new SearchAndGo(bm).AttachTo("searchbox");
|
||||||
|
@ -239,7 +268,7 @@ new SearchAndGo(bm).AttachTo("searchbox");
|
||||||
new CollapseButton("messagesbox")
|
new CollapseButton("messagesbox")
|
||||||
.AttachTo("collapseButton");
|
.AttachTo("collapseButton");
|
||||||
|
|
||||||
var welcomeMessage = () => {
|
var generateWelcomeMessage = () => {
|
||||||
return new VariableUiElement(
|
return new VariableUiElement(
|
||||||
osmConnection.userDetails.map((userdetails) => {
|
osmConnection.userDetails.map((userdetails) => {
|
||||||
var login = layoutToUse.gettingStartedPlzLogin;
|
var login = layoutToUse.gettingStartedPlzLogin;
|
||||||
|
@ -254,11 +283,11 @@ var welcomeMessage = () => {
|
||||||
osmConnection.registerActivateOsmAUthenticationClass()
|
osmConnection.registerActivateOsmAUthenticationClass()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
leftMessage.setData(welcomeMessage);
|
generateWelcomeMessage().AttachTo("messagesbox");
|
||||||
welcomeMessage().AttachTo("messagesbox");
|
fullScreenMessage.setData(generateWelcomeMessage());
|
||||||
|
|
||||||
|
|
||||||
var messageBox = new MessageBoxHandler(leftMessage, () => {
|
var messageBox = new MessageBoxHandler(fullScreenMessage, () => {
|
||||||
selectedElement.setData(undefined)
|
selectedElement.setData(undefined)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -286,13 +315,3 @@ locationControl.ping();
|
||||||
messageBox.update();
|
messageBox.update();
|
||||||
|
|
||||||
|
|
||||||
// --- Locale ---
|
|
||||||
|
|
||||||
Locale.init()
|
|
||||||
|
|
||||||
window.setLanguage = function(language:string) {
|
|
||||||
Locale.language.setData(language)
|
|
||||||
}
|
|
||||||
|
|
||||||
// const eLanguageSelect = document.getElementById('language-select') as HTMLOptionElement
|
|
||||||
// eLanguageSelect.addEventListener('selectionchange')
|
|
||||||
|
|
10
test.ts
10
test.ts
|
@ -1 +1,9 @@
|
||||||
console.log("Hello world")
|
import {DropDown} from "./UI/Input/DropDown";
|
||||||
|
import Locale from "./UI/i18n/Locale";
|
||||||
|
|
||||||
|
console.log("Hello world")
|
||||||
|
|
||||||
|
let languagePicker = new DropDown("", ["en", "nl"].map(lang => {
|
||||||
|
return {value: lang, shown: lang}
|
||||||
|
}
|
||||||
|
), Locale.language).AttachTo("maindiv");
|
Loading…
Reference in a new issue