feat: added more editor settings

This commit is contained in:
jideguru 2021-06-03 00:13:12 +01:00
parent 666bd5f58a
commit 509808d220
7 changed files with 134 additions and 119 deletions

View File

@ -105,7 +105,8 @@ class _MyHomePageState extends State<MyHomePage> {
placeholder: 'Start typing',
// backgroundColor: Colors.blueGrey,
// baseTextColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 50.0),
padding: EdgeInsets.symmetric(horizontal: 5.0),
baseFontFamily: 'sans-serif',
// You can return a Link (maybe you need to upload the image to your
// storage before displaying in the editor or you can also use base64
getImageUrl: (image) {

View File

@ -281,7 +281,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.1"
version: "0.0.2"
sky_engine:
dependency: transitive
description: flutter

View File

@ -15,19 +15,21 @@ class RichEditor extends StatefulWidget {
final Color? baseTextColor;
final EdgeInsets? padding;
final String? placeholder;
final String? baseFontFamily;
final Function(File image)? getImageUrl;
final Function(File video)? getVideoUrl;
RichEditor(
{Key? key,
RichEditor({
Key? key,
this.value,
this.backgroundColor,
this.baseTextColor,
this.padding,
this.placeholder,
this.baseFontFamily,
this.getImageUrl,
this.getVideoUrl})
: super(key: key);
this.getVideoUrl,
}) : super(key: key);
@override
RichEditorState createState() => RichEditorState();
@ -35,30 +37,29 @@ class RichEditor extends StatefulWidget {
class RichEditorState extends State<RichEditor> {
WebViewController? _controller;
String text = "";
final Key _mapKey = UniqueKey();
String assetPath = 'packages/rich_editor/assets/editor/editor.html';
int port = 5321;
String html = '';
LocalServer? localServer;
JavascriptExecutorBase javascriptExecutorBase = JavascriptExecutorBase();
JavascriptExecutorBase javascriptExecutor = JavascriptExecutorBase();
@override
void initState() {
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
if (!Platform.isAndroid) {
initServer();
_initServer();
}
}
initServer() async {
_initServer() async {
localServer = LocalServer(port);
await localServer!.start(handleRequest);
await localServer!.start(_handleRequest);
}
void handleRequest(HttpRequest request) {
void _handleRequest(HttpRequest request) {
try {
if (request.method == 'GET' &&
request.uri.queryParameters['query'] == "getRawTeXHTML") {
@ -91,7 +92,7 @@ class RichEditorState extends State<RichEditor> {
EditorToolBar(
controller: _controller,
getImageUrl: widget.getImageUrl,
javascriptExecutorBase: javascriptExecutorBase,
javascriptExecutor: javascriptExecutor,
),
Expanded(
child: WebView(
@ -105,7 +106,7 @@ class RichEditorState extends State<RichEditor> {
await _controller!
.loadUrl('file:///android_asset/flutter_assets/$assetPath');
}
javascriptExecutorBase.init(_controller!);
javascriptExecutor.init(_controller!);
},
onPageFinished: (link) async {
await _setInitialValues();
@ -125,44 +126,70 @@ class RichEditorState extends State<RichEditor> {
}
_setInitialValues() async {
if (widget.value != null)
await javascriptExecutorBase.setHtml(widget.value!);
if (widget.value != null) await javascriptExecutor.setHtml(widget.value!);
if (widget.padding != null)
await javascriptExecutorBase.setPadding(widget.padding!);
await javascriptExecutor.setPadding(widget.padding!);
if (widget.backgroundColor != null)
await javascriptExecutorBase.setBackgroundColor(widget.backgroundColor!);
await javascriptExecutor.setBackgroundColor(widget.backgroundColor!);
if (widget.baseTextColor != null)
await javascriptExecutorBase.setBaseTextColor(widget.baseTextColor!);
await javascriptExecutor.setBaseTextColor(widget.baseTextColor!);
if (widget.placeholder != null)
await javascriptExecutorBase.setPlaceholder(widget.placeholder!);
await javascriptExecutor.setPlaceholder(widget.placeholder!);
if (widget.baseFontFamily != null)
await javascriptExecutor.setBaseFontFamily(widget.baseFontFamily!);
}
/// Get current HTML from editor
Future<String?> getHtml() async {
try {
html = await javascriptExecutorBase.getCurrentHtml();
html = await javascriptExecutor.getCurrentHtml();
} catch (e) {}
return html;
}
/// Set your HTML to the editor
setHtml(String html) async {
return await javascriptExecutorBase.setHtml(html);
return await javascriptExecutor.setHtml(html);
}
// Hide the keyboard using JavaScript since it's being opened in a WebView
// https://stackoverflow.com/a/8263376/10835183
/// Hide the keyboard using JavaScript since it's being opened in a WebView
/// https://stackoverflow.com/a/8263376/10835183
unFocus() {
javascriptExecutorBase.unFocus();
javascriptExecutor.unFocus();
}
// Clear editor content using Javascript
/// Clear editor content using Javascript
clear() {
_controller!.evaluateJavascript(
'document.getElementById(\'editor\').innerHTML = "";');
}
// Focus and Show the keyboard using JavaScript
// https://stackoverflow.com/a/6809236/10835183
/// Focus and Show the keyboard using JavaScript
/// https://stackoverflow.com/a/6809236/10835183
focus() {
javascriptExecutorBase.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(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>';
}
}

View File

@ -8,7 +8,7 @@ import 'package:rich_editor/src/models/font.dart';
import 'package:rich_editor/src/models/system_font.dart';
import 'package:xml2json/xml2json.dart';
/// A simple port of FontListParser from Java to Kotlin
/// A simple port of FontListParser from Java to Dart
/// See https://stackoverflow.com/a/29533686/10835183
class FontListParser {
File androidFontsFile = File("/system/etc/fonts.xml");

View File

@ -173,48 +173,52 @@ class JavascriptExecutorBase {
if (height == null) height = 300;
if (alt == null) alt = '';
await executeJavascript(
"insertImage('$url', '$alt', '$width', '$height', $rotation)",
"insertImage('$url', '$alt', '$width', '$height', $rotation);",
);
}
insertCheckbox(String text) async {
await executeJavascript("insertCheckbox('$text')");
await executeJavascript("insertCheckbox('$text');");
}
insertHtml(String html) async {
String? encodedHtml = encodeHtml(html);
await executeJavascript("insertHtml('$encodedHtml')");
await executeJavascript("insertHtml('$encodedHtml');");
}
makeImagesResizeable() async {
await executeJavascript("makeImagesResizeable()");
await executeJavascript("makeImagesResizeable();");
}
disableImageResizing() async {
await executeJavascript("disableImageResizing()");
await executeJavascript("disableImageResizing();");
}
// Editor settings commands
focus() async {
await executeJavascript("focus()");
await executeJavascript("focus();");
}
unFocus() async {
await executeJavascript("blurFocus()");
await executeJavascript("blurFocus();");
}
setBackgroundColor(Color? color) async {
String? hex = color!.toHexColorString();
await executeJavascript("setBackgroundColor('$hex')");
await executeJavascript("setBackgroundColor('$hex');");
}
setBackgroundImage(String image) async {
await executeJavascript("setBackgroundImage('$image')");
await executeJavascript("setBackgroundImage('$image');");
}
setBaseTextColor(Color? color) async {
String? hex = color!.toHexColorString();
await executeJavascript("setBaseTextColor('$hex')");
await executeJavascript("setBaseTextColor('$hex');");
}
setBaseFontFamily(String fontFamily) async {
await executeJavascript("setBaseFontFamily('$fontFamily');");
}
setPadding(EdgeInsets? padding) async {
@ -222,11 +226,21 @@ class JavascriptExecutorBase {
String top = padding.top.toString();
String right = padding.right.toString();
String bottom = padding.bottom.toString();
await executeJavascript("setPadding('$left', '$top', '$right', '$bottom')");
await executeJavascript(
"setPadding('${left}px', '${top}px', '${right}px', '${bottom}px');");
}
// Doesnt actually work for' now
setPlaceholder(String placeholder) async {
await executeJavascript("setPlaceholder('$placeholder')");
await executeJavascript("setPlaceholder('$placeholder');");
}
setEditorWidth(int px) async {
await executeJavascript("setWidth('" + px.toString() + "px');");
}
setEditorHeight(int px) async {
await executeJavascript("setHeight('" + px.toString() + "px');");
}
static decodeHtml(String html) {

View File

@ -17,23 +17,18 @@ class EditorToolBar extends StatelessWidget {
final WebViewController? controller;
final Function(File image)? getImageUrl;
final Function(File video)? getVideoUrl;
final JavascriptExecutorBase javascriptExecutorBase;
final JavascriptExecutorBase javascriptExecutor;
EditorToolBar({
this.controller,
this.getImageUrl,
this.getVideoUrl,
required this.javascriptExecutorBase,
required this.javascriptExecutor,
});
@override
Widget build(BuildContext context) {
// if (controller != null) {
// javascriptExecutorBase.init(controller!);
// }
return Container(
// color: Color(0xff424242),
height: 54.0,
child: Column(
children: [
@ -46,21 +41,20 @@ class EditorToolBar extends StatelessWidget {
tooltip: 'Bold',
icon: Icons.format_bold,
onTap: () async {
await javascriptExecutorBase.setBold();
await javascriptExecutor.setBold();
},
),
TabButton(
tooltip: 'Italic',
icon: Icons.format_italic,
onTap: () async {
await javascriptExecutorBase.setItalic();
await javascriptExecutor.setItalic();
},
),
TabButton(
tooltip: 'Insert Link',
icon: Icons.link,
onTap: () async {
_closeKeyboard();
var link = await showDialog(
context: context,
barrierDismissible: false,
@ -69,14 +63,13 @@ class EditorToolBar extends StatelessWidget {
},
);
if (link != null)
await javascriptExecutorBase.insertLink(link[0], link[1]);
await javascriptExecutor.insertLink(link[0], link[1]);
},
),
TabButton(
tooltip: 'Insert Image',
icon: Icons.image,
onTap: () async {
_closeKeyboard();
var link = await showDialog(
context: context,
barrierDismissible: false,
@ -88,7 +81,7 @@ class EditorToolBar extends StatelessWidget {
if (getImageUrl != null && link[2]) {
link[0] = await getImageUrl!(File(link[0]));
}
await javascriptExecutorBase.insertImage(
await javascriptExecutor.insertImage(
link[0],
alt: link[1],
);
@ -99,63 +92,62 @@ class EditorToolBar extends StatelessWidget {
tooltip: 'Underline',
icon: Icons.format_underline,
onTap: () async {
await javascriptExecutorBase.setUnderline();
await javascriptExecutor.setUnderline();
},
),
TabButton(
tooltip: 'Strike through',
icon: Icons.format_strikethrough,
onTap: () async {
await javascriptExecutorBase.setStrikeThrough();
await javascriptExecutor.setStrikeThrough();
},
),
TabButton(
tooltip: 'Superscript',
icon: Icons.superscript,
onTap: () async {
await javascriptExecutorBase.setSuperscript();
await javascriptExecutor.setSuperscript();
},
),
TabButton(
tooltip: 'Subscript',
icon: Icons.subscript,
onTap: () async {
await javascriptExecutorBase.setSubscript();
await javascriptExecutor.setSubscript();
},
),
TabButton(
tooltip: 'Clear format',
icon: Icons.format_clear,
onTap: () async {
await javascriptExecutorBase.removeFormat();
await javascriptExecutor.removeFormat();
},
),
TabButton(
tooltip: 'Undo',
icon: Icons.undo,
onTap: () async {
await javascriptExecutorBase.undo();
await javascriptExecutor.undo();
},
),
TabButton(
tooltip: 'Redo',
icon: Icons.redo,
onTap: () async {
await javascriptExecutorBase.redo();
await javascriptExecutor.redo();
},
),
TabButton(
tooltip: 'Blockquote',
icon: Icons.format_quote,
onTap: () async {
await javascriptExecutorBase.setBlockQuote();
await javascriptExecutor.setBlockQuote();
},
),
TabButton(
tooltip: 'Font format',
icon: Icons.text_format,
onTap: () async {
_closeKeyboard();
var command = await showDialog(
// isScrollControlled: true,
context: context,
@ -165,13 +157,13 @@ class EditorToolBar extends StatelessWidget {
);
if (command != null) {
if (command == 'p') {
await javascriptExecutorBase.setFormattingToParagraph();
await javascriptExecutor.setFormattingToParagraph();
} else if (command == 'pre') {
await javascriptExecutorBase.setPreformat();
await javascriptExecutor.setPreformat();
} else if (command == 'blockquote') {
await javascriptExecutorBase.setBlockQuote();
await javascriptExecutor.setBlockQuote();
} else {
await javascriptExecutorBase
await javascriptExecutor
.setHeading(int.tryParse(command)!);
}
}
@ -184,9 +176,6 @@ class EditorToolBar extends StatelessWidget {
tooltip: 'Font face',
icon: Icons.font_download,
onTap: () async {
Directory fontsDir = Directory("/system/fonts/");
File file = File('/system/etc/fonts.xml');
// debugPrint(await file.readAsString());
var command = await showDialog(
// isScrollControlled: true,
context: context,
@ -194,8 +183,9 @@ class EditorToolBar extends StatelessWidget {
return FontsDialog();
},
);
print(command);
if (command != null)
await javascriptExecutorBase.setFontName(command);
await javascriptExecutor.setFontName(command);
},
),
),
@ -203,7 +193,6 @@ class EditorToolBar extends StatelessWidget {
icon: Icons.format_size,
tooltip: 'Font Size',
onTap: () async {
_closeKeyboard();
String? command = await showDialog(
// isScrollControlled: true,
context: context,
@ -212,7 +201,7 @@ class EditorToolBar extends StatelessWidget {
},
);
if (command != null)
await javascriptExecutorBase
await javascriptExecutor
.setFontSize(int.tryParse(command)!);
},
),
@ -220,7 +209,6 @@ class EditorToolBar extends StatelessWidget {
tooltip: 'Text Color',
icon: Icons.format_color_text,
onTap: () async {
_closeKeyboard();
var color = await showDialog(
context: context,
builder: (BuildContext context) {
@ -228,14 +216,13 @@ class EditorToolBar extends StatelessWidget {
},
);
if (color != null)
await javascriptExecutorBase.setTextColor(color);
await javascriptExecutor.setTextColor(color);
},
),
TabButton(
tooltip: 'Background Color',
icon: Icons.format_color_fill,
onTap: () async {
_closeKeyboard();
var color = await showDialog(
context: context,
builder: (BuildContext context) {
@ -243,71 +230,69 @@ class EditorToolBar extends StatelessWidget {
},
);
if (color != null)
await javascriptExecutorBase
.setTextBackgroundColor(color);
await javascriptExecutor.setTextBackgroundColor(color);
},
),
TabButton(
tooltip: 'Increase Indent',
icon: Icons.format_indent_increase,
onTap: () async {
await javascriptExecutorBase.setIndent();
await javascriptExecutor.setIndent();
},
),
TabButton(
tooltip: 'Decrease Indent',
icon: Icons.format_indent_decrease,
onTap: () async {
await javascriptExecutorBase.setOutdent();
await javascriptExecutor.setOutdent();
},
),
TabButton(
tooltip: 'Align Left',
icon: Icons.format_align_left_outlined,
onTap: () async {
await javascriptExecutorBase.setJustifyLeft();
await javascriptExecutor.setJustifyLeft();
},
),
TabButton(
tooltip: 'Align Center',
icon: Icons.format_align_center,
onTap: () async {
await javascriptExecutorBase.setJustifyCenter();
await javascriptExecutor.setJustifyCenter();
},
),
TabButton(
tooltip: 'Align Right',
icon: Icons.format_align_right,
onTap: () async {
await javascriptExecutorBase.setJustifyRight();
await javascriptExecutor.setJustifyRight();
},
),
TabButton(
tooltip: 'Justify',
icon: Icons.format_align_justify,
onTap: () async {
await javascriptExecutorBase.setJustifyFull();
await javascriptExecutor.setJustifyFull();
},
),
TabButton(
tooltip: 'Bullet List',
icon: Icons.format_list_bulleted,
onTap: () async {
await javascriptExecutorBase.insertBulletList();
await javascriptExecutor.insertBulletList();
},
),
TabButton(
tooltip: 'Numbered List',
icon: Icons.format_list_numbered,
onTap: () async {
await javascriptExecutorBase.insertNumberedList();
await javascriptExecutor.insertNumberedList();
},
),
TabButton(
tooltip: 'Checkbox',
icon: Icons.check_box_outlined,
onTap: () async {
_closeKeyboard();
var text = await showDialog(
context: context,
builder: (BuildContext context) {
@ -316,7 +301,7 @@ class EditorToolBar extends StatelessWidget {
);
print(text);
if (text != null)
await javascriptExecutorBase.insertCheckbox(text);
await javascriptExecutor.insertCheckbox(text);
},
),
@ -325,7 +310,7 @@ class EditorToolBar extends StatelessWidget {
// tooltip: 'Search',
// icon: Icons.search,
// onTap: () async {
// // await javascriptExecutorBase.insertNumberedList();
// // await javascriptExecutor.insertNumberedList();
// },
// ),
],
@ -335,10 +320,4 @@ class EditorToolBar extends StatelessWidget {
),
);
}
// Hide the keyboard using JavaScript since it's being opened in a WebView
// https://stackoverflow.com/a/8263376/10835183
_closeKeyboard() async {
// controller!.evaluateJavascript('document.activeElement.blur();');
}
}

View File

@ -23,19 +23,13 @@ class FontsDialog extends StatelessWidget {
InkWell(
child: Html(data: '<p style="font-family:${font.name}">'
'${basename(font.path!)}</p>'),
onTap: () => Navigator.pop(context, font.path),
onTap: () {
Navigator.pop(context, font.name);
},
)
],
),
),
);
}
fontSlug(FileSystemEntity font) {
String name = basename(font.path);
String slug = name.toLowerCase();
slug = slug.replaceAll(extension(font.path), '');
// print(slug);
return slug;
}
}