@@ -25,7 +25,8 @@ export class HTMLLinkElement extends HTMLElement {
2525 'hreflang' ,
2626 'tref' ,
2727 'tms' ,
28- 'projection'
28+ 'projection' ,
29+ 'disabled'
2930 ] ;
3031 }
3132 /* jshint ignore:start */
@@ -174,6 +175,16 @@ export class HTMLLinkElement extends HTMLElement {
174175 getLayerEl ( ) {
175176 return Util . getClosest ( this , 'map-layer,layer-' ) ;
176177 }
178+ get disabled ( ) {
179+ return this . hasAttribute ( 'disabled' ) ;
180+ }
181+ set disabled ( val ) {
182+ if ( val ) {
183+ this . setAttribute ( 'disabled' , '' ) ;
184+ } else {
185+ this . removeAttribute ( 'disabled' ) ;
186+ }
187+ }
177188
178189 attributeChangedCallback ( name , oldValue , newValue ) {
179190 //['type','rel','href','hreflang','tref','tms','projection'];
@@ -239,14 +250,21 @@ export class HTMLLinkElement extends HTMLElement {
239250 // handle side effects
240251 }
241252 break ;
253+ case 'disabled' :
254+ if ( typeof newValue === 'string' ) {
255+ this . disableLink ( ) ;
256+ } else {
257+ this . enableLink ( ) ;
258+ }
259+ break ;
242260 }
243261 }
244262 }
245263 constructor ( ) {
246264 // Always call super first in constructor
247265 super ( ) ;
248266 }
249- connectedCallback ( ) {
267+ async connectedCallback ( ) {
250268 this . #hasConnected = true ; /* jshint ignore:line */
251269 if (
252270 this . getLayerEl ( ) . hasAttribute ( 'data-moving' ) ||
@@ -259,8 +277,10 @@ export class HTMLLinkElement extends HTMLElement {
259277 case 'image' :
260278 case 'features' :
261279 case 'query' :
262- this . _initTemplateVars ( ) ;
263- this . _createTemplatedLink ( ) ;
280+ if ( ! this . disabled ) {
281+ this . _initTemplateVars ( ) ;
282+ await this . _createTemplatedLink ( ) ;
283+ }
264284 break ;
265285 case 'style' :
266286 case 'self' :
@@ -276,25 +296,7 @@ export class HTMLLinkElement extends HTMLElement {
276296 //this._createLegendLink();
277297 break ;
278298 case 'stylesheet' :
279- // MIME type application/pmtiles+stylesheet is an invention of the requirement to get
280- // closer to loading style rules as CSS does, via link / (map-link)
281- // we could probably do something similar with map-style i.e. treat the
282- // content of map-style as though it was a stylesheet tbd caveat CSP
283- if ( this . type === 'application/pmtiles+stylesheet' ) {
284- const pmtilesStyles = new URL ( this . href , this . getBase ( ) ) . href ;
285- import ( pmtilesStyles )
286- . then ( ( module ) => module . pmtilesRulesReady )
287- . then ( ( initializedRules ) => {
288- this . _pmtilesRules = initializedRules ;
289- } )
290- . catch ( ( reason ) => {
291- console . error (
292- 'Error importing pmtiles symbolizer rules or theme: \n' + reason
293- ) ;
294- } ) ;
295- } else {
296- this . _createStylesheetLink ( ) ;
297- }
299+ this . _createStylesheetLink ( ) ;
298300 break ;
299301 case 'alternate' :
300302 this . _createAlternateLink ( ) ; // add media attribute
@@ -320,35 +322,100 @@ export class HTMLLinkElement extends HTMLElement {
320322 break ;
321323 }
322324 }
325+ disableLink ( ) {
326+ switch ( this . rel . toLowerCase ( ) ) {
327+ case 'tile' :
328+ case 'image' :
329+ case 'features' :
330+ // tile, image, features
331+ if (
332+ this . _templatedLayer &&
333+ this . parentExtent ?. _extentLayer ?. hasLayer ( this . _templatedLayer )
334+ ) {
335+ this . parentExtent . _extentLayer . removeLayer ( this . _templatedLayer ) ;
336+ delete this . _templatedLayer ;
337+ this . getLayerEl ( ) . _validateDisabled ( ) ;
338+ }
339+ break ;
340+ case 'query' :
341+ delete this . _templateVars ;
342+ if ( this . shadowRoot ) {
343+ this . shadowRoot . innerHTML = '' ;
344+ }
345+ this . getLayerEl ( ) . _validateDisabled ( ) ;
346+ break ;
347+ case 'stylesheet' :
348+ delete this . _pmtilesRules ;
349+ delete this . _stylesheetHost ;
350+ if ( this . link ) {
351+ this . link . remove ( ) ;
352+ delete this . link ;
353+ }
354+ break ;
355+ }
356+ }
357+ enableLink ( ) {
358+ switch ( this . rel . toLowerCase ( ) ) {
359+ case 'tile' :
360+ case 'image' :
361+ case 'features' :
362+ case 'query' :
363+ case 'stylesheet' :
364+ this . connectedCallback ( ) . then ( ( ) => {
365+ // ensures that the layer control is updated, if applicable
366+ this . getLayerEl ( ) . _validateDisabled ( ) ;
367+ } ) ;
368+ break ;
369+ }
370+ }
323371 _createAlternateLink ( mapml ) {
324372 if ( this . href && this . projection ) this . _alternate = true ;
325373 }
326374 _createStylesheetLink ( ) {
327- // if the parent element is a map-link, the stylesheet is a link that should
328- // be loaded as part of a templated layer processing i.e. on moveend
329- // and the generated <link> that implements this <map-link> should be located
330- // in the parent <map-link>._templatedLayer.container root node if
331- // the _templatedLayer is an instance of TemplatedTileLayer or TemplatedFeaturesLayer
332- //
333- // if the parent node (or the host of the shadow root parent node) is map-layer, the link should be created in the _layer
334- // container
335- this . _stylesheetHost =
336- this . getRootNode ( ) instanceof ShadowRoot
337- ? this . getRootNode ( ) . host
338- : this . parentElement ;
339- if ( this . _stylesheetHost === undefined ) return ;
375+ // MIME type application/pmtiles+stylesheet is an invention of the requirement to get
376+ // closer to loading style rules as CSS does, via link / (map-link)
377+ // we could probably do something similar with map-style i.e. treat the
378+ // content of map-style as though it was a stylesheet tbd caveat CSP
379+ if ( this . type === 'application/pmtiles+stylesheet' ) {
380+ const pmtilesStyles = new URL ( this . href , this . getBase ( ) ) . href ;
381+ import ( pmtilesStyles )
382+ . then ( ( module ) => module . pmtilesRulesReady )
383+ . then ( ( initializedRules ) => {
384+ this . _pmtilesRules = initializedRules ;
385+ } )
386+ . catch ( ( reason ) => {
387+ console . error (
388+ 'Error importing pmtiles symbolizer rules or theme: \n' + reason
389+ ) ;
390+ } ) ;
391+ } else {
392+ // a CSS stylesheet
393+ // if the parent element is a map-link, the stylesheet is a link that should
394+ // be loaded as part of a templated layer processing i.e. on moveend
395+ // and the generated <link> that implements this <map-link> should be located
396+ // in the parent <map-link>._templatedLayer.container root node if
397+ // the _templatedLayer is an instance of TemplatedTileLayer or TemplatedFeaturesLayer
398+ //
399+ // if the parent node (or the host of the shadow root parent node) is map-layer, the link should be created in the _layer
400+ // container
401+ this . _stylesheetHost =
402+ this . getRootNode ( ) instanceof ShadowRoot
403+ ? this . getRootNode ( ) . host
404+ : this . parentElement ;
405+ if ( this . _stylesheetHost === undefined ) return ;
340406
341- this . link = document . createElement ( 'link' ) ;
342- this . link . mapLink = this ;
343- this . link . setAttribute ( 'href' , new URL ( this . href , this . getBase ( ) ) . href ) ;
344- copyAttributes ( this , this . link ) ;
407+ this . link = document . createElement ( 'link' ) ;
408+ this . link . mapLink = this ;
409+ this . link . setAttribute ( 'href' , new URL ( this . href , this . getBase ( ) ) . href ) ;
410+ copyAttributes ( this , this . link ) ;
345411
346- if ( this . _stylesheetHost . _layer ) {
347- this . _stylesheetHost . _layer . appendStyleLink ( this ) ;
348- } else if ( this . _stylesheetHost . _templatedLayer ) {
349- this . _stylesheetHost . _templatedLayer . appendStyleLink ( this ) ;
350- } else if ( this . _stylesheetHost . _extentLayer ) {
351- this . _stylesheetHost . _extentLayer . appendStyleLink ( this ) ;
412+ if ( this . _stylesheetHost . _layer ) {
413+ this . _stylesheetHost . _layer . appendStyleLink ( this ) ;
414+ } else if ( this . _stylesheetHost . _templatedLayer ) {
415+ this . _stylesheetHost . _templatedLayer . appendStyleLink ( this ) ;
416+ } else if ( this . _stylesheetHost . _extentLayer ) {
417+ this . _stylesheetHost . _extentLayer . appendStyleLink ( this ) ;
418+ }
352419 }
353420
354421 function copyAttributes ( source , target ) {
@@ -366,7 +433,7 @@ export class HTMLLinkElement extends HTMLElement {
366433 this . parentNode . nodeName . toUpperCase ( ) === 'MAP-EXTENT'
367434 ? this . parentNode
368435 : this . parentNode . host ;
369- if ( ! this . tref || ! this . parentExtent ) return ;
436+ if ( this . disabled || ! this . tref || ! this . parentExtent ) return ;
370437 try {
371438 await this . parentExtent . whenReady ( ) ;
372439 await this . _templateVars . inputsReady ;
@@ -386,7 +453,7 @@ export class HTMLLinkElement extends HTMLElement {
386453 this . type === 'application/vnd.mapbox-vector-tile'
387454 ) {
388455 let s =
389- 'map-link[rel="stylesheet"][type="application/pmtiles+stylesheet"]' ;
456+ 'map-link[rel="stylesheet"][type="application/pmtiles+stylesheet"]:not([disabled]) ' ;
390457 let pmtilesStylesheetLink = this . getLayerEl ( ) . src
391458 ? this . closest ( 'map-extent' ) ?. querySelector ( s ) ??
392459 this . getRootNode ( ) . querySelector ( ':host > ' + s )
@@ -439,7 +506,9 @@ export class HTMLLinkElement extends HTMLElement {
439506 } ) . addTo ( this . parentExtent . _extentLayer ) ;
440507 } else if ( this . rel === 'features' ) {
441508 // map-feature retrieved by link will be stored in shadowRoot owned by link
442- this . attachShadow ( { mode : 'open' } ) ;
509+ if ( ! this . shadowRoot ) {
510+ this . attachShadow ( { mode : 'open' } ) ;
511+ }
443512 this . _templatedLayer = templatedFeaturesLayer ( this . _templateVars , {
444513 zoomBounds : this . getZoomBounds ( ) ,
445514 extentBounds : this . getBounds ( ) ,
@@ -448,7 +517,9 @@ export class HTMLLinkElement extends HTMLElement {
448517 linkEl : this
449518 } ) . addTo ( this . parentExtent . _extentLayer ) ;
450519 } else if ( this . rel === 'query' ) {
451- this . attachShadow ( { mode : 'open' } ) ;
520+ if ( ! this . shadowRoot ) {
521+ this . attachShadow ( { mode : 'open' } ) ;
522+ }
452523 extend ( this . _templateVars , this . _setupQueryVars ( this . _templateVars ) ) ;
453524 extend ( this . _templateVars , { extentBounds : this . getBounds ( ) } ) ;
454525 }
@@ -853,7 +924,8 @@ export class HTMLLinkElement extends HTMLElement {
853924
854925 return zoomBounds ;
855926 }
856- _validateDisabled ( ) {
927+ isVisible ( ) {
928+ if ( this . disabled ) return false ;
857929 let isVisible = false ,
858930 map = this . getMapEl ( ) ,
859931 mapZoom = map . zoom ,
@@ -958,6 +1030,7 @@ export class HTMLLinkElement extends HTMLElement {
9581030 case 'image' :
9591031 case 'features' :
9601032 ready = '_templatedLayer' ;
1033+ if ( this . disabled ) resolve ( ) ;
9611034 break ;
9621035 case 'style' :
9631036 case 'self' :
@@ -967,6 +1040,7 @@ export class HTMLLinkElement extends HTMLElement {
9671040 break ;
9681041 case 'query' :
9691042 ready = 'shadowRoot' ;
1043+ if ( this . disabled ) resolve ( ) ;
9701044 break ;
9711045 case 'alternate' :
9721046 ready = '_alternate' ;
@@ -975,7 +1049,7 @@ export class HTMLLinkElement extends HTMLElement {
9751049 if ( this . type === 'application/pmtiles+stylesheet' ) {
9761050 ready = '_pmtilesRules' ;
9771051 } else {
978- resolve ( ) ;
1052+ ready = '_stylesheetHost' ;
9791053 }
9801054 break ;
9811055 case 'zoomin' :
0 commit comments