html_editor_enhanced/lib/utils/shims/flutter_inappwebview_fake.dart

285 lines
8.5 KiB
Dart
Raw Normal View History

2022-10-30 15:25:33 +07:00
///Class that is used by [WebView.shouldOverrideUrlLoading] event.
///It represents the policy to pass back to the decision handler.
class NavigationActionPolicy {
final int _value;
const NavigationActionPolicy._internal(this._value);
int toValue() => _value;
///Cancel the navigation.
static const CANCEL = NavigationActionPolicy._internal(0);
///Allow the navigation to continue.
static const ALLOW = NavigationActionPolicy._internal(1);
@override
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
Map<String, dynamic> toMap() {
return {
'action': _value,
};
}
}
///Class that represents the WebView context menu. It used by [WebView.contextMenu].
///
///**NOTE**: To make it work properly on Android, JavaScript should be enabled!
class ContextMenu {
///Event fired when the context menu for this WebView is being built.
///
///[hitTestResult] represents the hit result for hitting an HTML elements.
final void Function(dynamic hitTestResult)? onCreateContextMenu;
///Event fired when the context menu for this WebView is being hidden.
final void Function()? onHideContextMenu;
///Event fired when a context menu item has been clicked.
///
///[contextMenuItemClicked] represents the [ContextMenuItem] clicked.
final void Function(ContextMenuItem contextMenuItemClicked)?
onContextMenuActionItemClicked;
///Context menu options.
final ContextMenuOptions? options;
///List of the custom [ContextMenuItem].
final List<ContextMenuItem> menuItems;
ContextMenu(
{this.menuItems = const [],
this.onCreateContextMenu,
this.onHideContextMenu,
this.options,
this.onContextMenuActionItemClicked});
Map<String, dynamic> toMap() {
return {
'menuItems': menuItems.map((menuItem) => menuItem.toMap()).toList(),
'options': options?.toMap()
};
}
Map<String, dynamic> toJson() {
return toMap();
}
@override
String toString() {
return toMap().toString();
}
}
///Class that represent an item of the [ContextMenu].
class ContextMenuItem {
///Android menu item ID.
int? androidId;
///iOS menu item ID.
String? iosId;
///Menu item title.
String title;
///Menu item action that will be called when an user clicks on it.
Function()? action;
ContextMenuItem(
{this.androidId, this.iosId, required this.title, this.action});
Map<String, dynamic> toMap() {
return {'androidId': androidId, 'iosId': iosId, 'title': title};
}
Map<String, dynamic> toJson() {
return toMap();
}
@override
String toString() {
return toMap().toString();
}
}
///Class that represents available options used by [ContextMenu].
class ContextMenuOptions {
///Whether all the default system context menu items should be hidden or not. The default value is `false`.
bool hideDefaultSystemContextMenuItems;
ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false});
Map<String, dynamic> toMap() {
return {
'hideDefaultSystemContextMenuItems': hideDefaultSystemContextMenuItems
};
}
Map<String, dynamic> toJson() {
return toMap();
}
@override
String toString() {
return toMap().toString();
}
}
///Class that represents contains the constants for the times at which to inject script content into a [WebView] used by an [UserScript].
class UserScriptInjectionTime {
final int _value;
const UserScriptInjectionTime._internal(this._value);
static final Set<UserScriptInjectionTime> values = {
UserScriptInjectionTime.AT_DOCUMENT_START,
UserScriptInjectionTime.AT_DOCUMENT_END,
};
static UserScriptInjectionTime? fromValue(int? value) {
if (value != null) {
try {
return UserScriptInjectionTime.values
.firstWhere((element) => element.toValue() == value);
} catch (e) {
return null;
}
}
return null;
}
int toValue() => _value;
@override
String toString() {
switch (_value) {
case 1:
return 'AT_DOCUMENT_END';
case 0:
default:
return 'AT_DOCUMENT_START';
}
}
///**NOTE for iOS**: A constant to inject the script after the creation of the webpages document element, but before loading any other content.
///
///**NOTE for Android**: A constant to try to inject the script as soon as the page starts loading.
static const AT_DOCUMENT_START = UserScriptInjectionTime._internal(0);
///**NOTE for iOS**: A constant to inject the script after the document finishes loading, but before loading any other subresources.
///
///**NOTE for Android**: A constant to inject the script as soon as the page finishes loading.
static const AT_DOCUMENT_END = UserScriptInjectionTime._internal(1);
@override
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
}
///Class that represents a script that the [WebView] injects into the web page.
class UserScript {
///The scripts group name.
String? groupName;
///The scripts source code.
String source;
///The time at which to inject the script into the [WebView].
UserScriptInjectionTime injectionTime;
///A Boolean value that indicates whether to inject the script into the main frame.
///Specify true to inject the script only into the main frame, or false to inject it into all frames.
///The default value is `true`.
///
///**NOTE**: available only on iOS.
bool iosForMainFrameOnly;
///A scope of execution in which to evaluate the script to prevent conflicts between different scripts.
///For more information about content worlds, see [ContentWorld].
late ContentWorld contentWorld;
UserScript(
{this.groupName,
required this.source,
required this.injectionTime,
this.iosForMainFrameOnly = true,
ContentWorld? contentWorld}) {
this.contentWorld = contentWorld ?? ContentWorld.PAGE;
}
Map<String, dynamic> toMap() {
return {
'groupName': groupName,
'source': source,
'injectionTime': injectionTime.toValue(),
'iosForMainFrameOnly': iosForMainFrameOnly,
'contentWorld': contentWorld.toMap()
};
}
Map<String, dynamic> toJson() {
return toMap();
}
@override
String toString() {
return toMap().toString();
}
}
final _contentWorldNameRegExp = RegExp(r'[\s]');
///Class that represents an object that defines a scope of execution for JavaScript code and which you use to prevent conflicts between different scripts.
///
///**NOTE for iOS**: available on iOS 14.0+. This class represents the native [WKContentWorld](https://developer.apple.com/documentation/webkit/wkcontentworld) class.
///
///**NOTE for Android**: it will create and append an `<iframe>` HTML element with `id` attribute equals to `flutter_inappwebview_[name]`
///to the webpage's content that contains only the inline `<script>` HTML elements in order to define a new scope of execution for JavaScript code.
///Unfortunately, there isn't any other way to do it.
///There are some limitations:
///- for any [ContentWorld], except [ContentWorld.PAGE] (that is the webpage itself), if you need to access to the `window` or `document` global Object,
///you need to use `window.top` and `window.top.document` because the code runs inside an `<iframe>`;
///- also, the execution of the inline `<script>` could be blocked by the `Content-Security-Policy` header.
class ContentWorld {
///The name of a custom content world.
///It cannot contain space characters.
final String name;
///Returns the custom content world with the specified name.
ContentWorld.world({required this.name}) {
// WINDOW-ID- is used internally by the plugin!
assert(!name.startsWith('WINDOW-ID-') &&
!name.contains(_contentWorldNameRegExp));
}
///The default world for clients.
// ignore: non_constant_identifier_names
static final ContentWorld DEFAULT_CLIENT =
ContentWorld.world(name: 'defaultClient');
///The content world for the current webpages content.
///This property contains the content world for scripts that the current webpage executes.
///Be careful when manipulating variables in this content world.
///If you modify a variable with the same name as one the webpage uses, you may unintentionally disrupt the normal operation of that page.
// ignore: non_constant_identifier_names
static final ContentWorld PAGE = ContentWorld.world(name: 'page');
Map<String, dynamic> toMap() {
return {'name': name};
}
Map<String, dynamic> toJson() {
return toMap();
}
@override
String toString() {
return toMap().toString();
}
}