pull/147/head
Candid Dauth 2021-04-02 00:49:14 +02:00
rodzic ef1e73fca3
commit c1b0453e38
13 zmienionych plików z 123 dodań i 35 usunięć

Wyświetl plik

@ -37,10 +37,14 @@ To synchronize the map state with the location hash (to add something like #9/31
location.replace("#" + evt.data.hash);
});
window.addEventListener("hashchange", function() {
function handleHashChange() {
var iframe = document.getElementById("facilmap");
iframe.src = iframe.src.replace(/#.*$/, "") + location.hash;
});
iframe.src = iframe.src.replace(/(#.*)?$/, "") + location.hash;
}
window.addEventListener("hashchange", handleHashChange);
if (location.hash)
handleHashChange();
</script>
```

Wyświetl plik

@ -0,0 +1,30 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>FacilMap iframe test</title>
<style type="text/css">
iframe { position: absolute; top: 25%; left: 25%; width: 50%; height: 50%; }
</style>
</head>
<body>
<iframe src="http://localhost:40829/"></iframe>
<script>
window.addEventListener("message", function(evt) {
if (evt.data && evt.data.type == "facilmap-hash" && location.hash != "#" + evt.data.hash)
location.replace("#" + evt.data.hash);
});
function handleHashChange() {
var iframe = document.querySelector("iframe");
iframe.src = iframe.src.replace(/(#.*)?$/, "") + location.hash;
}
window.addEventListener("hashchange", handleHashChange);
if (location.hash)
handleHashChange();
</script>
</body>
</html>

Wyświetl plik

@ -14,7 +14,8 @@ const context = Vue.observable({
autofocus: toBoolean(queryParams.autofocus, parent === window),
legend: toBoolean(queryParams.legend, true),
interactive: toBoolean(queryParams.interactive, parent === window),
isNarrow: isNarrow()
isNarrow: isNarrow(),
isInFrame: parent !== window
});
window.addEventListener("resize", () => {

Wyświetl plik

@ -77,7 +77,6 @@ export default class LeafletMap extends Vue {
@Ref() innerContainer!: HTMLElement;
isInFrame = (parent !== window);
loaded = false;
interaction = 0;
@ -86,7 +85,11 @@ export default class LeafletMap extends Vue {
}
get selfUrl(): string {
return `${location.origin}${location.pathname}${this.mapContext.hash ? `#${this.mapContext.hash}` : ''}`;
return `${location.origin}${location.pathname}${this.mapContext?.hash ? `#${this.mapContext.hash}` : ''}`;
}
get isInFrame(): boolean {
return context.isInFrame;
}
mounted(): void {

Wyświetl plik

@ -3,10 +3,10 @@
<Toolbox v-if="context.toolbox" :interactive="context.interactive"></Toolbox>
<Legend v-if="context.legend"></Legend>
<Import v-if="context.interactive"></Import>
<ClickMarker v-if="context.interactive"></ClickMarker>
<ClickMarker></ClickMarker>
<template #after>
<SearchBox v-if="context.search"></SearchBox>
<SearchBox></SearchBox>
</template>
</LeafletMap>
</div>

Wyświetl plik

@ -12,6 +12,7 @@ import "./marker-info.scss";
import { flyTo, getZoomDestinationForMarker } from "../../utils/zoom";
import Icon from "../ui/icon/icon";
import StringMap from "../../utils/string-map";
import context from "../context";
@WithRender
@Component({
@ -31,6 +32,10 @@ export default class MarkerInfo extends Vue {
return this.client.markers[this.markerId];
}
get context(): typeof context {
return context;
}
move(): void {
moveMarker(this.markerId, this, this.client, this.mapComponents);
}

Wyświetl plik

@ -18,7 +18,7 @@
<b-button-toolbar>
<b-button v-b-tooltip.hover="'Zoom to marker'" @click="zoomToMarker()" size="sm"><Icon icon="zoom-in" alt="Zoom to line"></Icon></b-button>
<b-dropdown text="Use as" size="sm">
<b-dropdown text="Use as" size="sm" v-if="context.search">
<b-dropdown-item href="javascript:" @click="useAsFrom()">Route start</b-dropdown-item>
<b-dropdown-item href="javascript:" @click="useAsVia()">Route via</b-dropdown-item>
<b-dropdown-item href="javascript:" @click="useAsTo()">Route destination</b-dropdown-item>

Wyświetl plik

@ -41,11 +41,16 @@ export default class SearchBox extends Vue {
resizeStartWidth: number | null = null;
hasFocus = false;
isResizing = false;
isMounted = false;
get isNarrow(): boolean {
return context.isNarrow;
}
get context(): typeof context {
return context;
}
mounted(): void {
this.mapContext.$on("fm-search-box-show-tab", this.handleShowTab);
@ -71,6 +76,8 @@ export default class SearchBox extends Vue {
this.$watch(() => this.tabsComponent?.tabs[this.tab]?.$attrs?.["fm-hash-query"], (hashQuery: HashQuery | undefined) => {
this.mapContext.fallbackQuery = hashQuery;
});
this.isMounted = true;
}
beforeDestroy(): void {
@ -78,6 +85,10 @@ export default class SearchBox extends Vue {
this.cardHeader = undefined as any;
}
get hasTabs(): boolean {
return this.isMounted && this.tabsComponent?.tabs.length > 0;
}
handlePanStart(event: any): void {
this.restoreHeight = null;
this.panStartHeight = parseInt($(this.searchBox).css("flex-basis"));

Wyświetl plik

@ -1,7 +1,7 @@
<b-card no-body ref="searchBox" class="fm-search-box" :class="{ isNarrow, hasFocus }" @focusin="handleFocusIn" @focusout="handleFocusOut">
<b-card v-show="hasTabs" no-body ref="searchBox" class="fm-search-box" :class="{ isNarrow, hasFocus }" @focusin="handleFocusIn" @focusout="handleFocusOut">
<b-tabs card align="center" v-model="tab" ref="tabsComponent" @changed="handleChanged" @activate-tab="handleActivateTab" no-fade>
<SearchFormTab></SearchFormTab>
<RouteFormTab></RouteFormTab>
<SearchFormTab v-if="context.search"></SearchFormTab>
<RouteFormTab v-if="context.search"></RouteFormTab>
<MarkerInfoTab></MarkerInfoTab>
<LineInfoTab></LineInfoTab>
<portal-target name="fm-search-box" multiple></portal-target>

Wyświetl plik

@ -10,6 +10,7 @@ import { FileResult } from "../../utils/files";
import { MapComponents, MapContext } from "../leaflet-map/leaflet-map";
import { isLineResult, isMarkerResult } from "../../utils/search";
import { flyTo, getZoomDestinationForSearchResult } from "../../utils/zoom";
import context from "../context";
@WithRender
@Component({
@ -39,6 +40,10 @@ export default class SearchResultInfo extends Vue {
return Object.values(this.client.types).filter((type) => (this.isMarker && type.type == "marker") || (this.isLine && type.type == "line"));
}
get context(): typeof context {
return context;
}
zoomToResult(): void {
const dest = getZoomDestinationForSearchResult(this.result);
if (dest)

Wyświetl plik

@ -30,7 +30,7 @@
</b-dropdown>
<b-button v-if="!client.readonly && types.length == 1" @click="$emit('add-to-map', types[0])" size="sm">Add to map</b-button>
<b-dropdown v-if="isMarker" text="Use as" size="sm">
<b-dropdown v-if="isMarker && context.search" text="Use as" size="sm">
<b-dropdown-item href="javascript:" @click="$emit('use-as-from')">Route start</b-dropdown-item>
<b-dropdown-item href="javascript:" @click="$emit('use-as-via')">Route via</b-dropdown-item>
<b-dropdown-item href="javascript:" @click="$emit('use-as-to')">Route destination</b-dropdown-item>

Wyświetl plik

@ -35,7 +35,7 @@
<b-dropdown-item v-if="!client.readonly && client.padData" href="javascript:" v-b-modal.fm-toolbox-history v-b-toggle.fm-toolbox-sidebar>Show edit history</b-dropdown-item>
<b-dropdown-divider v-if="client.padData"></b-dropdown-divider>
<b-dropdown-item v-b-modal.fm-toolbox-about v-b-toggle.fm-toolbox-sidebar href="javascript:">About FacilMap</b-dropdown-item>
<b-dropdown-item v-if="client.padData" :href="links.facilmap">Exit collaborative map</b-dropdown-item>
<b-dropdown-item v-if="client.padData && interactive" :href="links.facilmap">Exit collaborative map</b-dropdown-item>
</b-nav-item-dropdown>
</Sidebar>

Wyświetl plik

@ -1,5 +1,5 @@
import { ID, SearchResult } from "facilmap-types";
import { DomEvent, Evented, Handler, LeafletEvent, Map, Util } from "leaflet";
import { Browser, DomEvent, Evented, Handler, LatLng, LeafletEvent, Map, Util } from "leaflet";
import { LinesLayer, MarkersLayer, SearchResultsLayer } from "facilmap-leaflet";
export type SelectedItem = {
@ -41,8 +41,8 @@ export default class SelectionHandler extends Handler {
_linesLayer: LinesLayer;
_searchResultLayers: SearchResultsLayer[];
_mapFocusTime: number | undefined = undefined;
_mapInteraction: number = 0;
_isLongClick: boolean = false;
constructor(map: Map, markersLayer: MarkersLayer, linesLayer: LinesLayer, searchResultsLayer: SearchResultsLayer) {
super(map);
@ -60,8 +60,10 @@ export default class SelectionHandler extends Handler {
this._map.on("click", this.handleClickMap);
this._map.on("fmInteractionStart", this.handleMapInteractionStart);
this._map.on("fmInteractionEnd", this.handleMapInteractionEnd);
this._map.getContainer().addEventListener("focusin", this.handleMapFocusIn);
this._map.getContainer().addEventListener("focusout", this.handleMapFocusOut);
if (Browser.touch && !Browser.pointer) // Long click will call the contextmenu event
this._map.on("contextmenu", this.handleMapContextMenu);
else
this._map.on("mousedown", this.handleMapMouseDown);
}
removeHooks(): void {
@ -72,8 +74,8 @@ export default class SelectionHandler extends Handler {
this._map.off("click", this.handleClickMap);
this._map.off("fmInteractionStart", this.handleMapInteractionStart);
this._map.off("fmInteractionEnd", this.handleMapInteractionEnd);
this._map.getContainer().removeEventListener("focusin", this.handleMapFocusIn);
this._map.getContainer().removeEventListener("focusout", this.handleMapFocusOut);
this._map.off("contextmenu", this.handleMapContextMenu);
this._map.off("mousedown", this.handleMapMouseDown);
}
addSearchResultLayer(layer: SearchResultsLayer): void {
@ -172,26 +174,53 @@ export default class SelectionHandler extends Handler {
}
handleClickMap = (e: LeafletEvent): void => {
if (this._mapInteraction)
if (this._mapInteraction || this._isLongClick)
return;
if (!(e.originalEvent as any).ctrlKey && !(e.originalEvent as any).shiftKey) {
if (this._selection.length == 0) {
// Focus event is fired before click event. Delay so that our click handlers knows whether the map was focused before it was clicked.
if (this._mapFocusTime && Date.now() - this._mapFocusTime > 500)
this.fire("fmMapClick", e);
} else
this.setSelectedItems([]);
if (!(e.originalEvent as any).ctrlKey && !(e.originalEvent as any).shiftKey)
this.setSelectedItems([]);
}
handleMapContextMenu = (e: any): void => {
this.fire("fmMapClick", e);
}
handleMapMouseDown = (e: any): void => {
if(e.originalEvent.which != 1) // Only react to left click
return;
const pos: LatLng = e.containerPoint;
const timeout = setTimeout(() => {
this._isLongClick = true;
this.fire("fmMapClick", e);
}, 500);
const handleMouseMove = (e: any) => {
if(pos.distanceTo(e.containerPoint) > (this._map.dragging as any)._draggable.options.clickTolerance)
clear();
};
const handleContextMenu = (e: any) => {
DomEvent.preventDefault(e);
}
}
handleMapFocusIn = (): void => {
this._mapFocusTime = Date.now();
}
const clear = () => {
clearTimeout(timeout);
this._map.off("mousemove", handleMouseMove);
this._map.off("mouseup", clear);
this._map.off("contextmenu", handleContextMenu);
handleMapFocusOut = (): void => {
this._mapFocusTime = undefined;
}
setTimeout(() => {
this._isLongClick = false;
}, 0);
}
this._map.on("mousemove", handleMouseMove);
this._map.on("touchmove", handleMouseMove);
this._map.on("mouseup", clear);
this._map.on("touchend", clear);
this._map.on("contextmenu", handleContextMenu);
}
handleMapInteractionStart = (): void => {
this._mapInteraction++;