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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | const string2value = (type, v) => { if( type === 'text') return v; if( type === 'json') try{ return JSON.parse( v );} catch(err){ return null } const el = document.createElement('input'); el.setAttribute('type',type); if( 'number' === type ) { el.value = v; return el.valueAsNumber; } if( 'date' === type ) { if(!v) return null; el.valueAsDate = new Date( v ); return el.value; } el.value = v; return el.value; }; let originalSetItem,originalRemoveItem,originalClear; function ensureTrackLocalStorage() { if( originalSetItem ) return; originalSetItem = localStorage.setItem; localStorage.setItem = function( key, value, ...rest ) { originalSetItem.apply(this, [ key, value, ...rest ]); window.dispatchEvent( new CustomEvent('local-storage',{detail:{key,value}}) ); }; originalRemoveItem = localStorage.removeItem; localStorage.removeItem = function( key, ...rest ) { originalRemoveItem.apply(this, [ key, ...rest ]); window.dispatchEvent( new CustomEvent('local-storage',{detail:{key}}) ); }; originalClear = localStorage.clear; localStorage.clear = function( ...rest ) { originalClear.apply(this, [ ...rest ]); window.dispatchEvent( new CustomEvent('local-storage',{detail:{}}) ); }; } export function localStorageSetItem(key, value) { localStorage.setItem(key, value); window.dispatchEvent( new CustomEvent('local-storage',{detail:{key,value}}) ); } export class LocalStorageElement extends HTMLElement { static observedAttributes= [ 'value' // populated from localStorage, if defined initially, sets the value in storage , 'slice' , 'key' , 'type' // `text|json`, defaults to text, other types are compatible with INPUT field , 'live' // monitors localStorage change ]; #value; get value(){ return this.#value ===null ? undefined: this.#value } set value(o){ return this.#value = o; } async connectedCallback() { const attr = attr => this.getAttribute(attr) , fromStorage = ()=> { this.#value = string2value( attr('type'), localStorage.getItem( attr( 'key' ) ) ); this.dispatchEvent( new Event('change') ) } this.#value = string2value( attr('type'), localStorage.getItem( attr( 'key' ) ) ); if( this.hasAttribute('value')) localStorageSetItem( attr( 'key' ), this.#value = attr( 'value' ) ) else fromStorage() if( this.hasAttribute('live') ) { const listener = (e => (e.detail.key === attr( 'key' ) || !e.detail.key ) && fromStorage()); window.addEventListener( 'local-storage', listener ); ensureTrackLocalStorage(); this._destroy = ()=> window.removeEventListener('local-storage', listener ); } } disconnectedCallback(){ this._destroy?.(); } } window.customElements.define( 'local-storage', LocalStorageElement ); export default LocalStorageElement; |