diff --git a/lib/src/widgets/html_editor_widget_web.dart b/lib/src/widgets/html_editor_widget_web.dart index cb595f46..0c54b51d 100644 --- a/lib/src/widgets/html_editor_widget_web.dart +++ b/lib/src/widgets/html_editor_widget_web.dart @@ -1,6 +1,8 @@ export 'dart:html'; +import 'dart:async'; import 'dart:convert'; +import 'dart:html'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -63,6 +65,10 @@ class _HtmlEditorWidgetWebState extends State { final _jsonEncoder = const JsonEncoder(); + StreamSubscription? _editorJSListener; + StreamSubscription? _summernoteOnLoadListener; + static const String _summernoteLoadedMessage = '_HtmlEditorWidgetWebState::summernoteLoaded'; + @override void initState() { actualHeight = widget.otherOptions.height; @@ -546,6 +552,14 @@ class _HtmlEditorWidgetWebState extends State { } $jsCallbacks + + function iframeLoaded(event) { + window.parent.postMessage(JSON.stringify({"view": "$createdViewId", "message": "$_summernoteLoadedMessage"}), "*"); + } + window.addEventListener('load', iframeLoaded, false); + window.addEventListener('beforeunload', (event) => { + window.parent.removeEventListener('message', handleMessage, false); + }); """; var filePath = @@ -585,78 +599,7 @@ class _HtmlEditorWidgetWebState extends State { ..style.border = 'none' ..style.overflow = 'hidden' ..style.width = '100%' - ..style.height = '100%' - ..onLoad.listen((event) async { - if (widget.htmlEditorOptions.disabled && !alreadyDisabled) { - widget.controller.disable(); - alreadyDisabled = true; - } - if (widget.callbacks != null && widget.callbacks!.onInit != null) { - widget.callbacks!.onInit!.call(); - } - if (widget.htmlEditorOptions.initialText != null) { - widget.controller.setText(widget.htmlEditorOptions.initialText!); - } - var data = {'type': 'toIframe: getHeight'}; - data['view'] = createdViewId; - var data2 = {'type': 'toIframe: setInputType'}; - data2['view'] = createdViewId; - var jsonStr = _jsonEncoder.convert(data); - var jsonStr2 = _jsonEncoder.convert(data2); - html.window.onMessage.listen((event) { - var data = json.decode(event.data); - if (data['type'] != null && - data['type'].contains('toDart: htmlHeight') && - data['view'] == createdViewId && - widget.htmlEditorOptions.autoAdjustHeight) { - final docHeight = data['height'] ?? actualHeight; - if ((docHeight != null && docHeight != actualHeight) && - mounted && - docHeight > 0) { - setState(mounted, this.setState, () { - actualHeight = - docHeight + (toolbarKey.currentContext?.size?.height ?? 0); - }); - } - } - if (data['type'] != null && - data['type'].contains('toDart: onChangeContent') && - data['view'] == createdViewId) { - if (widget.callbacks != null && - widget.callbacks!.onChangeContent != null) { - widget.callbacks!.onChangeContent!.call(data['contents']); - } - - if (mounted) { - final scrollableState = Scrollable.maybeOf(context); - if (widget.htmlEditorOptions.shouldEnsureVisible && - scrollableState != null) { - scrollableState.position.ensureVisible( - context.findRenderObject()!, - duration: const Duration(milliseconds: 100), - curve: Curves.easeIn); - } - } - } - if (data['type'] != null && - data['type'].contains('toDart: updateToolbar') && - data['view'] == createdViewId) { - if (widget.controller.toolbar != null) { - widget.controller.toolbar!.updateToolbar(data); - } - } - }); - html.window.postMessage(jsonStr, '*'); - html.window.postMessage(jsonStr2, '*'); - - if (widget.otherOptions.dropZoneHeight != null || - widget.otherOptions.dropZoneWidth != null) { - _setDimensionDropZoneView( - height: widget.otherOptions.dropZoneHeight, - width: widget.otherOptions.dropZoneWidth - ); - } - }); + ..style.height = '100%'; ui.platformViewRegistry .registerViewFactory(createdViewId, (int viewId) => iframe); setState(mounted, this.setState, () { @@ -672,8 +615,8 @@ class _HtmlEditorWidgetWebState extends State { : widget.otherOptions.height, child: Column( children: [ - widget.htmlToolbarOptions.toolbarPosition == - ToolbarPosition.aboveEditor + widget.htmlToolbarOptions.toolbarPosition == ToolbarPosition.aboveEditor + && widget.htmlToolbarOptions.toolbarType != ToolbarType.hide ? ToolbarWidget( key: toolbarKey, controller: widget.controller, @@ -697,8 +640,8 @@ class _HtmlEditorWidgetWebState extends State { : widget.otherOptions.height); } }))), - widget.htmlToolbarOptions.toolbarPosition == - ToolbarPosition.belowEditor + widget.htmlToolbarOptions.toolbarPosition == ToolbarPosition.belowEditor + && widget.htmlToolbarOptions.toolbarType != ToolbarType.hide ? ToolbarWidget( key: toolbarKey, controller: widget.controller, @@ -823,11 +766,12 @@ class _HtmlEditorWidgetWebState extends State { /// Adds an event listener to check when a callback is fired void addJSListener(Callbacks c) { - html.window.onMessage.listen((event) { + _editorJSListener = html.window.onMessage.listen((event) { var data = json.decode(event.data); - if (data['type'] != null && - data['type'].contains('toDart:') && - data['view'] == createdViewId) { + + if (data['view'] != createdViewId) return; + + if (data['type'] != null && data['type'].contains('toDart:')) { if (data['type'].contains('onBeforeCommand')) { c.onBeforeCommand!.call(data['contents']); } @@ -914,6 +858,78 @@ class _HtmlEditorWidgetWebState extends State { c.onTextFontSizeChanged!.call(data['size']); } } + + if (data['message'] == _summernoteLoadedMessage) { + if (widget.htmlEditorOptions.disabled && !alreadyDisabled) { + widget.controller.disable(); + alreadyDisabled = true; + } + if (widget.callbacks != null && widget.callbacks!.onInit != null) { + widget.callbacks!.onInit!.call(); + } + if (widget.htmlEditorOptions.initialText != null) { + widget.controller.setText(widget.htmlEditorOptions.initialText!); + } + var data = {'type': 'toIframe: getHeight'}; + data['view'] = createdViewId; + var data2 = {'type': 'toIframe: setInputType'}; + data2['view'] = createdViewId; + var jsonStr = _jsonEncoder.convert(data); + var jsonStr2 = _jsonEncoder.convert(data2); + _summernoteOnLoadListener = html.window.onMessage.listen((event) { + var data = json.decode(event.data); + if (data['type'] != null && + data['type'].contains('toDart: htmlHeight') && + data['view'] == createdViewId && + widget.htmlEditorOptions.autoAdjustHeight) { + final docHeight = data['height'] ?? actualHeight; + if ((docHeight != null && docHeight != actualHeight) && + mounted && + docHeight > 0) { + setState(mounted, this.setState, () { + actualHeight = + docHeight + (toolbarKey.currentContext?.size?.height ?? 0); + }); + } + } + if (data['type'] != null && + data['type'].contains('toDart: onChangeContent') && + data['view'] == createdViewId) { + if (widget.callbacks != null && + widget.callbacks!.onChangeContent != null) { + widget.callbacks!.onChangeContent!.call(data['contents']); + } + + if (mounted) { + final scrollableState = Scrollable.maybeOf(context); + if (widget.htmlEditorOptions.shouldEnsureVisible && + scrollableState != null) { + scrollableState.position.ensureVisible( + context.findRenderObject()!, + duration: const Duration(milliseconds: 100), + curve: Curves.easeIn); + } + } + } + if (data['type'] != null && + data['type'].contains('toDart: updateToolbar') && + data['view'] == createdViewId) { + if (widget.controller.toolbar != null) { + widget.controller.toolbar!.updateToolbar(data); + } + } + }); + html.window.postMessage(jsonStr, '*'); + html.window.postMessage(jsonStr2, '*'); + + if (widget.otherOptions.dropZoneHeight != null || + widget.otherOptions.dropZoneWidth != null) { + _setDimensionDropZoneView( + height: widget.otherOptions.dropZoneHeight, + width: widget.otherOptions.dropZoneWidth + ); + } + } }); } @@ -931,4 +947,11 @@ class _HtmlEditorWidgetWebState extends State { final jsonDimension = _jsonEncoder.convert(dataDimension); html.window.postMessage(jsonDimension, '*'); } + + @override + void dispose() { + _editorJSListener?.cancel(); + _summernoteOnLoadListener?.cancel(); + super.dispose(); + } }