Files
redash/client/app/services/location.js
Tsuneo Yoshioka 59951eda3d Fix/too many history replace state (#7530)
* Fix too many history.replaceState() error on Safari

* fix restyled error by running prettier for client/app/services/location.js
2025-09-12 03:41:04 +09:00

106 lines
2.6 KiB
JavaScript

import { isNil, isUndefined, isFunction, isObject, trimStart, mapValues, omitBy, extend } from "lodash";
import qs from "query-string";
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
function normalizeLocation(rawLocation) {
const { pathname, search, hash } = rawLocation;
const result = {};
result.path = pathname;
result.search = mapValues(qs.parse(search), (value) => (isNil(value) ? true : value));
result.hash = trimStart(hash, "#");
result.url = `${pathname}${search}${hash}`;
return result;
}
const location = {
listen(handler) {
if (isFunction(handler)) {
return history.listen((unused, action) => handler(location, action));
} else {
return () => {};
}
},
confirmChange(handler) {
if (isFunction(handler)) {
return history.block((nextLocation) => {
return handler(normalizeLocation(nextLocation), location);
});
} else {
return () => {};
}
},
update(newLocation, replace = false) {
if (isObject(newLocation)) {
// remap fields and remove undefined ones
newLocation = omitBy(
{
pathname: newLocation.path,
search: newLocation.search,
hash: newLocation.hash,
},
isUndefined
);
// keep existing fields (!)
newLocation = extend(
{
pathname: location.path,
search: location.search,
hash: location.hash,
},
newLocation
);
// serialize search and keep existing search parameters (!)
if (isObject(newLocation.search)) {
newLocation.search = omitBy(extend({}, location.search, newLocation.search), isNil);
newLocation.search = mapValues(newLocation.search, (value) => (value === true ? null : value));
newLocation.search = qs.stringify(newLocation.search);
}
}
if (replace) {
if (
newLocation.pathname !== location.path ||
newLocation.search !== qs.stringify(location.search) ||
newLocation.hash !== location.hash
) {
history.replace(newLocation);
}
} else {
history.push(newLocation);
}
},
url: undefined,
path: undefined,
setPath(path, replace = false) {
location.update({ path }, replace);
},
search: undefined,
setSearch(search, replace = false) {
location.update({ search }, replace);
},
hash: undefined,
setHash(hash, replace = false) {
location.update({ hash }, replace);
},
};
function locationChanged() {
extend(location, normalizeLocation(history.location));
}
history.listen(locationChanged);
locationChanged(); // init service
export default location;