From a0b909e8a6718b027366eb5b1b06bfb99f6a0cca Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 25 Feb 2021 02:23:26 +0100 Subject: [PATCH] Fixes to popup handling and to broken styles --- InitUiElements.ts | 53 +++--- Logic/Actors/GeoLocationHandler.ts | 56 ++++++- Logic/Actors/StrayClickHandler.ts | 12 +- Models/Constants.ts | 2 +- UI/Base/LazyElement.ts | 6 + UI/Base/ScrollableFullScreen.ts | 175 ++++++-------------- UI/BigComponents/FullWelcomePaneWithTabs.ts | 28 ++-- UI/BigComponents/LayerControlPanel.ts | 24 +-- UI/OpeningHours/OhVisualization.ts | 2 +- UI/OpeningHours/OpeningHoursPickerTable.ts | 1 - UI/Popup/FeatureInfoBox.ts | 22 +-- UI/Reviews/ReviewElement.ts | 2 +- UI/ShowDataLayer.ts | 25 ++- css/openinghourstable.css | 2 + index.css | 18 -- index.html | 7 +- 16 files changed, 188 insertions(+), 247 deletions(-) diff --git a/InitUiElements.ts b/InitUiElements.ts index 9b08e330a..5ebe3a3b2 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -31,11 +31,9 @@ import FeatureSwitched from "./UI/Base/FeatureSwitched"; import ShowDataLayer from "./UI/ShowDataLayer"; import Hash from "./Logic/Web/Hash"; import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline"; -import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; import ScrollableFullScreen from "./UI/Base/ScrollableFullScreen"; import Translations from "./UI/i18n/Translations"; import MapControlButton from "./UI/MapControlButton"; -import {Map} from "leaflet"; import Combine from "./UI/Base/Combine"; export class InitUiElements { @@ -230,15 +228,13 @@ export class InitUiElements { private static InitWelcomeMessage() { - const isOpened = new UIEventSource(true); - const fullOptions = new FullWelcomePaneWithTabs(() => { - isOpened.setData(false); - }); + const isOpened = new UIEventSource(false); + const fullOptions = new FullWelcomePaneWithTabs(isOpened); // ?-Button on Desktop, opens panel with close-X. const help = new MapControlButton(Svg.help_svg()); - // .SetClass("open-welcome-button block"); - const checkbox = new CheckBox( + // .SetClass("open-welcome-button block"); + new CheckBox( fullOptions .SetClass("welcomeMessage") .onClick(() => {/*Catch the click*/ @@ -252,14 +248,15 @@ export class InitUiElements { // Don't autoclose the first 15 secs when the map is moving return; } - checkbox.isEnabled.setData(false); + isOpened.setData(false); }) State.state.selectedElement.addCallbackAndRun(selected => { if (selected !== undefined) { - checkbox.isEnabled.setData(false); + isOpened.setData(false); } }) + isOpened.setData(true) } @@ -267,36 +264,32 @@ export class InitUiElements { InitUiElements.OnlyIf(State.state.featureSwitchLayers, () => { const layerControlPanel = new LayerControlPanel( - () => State.state.layerControlIsOpened.setData(false)) + State.state.layerControlIsOpened) .SetClass("block p-1 rounded-full"); const checkbox = new CheckBox( layerControlPanel, new MapControlButton(Svg.layers_svg()), State.state.layerControlIsOpened ) - const copyrightState = new UIEventSource(false); const copyrightNotice = new ScrollableFullScreen( - Translations.t.general.attribution.attributionTitle, - new Combine([ + () => Translations.t.general.attribution.attributionTitle.Clone(), + () => new Combine([ Translations.t.general.attribution.attributionContent, "
", new Attribution(undefined, undefined, State.state.layoutToUse, undefined) - ]), - () => { - copyrightState.setData(false) - } + ]) ) ; const copyrightButton = new CheckBox( copyrightNotice, new MapControlButton(Svg.osm_copyright_svg()), - copyrightState + copyrightNotice.isShown ).SetClass("p-0.5 md:hidden") - new Combine([copyrightButton, checkbox]) - .AttachTo("bottom-left"); + new Combine([copyrightButton, checkbox]) + .AttachTo("bottom-left"); State.state.locationControl @@ -394,7 +387,7 @@ export class InitUiElements { new ShowDataLayer(source.features, State.state.leafletMap, State.state.layoutToUse); - // TOO reenable new SelectedFeatureHandler(Hash.hash, State.state.selectedElement, source); + // TOO reenable new SelectedFeatureHandler(Hash.hash, State.state.selectedElement, source); } @@ -423,16 +416,22 @@ export class InitUiElements { } + const addNewPoint = new ScrollableFullScreen( + () => Translations.t.general.add.title.Clone(), + () => new SimpleAddUI()); + + addNewPoint.isShown.addCallback(isShown => { + if (!isShown) { + State.state.LastClickLocation.setData(undefined) + } + }) + new StrayClickHandler( State.state.LastClickLocation, State.state.selectedElement, State.state.filteredLayers, State.state.leafletMap, - () => - new ScrollableFullScreen( - Translations.t.general.add.title, - new SimpleAddUI(), - () => State.state.LastClickLocation.setData(undefined)) + addNewPoint ); }); diff --git a/Logic/Actors/GeoLocationHandler.ts b/Logic/Actors/GeoLocationHandler.ts index 191316629..da4f746d6 100644 --- a/Logic/Actors/GeoLocationHandler.ts +++ b/Logic/Actors/GeoLocationHandler.ts @@ -8,13 +8,46 @@ import {LocalStorageSource} from "../Web/LocalStorageSource"; export default class GeoLocationHandler extends UIElement { + /** + * Wether or not the geolocation is active, aka the user requested the current location + * @private + */ private readonly _isActive: UIEventSource = new UIEventSource(false); + + /** + * The callback over the permission API + * @private + */ private readonly _permission: UIEventSource = new UIEventSource(""); + /*** + * The marker on the map, in order to update it + * @private + */ private _marker: L.Marker; + /** + * Literally: _currentGPSLocation.data != undefined + * @private + */ private readonly _hasLocation: UIEventSource; private readonly _currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>; + /** + * Kept in order to update the marker + * @private + */ private readonly _leafletMap: UIEventSource; + /** + * The date when the user requested the geolocation. If we have a location, it'll autozoom to it the first 30 secs + * @private + */ private _lastUserRequest: Date; + /** + * A small flag on localstorage. If the user previously granted the geolocation, it will be set. + * On firefox, the permissions api is broken (probably fingerprint resistiance) and "granted + don't ask again" doesn't stick between sessions. + * + * Instead, we set this flag. If this flag is set upon loading the page, we start geolocating immediately. + * If the user denies the geolocation this time, we unset this flag + * @private + */ private readonly _previousLocationGrant : UIEventSource = LocalStorageSource.Get("geolocation-permissions"); constructor(currentGPSLocation: UIEventSource<{ latlng: any; accuracy: number }>, @@ -28,17 +61,26 @@ export default class GeoLocationHandler extends UIElement { import("../../vendor/Leaflet.AccuratePosition.js").then(() => { self.init(); }) + + const currentPointer = this._isActive.map(isActive => { + if(isActive && !self._hasLocation.data){ + return "cursor-wait" + } + return "cursor-pointer" + }, [this._hasLocation]) + currentPointer.addCallbackAndRun(pointerClass => { + self.SetClass(pointerClass); + self.Update() + }) } - - public init() { + private init() { this.ListenTo(this._hasLocation); this.ListenTo(this._isActive); this.ListenTo(this._permission); const self = this; - function onAccuratePositionProgress(e) { self._currentGPSLocation.setData({latlng: e.latlng, accuracy: e.accuracy}); } @@ -60,7 +102,7 @@ export default class GeoLocationHandler extends UIElement { this._currentGPSLocation.addCallback((location) => { self._previousLocationGrant.setData("granted"); - + const timeSinceRequest = (new Date().getTime() - (self._lastUserRequest?.getTime() ?? 0)) / 1000; if(timeSinceRequest < 30){ self._lastUserRequest = undefined; @@ -90,7 +132,7 @@ export default class GeoLocationHandler extends UIElement { ?.then(function (status) { console.log("Geolocation is already", status) if (status.state === "granted") { - self.StartGeolocating(); + self.StartGeolocating(19, false); } self._permission.setData(status.state); status.onchange = function () { @@ -134,10 +176,10 @@ export default class GeoLocationHandler extends UIElement { } - private StartGeolocating(zoomlevel = 19) { + private StartGeolocating(zoomlevel = 19, zoomToGPS=true) { const self = this; console.log("Starting geolocation") - this._lastUserRequest = new Date(); + this._lastUserRequest = zoomToGPS ? new Date() : new Date(0); const map: any = this._leafletMap.data; if (self._permission.data === "denied") { self._previousLocationGrant.setData(""); diff --git a/Logic/Actors/StrayClickHandler.ts b/Logic/Actors/StrayClickHandler.ts index 1449ee1bb..064da814c 100644 --- a/Logic/Actors/StrayClickHandler.ts +++ b/Logic/Actors/StrayClickHandler.ts @@ -1,8 +1,8 @@ import * as L from "leaflet"; -import {UIElement} from "../../UI/UIElement"; import Svg from "../../Svg"; import {UIEventSource} from "../UIEventSource"; import Img from "../../UI/Base/Img"; +import ScrollableFullScreen from "../../UI/Base/ScrollableFullScreen"; /** * The stray-click-hanlders adds a marker to the map if no feature was clicked. @@ -10,15 +10,13 @@ import Img from "../../UI/Base/Img"; */ export default class StrayClickHandler { private _lastMarker; - private _uiToShow: (() => UIElement); constructor( lastClickLocation: UIEventSource<{ lat: number, lon: number }>, selectedElement: UIEventSource, filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource }[]>, leafletMap: UIEventSource, - uiToShow: (() => UIElement)) { - this._uiToShow = uiToShow; + uiToShow: ScrollableFullScreen) { const self = this; filteredLayers.data.forEach((filteredLayer) => { filteredLayer.isDisplayed.addCallback(isEnabled => { @@ -49,13 +47,13 @@ export default class StrayClickHandler { popupAnchor: [0, -45] }) }); - const uiElement = uiToShow(); - const popup = L.popup().setContent(uiElement.Render()); + const popup = L.popup().setContent(uiToShow.Render()); self._lastMarker.addTo(leafletMap.data); self._lastMarker.bindPopup(popup); self._lastMarker.on("click", () => { - uiElement.Update(); + uiToShow.Activate(); + uiToShow.Update(); }); }); diff --git a/Models/Constants.ts b/Models/Constants.ts index 8d9e1bf6f..082ff3096 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -2,7 +2,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.5.2a"; + public static vNumber = "0.5.2b"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/UI/Base/LazyElement.ts b/UI/Base/LazyElement.ts index 40555d1f3..99161dd2f 100644 --- a/UI/Base/LazyElement.ts +++ b/UI/Base/LazyElement.ts @@ -17,6 +17,12 @@ export default class LazyElement extends UIElement { self._content = content(); } self.Update(); + // @ts-ignore + if(this._content.Activate){ + // THis is ugly - I know + // @ts-ignore + this._content.Activate(); + } } } diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts index d1e8fc603..e2b588617 100644 --- a/UI/Base/ScrollableFullScreen.ts +++ b/UI/Base/ScrollableFullScreen.ts @@ -2,157 +2,76 @@ import {UIElement} from "../UIElement"; import Svg from "../../Svg"; import Combine from "./Combine"; import Ornament from "./Ornament"; +import {FixedUiElement} from "./FixedUiElement"; +import {UIEventSource} from "../../Logic/UIEventSource"; /** * Wraps some contents into a panel that scrolls the content _under_ the title */ export default class ScrollableFullScreen extends UIElement { - private static _isInited = false; + private static readonly empty = new FixedUiElement(""); + public isShown: UIEventSource; private _component: UIElement; + private _fullscreencomponent: UIElement; - constructor(title: UIElement, content: UIElement, onClose: (() => void)) { + constructor(title: (() => UIElement), content: (() => UIElement), isShown: UIEventSource = new UIEventSource(false)) { super(); - if (!ScrollableFullScreen._isInited) { - ScrollableFullScreen._isInited = ScrollableFullScreen.PreparePatchesForFullscreen(); - } + this.isShown = isShown; + + this._component = this.BuildComponent(title(), content(), isShown); + this._fullscreencomponent = this.BuildComponent(title(), content(), isShown); + this.dumbMode = false; + const self = this; + isShown.addCallback(isShown => { + if (isShown) { + self.Activate(); + } else { + self.clear(); + + } + }) + } + + InnerRender(): string { + return this._component.Render(); + } + + Activate(): void { + this.isShown.setData(true) + this._fullscreencomponent.AttachTo("fullscreen"); + const fs = document.getElementById("fullscreen"); + fs.classList.remove("hidden") + } + + private BuildComponent(title: UIElement, content: UIElement, isShown: UIEventSource) { const returnToTheMap = new Combine([ Svg.back_svg().SetClass("block md:hidden"), Svg.close_svg().SetClass("hidden md:block") ]) .onClick(() => { - ScrollableFullScreen.RestoreLeaflet(); - if (onClose !== undefined) { - onClose(); - } else { - console.error("WARNING: onClose is not defined") - } + isShown.setData(false) }).SetClass("mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5 flex-shrink-0") title.SetClass("block text-l sm:text-xl md:text-2xl w-full font-bold p-2 pl-4 max-h-20vh overflow-y-auto") const ornament = new Combine([new Ornament().SetStyle("height:5em;")]) .SetClass("md:hidden h-5") - - - this._component = + return new Combine([ new Combine([ - new Combine([ - new Combine([returnToTheMap, title]) - .SetClass("border-b-2 border-black shadow md:shadow-none bg-white p-2 pb-0 md:p-0 flex flex-shrink-0"), - new Combine([content, ornament]) - .SetClass("block p-2 md:pt-4 w-full h-full overflow-y-auto md:max-h-65vh"), - // We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide - ]).SetClass("flex flex-col h-full relative bg-white") - ]).SetClass("fixed top-0 left-0 right-0 h-screen w-screen md:max-h-65vh md:w-auto md:relative z-above-controls"); - - this.dumbMode = false; - } - - private static HideClutter(htmlElement: HTMLElement) { - const whiteList = new Set(); - do { - if(htmlElement === null){ - break; - } - if (htmlElement.classList.contains("clutter")) { - // Don't hide the parent element - whiteList.add(htmlElement) - } - htmlElement = htmlElement.parentElement; - } while (htmlElement != null) - - const clutter = document.getElementsByClassName("clutter"); - for (let i = 0; i < clutter.length; ++i) { - if (whiteList.has(clutter[i])) { - continue; - } - const classlist = clutter[i].classList; - if (classlist.contains("clutter-hidden")) { - continue; - } - classlist.add("clutter-hidden"); - } - + new Combine([returnToTheMap, title]) + .SetClass("border-b-2 border-black shadow md:shadow-none bg-white p-2 pb-0 md:p-0 flex flex-shrink-0"), + new Combine([content, ornament]) + .SetClass("block p-2 md:pt-4 w-full h-full overflow-y-auto md:max-h-65vh"), + // We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide + ]).SetClass("flex flex-col h-full relative bg-white") + ]).SetClass("fixed top-0 left-0 right-0 h-screen w-screen md:max-h-65vh md:w-auto md:relative z-above-controls"); } - /** - * Adds the 'clutter' class (which merely acts as a tag) onto some elements, e.g. the leaflet attributions - * @constructor - */ - private static PreparePatchesForFullscreen(): boolean { - const toHide = document.getElementsByClassName("leaflet-control-container"); - for (let i = 0; i < toHide.length; ++i) { - toHide[i].classList.add("clutter"); - } - return true; - } - - private static PatchLeaflet(htmlElement) { - if(htmlElement === undefined || htmlElement === null){ - return; - } - - let toHide = document.getElementsByClassName("leaflet-pane"); - for (let i = 0; i < toHide.length; ++i) { - toHide[i].classList.add("no-transform"); - toHide[i].classList.add("scrollable-fullscreen-no-transform"); - } - - toHide = document.getElementsByClassName("leaflet-popup"); - for (let i = 0; i < toHide.length; ++i) { - toHide[i].classList.add("no-transform"); - toHide[i].classList.add("scrollable-fullscreen-no-transform"); - } - - do { - // A leaflet workaround: in order for fullscreen to work, we need to get the parent element which does a transform3d and remove/read the transform - if (htmlElement.style.transform !== "") { - if (!htmlElement.classList.contains("no-transform")) { - htmlElement.classList.add("no-transform"); - htmlElement.classList.add("scrollable-fullscreen-no-transform") - } - } - htmlElement = htmlElement.parentElement; - } while (htmlElement != null) - - } - - public static RestoreLeaflet() { - const noTransf = document.getElementsByClassName("scrollable-fullscreen-no-transform"); - for (let i = 0; i < noTransf.length; ++i) { - noTransf[i].classList.remove("no-transform"); - noTransf[i].classList.remove("scrollable-fullscreen-no-transform"); - } - let clutter = document.getElementsByClassName("clutter-hidden"); - - do { - for (let i = 0; i < clutter.length; ++i) { - clutter[i].classList.remove("clutter-hidden"); - } - clutter = document.getElementsByClassName("clutter-hidden"); - } while (clutter.length > 0) - } - - InnerRender(): string { - return this._component.Render(); - } - - public PrepFullscreen(htmlElement = undefined) { - ScrollableFullScreen.PatchLeaflet(htmlElement); - - htmlElement = htmlElement ?? document.getElementById(this.id); - ScrollableFullScreen.HideClutter(htmlElement); - - } - - protected InnerUpdate(htmlElement: HTMLElement) { - this.PrepFullscreen(htmlElement) - super.InnerUpdate(htmlElement); - } - - Update() { - super.Update(); + private clear() { + ScrollableFullScreen.empty.AttachTo("fullscreen") + const fs = document.getElementById("fullscreen"); + fs.classList.add("hidden") } diff --git a/UI/BigComponents/FullWelcomePaneWithTabs.ts b/UI/BigComponents/FullWelcomePaneWithTabs.ts index 8edc8d76e..c0f945b32 100644 --- a/UI/BigComponents/FullWelcomePaneWithTabs.ts +++ b/UI/BigComponents/FullWelcomePaneWithTabs.ts @@ -23,13 +23,22 @@ export default class FullWelcomePaneWithTabs extends UIElement { private readonly _component: UIElement; - constructor(onClose: () => void) { + constructor(isShown: UIEventSource) { super(State.state.layoutToUse); this._layoutToUse = State.state.layoutToUse; this._userDetails = State.state.osmConnection.userDetails; - - const layoutToUse = this._layoutToUse.data; + + + this._component = new ScrollableFullScreen( + () => layoutToUse.title.Clone(), + () => FullWelcomePaneWithTabs.GenerateContents(layoutToUse, State.state.osmConnection.userDetails), + isShown + ) + } + + private static GenerateContents(layoutToUse: LayoutConfig, userDetails: UIEventSource) { + let welcome: UIElement = new ThemeIntroductionPanel(); if (layoutToUse.id === personal.id) { welcome = new PersonalLayersPanel(); @@ -58,7 +67,7 @@ export default class FullWelcomePaneWithTabs extends UIElement { tabs.push({ header: Svg.help, - content: new VariableUiElement(this._userDetails.map(userdetails => { + content: new VariableUiElement(userDetails.map(userdetails => { if (userdetails.csCount < Constants.userJourney.mapCompleteHelpUnlock) { return "" } @@ -67,15 +76,8 @@ export default class FullWelcomePaneWithTabs extends UIElement { } ); - const tabbedPart = new TabbedComponent(tabs, State.state.welcomeMessageOpenedTab) - .ListenTo(this._userDetails); - - - this._component = new ScrollableFullScreen( - layoutToUse.title, - tabbedPart, - onClose - ) + return new TabbedComponent(tabs, State.state.welcomeMessageOpenedTab) + .ListenTo(userDetails); } InnerRender(): string { diff --git a/UI/BigComponents/LayerControlPanel.ts b/UI/BigComponents/LayerControlPanel.ts index dc5dc0a62..0357600bb 100644 --- a/UI/BigComponents/LayerControlPanel.ts +++ b/UI/BigComponents/LayerControlPanel.ts @@ -6,13 +6,20 @@ import Combine from "../Base/Combine"; import {FixedUiElement} from "../Base/FixedUiElement"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; import Translations from "../i18n/Translations"; +import {UIEventSource} from "../../Logic/UIEventSource"; -export default class LayerControlPanel extends UIElement { - private readonly _panel: UIElement; +export default class LayerControlPanel extends ScrollableFullScreen { + constructor(isShown: UIEventSource) { + super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, isShown); + } - constructor(onClose: () => void) { - super(); + private static GenTitle(): UIElement { + const title = Translations.t.general.layerSelection.title.SetClass("text-2xl break-words font-bold p-2") + return title.Clone(); + } + + private static GeneratePanel() { let layerControlPanel: UIElement = new FixedUiElement(""); if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { layerControlPanel = new BackgroundSelector(); @@ -28,14 +35,7 @@ export default class LayerControlPanel extends UIElement { layerControlPanel = new Combine([layerSelection, "
", layerControlPanel]); } - - const title = Translations.t.general.layerSelection.title.SetClass("text-2xl break-words font-bold p-2") - - this._panel = new ScrollableFullScreen(title, layerControlPanel, onClose); - } - - InnerRender(): string { - return this._panel.Render(); + return layerControlPanel; } } \ No newline at end of file diff --git a/UI/OpeningHours/OhVisualization.ts b/UI/OpeningHours/OhVisualization.ts index 937ca600b..34c4b55a0 100644 --- a/UI/OpeningHours/OhVisualization.ts +++ b/UI/OpeningHours/OhVisualization.ts @@ -314,7 +314,7 @@ export default class OpeningHoursVisualization extends UIElement { return new Combine([ - "", + "
", rows.map(el => "" + el.Render() + "").join(""), "
" ]).SetClass("ohviz-container").Render(); diff --git a/UI/OpeningHours/OpeningHoursPickerTable.ts b/UI/OpeningHours/OpeningHoursPickerTable.ts index 2248d7a2f..5192e7bfc 100644 --- a/UI/OpeningHours/OpeningHoursPickerTable.ts +++ b/UI/OpeningHours/OpeningHoursPickerTable.ts @@ -63,7 +63,6 @@ export default class OpeningHoursPickerTable extends InputElement protected InnerUpdate() { const self = this; const table = (document.getElementById(`oh-table-${this.id}`) as HTMLTableElement); - console.log("Inner update!") if (table === undefined || table === null) { return; } diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index 55c9d9845..1e92baffa 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -9,26 +9,21 @@ import State from "../../State"; import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; -export default class FeatureInfoBox extends UIElement { +export default class FeatureInfoBox extends ScrollableFullScreen { private static featureInfoboxCache: Map, FeatureInfoBox>> = new Map, FeatureInfoBox>>(); - private _component: ScrollableFullScreen; private constructor( tags: UIEventSource, - layerConfig: LayerConfig, - onClose: () => void + layerConfig: LayerConfig ) { - super(); + super(() => FeatureInfoBox.GenerateTitleBar(tags, layerConfig),() => FeatureInfoBox.GenerateContent(tags, layerConfig)); if (layerConfig === undefined) { - throw "Undefined layerconfig" + throw "Undefined layerconfig"; } - const title = FeatureInfoBox.GenerateTitleBar(tags, layerConfig); - const contents = FeatureInfoBox.GenerateContent(tags, layerConfig); - this._component = new ScrollableFullScreen(title, contents, onClose); } - static construct(tags: UIEventSource, layer: LayerConfig, onClose: () => void) { + static construct(tags: UIEventSource, layer: LayerConfig): FeatureInfoBox { let innerMap = FeatureInfoBox.featureInfoboxCache.get(layer); if (innerMap === undefined) { innerMap = new Map, FeatureInfoBox>(); @@ -37,7 +32,7 @@ export default class FeatureInfoBox extends UIElement { let featureInfoBox = innerMap.get(tags); if (featureInfoBox === undefined) { - featureInfoBox = new FeatureInfoBox(tags, layer, onClose); + featureInfoBox = new FeatureInfoBox(tags, layer); innerMap.set(tags, featureInfoBox); } return featureInfoBox; @@ -48,7 +43,7 @@ export default class FeatureInfoBox extends UIElement { const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined)) .SetClass("break-words font-bold sm:p-0.5 md:p-1 sm:p-1.5 md:p-2"); const titleIcons = new Combine( - layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon, + layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon, "block w-8 h-8 align-baseline box-content sm:p-0.5", "width: 2rem !important;") .HideOnEmpty(true) )) @@ -90,7 +85,4 @@ export default class FeatureInfoBox extends UIElement { } - InnerRender(): string { - return this._component.Render(); - } } diff --git a/UI/Reviews/ReviewElement.ts b/UI/Reviews/ReviewElement.ts index 39e727e1a..2b6de019e 100644 --- a/UI/Reviews/ReviewElement.ts +++ b/UI/Reviews/ReviewElement.ts @@ -33,7 +33,7 @@ export default class ReviewElement extends UIElement { const avg = (revs.map(review => review.rating).reduce((a, b) => a + b, 0) / revs.length); elements.push( new Combine([ - SingleReview.GenStars(avg).SetClass("stars"), + SingleReview.GenStars(avg).SetClass("stars flex"), ``, revs.length === 1 ? Translations.t.reviews.title_singular : Translations.t.reviews.title diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index eb8879a45..f10bc41f6 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -9,7 +9,6 @@ import State from "../State"; import LazyElement from "./Base/LazyElement"; import FeatureInfoBox from "./Popup/FeatureInfoBox"; import LayoutConfig from "../Customizations/JSON/LayoutConfig"; -import ScrollableFullScreen from "./Base/ScrollableFullScreen"; import {GeoOperations} from "../Logic/GeoOperations"; @@ -125,18 +124,19 @@ export default class ShowDataLayer { }, leafletLayer); const tags = State.state.allElements.getEventSourceFor(feature); - const uiElement = new LazyElement(() => - FeatureInfoBox.construct(tags, layer, () => { - State.state.selectedElement.setData(undefined); - leafletLayer.closePopup(); - popup.remove(); - ScrollableFullScreen.RestoreLeaflet(); - }), - "
Rendering
"); // By setting 90vh, leaflet will attempt to fit the entire screen and move the feature down + const uiElement = new LazyElement(() => { + const infoBox = FeatureInfoBox.construct(tags, layer); + infoBox.isShown.addCallback(isShown => { + if(!isShown){ + State.state.selectedElement.setData(undefined); + leafletLayer.closePopup(); + popup.remove(); + } + }); + return infoBox; + }, + "
Rendering
"); // By setting 50vh, leaflet will attempt to fit the entire screen and move the feature down popup.setContent(uiElement.Render()); - popup.on('remove', () => { - ScrollableFullScreen.RestoreLeaflet(); // Just in case... - }); leafletLayer.bindPopup(popup); // We first render the UIelement (which'll still need an update later on...) // But at least it'll be visible already @@ -145,7 +145,6 @@ export default class ShowDataLayer { leafletLayer.on("popupopen", () => { State.state.selectedElement.setData(feature); uiElement.Activate(); - uiElement.Update(); }) State.state.selectedElement.addCallbackAndRun(selected => { diff --git a/css/openinghourstable.css b/css/openinghourstable.css index 4d04de090..20d76cf29 100644 --- a/css/openinghourstable.css +++ b/css/openinghourstable.css @@ -4,6 +4,7 @@ height: 100%; text-align: center; word-break: normal; + word-wrap: normal; } .oh-table th { padding: 0; @@ -170,6 +171,7 @@ .ohviz-table { word-break: normal; + word-wrap: normal; } .ohviz-range { diff --git a/index.css b/index.css index ba86a513c..756fda0ec 100644 --- a/index.css +++ b/index.css @@ -46,20 +46,6 @@ } } -@media only screen and (max-width: 768px) { - .no-transform { - /*This is a workaround to let popup contents escape the popup on mobile - see scrollableFullScreen.ts*/ - transform: none !important; - } - - .clutter-hidden { - /*This is a workaround to let popup contents escape the popup on mobile - see scrollableFullScreen.ts*/ - visibility: hidden !important; - } -} - - - :root { --subtle-detail-color: #e5f5ff; @@ -79,10 +65,6 @@ --image-carousel-height: 400px; } -.clutter { - /*Clutter is actually a class indicating that the element should be hidden when a scrollableFullScreen is opened - It doesn't actually define any rules*/ -} .slick-carousel-content { width: 300px; max-height: var(--image-carousel-height); diff --git a/index.html b/index.html index 5b343fac1..69ecf17ca 100644 --- a/index.html +++ b/index.html @@ -47,7 +47,8 @@ -
+ +
-
-
+
+
Loading MapComplete, hang on...