Refactoring fullscreenhandling
This commit is contained in:
parent
e1a4c75391
commit
00f610c589
23 changed files with 346 additions and 245 deletions
|
@ -12,7 +12,6 @@ import CenterMessageBox from "./UI/CenterMessageBox";
|
||||||
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
||||||
import UserBadge from "./UI/BigComponents/UserBadge";
|
import UserBadge from "./UI/BigComponents/UserBadge";
|
||||||
import SearchAndGo from "./UI/BigComponents/SearchAndGo";
|
import SearchAndGo from "./UI/BigComponents/SearchAndGo";
|
||||||
import FullScreenMessageBox from "./UI/FullScreenMessageBoxHandler";
|
|
||||||
import GeoLocationHandler from "./Logic/Actors/GeoLocationHandler";
|
import GeoLocationHandler from "./Logic/Actors/GeoLocationHandler";
|
||||||
import {LocalStorageSource} from "./Logic/Web/LocalStorageSource";
|
import {LocalStorageSource} from "./Logic/Web/LocalStorageSource";
|
||||||
import {Utils} from "./Utils";
|
import {Utils} from "./Utils";
|
||||||
|
@ -33,7 +32,6 @@ import FeatureSwitched from "./UI/Base/FeatureSwitched";
|
||||||
import LayerConfig from "./Customizations/JSON/LayerConfig";
|
import LayerConfig from "./Customizations/JSON/LayerConfig";
|
||||||
import ShowDataLayer from "./UI/ShowDataLayer";
|
import ShowDataLayer from "./UI/ShowDataLayer";
|
||||||
import Hash from "./Logic/Web/Hash";
|
import Hash from "./Logic/Web/Hash";
|
||||||
import HistoryHandling from "./Logic/Actors/HistoryHandling";
|
|
||||||
import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline";
|
import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline";
|
||||||
|
|
||||||
export class InitUiElements {
|
export class InitUiElements {
|
||||||
|
@ -118,8 +116,6 @@ export class InitUiElements {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
new HistoryHandling(Hash.hash, State.state.fullScreenMessage);
|
|
||||||
|
|
||||||
InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => {
|
InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => {
|
||||||
new UserBadge().AttachTo('userbadge');
|
new UserBadge().AttachTo('userbadge');
|
||||||
});
|
});
|
||||||
|
@ -129,9 +125,6 @@ export class InitUiElements {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
new FullScreenMessageBox().AttachTo("messagesboxmobile");
|
|
||||||
|
|
||||||
|
|
||||||
InitUiElements.OnlyIf(State.state.featureSwitchWelcomeMessage, () => {
|
InitUiElements.OnlyIf(State.state.featureSwitchWelcomeMessage, () => {
|
||||||
InitUiElements.InitWelcomeMessage()
|
InitUiElements.InitWelcomeMessage()
|
||||||
});
|
});
|
||||||
|
@ -214,18 +207,18 @@ export class InitUiElements {
|
||||||
private static InitWelcomeMessage() {
|
private static InitWelcomeMessage() {
|
||||||
|
|
||||||
const isOpened = new UIEventSource<boolean>(true);
|
const isOpened = new UIEventSource<boolean>(true);
|
||||||
const fullOptions = new FullWelcomePaneWithTabs(() => isOpened.setData(false));
|
const fullOptions = new FullWelcomePaneWithTabs(() => {
|
||||||
|
console.log("Closing the welcome message...")
|
||||||
|
isOpened.setData(false);
|
||||||
|
});
|
||||||
|
|
||||||
// ?-Button on Desktop, opens panel with close-X.
|
// ?-Button on Desktop, opens panel with close-X.
|
||||||
const help = Svg.help_svg().SetClass("open-welcome-button block");
|
const help = Svg.help_svg().SetClass("open-welcome-button block");
|
||||||
const close = Svg.close_svg().SetClass("close-welcome-button");
|
|
||||||
const checkbox = new CheckBox(
|
const checkbox = new CheckBox(
|
||||||
new Combine([
|
|
||||||
close,
|
|
||||||
fullOptions
|
fullOptions
|
||||||
.SetClass("welcomeMessage")
|
.SetClass("welcomeMessage")
|
||||||
.onClick(() => {/*Catch the click*/
|
.onClick(() => {/*Catch the click*/
|
||||||
})]),
|
}),
|
||||||
help
|
help
|
||||||
, isOpened
|
, isOpened
|
||||||
).AttachTo("messagesbox");
|
).AttachTo("messagesbox");
|
||||||
|
@ -252,15 +245,8 @@ export class InitUiElements {
|
||||||
const layerControlPanel = new LayerControlPanel(
|
const layerControlPanel = new LayerControlPanel(
|
||||||
() => State.state.layerControlIsOpened.setData(false))
|
() => State.state.layerControlIsOpened.setData(false))
|
||||||
.SetClass("block p-1 rounded-full");
|
.SetClass("block p-1 rounded-full");
|
||||||
const closeButton = Svg.close_svg()
|
|
||||||
.SetClass("layer-selection-toggle")
|
|
||||||
.SetStyle(" background: var(--subtle-detail-color);")
|
|
||||||
const checkbox = new CheckBox(
|
const checkbox = new CheckBox(
|
||||||
new Combine([
|
layerControlPanel,
|
||||||
closeButton,
|
|
||||||
layerControlPanel])
|
|
||||||
.SetClass("flex flex-row")
|
|
||||||
,
|
|
||||||
Svg.layers_svg().SetClass("layer-selection-toggle"),
|
Svg.layers_svg().SetClass("layer-selection-toggle"),
|
||||||
State.state.layerControlIsOpened
|
State.state.layerControlIsOpened
|
||||||
).AttachTo("layer-selection");
|
).AttachTo("layer-selection");
|
||||||
|
@ -388,7 +374,6 @@ export class InitUiElements {
|
||||||
State.state.selectedElement,
|
State.state.selectedElement,
|
||||||
State.state.filteredLayers,
|
State.state.filteredLayers,
|
||||||
State.state.leafletMap,
|
State.state.leafletMap,
|
||||||
State.state.fullScreenMessage,
|
|
||||||
() => {
|
() => {
|
||||||
return new SimpleAddUI(
|
return new SimpleAddUI(
|
||||||
() => State.state.LastClickLocation.setData(undefined)
|
() => State.state.LastClickLocation.setData(undefined)
|
||||||
|
|
|
@ -17,7 +17,6 @@ export default class StrayClickHandler {
|
||||||
selectedElement: UIEventSource<string>,
|
selectedElement: UIEventSource<string>,
|
||||||
filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource<boolean> }[]>,
|
filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource<boolean> }[]>,
|
||||||
leafletMap: UIEventSource<L.Map>,
|
leafletMap: UIEventSource<L.Map>,
|
||||||
fullscreenMessage: UIEventSource<{content: UIElement, hashText: string}>,
|
|
||||||
uiToShow: (() => UIElement)) {
|
uiToShow: (() => UIElement)) {
|
||||||
this._uiToShow = uiToShow;
|
this._uiToShow = uiToShow;
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
|
@ -3,31 +3,70 @@ import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
|
||||||
import Translations from "../../UI/i18n/Translations";
|
import Translations from "../../UI/i18n/Translations";
|
||||||
import Locale from "../../UI/i18n/Locale";
|
import Locale from "../../UI/i18n/Locale";
|
||||||
import {UIElement} from "../../UI/UIElement";
|
import {UIElement} from "../../UI/UIElement";
|
||||||
|
import TagRenderingAnswer from "../../UI/Popup/TagRenderingAnswer";
|
||||||
|
import {ElementStorage} from "../ElementStorage";
|
||||||
|
import Combine from "../../UI/Base/Combine";
|
||||||
|
|
||||||
|
class TitleElement extends UIElement {
|
||||||
|
private readonly _layoutToUse: UIEventSource<LayoutConfig>;
|
||||||
|
private readonly _selectedFeature: UIEventSource<any>;
|
||||||
|
private readonly _allElementsStorage: ElementStorage;
|
||||||
|
|
||||||
|
constructor(layoutToUse: UIEventSource<LayoutConfig>,
|
||||||
|
selectedFeature: UIEventSource<any>,
|
||||||
|
allElementsStorage : ElementStorage) {
|
||||||
|
super(layoutToUse);
|
||||||
|
this._layoutToUse = layoutToUse;
|
||||||
|
this._selectedFeature = selectedFeature;
|
||||||
|
this._allElementsStorage = allElementsStorage;
|
||||||
|
this.ListenTo(Locale.language);
|
||||||
|
this.dumbMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerRender(): string {
|
||||||
|
|
||||||
|
const defaultTitle = Translations.WT(this._layoutToUse.data?.title)?.txt ?? "MapComplete"
|
||||||
|
const feature = this._selectedFeature.data;
|
||||||
|
|
||||||
|
if(feature === undefined){
|
||||||
|
return defaultTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const layout = this._layoutToUse.data;
|
||||||
|
const properties = this._selectedFeature.data.properties;
|
||||||
|
for (const layer of layout.layers) {
|
||||||
|
if(layer.title === undefined){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (layer.overpassTags.matchesProperties(properties)) {
|
||||||
|
|
||||||
|
const title = new TagRenderingAnswer(
|
||||||
|
this._allElementsStorage.getEventSourceFor(feature),
|
||||||
|
layer.title
|
||||||
|
)
|
||||||
|
return new Combine([defaultTitle," | ", title]).Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export default class TitleHandler {
|
export default class TitleHandler {
|
||||||
constructor(layoutToUse: UIEventSource<LayoutConfig>, fullScreenMessage: UIEventSource<{ content: UIElement, hashText: string, titleText?: UIElement }>) {
|
constructor(layoutToUse: UIEventSource<LayoutConfig>,
|
||||||
|
selectedFeature: UIEventSource<any>,
|
||||||
|
allElementsStorage : ElementStorage) {
|
||||||
|
|
||||||
|
new TitleElement(layoutToUse, selectedFeature, allElementsStorage)
|
||||||
|
.addCallbackAndRun(contents => {
|
||||||
|
|
||||||
|
const d = document.createElement('div');
|
||||||
|
d.innerHTML = contents;
|
||||||
|
// We pass everything into a div to strip out images etc...
|
||||||
|
document.title = (d.textContent || d.innerText);
|
||||||
|
|
||||||
layoutToUse.map((layoutToUse) => {
|
|
||||||
return Translations.WT(layoutToUse?.title)?.txt ?? "MapComplete"
|
|
||||||
}, [Locale.language]
|
|
||||||
).addCallbackAndRun((title) => {
|
|
||||||
document.title = title
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fullScreenMessage.addCallbackAndRun(selected => {
|
|
||||||
const title = Translations.WT(layoutToUse.data?.title)?.txt ?? "MapComplete"
|
|
||||||
if(selected?.titleText?.data === undefined){
|
|
||||||
document.title = title
|
|
||||||
}else{
|
|
||||||
selected.titleText.Update();
|
|
||||||
var d = document.createElement('div');
|
|
||||||
d.innerHTML = selected.titleText.InnerRender();
|
|
||||||
const poi = (d.textContent || d.innerText)
|
|
||||||
document.title = title + " | " + poi;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -74,7 +74,7 @@ export default class MetaTagging {
|
||||||
const tagsSource = State.state.allElements.getEventSourceFor(feature);
|
const tagsSource = State.state.allElements.getEventSourceFor(feature);
|
||||||
tagsSource.ping();
|
tagsSource.ping();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.warn(e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {Utils} from "../../Utils";
|
||||||
|
|
||||||
export class OsmPreferences {
|
export class OsmPreferences {
|
||||||
|
|
||||||
public preferences = new UIEventSource<any>({});
|
public preferences = new UIEventSource<any>({}, "all-osm-preferences");
|
||||||
public preferenceSources: any = {}
|
public preferenceSources: any = {}
|
||||||
private auth: any;
|
private auth: any;
|
||||||
private userDetails: UIEventSource<UserDetails>;
|
private userDetails: UIEventSource<UserDetails>;
|
||||||
|
@ -29,7 +29,7 @@ export class OsmPreferences {
|
||||||
return this.longPreferences[prefix + key];
|
return this.longPreferences[prefix + key];
|
||||||
}
|
}
|
||||||
|
|
||||||
const source = new UIEventSource<string>(undefined);
|
const source = new UIEventSource<string>(undefined, "long-osm-preference:"+prefix+key);
|
||||||
this.longPreferences[prefix + key] = source;
|
this.longPreferences[prefix + key] = source;
|
||||||
|
|
||||||
const allStartWith = prefix + key + "-combined";
|
const allStartWith = prefix + key + "-combined";
|
||||||
|
@ -106,7 +106,7 @@ export class OsmPreferences {
|
||||||
if (this.userDetails.data.loggedIn && this.preferences.data[key] === undefined) {
|
if (this.userDetails.data.loggedIn && this.preferences.data[key] === undefined) {
|
||||||
this.UpdatePreferences();
|
this.UpdatePreferences();
|
||||||
}
|
}
|
||||||
const pref = new UIEventSource<string>(this.preferences.data[key]);
|
const pref = new UIEventSource<string>(this.preferences.data[key],"osm-preference:"+key);
|
||||||
pref.addCallback((v) => {
|
pref.addCallback((v) => {
|
||||||
this.SetPreference(key, v);
|
this.SetPreference(key, v);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,60 @@
|
||||||
export class UIEventSource<T> {
|
export class UIEventSource<T> {
|
||||||
|
|
||||||
public data: T;
|
public data: T;
|
||||||
|
private readonly tag: string;
|
||||||
private _callbacks = [];
|
private _callbacks = [];
|
||||||
|
|
||||||
constructor(data: T) {
|
private static allSources : UIEventSource<any>[] = UIEventSource.PrepPerf();
|
||||||
|
|
||||||
|
static PrepPerf(){
|
||||||
|
// @ts-ignore
|
||||||
|
window.mcperf = () => {
|
||||||
|
console.log(UIEventSource.allSources.length, "uieventsources created");
|
||||||
|
const copy = [...UIEventSource.allSources];
|
||||||
|
copy.sort((a,b) => b._callbacks.length - a._callbacks.length);
|
||||||
|
console.log("Topten is:")
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
console.log(copy[i].tag, copy[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(data: T, tag: string = "") {
|
||||||
|
this.tag = tag;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
UIEventSource.allSources.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static flatten<X>(source: UIEventSource<UIEventSource<X>>, possibleSources: UIEventSource<any>[]): UIEventSource<X> {
|
||||||
|
const sink = new UIEventSource<X>(source.data?.data);
|
||||||
|
|
||||||
|
source.addCallback((latestData) => {
|
||||||
|
sink.setData(latestData?.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const possibleSource of possibleSources) {
|
||||||
|
possibleSource?.addCallback(() => {
|
||||||
|
sink.setData(source.data?.data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Chronic(millis: number, asLong: () => boolean = undefined): UIEventSource<Date> {
|
||||||
|
const source = new UIEventSource<Date>(undefined);
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
source.setData(new Date());
|
||||||
|
if (asLong === undefined || asLong()) {
|
||||||
|
window.setTimeout(run, millis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
return source;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public addCallback(callback: ((latestData: T) => void)): UIEventSource<T> {
|
public addCallback(callback: ((latestData: T) => void)): UIEventSource<T> {
|
||||||
|
@ -36,22 +86,6 @@ export class UIEventSource<T>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static flatten<X>(source: UIEventSource<UIEventSource<X>>, possibleSources: UIEventSource<any>[]): UIEventSource<X> {
|
|
||||||
const sink = new UIEventSource<X>(source.data?.data);
|
|
||||||
|
|
||||||
source.addCallback((latestData) => {
|
|
||||||
sink.setData(latestData?.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const possibleSource of possibleSources) {
|
|
||||||
possibleSource?.addCallback(() => {
|
|
||||||
sink.setData(source.data?.data);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return sink;
|
|
||||||
}
|
|
||||||
|
|
||||||
public map<J>(f: ((T) => J),
|
public map<J>(f: ((T) => J),
|
||||||
extraSources: UIEventSource<any>[] = [],
|
extraSources: UIEventSource<any>[] = [],
|
||||||
g: ((J) => T) = undefined): UIEventSource<J> {
|
g: ((J) => T) = undefined): UIEventSource<J> {
|
||||||
|
@ -79,7 +113,6 @@ export class UIEventSource<T>{
|
||||||
return newSource;
|
return newSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public syncWith(otherSource: UIEventSource<T>, reverseOverride = false): UIEventSource<T> {
|
public syncWith(otherSource: UIEventSource<T>, reverseOverride = false): UIEventSource<T> {
|
||||||
this.addCallback((latest) => otherSource.setData(latest));
|
this.addCallback((latest) => otherSource.setData(latest));
|
||||||
const self = this;
|
const self = this;
|
||||||
|
@ -112,19 +145,4 @@ export class UIEventSource<T>{
|
||||||
return newSource;
|
return newSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Chronic(millis: number, asLong: () => boolean = undefined): UIEventSource<Date> {
|
|
||||||
const source = new UIEventSource<Date>(undefined);
|
|
||||||
|
|
||||||
function run() {
|
|
||||||
source.setData(new Date());
|
|
||||||
if (asLong === undefined || asLong()) {
|
|
||||||
window.setTimeout(run, millis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
return source;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ export class LocalStorageSource {
|
||||||
static Get(key: string, defaultValue: string = undefined): UIEventSource<string> {
|
static Get(key: string, defaultValue: string = undefined): UIEventSource<string> {
|
||||||
try {
|
try {
|
||||||
const saved = localStorage.getItem(key);
|
const saved = localStorage.getItem(key);
|
||||||
const source = new UIEventSource<string>(saved ?? defaultValue);
|
const source = new UIEventSource<string>(saved ?? defaultValue, "localstorage:"+key);
|
||||||
|
|
||||||
source.addCallback((data) => {
|
source.addCallback((data) => {
|
||||||
localStorage.setItem(key, data);
|
localStorage.setItem(key, data);
|
||||||
|
|
6
State.ts
6
State.ts
|
@ -72,10 +72,6 @@ export default class State {
|
||||||
* The message that should be shown at the center of the screen
|
* The message that should be shown at the center of the screen
|
||||||
*/
|
*/
|
||||||
public readonly centerMessage = new UIEventSource<string>("");
|
public readonly centerMessage = new UIEventSource<string>("");
|
||||||
/**
|
|
||||||
This message is shown full screen on mobile devices
|
|
||||||
*/
|
|
||||||
public readonly fullScreenMessage = new UIEventSource<{ content: UIElement, hashText: string, titleText?: UIElement }>(undefined)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The latest element that was selected - used to generate the right UI at the right place
|
The latest element that was selected - used to generate the right UI at the right place
|
||||||
|
@ -244,7 +240,7 @@ export default class State {
|
||||||
}
|
}
|
||||||
}).ping()
|
}).ping()
|
||||||
|
|
||||||
new TitleHandler(this.layoutToUse, this.fullScreenMessage);
|
new TitleHandler(this.layoutToUse, this.selectedElement, this.allElements);
|
||||||
|
|
||||||
|
|
||||||
this.allElements = new ElementStorage();
|
this.allElements = new ElementStorage();
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
import {UIElement} from "../UIElement";
|
import {UIElement} from "../UIElement";
|
||||||
|
|
||||||
export default class LazyElement extends UIElement {
|
export default class LazyElement<T extends UIElement> extends UIElement {
|
||||||
|
|
||||||
|
|
||||||
private _content: UIElement = undefined;
|
public Activate: (onElement?: (element: T) => void) => void;
|
||||||
|
private _content: T = undefined;
|
||||||
|
private readonly _loadingContent: string;
|
||||||
|
|
||||||
public Activate: () => void;
|
constructor(content: (() => T), loadingContent = "Rendering...") {
|
||||||
private _loadingContent: string;
|
|
||||||
|
|
||||||
constructor(content: (() => UIElement), loadingContent = "Rendering...") {
|
|
||||||
super();
|
super();
|
||||||
this._loadingContent = loadingContent;
|
this._loadingContent = loadingContent;
|
||||||
this.dumbMode = false;
|
this.dumbMode = false;
|
||||||
const self = this;
|
const self = this;
|
||||||
this.Activate = () => {
|
this.Activate = (onElement?: (element: T) => void) => {
|
||||||
|
console.log("ACTIVATED")
|
||||||
if (this._content === undefined) {
|
if (this._content === undefined) {
|
||||||
self._content = content();
|
self._content = content();
|
||||||
}
|
}
|
||||||
|
if (onElement) {
|
||||||
|
onElement(self._content)
|
||||||
|
}
|
||||||
self.Update();
|
self.Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,4 +31,6 @@ export default class LazyElement extends UIElement {
|
||||||
return this._content.InnerRender();
|
return this._content.InnerRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import {UIElement} from "../UIElement";
|
import {UIElement} from "../UIElement";
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg";
|
||||||
import State from "../../State";
|
|
||||||
import Combine from "./Combine";
|
import Combine from "./Combine";
|
||||||
import Ornament from "./Ornament";
|
import Ornament from "./Ornament";
|
||||||
|
|
||||||
|
@ -8,22 +7,38 @@ import Ornament from "./Ornament";
|
||||||
* Wraps some contents into a panel that scrolls the content _under_ the title
|
* Wraps some contents into a panel that scrolls the content _under_ the title
|
||||||
*/
|
*/
|
||||||
export default class ScrollableFullScreen extends UIElement {
|
export default class ScrollableFullScreen extends UIElement {
|
||||||
|
private static _isInited = false;
|
||||||
|
private title: UIElement;
|
||||||
|
private content: UIElement;
|
||||||
private _component: UIElement;
|
private _component: UIElement;
|
||||||
private elementsToRestore: Set<HTMLElement> = new Set<HTMLElement>();
|
|
||||||
|
|
||||||
constructor(title: UIElement, content: UIElement, onClose: (() => void)) {
|
constructor(title: UIElement, content: UIElement, onClose: (() => void)) {
|
||||||
super();
|
super();
|
||||||
this.dumbMode = false;
|
this.content = content;
|
||||||
const returnToTheMap = Svg.back_svg().onClick(() => {
|
this.title = title;
|
||||||
console.log("Clicked back!");
|
if (!ScrollableFullScreen._isInited) {
|
||||||
this.RestoreLeaflet();
|
ScrollableFullScreen._isInited = ScrollableFullScreen.PreparePatchesForFullscreen();
|
||||||
if (onClose() !== undefined) {
|
|
||||||
console.error("WARNING: onClose is not defined")
|
|
||||||
onClose();
|
|
||||||
}
|
}
|
||||||
}).SetClass("block sm:hidden mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5")
|
if (onClose === undefined) {
|
||||||
|
console.error("ScrollableFullScreen initialized without onClose!")
|
||||||
|
}
|
||||||
|
this.dumbMode = false;
|
||||||
|
const returnToTheMap =
|
||||||
|
new Combine([
|
||||||
|
Svg.back_svg().SetClass("block sm:hidden"),
|
||||||
|
Svg.close_svg().SetClass("hidden sm:block")
|
||||||
|
])
|
||||||
|
.onClick(() => {
|
||||||
|
console.log("Clicked back!");
|
||||||
|
ScrollableFullScreen.RestoreLeaflet();
|
||||||
|
if (onClose !== undefined) {
|
||||||
|
onClose();
|
||||||
|
} else {
|
||||||
|
console.error("WARNING: onClose is not defined")
|
||||||
|
}
|
||||||
|
}).SetClass("mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5")
|
||||||
|
|
||||||
title.SetClass("block w-full")
|
title.SetClass("block w-full text-2xl font-bold p-2 pl-4")
|
||||||
const ornament = new Combine([new Ornament().SetStyle("height:5em;")])
|
const ornament = new Combine([new Ornament().SetStyle("height:5em;")])
|
||||||
.SetClass("block sm:hidden h-5")
|
.SetClass("block sm:hidden h-5")
|
||||||
|
|
||||||
|
@ -32,39 +47,110 @@ export default class ScrollableFullScreen extends UIElement {
|
||||||
new Combine([
|
new Combine([
|
||||||
new Combine([
|
new Combine([
|
||||||
new Combine([returnToTheMap, title])
|
new Combine([returnToTheMap, title])
|
||||||
.AddClass("border-b-2 border-black shadow sm:shadow-none bg-white p-2 pb-0 sm:p-0 flex overflow-x-hidden flex-shrink-0 max-h-20vh"),
|
.SetClass("border-b-2 border-black shadow sm:shadow-none 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])
|
new Combine(["<span>", content, "</span>", ornament])
|
||||||
.SetClass("block p-2 sm:pt-4 w-full h-screen landscape:h-screen sm:h-full sm:w-full overflow-y-auto overflow-x-hidden"),
|
.SetClass("block p-2 sm:pt-4 w-full h-screen landscape:h-screen sm:h-full sm:w-full 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
|
// 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 relative bg-white")
|
]).SetClass("block flex flex-col relative bg-white")
|
||||||
]).SetClass("fixed top-0 left-0 right-0 h-screen w-screen sm:max-h-65vh sm:w-auto");
|
]).SetClass("fixed top-0 left-0 right-0 h-screen w-screen sm:max-h-65vh sm:w-auto sm:relative");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static HideClutter(htmlElement: HTMLElement) {
|
||||||
|
const whiteList = new Set<Element>();
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 === null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RestoreLeaflet() {
|
||||||
|
console.log("Restoring")
|
||||||
|
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 {
|
InnerRender(): string {
|
||||||
return this._component.Render();
|
return this._component.Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
Update() {
|
||||||
|
console.log("Updating the scrollableFullScreen")
|
||||||
do {
|
super.Update();
|
||||||
// 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
|
this._component.Update();
|
||||||
if (htmlElement.style.transform !== "") {
|
|
||||||
this.elementsToRestore.add(htmlElement);
|
|
||||||
htmlElement.classList.add("no-transform")
|
|
||||||
}
|
}
|
||||||
htmlElement = htmlElement.parentElement;
|
|
||||||
} while (htmlElement != null)
|
|
||||||
|
|
||||||
|
public PrepFullscreen(htmlElement = undefined) {
|
||||||
|
htmlElement = htmlElement ?? document.getElementById(this.id);
|
||||||
|
ScrollableFullScreen.PatchLeaflet(htmlElement);
|
||||||
|
ScrollableFullScreen.HideClutter(htmlElement);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||||
|
this.PrepFullscreen(htmlElement)
|
||||||
super.InnerUpdate(htmlElement);
|
super.InnerUpdate(htmlElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RestoreLeaflet() {
|
|
||||||
this.elementsToRestore.forEach(
|
|
||||||
el => el.classList.remove("no-transform")
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -24,9 +24,9 @@ export class SubtleButton extends UIElement{
|
||||||
} else {
|
} else {
|
||||||
img = imageUrl;
|
img = imageUrl;
|
||||||
}
|
}
|
||||||
img.AddClass("block flex items-center justify-center h-11 w-11 flex-shrink0")
|
img.SetClass("block flex items-center justify-center h-11 w-11 flex-shrink0")
|
||||||
this.image = new Combine([img])
|
this.image = new Combine([img])
|
||||||
.AddClass("flex-shrink-0");
|
.SetClass("flex-shrink-0");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ export class SubtleButton extends UIElement{
|
||||||
return new Combine([
|
return new Combine([
|
||||||
this.image,
|
this.image,
|
||||||
this.message,
|
this.message,
|
||||||
]).AddClass("block flex p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200")
|
]).SetClass("block flex p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200")
|
||||||
.Render();
|
.Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,22 +7,22 @@ export default class IndexText extends Combine {
|
||||||
constructor() {
|
constructor() {
|
||||||
super([
|
super([
|
||||||
new FixedUiElement(`<img class="w-12 h-12 sm:h-24 sm:w-24" src="./assets/svg/logo.svg" alt="MapComplete Logo">`)
|
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"),
|
.SetClass("flex-none m-3"),
|
||||||
|
|
||||||
new Combine([
|
new Combine([
|
||||||
Translations.t.index.title
|
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"),
|
.SetClass("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(
|
Translations.t.index.intro.SetClass(
|
||||||
"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"),
|
"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")
|
Translations.t.index.pickTheme.SetClass("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")
|
]).SetClass("flex flex-col sm:text-center lg:text-left m-1 mt-2 md:m-2 md:mt-4")
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
this.AddClass("flex flex-row");
|
this.SetClass("flex flex-row");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ export default class SearchAndGo extends UIElement {
|
||||||
);
|
);
|
||||||
|
|
||||||
private _foundEntries = new UIEventSource([]);
|
private _foundEntries = new UIEventSource([]);
|
||||||
private _goButton = Svg.search_ui().AddClass('w-8 h-8 full-rounded border-black float-right');
|
private _goButton = Svg.search_ui().SetClass('w-8 h-8 full-rounded border-black float-right');
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(undefined);
|
super(undefined);
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
import {UIElement} from "./UIElement";
|
|
||||||
import State from "../State";
|
|
||||||
import Combine from "./Base/Combine";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the full screen popup on mobile
|
|
||||||
*/
|
|
||||||
export default class FullScreenMessageBox extends UIElement {
|
|
||||||
|
|
||||||
private _content: UIElement;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super(State.state.fullScreenMessage);
|
|
||||||
this.HideOnEmpty(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
InnerRender(): string {
|
|
||||||
if (State.state.fullScreenMessage.data === undefined) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
this._content = State.state.fullScreenMessage.data.content;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -9,29 +9,41 @@ import State from "../../State";
|
||||||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
||||||
|
|
||||||
export default class FeatureInfoBox extends UIElement {
|
export default class FeatureInfoBox extends ScrollableFullScreen {
|
||||||
private _component: UIElement;
|
|
||||||
|
|
||||||
public title: UIElement ;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
tags: UIEventSource<any>,
|
tags: UIEventSource<any>,
|
||||||
layerConfig: LayerConfig,
|
layerConfig: LayerConfig,
|
||||||
onClose: () => {}
|
onClose: () => void
|
||||||
) {
|
) {
|
||||||
super();
|
super(
|
||||||
|
FeatureInfoBox.GenerateTitleBar(tags, layerConfig),
|
||||||
|
FeatureInfoBox.GenerateContent(tags, layerConfig),
|
||||||
|
onClose
|
||||||
|
);
|
||||||
if (layerConfig === undefined) {
|
if (layerConfig === undefined) {
|
||||||
throw "Undefined layerconfig"
|
throw "Undefined layerconfig"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GenerateTitleBar( tags: UIEventSource<any>,
|
||||||
|
layerConfig: LayerConfig): UIElement{
|
||||||
const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined))
|
const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined))
|
||||||
.AddClass("text-2xl break-words font-bold p-2");
|
.SetClass("text-2xl break-words font-bold p-2");
|
||||||
this.title = title;
|
|
||||||
const titleIcons = new Combine(
|
const titleIcons = new Combine(
|
||||||
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)
|
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)
|
||||||
.AddClass("block w-8 h-8 align-baseline box-content p-0.5")))
|
.SetClass("block w-8 h-8 align-baseline box-content p-0.5")))
|
||||||
.AddClass("flex flex-row flex-wrap pt-1 items-center mr-2");
|
.SetClass("flex flex-row flex-wrap pt-1 items-center mr-2");
|
||||||
|
|
||||||
|
return new Combine([
|
||||||
|
new Combine([title, titleIcons]).SetClass("flex flex-grow justify-between")
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GenerateContent(tags: UIEventSource<any>,
|
||||||
|
layerConfig: LayerConfig): UIElement{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let questionBox: UIElement = undefined;
|
let questionBox: UIElement = undefined;
|
||||||
if (State.state.featureSwitchUserbadge.data) {
|
if (State.state.featureSwitchUserbadge.data) {
|
||||||
|
@ -53,20 +65,12 @@ export default class FeatureInfoBox extends UIElement {
|
||||||
}
|
}
|
||||||
const tail = new Combine([]).SetClass("only-on-mobile");
|
const tail = new Combine([]).SetClass("only-on-mobile");
|
||||||
|
|
||||||
const content = new Combine([
|
return new Combine([
|
||||||
...renderings,
|
...renderings,
|
||||||
tail.SetClass("featureinfobox-tail")
|
tail.SetClass("featureinfobox-tail")
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
const titleBar = new Combine([
|
|
||||||
new Combine([title, titleIcons]).SetClass("flex flex-grow justify-between")
|
|
||||||
])
|
|
||||||
|
|
||||||
this._component = new ScrollableFullScreen(titleBar, content, onClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
InnerRender(): string {
|
|
||||||
return this._component.Render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default class TagRenderingAnswer extends UIElement {
|
||||||
if (configuration === undefined) {
|
if (configuration === undefined) {
|
||||||
throw "Trying to generate a tagRenderingAnswer without configuration..."
|
throw "Trying to generate a tagRenderingAnswer without configuration..."
|
||||||
}
|
}
|
||||||
this.AddClass("flex items-center flex-row text-lg")
|
this.SetClass("flex items-center flex-row text-lg")
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerRender(): string {
|
InnerRender(): string {
|
||||||
|
|
|
@ -88,7 +88,7 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
return tags.asHumanString(true, true);
|
return tags.asHumanString(true, true);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
).AddClass("block")
|
).SetClass("block")
|
||||||
}
|
}
|
||||||
|
|
||||||
private GenerateInputElement(): InputElement<TagsFilter> {
|
private GenerateInputElement(): InputElement<TagsFilter> {
|
||||||
|
|
|
@ -126,7 +126,12 @@ export default class ShowDataLayer {
|
||||||
|
|
||||||
|
|
||||||
const tags = State.state.allElements.getEventSourceFor(feature);
|
const tags = State.state.allElements.getEventSourceFor(feature);
|
||||||
const uiElement: LazyElement = new LazyElement(() => new FeatureInfoBox(tags, layer, () => popup.closePopup()),
|
const uiElement: LazyElement<FeatureInfoBox> = new LazyElement(() => new FeatureInfoBox(tags, layer, () => {
|
||||||
|
console.log("Closing the popup!")
|
||||||
|
State.state.selectedElement.setData(undefined);
|
||||||
|
popup.remove();
|
||||||
|
|
||||||
|
}),
|
||||||
"<div style='height: 90vh'>Rendering</div>");
|
"<div style='height: 90vh'>Rendering</div>");
|
||||||
popup.setContent(uiElement.Render());
|
popup.setContent(uiElement.Render());
|
||||||
popup.on('remove', () => {
|
popup.on('remove', () => {
|
||||||
|
@ -140,9 +145,10 @@ export default class ShowDataLayer {
|
||||||
// But at least it'll be visible already
|
// But at least it'll be visible already
|
||||||
|
|
||||||
|
|
||||||
leafletLayer.on("click", (e) => {
|
leafletLayer.on("click", () => {
|
||||||
// We set the element as selected...
|
// We set the element as selected...
|
||||||
uiElement.Activate();
|
|
||||||
|
uiElement.Activate(e => e.PrepFullscreen());
|
||||||
State.state.selectedElement.setData(feature);
|
State.state.selectedElement.setData(feature);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -153,14 +159,15 @@ export default class ShowDataLayer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
leafletLayer.openPopup();
|
leafletLayer.openPopup();
|
||||||
uiElement.Activate();
|
uiElement.Activate(e => e.PrepFullscreen());
|
||||||
State.state.selectedElement.setData(feature);
|
State.state.selectedElement.setData(feature);
|
||||||
}
|
}
|
||||||
this._onSelectedTrigger[feature.properties.id.replace("/", "_")] = this._onSelectedTrigger[id];
|
this._onSelectedTrigger[feature.properties.id.replace("/", "_")] = this._onSelectedTrigger[id];
|
||||||
if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data) {
|
if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data && State.state.selectedElement.data === undefined) {
|
||||||
// This element is in the URL, so this is a share link
|
// This element is in the URL, so this is a share link
|
||||||
// We open the relevant popup straight away
|
// We open the relevant popup straight away
|
||||||
uiElement.Activate();
|
console.log("Opening the popup due to sharelink")
|
||||||
|
uiElement.Activate(e => e.PrepFullscreen());
|
||||||
popup.setContent(uiElement.Render());
|
popup.setContent(uiElement.Render());
|
||||||
|
|
||||||
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
|
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
|
||||||
|
|
|
@ -149,16 +149,12 @@ export abstract class UIElement extends UIEventSource<string> {
|
||||||
return this.InnerRender() === "";
|
return this.InnerRender() === "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SetClass(clss: string): UIElement {
|
|
||||||
return this.AddClass(clss);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds all the relevant classes, space seperated
|
* Adds all the relevant classes, space seperated
|
||||||
* @param clss
|
* @param clss
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
public AddClass(clss: string) {
|
public SetClass(clss: string) {
|
||||||
this.dumbMode = false;
|
this.dumbMode = false;
|
||||||
const all = clss.split(" ");
|
const all = clss.split(" ");
|
||||||
let recordedChange = false;
|
let recordedChange = false;
|
||||||
|
|
|
@ -79,10 +79,3 @@
|
||||||
max-height: 30vh;
|
max-height: 30vh;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
/* This is used by the slideshow, to hide non-active slides*/
|
|
||||||
display: none !important;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
16
index.css
16
index.css
|
@ -32,12 +32,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (max-width: 640px), only screen and (max-height: 640px) {
|
@media only screen and (max-width: 640px) {
|
||||||
.no-transform {
|
.no-transform {
|
||||||
/*This is a workaround to let popup contents escape the popup on mobile*/
|
/*This is a workaround to let popup contents escape the popup on mobile - see scrollableFullScreen.ts*/
|
||||||
transform: none !important;
|
transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clutter-hidden {
|
||||||
|
/*This is a workaround to let popup contents escape the popup on mobile - see scrollableFullScreen.ts*/
|
||||||
|
visibility: hidden !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,6 +63,11 @@
|
||||||
--return-to-the-map-height: 2em;
|
--return-to-the-map-height: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide-when-fullscreen-is-shown {
|
||||||
|
/*Clutter is actually a class indicating that the element should be hidden when a scrollableFullScreen is opened
|
||||||
|
It doesn't actually define any rules*/
|
||||||
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
@ -333,7 +344,6 @@ a {
|
||||||
|
|
||||||
.welcomeMessage {
|
.welcomeMessage {
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: 4em;
|
|
||||||
max-width: calc(100vw - 5em);
|
max-width: calc(100vw - 5em);
|
||||||
width: 40em;
|
width: 40em;
|
||||||
max-height: calc(100vh - 15em);
|
max-height: calc(100vh - 15em);
|
||||||
|
|
10
index.html
10
index.html
|
@ -44,11 +44,7 @@
|
||||||
<!-- DECORATION 0 END -->
|
<!-- DECORATION 0 END -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="only-on-mobile">
|
<div id="topleft-tools" class="z-index-above-map clutter">
|
||||||
<div id="messagesboxmobile"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="topleft-tools" class="z-index-above-map">
|
|
||||||
<div id="userbadge-and-search" class="p-3">
|
<div id="userbadge-and-search" class="p-3">
|
||||||
<div id="userbadge" class="shadow rounded-3xl overflow-hidden"></div>
|
<div id="userbadge" class="shadow rounded-3xl overflow-hidden"></div>
|
||||||
<div id="searchbox" class="shadow rounded-3xl overflow-hidden"></div>
|
<div id="searchbox" class="shadow rounded-3xl overflow-hidden"></div>
|
||||||
|
@ -57,13 +53,13 @@
|
||||||
<div id="help-button-mobile"></div>
|
<div id="help-button-mobile"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="layer-selection" class="absolute bottom-3 left-3 rounded-3xl overflow-hidden"></div>
|
<div id="layer-selection" class="absolute bottom-3 left-3 rounded-3xl overflow-hidden clutter"></div>
|
||||||
|
|
||||||
<div id="centermessage" class="absolute rounded-3xl h-24 left-24 right-24 top-56 bg-white p-3 pt-5 sm:pt-8 text-xl font-bold text-center">
|
<div id="centermessage" class="absolute rounded-3xl h-24 left-24 right-24 top-56 bg-white p-3 pt-5 sm:pt-8 text-xl font-bold text-center">
|
||||||
Loading MapComplete, hang on...
|
Loading MapComplete, hang on...
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="geolocate-button"></div>
|
<div id="geolocate-button" class="clutter"></div>
|
||||||
<div id="leafletDiv"></div>
|
<div id="leafletDiv"></div>
|
||||||
|
|
||||||
<script src="./index.ts"></script>
|
<script src="./index.ts"></script>
|
||||||
|
|
3
index.ts
3
index.ts
|
@ -119,11 +119,10 @@ if (layoutFromBase64.startsWith("wiki:")) {
|
||||||
} else {
|
} else {
|
||||||
// We fall through: no theme loaded: just show a few buttons
|
// We fall through: no theme loaded: just show a few buttons
|
||||||
State.state = new State(undefined);
|
State.state = new State(undefined);
|
||||||
document.getElementById("messagesboxmobile").remove();
|
|
||||||
new Combine([new MoreScreen(true)
|
new Combine([new MoreScreen(true)
|
||||||
.SetStyle("pointer-events: all;"),
|
.SetStyle("pointer-events: all;"),
|
||||||
Translations.t.general.openStreetMapIntro
|
Translations.t.general.openStreetMapIntro
|
||||||
]).AddClass("block m-5 lg:w-3/4 lg:ml-40")
|
]).SetClass("block m-5 lg:w-3/4 lg:ml-40")
|
||||||
.AttachTo("topleft-tools");
|
.AttachTo("topleft-tools");
|
||||||
}
|
}
|
||||||
window.addEventListener('contextmenu', function (e) { // Not compatible with IE < 9
|
window.addEventListener('contextmenu', function (e) { // Not compatible with IE < 9
|
||||||
|
|
Loading…
Reference in a new issue