Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 55x 46x 44x 2x 2x 10x 10x 4x 4x 4x 1x 1x 1x 1x 1x 4x 18x 18x 18x 18x 55x 55x 46x 55x 55x 55x 55x 26x 55x 55x 770x 513x 55x 55x 18x 51x 41x 41x 41x 12x 1x 1x 11x 7x 51x 5x 5x 5x 5x 5x 51x 51x 18x 2x 2x 2x 2x 63x 33x 16x 47x 4x 2x 4x | const attr = ( el, attr )=> el.getAttribute( attr );
let originalHistory;
function ensureTrackLocationChange()
{ if( originalHistory )
return;
originalHistory = {};
'back,forward,go,pushState,replaceState'.split(',').forEach( k =>
{
originalHistory[ k ] = history[ k ];
history[ k ] = function(...rest )
{
originalHistory[k].apply( history, rest );
window.dispatchEvent( new CustomEvent('dce-location',{detail:{ k }}) );
}
});
}
const methods =
{ 'location.href' : src => window.location.href = src
, 'location.hash' : src => window.location.hash = src
, 'location.assign' : src => window.location.assign( src )
, 'location.replace' : src => window.location.replace( src )
, 'history.pushState' : src => window.history.pushState( {}, "", src )
, 'history.replaceState' : src => window.history.replaceState( {}, "", src )
};
export class LocationElement extends HTMLElement
{
static observedAttributes=
[ 'value' // populated from url
, 'slice'
, 'href' // url to be parsed. When omitted window.location is used.
, 'type' // `text|json`, defaults to text, other types are compatible with INPUT field
, 'live' // monitors history change, applicable only when href is omitted.
, 'src' // sets the URL
, 'method' // when defined, changes URL by one of predefined methods.
];
constructor()
{
super();
const state = {}
, listener = () => setTimeout( propagateSlice,1 )
, propagateSlice = ()=>
{ const urlStr = attr(this,'href')
if(!urlStr)
ensureTrackLocationChange();
const url = urlStr? new URL(urlStr, window.location) : window.location;
const params= {}
const search = new URLSearchParams(url.search);
for (const key of search.keys())
params[key] = search.getAll(key)
const detail = {params}
for( const k in url )
{ if ('string' === typeof url[k])
detail[k] = url[k]
}
this.value = detail;
this.dispatchEvent( new Event('change') );
};
this.sliceInit = s =>
{
if( this.hasAttribute('method') )
{
const method = this.getAttribute('method');
const src = this.getAttribute('src');
if( method && src )
if( method === 'location.hash' )
{ Eif( src !== window.location.hash )
methods[ method ]?.( src );
}else if( window.location.href !== new URL(src, window.location).href )
methods[method]?.(src);
}
if( !state.listener && this.hasAttribute('live') )
{ state.listener = 1;
window.navigation?.addEventListener("navigate", listener );
window.addEventListener( 'popstate' , listener );
window.addEventListener( 'hashchange' , listener );
window.addEventListener( 'dce-location' , listener );
}
propagateSlice();
return s || {}
}
this._destroy = ()=>
{
window.removeEventListener('popstate' , listener);
window.removeEventListener('hashchange' , listener);
window.removeEventListener('dce-location', listener);
delete state.listener;
};
}
attributeChangedCallback(name, oldValue, newValue)
{
if('href'!== name && 'method' !== name && 'src' )
if( !['method','src','href'].includes(name) )
return;
this.sliceInit && this.sliceInit();
}
connectedCallback(){ this.sliceInit() }
disconnectedCallback(){ this._destroy() }
}
window.customElements.define( 'location-element', LocationElement );
export default LocationElement; |