From 0fa11cb6461a4b5e941000f3c0d5147fc9b30e26 Mon Sep 17 00:00:00 2001 From: Ahmed Fwela Date: Wed, 16 Feb 2022 08:18:19 +0200 Subject: [PATCH 1/3] Fix initialization logic --- lib/src/html_editor_web.dart | 1 - .../widgets/html_editor_widget_mobile.dart | 8 +- lib/src/widgets/html_editor_widget_web.dart | 108 ++++++++++-------- lib/utils/utils.dart | 4 +- pubspec.lock | 23 ++-- 5 files changed, 82 insertions(+), 62 deletions(-) diff --git a/lib/src/html_editor_web.dart b/lib/src/html_editor_web.dart index 3de5c787..d42c759f 100644 --- a/lib/src/html_editor_web.dart +++ b/lib/src/html_editor_web.dart @@ -46,7 +46,6 @@ class HtmlEditor extends StatelessWidget { htmlEditorOptions: htmlEditorOptions, htmlToolbarOptions: htmlToolbarOptions, otherOptions: otherOptions, - initBC: context, ); } else { return Text( diff --git a/lib/src/widgets/html_editor_widget_mobile.dart b/lib/src/widgets/html_editor_widget_mobile.dart index 6fe0182d..99b89064 100644 --- a/lib/src/widgets/html_editor_widget_mobile.dart +++ b/lib/src/widgets/html_editor_widget_mobile.dart @@ -66,6 +66,7 @@ class _HtmlEditorWidgetMobileState extends State { @override void initState() { + super.initState(); docHeight = widget.otherOptions.height; key = getRandString(10); if (widget.htmlEditorOptions.filePath != null) { @@ -76,7 +77,6 @@ class _HtmlEditorWidgetMobileState extends State { } else { filePath = 'packages/html_editor_enhanced/assets/summernote.html'; } - super.initState(); } @override @@ -150,7 +150,8 @@ class _HtmlEditorWidgetMobileState extends State { useShouldOverrideUrlLoading: true, ), android: AndroidInAppWebViewOptions( - useHybridComposition: widget.htmlEditorOptions.androidUseHybridComposition, + useHybridComposition: widget + .htmlEditorOptions.androidUseHybridComposition, loadWithOverviewMode: true, )), initialUserScripts: @@ -506,7 +507,8 @@ class _HtmlEditorWidgetMobileState extends State { keyCode.first as int; }); //disable editor if necessary - if (widget.htmlEditorOptions.disabled && !callbacksInitialized) { + if (widget.htmlEditorOptions.disabled && + !callbacksInitialized) { widget.controller.disable(); } //initialize callbacks diff --git a/lib/src/widgets/html_editor_widget_web.dart b/lib/src/widgets/html_editor_widget_web.dart index cbedce98..bcc3213e 100644 --- a/lib/src/widgets/html_editor_widget_web.dart +++ b/lib/src/widgets/html_editor_widget_web.dart @@ -10,6 +10,7 @@ import 'package:html_editor_enhanced/utils/utils.dart'; // ignore: avoid_web_libraries_in_flutter import 'dart:html' as html; import 'package:html_editor_enhanced/utils/shims/dart_ui.dart' as ui; +import 'package:async/async.dart'; /// The HTML Editor widget itself, for web (uses IFrameElement) class HtmlEditorWidget extends StatefulWidget { @@ -21,7 +22,6 @@ class HtmlEditorWidget extends StatefulWidget { required this.htmlEditorOptions, required this.htmlToolbarOptions, required this.otherOptions, - required this.initBC, }) : super(key: key); final HtmlEditorController controller; @@ -30,7 +30,6 @@ class HtmlEditorWidget extends StatefulWidget { final HtmlEditorOptions htmlEditorOptions; final HtmlToolbarOptions htmlToolbarOptions; final OtherOptions otherOptions; - final BuildContext initBC; @override _HtmlEditorWidgetWebState createState() => _HtmlEditorWidgetWebState(); @@ -41,6 +40,8 @@ class HtmlEditorWidget extends StatefulWidget { /// A stateful widget is necessary here, otherwise the IFrameElement will be /// rebuilt excessively, hurting performance class _HtmlEditorWidgetWebState extends State { + final memoizer = AsyncMemoizer(); + /// The view ID for the IFrameElement. Must be unique. late String createdViewId; @@ -61,14 +62,13 @@ class _HtmlEditorWidgetWebState extends State { @override void initState() { + super.initState(); actualHeight = widget.otherOptions.height; createdViewId = getRandString(10); widget.controller.viewId = createdViewId; - initSummernote(); - super.initState(); } - void initSummernote() async { + Future initSummernote(BuildContext context) async { var headString = ''; var summernoteCallbacks = '''callbacks: { onKeydown: function(e) { @@ -183,7 +183,7 @@ class _HtmlEditorWidgetWebState extends State { } summernoteCallbacks = summernoteCallbacks + '}'; var darkCSS = ''; - if ((Theme.of(widget.initBC).brightness == Brightness.dark || + if ((Theme.of(context).brightness == Brightness.dark || widget.htmlEditorOptions.darkMode == true) && widget.htmlEditorOptions.darkMode != false) { darkCSS = @@ -464,7 +464,7 @@ class _HtmlEditorWidgetWebState extends State { '"assets/packages/html_editor_enhanced/assets/summernote-lite.min.js"'); if (widget.callbacks != null) addJSListener(widget.callbacks!); final iframe = html.IFrameElement() - ..width = MediaQuery.of(widget.initBC).size.width.toString() //'800' + ..width = MediaQuery.of(context).size.width.toString() //'800' ..height = widget.htmlEditorOptions.autoAdjustHeight ? actualHeight.toString() : widget.otherOptions.height.toString() @@ -531,6 +531,7 @@ class _HtmlEditorWidgetWebState extends State { }); ui.platformViewRegistry .registerViewFactory(createdViewId, (int viewId) => iframe); + setState(mounted, this.setState, () { summernoteInit = Future.value(true); }); @@ -538,48 +539,57 @@ class _HtmlEditorWidgetWebState extends State { @override Widget build(BuildContext context) { - return Container( - height: widget.htmlEditorOptions.autoAdjustHeight - ? actualHeight - : widget.otherOptions.height, - child: Column( - children: [ - widget.htmlToolbarOptions.toolbarPosition == - ToolbarPosition.aboveEditor - ? ToolbarWidget( - key: toolbarKey, - controller: widget.controller, - htmlToolbarOptions: widget.htmlToolbarOptions, - callbacks: widget.callbacks) - : Container(height: 0, width: 0), - Expanded( - child: Directionality( - textDirection: TextDirection.ltr, - child: FutureBuilder( - future: summernoteInit, - builder: (context, snapshot) { - if (snapshot.hasData) { - return HtmlElementView( - viewType: createdViewId, - ); - } else { - return Container( - height: widget.htmlEditorOptions.autoAdjustHeight - ? actualHeight - : widget.otherOptions.height); - } - }))), - widget.htmlToolbarOptions.toolbarPosition == - ToolbarPosition.belowEditor - ? ToolbarWidget( - key: toolbarKey, - controller: widget.controller, - htmlToolbarOptions: widget.htmlToolbarOptions, - callbacks: widget.callbacks) - : Container(height: 0, width: 0), - ], - ), - ); + return FutureBuilder( + future: memoizer.runOnce(() => initSummernote(context)), + builder: (context, state) { + if (state.hasError) return ErrorWidget(state.error!); + if (state.connectionState != ConnectionState.done) { + return SizedBox.shrink(); + } + return Container( + height: widget.htmlEditorOptions.autoAdjustHeight + ? actualHeight + : widget.otherOptions.height, + child: Column( + children: [ + widget.htmlToolbarOptions.toolbarPosition == + ToolbarPosition.aboveEditor + ? ToolbarWidget( + key: toolbarKey, + controller: widget.controller, + htmlToolbarOptions: widget.htmlToolbarOptions, + callbacks: widget.callbacks) + : Container(height: 0, width: 0), + Expanded( + child: Directionality( + textDirection: TextDirection.ltr, + child: FutureBuilder( + future: summernoteInit, + builder: (context, snapshot) { + if (snapshot.hasData) { + return HtmlElementView( + viewType: createdViewId, + ); + } else { + return Container( + height: widget + .htmlEditorOptions.autoAdjustHeight + ? actualHeight + : widget.otherOptions.height); + } + }))), + widget.htmlToolbarOptions.toolbarPosition == + ToolbarPosition.belowEditor + ? ToolbarWidget( + key: toolbarKey, + controller: widget.controller, + htmlToolbarOptions: widget.htmlToolbarOptions, + callbacks: widget.callbacks) + : Container(height: 0, width: 0), + ], + ), + ); + }); } /// Adds the callbacks the user set into JavaScript diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 7d5e6768..da0f78d5 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -12,7 +12,9 @@ import 'package:html_editor_enhanced/utils/shims/dart_ui.dart'; void setState( bool mounted, void Function(Function()) setState, void Function() fn) { if (mounted) { - setState.call(fn); + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + setState.call(fn); + }); } } diff --git a/pubspec.lock b/pubspec.lock index 736f2538..700e7b8a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -63,14 +63,14 @@ packages: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "4.2.0" + version: "4.4.0" flex_color_picker: dependency: "direct main" description: name: flex_color_picker url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.2.0" flutter: dependency: "direct main" description: flutter @@ -89,7 +89,7 @@ packages: name: flutter_keyboard_visibility url: "https://pub.dartlang.org" source: hosted - version: "5.1.0" + version: "5.2.0" flutter_keyboard_visibility_platform_interface: dependency: transitive description: @@ -110,7 +110,7 @@ packages: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.5" flutter_test: dependency: "direct dev" description: flutter @@ -142,6 +142,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: "direct main" description: @@ -176,14 +183,14 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.2" pointer_interceptor: dependency: "direct main" description: name: pointer_interceptor url: "https://pub.dartlang.org" source: hosted - version: "0.9.0+1" + version: "0.9.3" sky_engine: dependency: transitive description: flutter @@ -230,7 +237,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" typed_data: dependency: transitive description: @@ -254,4 +261,4 @@ packages: version: "0.2.2" sdks: dart: ">=2.14.0 <3.0.0" - flutter: ">=2.2.0" + flutter: ">=2.10.0" From f8a615d58b6ea997d7f8d7384417e8b00854de2a Mon Sep 17 00:00:00 2001 From: Ahmed Fwela Date: Sat, 19 Feb 2022 22:37:16 +0200 Subject: [PATCH 2/3] removed extra future variable --- .../android/app/src/main/AndroidManifest.xml | 2 +- example/pubspec.lock | 9 ++++- lib/src/widgets/html_editor_widget_web.dart | 38 ++++++------------- pubspec.lock | 2 +- 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index d92152da..f56c80bc 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ diff --git a/example/pubspec.lock b/example/pubspec.lock index b306b148..84e69447 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -156,6 +156,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: @@ -244,7 +251,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" typed_data: dependency: transitive description: diff --git a/lib/src/widgets/html_editor_widget_web.dart b/lib/src/widgets/html_editor_widget_web.dart index bcc3213e..ddcbef1d 100644 --- a/lib/src/widgets/html_editor_widget_web.dart +++ b/lib/src/widgets/html_editor_widget_web.dart @@ -48,11 +48,6 @@ class _HtmlEditorWidgetWebState extends State { /// The actual height of the editor, used to automatically set the height late double actualHeight; - /// A Future that is observed by the [FutureBuilder]. We don't use a function - /// as the Future on the [FutureBuilder] because when the widget is rebuilt, - /// the function may be excessively called, hurting performance. - Future? summernoteInit; - /// Helps get the height of the toolbar to accurately adjust the height of /// the editor when the keyboard is visible. GlobalKey toolbarKey = GlobalKey(); @@ -531,10 +526,6 @@ class _HtmlEditorWidgetWebState extends State { }); ui.platformViewRegistry .registerViewFactory(createdViewId, (int viewId) => iframe); - - setState(mounted, this.setState, () { - summernoteInit = Future.value(true); - }); } @override @@ -544,7 +535,10 @@ class _HtmlEditorWidgetWebState extends State { builder: (context, state) { if (state.hasError) return ErrorWidget(state.error!); if (state.connectionState != ConnectionState.done) { - return SizedBox.shrink(); + return Container( + height: widget.htmlEditorOptions.autoAdjustHeight + ? actualHeight + : widget.otherOptions.height); } return Container( height: widget.htmlEditorOptions.autoAdjustHeight @@ -561,23 +555,13 @@ class _HtmlEditorWidgetWebState extends State { callbacks: widget.callbacks) : Container(height: 0, width: 0), Expanded( - child: Directionality( - textDirection: TextDirection.ltr, - child: FutureBuilder( - future: summernoteInit, - builder: (context, snapshot) { - if (snapshot.hasData) { - return HtmlElementView( - viewType: createdViewId, - ); - } else { - return Container( - height: widget - .htmlEditorOptions.autoAdjustHeight - ? actualHeight - : widget.otherOptions.height); - } - }))), + child: Directionality( + textDirection: TextDirection.ltr, + child: HtmlElementView( + viewType: createdViewId, + ), + ), + ), widget.htmlToolbarOptions.toolbarPosition == ToolbarPosition.belowEditor ? ToolbarWidget( diff --git a/pubspec.lock b/pubspec.lock index 700e7b8a..8fd84b7d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -70,7 +70,7 @@ packages: name: flex_color_picker url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" flutter: dependency: "direct main" description: flutter From b9b96c0d75ac433d65d12d8bcefceb8d660543d8 Mon Sep 17 00:00:00 2001 From: Ahmed Fwela Date: Sat, 19 Feb 2022 22:47:11 +0200 Subject: [PATCH 3/3] fixed undefined error --- lib/src/widgets/html_editor_widget_web.dart | 96 +++++++++++---------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/lib/src/widgets/html_editor_widget_web.dart b/lib/src/widgets/html_editor_widget_web.dart index ddcbef1d..10d63435 100644 --- a/lib/src/widgets/html_editor_widget_web.dart +++ b/lib/src/widgets/html_editor_widget_web.dart @@ -236,7 +236,10 @@ class _HtmlEditorWidgetWebState extends State { window.parent.postMessage(JSON.stringify({"view": "$createdViewId", "type": "toDart: htmlHeight", "height": height}), "*"); } if (data["type"].includes("setInputType")) { - document.getElementsByClassName('note-editable')[0].setAttribute('inputmode', '${describeEnum(widget.htmlEditorOptions.inputType)}'); + const editable = document.getElementsByClassName('note-editable')[0]; + if (editable) { + editable.setAttribute('inputmode', '${describeEnum(widget.htmlEditorOptions.inputType)}'); + } } if (data["type"].includes("setText")) { \$('#summernote-2').summernote('code', data["text"]); @@ -528,52 +531,57 @@ class _HtmlEditorWidgetWebState extends State { .registerViewFactory(createdViewId, (int viewId) => iframe); } +/* + + */ @override Widget build(BuildContext context) { - return FutureBuilder( - future: memoizer.runOnce(() => initSummernote(context)), - builder: (context, state) { - if (state.hasError) return ErrorWidget(state.error!); - if (state.connectionState != ConnectionState.done) { - return Container( - height: widget.htmlEditorOptions.autoAdjustHeight - ? actualHeight - : widget.otherOptions.height); - } - return Container( - height: widget.htmlEditorOptions.autoAdjustHeight - ? actualHeight - : widget.otherOptions.height, - child: Column( - children: [ - widget.htmlToolbarOptions.toolbarPosition == - ToolbarPosition.aboveEditor - ? ToolbarWidget( - key: toolbarKey, - controller: widget.controller, - htmlToolbarOptions: widget.htmlToolbarOptions, - callbacks: widget.callbacks) - : Container(height: 0, width: 0), - Expanded( - child: Directionality( - textDirection: TextDirection.ltr, - child: HtmlElementView( - viewType: createdViewId, - ), - ), - ), - widget.htmlToolbarOptions.toolbarPosition == - ToolbarPosition.belowEditor - ? ToolbarWidget( - key: toolbarKey, - controller: widget.controller, - htmlToolbarOptions: widget.htmlToolbarOptions, - callbacks: widget.callbacks) - : Container(height: 0, width: 0), - ], + return Container( + height: widget.htmlEditorOptions.autoAdjustHeight + ? actualHeight + : widget.otherOptions.height, + child: Column( + children: [ + widget.htmlToolbarOptions.toolbarPosition == + ToolbarPosition.aboveEditor + ? ToolbarWidget( + key: toolbarKey, + controller: widget.controller, + htmlToolbarOptions: widget.htmlToolbarOptions, + callbacks: widget.callbacks) + : Container(height: 0, width: 0), + Expanded( + child: Directionality( + textDirection: TextDirection.ltr, + child: FutureBuilder( + future: memoizer.runOnce(() => initSummernote(context)), + builder: (context, state) { + if (state.hasError) return ErrorWidget(state.error!); + if (state.connectionState != ConnectionState.done) { + return Container( + height: widget.htmlEditorOptions.autoAdjustHeight + ? actualHeight + : widget.otherOptions.height, + ); + } + return HtmlElementView( + viewType: createdViewId, + ); + }, + ), ), - ); - }); + ), + widget.htmlToolbarOptions.toolbarPosition == + ToolbarPosition.belowEditor + ? ToolbarWidget( + key: toolbarKey, + controller: widget.controller, + htmlToolbarOptions: widget.htmlToolbarOptions, + callbacks: widget.callbacks) + : Container(height: 0, width: 0), + ], + ), + ); } /// Adds the callbacks the user set into JavaScript