Skip to content

Commit 1aa7394

Browse files
committed
Update implementation of map-link and map-style rendering to take
media attribute into account. Update map-style-media.test
1 parent 6f061a0 commit 1aa7394

17 files changed

+186
-89
lines changed

src/layer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,12 @@ export class BaseLayerElement extends HTMLElement {
482482
};
483483
const _addStylesheetLink = (mapLink) => {
484484
this.whenReady().then(() => {
485-
this._layer.appendStyleLink(mapLink);
485+
this._layer.renderStyles(mapLink);
486486
});
487487
};
488488
const _addStyleElement = (mapStyle) => {
489489
this.whenReady().then(() => {
490-
this._layer.appendStyleElement(mapStyle);
490+
this._layer.renderStyles(mapStyle);
491491
});
492492
};
493493
const _addExtentElement = (mapExtent) => {

src/map-extent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,12 @@ export class HTMLExtentElement extends HTMLElement {
311311
};
312312
const _addStylesheetLink = (mapLink) => {
313313
this.whenReady().then(() => {
314-
this._extentLayer.appendStyleLink(mapLink);
314+
this._extentLayer.renderStyles(mapLink);
315315
});
316316
};
317317
const _addStyleElement = (mapStyle) => {
318318
this.whenReady().then(() => {
319-
this._extentLayer.appendStyleElement(mapStyle);
319+
this._extentLayer.renderStyles(mapStyle);
320320
});
321321
};
322322
for (let i = 0; i < elementsGroup.length; ++i) {

src/map-link.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,11 @@ export class HTMLLinkElement extends HTMLElement {
452452
copyAttributes(this, this.link);
453453

454454
if (this._stylesheetHost._layer) {
455-
this._stylesheetHost._layer.appendStyleLink(this);
455+
this._stylesheetHost._layer.renderStyles(this);
456456
} else if (this._stylesheetHost._templatedLayer) {
457-
this._stylesheetHost._templatedLayer.appendStyleLink(this);
457+
this._stylesheetHost._templatedLayer.renderStyles(this);
458458
} else if (this._stylesheetHost._extentLayer) {
459-
this._stylesheetHost._extentLayer.appendStyleLink(this);
459+
this._stylesheetHost._extentLayer.renderStyles(this);
460460
}
461461
}
462462

src/map-style.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ export class HTMLStyleElement extends HTMLElement {
7171
this.styleElement.textContent = this.textContent;
7272
copyAttributes(this, this.styleElement);
7373
if (this._stylesheetHost._layer) {
74-
this._stylesheetHost._layer.appendStyleElement(this);
74+
this._stylesheetHost._layer.renderStyles(this);
7575
} else if (this._stylesheetHost._templatedLayer) {
76-
this._stylesheetHost._templatedLayer.appendStyleElement(this);
76+
this._stylesheetHost._templatedLayer.renderStyles(this);
7777
} else if (this._stylesheetHost._extentLayer) {
78-
this._stylesheetHost._extentLayer.appendStyleElement(this);
78+
this._stylesheetHost._extentLayer.renderStyles(this);
7979
}
8080

8181
function copyAttributes(source, target) {

src/mapml/layers/ExtentLayer.js

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,30 +82,57 @@ export var ExtentLayer = LayerGroup.extend({
8282
if (this._extentEl._opacitySlider)
8383
this._extentEl._opacitySlider.value = opacity;
8484
},
85-
appendStyleLink: function (mapLink) {
86-
if (!mapLink.link) return;
87-
let positionAndNode = this._getStylePositionAndNode();
88-
positionAndNode.node.insertAdjacentElement(
89-
positionAndNode.position,
90-
mapLink.link
91-
);
92-
},
93-
_getStylePositionAndNode: function () {
94-
return this._container.lastChild &&
95-
(this._container.lastChild.nodeName.toUpperCase() === 'SVG' ||
96-
this._container.lastChild.classList.contains('mapml-vector-container'))
97-
? { position: 'beforebegin', node: this._container.lastChild }
98-
: this._container.lastChild
99-
? { position: 'afterend', node: this._container.lastChild }
100-
: { position: 'afterbegin', node: this._container };
101-
},
102-
appendStyleElement: function (mapStyle) {
103-
if (!mapStyle.styleElement) return;
104-
let positionAndNode = this._getStylePositionAndNode();
105-
positionAndNode.node.insertAdjacentElement(
106-
positionAndNode.position,
107-
mapStyle.styleElement
108-
);
85+
renderStyles: function (mapStyleOrLink) {
86+
let e = mapStyleOrLink.link || mapStyleOrLink.styleElement;
87+
if (e === undefined) return;
88+
89+
const getStylePositionAndNode = (styleOrLink) => {
90+
// Get all already rendered <style> or <link> elements in the shadow DOM container
91+
const renderedSiblingStyles = Array.from(
92+
this._container.querySelectorAll('style, link[rel="stylesheet"]')
93+
);
94+
95+
// If there are no rendered styles or links yet, insert before any content
96+
if (renderedSiblingStyles.length === 0) {
97+
return this._container.lastChild &&
98+
(this._container.lastChild.nodeName.toUpperCase() === 'SVG' ||
99+
this._container.lastChild.classList.contains(
100+
'mapml-vector-container'
101+
))
102+
? { position: 'beforebegin', node: this._container.lastChild }
103+
: this._container.lastChild
104+
? { position: 'afterend', node: this._container.lastChild }
105+
: { position: 'afterbegin', node: this._container };
106+
}
107+
108+
// Peek into the light DOM context for comparison
109+
const mapStyleOrLinkLightDOMElement =
110+
styleOrLink.mapStyle || styleOrLink.mapLink;
111+
112+
// Traverse the rendered siblings in the shadow DOM
113+
for (let i = 0; i < renderedSiblingStyles.length; i++) {
114+
const rendered = renderedSiblingStyles[i];
115+
const siblingMapStyleOrLinkLightDOMElement =
116+
rendered.mapStyle || rendered.mapLink;
117+
118+
// Compare the light DOM order
119+
if (
120+
siblingMapStyleOrLinkLightDOMElement &&
121+
mapStyleOrLinkLightDOMElement.compareDocumentPosition(
122+
siblingMapStyleOrLinkLightDOMElement
123+
) & Node.DOCUMENT_POSITION_FOLLOWING
124+
) {
125+
// Insert the new style or link before the already-rendered sibling element
126+
return { position: 'beforebegin', node: rendered };
127+
}
128+
}
129+
130+
// If no preceding sibling was found, insert after the last rendered element
131+
return { position: 'afterend', node: renderedSiblingStyles.at(-1) };
132+
};
133+
134+
let positionAndNode = getStylePositionAndNode(e);
135+
positionAndNode.node.insertAdjacentElement(positionAndNode.position, e);
109136
}
110137
});
111138
export var extentLayer = function (options) {

src/mapml/layers/MapMLLayer.js

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -248,30 +248,57 @@ export var MapMLLayer = LayerGroup.extend({
248248
this._href
249249
).href;
250250
},
251-
appendStyleLink: function (mapLink) {
252-
if (!mapLink.link) return;
253-
let positionAndNode = this._getStylePositionAndNode();
254-
positionAndNode.node.insertAdjacentElement(
255-
positionAndNode.position,
256-
mapLink.link
257-
);
258-
},
259-
_getStylePositionAndNode: function () {
260-
return this._container.lastChild &&
261-
(this._container.lastChild.nodeName.toUpperCase() === 'SVG' ||
262-
this._container.lastChild.classList.contains('mapml-vector-container'))
263-
? { position: 'beforebegin', node: this._container.lastChild }
264-
: this._container.lastChild
265-
? { position: 'afterend', node: this._container.lastChild }
266-
: { position: 'afterbegin', node: this._container };
267-
},
268-
appendStyleElement: function (mapStyle) {
269-
if (!mapStyle.styleElement) return;
270-
let positionAndNode = this._getStylePositionAndNode();
271-
positionAndNode.node.insertAdjacentElement(
272-
positionAndNode.position,
273-
mapStyle.styleElement
274-
);
251+
renderStyles: function (mapStyleOrLink) {
252+
let e = mapStyleOrLink.link || mapStyleOrLink.styleElement;
253+
if (e === undefined) return;
254+
255+
const getStylePositionAndNode = (styleOrLink) => {
256+
// Get all already rendered <style> or <link> elements in the shadow DOM container
257+
const renderedSiblingStyles = Array.from(
258+
this._container.querySelectorAll('style, link[rel="stylesheet"]')
259+
);
260+
261+
// If there are no rendered styles or links yet, insert before any content
262+
if (renderedSiblingStyles.length === 0) {
263+
return this._container.lastChild &&
264+
(this._container.lastChild.nodeName.toUpperCase() === 'SVG' ||
265+
this._container.lastChild.classList.contains(
266+
'mapml-vector-container'
267+
))
268+
? { position: 'beforebegin', node: this._container.lastChild }
269+
: this._container.lastChild
270+
? { position: 'afterend', node: this._container.lastChild }
271+
: { position: 'afterbegin', node: this._container };
272+
}
273+
274+
// Peek into the light DOM context for comparison
275+
const mapStyleOrLinkLightDOMElement =
276+
styleOrLink.mapStyle || styleOrLink.mapLink;
277+
278+
// Traverse the rendered siblings in the shadow DOM
279+
for (let i = 0; i < renderedSiblingStyles.length; i++) {
280+
const rendered = renderedSiblingStyles[i];
281+
const siblingMapStyleOrLinkLightDOMElement =
282+
rendered.mapStyle || rendered.mapLink;
283+
284+
// Compare the light DOM order
285+
if (
286+
siblingMapStyleOrLinkLightDOMElement &&
287+
mapStyleOrLinkLightDOMElement.compareDocumentPosition(
288+
siblingMapStyleOrLinkLightDOMElement
289+
) & Node.DOCUMENT_POSITION_FOLLOWING
290+
) {
291+
// Insert the new style or link before the already-rendered sibling element
292+
return { position: 'beforebegin', node: rendered };
293+
}
294+
}
295+
296+
// If no preceding sibling was found, insert after the last rendered element
297+
return { position: 'afterend', node: renderedSiblingStyles.at(-1) };
298+
};
299+
300+
let positionAndNode = getStylePositionAndNode(e);
301+
positionAndNode.node.insertAdjacentElement(positionAndNode.position, e);
275302
},
276303
_initialize: function () {
277304
var layer = this;

src/mapml/layers/TemplatedFeaturesLayer.js

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,31 +95,59 @@ export var TemplatedFeaturesLayer = Layer.extend({
9595
if (this._features) this._features.eachLayer((layer) => layer.remove());
9696
DomUtil.remove(this._container);
9797
},
98-
appendStyleLink: function (mapLink) {
99-
if (!mapLink.link) return;
100-
let positionAndNode = this._getStylePositionAndNode();
101-
positionAndNode.node.insertAdjacentElement(
102-
positionAndNode.position,
103-
mapLink.link
104-
);
105-
},
106-
_getStylePositionAndNode: function () {
107-
return this._container.lastChild &&
108-
(this._container.lastChild.nodeName.toUpperCase() === 'SVG' ||
109-
this._container.lastChild.classList.contains('mapml-vector-container'))
110-
? { position: 'beforebegin', node: this._container.lastChild }
111-
: this._container.lastChild
112-
? { position: 'afterend', node: this._container.lastChild }
113-
: { position: 'afterbegin', node: this._container };
114-
},
115-
appendStyleElement: function (mapStyle) {
116-
if (!mapStyle.styleElement) return;
117-
let positionAndNode = this._getStylePositionAndNode();
118-
positionAndNode.node.insertAdjacentElement(
119-
positionAndNode.position,
120-
mapStyle.styleElement
121-
);
98+
renderStyles: function (mapStyleOrLink) {
99+
let e = mapStyleOrLink.link || mapStyleOrLink.styleElement;
100+
if (e === undefined) return;
101+
102+
const getStylePositionAndNode = (styleOrLink) => {
103+
// Get all already rendered <style> or <link> elements in the shadow DOM container
104+
const renderedSiblingStyles = Array.from(
105+
this._container.querySelectorAll('style, link[rel="stylesheet"]')
106+
);
107+
108+
// If there are no rendered styles or links yet, insert before any content
109+
if (renderedSiblingStyles.length === 0) {
110+
return this._container.lastChild &&
111+
(this._container.lastChild.nodeName.toUpperCase() === 'SVG' ||
112+
this._container.lastChild.classList.contains(
113+
'mapml-vector-container'
114+
))
115+
? { position: 'beforebegin', node: this._container.lastChild }
116+
: this._container.lastChild
117+
? { position: 'afterend', node: this._container.lastChild }
118+
: { position: 'afterbegin', node: this._container };
119+
}
120+
121+
// Peek into the light DOM context for comparison
122+
const mapStyleOrLinkLightDOMElement =
123+
styleOrLink.mapStyle || styleOrLink.mapLink;
124+
125+
// Traverse the rendered siblings in the shadow DOM
126+
for (let i = 0; i < renderedSiblingStyles.length; i++) {
127+
const rendered = renderedSiblingStyles[i];
128+
const siblingMapStyleOrLinkLightDOMElement =
129+
rendered.mapStyle || rendered.mapLink;
130+
131+
// Compare the light DOM order
132+
if (
133+
siblingMapStyleOrLinkLightDOMElement &&
134+
mapStyleOrLinkLightDOMElement.compareDocumentPosition(
135+
siblingMapStyleOrLinkLightDOMElement
136+
) & Node.DOCUMENT_POSITION_FOLLOWING
137+
) {
138+
// Insert the new style or link before the already-rendered sibling element
139+
return { position: 'beforebegin', node: rendered };
140+
}
141+
}
142+
143+
// If no preceding sibling was found, insert after the last rendered element
144+
return { position: 'afterend', node: renderedSiblingStyles.at(-1) };
145+
};
146+
147+
let positionAndNode = getStylePositionAndNode(e);
148+
positionAndNode.node.insertAdjacentElement(positionAndNode.position, e);
122149
},
150+
123151
redraw: function () {
124152
this._onMoveEnd();
125153
},

test/e2e/elements/map-style/map-style-media.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,12 @@
3030
<map-layer data-testid="restaurants" label="Restaurants" checked="">
3131
<map-meta name="extent" content="top-left-easting=-8433179, top-left-northing=5689316, bottom-right-easting=-8420968, bottom-right-northing=5683139"></map-meta>
3232
<map-extent units="OSMTILE" checked="">
33-
<!-- markers should be red on load -->
3433
<map-style>.restaurant {fill: red; stroke: red;}</map-style>
34+
<!-- markers should be orange on load -->
35+
<!-- markers should go red on zoomend -->
36+
<map-style media="(map-zoom: 14)">.restaurant {fill: orange; stroke: orange}</map-style>
37+
<!-- markers should turn purple when media query below is removed -->
38+
<map-style data-testid="invalid-mq" media="invalid query">.restaurant {fill: purple; stroke: purple}</map-style>
3539
<map-select id="restaurants" name="cusine">
3640
<map-option value="restaurants" selected="selected">All cuisines</map-option>
3741
<map-option value="african">African</map-option>

test/e2e/elements/map-style/map-style-media.test.js

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,36 @@ test.describe('map-style media attribute', () => {
1313
await page.goto('map-style-media.html');
1414
await page.waitForTimeout(1000);
1515
viewer = page.getByTestId('viewer');
16-
stylesheet = page.locator('map-style');
16+
stylesheet = page.locator('map-style[data-testid="invalid-mq"]');
1717
});
1818
test(`when a map-style disables due to a media query, the styles\
1919
should be removed`, async () => {
20-
// map starts off at
21-
await expect(viewer).toHaveScreenshot('red_styled_markers.png', {
20+
// map starts off with orange markers
21+
await expect(viewer).toHaveScreenshot('orange_styled_markers.png', {
2222
maxDiffPixels: 20
2323
});
24-
await stylesheet.evaluate((l) => (l.media = '(14 < map-zoom <= 18)'));
24+
await viewer.evaluate((v)=> v.zoomTo(v.lat,v.lon, (v.zoom - 1)));
2525
await page.waitForTimeout(500);
26-
await expect(viewer).toHaveScreenshot('default_styled_markers.png', {
26+
await expect(viewer).toHaveScreenshot('red_styled_markers.png', {
2727
maxDiffPixels: 20
2828
});
2929
});
3030
test(`when a map-style enables due to a mq being removed, the \
3131
styles should apply`, async () => {
32+
3233
await stylesheet.evaluate((l) => l.removeAttribute('media'));
33-
await expect(viewer).toHaveScreenshot('red_styled_markers.png', {
34+
await page.waitForTimeout(500);
35+
await expect(viewer).toHaveScreenshot('purple_styled_markers.png', {
3436
maxDiffPixels: 20
3537
});
3638
});
3739
});
40+
41+
// when a map-style loads with a matching media query, the styles apply
42+
// when a map-style loads without a media query, the styles apply
43+
// when a map-style loads with a non-matching media query, the styles do not apply
44+
// map-style disabled due to setting of non-matching media query
45+
// map-style enables when non-matching media query is updated to be matching
46+
// map-style disabled due to update of matching to invalid mq
47+
// map-style enables due to removal of invalid mq
48+
//

0 commit comments

Comments
 (0)