Created
May 29, 2021 20:36
-
-
Save andersonbosa/804e27a70c2c06abb79dc848f1a572be to your computer and use it in GitHub Desktop.
Listen to "location" change on SPAs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Returns a function, that, as long as it continues to be invoked, will not | |
* be triggered. The function will be called after it stops being called for | |
* N milliseconds. If `immediate` is passed, trigger the function on the | |
* leading edge, instead of the trailing | |
* | |
* @param { function () : void } func - will be triggered when it stops to be invoked | |
* @param { Number } wait - time to wait | |
* @param { boolean } [immediate] - Either to trigger the function on the | |
* leading edge (truthy `immediate`) or instead of the trailing (falsy `immediate`) | |
*/ | |
function debounce (func, wait, immediate) { | |
let timeout | |
return function execute () { | |
const context = this | |
const args = arguments | |
const later = () => { | |
timeout = null | |
if (!immediate) { | |
func.apply(context, args) | |
} | |
} | |
const callNow = immediate && !timeout | |
clearTimeout(timeout) | |
timeout = setTimeout(later, wait) | |
if (callNow) { | |
func.apply(context, args) | |
} | |
} | |
} | |
/** | |
* Alias from window | |
*/ | |
//const Event = window.Event | |
/** | |
* Location change handler for SPA environment | |
* It modifies popstate, pushstate and replacestate | |
* functions so that all fire a custom locationchange | |
*/ | |
const spaLocationHandler = { | |
/** | |
* Flag to avoid many recasting of | |
* same function | |
*/ | |
firstInitialization: true, | |
/** | |
* Dispatches two new events [`pushState`, `locationchange`] | |
* applying old arguments to this method as well | |
* @param {Function} oldPushState - native code | |
*/ | |
recastPushState: oldPushState => { | |
return function pushState () { | |
const revised = oldPushState.apply(this, arguments) | |
window.dispatchEvent(new Event('pushState')) | |
window.dispatchEvent(new Event('locationchange')) | |
return revised | |
} | |
}, | |
/** | |
* Dispatches two new events [`replaceState`, `locationchange`] | |
* applying old arguments to this method as well | |
* @param {Function} oldReplaceState - native code | |
*/ | |
recastReplaceState: oldReplaceState => { | |
return function replaceState () { | |
const revised = oldReplaceState.apply(this, arguments) | |
window.dispatchEvent(new Event('replaceState')) | |
window.dispatchEvent(new Event('locationchange')) | |
return revised | |
} | |
}, | |
/** | |
* Dispatch a new event `locationchange` | |
*/ | |
popstateEventDispatcher: () => { | |
window.dispatchEvent(new Event('locationchange')) | |
}, | |
/** | |
* Trigged when page "location" changes | |
*/ | |
onLocationChangeHandler: () => { | |
console.log('***** onLocationChangeHandler') | |
}, | |
/** | |
* Initialize native functions rectification | |
* Note: This handler does not modify the previous | |
* functionalities, it just adds a custom dispatcher | |
*/ | |
init: () => { | |
const self = spaLocationHandler | |
if (!self.firstInitialization) { | |
return | |
} | |
/** | |
* Builds the new `locationchange` event to | |
* be used on any url change | |
*/ | |
window.history.pushState = self.recastPushState(window.history.pushState) | |
window.history.replaceState = self.recastReplaceState(window.history.replaceState) | |
window.addEventListener('popstate', self.popstateEventDispatcher) | |
/** | |
* New event available to atach into window | |
*/ | |
window.addEventListener('locationchange', debounce(self.onLocationChangeHandler, 2000)) | |
self.firstInitialization = false | |
} | |
} | |
spaLocationHandler.init() | |
// test | |
window.addEventListener('locationchange', evt => { | |
console.log('**** locationchange', evt) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment