parent
78e48eb49b
commit
b07b26326b
16 changed files with 335 additions and 7 deletions
@ -0,0 +1,30 @@ |
||||
# Miscellaneous |
||||
*.class |
||||
*.log |
||||
*.pyc |
||||
*.swp |
||||
.DS_Store |
||||
.atom/ |
||||
.buildlog/ |
||||
.history |
||||
.svn/ |
||||
migrate_working_dir/ |
||||
|
||||
# IntelliJ related |
||||
*.iml |
||||
*.ipr |
||||
*.iws |
||||
.idea/ |
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in |
||||
# VS Code which you may wish to be included in version control, so this line |
||||
# is commented out by default. |
||||
#.vscode/ |
||||
|
||||
# Flutter/Dart/Pub related |
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. |
||||
/pubspec.lock |
||||
**/doc/api/ |
||||
.dart_tool/ |
||||
.packages |
||||
build/ |
@ -0,0 +1,10 @@ |
||||
# This file tracks properties of this Flutter project. |
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc. |
||||
# |
||||
# This file should be version controlled and should not be manually edited. |
||||
|
||||
version: |
||||
revision: "d211f42860350d914a5ad8102f9ec32764dc6d06" |
||||
channel: "stable" |
||||
|
||||
project_type: package |
@ -0,0 +1,3 @@ |
||||
## 0.0.1 |
||||
|
||||
* TODO: Describe initial release. |
@ -0,0 +1 @@ |
||||
TODO: Add your license here. |
@ -0,0 +1,23 @@ |
||||
# Flutter Quill HTML |
||||
A extension for [flutter_quill](https://pub.dev/packages/flutter_quill) package to add support for dealing with conversion to/from html |
||||
|
||||
It uses [vsc_quill_delta_to_html](https://pub.dev/packages/vsc_quill_delta_to_html) package to convert the the delta to HTML |
||||
|
||||
## Features |
||||
|
||||
```markdown |
||||
- Easy to use |
||||
- Support with Flutter Quill package |
||||
``` |
||||
|
||||
## Getting started |
||||
|
||||
This will be updated soon. |
||||
|
||||
## Usage |
||||
|
||||
Take a look at the example of the repo, This will be updated soon. |
||||
|
||||
## Additional information |
||||
|
||||
This will be updated soon. |
@ -0,0 +1,36 @@ |
||||
include: package:flutter_lints/flutter.yaml |
||||
|
||||
analyzer: |
||||
errors: |
||||
undefined_prefixed_name: ignore |
||||
unsafe_html: ignore |
||||
linter: |
||||
rules: |
||||
always_declare_return_types: true |
||||
always_put_required_named_parameters_first: true |
||||
annotate_overrides: true |
||||
avoid_empty_else: true |
||||
avoid_escaping_inner_quotes: true |
||||
avoid_print: true |
||||
avoid_redundant_argument_values: true |
||||
avoid_types_on_closure_parameters: true |
||||
avoid_void_async: true |
||||
cascade_invocations: true |
||||
directives_ordering: true |
||||
omit_local_variable_types: true |
||||
prefer_const_constructors: true |
||||
prefer_const_constructors_in_immutables: true |
||||
prefer_const_declarations: true |
||||
prefer_final_fields: true |
||||
prefer_final_in_for_each: true |
||||
prefer_final_locals: true |
||||
prefer_initializing_formals: true |
||||
prefer_int_literals: true |
||||
prefer_interpolation_to_compose_strings: true |
||||
prefer_relative_imports: true |
||||
prefer_single_quotes: true |
||||
sort_constructors_first: true |
||||
sort_unnamed_constructors_first: true |
||||
unnecessary_lambdas: true |
||||
unnecessary_parenthesis: true |
||||
unnecessary_string_interpolations: true |
@ -0,0 +1 @@ |
||||
Subproject commit 22e49a1abe72894f6666baedcc00fb89f13d2c4a |
@ -0,0 +1,132 @@ |
||||
library flutter_quill_html; |
||||
|
||||
import 'dart:convert' show jsonDecode; |
||||
|
||||
import 'package:delta_markdown/delta_markdown.dart' show markdownToDelta; |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter_quill/flutter_quill.dart' show Delta; |
||||
// ignore: depend_on_referenced_packages |
||||
import 'package:html/dom.dart' as html_dom; |
||||
// ignore: depend_on_referenced_packages |
||||
import 'package:html/parser.dart' as html_parse; |
||||
import 'package:html2md/html2md.dart' as html2md; |
||||
import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart' |
||||
as conventer show ConverterOptions, QuillDeltaToHtmlConverter; |
||||
|
||||
typedef ConverterOptions = conventer.ConverterOptions; |
||||
|
||||
extension DeltaHtmlExt on Delta { |
||||
String toHtml({ConverterOptions? options}) { |
||||
final html = conventer.QuillDeltaToHtmlConverter( |
||||
List.castFrom(toJson()), |
||||
options, |
||||
).convert(); |
||||
return html; |
||||
} |
||||
|
||||
static Delta fromHtml(String html) { |
||||
return Delta.fromJson( |
||||
jsonDecode( |
||||
markdownToDelta( |
||||
html2md.convert(html), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
} |
||||
|
||||
// From https://github.com/singerdmx/flutter-quill/issues/1100#issuecomment-1681274676 |
||||
@immutable |
||||
class HtmlToDeltaConverter { |
||||
static const _collorPattern = r'color: rgb\((\d+), (\d+), (\d+)\);'; |
||||
|
||||
static Delta _parseInlineStyles(html_dom.Element element) { |
||||
var delta = Delta(); |
||||
|
||||
for (final node in element.nodes) { |
||||
final attributes = _parseElementStyles(element); |
||||
|
||||
if (node is html_dom.Text) { |
||||
delta.insert(node.text, attributes); |
||||
} else if (node is html_dom.Element && node.localName == 'img') { |
||||
final src = node.attributes['src']; |
||||
if (src != null) { |
||||
delta.insert({'image': src}); |
||||
} |
||||
} else if (node is html_dom.Element) { |
||||
delta = delta.concat(_parseInlineStyles(node)); |
||||
} |
||||
} |
||||
|
||||
return delta; |
||||
} |
||||
|
||||
static Map<String, dynamic> _parseElementStyles(html_dom.Element element) { |
||||
final attributes = <String, dynamic>{}; |
||||
|
||||
if (element.localName == 'strong') attributes['bold'] = true; |
||||
if (element.localName == 'em') attributes['italic'] = true; |
||||
if (element.localName == 'u') attributes['underline'] = true; |
||||
if (element.localName == 'del') attributes['strike'] = true; |
||||
|
||||
final style = element.attributes['style']; |
||||
if (style != null) { |
||||
final colorValue = _parseColorFromStyle(style); |
||||
if (colorValue != null) attributes['color'] = colorValue; |
||||
|
||||
final bgColorValue = _parseBackgroundColorFromStyle(style); |
||||
if (bgColorValue != null) attributes['background'] = bgColorValue; |
||||
} |
||||
|
||||
return attributes; |
||||
} |
||||
|
||||
static String? _parseColorFromStyle(String style) { |
||||
if (RegExp(r'(^|\s)color:(\s|$)').hasMatch(style)) { |
||||
return _parseRgbColorFromMatch(RegExp(_collorPattern).firstMatch(style)); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
static String? _parseBackgroundColorFromStyle(String style) { |
||||
if (RegExp(r'(^|\s)background-color:(\s|$)').hasMatch(style)) { |
||||
return _parseRgbColorFromMatch(RegExp(_collorPattern).firstMatch(style)); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
static String? _parseRgbColorFromMatch(RegExpMatch? colorMatch) { |
||||
if (colorMatch != null) { |
||||
try { |
||||
final red = int.parse(colorMatch.group(1)!); |
||||
final green = int.parse(colorMatch.group(2)!); |
||||
final blue = int.parse(colorMatch.group(3)!); |
||||
return '#${red.toRadixString(16).padLeft(2, '0')}${green.toRadixString(16).padLeft(2, '0')}${blue.toRadixString(16).padLeft(2, '0')}'; |
||||
} catch (e) { |
||||
// debugPrintStack(label: e.toString()); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
static Delta htmlToDelta(String html) { |
||||
final document = html_parse.parse(html); |
||||
var delta = Delta(); |
||||
|
||||
for (final node in document.body?.nodes ?? []) { |
||||
if (node is html_dom.Element) { |
||||
switch (node.localName) { |
||||
case 'p': |
||||
delta = delta.concat(_parseInlineStyles(node))..insert('\n'); |
||||
break; |
||||
case 'br': |
||||
delta.insert('\n'); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return html.isNotEmpty ? delta : Delta() |
||||
..insert('\n'); |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
name: flutter_quill_html |
||||
description: A extension for flutter_quill package to add support for dealing with conversion to/from html |
||||
version: 0.0.1-experimental.1 |
||||
homepage: https://github.com/singerdmx/flutter-quill/tree/master/packages/flutter_quill_html |
||||
repository: https://github.com/singerdmx/flutter-quill/tree/master/packages/flutter_quill_html |
||||
|
||||
topics: |
||||
- ui |
||||
- widgets |
||||
- widget |
||||
- rich-text-editor |
||||
- quill |
||||
|
||||
environment: |
||||
sdk: '>=3.1.5 <4.0.0' |
||||
flutter: ">=1.17.0" |
||||
|
||||
dependencies: |
||||
flutter: |
||||
sdk: flutter |
||||
flutter_quill: ^8.5.1 |
||||
vsc_quill_delta_to_html: ^1.0.3 |
||||
html2md: ^1.3.1 |
||||
delta_markdown: |
||||
path: ./delta_markdown |
||||
|
||||
dev_dependencies: |
||||
flutter_test: |
||||
sdk: flutter |
||||
flutter_lints: ^3.0.1 |
||||
|
||||
# For information on the generic Dart part of this file, see the |
||||
# following page: https://dart.dev/tools/pub/pubspec |
||||
|
||||
# The following section is specific to Flutter packages. |
||||
flutter: |
||||
|
||||
uses-material-design: true |
@ -0,0 +1,3 @@ |
||||
dependency_overrides: |
||||
flutter_quill: |
||||
path: ../../ |
@ -0,0 +1,7 @@ |
||||
import 'package:flutter_test/flutter_test.dart'; |
||||
|
||||
void main() { |
||||
test('No tests for now', () { |
||||
expect(true, true); |
||||
}); |
||||
} |
Loading…
Reference in new issue