import { bind, debounce } from 'decko'; import { EventEmitter } from 'eventemitter3'; const EVENT = 'hashchange'; function isSameHash(a: string, b: string): boolean { return a === b || '#' + a === b || a === '#' + b; } class _HistoryService { private causedHashChange: boolean = false; private _emiter; constructor() { this._emiter = new EventEmitter(); this.bind(); } get hash(): string { return window.location.hash; } subscribe(cb): () => void { const emmiter = this._emiter.addListener(EVENT, cb); return () => emmiter.removeListener(EVENT, cb); } emit = () => { if (this.causedHashChange) { this.causedHashChange = false; return; } this._emiter.emit(EVENT, this.hash); }; bind() { window.addEventListener('hashchange', this.emit, false); } dispose() { window.removeEventListener('hashchange', this.emit); this.causedHashChange = false; } @bind @debounce update(hash: string | null, rewriteHistory: boolean = false) { if (hash == null || isSameHash(hash, this.hash)) return; if (rewriteHistory) { window.history.replaceState(null, '', window.location.href.split('#')[0] + '#' + hash); return; } this.causedHashChange = true; window.location.hash = hash; } } export const HistoryService = new _HistoryService(); if (module.hot) { module.hot.dispose(() => { HistoryService.dispose(); }); }