all repos — onyx @ fbd1d515d30e2aa11ff772be3a01c310d7980fec

minimal map annotation and location data sharing tool

add polygon support and use cancel/okCancel modals
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmL5svAACgkQO3+8IhRO
Y5hjbQ//YRllJL2a4Lhtz+isvKzC875MhTy03KwQIacuJpX9wGB06hugTlCr9aei
kMevkdajmr6+FW6XEndv2NScb9MNltRsFCimdTzR37VmPdhvwWg11icFjcPw/ag/
FqO3q4f9Uc/TyBjQz1Lu88x6pL69xRse2OoB2yLESXmrb176yTpMGXM15HEK6l9B
1RbL9eWKkNNtN4TD1DKA9oxqE2EjZDU7XKRgcebui1Kc6Y3+DWZqhSkOjjxT/4Vb
sYZOhr6lx+uNFCX4ISg6zQHELhS4A2SzsUi//e0nQLxSWNZmlORO9RpdpbIMOcMC
IZ9YS//IOBqEgYVzXMF25zGMWJUgv1j9DWn2Ogj1dQ8GxtIjP79rM05D2aVEht09
opmkjW/oyUb8TCKCSMWfUV+d3khs8tTUx4AOZO1vS/03usQKyjtavqLMcaLe6FSE
WBr88NaQWayrLYUS8cgixZKEb2k957Fr4nxH7i1aZLFbVtKmmP2ZWHL8yio2dW4S
Obmm4an7tO9OF7QByGVNGvxhsxGJkPmIZ0xXCuL96kr6h11rrQjKg0WXPBQKSsWR
QcUUYC8hKDnsiSo4XeVsh8tKB3rrhe0+dkvvgi8UyYllTi4t2fDEDzuVvOCipjkZ
GhpzHReOFyE/111dSF/J/CJ33K2C5aYsxgjkx21QLuuXf1Kqm+Y=
=EUUo
-----END PGP SIGNATURE-----
commit

fbd1d515d30e2aa11ff772be3a01c310d7980fec

parent

c80313085e7c6f7569fb3d81500a1b5b761aae78

M src/10-overlay.tssrc/10-overlay.ts

@@ -79,17 +79,28 @@

constructor(name: string, desc: string, points: Point[], options: any) { super(name, desc, points, options); this.self = L.polygon(points, options); + this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } } -class Path extends OverlayBase { +class Polyline extends OverlayBase { constructor() { super("", "", [ ], {}); this.self = L.polyline([]); } - insertPoint(pt: Point) { + insertPoint(pt: Point): void { this.self.addLatLng(pt); + this.points.push(pt); + } + + clearPoints(): void { + this.points = []; + this.self.setLatLngs([]); + } + + numPoints(): number { + return this.self.getLatLngs().length; } }

@@ -97,11 +108,13 @@ class OverlayState {

markers: Marker[]; circles: Circle[]; polygons: Polygon[]; + polyline: Polyline; constructor() { this.markers = []; this.circles = []; this.polygons = []; + this.polyline = new Polyline(); } static load(): OverlayState {

@@ -112,6 +125,7 @@ return {

markers: model.markers.map((m: OverlayData) => OverlayState.fromData(m)), circles: model.circles.map((c: OverlayData) => OverlayState.fromData(c)), polygons: model.polygons.map((p: OverlayData) => OverlayState.fromData(p)), + polyline: new Polyline(), } as OverlayState } else { return new OverlayState();
M src/12-textUtils.tssrc/12-textUtils.ts

@@ -1,11 +1,13 @@

class TextUtils { static decodeHTML(text: string): string { + return text; const textArea = document.createElement('textarea'); textArea.innerHTML = text; return textArea.value; } static encodeHTML(text: string): string { + return text; const textArea = document.createElement('textarea'); textArea.innerText = text; return textArea.innerHTML;
M src/20-createOverlayModal.tssrc/20-createOverlayModal.ts

@@ -89,6 +89,9 @@ if (submitBtn) {

submitBtn.onclick = () => { const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); + if (name.trim().length < 1 || desc.trim().length < 1) { + return; + } const point = new Marker(name, desc, args.latlng, {title: name, alt: name}); point.add(args.map); args.overlays.markers.push(point);

@@ -105,6 +108,9 @@ submitBtn.onclick = () => {

const radius = _this.radiusField(); const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); + if (name.trim().length < 1 || desc.trim().length < 1) { + return; + } const circle = new Circle(name, desc, args.latlng, {radius: Number(radius) || 500}); circle.add(args.map); args.overlays.circles.push(circle);

@@ -113,6 +119,22 @@ }

} break; case OverlayType.POLYGON: + if (title) { + title.innerHTML = "Add Polygon"; + } + if (submitBtn) { + submitBtn.onclick = () => { + const name = TextUtils.encodeHTML(_this.nameField()); + const desc = TextUtils.encodeHTML(_this.descField()); + if (name.trim().length < 1 || desc.trim().length < 1) { + return; + } + const polygon = new Polygon(name, desc, args.points, {}); + polygon.add(args.map); + args.overlays.polygons.push(polygon); + _this.setVisible(false); + } + } break; } }
A src/21-cancelModal.ts

@@ -0,0 +1,31 @@

+class CancelModal { + self(): HTMLElement | null { + return document.getElementById("cancel-container"); + } + + cancelMsg(): HTMLElement | null { + return document.getElementById("cancel-msg"); + } + + cancelBtn(): HTMLElement | null { + return document.getElementById("cancel-btn"); + } + + visible(): boolean { + return this.self()?.style.display != "none"; + } + + setVisible(v: boolean): void { + const modal = this.self(); + if (modal) { + modal.style.display = v ? "block" : "none"; + } + } + + setMsg(s: string): void { + const msg = this.cancelMsg(); + if (msg) { + msg.innerText = s; + } + } +}
A src/22-okCancelModal.ts

@@ -0,0 +1,35 @@

+class OKCancelModal { + self(): HTMLElement | null { + return document.getElementById("confirm-container"); + } + + confirmMsg(): HTMLElement | null { + return document.getElementById("confirm-msg"); + } + + okBtn(): HTMLElement | null { + return document.getElementById("yes-btn"); + } + + cancelBtn(): HTMLElement | null { + return document.getElementById("no-btn"); + } + + visible(): boolean { + return this.self()?.style.display != "none"; + } + + setVisible(v: boolean): void { + const modal = this.self(); + if (modal) { + modal.style.display = v ? "block" : "none"; + } + } + + setMsg(s: string): void { + const msg = this.confirmMsg(); + if (msg) { + msg.innerText = s; + } + } +}
M src/29-modalCollection.tssrc/29-modalCollection.ts

@@ -1,11 +1,21 @@

class ModalCollection { createOverlay: CreateOverlayModal; + cancel: CancelModal; + okCancel: OKCancelModal; - constructor(createOverlay: CreateOverlayModal) { + constructor( + createOverlay: CreateOverlayModal, + cancel: CancelModal, + okCancel: OKCancelModal + ) { this.createOverlay = createOverlay; + this.cancel = cancel; + this.okCancel = okCancel; } closeAll(): void { this.createOverlay.setVisible(false); + this.cancel.setVisible(false); + this.okCancel.setVisible(false); } }
M src/40-handlers.tssrc/40-handlers.ts

@@ -34,14 +34,21 @@ const addPointBtn = document.getElementById("addPoint-btn");

if (addPointBtn) { addPointBtn.classList.remove("activeBtn"); } - self.map.off("click", this.addMarker); + self.map.off("click", MapHandler.addMarker); } catch {} try { const addCircleBtn = document.getElementById("addCircle-btn"); if (addCircleBtn) { addCircleBtn.classList.remove("activeBtn"); } - self.map.off("click", this.addCircle); + self.map.off("click", MapHandler.addCircle); + } catch {} + try { + const addPolygonBtn = document.getElementById("addPolygon-btn"); + if (addPolygonBtn) { + addPolygonBtn.classList.remove("activeBtn"); + } + self.map.off("click", MapHandler.polygonAddPoint); } catch {} } }

@@ -49,26 +56,43 @@

static addMarker(e: any): void { const self = MapHandler.instance; if (self) { - self.modals.createOverlay.setVisible(true); + self.modals.cancel.setVisible(false); self.modals.createOverlay.setState(OverlayType.POINT, { latlng: e.latlng, map: self.map, overlays: self.overlays, }); MapHandler.resetMapClick(); + self.modals.createOverlay.setVisible(true); } } static addCircle(e: any): void { const self = MapHandler.instance; if (self) { - self.modals.createOverlay.setVisible(true); + self.modals.cancel.setVisible(false); self.modals.createOverlay.setState(OverlayType.CIRCLE, { latlng: e.latlng, map: self.map, overlays: self.overlays, }); MapHandler.resetMapClick(); + self.modals.createOverlay.setVisible(true); + } + } + + static addPolygon(e: any): void { + const self = MapHandler.instance; + if (self) { + self.modals.okCancel.setVisible(false); + self.modals.createOverlay.setState(OverlayType.POLYGON, { + points: self.overlays.polyline.points, + map: self.map, + overlays: self.overlays, + }); + MapHandler.resetMapClick(); + self.overlays.polyline.clearPoints(); + self.modals.createOverlay.setVisible(true); } }

@@ -79,6 +103,16 @@ self.modals.closeAll();

MapHandler.resetMapClick(); (e.target as HTMLElement).classList.add("activeBtn"); self.map.on("click", MapHandler.addCircle); + + const cancelBtn = self.modals.cancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = ()=> { + self.modals.closeAll(); + MapHandler.resetMapClick(); + }; + } + self.modals.cancel.setMsg("Placing circle"); + self.modals.cancel.setVisible(true); } }

@@ -89,20 +123,116 @@ self.modals.closeAll();

MapHandler.resetMapClick(); (e.target as HTMLElement).classList.add("activeBtn"); self.map.on("click", MapHandler.addMarker); + + const cancelBtn = self.modals.cancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = ()=> { + self.modals.closeAll(); + MapHandler.resetMapClick(); + }; + } + self.modals.cancel.setMsg("Placing marker"); + self.modals.cancel.setVisible(true); + } + } + + static polygonCollect(e: any): void { + const self = MapHandler.instance; + if (self) { + self.modals.closeAll(); + MapHandler.resetMapClick(); + (e.target as HTMLElement).classList.add("activeBtn"); + + // show cancel -- on cancel, clear polyline and reset map handling + const cancelBtn = self.modals.cancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = MapHandler.polygonClearPoints; + } + self.modals.cancel.setMsg("Creating polygon"); + self.modals.cancel.setVisible(true); + + self.map.on("click", MapHandler.polygonAddPoint); + } + } + + static polygonClearPoints(e: any): void { + const self = MapHandler.instance; + if (self) { + self.modals.closeAll(); + self.overlays.polyline.clearPoints(); + MapHandler.resetMapClick(); + } + } + + static polygonAddPoint(e: any): void { + const self = MapHandler.instance; + if (self) { + self.overlays.polyline.insertPoint(e.latlng); + if (self.overlays.polyline.numPoints() >= 3) { + self.modals.cancel.setVisible(false); + + const okBtn = self.modals.okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = MapHandler.addPolygon; + } + const cancelBtn = self.modals.okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = MapHandler.polygonClearPoints; + } + self.modals.okCancel.setMsg("Creating polygon"); + self.modals.okCancel.setVisible(true); + } } } static overlaySave(e: any): void { const self = MapHandler.instance; if (self) { - OverlayState.save(self.overlays); + self.modals.closeAll(); + MapHandler.resetMapClick(); + (e.target as HTMLElement).classList.add("activeBtn"); + self.modals.okCancel.setMsg("Save current map overlays?"); + + const okBtn = self.modals.okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = ()=> { + OverlayState.save(self.overlays); + self.modals.okCancel.setVisible(false); + // show info modal "Save complete" + } + } + const cancelBtn = self.modals.okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + self.modals.okCancel.setVisible(false); + } + } + self.modals.okCancel.setVisible(true); } } static overlayClear(e: any): void { const self = MapHandler.instance; if (self) { - self.overlays = OverlayState.clear(self.overlays, self.map); + self.modals.closeAll(); + MapHandler.resetMapClick(); + (e.target as HTMLElement).classList.add("activeBtn"); + self.modals.okCancel.setMsg("Clear all map overlays (will not affect saved data)?"); + + const okBtn = self.modals.okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = ()=> { + self.overlays = OverlayState.clear(self.overlays, self.map); + self.modals.okCancel.setVisible(false); + } + } + const cancelBtn = self.modals.okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + self.modals.okCancel.setVisible(false); + } + } + self.modals.okCancel.setVisible(true); } }
M src/99-onyx-scry.tssrc/99-onyx-scry.ts

@@ -26,14 +26,18 @@

overlays.markers.forEach(m=>m.add(map)); overlays.circles.forEach(m=>m.add(map)); overlays.polygons.forEach(m=>m.add(map)); - const createOverlayModal = new CreateOverlayModal(); + overlays.polyline.add(map); + const modals = new ModalCollection( - createOverlayModal); + new CreateOverlayModal(), + new CancelModal(), + new OKCancelModal()); MapHandler.init(map, overlays, TileLayerWrapper.layers, modals); MapHandler.setButtonClick("addPoint-btn", MapHandler.markerCollect); MapHandler.setButtonClick("addCircle-btn", MapHandler.circleCollect); + MapHandler.setButtonClick("addPolygon-btn", MapHandler.polygonCollect); MapHandler.setButtonClick("save-btn", MapHandler.overlaySave); MapHandler.setButtonClick("clear-btn", MapHandler.overlayClear);
M static/index.htmlstatic/index.html

@@ -22,8 +22,8 @@ <button id="addPoint-btn">&middot;</button>

<button id="addCircle-btn">&compfn;</button> <button id="addPolygon-btn">&diamond;</button> <div id="subControls"> + <button id="tiles-btn">&Colon;</button> <button id="save-btn">&darr;</button> - <button id="tiles-btn">&Colon;</button> <button id="clear-btn">&olarr;</button> <button id="menu-btn">&equiv;</button> </div>

@@ -49,20 +49,23 @@ </form>

</div> <div id="cancel-container"> + <span id="cancel-msg"></span> + <div class="multiBtn-container"> <button class="negative-btn" id="cancel-btn">Cancel</button> + </div> </div> <div id="info-container"> <button class="closeBtn" id="info-closeBtn">x</button> - <div class="info-content> + <div class="info-content"> </div> </div> <div id="confirm-container"> <span id="confirm-msg"></span> <div class="multiBtn-container"> - <button class="positive-btn" id="yes-btn">Yes</button> - <button class="negative-btn" id="no-btn">No</button> + <button class="positive-btn" id="yes-btn">OK</button> + <button class="negative-btn" id="no-btn">Cancel</button> </div> </div>
M static/onyx-scry.jsstatic/onyx-scry.js

@@ -52,15 +52,24 @@ class Polygon extends OverlayBase {

constructor(name, desc, points, options) { super(name, desc, points, options); this.self = L.polygon(points, options); + this.self.bindPopup(`<h3>${name}</h3><p>${desc}</p>`); } } -class Path extends OverlayBase { +class Polyline extends OverlayBase { constructor() { super("", "", [], {}); this.self = L.polyline([]); } insertPoint(pt) { this.self.addLatLng(pt); + this.points.push(pt); + } + clearPoints() { + this.points = []; + this.self.setLatLngs([]); + } + numPoints() { + return this.self.getLatLngs().length; } } class OverlayState {

@@ -68,6 +77,7 @@ constructor() {

this.markers = []; this.circles = []; this.polygons = []; + this.polyline = new Polyline(); } static load() { const store = localStorage.getItem("overlay_state");

@@ -77,6 +87,7 @@ return {

markers: model.markers.map((m) => OverlayState.fromData(m)), circles: model.circles.map((c) => OverlayState.fromData(c)), polygons: model.polygons.map((p) => OverlayState.fromData(p)), + polyline: new Polyline(), }; } else {

@@ -239,6 +250,9 @@ if (submitBtn) {

submitBtn.onclick = () => { const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); + if (name.trim().length < 1 || desc.trim().length < 1) { + return; + } const point = new Marker(name, desc, args.latlng, { title: name, alt: name }); point.add(args.map); args.overlays.markers.push(point);

@@ -255,6 +269,9 @@ submitBtn.onclick = () => {

const radius = _this.radiusField(); const name = TextUtils.encodeHTML(_this.nameField()); const desc = TextUtils.encodeHTML(_this.descField()); + if (name.trim().length < 1 || desc.trim().length < 1) { + return; + } const circle = new Circle(name, desc, args.latlng, { radius: Number(radius) || 500 }); circle.add(args.map); args.overlays.circles.push(circle);

@@ -263,16 +280,93 @@ };

} break; case OverlayType.POLYGON: + if (title) { + title.innerHTML = "Add Polygon"; + } + if (submitBtn) { + submitBtn.onclick = () => { + const name = TextUtils.encodeHTML(_this.nameField()); + const desc = TextUtils.encodeHTML(_this.descField()); + if (name.trim().length < 1 || desc.trim().length < 1) { + return; + } + const polygon = new Polygon(name, desc, args.points, {}); + polygon.add(args.map); + args.overlays.polygons.push(polygon); + _this.setVisible(false); + }; + } break; } } } +class CancelModal { + self() { + return document.getElementById("cancel-container"); + } + cancelMsg() { + return document.getElementById("cancel-msg"); + } + cancelBtn() { + return document.getElementById("cancel-btn"); + } + visible() { + var _a; + return ((_a = this.self()) === null || _a === void 0 ? void 0 : _a.style.display) != "none"; + } + setVisible(v) { + const modal = this.self(); + if (modal) { + modal.style.display = v ? "block" : "none"; + } + } + setMsg(s) { + const msg = this.cancelMsg(); + if (msg) { + msg.innerText = s; + } + } +} +class OKCancelModal { + self() { + return document.getElementById("confirm-container"); + } + confirmMsg() { + return document.getElementById("confirm-msg"); + } + okBtn() { + return document.getElementById("yes-btn"); + } + cancelBtn() { + return document.getElementById("no-btn"); + } + visible() { + var _a; + return ((_a = this.self()) === null || _a === void 0 ? void 0 : _a.style.display) != "none"; + } + setVisible(v) { + const modal = this.self(); + if (modal) { + modal.style.display = v ? "block" : "none"; + } + } + setMsg(s) { + const msg = this.confirmMsg(); + if (msg) { + msg.innerText = s; + } + } +} class ModalCollection { - constructor(createOverlay) { + constructor(createOverlay, cancel, okCancel) { this.createOverlay = createOverlay; + this.cancel = cancel; + this.okCancel = okCancel; } closeAll() { this.createOverlay.setVisible(false); + this.cancel.setVisible(false); + this.okCancel.setVisible(false); } } class MapHandler {

@@ -301,7 +395,7 @@ const addPointBtn = document.getElementById("addPoint-btn");

if (addPointBtn) { addPointBtn.classList.remove("activeBtn"); } - self.map.off("click", this.addMarker); + self.map.off("click", MapHandler.addMarker); } catch (_a) { } try {

@@ -309,33 +403,57 @@ const addCircleBtn = document.getElementById("addCircle-btn");

if (addCircleBtn) { addCircleBtn.classList.remove("activeBtn"); } - self.map.off("click", this.addCircle); + self.map.off("click", MapHandler.addCircle); } catch (_b) { } + try { + const addPolygonBtn = document.getElementById("addPolygon-btn"); + if (addPolygonBtn) { + addPolygonBtn.classList.remove("activeBtn"); + } + self.map.off("click", MapHandler.polygonAddPoint); + } + catch (_c) { } } } static addMarker(e) { const self = MapHandler.instance; if (self) { - self.modals.createOverlay.setVisible(true); + self.modals.cancel.setVisible(false); self.modals.createOverlay.setState(OverlayType.POINT, { latlng: e.latlng, map: self.map, overlays: self.overlays, }); MapHandler.resetMapClick(); + self.modals.createOverlay.setVisible(true); } } static addCircle(e) { const self = MapHandler.instance; if (self) { - self.modals.createOverlay.setVisible(true); + self.modals.cancel.setVisible(false); self.modals.createOverlay.setState(OverlayType.CIRCLE, { latlng: e.latlng, map: self.map, overlays: self.overlays, }); MapHandler.resetMapClick(); + self.modals.createOverlay.setVisible(true); + } + } + static addPolygon(e) { + const self = MapHandler.instance; + if (self) { + self.modals.okCancel.setVisible(false); + self.modals.createOverlay.setState(OverlayType.POLYGON, { + points: self.overlays.polyline.points, + map: self.map, + overlays: self.overlays, + }); + MapHandler.resetMapClick(); + self.overlays.polyline.clearPoints(); + self.modals.createOverlay.setVisible(true); } } static circleCollect(e) {

@@ -345,6 +463,15 @@ self.modals.closeAll();

MapHandler.resetMapClick(); e.target.classList.add("activeBtn"); self.map.on("click", MapHandler.addCircle); + const cancelBtn = self.modals.cancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + self.modals.closeAll(); + MapHandler.resetMapClick(); + }; + } + self.modals.cancel.setMsg("Placing circle"); + self.modals.cancel.setVisible(true); } } static markerCollect(e) {

@@ -354,18 +481,105 @@ self.modals.closeAll();

MapHandler.resetMapClick(); e.target.classList.add("activeBtn"); self.map.on("click", MapHandler.addMarker); + const cancelBtn = self.modals.cancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + self.modals.closeAll(); + MapHandler.resetMapClick(); + }; + } + self.modals.cancel.setMsg("Placing marker"); + self.modals.cancel.setVisible(true); + } + } + static polygonCollect(e) { + const self = MapHandler.instance; + if (self) { + self.modals.closeAll(); + MapHandler.resetMapClick(); + e.target.classList.add("activeBtn"); + // show cancel -- on cancel, clear polyline and reset map handling + const cancelBtn = self.modals.cancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = MapHandler.polygonClearPoints; + } + self.modals.cancel.setMsg("Creating polygon"); + self.modals.cancel.setVisible(true); + self.map.on("click", MapHandler.polygonAddPoint); + } + } + static polygonClearPoints(e) { + const self = MapHandler.instance; + if (self) { + self.modals.closeAll(); + self.overlays.polyline.clearPoints(); + MapHandler.resetMapClick(); + } + } + static polygonAddPoint(e) { + const self = MapHandler.instance; + if (self) { + self.overlays.polyline.insertPoint(e.latlng); + if (self.overlays.polyline.numPoints() >= 3) { + self.modals.cancel.setVisible(false); + const okBtn = self.modals.okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = MapHandler.addPolygon; + } + const cancelBtn = self.modals.okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = MapHandler.polygonClearPoints; + } + self.modals.okCancel.setMsg("Creating polygon"); + self.modals.okCancel.setVisible(true); + } } } static overlaySave(e) { const self = MapHandler.instance; if (self) { - OverlayState.save(self.overlays); + self.modals.closeAll(); + MapHandler.resetMapClick(); + e.target.classList.add("activeBtn"); + self.modals.okCancel.setMsg("Save current map overlays?"); + const okBtn = self.modals.okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = () => { + OverlayState.save(self.overlays); + self.modals.okCancel.setVisible(false); + // show info modal "Save complete" + }; + } + const cancelBtn = self.modals.okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + self.modals.okCancel.setVisible(false); + }; + } + self.modals.okCancel.setVisible(true); } } static overlayClear(e) { const self = MapHandler.instance; if (self) { - self.overlays = OverlayState.clear(self.overlays, self.map); + self.modals.closeAll(); + MapHandler.resetMapClick(); + e.target.classList.add("activeBtn"); + self.modals.okCancel.setMsg("Clear all map overlays (will not affect saved data)?"); + const okBtn = self.modals.okCancel.okBtn(); + if (okBtn) { + okBtn.onclick = () => { + self.overlays = OverlayState.clear(self.overlays, self.map); + self.modals.okCancel.setVisible(false); + }; + } + const cancelBtn = self.modals.okCancel.cancelBtn(); + if (cancelBtn) { + cancelBtn.onclick = () => { + self.modals.okCancel.setVisible(false); + }; + } + self.modals.okCancel.setVisible(true); } } static swapTiles(e) {

@@ -397,11 +611,12 @@ TileLayerWrapper.enableOnly("streetLayer", map);

overlays.markers.forEach(m => m.add(map)); overlays.circles.forEach(m => m.add(map)); overlays.polygons.forEach(m => m.add(map)); - const createOverlayModal = new CreateOverlayModal(); - const modals = new ModalCollection(createOverlayModal); + overlays.polyline.add(map); + const modals = new ModalCollection(new CreateOverlayModal(), new CancelModal(), new OKCancelModal()); MapHandler.init(map, overlays, TileLayerWrapper.layers, modals); MapHandler.setButtonClick("addPoint-btn", MapHandler.markerCollect); MapHandler.setButtonClick("addCircle-btn", MapHandler.circleCollect); + MapHandler.setButtonClick("addPolygon-btn", MapHandler.polygonCollect); MapHandler.setButtonClick("save-btn", MapHandler.overlaySave); MapHandler.setButtonClick("clear-btn", MapHandler.overlayClear); MapHandler.setButtonClick("tiles-btn", MapHandler.swapTiles);
M static/style.cssstatic/style.css

@@ -169,9 +169,9 @@ button.closeBtn:hover {

color: crimson; } -button#createOverlay-submitBtn { +button#createOverlay-submitBtn, button.positive-btn, button.negative-btn { font-size: 150%; - background: transparent;; + background: transparent; color: white; border: solid 2px dimgray; position: relative;

@@ -186,14 +186,42 @@ color: black;

border: solid 2px white; } +button.positive-btn, button.negative-btn { + font-size: 66.66%; + margin-top: 1em; +} + +button.positive-btn { + border: solid 2px #1f9b92; + float: left; +} + +button.positive-btn:hover { + color: black; + background: #1f9b92; +} + +button.negative-btn { + float: right; +} + +button.negative-btn:hover { + color: black; + background: crimson; + border: solid 2px crimson; +} + #cancel-container, #confirm-container, #info-container { position: fixed; - font-size: 200%; - bottom: 1.5em; + font-size: 250%; + bottom: 5em; display: none; left: 50%; - transform: translateY(-50%); + transform: translateX(-50%); background: black; + z-index: 10; + color: white; + padding: 0.5em; } #import-export-container {