diff --git a/.gitignore b/.gitignore index 3aaaba5e..69299fc0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ build/ .flutter-plugins -.flutter-plugins-dependencies \ No newline at end of file +.flutter-plugins-dependencies diff --git a/example/lib/main.dart b/example/lib/main.dart index 85057082..79053bab 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -68,6 +68,9 @@ class _HtmlEditorExampleState extends State { children: [ HtmlEditor( controller: controller, + onScrollToTop: () { + print('scroll to top'); + }, htmlEditorOptions: HtmlEditorOptions( hint: 'Your text here...', shouldEnsureVisible: true, diff --git a/example/pubspec.lock b/example/pubspec.lock index b98a159b..34709ab6 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,77 +5,88 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: "1989d917fbe8e6b39806207df5a3fdd3d816cbd090fac2ce26fb45e9a71476e5" + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" source: hosted version: "2.0.1" file_picker: dependency: transitive description: name: file_picker - url: "https://pub.dartlang.org" + sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 + url: "https://pub.dev" source: hosted version: "5.2.5" flex_color_picker: dependency: transitive description: name: flex_color_picker - url: "https://pub.dartlang.org" + sha256: "40c1cbf8426a05c2b418ecf6c0fce386429fd7f9d238abbb2182985e8e6c5596" + url: "https://pub.dev" source: hosted version: "3.0.2" flex_seed_scheme: dependency: transitive description: name: flex_seed_scheme - url: "https://pub.dartlang.org" + sha256: "7ded1dbf0cef4d9d27a194ad021f4755cd4a82a3c5f10e803dca84d9843fd639" + url: "https://pub.dev" source: hosted version: "1.1.0" flutter: @@ -87,21 +98,16 @@ packages: dependency: transitive description: name: flutter_inappwebview - url: "https://pub.dartlang.org" + sha256: dcbaeeac2e47d5c4649a456b009a2fe230f9c35e33c3124ca16f868b4c789a2e + url: "https://pub.dev" source: hosted version: "5.7.2+3" flutter_keyboard_visibility: dependency: transitive description: name: flutter_keyboard_visibility - url: "https://pub.dartlang.org" - source: hosted - version: "5.4.0" - flutter_keyboard_visibility_linux: - dependency: transitive - description: - name: flutter_keyboard_visibility_linux - url: "https://pub.dartlang.org" + sha256: "5c5c2bf049e0f8b61c6bb6c317e3bf6142d238ab6711841f829e7432c568cc00" + url: "https://pub.dev" source: hosted version: "1.0.0" flutter_keyboard_visibility_macos: @@ -115,14 +121,16 @@ packages: dependency: transitive description: name: flutter_keyboard_visibility_platform_interface - url: "https://pub.dartlang.org" + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_keyboard_visibility_web: dependency: transitive description: name: flutter_keyboard_visibility_web - url: "https://pub.dartlang.org" + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_keyboard_visibility_windows: @@ -136,7 +144,8 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + url: "https://pub.dev" source: hosted version: "2.0.7" flutter_test: @@ -160,70 +169,80 @@ packages: dependency: transitive description: name: infinite_listview - url: "https://pub.dartlang.org" + sha256: f6062c1720eb59be553dfa6b89813d3e8dd2f054538445aaa5edaddfa5195ce6 + url: "https://pub.dev" source: hosted version: "1.1.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.7" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" numberpicker: dependency: transitive description: name: numberpicker - url: "https://pub.dartlang.org" + sha256: "73723bd13c940ebcd9e5f0ed56b4874588c1748a9a6a38254f97ad627715142e" + url: "https://pub.dev" source: hosted version: "2.1.1" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" source: hosted version: "1.11.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pointer_interceptor: dependency: transitive description: name: pointer_interceptor - url: "https://pub.dartlang.org" + sha256: eb58f5b0ed416067735c49b3187f9c5efe96ae85f628f3f77e7fb02db92a1805 + url: "https://pub.dev" source: hosted version: "0.9.3+3" sky_engine: @@ -235,65 +254,74 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.5.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" visibility_detector: dependency: transitive description: name: visibility_detector - url: "https://pub.dartlang.org" + sha256: "15c54a459ec2c17b4705450483f3d5a2858e733aee893dcee9d75fd04814940d" + url: "https://pub.dev" source: hosted version: "0.3.3" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + url: "https://pub.dev" source: hosted version: "3.1.3" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.3.0" diff --git a/lib/src/html_editor_controller_mobile.dart b/lib/src/html_editor_controller_mobile.dart index 7210d11c..a892b463 100644 --- a/lib/src/html_editor_controller_mobile.dart +++ b/lib/src/html_editor_controller_mobile.dart @@ -63,6 +63,11 @@ class HtmlEditorController extends unsupported.HtmlEditorController { "document.execCommand('$command', false${argument == null ? "" : ", '$argument'"});"); } + @override + void evaluateJavascript(String js) { + _evaluateJavascript(source: '$js;'); + } + /// Gets the text from the editor and returns it as a [String]. @override Future getText() async { @@ -95,7 +100,7 @@ class HtmlEditorController extends unsupported.HtmlEditorController { /// Sets the focus to the editor. @override - void setFocus() { + void setFocus() async { _evaluateJavascript(source: "\$('#summernote-2').summernote('focus');"); } @@ -217,6 +222,15 @@ class HtmlEditorController extends unsupported.HtmlEditorController { "var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', height);"); } + /// Set the height of the editor scale with the height of the html content + /// Adapt the webview height to the height of the html content + @override + void recalculateHeightWithNoScroll() { + _evaluateJavascript( + source: + "var lastRange = \$('.div.note-editable').summernote('editor.getLastRange');console.log('TZANOU', \$('div.note-editable').html(), lastRange);var height = document.querySelector('div.note-editable').scrollHeight; window.flutter_inappwebview.callHandler('recalculateHeightWithNoScroll', height);"); + } + /// Add a notification to the bottom of the editor. This is styled similar to /// Bootstrap alerts. You can set the HTML to be displayed in the alert, /// and the notificationType determines how the alert is displayed. diff --git a/lib/src/html_editor_controller_unsupported.dart b/lib/src/html_editor_controller_unsupported.dart index 618cbf1a..c1b60061 100644 --- a/lib/src/html_editor_controller_unsupported.dart +++ b/lib/src/html_editor_controller_unsupported.dart @@ -81,6 +81,8 @@ class HtmlEditorController { /// A function to quickly call a document.execCommand function in a readable format void execCommand(String command, {String? argument}) {} + void evaluateJavascript(String js) {} + /// A function to execute JS passed as a [WebScript] to the editor. This should /// only be used on Flutter Web. Future evaluateJavascriptWeb(String name, @@ -117,6 +119,10 @@ class HtmlEditorController { /// This method will not do anything if [autoAdjustHeight] is turned off. void recalculateHeight() {} + /// Set the height of the editor scale with the height of the html content + /// Adapt the webview height to the height of the html content + void recalculateHeightWithNoScroll() {} + /// Redoes the last action void redo() {} diff --git a/lib/src/html_editor_mobile.dart b/lib/src/html_editor_mobile.dart index 50faf109..982c14b6 100644 --- a/lib/src/html_editor_mobile.dart +++ b/lib/src/html_editor_mobile.dart @@ -10,17 +10,21 @@ class HtmlEditor extends StatelessWidget { HtmlEditor({ Key? key, required this.controller, + required this.onScrollToTop, this.callbacks, this.htmlEditorOptions = const HtmlEditorOptions(), this.htmlToolbarOptions = const HtmlToolbarOptions(), this.otherOptions = const OtherOptions(), this.plugins = const [], + this.focusScopeNode, }) : super(key: key); /// The controller that is passed to the widget, which allows multiple [HtmlEditor] /// widgets to be used on the same page independently. final HtmlEditorController controller; + final VoidCallback onScrollToTop; + /// Sets & activates Summernote's callbacks. See the functions available in /// [Callbacks] for more details. final Callbacks? callbacks; @@ -37,17 +41,22 @@ class HtmlEditor extends StatelessWidget { /// Sets the list of Summernote plugins enabled in the editor. final List plugins; + /// FocusScopeNode for the editor (focusNode of the editor should be focusScopeNode.next()) + final FocusScopeNode? focusScopeNode; + @override Widget build(BuildContext context) { if (!kIsWeb) { return HtmlEditorWidget( key: key, controller: controller, + onScrollToTop: onScrollToTop, callbacks: callbacks, plugins: plugins, htmlEditorOptions: htmlEditorOptions, htmlToolbarOptions: htmlToolbarOptions, otherOptions: otherOptions, + focusScopeNode: focusScopeNode, ); } else { return Text( diff --git a/lib/src/html_editor_unsupported.dart b/lib/src/html_editor_unsupported.dart index abc6239a..c079ef86 100644 --- a/lib/src/html_editor_unsupported.dart +++ b/lib/src/html_editor_unsupported.dart @@ -6,17 +6,22 @@ class HtmlEditor extends StatelessWidget { HtmlEditor({ Key? key, required this.controller, + required this.onScrollToTop, this.callbacks, this.htmlEditorOptions = const HtmlEditorOptions(), this.htmlToolbarOptions = const HtmlToolbarOptions(), this.otherOptions = const OtherOptions(), this.plugins = const [], + this.focusScopeNode, }) : super(key: key); /// The controller that is passed to the widget, which allows multiple [HtmlEditor] /// widgets to be used on the same page independently. final HtmlEditorController controller; + /// Scroll to top callback + final VoidCallback onScrollToTop; + /// Sets & activates Summernote's callbacks. See the functions available in /// [Callbacks] for more details. final Callbacks? callbacks; @@ -33,6 +38,9 @@ class HtmlEditor extends StatelessWidget { /// Sets the list of Summernote plugins enabled in the editor. final List plugins; + /// FocusScopeNode for the editor (focusNode of the editor should be focusScopeNode.next()) + final FocusScopeNode? focusScopeNode; + @override Widget build(BuildContext context) { return Text('Unsupported in this environment'); diff --git a/lib/src/widgets/html_editor_widget_mobile.dart b/lib/src/widgets/html_editor_widget_mobile.dart index a2458ca8..0dc815cf 100644 --- a/lib/src/widgets/html_editor_widget_mobile.dart +++ b/lib/src/widgets/html_editor_widget_mobile.dart @@ -1,3 +1,5 @@ +// ignore_for_file: omit_local_variable_types + import 'dart:async'; import 'dart:collection'; import 'dart:math'; @@ -5,7 +7,6 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:html_editor_enhanced/html_editor.dart' @@ -18,20 +19,23 @@ class HtmlEditorWidget extends StatefulWidget { HtmlEditorWidget({ Key? key, required this.controller, + required this.onScrollToTop, this.callbacks, required this.plugins, required this.htmlEditorOptions, required this.htmlToolbarOptions, required this.otherOptions, + this.focusScopeNode, }) : super(key: key); final HtmlEditorController controller; + final VoidCallback onScrollToTop; final Callbacks? callbacks; final List plugins; final HtmlEditorOptions htmlEditorOptions; final HtmlToolbarOptions htmlToolbarOptions; final OtherOptions otherOptions; - + final FocusScopeNode? focusScopeNode; @override _HtmlEditorWidgetMobileState createState() => _HtmlEditorWidgetMobileState(); } @@ -46,6 +50,9 @@ class _HtmlEditorWidgetMobileState extends State { /// The height of the document loaded in the editor late double docHeight; + /// The initial height of the document loaded in the editor + late double initialdocHeight; + /// The file path to the html code late String filePath; @@ -64,9 +71,14 @@ class _HtmlEditorWidgetMobileState extends State { /// the editor is focused much after its visibility changes double? cachedVisibleDecimal; + /// FocusScopeNode for the editor (focusNode of the editor should be focusScopeNode.next()) + late FocusScopeNode focusScopeNode; + @override void initState() { docHeight = widget.otherOptions.height; + initialdocHeight = widget.otherOptions.height; + print("initial doc height: $initialdocHeight"); key = getRandString(10); if (widget.htmlEditorOptions.filePath != null) { filePath = widget.htmlEditorOptions.filePath!; @@ -76,6 +88,10 @@ class _HtmlEditorWidgetMobileState extends State { } else { filePath = 'packages/html_editor_enhanced/assets/summernote.html'; } + + focusScopeNode = widget.focusScopeNode ?? + FocusScopeNode(debugLabel: 'HtmlEditor Focus Scope'); + super.initState(); } @@ -87,6 +103,7 @@ class _HtmlEditorWidgetMobileState extends State { /// resets the height of the editor to the original height void resetHeight() async { + print("resetting height"); if (mounted) { this.setState(() { docHeight = widget.otherOptions.height; @@ -97,12 +114,23 @@ class _HtmlEditorWidgetMobileState extends State { } } + void focusEditor() { + double? pos = Scrollable.of(context)?.position.pixels; + if (!focusScopeNode.hasFocus) { + // get the scope focused + focusScopeNode.requestFocus(); + } + //the only children of the scope should be the editor + focusScopeNode.nextFocus(); + + double? pos2 = Scrollable.of(context)?.position.pixels; + Scrollable.of(context)?.position.jumpTo(pos ?? 0); + } + @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - SystemChannels.textInput.invokeMethod('TextInput.hide'); - }, + return FocusScope.withExternalFocusNode( + focusScopeNode: focusScopeNode, child: VisibilityDetector( key: Key(key), onVisibilityChanged: (VisibilityInfo info) async { @@ -129,418 +157,402 @@ class _HtmlEditorWidgetMobileState extends State { callbacks: widget.callbacks) : Container(height: 0, width: 0), Expanded( - child: InAppWebView( - initialFile: filePath, - onWebViewCreated: (InAppWebViewController controller) { - widget.controller.editorController = controller; - controller.addJavaScriptHandler( - handlerName: 'FormatSettings', - callback: (e) { - var json = e[0] as Map; - print(json); - if (widget.controller.toolbar != null) { - widget.controller.toolbar!.updateToolbar(json); - } - }); - }, - initialOptions: InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions( - javaScriptEnabled: true, - transparentBackground: true, - useShouldOverrideUrlLoading: true, - ), - android: AndroidInAppWebViewOptions( - useHybridComposition: widget - .htmlEditorOptions.androidUseHybridComposition, - loadWithOverviewMode: true, - )), - initialUserScripts: - widget.htmlEditorOptions.mobileInitialScripts - as UnmodifiableListView?, - contextMenu: widget.htmlEditorOptions.mobileContextMenu - as ContextMenu?, - gestureRecognizers: { - Factory( - () => VerticalDragGestureRecognizer()), - Factory(() => - LongPressGestureRecognizer( - duration: widget - .htmlEditorOptions.mobileLongPressDuration)), - }, - shouldOverrideUrlLoading: (controller, action) async { - if (!action.request.url.toString().contains(filePath)) { - return (await widget.callbacks?.onNavigationRequestMobile - ?.call(action.request.url.toString())) - as NavigationActionPolicy? ?? - NavigationActionPolicy.ALLOW; - } - return NavigationActionPolicy.ALLOW; - }, - onConsoleMessage: (controller, message) { - print(message.message); - }, - onWindowFocus: (controller) async { - if (widget.htmlEditorOptions.shouldEnsureVisible && - Scrollable.of(context) != null) { - await Scrollable.of(context)!.position.ensureVisible( - context.findRenderObject()!, - ); - } - if (widget.htmlEditorOptions.adjustHeightForKeyboard && - mounted && - !visibleStream.isClosed) { - Future setHeightJS() async { - await controller.evaluateJavascript(source: """ - \$('div.note-editable').outerHeight(${max(docHeight - (toolbarKey.currentContext?.size?.height ?? 0), 30)}); - // from https://stackoverflow.com/a/67152280 - var selection = window.getSelection(); - if (selection.rangeCount) { - var firstRange = selection.getRangeAt(0); - if (firstRange.commonAncestorContainer !== document) { - var tempAnchorEl = document.createElement('br'); - firstRange.insertNode(tempAnchorEl); - tempAnchorEl.scrollIntoView({ - block: 'end', - }); - tempAnchorEl.remove(); - } - } - """); - } + child: KeyboardVisibilityBuilder( + builder: (context, isKeyboardVisible) { + if (isKeyboardVisible) { + // build layout for visible keyboard - /// this is a workaround so jumping between focus on different - /// editable elements still resizes the editor - if ((cachedVisibleDecimal ?? 0) > 0.1) { - this.setState(() { - docHeight = widget.otherOptions.height * - cachedVisibleDecimal!; - }); - await setHeightJS(); - } - var visibleDecimal = await visibleStream.stream.first; - var newHeight = widget.otherOptions.height; - if (visibleDecimal > 0.1) { - this.setState(() { - docHeight = newHeight * visibleDecimal; - }); - //todo add support for traditional summernote controls again? - await setHeightJS(); + //FIX: scroll to 0 on focus, it help the automatic scroll of IOs on click with the keyboard + + widget.controller.editorController?.scrollTo(x: 0, y: 0); + } + + return InAppWebView( + initialFile: filePath, + onWebViewCreated: (InAppWebViewController controller) { + widget.controller.editorController = controller; + controller.addJavaScriptHandler( + handlerName: 'FormatSettings', + callback: (e) { + var json = e[0] as Map; + print(json); + if (widget.controller.toolbar != null) { + widget.controller.toolbar!.updateToolbar(json); + } + }); + }, + initialOptions: InAppWebViewGroupOptions( + crossPlatform: InAppWebViewOptions( + disableVerticalScroll: true, + horizontalScrollBarEnabled: false, + disableHorizontalScroll: true, + verticalScrollBarEnabled: false, + javaScriptEnabled: true, + transparentBackground: true, + useShouldOverrideUrlLoading: true, + ), + ios: IOSInAppWebViewOptions(scrollsToTop: false), + android: AndroidInAppWebViewOptions( + useHybridComposition: widget + .htmlEditorOptions.androidUseHybridComposition, + loadWithOverviewMode: true, + )), + // initialUserScripts: + // widget.htmlEditorOptions.mobileInitialScripts + // as UnmodifiableListView?, + contextMenu: widget.htmlEditorOptions.mobileContextMenu + as ContextMenu?, + gestureRecognizers: { + // Factory( + // () => VerticalDragGestureRecognizer()), + Factory(() => + LongPressGestureRecognizer( + duration: widget + .htmlEditorOptions.mobileLongPressDuration)), + }, + shouldOverrideUrlLoading: (controller, action) async { + if (!action.request.url.toString().contains(filePath)) { + return (await widget + .callbacks?.onNavigationRequestMobile + ?.call(action.request.url.toString())) + as NavigationActionPolicy? ?? + NavigationActionPolicy.ALLOW; } - } - }, - onLoadStop: - (InAppWebViewController controller, Uri? uri) async { - var url = uri.toString(); - var maximumFileSize = 10485760; - if (url.contains(filePath)) { - var summernoteToolbar = '[\n'; - var summernoteCallbacks = '''callbacks: { - onKeydown: function(e) { - var chars = \$(".note-editable").text(); - var totalChars = chars.length; - ${widget.htmlEditorOptions.characterLimit != null ? '''allowedKeys = ( - e.which === 8 || /* BACKSPACE */ - e.which === 35 || /* END */ - e.which === 36 || /* HOME */ - e.which === 37 || /* LEFT */ - e.which === 38 || /* UP */ - e.which === 39 || /* RIGHT*/ - e.which === 40 || /* DOWN */ - e.which === 46 || /* DEL*/ - e.ctrlKey === true && e.which === 65 || /* CTRL + A */ - e.ctrlKey === true && e.which === 88 || /* CTRL + X */ - e.ctrlKey === true && e.which === 67 || /* CTRL + C */ - e.ctrlKey === true && e.which === 86 || /* CTRL + V */ - e.ctrlKey === true && e.which === 90 /* CTRL + Z */ - ); - if (!allowedKeys && \$(e.target).text().length >= ${widget.htmlEditorOptions.characterLimit}) { - e.preventDefault(); - }''' : ''} - window.flutter_inappwebview.callHandler('totalChars', totalChars); - }, - '''; - if (widget.plugins.isNotEmpty) { - summernoteToolbar = summernoteToolbar + "['plugins', ["; - for (var p in widget.plugins) { - summernoteToolbar = summernoteToolbar + - (p.getToolbarString().isNotEmpty - ? "'${p.getToolbarString()}'" - : '') + - (p == widget.plugins.last - ? ']]\n' - : p.getToolbarString().isNotEmpty - ? ', ' - : ''); - if (p is SummernoteAtMention) { - summernoteCallbacks = summernoteCallbacks + - """ - \nsummernoteAtMention: { - getSuggestions: async function(value) { - var result = await window.flutter_inappwebview.callHandler('getSuggestions', value); - var resultList = result.split(','); - return resultList; - }, - onSelect: (value) => { - window.flutter_inappwebview.callHandler('onSelectMention', value); + return NavigationActionPolicy.ALLOW; + }, + onConsoleMessage: (controller, message) { + print(message.message); + }, + onWindowFocus: (controller) async { + focusEditor(); + + /// Function to log the full html in debug console + // controller.evaluateJavascript(source: ''' + // // window.onscroll = function() {}; + // var tzanouHtml = \$('html').html(); + // for(var i = 0; i < tzanouHtml.length/100;i++) { + // console.log(tzanouHtml.substring(i*100,(i+1)*100)); + // } + // '''); + }, + onLoadStop: + (InAppWebViewController controller, Uri? uri) async { + var url = uri.toString(); + var maximumFileSize = 10485760; + if (url.contains(filePath)) { + var summernoteToolbar = '[\n'; + var summernoteCallbacks = '''callbacks: { + onKeydown: function(e) { + var chars = \$(".note-editable").text(); + var totalChars = chars.length; + ${widget.htmlEditorOptions.characterLimit != null ? '''allowedKeys = ( + e.which === 8 || /* BACKSPACE */ + e.which === 35 || /* END */ + e.which === 36 || /* HOME */ + e.which === 37 || /* LEFT */ + e.which === 38 || /* UP */ + e.which === 39 || /* RIGHT*/ + e.which === 40 || /* DOWN */ + e.which === 46 || /* DEL*/ + e.ctrlKey === true && e.which === 65 || /* CTRL + A */ + e.ctrlKey === true && e.which === 88 || /* CTRL + X */ + e.ctrlKey === true && e.which === 67 || /* CTRL + C */ + e.ctrlKey === true && e.which === 86 || /* CTRL + V */ + e.ctrlKey === true && e.which === 90 /* CTRL + Z */ + ); + if (!allowedKeys && \$(e.target).text().length >= ${widget.htmlEditorOptions.characterLimit}) { + e.preventDefault(); + }''' : ''} + window.flutter_inappwebview.callHandler('totalChars', totalChars); + }, + '''; + + if (widget.plugins.isNotEmpty) { + summernoteToolbar = + summernoteToolbar + "['plugins', ["; + for (var p in widget.plugins) { + summernoteToolbar = summernoteToolbar + + (p.getToolbarString().isNotEmpty + ? "'${p.getToolbarString()}'" + : '') + + (p == widget.plugins.last + ? ']]\n' + : p.getToolbarString().isNotEmpty + ? ', ' + : ''); + if (p is SummernoteAtMention) { + summernoteCallbacks = summernoteCallbacks + + """ + \nsummernoteAtMention: { + getSuggestions: async function(value) { + var result = await window.flutter_inappwebview.callHandler('getSuggestions', value); + var resultList = result.split(','); + return resultList; + }, + onSelect: (value) => { + window.flutter_inappwebview.callHandler('onSelectMention', value); + }, }, - }, - """; - controller.addJavaScriptHandler( - handlerName: 'getSuggestions', - callback: (value) { - return p.getSuggestionsMobile! - .call(value.first.toString()) - .toString() - .replaceAll('[', '') - .replaceAll(']', ''); - }); - if (p.onSelect != null) { + """; controller.addJavaScriptHandler( - handlerName: 'onSelectMention', + handlerName: 'getSuggestions', callback: (value) { - p.onSelect!.call(value.first.toString()); + return p.getSuggestionsMobile! + .call(value.first.toString()) + .toString() + .replaceAll('[', '') + .replaceAll(']', ''); }); + if (p.onSelect != null) { + controller.addJavaScriptHandler( + handlerName: 'onSelectMention', + callback: (value) { + p.onSelect!.call(value.first.toString()); + }); + } } } } - } - if (widget.callbacks != null) { - if (widget.callbacks!.onImageLinkInsert != null) { - summernoteCallbacks = summernoteCallbacks + - """ - onImageLinkInsert: function(url) { - window.flutter_inappwebview.callHandler('onImageLinkInsert', url); - }, - """; - } - if (widget.callbacks!.onImageUpload != null) { - summernoteCallbacks = summernoteCallbacks + - """ - onImageUpload: function(files) { - var reader = new FileReader(); - var base64 = ""; - reader.onload = function (_) { - base64 = reader.result; - var newObject = { - 'lastModified': files[0].lastModified, - 'lastModifiedDate': files[0].lastModifiedDate, - 'name': files[0].name, - 'size': files[0].size, - 'type': files[0].type, - 'base64': base64 - }; - window.flutter_inappwebview.callHandler('onImageUpload', JSON.stringify(newObject)); - }; - reader.onerror = function (_) { - var newObject = { - 'lastModified': files[0].lastModified, - 'lastModifiedDate': files[0].lastModifiedDate, - 'name': files[0].name, - 'size': files[0].size, - 'type': files[0].type, - 'base64': base64 + if (widget.callbacks != null) { + if (widget.callbacks!.onImageLinkInsert != null) { + summernoteCallbacks = summernoteCallbacks + + """ + onImageLinkInsert: function(url) { + window.flutter_inappwebview.callHandler('onImageLinkInsert', url); + }, + """; + } + if (widget.callbacks!.onImageUpload != null) { + summernoteCallbacks = summernoteCallbacks + + """ + onImageUpload: function(files) { + var reader = new FileReader(); + var base64 = ""; + reader.onload = function (_) { + base64 = reader.result; + var newObject = { + 'lastModified': files[0].lastModified, + 'lastModifiedDate': files[0].lastModifiedDate, + 'name': files[0].name, + 'size': files[0].size, + 'type': files[0].type, + 'base64': base64 + }; + window.flutter_inappwebview.callHandler('onImageUpload', JSON.stringify(newObject)); }; - window.flutter_inappwebview.callHandler('onImageUpload', JSON.stringify(newObject)); - }; - reader.readAsDataURL(files[0]); - }, - """; - } - if (widget.callbacks!.onImageUploadError != null) { - summernoteCallbacks = summernoteCallbacks + - """ - onImageUploadError: function(file, error) { - if (typeof file === 'string') { - window.flutter_inappwebview.callHandler('onImageUploadError', file, error); - } else { + reader.onerror = function (_) { var newObject = { - 'lastModified': file.lastModified, - 'lastModifiedDate': file.lastModifiedDate, - 'name': file.name, - 'size': file.size, - 'type': file.type, + 'lastModified': files[0].lastModified, + 'lastModifiedDate': files[0].lastModifiedDate, + 'name': files[0].name, + 'size': files[0].size, + 'type': files[0].type, + 'base64': base64 }; - window.flutter_inappwebview.callHandler('onImageUploadError', JSON.stringify(newObject), error); - } + window.flutter_inappwebview.callHandler('onImageUpload', JSON.stringify(newObject)); + }; + reader.readAsDataURL(files[0]); }, - """; + """; + } + if (widget.callbacks!.onImageUploadError != null) { + summernoteCallbacks = summernoteCallbacks + + """ + onImageUploadError: function(file, error) { + if (typeof file === 'string') { + window.flutter_inappwebview.callHandler('onImageUploadError', file, error); + } else { + var newObject = { + 'lastModified': file.lastModified, + 'lastModifiedDate': file.lastModifiedDate, + 'name': file.name, + 'size': file.size, + 'type': file.type, + }; + window.flutter_inappwebview.callHandler('onImageUploadError', JSON.stringify(newObject), error); + } + }, + """; + } } - } - summernoteToolbar = summernoteToolbar + '],'; - summernoteCallbacks = summernoteCallbacks + '}'; - await controller.evaluateJavascript(source: """ - \$('#summernote-2').summernote({ - placeholder: "${widget.htmlEditorOptions.hint ?? ""}", - tabsize: 2, - height: ${widget.otherOptions.height - (toolbarKey.currentContext?.size?.height ?? 0)}, - toolbar: $summernoteToolbar - disableGrammar: false, - spellCheck: ${widget.htmlEditorOptions.spellCheck}, - maximumFileSize: $maximumFileSize, - ${widget.htmlEditorOptions.customOptions} - $summernoteCallbacks - }); - - \$('#summernote-2').on('summernote.change', function(_, contents, \$editable) { - window.flutter_inappwebview.callHandler('onChangeContent', contents); - }); - - function onSelectionChange() { - let {anchorNode, anchorOffset, focusNode, focusOffset} = document.getSelection(); - var isBold = false; - var isItalic = false; - var isUnderline = false; - var isStrikethrough = false; - var isSuperscript = false; - var isSubscript = false; - var isUL = false; - var isOL = false; - var isLeft = false; - var isRight = false; - var isCenter = false; - var isFull = false; - var parent; - var fontName; - var fontSize = 16; - var foreColor = "000000"; - var backColor = "FFFF00"; - var focusNode2 = \$(window.getSelection().focusNode); - var parentList = focusNode2.closest("div.note-editable ol, div.note-editable ul"); - var parentListType = parentList.css('list-style-type'); - var lineHeight = \$(focusNode.parentNode).css('line-height'); - var direction = \$(focusNode.parentNode).css('direction'); - if (document.queryCommandState) { - isBold = document.queryCommandState('bold'); - isItalic = document.queryCommandState('italic'); - isUnderline = document.queryCommandState('underline'); - isStrikethrough = document.queryCommandState('strikeThrough'); - isSuperscript = document.queryCommandState('superscript'); - isSubscript = document.queryCommandState('subscript'); - isUL = document.queryCommandState('insertUnorderedList'); - isOL = document.queryCommandState('insertOrderedList'); - isLeft = document.queryCommandState('justifyLeft'); - isRight = document.queryCommandState('justifyRight'); - isCenter = document.queryCommandState('justifyCenter'); - isFull = document.queryCommandState('justifyFull'); - } - if (document.queryCommandValue) { - parent = document.queryCommandValue('formatBlock'); - fontSize = document.queryCommandValue('fontSize'); - foreColor = document.queryCommandValue('foreColor'); - backColor = document.queryCommandValue('hiliteColor'); - fontName = document.queryCommandValue('fontName'); + summernoteToolbar = summernoteToolbar + '],'; + summernoteCallbacks = summernoteCallbacks + '}'; + await controller.evaluateJavascript(source: """ + \$('#summernote-2').summernote({ + placeholder: "${widget.htmlEditorOptions.hint ?? ""}", + tabsize: 2, + height: ${widget.otherOptions.height - (toolbarKey.currentContext?.size?.height ?? 0)}, + toolbar: $summernoteToolbar + disableGrammar: false, + spellCheck: ${widget.htmlEditorOptions.spellCheck}, + maximumFileSize: $maximumFileSize, + ${widget.htmlEditorOptions.customOptions} + $summernoteCallbacks + }); + + \$('#summernote-2').on('summernote.change', function(_, contents, \$editable) { + window.flutter_inappwebview.callHandler('onChangeContent', contents); + }); + + function onSelectionChange() { + let {anchorNode, anchorOffset, focusNode, focusOffset} = document.getSelection(); + var isBold = false; + var isItalic = false; + var isUnderline = false; + var isStrikethrough = false; + var isSuperscript = false; + var isSubscript = false; + var isUL = false; + var isOL = false; + var isLeft = false; + var isRight = false; + var isCenter = false; + var isFull = false; + var parent; + var fontName; + var fontSize = 16; + var foreColor = "000000"; + var backColor = "FFFF00"; + var focusNode2 = \$(window.getSelection().focusNode); + var parentList = focusNode2.closest("div.note-editable ol, div.note-editable ul"); + var parentListType = parentList.css('list-style-type'); + var lineHeight = \$(focusNode.parentNode).css('line-height'); + var direction = \$(focusNode.parentNode).css('direction'); + if (document.queryCommandState) { + isBold = document.queryCommandState('bold'); + isItalic = document.queryCommandState('italic'); + isUnderline = document.queryCommandState('underline'); + isStrikethrough = document.queryCommandState('strikeThrough'); + isSuperscript = document.queryCommandState('superscript'); + isSubscript = document.queryCommandState('subscript'); + isUL = document.queryCommandState('insertUnorderedList'); + isOL = document.queryCommandState('insertOrderedList'); + isLeft = document.queryCommandState('justifyLeft'); + isRight = document.queryCommandState('justifyRight'); + isCenter = document.queryCommandState('justifyCenter'); + isFull = document.queryCommandState('justifyFull'); + } + if (document.queryCommandValue) { + parent = document.queryCommandValue('formatBlock'); + fontSize = document.queryCommandValue('fontSize'); + foreColor = document.queryCommandValue('foreColor'); + backColor = document.queryCommandValue('hiliteColor'); + fontName = document.queryCommandValue('fontName'); + } + var message = { + 'style': parent, + 'fontName': fontName, + 'fontSize': fontSize, + 'font': [isBold, isItalic, isUnderline], + 'miscFont': [isStrikethrough, isSuperscript, isSubscript], + 'color': [foreColor, backColor], + 'paragraph': [isUL, isOL], + 'listStyle': parentListType, + 'align': [isLeft, isCenter, isRight, isFull], + 'lineHeight': lineHeight, + 'direction': direction, + }; + window.flutter_inappwebview.callHandler('FormatSettings', message); } - var message = { - 'style': parent, - 'fontName': fontName, - 'fontSize': fontSize, - 'font': [isBold, isItalic, isUnderline], - 'miscFont': [isStrikethrough, isSuperscript, isSubscript], - 'color': [foreColor, backColor], - 'paragraph': [isUL, isOL], - 'listStyle': parentListType, - 'align': [isLeft, isCenter, isRight, isFull], - 'lineHeight': lineHeight, - 'direction': direction, - }; - window.flutter_inappwebview.callHandler('FormatSettings', message); - } - """); - await controller.evaluateJavascript( - source: - "document.onselectionchange = onSelectionChange; console.log('done');"); - await controller.evaluateJavascript( - source: - "document.getElementsByClassName('note-editable')[0].setAttribute('inputmode', '${describeEnum(widget.htmlEditorOptions.inputType)}');"); - if ((Theme.of(context).brightness == Brightness.dark || - widget.htmlEditorOptions.darkMode == true) && - widget.htmlEditorOptions.darkMode != false) { - //todo fix for iOS (https://github.com/pichillilorenzo/flutter_inappwebview/issues/695) - var darkCSS = - ''; + """); await controller.evaluateJavascript( - source: "\$('head').append('$darkCSS');"); - } - //set the text once the editor is loaded - if (widget.htmlEditorOptions.initialText != null) { - widget.controller - .setText(widget.htmlEditorOptions.initialText!); - } - //adjusts the height of the editor when it is loaded - if (widget.htmlEditorOptions.autoAdjustHeight) { + source: + "document.onselectionchange = onSelectionChange; console.log('done');"); + await controller.evaluateJavascript( + source: + "document.getElementsByClassName('note-editable')[0].setAttribute('inputmode', '${describeEnum(widget.htmlEditorOptions.inputType)}');"); + if ((Theme.of(context).brightness == Brightness.dark || + widget.htmlEditorOptions.darkMode == true) && + widget.htmlEditorOptions.darkMode != false) { + //todo fix for iOS (https://github.com/pichillilorenzo/flutter_inappwebview/issues/695) + var darkCSS = + ''; + await controller.evaluateJavascript( + source: "\$('head').append('$darkCSS');"); + } + //set the text once the editor is loaded + if (widget.htmlEditorOptions.initialText != null) { + widget.controller + .setText(widget.htmlEditorOptions.initialText!); + } + //adjusts the height of the editor when it is loaded + if (widget.htmlEditorOptions.autoAdjustHeight) { + controller.addJavaScriptHandler( + handlerName: 'setHeight', + callback: (height) { + if (height.first == 'reset') { + resetHeight(); + } else { + setState(mounted, this.setState, () { + docHeight = (double.tryParse( + height.first.toString()) ?? + widget.otherOptions.height) + + (toolbarKey + .currentContext?.size?.height ?? + 0); + }); + } + }); + } + controller.addJavaScriptHandler( - handlerName: 'setHeight', + handlerName: 'recalculateHeightWithNoScroll', callback: (height) { - if (height.first == 'reset') { - resetHeight(); + print("initialdocHeight ${initialdocHeight}"); + print("docheight ${docHeight}"); + print("height ${height.first}"); + if (height.first > initialdocHeight) { + int newHeight = height.first - 22; + if (newHeight > docHeight) { + setState(mounted, this.setState, () { + docHeight = double.tryParse( + (newHeight + 500).toString()) ?? + 0; + }); + } } else { - setState(mounted, this.setState, () { - docHeight = (double.tryParse( - height.first.toString()) ?? - widget.otherOptions.height) + - (toolbarKey - .currentContext?.size?.height ?? - 0); + docHeight = initialdocHeight; + } + }); + widget.controller.editorController! + .addJavaScriptHandler( + handlerName: 'totalChars', + callback: (keyCode) { + widget.controller.characterCount = + keyCode.first as int; }); + //disable editor if necessary + if (widget.htmlEditorOptions.disabled && + !callbacksInitialized) { + widget.controller.disable(); + } + //initialize callbacks + if (widget.callbacks != null && !callbacksInitialized) { + addJSCallbacks(widget.callbacks!); + addJSHandlers(widget.callbacks!); + callbacksInitialized = true; + } + //call onInit callback + if (widget.callbacks != null && + widget.callbacks!.onInit != null) { + widget.callbacks!.onInit!.call(); + } + //add onChange handler + controller.addJavaScriptHandler( + handlerName: 'onChangeContent', + callback: (contents) { + if (widget.callbacks != null && + widget.callbacks!.onChangeContent != null) { + widget.callbacks!.onChangeContent! + .call(contents.first.toString()); } }); - await controller.evaluateJavascript( - source: - "var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', height);"); } - //reset the editor's height if the keyboard disappears at any point - if (widget.htmlEditorOptions.adjustHeightForKeyboard) { - var keyboardVisibilityController = - KeyboardVisibilityController(); - keyboardVisibilityController.onChange - .listen((bool visible) { - if (!visible && mounted) { - controller.clearFocus(); - resetHeight(); - } - }); - } - widget.controller.editorController!.addJavaScriptHandler( - handlerName: 'totalChars', - callback: (keyCode) { - widget.controller.characterCount = - keyCode.first as int; - }); - //disable editor if necessary - if (widget.htmlEditorOptions.disabled && - !callbacksInitialized) { - widget.controller.disable(); - } - //initialize callbacks - if (widget.callbacks != null && !callbacksInitialized) { - addJSCallbacks(widget.callbacks!); - addJSHandlers(widget.callbacks!); - callbacksInitialized = true; - } - //call onInit callback - if (widget.callbacks != null && - widget.callbacks!.onInit != null) { - widget.callbacks!.onInit!.call(); - } - //add onChange handler - controller.addJavaScriptHandler( - handlerName: 'onChangeContent', - callback: (contents) { - if (widget.htmlEditorOptions.shouldEnsureVisible && - Scrollable.of(context) != null) { - Scrollable.of(context)!.position.ensureVisible( - context.findRenderObject()!, - ); - } - if (widget.callbacks != null && - widget.callbacks!.onChangeContent != null) { - widget.callbacks!.onChangeContent! - .call(contents.first.toString()); - } - }); - } - }, - ), + await controller.injectCSSCode( + source: 'blockquote { margin: 0 !important;}'); + }, + ); + }), ), widget.htmlToolbarOptions.toolbarPosition == ToolbarPosition.belowEditor diff --git a/pubspec.lock b/pubspec.lock index 88f4be47..2658df11 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,70 +5,80 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" source: hosted version: "2.0.1" file_picker: dependency: "direct main" description: name: file_picker - url: "https://pub.dartlang.org" + sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 + url: "https://pub.dev" source: hosted version: "5.2.5" flex_color_picker: dependency: "direct main" description: name: flex_color_picker - url: "https://pub.dartlang.org" + sha256: "40c1cbf8426a05c2b418ecf6c0fce386429fd7f9d238abbb2182985e8e6c5596" + url: "https://pub.dev" source: hosted version: "3.0.2" flex_seed_scheme: dependency: transitive description: name: flex_seed_scheme - url: "https://pub.dartlang.org" + sha256: "7ded1dbf0cef4d9d27a194ad021f4755cd4a82a3c5f10e803dca84d9843fd639" + url: "https://pub.dev" source: hosted version: "1.1.0" flutter: @@ -80,56 +90,64 @@ packages: dependency: "direct main" description: name: flutter_inappwebview - url: "https://pub.dartlang.org" + sha256: f73505c792cf083d5566e1a94002311be497d984b5607f25be36d685cf6361cf + url: "https://pub.dev" source: hosted version: "5.7.2+3" flutter_keyboard_visibility: dependency: "direct main" description: name: flutter_keyboard_visibility - url: "https://pub.dartlang.org" + sha256: "86b71bbaffa38e885f5c21b1182408b9be6951fd125432cf6652c636254cef2d" + url: "https://pub.dev" source: hosted version: "5.4.0" flutter_keyboard_visibility_linux: dependency: transitive description: name: flutter_keyboard_visibility_linux - url: "https://pub.dartlang.org" + sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08" + url: "https://pub.dev" source: hosted version: "1.0.0" flutter_keyboard_visibility_macos: dependency: transitive description: name: flutter_keyboard_visibility_macos - url: "https://pub.dartlang.org" + sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086 + url: "https://pub.dev" source: hosted version: "1.0.0" flutter_keyboard_visibility_platform_interface: dependency: transitive description: name: flutter_keyboard_visibility_platform_interface - url: "https://pub.dartlang.org" + sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4 + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_keyboard_visibility_web: dependency: transitive description: name: flutter_keyboard_visibility_web - url: "https://pub.dartlang.org" + sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1 + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_keyboard_visibility_windows: dependency: transitive description: name: flutter_keyboard_visibility_windows - url: "https://pub.dartlang.org" + sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73 + url: "https://pub.dev" source: hosted version: "1.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + url: "https://pub.dev" source: hosted version: "2.0.7" flutter_test: @@ -146,70 +164,80 @@ packages: dependency: transitive description: name: infinite_listview - url: "https://pub.dartlang.org" + sha256: f6062c1720eb59be553dfa6b89813d3e8dd2f054538445aaa5edaddfa5195ce6 + url: "https://pub.dev" source: hosted version: "1.1.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.7" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: "direct main" description: name: meta - url: "https://pub.dartlang.org" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" numberpicker: dependency: "direct main" description: name: numberpicker - url: "https://pub.dartlang.org" + sha256: "73723bd13c940ebcd9e5f0ed56b4874588c1748a9a6a38254f97ad627715142e" + url: "https://pub.dev" source: hosted version: "2.1.1" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" pedantic: dependency: "direct main" description: name: pedantic - url: "https://pub.dartlang.org" + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" source: hosted version: "1.11.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pointer_interceptor: dependency: "direct main" description: name: pointer_interceptor - url: "https://pub.dartlang.org" + sha256: fee6ba42b910637465bc0d367ba27066c6eccfbc3bc0ceb14831915acc600db0 + url: "https://pub.dev" source: hosted version: "0.9.3+3" sky_engine: @@ -221,65 +249,74 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.5.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" visibility_detector: dependency: "direct main" description: name: visibility_detector - url: "https://pub.dartlang.org" + sha256: "15c54a459ec2c17b4705450483f3d5a2858e733aee893dcee9d75fd04814940d" + url: "https://pub.dev" source: hosted version: "0.3.3" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + url: "https://pub.dev" source: hosted version: "3.1.3" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 82d4a1ad..582d4894 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: # plugin to show a color picker for foreground/highlight color flex_color_picker: ^3.0.2 # plugin to get files from filesystem - file_picker: ^5.2.0+1 + file_picker: ^5.2.5 # plugin to show a scrollable number picker for inserting tables numberpicker: ^2.1.1 # plugin to allow dropdowns and dialogs to be interactable when displaying over the editor @@ -43,25 +43,32 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - assets: - - packages/html_editor_enhanced/assets/summernote.html - - packages/html_editor_enhanced/assets/summernote-no-plugins.html - - packages/html_editor_enhanced/assets/summernote-lite.min.css - - packages/html_editor_enhanced/assets/summernote-lite-dark.css - - packages/html_editor_enhanced/assets/summernote-lite.min.js - - packages/html_editor_enhanced/assets/jquery.min.js - - packages/html_editor_enhanced/assets/font/summernote.eot - - packages/html_editor_enhanced/assets/font/summernote.ttf - - packages/html_editor_enhanced/assets/plugins/summernote-at-mention/summernote-at-mention.js +# assets: +# - packages/html_editor_enhanced/assets/summernote.html +# - packages/html_editor_enhanced/assets/summernote-no-plugins.html +# - packages/html_editor_enhanced/assets/summernote-lite.min.css +# - packages/html_editor_enhanced/assets/summernote-lite-dark.css +# - packages/html_editor_enhanced/assets/summernote-lite.min.js +# - packages/html_editor_enhanced/assets/jquery.min.js +# - packages/html_editor_enhanced/assets/font/summernote.eot +# - packages/html_editor_enhanced/assets/font/summernote.ttf +# - packages/html_editor_enhanced/assets/plugins/summernote-at-mention/summernote-at-mention.js # This section identifies this Flutter project as a plugin project. # The 'pluginClass' and Android 'package' identifiers should not ordinarily # be modified. They are used by the tooling to maintain consistency when # adding or updating assets for this project. # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - lib/assets/summernote.html + - lib/assets/summernote-no-plugins.html + - lib/assets/summernote-lite.min.css + - lib/assets/summernote-lite-dark.css + - lib/assets/summernote-lite.min.js + - lib/assets/jquery.min.js + - lib/assets/font/summernote.eot + - lib/assets/font/summernote.ttf + - lib/assets/plugins/summernote-at-mention/summernote-at-mention.js # # For details regarding assets in packages, see # https://flutter.dev/assets-and-images/#from-packages