diff --git a/src/domain/navigation/URLRouter.js b/src/domain/navigation/URLRouter.js index c82b814b..2b7e8513 100644 --- a/src/domain/navigation/URLRouter.js +++ b/src/domain/navigation/URLRouter.js @@ -17,17 +17,17 @@ limitations under the License. import {Segment} from "./Navigation.js"; export class URLRouter { - constructor(pathObservable, navigation) { + constructor(history, navigation) { this._subscription = null; - this._pathObservable = pathObservable; + this._history = history; this._navigation = navigation; } start() { - this._subscription = this._pathObservable.subscribe(url => { + this._subscription = this._history.subscribe(url => { this._applyUrl(url); }); - this._applyUrl(this._pathObservable.get()); + this._applyUrl(this._history.get()); } _applyUrl(url) { @@ -40,7 +40,8 @@ export class URLRouter { this._subscription = this._subscription(); } - _segmentsFromUrl(path) { + _segmentsFromUrl(url) { + const path = this._history.urlAsPath(url); const parts = path.split("/").filter(p => !!p); let index = 0; const segments = []; @@ -58,6 +59,10 @@ export class URLRouter { return segments; } + replaceUrl(url) { + this._history.replaceUrl(url); + } + urlForSegment(type, value) { const path = this._navigation.path.with(new Segment(type, value)); if (path) { @@ -66,14 +71,14 @@ export class URLRouter { } urlForPath(path) { - let url = "#"; + let urlPath = ""; for (const {type, value} of path.segments) { if (typeof value === "boolean") { - url += `/${type}`; + urlPath += `/${type}`; } else { - url += `/${type}/${value}`; + urlPath += `/${type}/${value}`; } } - return url; + return this._history.pathAsUrl(urlPath); } } diff --git a/src/main.js b/src/main.js index 05767a34..2ff9b4ad 100644 --- a/src/main.js +++ b/src/main.js @@ -26,7 +26,7 @@ import {Navigation} from "./domain/navigation/Navigation.js"; import {URLRouter} from "./domain/navigation/URLRouter.js"; import {BrawlView} from "./ui/web/BrawlView.js"; import {Clock} from "./ui/web/dom/Clock.js"; -import {HashObservable} from "./ui/web/dom/HashObservable.js"; +import {History} from "./ui/web/dom/History.js"; import {OnlineStatus} from "./ui/web/dom/OnlineStatus.js"; import {CryptoDriver} from "./ui/web/dom/CryptoDriver.js"; import {WorkerPool} from "./utils/WorkerPool.js"; @@ -130,7 +130,7 @@ export async function main(container, paths, legacyExtras) { return false; } }); - const urlRouter = new URLRouter(new HashObservable(), navigation); + const urlRouter = new URLRouter(new History(), navigation); urlRouter.start(); const vm = new BrawlViewModel({ diff --git a/src/ui/web/dom/HashObservable.js b/src/ui/web/dom/History.js similarity index 69% rename from src/ui/web/dom/HashObservable.js rename to src/ui/web/dom/History.js index 4239f6ac..08bd6ed0 100644 --- a/src/ui/web/dom/HashObservable.js +++ b/src/ui/web/dom/History.js @@ -16,35 +16,40 @@ limitations under the License. import {BaseObservableValue} from "../../../observable/ObservableValue.js"; -export class HashObservable extends BaseObservableValue { +export class History extends BaseObservableValue { constructor() { super(); this._boundOnHashChange = null; - this._expectSetEcho = false; } _onHashChange() { - if (this._expectSetEcho) { - this._expectSetEcho = false; - return; - } this.emit(this.get()); } get() { - const hash = document.location.hash; - if (hash.length) { - // trim '#' - return hash.substr(1); - } - return hash; + return document.location.hash; } - set(hash) { - if (this._boundOnHashChange) { - this._expectSetEcho = true; + replaceUrl(url) { + window.history.replaceState(null, null, url); + // replaceState does not cause hashchange + this.emit(url); + } + + pushUrl(url) { + document.location.hash = this.urlAsPath(url); + } + + urlAsPath(url) { + if (url.startsWith("#")) { + return url.substr(1); + } else { + return url; } - document.location.hash = hash; + } + + pathAsUrl(path) { + return `#${path}`; } onSubscribeFirst() {