kopia lustrzana https://github.com/FacilMap/facilmap
Bugfixing
rodzic
ef1e73fca3
commit
c1b0453e38
|
@ -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>
|
||||
```
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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", () => {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
Ładowanie…
Reference in New Issue