From 43407cf155f38188dd7f9fe9698f4bd36bd9529a Mon Sep 17 00:00:00 2001 From: Vasiliy Ditsyak Date: Mon, 18 Sep 2023 23:12:08 +0200 Subject: [PATCH] Access to fragment in router state on page refresh (#131123) This PR fixes the issue #108614 Particularly this behaviour https://github.com/flutter/flutter/issues/108614#issuecomment-1645231915 --- .../lib/src/navigation/url_strategy.dart | 14 ++++++++++++- .../src/navigation_non_web/url_strategy.dart | 2 +- .../test/navigation/url_strategy_test.dart | 21 +++++++++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart index e0f0dbeaa8..ff2b08c063 100644 --- a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart @@ -46,6 +46,7 @@ class PathUrlStrategy extends ui_web.HashUrlStrategy { /// interactions. PathUrlStrategy([ super.platformLocation, + this.includeHash = false, ]) : _platformLocation = platformLocation, _basePath = stripTrailingSlash(extractPathname(checkBaseHref( platformLocation.getBaseHref(), @@ -54,9 +55,20 @@ class PathUrlStrategy extends ui_web.HashUrlStrategy { final ui_web.PlatformLocation _platformLocation; final String _basePath; + /// There were an issue with url #hash which disappears from URL on first start of the web application + /// This flag allows to preserve that hash and was introduced mainly to preserve backward compatibility + /// with existing applications that rely on a full match on the path. If someone navigates to + /// /profile or /profile#foo, they both will work without this flag otherwise /profile#foo won't match + /// with the /profile route name anymore because the hash became part of the path. + /// + /// This flag solves the edge cases when using auth provider which redirects back to the app with + /// token in redirect URL as /#access_token=bla_bla_bla + final bool includeHash; + @override String getPath() { - final String path = _platformLocation.pathname + _platformLocation.search; + final String? hash = includeHash ? _platformLocation.hash : null; + final String path = _platformLocation.pathname + _platformLocation.search + (hash ?? ''); if (_basePath.isNotEmpty && path.startsWith(_basePath)) { return ensureLeadingSlash(path.substring(_basePath.length)); } diff --git a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart index 0a4703b812..0e7aa1e994 100644 --- a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart @@ -129,5 +129,5 @@ class PathUrlStrategy extends HashUrlStrategy { /// /// The [PlatformLocation] parameter is useful for testing to mock out browser /// integrations. - const PathUrlStrategy([PlatformLocation? _]); + const PathUrlStrategy([PlatformLocation? _, bool __ = false,]); } diff --git a/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart b/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart index f5bfa16055..d9e0a4d453 100644 --- a/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart +++ b/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart @@ -80,17 +80,34 @@ void main() { expect(strategy.getPath(), '/bar'); }); - test('gets path correctly in the presence of query params', () { + test('gets path correctly in the presence of query params and omits fragment if no flag specified', () { location.baseHref = 'https://example.com/foo/'; location.pathname = '/foo/bar'; final PathUrlStrategy strategy = PathUrlStrategy(location); - location.search = '?q=1'; expect(strategy.getPath(), '/bar?q=1'); location.search = '?q=1&t=r'; expect(strategy.getPath(), '/bar?q=1&t=r'); + + location.hash = '#fragment=1'; + expect(strategy.getPath(), '/bar?q=1&t=r'); + }); + + test('gets path correctly in the presence of query params and fragment', () { + location.baseHref = 'https://example.com/foo/'; + location.pathname = '/foo/bar'; + final PathUrlStrategy strategy = PathUrlStrategy(location, true); + + location.search = '?q=1'; + expect(strategy.getPath(), '/bar?q=1'); + + location.search = '?q=1&t=r'; + expect(strategy.getPath(), '/bar?q=1&t=r'); + + location.hash = '#fragment=1'; + expect(strategy.getPath(), '/bar?q=1&t=r#fragment=1'); }); test('empty route name is ok', () {