Merge pull request #8 from JideGuru/v0.0.4

chore: prepare release
This commit is contained in:
Festus Olusegun 2021-06-08 19:53:11 +01:00 committed by GitHub
commit 807d2ca2a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 199 additions and 155 deletions

View File

@ -30,7 +30,6 @@ Based on https://github.com/dankito/RichTextEditor, but for Flutter.
## 📸 Screenshots
<img src="https://github.com/JideGuru/rich_editor/raw/master/res/1.png" width="400">
<img src="https://github.com/JideGuru/rich_editor/raw/master/res/2.png" width="400">
## Usage

View File

@ -60,14 +60,11 @@ class BasicDemo extends StatelessWidget {
),
body: RichEditor(
key: keyEditor,
// value: '''
// <h1>Heading 1</h1>
// <h2>Heading 2</h2>
// <h3>Heading 3</h3>
// <h4>Heading 4</h4>
// <h5>Heading 5</h5>
// <h6>Heading 6</h6>
// ''', // initial HTML data
value: '''
Hello, This is a rich text Editor for Flutter. It supports most things like Bold, italics and underline.
As well as Subscript, Superscript, Colored text, Colors bg text and hyperlink.
Images and Videos are also supports
''', // initial HTML data
editorOptions: RichEditorOptions(
placeholder: 'Start typing',
// backgroundColor: Colors.blueGrey, // Editor's bg color

View File

@ -211,7 +211,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.3"
version: "0.0.4"
sky_engine:
dependency: transitive
description: flutter

View File

@ -1,12 +1,10 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:rich_editor/src/extensions/extensions.dart';
import 'package:rich_editor/src/models/callbacks/did_html_change_listener.dart';
import 'package:rich_editor/src/models/callbacks/html_changed_listener.dart';
import 'package:rich_editor/src/models/callbacks/loaded_listener.dart';
import 'package:rich_editor/src/models/editor_state.dart';
import 'package:rich_editor/src/models/enum/command_name.dart';
import '../models/command_state.dart';
@ -43,10 +41,13 @@ class JavascriptExecutorBase {
List<LoadedListener> loadedListeners = <LoadedListener>[];
/// Initialise the controller so we don't have to
/// pass a controller into every Method
init(InAppWebViewController? controller) {
_controller = controller;
}
/// Run Javascript commands in the editor using the webview controller
executeJavascript(String command) async {
return await _controller!.evaluateJavascript(source: 'editor.$command');
}
@ -55,14 +56,16 @@ class JavascriptExecutorBase {
return htmlField!;
}
/// Display HTML data in editor
setHtml(String html) async {
String? baseUrl;
await executeJavascript("setHtml('" + encodeHtml(html) + "', '$baseUrl');");
htmlField = html;
}
/// Get current HTML data from Editor
getCurrentHtml() async {
String? html = await executeJavascript('getEncodedHtml()');
String? html = await executeJavascript('getEncodedHtml();');
String? decodedHtml = decodeHtml(html!);
if (decodedHtml!.startsWith('"') && decodedHtml.endsWith('"')) {
decodedHtml = decodedHtml.substring(1, decodedHtml.length - 1);
@ -70,57 +73,72 @@ class JavascriptExecutorBase {
return decodedHtml;
}
/// Check if editor's content has been modified
bool isDefaultRichTextEditorHtml(String html) {
return defaultHtml == html;
}
// Text commands
/// Undo last editor command/action
undo() async {
await executeJavascript("undo();");
}
/// Redo last editor command/action
redo() async {
await executeJavascript("redo();");
}
/// Make selected or subsequent text Bold
setBold() async {
await executeJavascript("setBold();");
}
/// Make selected or subsequent text Italic
setItalic() async {
await executeJavascript("setItalic();");
}
/// Make selected or subsequent text Underlined
setUnderline() async {
await executeJavascript("setUnderline();");
}
/// Make selected or subsequent text Subscript
setSubscript() async {
await executeJavascript("setSubscript();");
}
/// Make selected or subsequent text Superscript
setSuperscript() async {
await executeJavascript("setSuperscript();");
}
/// Strike through selected text
setStrikeThrough() async {
await executeJavascript("setStrikeThrough();");
}
/// Set a [Color] for the selected text
setTextColor(Color? color) async {
String? hex = color!.toHexColorString();
await executeJavascript("setTextColor('$hex');");
}
/// Set a [Color] for the selected text's background
setTextBackgroundColor(Color? color) async {
String? hex = color!.toHexColorString();
await executeJavascript("setTextBackgroundColor('$hex');");
}
/// Apply a font face to selected text
setFontName(String fontName) async {
await executeJavascript("setFontName('$fontName');");
}
/// Apply a font size to selected text
/// (Value can only be between 1 and 7)
setFontSize(int fontSize) async {
if (fontSize < 1 || fontSize > 7) {
throw ("Font size should have a value between 1-7");
@ -128,6 +146,8 @@ class JavascriptExecutorBase {
await executeJavascript("setFontSize('$fontSize');");
}
/// Apply a Heading style to selected text
/// (Value can only be between 1 and 6)
setHeading(int heading) async {
await executeJavascript("setHeading('$heading');");
}
@ -140,47 +160,58 @@ class JavascriptExecutorBase {
await executeJavascript("setPreformat();");
}
/// Create BlockQuote / make selected text a BlockQuote
setBlockQuote() async {
await executeJavascript("setBlockQuote();");
}
/// Remove formatting from selected text
removeFormat() async {
await executeJavascript("removeFormat();");
}
/// Align content left
setJustifyLeft() async {
await executeJavascript("setJustifyLeft();");
}
/// Align content center
setJustifyCenter() async {
await executeJavascript("setJustifyCenter();");
}
/// Align content right
setJustifyRight() async {
await executeJavascript("setJustifyRight();");
}
/// Justify content
setJustifyFull() async {
await executeJavascript("setJustifyFull();");
}
/// Add indentation
setIndent() async {
await executeJavascript("setIndent();");
}
/// Remove indentation
setOutdent() async {
await executeJavascript("setOutdent();");
}
/// Start an unordered list
insertBulletList() async {
await executeJavascript("insertBulletList();");
}
/// Start a ordered list
insertNumberedList() async {
await executeJavascript("insertNumberedList();");
}
// Insert element
/// Insert hyper link / make selected text an hyperlink
insertLink(String url, String title) async {
await executeJavascript("insertLink('$url', '$title');");
}
@ -217,50 +248,63 @@ class JavascriptExecutorBase {
);
}
/// Add a checkbox to the current editor
insertCheckbox(String text) async {
await executeJavascript("insertCheckbox('$text');");
}
/// Insert HTML code into the editor
/// (It wont display the HTML code but it'll render it)
insertHtml(String html) async {
String? encodedHtml = encodeHtml(html);
await executeJavascript("insertHtml('$encodedHtml');");
}
/// Enable Images resizing
makeImagesResizeable() async {
await executeJavascript("makeImagesResizeable();");
}
/// Disable Images resizing
disableImageResizing() async {
await executeJavascript("disableImageResizing();");
}
// Editor settings commands
/// Focus on editor and bring up keyboard
focus() async {
await executeJavascript("focus();");
SystemChannels.textInput.invokeMethod('TextInput.show');
}
/// Remove focus from the editor and close the keyboard
unFocus() async {
await executeJavascript("blurFocus();");
}
/// Set a [Color] for the editor's background
setBackgroundColor(Color? color) async {
String? hex = color!.toHexColorString();
await executeJavascript("setBackgroundColor('$hex');");
}
/// Set an image for the editor's background
setBackgroundImage(String image) async {
await executeJavascript("setBackgroundImage('$image');");
}
/// Set a default editor text color
setBaseTextColor(Color? color) async {
String? hex = color!.toHexColorString();
await executeJavascript("setBaseTextColor('$hex');");
}
/// Set a default editor text font family
setBaseFontFamily(String fontFamily) async {
await executeJavascript("setBaseFontFamily('$fontFamily');");
}
/// Add padding to the editor's content
setPadding(EdgeInsets? padding) async {
String left = padding!.left.toString();
String top = padding.top.toString();
@ -270,19 +314,23 @@ class JavascriptExecutorBase {
"setPadding('${left}px', '${top}px', '${right}px', '${bottom}px');");
}
// Doesnt actually work for' now
/// Set a hint when the editor is empty
/// Doesn't actually work for now
setPlaceholder(String placeholder) async {
await executeJavascript("setPlaceholder('$placeholder');");
}
/// Set editor's width in pixels
setEditorWidth(int px) async {
await executeJavascript("setWidth('" + px.toString() + "px');");
}
/// Set editor's height in pixels
setEditorHeight(int px) async {
await executeJavascript("setHeight('" + px.toString() + "px');");
}
/// Enable text input on editor
setInputEnabled(bool inputEnabled) async {
await executeJavascript("setInputEnabled($inputEnabled);");
}
@ -295,143 +343,143 @@ class JavascriptExecutorBase {
return Uri.encodeFull(html);
}
bool shouldOverrideUrlLoading(String url) {
String decodedUrl;
try {
decodedUrl = decodeHtml(url);
} catch (e) {
// No handling
return false;
}
if (url.indexOf(editorStateChangedCallbackScheme) == 0) {
editorStateChanged(
decodedUrl.substring(editorStateChangedCallbackScheme.length));
return true;
}
return false;
}
editorStateChanged(String statesString) {
try {
var editorState = EditorState.fromJson(jsonDecode(statesString));
bool currentHtmlChanged = this.htmlField != editorState.html;
this.htmlField = editorState.html;
retrievedEditorState(
editorState.didHtmlChange!, editorState.commandStates!);
if (currentHtmlChanged) {
// fireHtmlChangedListenersAsync(editorState.html);
}
} catch (e) {
throw ("Could not parse command states: $statesString $e");
}
}
retrievedEditorState(
bool didHtmlChange, Map<CommandName, CommandState> commandStates) {
if (this.didHtmlChange != didHtmlChange) {
this.didHtmlChange = didHtmlChange;
didHtmlChangeListeners.forEach((element) {
element.didHtmlChange(didHtmlChange);
});
}
handleRetrievedCommandStates(commandStates);
}
handleRetrievedCommandStates(Map<CommandName, CommandState> commandStates) {
determineDerivedCommandStates(commandStates);
this.commandStates = commandStates;
commandStatesChangedListeners.forEach((element) {
element = this.commandStates;
});
}
determineDerivedCommandStates(Map<CommandName, CommandState> commandStates) {
if (commandStates[CommandName.FORMATBLOCK] != null) {
var formatCommandState = commandStates[CommandName.FORMATBLOCK];
commandStates.update(
CommandName.H1,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h1")),
);
commandStates.update(
CommandName.H2,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h2")));
commandStates.update(
CommandName.H3,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h3")),
);
commandStates.update(
CommandName.H4,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h4")),
);
commandStates.update(
CommandName.H5,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h5")),
);
commandStates.update(
CommandName.H6,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "h6")),
);
commandStates.update(
CommandName.P,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "p")),
);
commandStates.update(
CommandName.PRE,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "pre")),
);
commandStates.update(
CommandName.BR,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "")),
);
commandStates.update(
CommandName.BLOCKQUOTE,
(val) => CommandState(formatCommandState!.executable,
isFormatActivated(formatCommandState, "blockquote")),
);
}
if (commandStates[CommandName.INSERTHTML] != null) {
CommandState? insertHtmlState = commandStates[CommandName.INSERTHTML];
commandStates.update(CommandName.INSERTLINK, (val) => insertHtmlState!);
commandStates.update(CommandName.INSERTIMAGE, (val) => insertHtmlState!);
commandStates.update(
CommandName.INSERTCHECKBOX, (val) => insertHtmlState!);
}
}
String isFormatActivated(CommandState formatCommandState, String format) {
return (formatCommandState.value == format)
.toString(); // rich_text_editor.js reports boolean values as string, so we also have to convert it to string
}
addCommandStatesChangedListener(
Map<CommandName, CommandState> commandStates) {
commandStatesChangedListeners.add(commandStates);
// listener.invoke(commandStates);
}
addDidHtmlChangeListener(DidHtmlChangeListener listener) {
didHtmlChangeListeners.add(listener);
}
addHtmlChangedListener(HtmlChangedListener listener) {
htmlChangedListeners.add(listener);
}
// bool shouldOverrideUrlLoading(String url) {
// String decodedUrl;
// try {
// decodedUrl = decodeHtml(url);
// } catch (e) {
// // No handling
// return false;
// }
//
// if (url.indexOf(editorStateChangedCallbackScheme) == 0) {
// editorStateChanged(
// decodedUrl.substring(editorStateChangedCallbackScheme.length));
// return true;
// }
//
// return false;
// }
//
// editorStateChanged(String statesString) {
// try {
// var editorState = EditorState.fromJson(jsonDecode(statesString));
//
// bool currentHtmlChanged = this.htmlField != editorState.html;
// this.htmlField = editorState.html;
//
// retrievedEditorState(
// editorState.didHtmlChange!, editorState.commandStates!);
//
// if (currentHtmlChanged) {
// // fireHtmlChangedListenersAsync(editorState.html);
// }
// } catch (e) {
// throw ("Could not parse command states: $statesString $e");
// }
// }
//
// retrievedEditorState(
// bool didHtmlChange, Map<CommandName, CommandState> commandStates) {
// if (this.didHtmlChange != didHtmlChange) {
// this.didHtmlChange = didHtmlChange;
// didHtmlChangeListeners.forEach((element) {
// element.didHtmlChange(didHtmlChange);
// });
// }
//
// handleRetrievedCommandStates(commandStates);
// }
//
// handleRetrievedCommandStates(Map<CommandName, CommandState> commandStates) {
// determineDerivedCommandStates(commandStates);
//
// this.commandStates = commandStates;
// commandStatesChangedListeners.forEach((element) {
// element = this.commandStates;
// });
// }
//
// determineDerivedCommandStates(Map<CommandName, CommandState> commandStates) {
// if (commandStates[CommandName.FORMATBLOCK] != null) {
// var formatCommandState = commandStates[CommandName.FORMATBLOCK];
// commandStates.update(
// CommandName.H1,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "h1")),
// );
// commandStates.update(
// CommandName.H2,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "h2")));
// commandStates.update(
// CommandName.H3,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "h3")),
// );
// commandStates.update(
// CommandName.H4,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "h4")),
// );
// commandStates.update(
// CommandName.H5,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "h5")),
// );
// commandStates.update(
// CommandName.H6,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "h6")),
// );
// commandStates.update(
// CommandName.P,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "p")),
// );
// commandStates.update(
// CommandName.PRE,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "pre")),
// );
// commandStates.update(
// CommandName.BR,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "")),
// );
// commandStates.update(
// CommandName.BLOCKQUOTE,
// (val) => CommandState(formatCommandState!.executable,
// isFormatActivated(formatCommandState, "blockquote")),
// );
// }
//
// if (commandStates[CommandName.INSERTHTML] != null) {
// CommandState? insertHtmlState = commandStates[CommandName.INSERTHTML];
// commandStates.update(CommandName.INSERTLINK, (val) => insertHtmlState!);
// commandStates.update(CommandName.INSERTIMAGE, (val) => insertHtmlState!);
// commandStates.update(
// CommandName.INSERTCHECKBOX, (val) => insertHtmlState!);
// }
// }
//
// String isFormatActivated(CommandState formatCommandState, String format) {
// return (formatCommandState.value == format)
// .toString(); // rich_text_editor.js reports boolean values as string, so we also have to convert it to string
// }
//
// addCommandStatesChangedListener(
// Map<CommandName, CommandState> commandStates) {
// commandStatesChangedListeners.add(commandStates);
//
// // listener.invoke(commandStates);
// }
//
// addDidHtmlChangeListener(DidHtmlChangeListener listener) {
// didHtmlChangeListeners.add(listener);
// }
//
// addHtmlChangedListener(HtmlChangedListener listener) {
// htmlChangedListeners.add(listener);
// }
}

View File

@ -1,6 +1,6 @@
name: rich_editor
description: WYSIWYG editor for Flutter with a rich set of supported formatting options.
version: 0.0.3
version: 0.0.4
homepage: https://github.com/JideGuru/rich_editor
environment:

BIN
res/1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
res/2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 KiB