aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontend/styles/pages/map.sass7
-rw-r--r--frontend/ts/src/lib/leaflet.d.ts6
-rw-r--r--frontend/ts/src/pages/map.ts74
-rw-r--r--frontend/ts/src/pages/map/footer.ts25
-rw-r--r--frontend/ts/src/pages/map/marker.ts20
5 files changed, 99 insertions, 33 deletions
diff --git a/frontend/styles/pages/map.sass b/frontend/styles/pages/map.sass
index 53c5dc4..1ac6c27 100644
--- a/frontend/styles/pages/map.sass
+++ b/frontend/styles/pages/map.sass
@@ -26,8 +26,15 @@
&__FooterButtons
display: flex
+ align-items: center
gap: 1rem
+ .g-ReadOnly
+ &--Active
+ background-color: colors.$green
+ &:not(.g-ReadOnly--Active)
+ opacity: 0.2
+
.g-ContextMenu
z-index: 1000
position: absolute
diff --git a/frontend/ts/src/lib/leaflet.d.ts b/frontend/ts/src/lib/leaflet.d.ts
index 76b88fd..ab8b038 100644
--- a/frontend/ts/src/lib/leaflet.d.ts
+++ b/frontend/ts/src/lib/leaflet.d.ts
@@ -40,6 +40,12 @@ export interface Layer {
addEventListener: (name: string, fn: (e: MapEvent) => void) => void
getLatLng: () => Pos
setLatLng: (pos: Pos) => void
+ dragging: Dragging
+}
+
+export interface Dragging {
+ enable(): () => void
+ disable(): () => void
}
export function tileLayer(url: string): Layer
diff --git a/frontend/ts/src/pages/map.ts b/frontend/ts/src/pages/map.ts
index b445f63..42da69c 100644
--- a/frontend/ts/src/pages/map.ts
+++ b/frontend/ts/src/pages/map.ts
@@ -1,4 +1,4 @@
-import { h, Html } from 'lib/rx'
+import { h, Html, Var } from 'lib/rx'
import * as rx from 'lib/rx'
import * as request from 'request'
import * as modal from 'ui/modal'
@@ -13,9 +13,9 @@ import * as L from 'lib/loadable'
import * as layout from 'ui/layout'
export function view(id: string): Html {
- return rx.withState2<L.Loadable<Map>, L.Loadable<markerModel.Map>>(
- [L.loading, L.loading],
- (mapVar, markersVar) => {
+ return rx.withState3<L.Loadable<Map>, L.Loadable<markerModel.Map>, boolean>(
+ [L.loading, L.loading, false],
+ (mapVar, markersVar, readOnlyVar) => {
request
.get<Map>(`/api/maps/${id}`)
.then(res => mapVar.update(_ => L.loaded(res)))
@@ -23,7 +23,11 @@ export function view(id: string): Html {
request
.get<Array<markerModel.Marker>>(`/api/markers?map=${id}`)
- .then(res => markersVar.update(_ => L.loaded(markerModel.toMap(res))))
+ .then(res => {
+ markersVar.update(_ => L.loaded(markerModel.toMap(res)))
+ // Set to readonly if there is one marker
+ if (res.length > 0) readOnlyVar.update(_ => true)
+ })
.catch(({ message }) => markersVar.update(_ => L.failure(message)))
return rx.map2(
@@ -33,8 +37,14 @@ export function view(id: string): Html {
L.map2([map, markers], (map, markers) => ({ map, markers })),
({map, markers}) => h('div',
{ className: 'g-Map' },
- withMap(map => mapView(id, map, markers)),
- footer.view(map)
+ withMap(leafletMap =>
+ [ mapView(id, leafletMap, markers, readOnlyVar),
+ footer.view({
+ mapInit: map,
+ readOnly: readOnlyVar,
+ onUpdateReadOnly: (b: boolean) => readOnlyVar.update(_ => b)
+ }) ]
+ )
)
)
}
@@ -74,7 +84,7 @@ interface ErrorModal {
message: string
}
-function mapView(map_id: string, map: M.Map, markers: markerModel.Map): Html {
+function mapView(map_id: string, map: M.Map, markers: markerModel.Map, readOnlyVar: Var<boolean>): Html {
let lastUserAdded: markerModel.Marker | undefined
return rx.withState3<
@@ -84,9 +94,17 @@ function mapView(map_id: string, map: M.Map, markers: markerModel.Map): Html {
>(
[undefined, undefined, undefined],
(addModalVar, updateModalVar, errorModalVar) => {
- map.addEventListener('click', (event: M.MapEvent) => addModalVar.update(_ => event.latlng))
+ map.addEventListener('click', (event: M.MapEvent) => {
+ if (!readOnlyVar.now()) {
+ addModalVar.update(_ => event.latlng)
+ }
+ })
- const onClick = (m: MarkerContext) => updateModalVar.update(_ => m)
+ const onClick = (m: MarkerContext) => {
+ if (!readOnlyVar.now()) {
+ updateModalVar.update(_ => m)
+ }
+ }
const onMoveError = (message: string) => {
errorModalVar.update(_ => ({
@@ -97,7 +115,7 @@ function mapView(map_id: string, map: M.Map, markers: markerModel.Map): Html {
const elements = M.featureGroup()
Object.values(markers).forEach(marker => {
- const elem = addMarker({ marker, markers, map, onClick, onMoveError })
+ const elem = addMarker({ marker, markers, map, onClick, onMoveError, readOnlyVar })
elements.addLayer(elem)
})
@@ -120,7 +138,7 @@ function mapView(map_id: string, map: M.Map, markers: markerModel.Map): Html {
body
),
onSuccess: marker => {
- addMarker({ marker, markers, map, onClick, onMoveError })
+ addMarker({ marker, markers, map, onClick, onMoveError, readOnlyVar })
addModalVar.update(_ => undefined)
markers[marker.id] = marker
lastUserAdded = marker
@@ -145,7 +163,7 @@ function mapView(map_id: string, map: M.Map, markers: markerModel.Map): Html {
),
onSuccess: marker => {
map.removeLayer(markerElem)
- addMarker({ marker, markers, map, onClick, onMoveError })
+ addMarker({ marker, markers, map, onClick, onMoveError, readOnlyVar })
updateModalVar.update(_ => undefined)
markers[marker.id] = marker
lastUserAdded = marker
@@ -175,24 +193,30 @@ interface AddMarkerParams {
map: M.Map
onClick: (m: MarkerContext) => void
onMoveError: (message: string) => void
+ readOnlyVar: Var<boolean>
}
-function addMarker({ markers, marker, map, onClick, onMoveError }: AddMarkerParams): M.FeatureGroup {
+function addMarker({ markers, marker, map, onClick, onMoveError, readOnlyVar }: AddMarkerParams): M.FeatureGroup {
const elem = markerView.create({
marker,
onMove: markerElem => {
- const pos = markerElem.getLatLng()
- const newMarker = structuredClone(marker)
- newMarker.lat = pos.lat
- newMarker.lng = pos.lng
- updateMarker(newMarker)
- .then(m => markers[marker.id] = m)
- .catch(({ message }) => {
- markerElem.setLatLng({ lat: marker.lat, lng: marker.lng })
- onMoveError(message)
- })
+ if (!readOnlyVar.now()) {
+ const pos = markerElem.getLatLng()
+ const newMarker = structuredClone(marker)
+ newMarker.lat = pos.lat
+ newMarker.lng = pos.lng
+ updateMarker(newMarker)
+ .then(m => markers[marker.id] = m)
+ .catch(({ message }) => {
+ markerElem.setLatLng({ lat: marker.lat, lng: marker.lng })
+ onMoveError(message)
+ })
+ } else {
+ markerElem.setLatLng({ lat: marker.lat, lng: marker.lng })
+ }
},
- onClick: (markerElem: M.FeatureGroup) => onClick({ markerId: marker.id, markerElem })
+ onClick: (markerElem: M.FeatureGroup) => onClick({ markerId: marker.id, markerElem }),
+ readOnlyVar
})
map.addLayer(elem)
diff --git a/frontend/ts/src/pages/map/footer.ts b/frontend/ts/src/pages/map/footer.ts
index 945bfd4..f514c66 100644
--- a/frontend/ts/src/pages/map/footer.ts
+++ b/frontend/ts/src/pages/map/footer.ts
@@ -1,4 +1,4 @@
-import { h, Html } from 'lib/rx'
+import { h, Html, Rx } from 'lib/rx'
import * as rx from 'lib/rx'
import * as request from 'request'
import * as modal from 'ui/modal'
@@ -7,12 +7,22 @@ import { Map } from 'models/map'
import * as form from 'lib/form'
import * as L from 'lib/loadable'
-export function view(mapInit: Map): Html {
+interface ViewParams {
+ mapInit: Map,
+ readOnly: Rx<boolean>,
+ onUpdateReadOnly: (b: boolean) => void,
+}
+
+export function view({ mapInit, readOnly, onUpdateReadOnly }: ViewParams): Html {
return h('footer',
{ className: 'g-Map__Footer' },
rx.withState<Map>(mapInit, mapVar =>
mapVar.map(map => [
- map.name,
+ h('div',
+ { className: 'g-Map__FooterButtons' },
+ map.name,
+ readOnlyButton(readOnly, onUpdateReadOnly)
+ ),
h('div',
{ className: 'g-Map__FooterButtons' },
viewRenameButton(map, (map: Map) => mapVar.update(_ => map)),
@@ -23,6 +33,15 @@ export function view(mapInit: Map): Html {
)
}
+function readOnlyButton(readOnly: Rx<boolean>, onUpdateReadOnly: (b: boolean) => void): Html {
+ return h('button',
+ { className: readOnly.map(b => `g-Button g-ReadOnly ${b ? 'g-ReadOnly--Active' : ''}`),
+ onclick: readOnly.map(b => (event: Event) => onUpdateReadOnly(!b))
+ },
+ 'Lecture seule'
+ )
+}
+
// Rename modal
function viewRenameButton(map: Map, onUpdate: (m: Map) => void): Html {
diff --git a/frontend/ts/src/pages/map/marker.ts b/frontend/ts/src/pages/map/marker.ts
index b690741..435ed5b 100644
--- a/frontend/ts/src/pages/map/marker.ts
+++ b/frontend/ts/src/pages/map/marker.ts
@@ -1,16 +1,17 @@
-import { mount, h, s } from 'lib/rx'
+import { Var, mount, h, s } from 'lib/rx'
import * as Color from 'lib/color'
import * as M from 'lib/leaflet'
import * as icons from 'lib/icons'
import * as markerModel from 'models/marker'
interface CreateParams {
- marker: markerModel.Marker,
- onMove: (marker: M.Layer) => void,
- onClick: (markerElem: M.FeatureGroup) => void,
+ marker: markerModel.Marker
+ onMove: (marker: M.Layer) => void
+ onClick: (markerElem: M.FeatureGroup) => void
+ readOnlyVar: Var<boolean>
}
-export function create({ marker, onMove, onClick }: CreateParams): M.FeatureGroup {
+export function create({ marker, onMove, onClick, readOnlyVar }: CreateParams): M.FeatureGroup {
const { lat, lng, color, icon, name, description, radius } = marker
const pos = { lat, lng }
@@ -30,6 +31,15 @@ export function create({ marker, onMove, onClick }: CreateParams): M.FeatureGrou
? M.featureGroup([ markerElem, circle ])
: M.featureGroup([ markerElem ])
+ // Fired before dragging, permits to disable dragging just at the right
+ // moment if in readonly mode.
+ markerElem.addEventListener('mousedown', () => {
+ if (readOnlyVar.now()) {
+ markerElem.dragging.disable()
+ window.setTimeout(() => markerElem.dragging.enable())
+ }
+ })
+
markerElem.addEventListener('drag', e => {
circle && circle.setLatLng(markerElem.getLatLng())
})