Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[web] Add path-based browser location handling #17829

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 62 additions & 11 deletions lib/web_ui/lib/src/engine/browser_location.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ part of engine;

// Some parts of this file were inspired/copied from the AngularDart router.

/// Enable the path based browser location handling.
const bool usePathStrategy =
bool.fromEnvironment('flutter.web.usePathStrategy', defaultValue: false);

/// [LocationStrategy] is responsible for representing and reading route state
/// from the browser's URL.
///
Expand Down Expand Up @@ -44,17 +48,7 @@ abstract class LocationStrategy {
/// to represent its state.
///
/// In order to use this [LocationStrategy] for an app, it needs to be set in
/// [ui.window.locationStrategy]:
///
/// ```dart
/// import 'package:flutter_web/material.dart';
/// import 'package:flutter_web/ui.dart' as ui;
///
/// void main() {
/// ui.window.locationStrategy = const ui.HashLocationStrategy();
/// runApp(MyApp());
/// }
/// ```
/// [engine.window.locationStrategy]:
class HashLocationStrategy extends LocationStrategy {
final PlatformLocation _platformLocation;

Expand Down Expand Up @@ -121,6 +115,63 @@ class HashLocationStrategy extends LocationStrategy {
}
}

/// This is an implementation of [LocationStrategy] that uses the browser URL's
/// [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax)
/// to represent its state.
///
/// In order to use this [LocationStrategy] for an app, it needs to be set in
/// [engine.window.locationStrategy.locationStrategy]:
class PathLocationStrategy extends LocationStrategy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have a lot of duplicated code from the hashlocationstrategy. We should probably refactor out a mixin

final PlatformLocation _platformLocation;

const PathLocationStrategy(
[this._platformLocation = const BrowserPlatformLocation()]);

@override
ui.VoidCallback onPopState(html.EventListener fn) {
_platformLocation.onPopState(fn);
return () => _platformLocation.offPopState(fn);
}

@override
String get path => '${_platformLocation.pathname}${_platformLocation.search}';

@override
String prepareExternalUrl(String internalUrl) {
return internalUrl.isEmpty ? path : '$internalUrl';
}

@override
void pushState(dynamic state, String title, String url) {
_platformLocation.pushState(state, title, prepareExternalUrl(url));
}

@override
void replaceState(dynamic state, String title, String url) {
_platformLocation.replaceState(state, title, prepareExternalUrl(url));
}

@override
Future<void> back() {
_platformLocation.back();
return _waitForPopState();
}

/// Waits until the next popstate event is fired.
///
/// This is useful for example to wait until the browser has handled the
/// `history.back` transition.
Future<void> _waitForPopState() {
final Completer<void> completer = Completer<void>();
ui.VoidCallback unsubscribe;
unsubscribe = onPopState((_) {
unsubscribe();
completer.complete();
});
return completer.future;
}
}

/// [PlatformLocation] encapsulates all calls to DOM apis, which allows the
/// [LocationStrategy] classes to be platform agnostic and testable.
///
Expand Down
6 changes: 5 additions & 1 deletion lib/web_ui/lib/src/ui/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ Future<void> webOnlyInitializePlatform({
engine.AssetManager assetManager,
}) async {
if (!debugEmulateFlutterTesterEnvironment) {
engine.window.locationStrategy = const engine.HashLocationStrategy();
if (engine.usePathStrategy) {
engine.window.locationStrategy = const engine.PathLocationStrategy();
} else {
engine.window.locationStrategy = const engine.HashLocationStrategy();
}
}

engine.webOnlyInitializeEngine();
Expand Down