diff --git a/index.html b/index.html
index c2cd34860..18f6bf4a3 100644
--- a/index.html
+++ b/index.html
@@ -139,7 +139,7 @@
Italian
Mexican
-
+
diff --git a/src/map-link.js b/src/map-link.js
index ed25f4d76..bcc1fa7d6 100644
--- a/src/map-link.js
+++ b/src/map-link.js
@@ -113,10 +113,7 @@ export class HTMLLinkElement extends HTMLElement {
}
}
get media() {
- // return the content of media attribute as an object
- // maybe memoizing the object to avoid repeated formatting
- // the Util function may need to be renamed?
- return Util._metaContentToObject(this.getAttribute('media'));
+ return this.getAttribute('media');
}
set media(val) {
this.setAttribute('media', val);
@@ -237,6 +234,9 @@ export class HTMLLinkElement extends HTMLElement {
}
break;
case 'media':
+ if (oldValue !== newValue) {
+ this._registerMediaQuery(newValue);
+ }
break;
case 'tms':
// rel = tile
@@ -305,6 +305,7 @@ export class HTMLLinkElement extends HTMLElement {
// this._createLicenseLink();
break;
}
+ this._registerMediaQuery(this.media);
// create the type of templated leaflet layer appropriate to the rel value
// image/map/features = templated(Image/Feature), tile=templatedTile,
// this._tempatedTileLayer = Util.templatedTile(pane: this.extentElement._leafletLayer._container)
@@ -354,18 +355,48 @@ export class HTMLLinkElement extends HTMLElement {
break;
}
}
- enableLink() {
+ async enableLink() {
switch (this.rel.toLowerCase()) {
case 'tile':
case 'image':
case 'features':
case 'query':
- case 'stylesheet':
- this.connectedCallback().then(() => {
- // ensures that the layer control is updated, if applicable
+ if (!this.disabled) {
+ this._initTemplateVars();
+ await this._createTemplatedLink();
this.getLayerEl()._validateDisabled();
- });
+ }
break;
+ case 'stylesheet':
+ this._createStylesheetLink();
+ break;
+ }
+ }
+ _registerMediaQuery(mq) {
+ if (!this._changeHandler) {
+ // Define and bind the change handler once
+ this._changeHandler = () => {
+ this.disabled = !this._mql.matches;
+ };
+ }
+
+ if (mq) {
+ let map = this.getMapEl();
+ if (!map) return;
+
+ // Remove listener from the old media query (if it exists)
+ if (this._mql) {
+ this._mql.removeEventListener('change', this._changeHandler);
+ }
+
+ // Set up the new media query and listener
+ this._mql = map.matchMedia(mq);
+ this._changeHandler(); // Initial evaluation
+ this._mql.addEventListener('change', this._changeHandler);
+ } else if (this._mql) {
+ // Clean up the existing listener
+ this._mql.removeEventListener('change', this._changeHandler);
+ delete this._mql;
}
}
_createAlternateLink(mapml) {
diff --git a/test/e2e/elements/map-link/map-link-media.html b/test/e2e/elements/map-link/map-link-media.html
new file mode 100644
index 000000000..7f1b4919e
--- /dev/null
+++ b/test/e2e/elements/map-link/map-link-media.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+ map-link-media.html
+
+
+
+
+
+
+
+
+
+
+
+ All cuisines
+ African
+ Asian
+ Cajun
+ Indian
+ Italian
+ Mexican
+
+
+
+
+
+
+
diff --git a/test/e2e/elements/map-link/map-link-media.test.js b/test/e2e/elements/map-link/map-link-media.test.js
new file mode 100644
index 000000000..ec6ed6be1
--- /dev/null
+++ b/test/e2e/elements/map-link/map-link-media.test.js
@@ -0,0 +1,101 @@
+import { test, expect, chromium } from '@playwright/test';
+
+test.describe('map-link media attribute', () => {
+ let page;
+ let context;
+ test.beforeAll(async function () {
+ context = await chromium.launchPersistentContext('');
+ page =
+ context.pages().find((page) => page.url() === 'about:blank') ||
+ (await context.newPage());
+ await page.goto('map-link-media.html');
+ });
+
+ test.afterAll(async function () {
+ await context.close();
+ });
+
+ test('map-link is disabled when media attribute does not match', async () => {
+ // const map = page.locator('mapml-viewer');
+ const layer = page.locator('map-layer');
+ const mapLink = page.locator('map-link').first();
+ await expect(layer).not.toHaveAttribute('disabled');
+ await expect(mapLink).not.toHaveAttribute('disabled');
+
+ // zoom out so that media attribute no longer matches, features should be disabled
+ await page.evaluate(() => {
+ const map = document.querySelector('mapml-viewer');
+ map.zoomTo(map.lat, map.lon, 10);
+ });
+ await expect(layer).toHaveAttribute('disabled');
+ await expect(mapLink).toHaveAttribute('disabled');
+
+ // zoom in so that media attribute matches, features should not be disabled
+ await page.evaluate(() => {
+ const map = document.querySelector('mapml-viewer');
+ map.zoomTo(map.lat, map.lon, 15);
+ });
+ await expect(layer).not.toHaveAttribute('disabled');
+ await expect(mapLink).not.toHaveAttribute('disabled');
+ });
+
+ test('remove media attribute works', async () => {
+ const layer = page.locator('map-layer');
+ const mapLink = page.locator('map-link').first();
+ await mapLink.evaluate((l) => {
+ l.media = '';
+ });
+
+ // zooming out no longer disables features
+ await page.evaluate(() => {
+ const map = document.querySelector('mapml-viewer');
+ map.zoomTo(map.lat, map.lon, 10);
+ });
+ await expect(layer).not.toHaveAttribute('disabled');
+ await expect(mapLink).not.toHaveAttribute('disabled');
+ });
+
+ test('set media attribute works', async () => {
+ const layer = page.locator('map-layer');
+ const mapLink = page.locator('map-link').first();
+ await mapLink.evaluate((l) => {
+ l.setAttribute('media', '(11 < map-zoom <= 18)');
+ });
+
+ // zoom out so that media attribute no longer matches, features should be disabled
+ await page.evaluate(() => {
+ const map = document.querySelector('mapml-viewer');
+ map.zoomTo(map.lat, map.lon, 10);
+ });
+ await expect(layer).toHaveAttribute('disabled');
+ await expect(mapLink).toHaveAttribute('disabled');
+
+ // zoom in so that media attribute matches, features should not be disabled
+ await page.evaluate(() => {
+ const map = document.querySelector('mapml-viewer');
+ map.zoomTo(map.lat, map.lon, 15);
+ });
+ await expect(layer).not.toHaveAttribute('disabled');
+ await expect(mapLink).not.toHaveAttribute('disabled');
+ });
+
+ test('modify media attribute works', async () => {
+ const layer = page.locator('map-layer');
+ const mapLink = page.locator('map-link').first();
+ await mapLink.evaluate((l) => {
+ l.setAttribute('media', '(15 < map-zoom <= 18)');
+ });
+
+ // the media attribute no longer matches, features should be disabled
+ await expect(layer).toHaveAttribute('disabled');
+ await expect(mapLink).toHaveAttribute('disabled');
+
+ // zoom in so that media attribute matches, features should not be disabled
+ await page.evaluate(() => {
+ const map = document.querySelector('mapml-viewer');
+ map.zoomTo(map.lat, map.lon, 16);
+ });
+ await expect(layer).not.toHaveAttribute('disabled');
+ await expect(mapLink).not.toHaveAttribute('disabled');
+ });
+});