diff --git a/assets/js/phoenix_live_view/live_socket.js b/assets/js/phoenix_live_view/live_socket.js index 3693afc687..4a139d5f6a 100644 --- a/assets/js/phoenix_live_view/live_socket.js +++ b/assets/js/phoenix_live_view/live_socket.js @@ -158,6 +158,7 @@ export default class LiveSocket { this.sessionStorage = opts.sessionStorage || window.sessionStorage this.boundTopLevelEvents = false this.domCallbacks = Object.assign({onNodeAdded: closure(), onBeforeElUpdated: closure()}, opts.dom || {}) + this.navigationCallbacks = Object.assign({beforeEach: closure(true), afterEach: closure()}, opts.navigation || {}) this.transitions = new TransitionSet() window.addEventListener("pagehide", _e => { this.unloaded = true @@ -687,6 +688,13 @@ export default class LiveSocket { }, 100) }) window.addEventListener("popstate", event => { + if(this.navigationCallbacks["beforeEach"](window.location.href) === false){ + // we want to stay at the current location; push the current location back + // and then the old location where we're coming from + Browser.pushState("push", history.state || {}, window.location.href) + Browser.pushState("push", history.state || {}, this.currentLocation.href) + return + } if(!this.registerNewLocation(window.location)){ return } let {type, id, root, scroll} = event.state || {} let href = window.location.href @@ -695,11 +703,13 @@ export default class LiveSocket { this.requestDOMUpdate(() => { if(this.main.isConnected() && (type === "patch" && id === this.main.id)){ this.main.pushLinkPatch(href, null, () => { + this.navigationCallbacks["afterEach"](href) this.maybeScroll(scroll) }) } else { this.replaceMain(href, null, () => { if(root){ this.replaceRootHistory() } + this.navigationCallbacks["afterEach"](href) this.maybeScroll(scroll) }) } @@ -757,6 +767,8 @@ export default class LiveSocket { } pushHistoryPatch(href, linkState, targetEl){ + if(this.navigationCallbacks["beforeEach"](href) === false) return + if(!this.isConnected() || !this.main.isMain()){ return Browser.redirect(href) } this.withPageLoading({to: href, kind: "patch"}, done => { @@ -773,9 +785,12 @@ export default class LiveSocket { Browser.pushState(linkState, {type: "patch", id: this.main.id}, href) DOM.dispatchEvent(window, "phx:navigate", {detail: {patch: true, href, pop: false}}) this.registerNewLocation(window.location) + this.navigationCallbacks["afterEach"](window.location.href) } historyRedirect(href, linkState, flash){ + if(!this.navigationCallbacks["beforeEach"](href) === false) return + if(!this.isConnected() || !this.main.isMain()){ return Browser.redirect(href, flash) } // convert to full href if only path prefix @@ -790,6 +805,7 @@ export default class LiveSocket { Browser.pushState(linkState, {type: "redirect", id: this.main.id, scroll: scroll}, href) DOM.dispatchEvent(window, "phx:navigate", {detail: {href, patch: false, pop: false}}) this.registerNewLocation(window.location) + this.navigationCallbacks["afterEach"](window.location.href) } done() })