forked from MapComplete/MapComplete
Derping around, bit of a dead end due to transform3d in a parent
This commit is contained in:
commit
81f0a21076
52 changed files with 1717 additions and 14115 deletions
|
@ -25,7 +25,11 @@ export default class Combine extends UIElement {
|
|||
console.error("Not a UI-element", ui);
|
||||
return "";
|
||||
}
|
||||
return ui.Render();
|
||||
let rendered = ui.Render();
|
||||
if(ui.IsEmpty()){
|
||||
return "";
|
||||
}
|
||||
return rendered;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
|
|
|
@ -12,5 +12,4 @@ export class FixedUiElement extends UIElement {
|
|||
return this._html;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -4,16 +4,16 @@ import {Utils} from "../../Utils";
|
|||
export default class Img {
|
||||
|
||||
public static runningFromConsole = false;
|
||||
|
||||
|
||||
static AsData(source:string){
|
||||
if(Utils.runningFromConsole){
|
||||
return source;
|
||||
}
|
||||
return `data:image/svg+xml;base64,${(btoa(source))}`;
|
||||
}
|
||||
|
||||
static AsImageElement(source: string): string{
|
||||
return `<img src="${Img.AsData(source)}">`;
|
||||
|
||||
static AsImageElement(source: string, css_class: string = ""): string{
|
||||
return `<img class="${css_class}" alt="" src="${Img.AsData(source)}">`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,28 +8,30 @@ import Ornament from "./Ornament";
|
|||
* Wraps some contents into a panel that scrolls the content _under_ the title
|
||||
*/
|
||||
export default class ScrollableFullScreen extends UIElement {
|
||||
private _component: Combine;
|
||||
private _component: UIElement;
|
||||
|
||||
|
||||
constructor(title: UIElement, content: UIElement, onClose: (() => void)) {
|
||||
super();
|
||||
const returnToTheMap = Svg.back_svg().onClick(() => {
|
||||
onClose();
|
||||
}).SetClass("sm:hidden")
|
||||
.SetClass("featureinfobox-back-to-the-map")
|
||||
title.SetStyle("width: 100%; display: block;")
|
||||
const ornament = new Combine([new Ornament().SetStyle("height:5em;")])
|
||||
.SetClass("block sm:hidden")
|
||||
}) .SetClass("block sm:hidden mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5")
|
||||
|
||||
this._component = new Combine([
|
||||
title.SetClass("block w-full")
|
||||
const ornament = new Combine([new Ornament().SetStyle("height:5em;")])
|
||||
.SetClass("block sm:hidden h-5")
|
||||
|
||||
|
||||
this._component = new Combine([
|
||||
new Combine([returnToTheMap, title])
|
||||
.SetClass("text-xl break-words"),
|
||||
new Combine([content, ornament])
|
||||
|
||||
])
|
||||
this.SetClass("fixed h-screen w-screen fixed sm:relative");
|
||||
.AddClass("border-b-2 border-black shadow sm:shadow-none z-50 bg-white p-2 pb-0 sm:p-0 flex overflow-x-hidden flex-shrink-0 max-h-20vh"),
|
||||
new Combine(["<span>", content, "</span>", ornament])
|
||||
.SetClass("block p-2 sm:pt-4 w-full max-h-screen landscape:max-h-screen overflow-y-auto overflow-x-hidden"),
|
||||
// We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide
|
||||
]).SetClass("block flex flex-col fixed max-h-screen sm:max-h-65vh sm:relative top-0 left-0 right-0");
|
||||
|
||||
}
|
||||
|
||||
|
||||
InnerRender(): string {
|
||||
return this._component.Render();
|
||||
|
|
|
@ -14,20 +14,25 @@ export class SubtleButton extends UIElement{
|
|||
this.linkTo = linkTo;
|
||||
this.message = Translations.W(message);
|
||||
if(this.message !== null){
|
||||
this.message.dumbMode = false;
|
||||
this.message.dumbMode = false;
|
||||
}
|
||||
let img;
|
||||
if ((imageUrl ?? "") === "") {
|
||||
this.image = new FixedUiElement("");
|
||||
img = new FixedUiElement("");
|
||||
} else if (typeof (imageUrl) === "string") {
|
||||
this.image = new FixedUiElement(`<img style="height:3em" src="${imageUrl}">`);
|
||||
img = new FixedUiElement(`<img style="width: 100%;" src="${imageUrl}" alt="">`);
|
||||
} else {
|
||||
this.image = imageUrl;
|
||||
img = imageUrl;
|
||||
}
|
||||
|
||||
img.AddClass("block flex items-center justify-center h-11 w-11 flex-shrink0")
|
||||
this.image = new Combine([img])
|
||||
.AddClass("flex-shrink-0");
|
||||
|
||||
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
||||
|
||||
if(this.message !== null && this.message.IsEmpty()){
|
||||
// Message == null: special case to force empty text
|
||||
return "";
|
||||
|
@ -35,19 +40,21 @@ export class SubtleButton extends UIElement{
|
|||
|
||||
if(this.linkTo != undefined){
|
||||
return new Combine([
|
||||
`<a class="subtle-button" href="${this.linkTo.url}" ${this.linkTo.newTab ? 'target="_blank"' : ""}>`,
|
||||
`<a class='block flex group p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200' href="${this.linkTo.url}" ${this.linkTo.newTab ? 'target="_blank"' : ""}>`,
|
||||
this.image,
|
||||
`<div class='ml-4'>`,
|
||||
this.message,
|
||||
'</a>'
|
||||
`</div>`,
|
||||
`</a>`
|
||||
]).Render();
|
||||
}
|
||||
|
||||
|
||||
// Styling todo
|
||||
return new Combine([
|
||||
'<span class="subtle-button">',
|
||||
this.image,
|
||||
this.message,
|
||||
'</span>'
|
||||
]).Render();
|
||||
]).AddClass("block flex p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200")
|
||||
.Render();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ export default class FullWelcomePaneWithTabs extends UIElement {
|
|||
const tabbedPart = new TabbedComponent(tabs, State.state.welcomeMessageOpenedTab)
|
||||
.ListenTo(this._userDetails);
|
||||
|
||||
|
||||
|
||||
this._component = new ScrollableFullScreen(
|
||||
layoutToUse.title,
|
||||
|
|
28
UI/BigComponents/IndexText.ts
Normal file
28
UI/BigComponents/IndexText.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import {UIElement} from "../UIElement";
|
||||
import Combine from "../Base/Combine";
|
||||
import Translations from "../i18n/Translations";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
|
||||
export default class IndexText extends Combine {
|
||||
constructor() {
|
||||
super([
|
||||
new FixedUiElement(`<img class="w-12 h-12 sm:h-24 sm:w-24" src="./assets/svg/logo.svg" alt="MapComplete Logo">`)
|
||||
.AddClass("flex-none m-3"),
|
||||
|
||||
new Combine([
|
||||
Translations.t.index.title
|
||||
.AddClass("text-2xl tracking-tight font-extrabold text-gray-900 sm:text-5xl md:text-6xl block text-gray-800 xl:inline"),
|
||||
|
||||
Translations.t.index.intro.AddClass(
|
||||
"mt-3 text-base font-semibold text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0"),
|
||||
|
||||
Translations.t.index.pickTheme.AddClass("mt-3 text-base text-green-600 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0")
|
||||
|
||||
]).AddClass("flex flex-col sm:text-center lg:text-left m-1 mt-2 md:m-2 md:mt-4")
|
||||
]);
|
||||
|
||||
|
||||
this.AddClass("flex flex-row");
|
||||
}
|
||||
|
||||
}
|
|
@ -29,7 +29,7 @@ export default class LayerControlPanel extends UIElement {
|
|||
}
|
||||
|
||||
|
||||
const title =Translations.t.general.layerSelection.title.SetClass("featureinfobox-title")
|
||||
const title = Translations.t.general.layerSelection.title.SetClass("text-2xl break-words font-bold p-2")
|
||||
|
||||
this._panel = new ScrollableFullScreen(title, layerControlPanel, () => {
|
||||
onClose
|
||||
|
|
|
@ -11,13 +11,14 @@ import Translations from "../i18n/Translations";
|
|||
import * as personal from "../../assets/themes/personalLayout/personalLayout.json"
|
||||
import Constants from "../../Models/Constants";
|
||||
import LanguagePicker from "../LanguagePicker";
|
||||
import IndexText from "./IndexText";
|
||||
|
||||
export default class MoreScreen extends UIElement {
|
||||
private readonly _onMainScreen: boolean;
|
||||
|
||||
|
||||
private _component: UIElement;
|
||||
|
||||
|
||||
|
||||
constructor(onMainScreen: boolean = false) {
|
||||
super(State.state.locationControl);
|
||||
this._onMainScreen = onMainScreen;
|
||||
|
@ -65,15 +66,14 @@ export default class MoreScreen extends UIElement {
|
|||
}
|
||||
|
||||
let description = Translations.W(layout.shortDescription);
|
||||
if (description !== undefined) {
|
||||
description = new Combine(["<br/>", description]);
|
||||
}
|
||||
return new SubtleButton(layout.icon,
|
||||
new Combine([
|
||||
"<b>",
|
||||
`<dt class='text-lg leading-6 font-medium text-gray-900 group-hover:text-blue-800'>`,
|
||||
Translations.W(layout.title),
|
||||
"</b>",
|
||||
`</dt>`,
|
||||
`<dd class='mt-1 text-base text-gray-500 group-hover:text-blue-900'>`,
|
||||
description ?? "",
|
||||
`</dd>`,
|
||||
]), {url: linkText, newTab: false});
|
||||
}
|
||||
|
||||
|
@ -83,21 +83,10 @@ export default class MoreScreen extends UIElement {
|
|||
|
||||
const els: UIElement[] = []
|
||||
|
||||
els.push(new VariableUiElement(
|
||||
State.state.osmConnection.userDetails.map(userDetails => {
|
||||
if (userDetails.csCount < Constants.userJourney.themeGeneratorReadOnlyUnlock) {
|
||||
return tr.requestATheme.Render();
|
||||
}
|
||||
return new SubtleButton(Svg.pencil_ui(), tr.createYourOwnTheme, {
|
||||
url: "./customGenerator.html",
|
||||
newTab: false
|
||||
}).Render();
|
||||
})
|
||||
));
|
||||
|
||||
const linkButton: UIElement[] = []
|
||||
|
||||
for (const k in AllKnownLayouts.allSets) {
|
||||
const layout : LayoutConfig = AllKnownLayouts.allSets[k];
|
||||
const layout: LayoutConfig = AllKnownLayouts.allSets[k];
|
||||
if (k === personal.id) {
|
||||
if (State.state.osmConnection.userDetails.data.csCount < Constants.userJourney.personalLayoutUnlock) {
|
||||
continue;
|
||||
|
@ -106,12 +95,25 @@ export default class MoreScreen extends UIElement {
|
|||
if (layout.id !== k) {
|
||||
continue; // This layout was added multiple time due to an uppercase
|
||||
}
|
||||
els.push(this.createLinkButton(layout));
|
||||
linkButton.push(this.createLinkButton(layout));
|
||||
}
|
||||
|
||||
els.push(new Combine(linkButton))
|
||||
|
||||
els.push(new VariableUiElement(
|
||||
State.state.osmConnection.userDetails.map(userDetails => {
|
||||
if (userDetails.csCount < Constants.userJourney.themeGeneratorReadOnlyUnlock) {
|
||||
return tr.requestATheme.SetClass("block text-base mx-10 my-3").Render();
|
||||
}
|
||||
return new SubtleButton(Svg.pencil_ui(), tr.createYourOwnTheme, {
|
||||
url: "./customGenerator.html",
|
||||
newTab: false
|
||||
}).Render();
|
||||
})
|
||||
));
|
||||
|
||||
const customThemesNames = State.state.installedThemes.data ?? [];
|
||||
|
||||
|
||||
if (customThemesNames.length > 0) {
|
||||
els.push(Translations.t.general.customThemeIntro)
|
||||
|
||||
|
@ -123,18 +125,19 @@ export default class MoreScreen extends UIElement {
|
|||
let intro : UIElement= tr.intro;
|
||||
if(this._onMainScreen){
|
||||
intro = new Combine([
|
||||
|
||||
LanguagePicker.CreateLanguagePicker(Translations.t.general.index.SupportedLanguages())
|
||||
.SetStyle("position: absolute; right: 1.5em; top: 1.5em;"),
|
||||
Translations.t.general.index.SetStyle("margin-top: 2em;display:block; margin-bottom: 1em;")
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
this._component = new VerticalCombine([
|
||||
intro,
|
||||
new VerticalCombine(els),
|
||||
tr.streetcomplete
|
||||
LanguagePicker.CreateLanguagePicker(Translations.t.index.title.SupportedLanguages())
|
||||
.SetClass("absolute top-2 right-3 dropdown-ui-element-2226"),
|
||||
new IndexText()
|
||||
|
||||
|
||||
])
|
||||
}
|
||||
|
||||
this._component = new Combine([
|
||||
intro,
|
||||
new Combine(els),
|
||||
tr.streetcomplete.SetClass("block text-base mx-10 my-3 mb-10")
|
||||
]);
|
||||
return this._component.Render();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export default class SearchAndGo extends UIElement {
|
|||
);
|
||||
|
||||
private _foundEntries = new UIEventSource([]);
|
||||
private _goButton = Svg.search_ui().SetClass('search-go');
|
||||
private _goButton = Svg.search_ui().AddClass('w-8 h-8 full-rounded border-black float-right');
|
||||
|
||||
constructor() {
|
||||
super(undefined);
|
||||
|
|
|
@ -29,7 +29,7 @@ export default class UserBadge extends UIElement {
|
|||
|
||||
this._loginButton = Translations.t.general.loginWithOpenStreetMap
|
||||
.Clone()
|
||||
.SetClass("userbadge-login")
|
||||
.SetClass("userbadge-login pt-3 w-full")
|
||||
.onClick(() => State.state.osmConnection.AttemptLogin());
|
||||
this._logout =
|
||||
Svg.logout_svg()
|
||||
|
@ -50,7 +50,7 @@ export default class UserBadge extends UIElement {
|
|||
this._homeButton = new VariableUiElement(
|
||||
this._userDetails.map((userinfo) => {
|
||||
if (userinfo.home) {
|
||||
return Svg.home;
|
||||
return Svg.home_svg().Render();
|
||||
}
|
||||
return "";
|
||||
})
|
||||
|
|
|
@ -40,7 +40,6 @@ export default class CenterMessageBox extends UIElement {
|
|||
return CenterMessageBox.prep().innerHtml;
|
||||
}
|
||||
|
||||
|
||||
InnerUpdate(htmlElement: HTMLElement) {
|
||||
const pstyle = htmlElement.parentElement.style;
|
||||
if (State.state.centerMessage.data != "") {
|
||||
|
|
|
@ -20,14 +20,12 @@ export default class FullScreenMessageBox extends UIElement {
|
|||
return "";
|
||||
}
|
||||
this._content = State.state.fullScreenMessage.data.content;
|
||||
return new Combine([this._content]).SetClass("fullscreenmessage-content").Render();
|
||||
return new Combine([this._content])
|
||||
.SetClass("block max-h-screen h-screen overflow-x-hidden overflow-y-auto bg-white p-0").Render();
|
||||
}
|
||||
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
super.InnerUpdate(htmlElement);
|
||||
// This is a bit out of place, and it is a fix specifically for the featureinfobox-titlebar
|
||||
const height = htmlElement.getElementsByClassName("featureinfobox-titlebar")[0]?.clientHeight ?? 0;
|
||||
htmlElement.style.setProperty("--variable-title-height", height + "px")
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,5 +28,5 @@ export default class CheckBox extends UIElement{
|
|||
return Translations.W(this._showDisabled).Render();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -11,13 +11,19 @@ export class DropDown<T> extends InputElement<T> {
|
|||
private readonly _value: UIEventSource<T>;
|
||||
|
||||
public IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||
private readonly _label_class: string;
|
||||
private readonly _select_class: string;
|
||||
|
||||
constructor(label: string | UIElement,
|
||||
values: { value: T, shown: string | UIElement }[],
|
||||
value: UIEventSource<T> = undefined) {
|
||||
value: UIEventSource<T> = undefined,
|
||||
label_class: string = "",
|
||||
select_class: string = "") {
|
||||
super(undefined);
|
||||
this._value = value ?? new UIEventSource<T>(undefined);
|
||||
this._label = Translations.W(label);
|
||||
this._label_class = label_class || '';
|
||||
this._select_class = select_class || '';
|
||||
this._values = values.map(v => {
|
||||
return {
|
||||
value: v.value,
|
||||
|
@ -29,10 +35,8 @@ export class DropDown<T> extends InputElement<T> {
|
|||
this.ListenTo(v.shown._source);
|
||||
}
|
||||
this.ListenTo(this._value);
|
||||
|
||||
this.onClick(() => {}) // by registering a click, the click event is consumed and doesn't bubble furter to other elements, e.g. checkboxes
|
||||
|
||||
|
||||
this.onClick(() => {}) // by registering a click, the click event is consumed and doesn't bubble furter to other elements, e.g. checkboxes
|
||||
}
|
||||
|
||||
GetValue(): UIEventSource<T> {
|
||||
|
@ -52,18 +56,18 @@ export class DropDown<T> extends InputElement<T> {
|
|||
if(this._values.length <=1){
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
let options = "";
|
||||
for (let i = 0; i < this._values.length; i++) {
|
||||
options += "<option value='" + i + "'>" + this._values[i].shown.InnerRender() + "</option>"
|
||||
}
|
||||
|
||||
return "<form>" +
|
||||
"<label for='dropdown-" + this.id + "'>" + this._label.Render() + " </label>" +
|
||||
"<select name='dropdown-" + this.id + "' id='dropdown-" + this.id + "'>" +
|
||||
|
||||
return `<form>` +
|
||||
`<label class='${this._label_class}' for='dropdown-${this.id}'>${this._label.Render()}</label>` +
|
||||
`<select class='${this._select_class}' name='dropdown-${this.id}' id='dropdown-${this.id}'>` +
|
||||
options +
|
||||
"</select>" +
|
||||
"</form>";
|
||||
`</select>` +
|
||||
`</form>`;
|
||||
}
|
||||
|
||||
protected InnerUpdate(element) {
|
||||
|
|
|
@ -11,7 +11,7 @@ export class RadioButton<T> extends InputElement<T> {
|
|||
private readonly value: UIEventSource<T>;
|
||||
private readonly _elements: InputElement<T>[]
|
||||
private readonly _selectFirstAsDefault: boolean;
|
||||
|
||||
|
||||
constructor(elements: InputElement<T>[],
|
||||
selectFirstAsDefault = true) {
|
||||
super(undefined);
|
||||
|
@ -74,14 +74,14 @@ export class RadioButton<T> extends InputElement<T> {
|
|||
for (let i = 0; i < this._elements.length; i++){
|
||||
const el = this._elements[i];
|
||||
const htmlElement =
|
||||
'<input type="radio" id="' + this.IdFor(i) + '" name="radiogroup-' + this.id + '">' +
|
||||
'<label for="' + this.IdFor(i) + '">' + el.Render() + '</label>' +
|
||||
'<br>';
|
||||
`<label for="${this.IdFor(i)}" class="question-option-with-border">` +
|
||||
`<input type="radio" id="${this.IdFor(i)}" name="radiogroup-${this.id}">` +
|
||||
el.Render() +
|
||||
`</label>`;
|
||||
body += htmlElement;
|
||||
|
||||
}
|
||||
|
||||
return "<form id='" + this.id + "-form'>" + body + "</form>";
|
||||
return `<form id='${this.id}-form'>${body}</form>`;
|
||||
}
|
||||
|
||||
public ShowValue(t: T): boolean {
|
||||
|
|
|
@ -13,10 +13,10 @@ export default class LanguagePicker {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
return new DropDown(label, languages.map(lang => {
|
||||
return new DropDown("Change Language", languages.map(lang => {
|
||||
return {value: lang, shown: lang}
|
||||
}
|
||||
), Locale.language);
|
||||
), Locale.language, 'sr-only', 'bg-indigo-100 p-1 rounded hover:bg-indigo-200');
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ export default class EditableTagRendering extends UIElement {
|
|||
|
||||
return new Combine([this._answer,
|
||||
(State.state?.osmConnection?.userDetails?.data?.loggedIn ?? true) ? this._editButton : undefined
|
||||
]).SetClass("answer")
|
||||
]).SetClass("flex w-full break-word justify-between text-default landscape:w-1/2 landscape:p-2 pb-2 border-b border-gray-300 mb-2")
|
||||
.Render();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ export default class FeatureInfoBox extends UIElement {
|
|||
private _component: UIElement;
|
||||
|
||||
public title: UIElement ;
|
||||
|
||||
|
||||
constructor(
|
||||
tags: UIEventSource<any>,
|
||||
layerConfig: LayerConfig,
|
||||
|
@ -26,11 +26,12 @@ export default class FeatureInfoBox extends UIElement {
|
|||
|
||||
|
||||
const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined))
|
||||
.SetClass("featureinfobox-title");
|
||||
.AddClass("text-2xl break-words font-bold p-2");
|
||||
this.title = title;
|
||||
const titleIcons = new Combine(
|
||||
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)))
|
||||
.SetClass("featureinfobox-icons");
|
||||
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)
|
||||
.AddClass("block w-8 h-8 align-baseline box-content p-0.5")))
|
||||
.AddClass("flex flex-row flex-wrap pt-1 items-center mr-2");
|
||||
|
||||
let questionBox: UIElement = undefined;
|
||||
if (State.state.featureSwitchUserbadge.data) {
|
||||
|
@ -58,7 +59,7 @@ export default class FeatureInfoBox extends UIElement {
|
|||
]
|
||||
)
|
||||
const titleBar = new Combine([
|
||||
new Combine([title, titleIcons]).SetClass("featureinfobox-titlebar-title")
|
||||
new Combine([title, titleIcons]).SetClass("flex flex-grow justify-between")
|
||||
])
|
||||
|
||||
this._component = new ScrollableFullScreen(titleBar, content, onClose)
|
||||
|
|
|
@ -40,7 +40,6 @@ export default class QuestionBox extends UIElement {
|
|||
})
|
||||
));
|
||||
|
||||
|
||||
this._skippedQuestionsButton = Translations.t.general.skippedQuestions.Clone()
|
||||
.onClick(() => {
|
||||
self._skippedQuestions.setData([]);
|
||||
|
@ -64,19 +63,19 @@ export default class QuestionBox extends UIElement {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tagRendering.GetRenderValue(this._tags.data) !== undefined) {
|
||||
// This value is known and can be rendered
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
for (let i = 0; i < this._tagRenderingQuestions.length; i++) {
|
||||
let tagRendering = this._tagRenderings[i];
|
||||
|
||||
|
||||
if(this.IsKnown(tagRendering)){
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ export default class TagRenderingAnswer extends UIElement {
|
|||
if (configuration === undefined) {
|
||||
throw "Trying to generate a tagRenderingAnswer without configuration..."
|
||||
}
|
||||
this.AddClass("flex items-center flex-row text-lg")
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
@ -34,11 +35,6 @@ export default class TagRenderingAnswer extends UIElement {
|
|||
if (tags === undefined) {
|
||||
return "";
|
||||
}
|
||||
const tr = this._configuration.GetRenderValue(tags);
|
||||
if (tr !== undefined) {
|
||||
this._content = new SubstitutedTranslation(tr, this._tags);
|
||||
return this._content.Render();
|
||||
}
|
||||
|
||||
// The render value doesn't work well with multi-answers (checkboxes), so we have to check for them manually
|
||||
if (this._configuration.multiAnswer) {
|
||||
|
@ -65,6 +61,14 @@ export default class TagRenderingAnswer extends UIElement {
|
|||
return this._content.Render();
|
||||
}
|
||||
}
|
||||
|
||||
const tr = this._configuration.GetRenderValue(tags);
|
||||
if (tr !== undefined) {
|
||||
this._content = new SubstitutedTranslation(tr, this._tags);
|
||||
return this._content.Render();
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
|
||||
}
|
||||
|
|
|
@ -78,7 +78,6 @@ export default class TagRenderingQuestion extends UIElement {
|
|||
if (csCount < Constants.userJourney.tagsVisibleAt) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (tags === undefined) {
|
||||
return Translations.t.general.noTagsSelected.SetClass("subtle").Render();
|
||||
}
|
||||
|
@ -89,8 +88,7 @@ export default class TagRenderingQuestion extends UIElement {
|
|||
return tags.asHumanString(true, true);
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
).AddClass("block")
|
||||
}
|
||||
|
||||
private GenerateInputElement(): InputElement<TagsFilter> {
|
||||
|
@ -104,9 +102,6 @@ export default class TagRenderingQuestion extends UIElement {
|
|||
return ff;
|
||||
}
|
||||
|
||||
mappings = Utils.NoNull([...mappings, ff]);
|
||||
mappings.forEach(el => el.SetClass("question-option-with-border"))
|
||||
|
||||
if (this._configuration.multiAnswer) {
|
||||
return this.GenerateMultiAnswer(mappings, ff)
|
||||
} else {
|
||||
|
@ -268,16 +263,16 @@ export default class TagRenderingQuestion extends UIElement {
|
|||
|
||||
}
|
||||
|
||||
|
||||
InnerRender(): string {
|
||||
return new Combine([
|
||||
this._question,
|
||||
this._inputElement, "<br/>",
|
||||
this._inputElement,
|
||||
this._cancelButton,
|
||||
this._saveButton, "<br/>",
|
||||
this._appliedTags])
|
||||
.SetClass("question")
|
||||
.Render()
|
||||
this._saveButton,
|
||||
this._appliedTags]
|
||||
)
|
||||
.SetClass("question")
|
||||
.Render()
|
||||
}
|
||||
|
||||
}
|
|
@ -87,11 +87,11 @@ export default class ReviewForm extends InputElement<Review> {
|
|||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
||||
|
||||
if(!this.userDetails.data.loggedIn){
|
||||
return Translations.t.reviews.plz_login.Render();
|
||||
}
|
||||
|
||||
|
||||
return new Combine([
|
||||
new Combine([this._stars, this._postingAs]).SetClass("review-form-top"),
|
||||
this._comment,
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class ShowDataLayer {
|
|||
action();
|
||||
}
|
||||
});
|
||||
Hash.hash.addCallback(id => {
|
||||
Hash.hash.addCallbackAndRun(id => {
|
||||
// This is a bit of an edge case: if the hash becomes an id to search, we have to show the corresponding popup
|
||||
if(State.state.selectedElement !== undefined){
|
||||
return; // Something is already selected, we don't have to apply this fix
|
||||
|
@ -130,6 +130,9 @@ export default class ShowDataLayer {
|
|||
"<div style='height: 90vh'>Rendering</div>");
|
||||
popup.setContent(uiElement.Render());
|
||||
popup.on('remove', () => {
|
||||
if(!popup.isOpen()){
|
||||
return;
|
||||
}
|
||||
State.state.selectedElement.setData(undefined);
|
||||
});
|
||||
leafletLayer.bindPopup(popup);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import Constants from "../Models/Constants";
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
export abstract class UIElement extends UIEventSource<string> {
|
||||
|
@ -8,7 +7,7 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
public readonly id: string;
|
||||
public readonly _source: UIEventSource<any>;
|
||||
public dumbMode = false;
|
||||
private clss: string[] = []
|
||||
private clss: Set<string> = new Set<string>();
|
||||
private style: string;
|
||||
private _hideIfEmpty = false;
|
||||
private lastInnerRender: string;
|
||||
|
@ -110,7 +109,7 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
|
||||
}
|
||||
|
||||
HideOnEmpty(hide: boolean) {
|
||||
HideOnEmpty(hide: boolean): UIElement {
|
||||
this._hideIfEmpty = hide;
|
||||
this.Update();
|
||||
return this;
|
||||
|
@ -127,8 +126,8 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
style = `style="${this.style}" `;
|
||||
}
|
||||
let clss = "";
|
||||
if (this.clss.length > 0) {
|
||||
clss = `class='${this.clss.join(" ")}' `;
|
||||
if (this.clss.size > 0) {
|
||||
clss = `class='${Array.from(this.clss).join(" ")}' `;
|
||||
}
|
||||
return `<span ${clss}${style}id='${this.id}'>${this.lastInnerRender}</span>`
|
||||
}
|
||||
|
@ -151,20 +150,34 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
}
|
||||
|
||||
public SetClass(clss: string): UIElement {
|
||||
return this.AddClass(clss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the relevant classes, space seperated
|
||||
* @param clss
|
||||
* @constructor
|
||||
*/
|
||||
public AddClass(clss: string) {
|
||||
this.dumbMode = false;
|
||||
if (clss === "" && this.clss.length > 0) {
|
||||
throw "Use RemoveClass instead";
|
||||
} else if (this.clss.indexOf(clss) < 0) {
|
||||
this.clss.push(clss);
|
||||
const all = clss.split(" ");
|
||||
let recordedChange = false;
|
||||
for (const c of all) {
|
||||
if (this.clss.has(clss)) {
|
||||
continue;
|
||||
}
|
||||
this.clss.add(c);
|
||||
recordedChange = true;
|
||||
}
|
||||
if (recordedChange) {
|
||||
this.Update();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public RemoveClass(clss: string): UIElement {
|
||||
const i = this.clss.indexOf(clss);
|
||||
if (i >= 0) {
|
||||
this.clss.splice(i, 1);
|
||||
if (this.clss.has(clss)) {
|
||||
this.clss.delete(clss);
|
||||
this.Update();
|
||||
}
|
||||
return this;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue