diff --git a/src/core/router/util.js b/src/core/router/util.js index 218c14f82..e50d48b03 100644 --- a/src/core/router/util.js +++ b/src/core/router/util.js @@ -122,7 +122,7 @@ export function parseQuery(query) { // Simple parse query.split('&').forEach(param => { - const parts = param.replace(/\+/g, ' ').split('='); + const parts = param.replace(/\+/g, ' ').split(/=(.*)/s); res[parts[0]] = parts[1] && decode(parts[1]); }); diff --git a/test/unit/router-util.test.js b/test/unit/router-util.test.js index e724f165c..30fe99968 100644 --- a/test/unit/router-util.test.js +++ b/test/unit/router-util.test.js @@ -4,11 +4,33 @@ import { getClickedLink, getSidebarNavigationTarget, isCurrentContextNavigation, + parseQuery, } from '../../src/core/router/util.js'; // Suite // ----------------------------------------------------------------------------- describe('router/util', () => { + describe('parseQuery()', () => { + test('preserves equals signs inside query values', () => { + expect(parseQuery('?id=a=b=c&other=ok')).toEqual({ + id: 'a=b=c', + other: 'ok', + }); + }); + + test.each([ + ['?value==', { value: '=' }], + ['?value=a%3Db', { value: 'a=b' }], + ['?value=a+b=c', { value: 'a b=c' }], + ['?empty=&flag', { empty: '', flag: undefined }], + ])( + 'parses %s without changing empty or encoded values', + (query, expected) => { + expect(parseQuery(query)).toEqual(expected); + }, + ); + }); + describe('navigation click helpers', () => { test('finds a link from a nested click target', () => { document.body.innerHTML = 'Guide';