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 | 52x 42x 40x 2x 2x 10x 10x 4x 4x 4x 1x 1x 1x 1x 1x 4x 18x 18x 18x 18x 52x 52x 42x 52x 52x 52x 52x 28x 52x 52x 728x 488x 52x 52x 18x 48x 37x 37x 37x 13x 1x 1x 12x 7x 48x 5x 5x 5x 5x 5x 48x 48x 18x 2x 2x 2x 2x 72x 39x 28x 44x 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; |