forked from MapComplete/MapComplete
More fixes
This commit is contained in:
parent
2ae380f1a6
commit
9a73ae4c47
21 changed files with 203 additions and 148 deletions
|
@ -7,8 +7,6 @@ import {Utils} from "../../Utils";
|
||||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||||
import {And} from "../../Logic/Tags/And";
|
import {And} from "../../Logic/Tags/And";
|
||||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||||
import {UIElement} from "../../UI/UIElement";
|
|
||||||
import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation";
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* The parsed version of TagRenderingConfigJSON
|
* The parsed version of TagRenderingConfigJSON
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Utils } from "../Utils";
|
||||||
|
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
|
|
||||||
public static vNumber = "0.8.0";
|
public static vNumber = "0.8.0-rc0";
|
||||||
|
|
||||||
// The user journey states thresholds when a new feature gets unlocked
|
// The user journey states thresholds when a new feature gets unlocked
|
||||||
public static userJourney = {
|
public static userJourney = {
|
||||||
|
|
|
@ -20,6 +20,7 @@ export class SubtleButton extends UIElement {
|
||||||
|
|
||||||
private static generateContent(imageUrl: string | BaseUIElement, messageT: string | BaseUIElement, linkTo: { url: string | UIEventSource<string>, newTab?: boolean } = undefined): BaseUIElement {
|
private static generateContent(imageUrl: string | BaseUIElement, messageT: string | BaseUIElement, linkTo: { url: string | UIEventSource<string>, newTab?: boolean } = undefined): BaseUIElement {
|
||||||
const message = Translations.W(messageT);
|
const message = Translations.W(messageT);
|
||||||
|
message
|
||||||
let img;
|
let img;
|
||||||
if ((imageUrl ?? "") === "") {
|
if ((imageUrl ?? "") === "") {
|
||||||
img = undefined;
|
img = undefined;
|
||||||
|
@ -36,7 +37,7 @@ export class SubtleButton extends UIElement {
|
||||||
return new Combine([
|
return new Combine([
|
||||||
image,
|
image,
|
||||||
message?.SetClass("blcok ml-4 overflow-ellipsis"),
|
message?.SetClass("blcok ml-4 overflow-ellipsis"),
|
||||||
]).SetClass("flex group");
|
]).SetClass("flex group w-full");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ export class SubtleButton extends UIElement {
|
||||||
new Combine([
|
new Combine([
|
||||||
image,
|
image,
|
||||||
message?.SetClass("block ml-4 overflow-ellipsis")
|
message?.SetClass("block ml-4 overflow-ellipsis")
|
||||||
]).SetClass("flex group"),
|
]).SetClass("flex group w-full"),
|
||||||
linkTo.url,
|
linkTo.url,
|
||||||
linkTo.newTab ?? false
|
linkTo.newTab ?? false
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,14 +23,14 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
|
||||||
const layoutToUse = State.state.layoutToUse.data;
|
const layoutToUse = State.state.layoutToUse.data;
|
||||||
super (
|
super (
|
||||||
() => layoutToUse.title.Clone(),
|
() => layoutToUse.title.Clone(),
|
||||||
() => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails),
|
() => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails, isShown),
|
||||||
"welcome" ,isShown
|
"welcome" ,isShown
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ConstructBaseTabs(layoutToUse: LayoutConfig): { header: string | BaseUIElement; content: BaseUIElement }[]{
|
private static ConstructBaseTabs(layoutToUse: LayoutConfig, isShown: UIEventSource<boolean>): { header: string | BaseUIElement; content: BaseUIElement }[]{
|
||||||
|
|
||||||
let welcome: BaseUIElement = new ThemeIntroductionPanel();
|
let welcome: BaseUIElement = new ThemeIntroductionPanel(isShown);
|
||||||
if (layoutToUse.id === personal.id) {
|
if (layoutToUse.id === personal.id) {
|
||||||
welcome = new PersonalLayersPanel();
|
welcome = new PersonalLayersPanel();
|
||||||
}
|
}
|
||||||
|
@ -58,10 +58,10 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GenerateContents(layoutToUse: LayoutConfig, userDetails: UIEventSource<UserDetails>) {
|
private static GenerateContents(layoutToUse: LayoutConfig, userDetails: UIEventSource<UserDetails>, isShown: UIEventSource<boolean>) {
|
||||||
|
|
||||||
const tabs = FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse)
|
const tabs = FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse, isShown)
|
||||||
const tabsWithAboutMc = [...FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse)]
|
const tabsWithAboutMc = [...FullWelcomePaneWithTabs.ConstructBaseTabs(layoutToUse, isShown)]
|
||||||
tabsWithAboutMc.push({
|
tabsWithAboutMc.push({
|
||||||
header: Svg.help,
|
header: Svg.help,
|
||||||
content: new Combine([Translations.t.general.aboutMapcomplete.Clone(), "<br/>Version " + Constants.vNumber])
|
content: new Combine([Translations.t.general.aboutMapcomplete.Clone(), "<br/>Version " + Constants.vNumber])
|
||||||
|
|
|
@ -4,26 +4,45 @@ import LanguagePicker from "../LanguagePicker";
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||||
import Toggle from "../Input/Toggle";
|
import Toggle from "../Input/Toggle";
|
||||||
|
import {SubtleButton} from "../Base/SubtleButton";
|
||||||
|
import Svg from "../../Svg";
|
||||||
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
|
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||||
|
|
||||||
export default class ThemeIntroductionPanel extends VariableUiElement {
|
export default class ThemeIntroductionPanel extends VariableUiElement {
|
||||||
|
|
||||||
constructor() {
|
constructor(isShown: UIEventSource<boolean>) {
|
||||||
|
|
||||||
const languagePicker =
|
const languagePicker =
|
||||||
new VariableUiElement(
|
new VariableUiElement(
|
||||||
State.state.layoutToUse.map(layout => LanguagePicker.CreateLanguagePicker(layout.language, Translations.t.general.pickLanguage.Clone()))
|
State.state.layoutToUse.map(layout => LanguagePicker.CreateLanguagePicker(layout.language, Translations.t.general.pickLanguage.Clone()))
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
const toTheMap = new SubtleButton(
|
||||||
|
new FixedUiElement(""),
|
||||||
|
Translations.t.general.openTheMap.Clone().SetClass("text-xl font-bold w-full text-center")
|
||||||
|
).onClick(() =>{
|
||||||
|
isShown.setData(false)
|
||||||
|
}).SetClass("only-on-mobile")
|
||||||
|
|
||||||
const plzLogIn =
|
const plzLogIn =
|
||||||
Translations.t.general.loginWithOpenStreetMap
|
new SubtleButton(
|
||||||
.Clone()
|
Svg.osm_logo_ui(),
|
||||||
|
|
||||||
|
new Combine([Translations.t.general.loginWithOpenStreetMap
|
||||||
|
.Clone().SetClass("text-xl font-bold"),
|
||||||
|
Translations.t.general.loginOnlyNeededToEdit.Clone().SetClass("font-bold")]
|
||||||
|
).SetClass("flex flex-col text-center w-full")
|
||||||
|
)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
State.state.osmConnection.AttemptLogin()
|
State.state.osmConnection.AttemptLogin()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const welcomeBack = Translations.t.general.welcomeBack.Clone();
|
const welcomeBack = Translations.t.general.welcomeBack.Clone();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const loginStatus =
|
const loginStatus =
|
||||||
new Toggle(
|
new Toggle(
|
||||||
|
@ -40,6 +59,7 @@ export default class ThemeIntroductionPanel extends VariableUiElement {
|
||||||
super(State.state.layoutToUse.map (layout => new Combine([
|
super(State.state.layoutToUse.map (layout => new Combine([
|
||||||
layout.description.Clone(),
|
layout.description.Clone(),
|
||||||
"<br/><br/>",
|
"<br/><br/>",
|
||||||
|
toTheMap,
|
||||||
loginStatus,
|
loginStatus,
|
||||||
layout.descriptionTail.Clone(),
|
layout.descriptionTail.Clone(),
|
||||||
"<br/>",
|
"<br/>",
|
||||||
|
|
|
@ -13,7 +13,6 @@ export class SlideShow extends BaseUIElement {
|
||||||
|
|
||||||
protected InnerConstructElement(): HTMLElement {
|
protected InnerConstructElement(): HTMLElement {
|
||||||
const el = document.createElement("div")
|
const el = document.createElement("div")
|
||||||
el.classList.add("slic-carousel")
|
|
||||||
el.style.overflowX = "auto"
|
el.style.overflowX = "auto"
|
||||||
el.style.width = "min-content"
|
el.style.width = "min-content"
|
||||||
el.style.minWidth = "min-content"
|
el.style.minWidth = "min-content"
|
||||||
|
@ -25,8 +24,9 @@ export class SlideShow extends BaseUIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const element of elements ?? []) {
|
for (const element of elements ?? []) {
|
||||||
element.SetClass("block ml-1")
|
element
|
||||||
.SetStyle("width: 300px; max-height: var(--image-carousel-height); height: var(--image-carousel-height)")
|
.SetClass("block ml-1; bg-gray-200")
|
||||||
|
.SetStyle("min-width: 150; max-height: var(--image-carousel-height); min-height: var(--image-carousel-height)")
|
||||||
|
|
||||||
el.appendChild(element.ConstructElement())
|
el.appendChild(element.ConstructElement())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,77 +7,83 @@ import BaseUIElement from "../BaseUIElement";
|
||||||
* Supports multi-input
|
* Supports multi-input
|
||||||
*/
|
*/
|
||||||
export default class CheckBoxes extends InputElement<number[]> {
|
export default class CheckBoxes extends InputElement<number[]> {
|
||||||
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
|
||||||
|
|
||||||
|
|
||||||
private readonly _element : HTMLElement
|
|
||||||
|
|
||||||
private static _nextId = 0;
|
private static _nextId = 0;
|
||||||
private readonly value: UIEventSource<number[]>
|
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||||
constructor(elements: BaseUIElement[], value =new UIEventSource<number[]>([])) {
|
private readonly value: UIEventSource<number[]>
|
||||||
|
private readonly _elements: BaseUIElement[];
|
||||||
|
|
||||||
|
constructor(elements: BaseUIElement[], value = new UIEventSource<number[]>([])) {
|
||||||
super();
|
super();
|
||||||
this.value = value;
|
this.value = value;
|
||||||
elements = Utils.NoNull(elements);
|
this._elements = Utils.NoNull(elements);
|
||||||
|
this.SetClass("flex flex-col")
|
||||||
const el = document.createElement("form")
|
|
||||||
|
|
||||||
for (let i = 0; i < elements.length; i++) {
|
|
||||||
|
|
||||||
let inputI = elements[i];
|
|
||||||
const input = document.createElement("input")
|
|
||||||
const id = CheckBoxes._nextId
|
|
||||||
CheckBoxes._nextId ++;
|
|
||||||
input.id = "checkbox"+id
|
|
||||||
|
|
||||||
input.type = "checkbox"
|
|
||||||
const label = document.createElement("label")
|
|
||||||
label.htmlFor = input.id
|
|
||||||
label.appendChild(inputI.ConstructElement())
|
|
||||||
|
|
||||||
value.addCallbackAndRun(selectedValues =>{
|
|
||||||
if(selectedValues === undefined){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(selectedValues.indexOf(i) >= 0){
|
|
||||||
input.checked = true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
input.onchange = () => {
|
|
||||||
const index = value.data.indexOf(i);
|
|
||||||
if(input.checked && index < 0){
|
|
||||||
value.data.push(i);
|
|
||||||
value.ping();
|
|
||||||
}else if(index >= 0){
|
|
||||||
value.data.splice(index,1);
|
|
||||||
value.ping();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
el.appendChild(input)
|
|
||||||
el.appendChild(document.createElement("br"))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerConstructElement(): HTMLElement {
|
|
||||||
return this._element
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IsValid(ts: number[]): boolean {
|
IsValid(ts: number[]): boolean {
|
||||||
return ts !== undefined;
|
return ts !== undefined;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetValue(): UIEventSource<number[]> {
|
GetValue(): UIEventSource<number[]> {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected InnerConstructElement(): HTMLElement {
|
||||||
|
const el = document.createElement("form")
|
||||||
|
|
||||||
|
const value = this.value;
|
||||||
|
const elements = this._elements;
|
||||||
|
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
|
||||||
|
let inputI = elements[i];
|
||||||
|
const input = document.createElement("input")
|
||||||
|
const id = CheckBoxes._nextId
|
||||||
|
CheckBoxes._nextId++;
|
||||||
|
input.id = "checkbox" + id
|
||||||
|
|
||||||
|
input.type = "checkbox"
|
||||||
|
input.classList.add("p-1","cursor-pointer","ml-3","pl-3")
|
||||||
|
|
||||||
|
const label = document.createElement("label")
|
||||||
|
label.htmlFor = input.id
|
||||||
|
label.appendChild(inputI.ConstructElement())
|
||||||
|
label.classList.add("block","w-full","p-2","cursor-pointer","bg-red")
|
||||||
|
|
||||||
|
const wrapper = document.createElement("span")
|
||||||
|
wrapper.classList.add("flex","w-full","border", "border-gray-400")
|
||||||
|
wrapper.appendChild(input)
|
||||||
|
wrapper.appendChild(label)
|
||||||
|
el.appendChild(wrapper)
|
||||||
|
|
||||||
|
value.addCallbackAndRun(selectedValues => {
|
||||||
|
if (selectedValues === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selectedValues.indexOf(i) >= 0) {
|
||||||
|
input.checked = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
input.onchange = () => {
|
||||||
|
// Index = index in the list of already checked items
|
||||||
|
const index = value.data.indexOf(i);
|
||||||
|
if (input.checked && index < 0) {
|
||||||
|
value.data.push(i);
|
||||||
|
value.ping();
|
||||||
|
} else if (index >= 0) {
|
||||||
|
value.data.splice(index, 1);
|
||||||
|
value.ping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ export default class DirectionInput extends InputElement<string> {
|
||||||
this.value = value ?? new UIEventSource<string>(undefined);
|
this.value = value ?? new UIEventSource<string>(undefined);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected InnerConstructElement(): HTMLElement {
|
protected InnerConstructElement(): HTMLElement {
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,19 @@ export class RadioButton<T> extends InputElement<T> {
|
||||||
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||||
private readonly value: UIEventSource<T>;
|
private readonly value: UIEventSource<T>;
|
||||||
private _elements: InputElement<T>[];
|
private _elements: InputElement<T>[];
|
||||||
private readonly _element: HTMLElement;
|
private _selectFirstAsDefault: boolean;
|
||||||
|
|
||||||
constructor(elements: InputElement<T>[],
|
constructor(elements: InputElement<T>[],
|
||||||
selectFirstAsDefault = true) {
|
selectFirstAsDefault = true) {
|
||||||
super()
|
super()
|
||||||
elements = Utils.NoNull(elements);
|
this._selectFirstAsDefault = selectFirstAsDefault;
|
||||||
|
this._elements = Utils.NoNull(elements);
|
||||||
|
this.value = new UIEventSource<T>(undefined)
|
||||||
|
}
|
||||||
|
protected InnerConstructElement(): HTMLElement {
|
||||||
|
const elements = this._elements;
|
||||||
|
const selectFirstAsDefault = this._selectFirstAsDefault;
|
||||||
|
|
||||||
const selectedElementIndex: UIEventSource<number> = new UIEventSource<number>(null);
|
const selectedElementIndex: UIEventSource<number> = new UIEventSource<number>(null);
|
||||||
const value =
|
const value =
|
||||||
UIEventSource.flatten(selectedElementIndex.map(
|
UIEventSource.flatten(selectedElementIndex.map(
|
||||||
|
@ -22,6 +29,7 @@ export class RadioButton<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
), elements.map(e => e?.GetValue()));
|
), elements.map(e => e?.GetValue()));
|
||||||
|
value.syncWith(this.value)
|
||||||
|
|
||||||
if(selectFirstAsDefault){
|
if(selectFirstAsDefault){
|
||||||
|
|
||||||
|
@ -61,7 +69,20 @@ export class RadioButton<T> extends InputElement<T> {
|
||||||
RadioButton._nextId++
|
RadioButton._nextId++
|
||||||
|
|
||||||
const form = document.createElement("form")
|
const form = document.createElement("form")
|
||||||
this._element = form;
|
const inputs = []
|
||||||
|
|
||||||
|
value.addCallbackAndRun(
|
||||||
|
selected => {
|
||||||
|
|
||||||
|
let somethingChecked = false;
|
||||||
|
for (let i = 0; i < inputs.length; i++){
|
||||||
|
let input = inputs[i];
|
||||||
|
input.checked = !somethingChecked && elements[i].IsValid(selected);
|
||||||
|
somethingChecked = somethingChecked || input.checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
for (let i1 = 0; i1 < elements.length; i1++) {
|
for (let i1 = 0; i1 < elements.length; i1++) {
|
||||||
let element = elements[i1];
|
let element = elements[i1];
|
||||||
const labelHtml = element.ConstructElement();
|
const labelHtml = element.ConstructElement();
|
||||||
|
@ -73,6 +94,7 @@ export class RadioButton<T> extends InputElement<T> {
|
||||||
input.id = "radio" + groupId + "-" + i1;
|
input.id = "radio" + groupId + "-" + i1;
|
||||||
input.name = groupId;
|
input.name = groupId;
|
||||||
input.type = "radio"
|
input.type = "radio"
|
||||||
|
input.classList.add("p-1","cursor-pointer","ml-2","pl-2","pr-0","m-0","ml-3")
|
||||||
|
|
||||||
input.onchange = () => {
|
input.onchange = () => {
|
||||||
if(input.checked){
|
if(input.checked){
|
||||||
|
@ -80,30 +102,26 @@ export class RadioButton<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value.addCallbackAndRun(
|
|
||||||
selected => input.checked = element.IsValid(selected)
|
inputs.push(input)
|
||||||
)
|
|
||||||
|
|
||||||
const label = document.createElement("label")
|
const label = document.createElement("label")
|
||||||
label.appendChild(labelHtml)
|
label.appendChild(labelHtml)
|
||||||
label.htmlFor = input.id;
|
label.htmlFor = input.id;
|
||||||
|
label.classList.add("block","w-full","p-2","cursor-pointer","bg-red")
|
||||||
|
|
||||||
|
|
||||||
const block = document.createElement("div")
|
const block = document.createElement("div")
|
||||||
block.appendChild(input)
|
block.appendChild(input)
|
||||||
block.appendChild(label)
|
block.appendChild(label)
|
||||||
|
block.classList.add("flex","w-full","border", "rounded-full", "border-gray-400")
|
||||||
|
|
||||||
form.appendChild(block)
|
form.appendChild(block)
|
||||||
form.addEventListener("change", () => {
|
|
||||||
// TODO FIXME
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.value = value;
|
|
||||||
this._elements = elements;
|
|
||||||
|
|
||||||
this.SetClass("flex flex-col")
|
this.SetClass("flex flex-col")
|
||||||
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsValid(t: T): boolean {
|
IsValid(t: T): boolean {
|
||||||
|
@ -120,9 +138,6 @@ export class RadioButton<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected InnerConstructElement(): HTMLElement {
|
|
||||||
return this._element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public ShowValue(t: T): boolean {
|
public ShowValue(t: T): boolean {
|
||||||
|
|
|
@ -67,10 +67,10 @@ export class TextField extends InputElement<string> {
|
||||||
|
|
||||||
this.value.addCallbackAndRun(value => {
|
this.value.addCallbackAndRun(value => {
|
||||||
if (!(value !== undefined && value !== null)) {
|
if (!(value !== undefined && value !== null)) {
|
||||||
|
field["value"] = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
field["value"] = value;
|
||||||
field.value = value;
|
|
||||||
if (self.IsValid(value)) {
|
if (self.IsValid(value)) {
|
||||||
self.RemoveClass("invalid")
|
self.RemoveClass("invalid")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,15 +8,13 @@ import State from "../../State";
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg";
|
||||||
import Toggle from "../Input/Toggle";
|
import Toggle from "../Input/Toggle";
|
||||||
import BaseUIElement from "../BaseUIElement";
|
import BaseUIElement from "../BaseUIElement";
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
|
||||||
|
|
||||||
export default class EditableTagRendering extends Toggle {
|
export default class EditableTagRendering extends Toggle {
|
||||||
|
|
||||||
constructor(tags: UIEventSource<any>,
|
constructor(tags: UIEventSource<any>,
|
||||||
configuration: TagRenderingConfig) {
|
configuration: TagRenderingConfig,
|
||||||
|
editMode = new UIEventSource<boolean>(false)
|
||||||
const editMode = new UIEventSource<boolean>(false);
|
) {
|
||||||
|
|
||||||
const answer: BaseUIElement = new TagRenderingAnswer(tags, configuration)
|
const answer: BaseUIElement = new TagRenderingAnswer(tags, configuration)
|
||||||
answer.SetClass("w-full")
|
answer.SetClass("w-full")
|
||||||
let rendering = answer;
|
let rendering = answer;
|
||||||
|
|
|
@ -26,8 +26,8 @@ export class SaveButton extends Toggle {
|
||||||
isSaveable
|
isSaveable
|
||||||
)
|
)
|
||||||
super(
|
super(
|
||||||
save
|
save,
|
||||||
, pleaseLogin,
|
pleaseLogin,
|
||||||
osmConnection?.userDetails?.map(userDetails => userDetails.loggedIn) ?? new UIEventSource<any>(false)
|
osmConnection?.userDetails?.map(userDetails => userDetails.loggedIn) ?? new UIEventSource<any>(false)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,8 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this._saveButton = new SaveButton(this._inputElement.GetValue(), State.state?.osmConnection)
|
this._saveButton = new SaveButton(this._inputElement.GetValue(),
|
||||||
|
State.state?.osmConnection)
|
||||||
.onClick(save)
|
.onClick(save)
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
return tags.asHumanString(true, true, self._tags.data);
|
return tags.asHumanString(true, true, self._tags.data);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
).SetClass("block")
|
).SetClass("block break-all")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +157,9 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
oppositeTags.push(notSelected);
|
oppositeTags.push(notSelected);
|
||||||
}
|
}
|
||||||
tags.push(TagUtils.FlattenMultiAnswer(oppositeTags));
|
tags.push(TagUtils.FlattenMultiAnswer(oppositeTags));
|
||||||
return TagUtils.FlattenMultiAnswer(tags);
|
const actualTags = TagUtils.FlattenMultiAnswer(tags);
|
||||||
|
console.log("Converted ", indices.join(","), "into", actualTags.asHumanString(false, false, {}), "with elems", elements)
|
||||||
|
return actualTags;
|
||||||
},
|
},
|
||||||
(tags: TagsFilter) => {
|
(tags: TagsFilter) => {
|
||||||
// {key --> values[]}
|
// {key --> values[]}
|
||||||
|
|
|
@ -2,19 +2,14 @@
|
||||||
Contains tweaks for small screens
|
Contains tweaks for small screens
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.only-on-mobile {
|
@media only screen and (min-width: 769px) {
|
||||||
display: none !important;
|
|
||||||
background-color: var(--background-color);
|
|
||||||
color: var(--foreground-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 600px), only screen and (max-height: 600px) {
|
|
||||||
|
|
||||||
.only-on-mobile {
|
.only-on-mobile {
|
||||||
display: unset !important;
|
display: none !important;
|
||||||
background-color: var(--background-color);
|
|
||||||
color: var(--foreground-color);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 768px), only screen and (max-height: 768px) {
|
||||||
|
|
||||||
|
|
||||||
.hidden-on-mobile {
|
.hidden-on-mobile {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.slick-carousel-content {
|
|
||||||
width: 300px;
|
|
||||||
max-height: var(--image-carousel-height);
|
|
||||||
display: block;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.slick-carousel-content img {
|
|
||||||
/**
|
|
||||||
Workaround to patch images within a slick carousel
|
|
||||||
*/
|
|
||||||
height: var(--image-carousel-height);
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
|
@ -226,10 +226,6 @@ li::marker {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.question form input[type="radio"] {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invalid {
|
.invalid {
|
||||||
box-shadow: 0 0 10px #ff5353;
|
box-shadow: 0 0 10px #ff5353;
|
||||||
height: min-content;
|
height: min-content;
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
<div id="bottom-right" class="absolute bottom-3 right-2 rounded-3xl z-above-map"></div>
|
<div id="bottom-right" class="absolute bottom-3 right-2 rounded-3xl z-above-map"></div>
|
||||||
|
|
||||||
<div id="centermessage"
|
<div id="centermessage"
|
||||||
class="clutter absolute h-24 left-24 right-24 top-56" style="z-index: 4000">
|
class="clutter absolute h-24 left-24 right-24 top-56 text-xl text-center" style="z-index: 4000">
|
||||||
Loading MapComplete, hang on...
|
Loading MapComplete, hang on...
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"loginWithOpenStreetMap": "Login with OpenStreetMap",
|
"loginWithOpenStreetMap": "Login with OpenStreetMap",
|
||||||
|
"loginOnlyNeededToEdit": "to make changes to the map",
|
||||||
"welcomeBack": "You are logged in, welcome back!",
|
"welcomeBack": "You are logged in, welcome back!",
|
||||||
"loginToStart": "Login to answer this question",
|
"loginToStart": "Login to answer this question",
|
||||||
"testing":"Testing - changes won't be saved",
|
"testing":"Testing - changes won't be saved",
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
"error": "Something went wrong…"
|
"error": "Something went wrong…"
|
||||||
},
|
},
|
||||||
"returnToTheMap": "Return to the map",
|
"returnToTheMap": "Return to the map",
|
||||||
|
"openTheMap": "Open the map",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"skip": "Skip this question",
|
"skip": "Skip this question",
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {Utils} from "../Utils";
|
import {Utils} from "../Utils";
|
||||||
|
|
||||||
Utils.runningFromConsole = true;
|
Utils.runningFromConsole = true;
|
||||||
import SpecialVisualizations from "../UI/SpecialVisualizations";
|
import SpecialVisualizations from "../UI/SpecialVisualizations";
|
||||||
import SimpleMetaTagger from "../Logic/SimpleMetaTagger";
|
import SimpleMetaTagger from "../Logic/SimpleMetaTagger";
|
||||||
|
@ -12,19 +11,19 @@ import {writeFileSync} from "fs";
|
||||||
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
import LayoutConfig from "../Customizations/JSON/LayoutConfig";
|
||||||
import State from "../State";
|
import State from "../State";
|
||||||
import {QueryParameters} from "../Logic/Web/QueryParameters";
|
import {QueryParameters} from "../Logic/Web/QueryParameters";
|
||||||
import Link from "../UI/Base/Link";
|
|
||||||
|
|
||||||
|
|
||||||
function WriteFile(filename, html: string | BaseUIElement, autogenSource: string): void {
|
|
||||||
|
function WriteFile(filename, html: string | BaseUIElement, autogenSource: string[]): void {
|
||||||
writeFileSync(filename, new Combine([Translations.W(html),
|
writeFileSync(filename, new Combine([Translations.W(html),
|
||||||
new Link("Generated from "+autogenSource, "../../../"+autogenSource)
|
"Generated from "+autogenSource.join(", ")
|
||||||
]).AsMarkdown());
|
]).AsMarkdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage, "UI/SpecialVisualisations.ts")
|
WriteFile("./Docs/SpecialRenderings.md", SpecialVisualizations.HelpMessage, ["UI/SpecialVisualisations.ts"])
|
||||||
WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"),
|
WriteFile("./Docs/CalculatedTags.md", new Combine([SimpleMetaTagger.HelpText(), ExtraFunction.HelpText()]).SetClass("flex-col"),
|
||||||
"SimpleMetaTagger and ExtraFunction")
|
["SimpleMetaTagger","ExtraFunction"])
|
||||||
WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(),"ValidatedTextField.ts");
|
WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(),["ValidatedTextField.ts"]);
|
||||||
|
|
||||||
|
|
||||||
new State(new LayoutConfig({
|
new State(new LayoutConfig({
|
||||||
|
@ -51,7 +50,7 @@ new State(new LayoutConfig({
|
||||||
}))
|
}))
|
||||||
QueryParameters.GetQueryParameter("layer-<layer-id>", "true", "Wether or not the layer with id <layer-id> is shown")
|
QueryParameters.GetQueryParameter("layer-<layer-id>", "true", "Wether or not the layer with id <layer-id> is shown")
|
||||||
|
|
||||||
WriteFile("./Docs/URL_Parameters.md", QueryParameters.GenerateQueryParameterDocs(), "QueryParameters")
|
WriteFile("./Docs/URL_Parameters.md", QueryParameters.GenerateQueryParameterDocs(), ["QueryParameters"])
|
||||||
|
|
||||||
console.log("Generated docs")
|
console.log("Generated docs")
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<head>
|
<head>
|
||||||
<title>Small tests</title>
|
<title>Small tests</title>
|
||||||
<link href="index.css" rel="stylesheet"/>
|
<link href="index.css" rel="stylesheet"/>
|
||||||
<link href="css/slideshow.css" rel="stylesheet"/>
|
|
||||||
<link href="css/tabbedComponent.css" rel="stylesheet"/>
|
<link href="css/tabbedComponent.css" rel="stylesheet"/>
|
||||||
<link href="css/openinghourstable.css" rel="stylesheet"/>
|
<link href="css/openinghourstable.css" rel="stylesheet"/>
|
||||||
<link href="css/tagrendering.css" rel="stylesheet"/>
|
<link href="css/tagrendering.css" rel="stylesheet"/>
|
||||||
|
|
50
test.ts
50
test.ts
|
@ -1,10 +1,50 @@
|
||||||
import ValidatedTextField from "./UI/Input/ValidatedTextField";
|
import ValidatedTextField from "./UI/Input/ValidatedTextField";
|
||||||
import Combine from "./UI/Base/Combine";
|
import Combine from "./UI/Base/Combine";
|
||||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
||||||
|
import {UIEventSource} from "./Logic/UIEventSource";
|
||||||
|
import TagRenderingConfig from "./Customizations/JSON/TagRenderingConfig";
|
||||||
|
import State from "./State";
|
||||||
|
import TagRenderingQuestion from "./UI/Popup/TagRenderingQuestion";
|
||||||
|
|
||||||
|
|
||||||
new Combine(ValidatedTextField.tpList.map(tp => {
|
function TestTagRendering(){
|
||||||
const tf = ValidatedTextField.InputForType(tp.name);
|
State.state = new State(undefined)
|
||||||
|
const tagsSource = new UIEventSource({
|
||||||
return new Combine([tf, new VariableUiElement(tf.GetValue()).SetClass("alert")]);
|
id:"node/1"
|
||||||
})).AttachTo("maindiv")
|
})
|
||||||
|
new TagRenderingQuestion(
|
||||||
|
tagsSource,
|
||||||
|
new TagRenderingConfig({
|
||||||
|
multiAnswer: false,
|
||||||
|
freeform: {
|
||||||
|
key:"valve"
|
||||||
|
},
|
||||||
|
question: "What valves are supported?",
|
||||||
|
render: "This pump supports {valve}",
|
||||||
|
mappings: [
|
||||||
|
{
|
||||||
|
if: "valve=dunlop",
|
||||||
|
then: "This pump supports dunlop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if:"valve=shrader",
|
||||||
|
then:"shrader is supported",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
}, undefined, "test")
|
||||||
|
).AttachTo("maindiv")
|
||||||
|
new VariableUiElement(tagsSource.map(tags => tags["valves"])).SetClass("alert").AttachTo("extradiv")
|
||||||
|
}
|
||||||
|
|
||||||
|
function TestAllInputMethods(){
|
||||||
|
|
||||||
|
new Combine(ValidatedTextField.tpList.map(tp => {
|
||||||
|
const tf = ValidatedTextField.InputForType(tp.name);
|
||||||
|
|
||||||
|
return new Combine([tf, new VariableUiElement(tf.GetValue()).SetClass("alert")]);
|
||||||
|
})).AttachTo("maindiv")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestTagRendering()
|
Loading…
Reference in a new issue