Skip to content

Commit 2677ab5

Browse files
prushforprushforth
authored andcommitted
Allow changing layer title in layer control via HTMLLayerElement.label
under limited conditions (no <map-title> in content). Encapsulate accessible name change into MapMLLayer.setName() method Remove unused, unspecified labelchanged event Add test fixture Add <map-meta name="projection"...> so as to not rely on default projection value just yet, wait until that lands. Add that the extentload event emitted by the HTMLLayerElement bubbles, which I believe is normal. Use this event to ensure that tests can rely on the layer metadata being final before testing name change ability. Add MapMLLayer.getName method to complement new setName. Name being the 'accessible name' of the layer, represented in the layer control via the MapMLLayer._title value. Add setTimeout to work around the evil createmap event -caused issues Add test of HTMLLayerElement.label behaviour
1 parent 7b0858f commit 2677ab5

File tree

6 files changed

+216
-6
lines changed

6 files changed

+216
-6
lines changed

src/layer.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,7 @@ export class MapLayer extends HTMLElement {
122122
attributeChangedCallback(name, oldValue, newValue) {
123123
switch (name) {
124124
case 'label':
125-
if (oldValue !== newValue) {
126-
this.dispatchEvent(
127-
new CustomEvent('labelchanged', { detail: { target: this } })
128-
);
129-
}
125+
this?._layer?.setName(newValue);
130126
break;
131127
case 'checked':
132128
if (this._layer) {

src/mapml/layers/MapMLLayer.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ export var MapMLLayer = L.Layer.extend({
136136
this._setLayerElExtent();
137137
}
138138
},
139+
setName(newName) {
140+
// a layer's accessible name is set by the <map-title>, if present
141+
// if it's not available the <layer- label="accessible-name"> attribute
142+
// can be used
143+
if (!this._titleIsReadOnly) {
144+
this._title = newName;
145+
this._mapmlLayerItem.querySelector('.mapml-layer-item-name').innerHTML =
146+
newName;
147+
}
148+
},
149+
getName() {
150+
return this._title;
151+
},
139152

140153
onAdd: function (map) {
141154
if (this._extent && !this._validProjection(map)) {
@@ -1615,6 +1628,7 @@ export var MapMLLayer = L.Layer.extend({
16151628

16161629
if (mapml.querySelector('map-title')) {
16171630
layer._title = mapml.querySelector('map-title').textContent.trim();
1631+
layer._titleIsReadOnly = true;
16181632
} else if (mapml instanceof Element && mapml.hasAttribute('label')) {
16191633
layer._title = mapml.getAttribute('label').trim();
16201634
}
@@ -1642,7 +1656,7 @@ export var MapMLLayer = L.Layer.extend({
16421656
layer._layerEl.parentElement._toggleControls();
16431657
}
16441658
layer._layerEl.dispatchEvent(
1645-
new CustomEvent('extentload', { detail: layer })
1659+
new CustomEvent('extentload', { detail: layer, bubbles: true })
16461660
);
16471661
}
16481662

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>domApi-HTMLLayerElement.html</title>
5+
<meta charset="UTF-8">
6+
<script type="module" src="mapml-viewer.js"></script>
7+
</head>
8+
<body>
9+
<template>
10+
<layer- id="remote-with-title" label="This should not appear in layer control" src="with-title.mapml" checked></layer->
11+
<layer- id="remote-no-title" label="Layer with name settable via HTMLLayerElement.label" src="no-title.mapml" checked></layer->
12+
<layer- id="local-no-title" label="Another Layer with name settable via HTMLLayerElement.label" checked>
13+
<map-meta name="projection" content="OSMTILE"></map-meta>
14+
<map-feature id="hg" zoom="3" min="0" max="22">
15+
<map-featurecaption>Statue of a guy with a hat</map-featurecaption>
16+
<map-geometry cs="gcrs">
17+
<map-point>
18+
<map-coordinates>-75.70628 45.39878</map-coordinates>
19+
</map-point>
20+
</map-geometry>
21+
<map-properties>
22+
<h1>A Man With Two Hats</h1>
23+
</map-properties>
24+
</map-feature>
25+
</layer->
26+
<layer- id="local-with-title" label="This should not appear in layer control" checked>
27+
<map-title>Layer name set via local map-title element - unsettable via HTMLLayerelement.label</map-title>
28+
<map-meta name="projection" content="OSMTILE"></map-meta>
29+
<map-feature id="hg" zoom="3" min="0" max="22">
30+
<map-featurecaption>Statue of a guy with a hat</map-featurecaption>
31+
<map-geometry cs="gcrs">
32+
<map-point>
33+
<map-coordinates>-75.70528 45.39778</map-coordinates>
34+
</map-point>
35+
</map-geometry>
36+
<map-properties>
37+
<h1>A Man With Two Hats</h1>
38+
</map-properties>
39+
</map-feature>
40+
</layer->
41+
</template>
42+
<mapml-viewer projection="OSMTILE" controls zoom="15" lat="45.39778" lon="-75.70528" width="500" height="500">
43+
</mapml-viewer>
44+
</body>
45+
<script>
46+
47+
let remoteWithTitle = document.querySelector('template').content.cloneNode(true).querySelector('#remote-with-title');
48+
remoteWithTitle = document.querySelector('mapml-viewer').appendChild(remoteWithTitle);
49+
let remoteNoTitle = document.querySelector('template').content.cloneNode(true).querySelector('#remote-no-title');
50+
remoteNoTitle = document.querySelector('mapml-viewer').appendChild(remoteNoTitle);
51+
let localNoTitle = document.querySelector('template').content.cloneNode(true).querySelector('#local-no-title');
52+
localNoTitle = document.querySelector('mapml-viewer').appendChild(localNoTitle);
53+
let localWithTitle = document.querySelector('template').content.cloneNode(true).querySelector('#local-with-title');
54+
localWithTitle = document.querySelector('mapml-viewer').appendChild(localWithTitle);
55+
56+
57+
addEventListener("extentload", (e) => {
58+
if (e.target === remoteWithTitle) {
59+
// setting label should not change the layer name in layer control
60+
remoteWithTitle.label = "Unforsettable in every way";
61+
} else if (e.target === remoteNoTitle) {
62+
// setting label should set the layer name in layer control
63+
remoteNoTitle.label = "Bedtime For Bonzo";
64+
} else if (e.target === localWithTitle) {
65+
// setting label should not set the layer name in layer control
66+
localWithTitle.label = "No dice, buddy!";
67+
} else if (e.target === localNoTitle) {
68+
// setting label should set the layer name in layer control
69+
// but because the layer is not fully initialized, need to wait unit
70+
// it triggers the createmap event, which eventually creates layer-._layer
71+
// but if we run this too early, before createmap, then the setter
72+
// for label does not have any (desired) side effects, namely running
73+
// layer-._layer.setName(labelValue). hence setTimeout.
74+
setTimeout(()=>{
75+
localNoTitle.label = "Go ahead, make my day!";
76+
}, 500);
77+
}
78+
});
79+
80+
</script>
81+
</html>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { test, expect, chromium } from '@playwright/test';
2+
3+
test.describe('HTMLLayerElement DOM API Tests', () => {
4+
let page;
5+
let context;
6+
test.beforeAll(async () => {
7+
context = await chromium.launchPersistentContext('');
8+
page =
9+
context.pages().find((page) => page.url() === 'about:blank') ||
10+
(await context.newPage());
11+
page = await context.newPage();
12+
await page.goto('domApi-HTMLLayerElement.html');
13+
});
14+
15+
test.afterAll(async function () {
16+
await context.close();
17+
});
18+
test('Setting HTMLLayerElement.label sets the layer name per spec', async () => {
19+
let remoteWithTitleLabel = await page.evaluate(() => {
20+
return document.querySelector('#remote-with-title').label;
21+
});
22+
expect(remoteWithTitleLabel).toEqual('Unforsettable in every way');
23+
let remoteWithTitleName = await page.evaluate(() => {
24+
let layer = document.querySelector('#remote-with-title');
25+
return layer._layer.getName();
26+
});
27+
expect(remoteWithTitleName).toEqual(
28+
'MapML author-controlled name - unsettable'
29+
);
30+
31+
let remoteNoTitleLabel = await page.evaluate(() => {
32+
return document.querySelector('#remote-no-title').label;
33+
});
34+
expect(remoteNoTitleLabel).toEqual('Bedtime For Bonzo');
35+
let remoteNoTitleName = await page.evaluate(() => {
36+
let layer = document.querySelector('#remote-no-title');
37+
return layer._layer.getName();
38+
});
39+
expect(remoteNoTitleName).toEqual(remoteNoTitleLabel);
40+
41+
let localWithTitleLabel = await page.evaluate(() => {
42+
return document.querySelector('#local-with-title').label;
43+
});
44+
expect(localWithTitleLabel).toEqual('No dice, buddy!');
45+
let localWithTitleName = await page.evaluate(() => {
46+
let layer = document.querySelector('#local-with-title');
47+
return layer._layer.getName();
48+
});
49+
expect(localWithTitleName).not.toEqual(localWithTitleLabel);
50+
51+
// THIS SHOULD NOT BE NECESSARY, BUT IT IS see comment below
52+
await page.waitForTimeout(500);
53+
let localNoTitleLabel = await page.evaluate(() => {
54+
return document.querySelector('#local-no-title').label;
55+
});
56+
expect(localNoTitleLabel).toEqual('Go ahead, make my day!');
57+
let localNoTitleName = await page.evaluate(() => {
58+
let layer = document.querySelector('#local-no-title');
59+
return layer._layer.getName();
60+
});
61+
// this isn't working, because waiting for the createmap event means
62+
// that the layer-._layer doesn't exist, so attributeChangeCallback on label
63+
// shortcircuits (does / can not setName on _layer) unless you wait for it.
64+
// need to ditch the createmap event!!
65+
expect(localNoTitleName).toEqual(localNoTitleLabel);
66+
});
67+
// add other tests here for HTMLLayerElement
68+
});

test/e2e/api/no-title.mapml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<mapml- xmlns="http://www.w3.org/1999/xhtml">
2+
<map-head>
3+
<!-- no map-title provided means the HTML <layer- src> that references
4+
this file may set its name via the HTMLLayerElement.label setter -->
5+
<map-meta charset="utf-8" ></map-meta>
6+
<map-meta content="text/mapml" http-equiv="Content-Type" ></map-meta>
7+
<map-link rel="license" href="http://opendatacommons.org/licenses/odbl/1-0/" title="© OpenStreetMap and contributors" />
8+
<map-meta name="projection" content="OSMTILE"></map-meta>
9+
<map-meta name="zoom" content="min=0,max=22,value=3" ></map-meta>
10+
<map-meta name="cs" content="gcrs" ></map-meta>
11+
<map-meta name="extent" content="top-left-easting=-8433179, top-left-northing=5689316, bottom-right-easting=-8420968, bottom-right-northing=5683139"></map-meta>
12+
</map-head>
13+
<map-body>
14+
<map-feature id="hg" zoom="3" min="0" max="22">
15+
<map-featurecaption>Statue of a guy with a hat</map-featurecaption>
16+
<map-geometry cs="gcrs">
17+
<map-point>
18+
<map-coordinates>-75.70528 45.39878</map-coordinates>
19+
</map-point>
20+
</map-geometry>
21+
<map-properties>
22+
<h1>A Man With Two Hats</h1>
23+
</map-properties>
24+
</map-feature>
25+
</map-body>
26+
</mapml->

test/e2e/api/with-title.mapml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<mapml- xmlns="http://www.w3.org/1999/xhtml">
2+
<map-head>
3+
<map-title>MapML author-controlled name - unsettable</map-title>
4+
<map-meta charset="utf-8" ></map-meta>
5+
<map-meta content="text/mapml" http-equiv="Content-Type" ></map-meta>
6+
<map-link rel="license" href="http://opendatacommons.org/licenses/odbl/1-0/" title="© OpenStreetMap and contributors" />
7+
<map-meta name="projection" content="OSMTILE"></map-meta>
8+
<map-meta name="zoom" content="min=0,max=22,value=3" ></map-meta>
9+
<map-meta name="cs" content="gcrs" ></map-meta>
10+
<map-meta name="extent" content="top-left-easting=-8433179, top-left-northing=5689316, bottom-right-easting=-8420968, bottom-right-northing=5683139"></map-meta>
11+
</map-head>
12+
<map-body>
13+
<map-feature id="hg" zoom="3" min="0" max="22">
14+
<map-featurecaption>Statue of a guy with a hat</map-featurecaption>
15+
<map-geometry cs="gcrs">
16+
<map-point>
17+
<map-coordinates>-75.70628 45.39778</map-coordinates>
18+
</map-point>
19+
</map-geometry>
20+
<map-properties>
21+
<h1>A Man With Two Hats</h1>
22+
</map-properties>
23+
</map-feature>
24+
</map-body>
25+
</mapml->

0 commit comments

Comments
 (0)