UNPKG

tab-syncer

Version:

A lightweight (4KB) library for browser tab state synchronization and communication. Supports auto-persistence and real-time data sync between tabs.

2 lines (1 loc) 2.91 kB
class t{constructor(t){this.name=t,this.bc=new BroadcastChannel(t),this.listeners=new Map,this._listenOn()}static getInstance(e){return this.instance||(this.instance=new t(e)),this.instance}_listenOn(){this.bc.onmessage=t=>{var e;const{event:s,params:n}=t.data;null===(e=this.listeners.get(s))||void 0===e||e(n)}}notify(t,e){console.log("notify",t,e),this.bc.postMessage({event:t,params:e})}subscribe(t,e){console.log("subscribe",t),this.listeners.set(t,e)}unsubscribe(t,e){console.log("unsubscribe",t),this.listeners.delete(t)}dispose(){this.listeners.clear(),this.bc.onmessage=null,this.bc.close()}}class e{static utf8Encode(t){return encodeURIComponent(t).replace(/%([0-9A-F]{2})/g,((t,e)=>String.fromCharCode(parseInt("0x"+e))))}static utf8Decode(t){try{return decodeURIComponent(t.split("").map((function(t){return"%"+("00"+t.charCodeAt(0).toString(16)).slice(-2)})).join(""))}catch(e){return t}}static encrypt(t){if(!t)return t;t=e.utf8Encode(t);const s=e.utf8Encode(e.keyStr);let n="",r=0;for(let e=0;e<t.length;e++){const i=t.charCodeAt(e),a=s.charCodeAt(r);n+=String.fromCharCode(i^a),r=(r+1)%s.length}return btoa(n)}static decrypt(t){if(!t)return t;t=atob(t);const s=e.utf8Encode(e.keyStr);let n="",r=0;for(let e=0;e<t.length;e++){const i=t.charCodeAt(e),a=s.charCodeAt(r);n+=String.fromCharCode(i^a),r=(r+1)%s.length}return e.utf8Decode(n)}}e.keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";const s="ts__state";class n{get data(){return this._data}set data(t){this._data=t,this._options.persist&&this.persist(t)}constructor(t,e,s,n={persist:!0}){this._data=this.stateFromLocalStorage()||t,this._options=n,this._listeners=[],this._subscriber=e,this._notifier=s,this._subscriber((t=>{this.data=t,this._listeners.forEach((e=>e(t)))}))}setState(t,e=!0){return this.data="function"!=typeof t?t:null==t?void 0:t(this.data),e&&this._notifier(this.data),this.data}getState(){return this.data}onStateChange(t){this._listeners.push(t)}offStateChange(t){this._listeners=this._listeners.filter((e=>e!==t))}stateFromLocalStorage(){const t=localStorage.getItem(s);try{if(t){const s=e.decrypt(t);return JSON.parse(s)}}catch(t){console.error("Error decrypting data from localStorage")}return null}persist(t){const n=e.encrypt(JSON.stringify(t));localStorage.setItem(s,n)}removeAllListeners(){this._listeners=[]}dispose(){this.removeAllListeners(),this.data={}}}class r{constructor(t,e,s){this.name=t,this.mode=e,this._handler=this.getHandler(),this.state=new n(s,(t=>{this._handler.subscribe("stateChange",t)}),(t=>this._handler.notify("stateChange",t)))}getHandler(){return this.mode,t.getInstance(this.name)}notify(t,e){this._handler.notify(t,e)}subscribe(t,e){this._handler.subscribe(t,e)}unsubscribe(t,e){this._handler.unsubscribe(t,e)}setState(...t){this.state.setState(...t)}getState(){return this.state.getState()}onStateChange(t){this.state.onStateChange(t)}}export{r as TabSyncer};