mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Use direct dart API from dart:ui_web
rather than JS shim. (#123443)
This is based off (and dependent on) these changes in the web engine that expose web-specific APIs: https://github.com/flutter/engine/pull/40608
This commit is contained in:
parent
042eaf6b90
commit
201f7311f7
@ -15,9 +15,8 @@
|
||||
/// describing how the `url_launcher` package was created using [flutter_web_plugins].
|
||||
library flutter_web_plugins;
|
||||
|
||||
export 'src/navigation/js_url_strategy.dart';
|
||||
export 'src/navigation/url_strategy.dart';
|
||||
export 'src/navigation/utils.dart';
|
||||
export 'src/navigation_common/url_strategy.dart';
|
||||
export 'src/navigation_common/platform_location.dart';
|
||||
export 'src/plugin_event_channel.dart';
|
||||
export 'src/plugin_registry.dart';
|
||||
|
@ -1,115 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// TODO(goderbauer): Remove this ignore when the documentation for the
|
||||
// now private, then public typedefs is clear.
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
|
||||
@JS()
|
||||
library js_location_strategy;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:html' as html;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:js/js.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../navigation_common/url_strategy.dart';
|
||||
|
||||
typedef _JsSetUrlStrategy = void Function(JsUrlStrategy?);
|
||||
|
||||
/// A JavaScript hook to customize the URL strategy of a Flutter app.
|
||||
//
|
||||
// Keep this in sync with the JS name in the web engine. Find it at:
|
||||
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/navigation/js_url_strategy.dart
|
||||
//
|
||||
// TODO(mdebbar): Add integration test https://github.com/flutter/flutter/issues/66852
|
||||
@JS('_flutter_web_set_location_strategy')
|
||||
external _JsSetUrlStrategy get jsSetUrlStrategy;
|
||||
|
||||
typedef _PathGetter = String Function();
|
||||
|
||||
typedef _StateGetter = Object? Function();
|
||||
|
||||
typedef _AddPopStateListener = ui.VoidCallback Function(EventListener);
|
||||
|
||||
typedef _StringToString = String Function(String);
|
||||
|
||||
typedef _StateOperation = void Function(Object state, String title, String url);
|
||||
|
||||
typedef _HistoryMove = Future<void> Function(int count);
|
||||
|
||||
/// Given a Dart implementation of URL strategy, converts it to a JavaScript
|
||||
/// URL strategy to be passed through JS interop.
|
||||
JsUrlStrategy convertToJsUrlStrategy(UrlStrategy strategy) {
|
||||
return JsUrlStrategy(
|
||||
getPath: allowInterop(strategy.getPath),
|
||||
getState: allowInterop(strategy.getState),
|
||||
addPopStateListener: allowInterop(strategy.addPopStateListener),
|
||||
prepareExternalUrl: allowInterop(strategy.prepareExternalUrl),
|
||||
pushState: allowInterop(strategy.pushState),
|
||||
replaceState: allowInterop(strategy.replaceState),
|
||||
go: allowInterop(strategy.go),
|
||||
);
|
||||
}
|
||||
|
||||
/// The JavaScript representation of a URL strategy.
|
||||
///
|
||||
/// This is used to pass URL strategy implementations across a JS-interop
|
||||
/// bridge from the app to the engine.
|
||||
@JS()
|
||||
@anonymous
|
||||
abstract class JsUrlStrategy {
|
||||
/// Creates an instance of [JsUrlStrategy] from a bag of URL strategy
|
||||
/// functions.
|
||||
external factory JsUrlStrategy({
|
||||
@required _PathGetter getPath,
|
||||
@required _StateGetter getState,
|
||||
@required _AddPopStateListener addPopStateListener,
|
||||
@required _StringToString prepareExternalUrl,
|
||||
@required _StateOperation pushState,
|
||||
@required _StateOperation replaceState,
|
||||
@required _HistoryMove go,
|
||||
});
|
||||
|
||||
/// Adds a listener to the `popstate` event and returns a function that
|
||||
/// removes the listener.
|
||||
external ui.VoidCallback addPopStateListener(html.EventListener fn);
|
||||
|
||||
/// Returns the active path in the browser.
|
||||
external String getPath();
|
||||
|
||||
/// Returns the history state in the browser.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state
|
||||
external Object getState();
|
||||
|
||||
/// Given a path that's internal to the app, create the external url that
|
||||
/// will be used in the browser.
|
||||
external String prepareExternalUrl(String internalUrl);
|
||||
|
||||
/// Push a new history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
|
||||
external void pushState(Object? state, String title, String url);
|
||||
|
||||
/// Replace the currently active history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
|
||||
external void replaceState(Object? state, String title, String url);
|
||||
|
||||
/// Moves forwards or backwards through the history stack.
|
||||
///
|
||||
/// A negative [count] value causes a backward move in the history stack. And
|
||||
/// a positive [count] value causes a forward move.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// * `go(-2)` moves back 2 steps in history.
|
||||
/// * `go(3)` moves forward 3 steps in history.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go
|
||||
external Future<void> go(int count);
|
||||
}
|
@ -5,11 +5,13 @@
|
||||
import 'dart:async';
|
||||
import 'dart:html' as html;
|
||||
import 'dart:ui' as ui;
|
||||
import 'dart:ui_web' as ui_web;
|
||||
|
||||
import '../navigation_common/url_strategy.dart';
|
||||
import 'js_url_strategy.dart';
|
||||
import '../navigation_common/platform_location.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
export 'dart:ui_web' show UrlStrategy;
|
||||
|
||||
/// Saves the current [UrlStrategy] to be accessed by [urlStrategy] or
|
||||
/// [setUrlStrategy].
|
||||
///
|
||||
@ -20,25 +22,20 @@ import 'utils.dart';
|
||||
// Find it at:
|
||||
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/window.dart#L360
|
||||
//
|
||||
UrlStrategy? _urlStrategy = const HashUrlStrategy();
|
||||
ui_web.UrlStrategy? _urlStrategy = const HashUrlStrategy();
|
||||
|
||||
/// Returns the present [UrlStrategy] for handling the browser URL.
|
||||
///
|
||||
/// In case null is returned, the browser integration has been manually
|
||||
/// disabled by [setUrlStrategy].
|
||||
UrlStrategy? get urlStrategy => _urlStrategy;
|
||||
ui_web.UrlStrategy? get urlStrategy => _urlStrategy;
|
||||
|
||||
/// Change the strategy to use for handling browser URL.
|
||||
///
|
||||
/// Setting this to null disables all integration with the browser history.
|
||||
void setUrlStrategy(UrlStrategy? strategy) {
|
||||
void setUrlStrategy(ui_web.UrlStrategy? strategy) {
|
||||
_urlStrategy = strategy;
|
||||
|
||||
JsUrlStrategy? jsUrlStrategy;
|
||||
if (strategy != null) {
|
||||
jsUrlStrategy = convertToJsUrlStrategy(strategy);
|
||||
}
|
||||
jsSetUrlStrategy(jsUrlStrategy);
|
||||
ui_web.urlStrategy = strategy;
|
||||
}
|
||||
|
||||
/// Use the [PathUrlStrategy] to handle the browser URL.
|
||||
@ -60,7 +57,7 @@ void usePathUrlStrategy() {
|
||||
/// // Somewhere before calling `runApp()` do:
|
||||
/// setUrlStrategy(const HashUrlStrategy());
|
||||
/// ```
|
||||
class HashUrlStrategy extends UrlStrategy {
|
||||
class HashUrlStrategy extends ui_web.UrlStrategy {
|
||||
/// Creates an instance of [HashUrlStrategy].
|
||||
///
|
||||
/// The [PlatformLocation] parameter is useful for testing to mock out browser
|
||||
@ -71,9 +68,13 @@ class HashUrlStrategy extends UrlStrategy {
|
||||
final PlatformLocation _platformLocation;
|
||||
|
||||
@override
|
||||
ui.VoidCallback addPopStateListener(EventListener fn) {
|
||||
_platformLocation.addPopStateListener(fn);
|
||||
return () => _platformLocation.removePopStateListener(fn);
|
||||
ui.VoidCallback addPopStateListener(ui_web.PopStateListener fn) {
|
||||
void wrappedFn(Object event) {
|
||||
// `fn` expects `event.state`, not a `html.Event`.
|
||||
fn((event as html.PopStateEvent).state);
|
||||
}
|
||||
_platformLocation.addPopStateListener(wrappedFn);
|
||||
return () => _platformLocation.removePopStateListener(wrappedFn);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2,63 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
/// Signature of an html event listener.
|
||||
///
|
||||
/// We have to redefine it because non-web platforms can't import dart:html.
|
||||
/// Function type that handles pop state events.
|
||||
typedef EventListener = dynamic Function(Object event);
|
||||
|
||||
/// Represents and reads route state from the browser's URL.
|
||||
///
|
||||
/// By default, the [HashUrlStrategy] subclass is used if the app doesn't
|
||||
/// specify one.
|
||||
abstract class UrlStrategy {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const UrlStrategy();
|
||||
|
||||
/// Adds a listener to the `popstate` event and returns a function that, when
|
||||
/// invoked, removes the listener.
|
||||
ui.VoidCallback addPopStateListener(EventListener fn);
|
||||
|
||||
/// Returns the active path in the browser.
|
||||
String getPath();
|
||||
|
||||
/// The state of the current browser history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state
|
||||
Object? getState();
|
||||
|
||||
/// Given a path that's internal to the app, create the external url that
|
||||
/// will be used in the browser.
|
||||
String prepareExternalUrl(String internalUrl);
|
||||
|
||||
/// Push a new history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
|
||||
void pushState(Object? state, String title, String url);
|
||||
|
||||
/// Replace the currently active history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
|
||||
void replaceState(Object? state, String title, String url);
|
||||
|
||||
/// Moves forwards or backwards through the history stack.
|
||||
///
|
||||
/// A negative [count] value causes a backward move in the history stack. And
|
||||
/// a positive [count] value causes a forward move.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// * `go(-2)` moves back 2 steps in history.
|
||||
/// * `go(3)` moves forward 3 steps in history.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go
|
||||
Future<void> go(int count);
|
||||
}
|
||||
|
||||
/// Encapsulates all calls to DOM apis, which allows the [UrlStrategy] classes
|
||||
/// to be platform agnostic and testable.
|
||||
///
|
@ -5,7 +5,68 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import '../navigation_common/url_strategy.dart';
|
||||
import '../navigation_common/platform_location.dart';
|
||||
|
||||
/// Callback that receives the new state of the browser history entry.
|
||||
typedef PopStateListener = void Function(Object? state);
|
||||
|
||||
/// Represents and reads route state from the browser's URL.
|
||||
///
|
||||
/// By default, the [HashUrlStrategy] subclass is used if the app doesn't
|
||||
/// specify one.
|
||||
abstract class UrlStrategy {
|
||||
/// Abstract const constructor. This constructor enables subclasses to provide
|
||||
/// const constructors so that they can be used in const expressions.
|
||||
const UrlStrategy();
|
||||
|
||||
/// Adds a listener to the `popstate` event and returns a function that, when
|
||||
/// invoked, removes the listener.
|
||||
ui.VoidCallback addPopStateListener(PopStateListener fn) {
|
||||
// No-op.
|
||||
return () {};
|
||||
}
|
||||
|
||||
/// Returns the active path in the browser.
|
||||
String getPath() => '';
|
||||
|
||||
/// The state of the current browser history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/state
|
||||
Object? getState() => null;
|
||||
|
||||
/// Given a path that's internal to the app, create the external url that
|
||||
/// will be used in the browser.
|
||||
String prepareExternalUrl(String internalUrl) => '';
|
||||
|
||||
/// Push a new history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
|
||||
void pushState(Object? state, String title, String url) {
|
||||
// No-op.
|
||||
}
|
||||
|
||||
/// Replace the currently active history entry.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
|
||||
void replaceState(Object? state, String title, String url) {
|
||||
// No-op.
|
||||
}
|
||||
|
||||
/// Moves forwards or backwards through the history stack.
|
||||
///
|
||||
/// A negative [count] value causes a backward move in the history stack. And
|
||||
/// a positive [count] value causes a forward move.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// * `go(-2)` moves back 2 steps in history.
|
||||
/// * `go(3)` moves forward 3 steps in history.
|
||||
///
|
||||
/// See: https://developer.mozilla.org/en-US/docs/Web/API/History/go
|
||||
Future<void> go(int count) async {
|
||||
// No-op.
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the present [UrlStrategy] for handling the browser URL.
|
||||
///
|
||||
@ -45,36 +106,6 @@ class HashUrlStrategy extends UrlStrategy {
|
||||
/// The [PlatformLocation] parameter is useful for testing to mock out browser
|
||||
/// integrations.
|
||||
const HashUrlStrategy([PlatformLocation? _]);
|
||||
|
||||
@override
|
||||
ui.VoidCallback addPopStateListener(EventListener fn) {
|
||||
// No-op.
|
||||
return () {};
|
||||
}
|
||||
|
||||
@override
|
||||
String getPath() => '';
|
||||
|
||||
@override
|
||||
Object? getState() => null;
|
||||
|
||||
@override
|
||||
String prepareExternalUrl(String internalUrl) => '';
|
||||
|
||||
@override
|
||||
void pushState(Object? state, String title, String url) {
|
||||
// No-op.
|
||||
}
|
||||
|
||||
@override
|
||||
void replaceState(Object? state, String title, String url) {
|
||||
// No-op.
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> go(int count) async {
|
||||
// No-op.
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses the browser URL's pathname to represent Flutter's route name.
|
||||
@ -92,11 +123,5 @@ class PathUrlStrategy extends HashUrlStrategy {
|
||||
///
|
||||
/// The [PlatformLocation] parameter is useful for testing to mock out browser
|
||||
/// integrations.
|
||||
PathUrlStrategy([super.platformLocation]);
|
||||
|
||||
@override
|
||||
String getPath() => '';
|
||||
|
||||
@override
|
||||
String prepareExternalUrl(String internalUrl) => '';
|
||||
PathUrlStrategy([PlatformLocation? _]);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
export 'src/navigation_common/url_strategy.dart';
|
||||
export 'src/navigation_common/platform_location.dart';
|
||||
|
||||
export 'src/navigation_non_web/url_strategy.dart'
|
||||
if (dart.library.html) 'src/navigation/url_strategy.dart';
|
||||
if (dart.library.ui_web) 'src/navigation/url_strategy.dart';
|
||||
|
47
packages/flutter_web_plugins/test/navigation/common.dart
Normal file
47
packages/flutter_web_plugins/test/navigation/common.dart
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||
|
||||
/// A mock implementation of [PlatformLocation] that doesn't access the browser.
|
||||
class TestPlatformLocation extends PlatformLocation {
|
||||
@override
|
||||
String pathname = '';
|
||||
|
||||
@override
|
||||
String search = '';
|
||||
|
||||
@override
|
||||
String hash = '';
|
||||
|
||||
@override
|
||||
Object? get state => null;
|
||||
|
||||
/// Mocks the base href of the document.
|
||||
String baseHref = '';
|
||||
|
||||
@override
|
||||
void addPopStateListener(EventListener fn) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void removePopStateListener(EventListener fn) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void pushState(Object? state, String title, String url) {}
|
||||
|
||||
@override
|
||||
void replaceState(Object? state, String title, String url) {}
|
||||
|
||||
@override
|
||||
void go(int count) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
String getBaseHref() => baseHref;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@TestOn('!chrome')
|
||||
library;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
group('Non-web UrlStrategy', () {
|
||||
late TestPlatformLocation location;
|
||||
|
||||
setUp(() {
|
||||
location = TestPlatformLocation();
|
||||
});
|
||||
|
||||
test('Can create and set a $HashUrlStrategy', () {
|
||||
expect(() {
|
||||
final HashUrlStrategy strategy = HashUrlStrategy(location);
|
||||
setUrlStrategy(strategy);
|
||||
}, returnsNormally);
|
||||
});
|
||||
|
||||
test('Can create and set a $PathUrlStrategy', () {
|
||||
expect(() {
|
||||
final PathUrlStrategy strategy = PathUrlStrategy(location);
|
||||
setUrlStrategy(strategy);
|
||||
}, returnsNormally);
|
||||
});
|
||||
|
||||
test('Can usePathUrlStrategy', () {
|
||||
expect(() {
|
||||
usePathUrlStrategy();
|
||||
}, returnsNormally);
|
||||
});
|
||||
});
|
||||
}
|
@ -6,7 +6,9 @@
|
||||
library;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
group('$HashUrlStrategy', () {
|
||||
@ -142,45 +144,3 @@ void main() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// A mock implementation of [PlatformLocation] that doesn't access the browser.
|
||||
class TestPlatformLocation extends PlatformLocation {
|
||||
@override
|
||||
String pathname = '';
|
||||
|
||||
@override
|
||||
String search = '';
|
||||
|
||||
@override
|
||||
String hash = '';
|
||||
|
||||
@override
|
||||
Object? get state => null;
|
||||
|
||||
/// Mocks the base href of the document.
|
||||
String baseHref = '';
|
||||
|
||||
@override
|
||||
void addPopStateListener(EventListener fn) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void removePopStateListener(EventListener fn) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void pushState(Object? state, String title, String url) {}
|
||||
|
||||
@override
|
||||
void replaceState(Object? state, String title, String url) {}
|
||||
|
||||
@override
|
||||
void go(int count) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
String getBaseHref() => baseHref;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user