@@ -6,7 +6,7 @@ import { createLayerControlHTML } from './mapml/elementSupport/layers/createLaye
6
6
7
7
export class BaseLayerElement extends HTMLElement {
8
8
static get observedAttributes ( ) {
9
- return [ 'src' , 'label' , 'checked' , 'hidden' , 'opacity' ] ;
9
+ return [ 'src' , 'label' , 'checked' , 'hidden' , 'opacity' , 'media' ] ;
10
10
}
11
11
/* jshint ignore:start */
12
12
#hasConnected;
@@ -53,6 +53,13 @@ export class BaseLayerElement extends HTMLElement {
53
53
}
54
54
}
55
55
56
+ get media ( ) {
57
+ return this . getAttribute ( 'media' ) ;
58
+ }
59
+ set media ( val ) {
60
+ this . setAttribute ( 'media' , val ) ;
61
+ }
62
+
56
63
get opacity ( ) {
57
64
// use ?? since 0 is falsy, || would return rhs in that case
58
65
return + ( this . _opacity ?? this . getAttribute ( 'opacity' ) ) ;
@@ -114,24 +121,73 @@ export class BaseLayerElement extends HTMLElement {
114
121
this . _onAdd ( ) ;
115
122
}
116
123
}
124
+ break ;
125
+ case 'media' :
126
+ if ( oldValue !== newValue ) {
127
+ this . _registerMediaQuery ( newValue ) ;
128
+ }
129
+ break ;
117
130
}
118
131
}
119
132
}
133
+ _registerMediaQuery ( mq ) {
134
+ if ( ! this . _changeHandler ) {
135
+ this . _changeHandler = ( ) => {
136
+ this . _onRemove ( ) ;
137
+ if ( this . _mql . matches ) {
138
+ this . _onAdd ( ) ;
139
+ }
140
+ // set the disabled 'read-only' attribute indirectly, via _validateDisabled
141
+ this . _validateDisabled ( ) ;
142
+ } ;
143
+ }
144
+
145
+ if ( mq ) {
146
+ // a new media query is being established
147
+ let map = this . getMapEl ( ) ;
148
+ if ( ! map ) return ;
120
149
150
+ // Remove listener from the old media query (if it exists)
151
+ if ( this . _mql ) {
152
+ this . _mql . removeEventListener ( 'change' , this . _changeHandler ) ;
153
+ }
154
+
155
+ this . _mql = map . matchMedia ( mq ) ;
156
+ this . _changeHandler ( ) ;
157
+ this . _mql . addEventListener ( 'change' , this . _changeHandler ) ;
158
+ } else if ( this . _mql ) {
159
+ // the media attribute removed or query set to ''
160
+ this . _mql . removeEventListener ( 'change' , this . _changeHandler ) ;
161
+ delete this . _mql ;
162
+ // effectively, no / empty media attribute matches, do what changeHandler does
163
+ this . _onRemove ( ) ;
164
+ this . _onAdd ( ) ;
165
+ this . _validateDisabled ( ) ;
166
+ }
167
+ }
168
+ getMapEl ( ) {
169
+ return Util . getClosest ( this , 'mapml-viewer,map[is=web-map]' ) ;
170
+ }
121
171
constructor ( ) {
122
172
// Always call super first in constructor
123
173
super ( ) ;
124
174
// this._opacity is used to record the current opacity value (with or without updates),
125
175
// the initial value of this._opacity should be set as opacity attribute value, if exists, or the default value 1.0
126
176
this . _opacity = this . opacity || 1.0 ;
127
- this . _renderingMapContent = M . options . contentPreference ;
128
177
this . attachShadow ( { mode : 'open' } ) ;
129
178
}
130
179
disconnectedCallback ( ) {
131
180
// if the map-layer node is removed from the dom, the layer should be
132
181
// removed from the map and the layer control
133
182
if ( this . hasAttribute ( 'data-moving' ) ) return ;
134
183
this . _onRemove ( ) ;
184
+
185
+ if ( this . _mql ) {
186
+ if ( this . _changeHandler ) {
187
+ this . _mql . removeEventListener ( 'change' , this . _changeHandler ) ;
188
+ }
189
+ delete this . _mql ;
190
+ }
135
191
}
136
192
137
193
_onRemove ( ) {
@@ -141,13 +197,6 @@ export class BaseLayerElement extends HTMLElement {
141
197
let l = this . _layer ,
142
198
lc = this . _layerControl ,
143
199
lchtml = this . _layerControlHTML ;
144
- // remove properties of layer involved in whenReady() logic
145
- delete this . _layer ;
146
- delete this . _layerControl ;
147
- delete this . _layerControlHTML ;
148
- delete this . _fetchError ;
149
- this . shadowRoot . innerHTML = '' ;
150
- if ( this . src ) this . innerHTML = '' ;
151
200
152
201
if ( l ) {
153
202
l . off ( ) ;
@@ -158,8 +207,16 @@ export class BaseLayerElement extends HTMLElement {
158
207
}
159
208
160
209
if ( lc && ! this . hidden ) {
210
+ // lc.removeLayer depends on this._layerControlHTML, can't delete it until after
161
211
lc . removeLayer ( l ) ;
162
212
}
213
+ // remove properties of layer involved in whenReady() logic
214
+ delete this . _layer ;
215
+ delete this . _layerControl ;
216
+ delete this . _layerControlHTML ;
217
+ delete this . _fetchError ;
218
+ this . shadowRoot . innerHTML = '' ;
219
+ if ( this . src ) this . innerHTML = '' ;
163
220
}
164
221
165
222
connectedCallback ( ) {
@@ -170,11 +227,17 @@ export class BaseLayerElement extends HTMLElement {
170
227
this . _createLayerControlHTML = createLayerControlHTML . bind ( this ) ;
171
228
const doConnected = this . _onAdd . bind ( this ) ;
172
229
const doRemove = this . _onRemove . bind ( this ) ;
230
+ const registerMediaQuery = this . _registerMediaQuery . bind ( this ) ;
231
+ let mq = this . media ;
173
232
this . parentElement
174
233
. whenReady ( )
175
234
. then ( ( ) => {
176
235
doRemove ( ) ;
177
- doConnected ( ) ;
236
+ if ( mq ) {
237
+ registerMediaQuery ( mq ) ;
238
+ } else {
239
+ doConnected ( ) ;
240
+ }
178
241
} )
179
242
. catch ( ( error ) => {
180
243
throw new Error ( 'Map never became ready: ' + error ) ;
@@ -189,20 +252,11 @@ export class BaseLayerElement extends HTMLElement {
189
252
e . stopPropagation ( ) ;
190
253
// if user changes the style in layer control
191
254
if ( e . detail ) {
192
- this . _renderingMapContent = e . detail . _renderingMapContent ;
193
255
this . src = e . detail . src ;
194
256
}
195
257
} ,
196
258
{ once : true }
197
259
) ;
198
- this . addEventListener (
199
- 'zoomchangesrc' ,
200
- function ( e ) {
201
- e . stopPropagation ( ) ;
202
- this . src = e . detail . href ;
203
- } ,
204
- { once : true }
205
- ) ;
206
260
let base = this . baseURI ? this . baseURI : document . baseURI ;
207
261
const headers = new Headers ( ) ;
208
262
headers . append ( 'Accept' , 'text/mapml' ) ;
@@ -240,7 +294,6 @@ export class BaseLayerElement extends HTMLElement {
240
294
. then ( ( ) => {
241
295
// may throw:
242
296
this . selectAlternateOrChangeProjection ( ) ;
243
- this . checkForPreferredContent ( ) ;
244
297
} )
245
298
. then ( ( ) => {
246
299
this . _layer = mapMLLayer ( new URL ( this . src , base ) . href , this , {
@@ -278,7 +331,6 @@ export class BaseLayerElement extends HTMLElement {
278
331
. then ( ( ) => {
279
332
// may throw:
280
333
this . selectAlternateOrChangeProjection ( ) ;
281
- this . checkForPreferredContent ( ) ;
282
334
} )
283
335
. then ( ( ) => {
284
336
this . _layer = mapMLLayer ( null , this , {
@@ -317,13 +369,6 @@ export class BaseLayerElement extends HTMLElement {
317
369
) ;
318
370
this . parentElement . projection = e . cause . mapprojection ;
319
371
}
320
- } else if ( e . message === 'findmatchingpreferredcontent' ) {
321
- if ( e . cause . href ) {
322
- console . log (
323
- 'Changing layer to matching preferred content at: ' + e . cause . href
324
- ) ;
325
- this . src = e . cause . href ;
326
- }
327
372
} else if ( e . message === 'Failed to fetch' ) {
328
373
// cut short whenReady with the _fetchError property
329
374
this . _fetchError = true ;
@@ -372,23 +417,6 @@ export class BaseLayerElement extends HTMLElement {
372
417
}
373
418
}
374
419
375
- checkForPreferredContent ( ) {
376
- let mapml = this . src ? this . shadowRoot : this ;
377
- let availablePreferMapContents = mapml . querySelector (
378
- `map-link[rel="style"][media="prefers-map-content=${ this . _renderingMapContent } "][href]`
379
- ) ;
380
- if ( availablePreferMapContents ) {
381
- // resolve href
382
- let url = new URL (
383
- availablePreferMapContents . getAttribute ( 'href' ) ,
384
- availablePreferMapContents . getBase ( )
385
- ) . href ;
386
- throw new Error ( 'findmatchingpreferredcontent' , {
387
- cause : { href : url }
388
- } ) ;
389
- }
390
- }
391
-
392
420
copyRemoteContentToShadowRoot ( mapml ) {
393
421
let shadowRoot = this . shadowRoot ;
394
422
// get the map-meta[name=projection/cs/extent/zoom] from map-head of remote mapml, attach them to the shadowroot
@@ -610,8 +638,13 @@ export class BaseLayerElement extends HTMLElement {
610
638
setTimeout ( ( ) => {
611
639
let layer = this . _layer ,
612
640
map = layer ?. _map ;
641
+ // if there's a media query in play, check it early
642
+ if ( this . _mql && ! this . _mql . matches ) {
643
+ this . setAttribute ( 'disabled' , '' ) ;
644
+ this . disabled = true ;
645
+ return ;
646
+ }
613
647
if ( map ) {
614
- this . _validateLayerZoom ( { zoom : map . getZoom ( ) } ) ;
615
648
// prerequisite: no inline and remote mapml elements exists at the same time
616
649
const mapExtents = this . src
617
650
? this . shadowRoot . querySelectorAll ( 'map-extent' )
@@ -664,35 +697,6 @@ export class BaseLayerElement extends HTMLElement {
664
697
}
665
698
} , 0 ) ;
666
699
}
667
- _validateLayerZoom ( e ) {
668
- // get the min and max zooms from all extents
669
- let toZoom = e . zoom ;
670
- let min = this . extent . zoom . minZoom ;
671
- let max = this . extent . zoom . maxZoom ;
672
- let inLink = this . src
673
- ? this . shadowRoot . querySelector ( 'map-link[rel=zoomin]' )
674
- : this . querySelector ( 'map-link[rel=zoomin]' ) ,
675
- outLink = this . src
676
- ? this . shadowRoot . querySelector ( 'map-link[rel=zoomout]' )
677
- : this . querySelector ( 'map-link[rel=zoomout]' ) ;
678
- let targetURL ;
679
- if ( ! ( min <= toZoom && toZoom <= max ) ) {
680
- if ( inLink && toZoom > max ) {
681
- targetURL = inLink . href ;
682
- } else if ( outLink && toZoom < min ) {
683
- targetURL = outLink . href ;
684
- }
685
- if ( targetURL ) {
686
- this . dispatchEvent (
687
- new CustomEvent ( 'zoomchangesrc' , {
688
- detail : {
689
- href : targetURL
690
- }
691
- } )
692
- ) ;
693
- }
694
- }
695
- }
696
700
// disable/italicize layer control elements based on the map-layer.disabled property
697
701
toggleLayerControlDisabled ( ) {
698
702
let input = this . _layerControlCheckbox ,
0 commit comments