From fb16e47b59368965ed0ac4066907fd9133848020 Mon Sep 17 00:00:00 2001 From: tanay Date: Wed, 7 Apr 2021 10:05:15 -0400 Subject: [PATCH] Prepare 1.8.0 to pub --- CHANGELOG.md | 20 +++ example/lib/main.dart | 126 ++++++++---------- example/pubspec.lock | 2 +- lib/html_editor.dart | 2 +- lib/src/html_editor_controller_mobile.dart | 12 +- lib/src/html_editor_controller_web.dart | 10 +- .../widgets/html_editor_widget_mobile.dart | 61 +++++---- lib/src/widgets/html_editor_widget_web.dart | 10 +- lib/utils/plugins.dart | 8 +- lib/utils/toolbar_widget.dart | 43 +++--- pubspec.yaml | 2 +- 11 files changed, 154 insertions(+), 142 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83e919c9..f1b88df5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +## [1.8.0] - 2021-04-07 +* Add support for `getSuggestionsMobile` (Summernote @ Mentions Plugin) - allows you to programatically return the list of mentions. + * Only supported on mobile. + * [BREAKING] renamed `mentions` to `mentionsWeb` as a result of this change +* Added support for the remainder of Summernote callbacks: + * `onBeforeCommand` + * `onChangeCodeview` + * `onDialogShown` + * `onImageUploadError` + * `onMouseDown` + * `onMouseUp` + * `onScroll` + * See the README for how these work. +* Added a few new functions: + * recalculateHeight(): recalculates the editor height and applies it + * addNotification(): adds a notification bar to the bottom of the editor in a specified style with specified text + * removeNotification(): removes the current notification from the bottom of the editor +* Fixed blank space at the bottom of the editor when `showBottomToolbar: false` +* Fixed 'Android resource linking failed' (bumped flutter_inappwebview to 5.3.1+1) + ## [1.7.1] - 2021-03-26 * Fixed bug where initial text would not be inserted and default toolbar would be shown regardless of editor options * Significantly improved keyboard height detection (detect when keyboard comes up and goes down) diff --git a/example/lib/main.dart b/example/lib/main.dart index 339b6abf..5f27bdfb 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -72,36 +72,27 @@ class _HtmlEditorExampleState extends State { //initialText: "

text content initial, if any

", options: HtmlEditorOptions(height: 450, shouldEnsureVisible: true), - callbacks: Callbacks( - onBeforeCommand: (String? currentHtml) { - print("html before change is $currentHtml"); - }, - onChange: (String? changed) { - print("content changed to $changed"); - }, - onChangeCodeview: (String? changed) { - print("code changed to $changed"); - }, - onDialogShown: () { - print("dialog shown"); - }, - onEnter: () { - print("enter/return pressed"); - }, - onFocus: () { - print("editor focused"); - }, - onBlur: () { - print("editor unfocused"); - }, - onBlurCodeview: () { - print("codeview either focused or unfocused"); - }, - onInit: () { - print("init"); - }, - //this is commented because it overrides the default Summernote handlers - /*onImageLinkInsert: (String? url) { + callbacks: Callbacks(onBeforeCommand: (String? currentHtml) { + print("html before change is $currentHtml"); + }, onChange: (String? changed) { + print("content changed to $changed"); + }, onChangeCodeview: (String? changed) { + print("code changed to $changed"); + }, onDialogShown: () { + print("dialog shown"); + }, onEnter: () { + print("enter/return pressed"); + }, onFocus: () { + print("editor focused"); + }, onBlur: () { + print("editor unfocused"); + }, onBlurCodeview: () { + print("codeview either focused or unfocused"); + }, onInit: () { + print("init"); + }, + //this is commented because it overrides the default Summernote handlers + /*onImageLinkInsert: (String? url) { print(url ?? "unknown url"); }, onImageUpload: (FileUpload file) async { @@ -110,35 +101,28 @@ class _HtmlEditorExampleState extends State { print(file.type); print(file.base64); },*/ - onImageUploadError: (FileUpload? file, String? base64Str, - UploadError error) { - print(describeEnum(error)); - print(base64Str ?? ""); - if (file != null) { - print(file.name); - print(file.size); - print(file.type); - } - }, - onKeyDown: (int? keyCode) { - print("$keyCode key downed"); - }, - onKeyUp: (int? keyCode) { - print("$keyCode key released"); - }, - onMouseDown: () { - print("mouse downed"); - }, - onMouseUp: () { - print("mouse released"); - }, - onPaste: () { - print("pasted into editor"); - }, - onScroll: () { - print("editor scrolled"); + onImageUploadError: (FileUpload? file, String? base64Str, + UploadError error) { + print(describeEnum(error)); + print(base64Str ?? ""); + if (file != null) { + print(file.name); + print(file.size); + print(file.type); } - ), + }, onKeyDown: (int? keyCode) { + print("$keyCode key downed"); + }, onKeyUp: (int? keyCode) { + print("$keyCode key released"); + }, onMouseDown: () { + print("mouse downed"); + }, onMouseUp: () { + print("mouse released"); + }, onPaste: () { + print("pasted into editor"); + }, onScroll: () { + print("editor scrolled"); + }), plugins: [ SummernoteEmoji(), AdditionalTextTags(), @@ -148,8 +132,9 @@ class _HtmlEditorExampleState extends State { SummernoteAtMention( getSuggestionsMobile: (String value) { List mentions = ['test1', 'test2', 'test3']; - return mentions.where((element) => - element.contains(value)).toList(); + return mentions + .where((element) => element.contains(value)) + .toList(); }, mentionsWeb: ['test1', 'test2', 'test3'], onSelect: (String value) { @@ -356,10 +341,11 @@ class _HtmlEditorExampleState extends State { style: TextButton.styleFrom( backgroundColor: Colors.blueGrey), onPressed: () { - controller.addNotification("Info notification", NotificationType.info); + controller.addNotification( + "Info notification", NotificationType.info); }, child: - Text("Info", style: TextStyle(color: Colors.white)), + Text("Info", style: TextStyle(color: Colors.white)), ), SizedBox( width: 16, @@ -368,10 +354,11 @@ class _HtmlEditorExampleState extends State { style: TextButton.styleFrom( backgroundColor: Colors.blueGrey), onPressed: () { - controller.addNotification("Warning notification", NotificationType.warning); + controller.addNotification( + "Warning notification", NotificationType.warning); }, - child: - Text("Warning", style: TextStyle(color: Colors.white)), + child: Text("Warning", + style: TextStyle(color: Colors.white)), ), SizedBox( width: 16, @@ -380,7 +367,8 @@ class _HtmlEditorExampleState extends State { style: TextButton.styleFrom( backgroundColor: Theme.of(context).accentColor), onPressed: () async { - controller.addNotification("Success notification", NotificationType.success); + controller.addNotification( + "Success notification", NotificationType.success); }, child: Text( "Success", @@ -394,7 +382,8 @@ class _HtmlEditorExampleState extends State { style: TextButton.styleFrom( backgroundColor: Theme.of(context).accentColor), onPressed: () { - controller.addNotification("Danger notification", NotificationType.danger); + controller.addNotification( + "Danger notification", NotificationType.danger); }, child: Text( "Danger", @@ -414,7 +403,8 @@ class _HtmlEditorExampleState extends State { style: TextButton.styleFrom( backgroundColor: Colors.blueGrey), onPressed: () { - controller.addNotification("Plaintext notification", NotificationType.plaintext); + controller.addNotification("Plaintext notification", + NotificationType.plaintext); }, child: Text("Plaintext", style: TextStyle(color: Colors.white)), diff --git a/example/pubspec.lock b/example/pubspec.lock index d58edcb1..7893d68b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -106,7 +106,7 @@ packages: path: ".." relative: true source: path - version: "1.7.1" + version: "1.8.0" js: dependency: transitive description: diff --git a/lib/html_editor.dart b/lib/html_editor.dart index 712dbec7..e7ccbfb2 100644 --- a/lib/html_editor.dart +++ b/lib/html_editor.dart @@ -24,4 +24,4 @@ Map controllerMap = {}; /// Manages the notification type for a notification displayed at the bottom of /// the editor -enum NotificationType {info, warning, success, danger, plaintext} +enum NotificationType { info, warning, success, danger, plaintext } diff --git a/lib/src/html_editor_controller_mobile.dart b/lib/src/html_editor_controller_mobile.dart index d145e279..c177c770 100644 --- a/lib/src/html_editor_controller_mobile.dart +++ b/lib/src/html_editor_controller_mobile.dart @@ -157,22 +157,23 @@ class HtmlEditorController extends unsupported.HtmlEditorController { /// when [adjustHeightForKeyboard] is enabled. void resetHeight() { _evaluateJavascript( - source: "window.flutter_inappwebview.callHandler('setHeight', 'reset');"); + source: + "window.flutter_inappwebview.callHandler('setHeight', 'reset');"); } /// Recalculates the height of the editor to remove any vertical scrolling. /// This method will not do anything if [autoAdjustHeight] is turned off. void recalculateHeight() { _evaluateJavascript( - source: "var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', height);"); + source: + "var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', 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. void addNotification(String html, NotificationType notificationType) async { - await _evaluateJavascript( - source: """ + await _evaluateJavascript(source: """ \$('.note-status-output').html( '
$html
' ); @@ -182,8 +183,7 @@ class HtmlEditorController extends unsupported.HtmlEditorController { /// Remove the current notification from the bottom of the editor void removeNotification() async { - await _evaluateJavascript( - source: "\$('.note-status-output').empty();"); + await _evaluateJavascript(source: "\$('.note-status-output').empty();"); recalculateHeight(); } diff --git a/lib/src/html_editor_controller_web.dart b/lib/src/html_editor_controller_web.dart index e709d7c8..dfc412cc 100644 --- a/lib/src/html_editor_controller_web.dart +++ b/lib/src/html_editor_controller_web.dart @@ -178,10 +178,8 @@ class HtmlEditorController extends unsupported.HtmlEditorController { /// and the notificationType determines how the alert is displayed. void addNotification(String html, NotificationType notificationType) { if (notificationType == NotificationType.plaintext) - _evaluateJavascriptWeb(data: { - "type": "toIframe: addNotification", - "html": html - }); + _evaluateJavascriptWeb( + data: {"type": "toIframe: addNotification", "html": html}); else _evaluateJavascriptWeb(data: { "type": "toIframe: addNotification", @@ -193,9 +191,7 @@ class HtmlEditorController extends unsupported.HtmlEditorController { /// Remove the current notification from the bottom of the editor void removeNotification() { - _evaluateJavascriptWeb(data: { - "type": "toIframe: removeNotification" - }); + _evaluateJavascriptWeb(data: {"type": "toIframe: removeNotification"}); recalculateHeight(); } diff --git a/lib/src/widgets/html_editor_widget_mobile.dart b/lib/src/widgets/html_editor_widget_mobile.dart index cde2d5b5..6ba1aa46 100644 --- a/lib/src/widgets/html_editor_widget_mobile.dart +++ b/lib/src/widgets/html_editor_widget_mobile.dart @@ -147,10 +147,13 @@ class _HtmlEditorWidgetMobileState extends State { double visibleDecimal = await visibleStream.stream.first; double newHeight = widget.options.height; if (docHeight != null) { - newHeight = (docHeight! + toolbarHeightCorrection) * visibleDecimal; + newHeight = (docHeight! + toolbarHeightCorrection) * + visibleDecimal; } else { - newHeight = - (widget.options.height + 85 + toolbarHeightCorrection) * visibleDecimal; + newHeight = (widget.options.height + + 85 + + toolbarHeightCorrection) * + visibleDecimal; } await controller.evaluateJavascript( source: @@ -204,7 +207,8 @@ class _HtmlEditorWidgetMobileState extends State { controller.addJavaScriptHandler( handlerName: 'getSuggestions', callback: (value) { - return p.getSuggestionsMobile!.call(value.first.toString()) + return p.getSuggestionsMobile! + .call(value.first.toString()) .toString() .replaceAll("[", "") .replaceAll("]", ""); @@ -425,18 +429,24 @@ class _HtmlEditorWidgetMobileState extends State { if (height.first == "reset") { resetHeight(); } else { - docHeight = double.tryParse(height.first.toString()); - if (docHeight != null && docHeight! > 0 && mounted) { + docHeight = + double.tryParse(height.first.toString()); + if (docHeight != null && + docHeight! > 0 && + mounted) { setState(() { - actualHeight = docHeight! + toolbarHeightCorrection; + actualHeight = + docHeight! + toolbarHeightCorrection; }); } else { - docHeight = actualHeight - toolbarHeightCorrection; + docHeight = + actualHeight - toolbarHeightCorrection; } } }); controller.evaluateJavascript( - source: "var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', height);"); + source: + "var height = document.body.scrollHeight; window.flutter_inappwebview.callHandler('setHeight', height);"); } else { docHeight = actualHeight - toolbarHeightCorrection; } @@ -449,12 +459,16 @@ class _HtmlEditorWidgetMobileState extends State { .listen((bool visible) { if (!visible && docHeight != null && - actualHeight != docHeight! + toolbarHeightCorrection) { + actualHeight != + docHeight! + toolbarHeightCorrection) { controller.clearFocus(); resetHeight(); } else if (!visible && docHeight == null && - actualHeight != widget.options.height + 85 + toolbarHeightCorrection) { + actualHeight != + widget.options.height + + 85 + + toolbarHeightCorrection) { controller.clearFocus(); resetHeight(); } @@ -605,7 +619,7 @@ class _HtmlEditorWidgetMobileState extends State { controllerMap[widget.controller].addJavaScriptHandler( handlerName: 'onBeforeCommand', callback: (contents) { - c.onBeforeCommand!.call(contents.first.toString()); + c.onBeforeCommand!.call(contents.first.toString()); }); } if (c.onChangeCodeview != null) { @@ -669,32 +683,25 @@ class _HtmlEditorWidgetMobileState extends State { controllerMap[widget.controller].addJavaScriptHandler( handlerName: 'onImageUploadError', callback: (args) { - if (!args.first - .toString() - .startsWith("{")) { + if (!args.first.toString().startsWith("{")) { c.onImageUploadError!.call( null, args.first, args.last.contains("base64") ? UploadError.jsException - : args.last - .contains("unsupported") - ? UploadError.unsupportedFile - : UploadError - .exceededMaxSize); + : args.last.contains("unsupported") + ? UploadError.unsupportedFile + : UploadError.exceededMaxSize); } else { - FileUpload file = fileUploadFromJson( - args.first.toString()); + FileUpload file = fileUploadFromJson(args.first.toString()); c.onImageUploadError!.call( file, null, args.last.contains("base64") ? UploadError.jsException - : args.last - .contains("unsupported") - ? UploadError.unsupportedFile - : UploadError - .exceededMaxSize); + : args.last.contains("unsupported") + ? UploadError.unsupportedFile + : UploadError.exceededMaxSize); } }); } diff --git a/lib/src/widgets/html_editor_widget_web.dart b/lib/src/widgets/html_editor_widget_web.dart index e9970a98..b7641ca0 100644 --- a/lib/src/widgets/html_editor_widget_web.dart +++ b/lib/src/widgets/html_editor_widget_web.dart @@ -502,7 +502,7 @@ class _HtmlEditorWidgetWebState extends State { String callbacks = ""; if (c.onBeforeCommand != null) { callbacks = callbacks + - """ + """ \$('#summernote-2').on('summernote.before.command', function(_, contents, \$editable) { window.parent.postMessage(JSON.stringify({"view": "$createdViewId", "type": "toDart: onBeforeCommand", "contents": contents}), "*"); });\n @@ -671,8 +671,8 @@ class _HtmlEditorWidgetWebState extends State { data["error"].contains("base64") ? UploadError.jsException : data["error"].contains("unsupported") - ? UploadError.unsupportedFile - : UploadError.exceededMaxSize); + ? UploadError.unsupportedFile + : UploadError.exceededMaxSize); } else { Map map = { 'lastModified': data["lastModified"], @@ -689,8 +689,8 @@ class _HtmlEditorWidgetWebState extends State { data["error"].contains("base64") ? UploadError.jsException : data["error"].contains("unsupported") - ? UploadError.unsupportedFile - : UploadError.exceededMaxSize); + ? UploadError.unsupportedFile + : UploadError.exceededMaxSize); } } if (data["type"].contains("onKeyDown")) { diff --git a/lib/utils/plugins.dart b/lib/utils/plugins.dart index 7cc600da..28dd0efc 100644 --- a/lib/utils/plugins.dart +++ b/lib/utils/plugins.dart @@ -139,11 +139,9 @@ class SummernoteAtMention extends Plugins { /// Callback to run code when a mention is selected final Function(String)? onSelect; - const SummernoteAtMention({ - this.getSuggestionsMobile, - this.mentionsWeb, - this.onSelect}) : - assert(kIsWeb ? mentionsWeb != null : getSuggestionsMobile != null); + const SummernoteAtMention( + {this.getSuggestionsMobile, this.mentionsWeb, this.onSelect}) + : assert(kIsWeb ? mentionsWeb != null : getSuggestionsMobile != null); @override String getHeadString() { diff --git a/lib/utils/toolbar_widget.dart b/lib/utils/toolbar_widget.dart index 41787d08..e9bd27dc 100644 --- a/lib/utils/toolbar_widget.dart +++ b/lib/utils/toolbar_widget.dart @@ -12,27 +12,28 @@ class ToolbarWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - height: 40, - child: Padding( - padding: const EdgeInsets.only(left: 4, right: 4, bottom: 8, top: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - toolbarIcon(context, Icons.content_copy, "Copy", onTap: () async { - String? data = await controller.getText(); - Clipboard.setData(new ClipboardData(text: data)); - }), - toolbarIcon(context, Icons.content_paste, "Paste", onTap: () async { - ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); - if (data != null) { - String text = data.text!; - controller.insertHtml(text); - } - }), - ], - ), - ) - ); + height: 40, + child: Padding( + padding: const EdgeInsets.only(left: 4, right: 4, bottom: 8, top: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + toolbarIcon(context, Icons.content_copy, "Copy", onTap: () async { + String? data = await controller.getText(); + Clipboard.setData(new ClipboardData(text: data)); + }), + toolbarIcon(context, Icons.content_paste, "Paste", + onTap: () async { + ClipboardData? data = + await Clipboard.getData(Clipboard.kTextPlain); + if (data != null) { + String text = data.text!; + controller.insertHtml(text); + } + }), + ], + ), + )); } } diff --git a/pubspec.yaml b/pubspec.yaml index 53cdc940..17d9792b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: html_editor_enhanced description: HTML rich text editor for Android, iOS, and Web, using the Summernote library. Enhanced with critical bug fixes and support for callbacks, plugins, dark mode, and much more. -version: 1.7.1 +version: 1.8.0 homepage: https://github.com/tneotia/html-editor-enhanced environment: