Files
rich_editor/lib/src/rendering/rich_editor.dart
2021-06-06 21:09:09 +01:00

239 lines
6.9 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:rich_editor/src/models/enum/bar_position.dart';
import 'package:rich_editor/src/models/rich_editor_options.dart';
import 'package:rich_editor/src/services/local_server.dart';
import 'package:rich_editor/src/utils/javascript_executor_base.dart';
import 'package:rich_editor/src/widgets/editor_tool_bar.dart';
class RichEditor extends StatefulWidget {
final String? value;
final RichEditorOptions? editorOptions;
final Function(File image)? getImageUrl;
final Function(File video)? getVideoUrl;
RichEditor({
Key? key,
this.value,
this.editorOptions,
this.getImageUrl,
this.getVideoUrl,
}) : super(key: key);
@override
RichEditorState createState() => RichEditorState();
}
class RichEditorState extends State<RichEditor> {
InAppWebViewController? _controller;
final Key _mapKey = UniqueKey();
String assetPath = 'packages/rich_editor/assets/editor/editor.html';
int port = 5321;
String html = '';
LocalServer? localServer;
JavascriptExecutorBase javascriptExecutor = JavascriptExecutorBase();
@override
void initState() {
super.initState();
if (Platform.isIOS) {
_initServer();
}
}
_initServer() async {
localServer = LocalServer(port);
await localServer!.start(_handleRequest);
}
void _handleRequest(HttpRequest request) {
try {
if (request.method == 'GET' &&
request.uri.queryParameters['query'] == "getRawTeXHTML") {
} else {}
} catch (e) {
print('Exception in handleRequest: $e');
}
}
@override
void dispose() {
if (_controller != null) {
_controller = null;
}
if (!Platform.isAndroid) {
localServer!.close();
}
super.dispose();
}
_loadHtmlFromAssets() async {
final filePath = assetPath;
_controller!.loadUrl(
urlRequest: URLRequest(
url: Uri.tryParse('http://localhost:$port/$filePath'),
),
);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Visibility(
visible: widget.editorOptions!.barPosition == BarPosition.TOP,
child: _buildToolBar(),
),
Expanded(
child: InAppWebView(
key: _mapKey,
onWebViewCreated: (controller) async {
_controller = controller;
setState(() {});
if (!Platform.isAndroid) {
await _loadHtmlFromAssets();
} else {
await _controller!.loadUrl(
urlRequest: URLRequest(
url: Uri.tryParse(
'file:///android_asset/flutter_assets/$assetPath'),
),
);
}
},
onLoadStop: (controller, link) async {
if (link!.path != 'blank') {
javascriptExecutor.init(_controller!);
await _setInitialValues();
_addJSListener();
}
},
// javascriptMode: JavascriptMode.unrestricted,
// gestureNavigationEnabled: false,
gestureRecognizers: [
Factory(() => VerticalDragGestureRecognizer()..onUpdate = (_) {}),
].toSet(),
onLoadError: (controller, url, code, e) {
print("error $e $code");
},
onConsoleMessage: (controller, consoleMessage) async {
print(
'WebView Message: $consoleMessage',
);
},
),
),
Visibility(
visible: widget.editorOptions!.barPosition == BarPosition.BOTTOM,
child: _buildToolBar(),
),
],
);
}
_buildToolBar() {
return EditorToolBar(
getImageUrl: widget.getImageUrl,
getVideoUrl: widget.getVideoUrl,
javascriptExecutor: javascriptExecutor,
enableVideo: widget.editorOptions!.enableVideo,
);
}
_setInitialValues() async {
if (widget.value != null) await javascriptExecutor.setHtml(widget.value!);
if (widget.editorOptions!.padding != null)
await javascriptExecutor.setPadding(widget.editorOptions!.padding!);
if (widget.editorOptions!.backgroundColor != null)
await javascriptExecutor
.setBackgroundColor(widget.editorOptions!.backgroundColor!);
if (widget.editorOptions!.baseTextColor != null)
await javascriptExecutor
.setBaseTextColor(widget.editorOptions!.baseTextColor!);
if (widget.editorOptions!.placeholder != null)
await javascriptExecutor
.setPlaceholder(widget.editorOptions!.placeholder!);
if (widget.editorOptions!.baseFontFamily != null)
await javascriptExecutor
.setBaseFontFamily(widget.editorOptions!.baseFontFamily!);
}
_addJSListener() async {
_controller!.addJavaScriptHandler(
handlerName: 'editor-state-changed-callback://',
callback: (c) {
print('Callback $c');
});
}
/// Get current HTML from editor
Future<String?> getHtml() async {
try {
html = await javascriptExecutor.getCurrentHtml();
} catch (e) {}
return html;
}
/// Set your HTML to the editor
setHtml(String html) async {
return await javascriptExecutor.setHtml(html);
}
/// Hide the keyboard using JavaScript since it's being opened in a WebView
/// https://stackoverflow.com/a/8263376/10835183
unFocus() {
javascriptExecutor.unFocus();
}
/// Clear editor content using Javascript
clear() {
_controller!.evaluateJavascript(
source: 'document.getElementById(\'editor\').innerHTML = "";');
}
/// Focus and Show the keyboard using JavaScript
/// https://stackoverflow.com/a/6809236/10835183
focus() {
javascriptExecutor.focus();
}
/// Add custom CSS code to Editor
loadCSS(String cssFile) {
var jsCSSImport = "(function() {" +
" var head = document.getElementsByTagName(\"head\")[0];" +
" var link = document.createElement(\"link\");" +
" link.rel = \"stylesheet\";" +
" link.type = \"text/css\";" +
" link.href = \"" +
cssFile +
"\";" +
" link.media = \"all\";" +
" head.appendChild(link);" +
"}) ();";
_controller!.evaluateJavascript(source: jsCSSImport);
}
/// if html is equal to html RichTextEditor sets by default at start
/// (<p></p>) so that RichTextEditor can be considered as 'empty'.
Future<bool> isEmpty() async {
html = await javascriptExecutor.getCurrentHtml();
return html == '<p></p>';
}
/// Enable Editing (If editing is disabled)
enableEditing() async {
await javascriptExecutor.setInputEnabled(true);
}
/// Disable Editing (Could be used for a 'view mode')
disableEditing() async {
await javascriptExecutor.setInputEnabled(false);
}
}