diff --git a/src/mapml/handlers/ContextMenu.js b/src/mapml/handlers/ContextMenu.js index fcbc3e9b3..be76c0d9b 100644 --- a/src/mapml/handlers/ContextMenu.js +++ b/src/mapml/handlers/ContextMenu.js @@ -6,6 +6,8 @@ to deal in the Software without restriction, including without limitation the ri and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. */ +/* global M */ + export var ContextMenu = L.Handler.extend({ _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart', @@ -16,22 +18,18 @@ export var ContextMenu = L.Handler.extend({ this._items = [ { text: M.options.locale.cmBack + " (B)", - callback:this._goBack, + callback:this._goBack }, { text: M.options.locale.cmForward + " (F)", - callback:this._goForward, + callback:this._goForward }, { text: M.options.locale.cmReload + " (R)", - callback:this._reload, - }, - { - spacer:"-", + callback:this._reload }, { - text: M.options.locale.cmToggleControls + " (T)", - callback:this._toggleControls, + spacer:"-" }, { text: M.options.locale.cmCopyCoords + " (C)", @@ -40,75 +38,52 @@ export var ContextMenu = L.Handler.extend({ popup:true, submenu:[ { - text:"tile", - callback:this._copyTile, - }, - { - text:"tilematrix", - callback:this._copyTileMatrix, - }, - { - spacer:"-", - }, - { - text:"map", - callback:this._copyMap, - }, - { - spacer:"-", + text: M.options.locale.cmCopyMapML, + callback:this._copyMapML }, { - text:"tcrs", - callback:this._copyTCRS, + text: M.options.locale.cmCopyExtent, + callback:this._copyExtent }, { - text:"pcrs", - callback:this._copyPCRS, - }, - { - text:"gcrs", - callback:this._copyGCRS, - }, - { - spacer:"-", - }, - { - text: M.options.locale.cmCopyAll, - callback:this._copyAllCoords, + text: M.options.locale.cmCopyLocation, + callback:this._copyLocation } ] }, { - text: M.options.locale.cmToggleDebug + " (D)", - callback:this._toggleDebug, + text: M.options.locale.cmPasteLayer + " (P)", + callback:this._paste }, { - text: M.options.locale.cmCopyMapML + " (M)", - callback:this._copyMapML, + spacer:"-" }, { - text: M.options.locale.cmPasteLayer + " (P)", - callback:this._paste, + text: M.options.locale.cmToggleControls + " (T)", + callback:this._toggleControls + }, { + text: M.options.locale.cmToggleDebug + " (D)", + callback:this._toggleDebug }, { text: M.options.locale.cmViewSource + " (V)", - callback:this._viewSource, - }, + callback:this._viewSource + } ]; + // setting the default cs for copying location and extent + // should be public as they are used in tests + this.defExtCS = M.options.defaultExtCoor; + this.defLocCS = M.options.defaultLocCoor; this._layerItems = [ { text: M.options.locale.lmZoomToLayer + " (Z)", callback:this._zoomToLayer }, - { - text: M.options.locale.lmCopyExtent + " (C)", - callback:this._copyLayerExtent - }, { text: M.options.locale.lmCopyLayer + " (L)", callback:this._copyLayer - }, + } ]; this._mapMenuVisible = false; this._keyboardEvent = false; @@ -116,7 +91,7 @@ export var ContextMenu = L.Handler.extend({ this._container = L.DomUtil.create("div", "mapml-contextmenu", map._container); this._container.setAttribute('hidden', ''); - for (let i = 0; i < 6; i++) { + for (let i = 0; i < 5; i++) { this._items[i].el = this._createItem(this._container, this._items[i]); } @@ -126,10 +101,11 @@ export var ContextMenu = L.Handler.extend({ this._clickEvent = null; - for(let i =0;i`; + _copyExtent: function (e) { + let context = e instanceof KeyboardEvent ? this._map.contextMenu : this.contextMenu, + coord = context.defExtCS? context.defExtCS.toLowerCase() : 'pcrs', + tL = e instanceof KeyboardEvent? this.extent.topLeft[coord] : this.options.mapEl.extent.topLeft[coord], + bR = e instanceof KeyboardEvent? this.extent.bottomRight[coord] : this.options.mapEl.extent.bottomRight[coord], + data = ""; + switch(coord) { + case 'MapML': + default: + if (coord === 'pcrs') { + data = ``; + } else if (coord === 'gcrs') { + data = ``; + } else if (coord === 'tcrs') { + data = ``; + } else if (coord === 'tilematrix') { + data = ``; + } else { + console.log('not support'); + } + break; + } context._copyData(data); }, @@ -272,10 +270,25 @@ export var ContextMenu = L.Handler.extend({ document.body.removeChild(el); }, + _copyLocation: function(e){ + const menu = this.contextMenu; + switch(menu.defLocCS.toLowerCase()) { + case 'tile': menu._copyTile.call(this, e); break; + case 'tilematrix': menu._copyTileMatrix.call(this, e); break; + case 'map': menu._copyMap.call(this, e); break; + case 'tcrs': menu._copyTCRS.call(this, e); break; + case 'pcrs': menu._copyPCRS.call(this, e); break; + case 'gcrs': + default: + menu._copyGCRS.call(this, e); + break; + } + }, + _copyGCRS: function(e){ let mapEl = this.options.mapEl, click = this.contextMenu._clickEvent; - this.contextMenu._copyData(`z:${mapEl.zoom}, lon :${click.latlng.lng.toFixed(6)}, lat:${click.latlng.lat.toFixed(6)}`); + this.contextMenu._copyData(`lon :${click.latlng.lng.toFixed(6)}, lat:${click.latlng.lat.toFixed(6)}`); }, _copyTCRS: function(e){ @@ -299,7 +312,7 @@ export var ContextMenu = L.Handler.extend({ point = mapEl._map.project(click.latlng), scale = mapEl._map.options.crs.scale(+mapEl.zoom), pcrs = mapEl._map.options.crs.transformation.untransform(point,scale); - this.contextMenu._copyData(`z:${mapEl.zoom}, easting:${pcrs.x.toFixed(2)}, northing:${pcrs.y.toFixed(2)}`); + this.contextMenu._copyData(`easting:${Math.round(pcrs.x)}, northing:${Math.round(pcrs.y)}`); }, _copyTile: function(e){ @@ -446,21 +459,25 @@ export var ContextMenu = L.Handler.extend({ let elem = e.originalEvent.target; if(elem.closest("fieldset")){ elem = elem.closest("fieldset"); - elem = (elem.className === "mapml-layer-extent") ? elem.closest("fieldset").parentNode.parentNode.parentNode.querySelector("span") : elem.querySelector("span"); + elem = (elem.className === "mapml-layer-extent") ? + elem.closest("fieldset").parentNode.parentNode.parentNode.querySelector("span") : + elem.querySelector("span"); if(!elem.layer.validProjection) return; this._layerClicked = elem; this._layerMenu.removeAttribute('hidden'); this._showAtPoint(e.containerPoint, e, this._layerMenu); } else if(elem.classList.contains("leaflet-container") || elem.classList.contains("mapml-debug-extent") || elem.tagName === "path") { - this._layerClicked = undefined; + let layerList = this._map.options.mapEl.layers; + this._layerClicked = Array.from(layerList).find(el => el.checked); // the 'hidden' attribute must be removed before any attempt to get the size of container this._container.removeAttribute('hidden'); this._showAtPoint(e.containerPoint, e, this._container); + this._updateCS(); } if(e.originalEvent.button === 0 || e.originalEvent.button === -1){ this._keyboardEvent = true; - if(this._layerClicked){ + if(this._layerClicked.className.includes('mapml-layer-item')){ let activeEl = document.activeElement; this._elementInFocus = activeEl.shadowRoot.activeElement; this._layerMenuTabs = 1; @@ -586,8 +603,10 @@ export var ContextMenu = L.Handler.extend({ if(this._layerMenuTabs === 0 || this._layerMenuTabs === 4 || key === 27){ L.DomEvent.stop(e); this._focusOnLayerControl(); - } - } else if(key !== 16 && key!== 9 && !(!this._layerClicked && key === 67) && path[0].innerText !== (M.options.locale.cmCopyCoords + " (C)")){ + } + } else if(key !== 16 && key!== 9 && + !(!(this._layerClicked.className.includes('mapml-layer-item')) && key === 67) && + (path[0].innerText !== (M.options.locale.cmCopyCoords + " (C)") || key === 27)){ this._hide(); } switch(key){ @@ -600,13 +619,9 @@ export var ContextMenu = L.Handler.extend({ this._goBack(e); break; case 67: //C KEY - if(this._layerClicked){ - this._copyLayerExtent(e); - } else { - this._copyCoords({ - latlng:this._map.getCenter() - }); - } + this._copyCoords({ + latlng:this._map.getCenter() + }); break; case 68: //D KEY this._toggleDebug(e); @@ -618,7 +633,7 @@ export var ContextMenu = L.Handler.extend({ this._goForward(e); break; case 76: //L KEY - if(this._layerClicked) + if(this._layerClicked.className.includes('mapml-layer-item')) this._copyLayer(e); break; case 80: //P KEY @@ -634,7 +649,7 @@ export var ContextMenu = L.Handler.extend({ this._viewSource(e); break; case 90: //Z KEY - if(this._layerClicked) + if(this._layerClicked.className.includes('mapml-layer-item')) this._zoomToLayer(e); break; } @@ -660,16 +675,8 @@ export var ContextMenu = L.Handler.extend({ menu.style.right = 'auto'; } - // height difference between the main contextmenu and submenu - const heightDiff = 73; - if (click.containerPoint.y + menuHeight + heightDiff > mapSize.y) { - menu.style.top = 'auto'; - // to make submenu show completely when clicking at the bottom of the map - menu.style.bottom = 32 + 'px'; - } else { - menu.style.top = 100 + 'px'; - menu.style.bottom = 'auto'; - } + menu.style.top = 100 - 22 + 'px'; + menu.style.bottom = 'auto'; if(this._keyboardEvent)menu.firstChild.focus(); }, @@ -677,7 +684,7 @@ export var ContextMenu = L.Handler.extend({ if(!e.relatedTarget || !e.relatedTarget.parentElement || e.relatedTarget.parentElement.classList.contains("mapml-submenu") || e.relatedTarget.classList.contains("mapml-submenu"))return; - let menu = this._coordMenu, copyEl = this._items[5].el.el; + let menu = this._coordMenu, copyEl = this._items[4].el.el; copyEl.setAttribute("aria-expanded","false"); menu.setAttribute('hidden', ''); }, diff --git a/src/mapml/options.js b/src/mapml/options.js index 131e62b8a..1d66db4ee 100644 --- a/src/mapml/options.js +++ b/src/mapml/options.js @@ -1,19 +1,21 @@ export var Options = { featureIndexOverlayOption: false, announceMovement: false, + defaultExtCoor: 'pcrs', + defaultLocCoor: 'gcrs', locale: { cmBack: "Back", cmForward: "Forward", cmReload: "Reload", cmToggleControls: "Toggle Controls", - cmCopyCoords: "Copy Coordinates", + cmCopyCoords: "Copy", + cmCopyMapML: "Map", + cmCopyExtent: "Extent", + cmCopyLocation: "Location", cmToggleDebug: "Toggle Debug Mode", - cmCopyMapML: "Copy MapML", cmPasteLayer: "Paste", cmViewSource: "View Map Source", - cmCopyAll: "All", lmZoomToLayer: "Zoom To Layer", - lmCopyExtent: "Copy Extent", lmCopyLayer: "Copy Layer", lcOpacity: "Opacity", btnZoomIn: "Zoom in", diff --git a/test/e2e/core/layerContextMenu.test.js b/test/e2e/core/layerContextMenu.test.js index a6ade23bd..01b834a9e 100644 --- a/test/e2e/core/layerContextMenu.test.js +++ b/test/e2e/core/layerContextMenu.test.js @@ -27,18 +27,6 @@ test.describe("Playwright Layer Context Menu Tests", () => { expect(menuDisplay).toEqual("block"); }); - test("Layer context menu copy layer extent", async () => { - await page.keyboard.press("c"); - await page.click("body > textarea#messageExtent"); - await page.keyboard.press("Control+v"); - const copyValue = await page.$eval( - "body > textarea#messageExtent", - (text) => text.value - ); - - expect(copyValue).toEqual(""); - }); - test("Layer context menu copy layer", async () => { await page.hover("div > div.leaflet-control-container > div.leaflet-top.leaflet-right > div"); await page.click("div > div.leaflet-control-container > div.leaflet-top.leaflet-right > div > section > div.leaflet-control-layers-overlays > fieldset:nth-child(1) > div:nth-child(1) > label > span", diff --git a/test/e2e/core/mapContextMenu.test.js b/test/e2e/core/mapContextMenu.test.js index 945d4fab3..725b82c85 100644 --- a/test/e2e/core/mapContextMenu.test.js +++ b/test/e2e/core/mapContextMenu.test.js @@ -15,9 +15,20 @@ let expectedFirstTCRS = [ { horizontal: 659, vertical: 730 }, { horizontal: 771.4482758620691, vertical: 753.8620689655173 }]; +// expected extent top-left and bottom-right values at different zoom levels +let expectedExtentPCRS_0 = [ + {horizontal: -9373489, vertical: 11303798}, + {horizontal: 9808841, vertical: -11714998} +]; +let expectedExtentPCRS_1 = [ + {horizontal: -5396794, vertical: 6520122}, + {horizontal: 5848021, vertical: -6973655} +]; + test.describe("Playwright Map Context Menu Tests", () => { let page; let context; + let currExtCS, currLocCS; test.beforeAll(async () => { context = await chromium.launchPersistentContext(''); await context.grantPermissions(["clipboard-read", "clipboard-write"]); @@ -46,7 +57,7 @@ test.describe("Playwright Map Context Menu Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("Toggle Controls (T)"); + expect(name).toEqual("Copy (C)"); }); test("Context menu tab goes to next item", async () => { @@ -57,7 +68,7 @@ test.describe("Playwright Map Context Menu Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("Copy Coordinates (C)"); + expect(name).toEqual("Paste (P)"); }); test("Submenu opens on C with focus on first item", async () => { @@ -68,7 +79,7 @@ test.describe("Playwright Map Context Menu Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("tile"); + expect(name).toEqual("Map"); }); test("Context menu displaying on map", async () => { @@ -162,7 +173,7 @@ test.describe("Playwright Map Context Menu Tests", () => { ); await page.click("body > map", { button: "right" }); - await page.click("div > div.mapml-contextmenu > button:nth-child(5)"); + await page.click("div > div.mapml-contextmenu > button:nth-of-type(6)"); const controlsOff = await page.$eval( "div > div.leaflet-control-container > div.leaflet-top.leaflet-left", @@ -180,7 +191,7 @@ test.describe("Playwright Map Context Menu Tests", () => { ); await page.click("body > map", { button: "right" }); - await page.click("div > div.mapml-contextmenu > button:nth-child(5)"); + await page.click("div > div.mapml-contextmenu > button:nth-of-type(6)"); const controlsOff = await page.$eval( "div > div.leaflet-control-container > div.leaflet-top.leaflet-left", @@ -221,15 +232,74 @@ test.describe("Playwright Map Context Menu Tests", () => { }); }); - test("Submenu, copy all coordinate systems using tab + enter to access", async () => { + test("Submenu, copy map (MapML)", async () => { + await page.reload(); + await page.click("body > map"); + await page.keyboard.press("Shift+F10"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); + + await page.click("body > textarea#coord"); + await page.keyboard.press("Control+v"); + const copyValue = await page.$eval( + "body > textarea#coord", + (text) => text.value + ); + const expected = ` + + + + `; + expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + }); + + test("Submenu, copy extent with zoom level = 0", async () => { + currExtCS = await page.$eval( + "body > map", + (map) => (map._map.contextMenu.defExtCS) + ); + // set cs to pcrs for copying extent test + await page.$eval( + "body > map", + (map) => {map._map.contextMenu.defExtCS = 'pcrs';} + ); await page.click("body > map"); await page.keyboard.press("Shift+F10"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + + await page.click("body > textarea#coord"); + await page.keyboard.press("Control+v"); + const copyValue = await page.$eval( + "body > textarea#coord", + (text) => text.value + ); + const expected = ``; + expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + }); - for (let i = 0; i < 3; i++) - await page.keyboard.press("Tab"); + test("Submenu, copy extent with zoom level = 1", async () => { + // zoom in + await page.click("body > map"); + await page.keyboard.press('Tab'); + await page.keyboard.press('Enter'); + await page.waitForTimeout(1000); + await page.click("body > map"); + await page.keyboard.press("Shift+F10"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Tab"); await page.keyboard.press("Enter"); - await page.click("#mapml-copy-submenu > button:nth-child(10)"); await page.click("body > textarea#coord"); await page.keyboard.press("Control+v"); @@ -237,15 +307,52 @@ test.describe("Playwright Map Context Menu Tests", () => { "body > textarea#coord", (text) => text.value ); - let expected = "z:1\n"; - expected += "tile: i:30, j:50\n"; - expected += "tilematrix: column:6, row:6\n"; - expected += "map: i:250, j:300\n"; - expected += "tcrs: x:1566, y:1586\n"; - expected += "pcrs: easting:562957.94, northing:3641449.50\n"; - expected += "gcrs: lon :-62.729466, lat:80.881921"; + const expected = ``; + expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + await page.$eval( + "body > map", + (map, currExtCS) => { + map._map.contextMenu.defExtCS = currExtCS; + }, + currExtCS + ); + }); + test("Submenu, copy location", async () => { + currLocCS = await page.$eval( + "body > map", + (map) => (map._map.contextMenu.defLocCS) + ) + // set cs to pcrs for copying location test + await page.$eval( + "body > map", + (map) => {map._map.contextMenu.defLocCS = 'gcrs';} + ); + await page.click("body > map"); + await page.keyboard.press("Shift+F10"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + await page.click("body > textarea#coord"); + await page.keyboard.press("Control+v"); + const copyValue = await page.$eval( + "body > textarea#coord", + (text) => text.value + ); + const expected = "lon :-92.062002, lat:46.922393"; expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + await page.$eval( + "body > map", + (map, currLocCS) => { + map._map.contextMenu.defLocCS = currLocCS; + }, + currLocCS + ); }); test("Paste valid Layer to map", async () => { @@ -339,10 +446,10 @@ test.describe("Playwright Map Context Menu Tests", () => { expect(contextMenuSize.x <= mapSize.x && contextMenuSize.y <= mapSize.y).toBeTruthy(); // move the mouse from "copy" to another button in the main contextmenu - await contextMenu.hover(); + await page.hover("div > div.mapml-contextmenu > button:nth-of-type(4)"); const submenu = await page.locator('div > div#mapml-copy-submenu').first(); expect(await submenu.isVisible()).toBeTruthy(); - await page.hover("div > div.mapml-contextmenu > button:nth-child(5)"); + await page.hover("div > div.mapml-contextmenu > button:nth-of-type(5)"); expect(await submenu.isHidden()).toBeTruthy(); }); @@ -378,4 +485,4 @@ test.describe("Playwright Map Context Menu Tests", () => { expect(fwdBtn).toEqual(false); expect(reloadBtn).toEqual(false); }); -}); \ No newline at end of file +}); diff --git a/test/e2e/mapml-viewer/mapml-viewer.html b/test/e2e/mapml-viewer/mapml-viewer.html index 5b95311dd..3e1300ec8 100644 --- a/test/e2e/mapml-viewer/mapml-viewer.html +++ b/test/e2e/mapml-viewer/mapml-viewer.html @@ -37,7 +37,7 @@ - + diff --git a/test/e2e/mapml-viewer/mapml-viewer.test.js b/test/e2e/mapml-viewer/mapml-viewer.test.js index 30b4baacc..baa2fd316 100644 --- a/test/e2e/mapml-viewer/mapml-viewer.test.js +++ b/test/e2e/mapml-viewer/mapml-viewer.test.js @@ -112,9 +112,11 @@ test.describe("Playwright mapml-viewer Element Tests", () => { let children = await page.$eval(".leaflet-top.leaflet-right", (div) => div.childElementCount); expect(children).toEqual(0); await page.click("body > mapml-viewer", { button: "right" }); - await page.click("div > div.mapml-contextmenu > button:nth-child(5)"); + // toggle controls + await page.click(".mapml-contextmenu > button:nth-of-type(6)"); await page.click("body > mapml-viewer", { button: "right" }); - await page.click("div > div.mapml-contextmenu > button:nth-child(5)"); + // toggle controls + await page.click(".mapml-contextmenu > button:nth-of-type(6)"); children = await page.$eval(".leaflet-top.leaflet-right", (div) => div.childElementCount); expect(children).toEqual(0); diff --git a/test/e2e/mapml-viewer/viewerContextMenu.test.js b/test/e2e/mapml-viewer/viewerContextMenu.test.js index 409573a86..46c0b55e3 100644 --- a/test/e2e/mapml-viewer/viewerContextMenu.test.js +++ b/test/e2e/mapml-viewer/viewerContextMenu.test.js @@ -15,11 +15,23 @@ let expectedFirstTCRS = [ { horizontal: 659, vertical: 730 }, { horizontal: 771.4482758620691, vertical: 753.8620689655173 }]; +// expected extent top-left and bottom-right value at different zoom levels (0 and 1) +let expectedExtentPCRS_0 = [ + {horizontal: -9373489, vertical: 11303798}, + {horizontal: 9808841, vertical: -11714998} +]; +let expectedExtentPCRS_1 = [ + {horizontal: -5396794, vertical: 6520122}, + {horizontal: 5848021, vertical: -6973655} +]; + test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { let page; let context; + let currExtCS, currLocCS; test.beforeAll(async () => { context = await chromium.launchPersistentContext(''); + await context.grantPermissions(["clipboard-read", "clipboard-write"]); page = context.pages().find((page) => page.url() === 'about:blank') || await context.newPage(); page = await context.newPage(); await page.goto("mapml-viewer.html"); @@ -38,7 +50,7 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("Toggle Controls (T)"); + expect(name).toEqual("Copy (C)"); }); test("Context menu tab goes to next item", async () => { @@ -49,7 +61,7 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("Copy Coordinates (C)"); + expect(name).toEqual("Paste (P)"); }); @@ -61,7 +73,7 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("Toggle Controls (T)"); + expect(name).toEqual("Copy (C)"); }); test("Submenu opens on C with focus on first item", async () => { @@ -72,7 +84,7 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { const nameHandle = await page.evaluateHandle(name => name.outerText, resultHandle); let name = await nameHandle.jsonValue(); await nameHandle.dispose(); - expect(name).toEqual("tile"); + expect(name).toEqual("Map"); }); test("Context menu displaying on map", async () => { @@ -166,7 +178,7 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { ); await page.click("body > mapml-viewer", { button: "right" }); - await page.click("div > div.mapml-contextmenu > button:nth-child(5)"); + await page.click("div > div.mapml-contextmenu > button:nth-of-type(6)"); const controlsOff = await page.$eval( "div > div.leaflet-control-container > div.leaflet-top.leaflet-left", @@ -184,7 +196,7 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { ); await page.click("body > mapml-viewer", { button: "right" }); - await page.click("div > div.mapml-contextmenu > button:nth-child(5)"); + await page.click("div > div.mapml-contextmenu > button:nth-of-type(6)"); const controlsOff = await page.$eval( "div > div.leaflet-control-container > div.leaflet-top.leaflet-left", @@ -226,57 +238,127 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { }); }); - test("Submenu, copy all coordinate systems using tab + enter to access", async () => { + test("Submenu, copy map (MapML)", async () => { + await page.reload(); await page.click("body > mapml-viewer"); await page.keyboard.press("Shift+F10"); - for (let i = 0; i < 3; i++) - await page.keyboard.press("Tab"); - + await page.keyboard.press("Enter"); await page.keyboard.press("Enter"); - await page.click("#mapml-copy-submenu > button:nth-child(10)"); - - await page.click("body > textarea"); + await page.click("body > textarea#coord"); await page.keyboard.press("Control+v"); const copyValue = await page.$eval( - "body > textarea", + "body > textarea#coord", (text) => text.value ); - let expected = "z:1\n"; - expected += "tile: i:30, j:50\n"; - expected += "tilematrix: column:6, row:6\n"; - expected += "map: i:250, j:300\n"; - expected += "tcrs: x:1566, y:1586\n"; - expected += "pcrs: easting:562957.94, northing:3641449.50\n"; - expected += "gcrs: lon :-62.729466, lat:80.881921"; - + const expected = ` + + + + `; expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); }); - test("Submenu, copy all coordinate systems", async () => { + test("Submenu, copy extent with zoom level = 0", async () => { + currExtCS = await page.$eval( + "body > mapml-viewer", + (map) => (map._map.contextMenu.defExtCS) + ); + // set cs to pcrs for copying extent test + await page.$eval( + "body > mapml-viewer", + (map) => {map._map.contextMenu.defExtCS = 'pcrs';} + ); await page.click("body > mapml-viewer"); await page.keyboard.press("Shift+F10"); - await page.keyboard.press("c"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); - await page.click("#mapml-copy-submenu > button:nth-child(10)"); + await page.click("body > textarea#coord"); + await page.keyboard.press("Control+v"); + const copyValue = await page.$eval( + "body > textarea#coord", + (text) => text.value + ); + const expected = ``; + expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + }); + + test("Submenu, copy extent with zoom level = 1", async () => { + // zoom in + await page.click("body > mapml-viewer"); + await page.keyboard.press('Tab'); + await page.keyboard.press('Enter'); + await page.waitForTimeout(1000); + + await page.click("body > mapml-viewer"); + await page.keyboard.press("Shift+F10"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); - await page.click("body > textarea"); - await page.keyboard.press("Control+a"); - await page.keyboard.press("Backspace"); + await page.click("body > textarea#coord"); await page.keyboard.press("Control+v"); const copyValue = await page.$eval( - "body > textarea", + "body > textarea#coord", (text) => text.value ); - let expected = "z:1\n"; - expected += "tile: i:30, j:50\n"; - expected += "tilematrix: column:6, row:6\n"; - expected += "map: i:250, j:300\n"; - expected += "tcrs: x:1566, y:1586\n"; - expected += "pcrs: easting:562957.94, northing:3641449.50\n"; - expected += "gcrs: lon :-62.729466, lat:80.881921"; + const expected = ``; + expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + await page.$eval( + "body > mapml-viewer", + (map, currExtCS) => { + map._map.contextMenu.defExtCS = currExtCS; + }, + currExtCS + ); + }); + test("Submenu, copy location", async () => { + currLocCS = await page.$eval( + "body > mapml-viewer", + (map) => (map._map.contextMenu.defLocCS) + ) + // set cs to pcrs for copying location test + await page.$eval( + "body > mapml-viewer", + (map) => {map._map.contextMenu.defLocCS = 'gcrs';} + ); + await page.click("body > mapml-viewer"); + await page.keyboard.press("Shift+F10"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + await page.click("body > textarea#coord"); + await page.keyboard.press("Control+v"); + const copyValue = await page.$eval( + "body > textarea#coord", + (text) => text.value + ); + const expected = "lon :-92.062002, lat:46.922393"; expect(copyValue).toEqual(expected); + await page.locator("body > textarea#coord").fill(''); + await page.$eval( + "body > mapml-viewer", + (map, currLocCS) => { + map._map.contextMenu.defLocCS = currLocCS; + }, + currLocCS + ); }); test("Context menu, All buttons enabled when fwd and back history present", async () => { @@ -311,4 +393,37 @@ test.describe("Playwright mapml-viewer Context Menu (and api) Tests", () => { expect(fwdBtn).toEqual(false); expect(reloadBtn).toEqual(false); }); -}); \ No newline at end of file + + test("Context menu, click at margin and move mouse out when submenu is visible", async () => { + // click at the right-bottom margin of map + await page.mouse.wheel(0, 200); + await page.waitForTimeout(200); + await page.click("body > mapml-viewer", { + button: 'right', + position: {x: 495, y: 580} + }); + const contextMenu = await page.locator('div > div.mapml-contextmenu').first(); + expect(await contextMenu.isVisible()).toBeTruthy(); + const mapSize = await page.$eval( + "body > mapml-viewer", + (map) => { return {x: map.width, y: map.height} } + ); + const contextMenuSize = await page.$eval( + "div > div.mapml-contextmenu", + (menu) => { + return { + x: menu.offsetWidth + menu.getBoundingClientRect().left, + y: menu.offsetHeight + menu.getBoundingClientRect().top + } + } + ); + expect(contextMenuSize.x <= mapSize.x && contextMenuSize.y <= mapSize.y).toBeTruthy(); + + // move the mouse from "copy" to another button in the main contextmenu + await page.hover("div > div.mapml-contextmenu > button:nth-of-type(4)"); + const submenu = await page.locator('div > div#mapml-copy-submenu').first(); + expect(await submenu.isVisible()).toBeTruthy(); + await page.hover("div > div.mapml-contextmenu > button:nth-of-type(5)"); + expect(await submenu.isHidden()).toBeTruthy(); + }); +});