-
Notifications
You must be signed in to change notification settings - Fork 844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Combination of styles numberList and text #1940
Comments
Hello Team, When you insert a simple text following by a list, blockquote or code-block, the delta generating by the editor is incorrect. Example of generated delta :
The bullet1 don't respect delta format So when using vcs_quill_delta_to_html, the html is wrong :
The version of flutter_quill 8.6.4 used by the app example in vcs_quill_delta_to_html is ok :
Do you confirm this ? Thanks for your help |
@scolnet I noticed that the problem occurs due to the delta at the time of conversions. But so far I have not been able to solve my problem. Have you managed to do so? |
Hello @Leonardo1952
Note that it's ok if you tap the text of the bullet before and after format with list button. I found the problem occurs in the insert rule : PreserveInlineStylesRule (/lib/src/models/rules/insert.dart) if(attributes!=null && (attributes.containsKey(Attribute.list.key)||attributes.containsKey(Attribute.codeBlock.key)||attributes.containsKey(Attribute.blockQuote.key))){
return null;
} complete code : class PreserveInlineStylesRule extends InsertRule {
const PreserveInlineStylesRule();
@override
Delta? applyRule(
Document document,
int index, {
int? len,
Object? data,
Attribute? attribute,
}) {
if (data is! String || data.contains('\n')) {
return null;
}
final itr = DeltaIterator(document.toDelta());
var prev = itr.skip(len == 0 ? index : index + 1);
if (prev == null || prev.data is! String) return null;
if ((prev.data as String).endsWith('\n')) {
if (prev.attributes != null) {
for (final key in prev.attributes!.keys) {
if (!Attribute.inlineKeys.contains(key)) {
return null;
}
}
}
prev = itr
.next(); // at the start of a line, apply the style for the current line and not the style for the preceding line
}
final attributes = prev.attributes;
if(attributes!=null && (attributes.containsKey(Attribute.list.key)||attributes.containsKey(Attribute.codeBlock.key)||attributes.containsKey(Attribute.blockQuote.key))){
return null;
}
final text = data;
if (attributes == null || !attributes.containsKey(Attribute.link.key)) {
return Delta()
..retain(index + (len ?? 0))
..insert(text, attributes);
}
attributes.remove(Attribute.link.key);
final delta = Delta()
..retain(index + (len ?? 0))
..insert(text, attributes.isEmpty ? null : attributes);
final next = itr.next();
final nextAttributes = next.attributes ?? const <String, dynamic>{};
if (!nextAttributes.containsKey(Attribute.link.key)) {
return delta;
}
if (attributes[Attribute.link.key] == nextAttributes[Attribute.link.key]) {
return Delta()
..retain(index + (len ?? 0))
..insert(text, attributes);
}
return delta;
}
} It's a bit complex, I don't know the algorithm well enough to ensure that it's the right correction to do. |
@AtlasAutocode made several sound style-related contributions, so maybe he will be able to help with this issue too. I will try to take a look a bit later is it's not resolved. |
I'm currently working on other fixes in PreserveInlineStylesRule. I'm not familiar with correct content of deltas and conversion to html. |
I also use 'return null' earlier in the code. However, I have found that this is not correct. I cannot reproduce the error in this posting with my current code. I need to go back to the released version to compare. |
Have submitted a PR that should resolve this issue. |
After first tests, it seems OK |
Did you run 'pub upgrade' to ensure that all dependencies are updated? I believe HTML output is no longer a part of the core quill editor. It would be helpful to know how you are producing the output since it appears that the fault is with the Delta-to-HTML code. |
@AtlasAutocode The problem is not with the HTML, it's with the Delta being generated by flutter_quill. List and blockquotes are block-level attributes and must be applied on an op with a \n (indicating the end of a block). This bug is also a regression because this package used to generate the correct delta in around 8.6.x. |
I agree with @dsyrstad . If we observe the generated Delta properly, Whereas it must have been: Same goes with the ordered list as well. |
Hello everyone, I didn't do a full of tests with 10.0.0 yet. @AtlasAutocode : I see a new commit in PreserveInlineStyleRule since your last fix by @CatHood0 (2 days ago) |
@dsyrstad your knowledge of deltas is better than mine - would you be able to find the problem and fix it? @scolnet that would narrow our focus - I suspect that this may be a deeper problem in delta creation (and out of my experience - so much to learn - life is good!) @EchoEllet the first line entry for a list is not generating the correct delta. Do we have an expert in debugging deltas that can help? |
It seems that most of the delta experts are no longer contributors to the project for now. I'm not quite familiar with Delta. This is one reason why we need tests and more docs. |
I don't have the time. However there is documentation on https://quilljs.com/docs. It is also the defacto standard for quill delta, so whatever it generates for given input can be used as a reference for flutter_quill. |
It's not related. I just fix an issue with the Rule assume the type of the operation and it could throw exceptions. |
Your The
|
I wanted this issue resolved on a priority, so here's a simple function and it seems to work without issues. Anyone facing the issue and wants to eliminate this particular use case, can use the function below. List<Map<String, dynamic>> transformArray(List<dynamic> inputArray) {
final List<Map<String, dynamic>> result = <Map<String, dynamic>>[];
for (final dynamic item in inputArray) {
if (item is Map<String, dynamic>) {
if (item.containsKey("attributes") && item["attributes"] != null) {
if (item["attributes"]["list"] == "ordered" || item["attributes"]["list"] == "bullet") {
// Split the item into two separate items
result
..add(<String, dynamic>{"insert": item["insert"].replaceAll("\n", "")})
..add(<String, dynamic>{
"insert": "\n",
"attributes": <String, dynamic>{"list": item["attributes"]["list"]}
});
} else {
result.add(item);
}
} else {
result.add(item);
}
}
}
return result;
} This is not a permanent solution. Just a workaround until it is fixed. |
I don't think that is a good idea. I prefer always use the original format, and, if you need the extension DeltaDenormilazer on Delta {
Delta fullDenormalizer() {
if (isEmpty) return this;
final List<Map<String, dynamic>> denormalizedOps =
map<List<Map<String, dynamic>>>((Operation op) => denormalize(op.toJson())).flattened.toList();
return Delta.fromOperations(denormalizedOps.map<fq.Operation>((Map<String, dynamic> e) => fq.Operation.fromJson(e)).toList());
}
List<Map<String, dynamic>> denormalize(Map<String, dynamic> op) {
const String newLine = '\n';
final insertValue = op['insert'];
if (insertValue is Map || insertValue == newLine) {
return <Map<String, dynamic>>[op];
}
final List<String> newlinedArray = tokenizeWithNewLines(insertValue.toString());
if (newlinedArray.length == 1) {
return <Map<String, dynamic>>[op];
}
// Copy op in to keep its attributes, but replace the insert value with a newline.
final Map<String, dynamic> nlObj = <String, dynamic>{
...op,
...<String, String>{'insert': newLine}
};
return newlinedArray.map((String line) {
if (line == newLine) {
return nlObj;
}
return <String, dynamic>{
...op,
...<String, String>{'insert': line},
};
}).toList();
}
}
/// Splits a string [str] by new line characters ("\n"), preserving empty lines
/// as separate tokens in the resulting array.
///
/// Example:
/// ```dart
/// String input = "hello\n\nworld\n ";
/// List<String> tokens = tokenizeWithNewLines(input);
/// print(tokens); // Output: ["hello", "\n", "\n", "world", "\n", " "]
/// ```
///
/// Returns a list of strings where each element represents either a line of text
/// or a new line character.
List<String> tokenizeWithNewLines(String str) {
const String newLine = '\n';
if (str == newLine) {
return <String>[str];
}
List<String> lines = str.split(newLine);
if (lines.length == 1) {
return lines;
}
int lastIndex = lines.length - 1;
return lines.foldIndexed(<String>[], (int ind, List<String> pv, String line) {
if (ind != lastIndex) {
if (line != '') {
pv.add(line);
pv.add(newLine);
} else {
pv.add(newLine);
}
} else if (line != '') {
pv.add(line);
}
return pv;
});
} |
@CatHood0 @BullsEye34 [{"insert":"Text\n\nFirst"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"Second"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"\n1st"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"2nd"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"\n"}] code HTML : <p>Text<br/></p><ul><li>First</li><li>Second</li></ul><p><br/></p><ol><li>1st</li><li>2nd</li></ol><p><br/></p> Could you explain precisely how you enter the data? |
@scolnet I don't know where is the issue. The generated
If you want to apply that |
@CatHood0 |
What I did was: Type in "-" and space and then the bullet item. This was reproducible also in this scenario. On the toolbar, click the button to insert an unordered/ordered list. Start typing. In both the scenarios, the first list item would have the "\n" appended to the item, therefore converting the same to html would become |
This is interesting. Let me try this out. If it is more stable, I'll Definitely use this. |
I'll take a look about it |
Are you using |
I'm using |
This is werid. I getting the same I used the same input text. I'm using the last version of And this is the output (i used directly If you want to know how i get this output, you can use a method like: import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
String convertDeltaToHtml(Document doc, [ConverterOptions? options]) {
return QuillDeltaToHtmlConverter(
doc.toDelta().toJson(),
options, // if this doesn't work, try using ConverterOptions.forEmail()
).convert();
} |
@BullsEye34 Strange, I try with your scenario and i get a correct delta [{"insert":"Text\n\nFirst"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"Second"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"\n1st"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"2nd"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"\n\n"}] so HTML : <p>Text<br/></p><ul><li>First</li><li>Second</li></ul><p><br/></p><ol><li>1st</li><li>2nd</li></ol><p><br/></p> |
It's the same for me. I think could be an issue from the |
Oh, very weird. Let me try upgrading dependencies.... |
My bad. I upgraded my dependencies, and things seem fine now. Very weird because I had upgraded the deps just yesterday. |
Is there an existing issue for this?
Flutter Quill version
9.4.4
Steps to reproduce
Create a normal text, then try to create a numbered list, the list will start to behave strangely.
Expected results
Make sure the spaces and numbering between items are correct.
Actual results
The numbers don't match and unnecessary spaces are added.
Code sample
Code sample
The text was updated successfully, but these errors were encountered: