Skip to content

Commit 27d0560

Browse files
authored
feat: improve parser newline sensitivity and fix empty list items issues (#118)
1 parent b44d6e8 commit 27d0560

2 files changed

Lines changed: 110 additions & 34 deletions

File tree

example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1940,7 +1940,7 @@ SPEC CHECKSUMS:
19401940
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
19411941
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
19421942
hermes-engine: c32f2e405098bc1ebe30630a051ddce6f21d3c2e
1943-
RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809
1943+
RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82
19441944
RCTDeprecation: 0ada4fb1e5c5637bff940dc40b94e2d3bf96b0ab
19451945
RCTRequired: 76ca80ff10acb3834ed0dacba9645645009578a2
19461946
RCTTypeSafety: 01b27f48153eb2d222c0ad4737fe291e9549946a

ios/parser/EditorParser.mm

Lines changed: 109 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,40 +53,53 @@ - (NSString *)parseToHtmlFromRange:(NSRange)range {
5353
unichar currentCharacterChar = [_editor->textView.textStorage.string characterAtIndex:currentRange.location];
5454

5555
if([[NSCharacterSet newlineCharacterSet] characterIsMember:currentCharacterChar]) {
56-
// just an empty line - only br tag and no style tags
5756
if(newLine) {
58-
// keep the newLine at YES
59-
60-
// br is not a valid child of lists:
61-
if(inOrderedList || inUnorderedList) {
62-
[result appendString:@"\n<li></li>"];
57+
// we can either have an empty list item OR need to close the list and put a BR in such a situation
58+
// the existence of the list must be checked on 0 length range, not on the newline character
59+
if(inOrderedList) {
60+
OrderedListStyle *oStyle = _editor->stylesDict[@(OrderedList)];
61+
BOOL detected = [oStyle detectStyle: NSMakeRange(currentRange.location, 0)];
62+
if(detected) {
63+
[result appendString:@"\n<li></li>"];
64+
} else {
65+
[result appendString:@"\n</ol>\n<br>"];
66+
inOrderedList = NO;
67+
}
68+
} else if(inUnorderedList) {
69+
UnorderedListStyle *uStyle = _editor->stylesDict[@(UnorderedList)];
70+
BOOL detected = [uStyle detectStyle: NSMakeRange(currentRange.location, 0)];
71+
if(detected) {
72+
[result appendString:@"\n<li></li>"];
73+
} else {
74+
[result appendString:@"\n</ul>\n<br>"];
75+
inUnorderedList = NO;
76+
}
6377
} else {
6478
[result appendString:@"\n<br>"];
6579
}
66-
continue;
67-
}
68-
69-
// newline finishes a paragraph and all style tags need to be closed
70-
// we use previous styles
71-
NSArray<NSNumber*> *sortedEndedStyles = [previousActiveStyles sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"intValue" ascending:NO]]];
72-
73-
// append closing tags
74-
for(NSNumber *style in sortedEndedStyles) {
75-
NSString *tagContent = [self tagContentForStyle:style openingTag:NO location:currentRange.location];
76-
[result appendString: [NSString stringWithFormat:@"</%@>", tagContent]];
77-
}
78-
79-
// append closing paragraph tag
80-
if([previousActiveStyles containsObject:@([UnorderedListStyle getStyleType])] ||
81-
[previousActiveStyles containsObject:@([OrderedListStyle getStyleType])] ||
82-
[previousActiveStyles containsObject:@([H1Style getStyleType])] ||
83-
[previousActiveStyles containsObject:@([H2Style getStyleType])] ||
84-
[previousActiveStyles containsObject:@([H3Style getStyleType])] ||
85-
[previousActiveStyles containsObject:@([BlockQuoteStyle getStyleType])]
86-
) {
87-
// do nothing, proper closing paragraph tags have been already appended
8880
} else {
89-
[result appendString:@"</p>"];
81+
// newline finishes a paragraph and all style tags need to be closed
82+
// we use previous styles
83+
NSArray<NSNumber*> *sortedEndedStyles = [previousActiveStyles sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"intValue" ascending:NO]]];
84+
85+
// append closing tags
86+
for(NSNumber *style in sortedEndedStyles) {
87+
NSString *tagContent = [self tagContentForStyle:style openingTag:NO location:currentRange.location];
88+
[result appendString: [NSString stringWithFormat:@"</%@>", tagContent]];
89+
}
90+
91+
// append closing paragraph tag
92+
if([previousActiveStyles containsObject:@([UnorderedListStyle getStyleType])] ||
93+
[previousActiveStyles containsObject:@([OrderedListStyle getStyleType])] ||
94+
[previousActiveStyles containsObject:@([H1Style getStyleType])] ||
95+
[previousActiveStyles containsObject:@([H2Style getStyleType])] ||
96+
[previousActiveStyles containsObject:@([H3Style getStyleType])] ||
97+
[previousActiveStyles containsObject:@([BlockQuoteStyle getStyleType])]
98+
) {
99+
// do nothing, proper closing paragraph tags have been already appended
100+
} else {
101+
[result appendString:@"</p>"];
102+
}
90103
}
91104

92105
// clear the previous styles
@@ -392,12 +405,24 @@ - (NSString * _Nullable)initiallyProcessHtml:(NSString * _Nonnull)html {
392405
if(html.length >= 15) {
393406
NSString *firstSix = [html substringWithRange:NSMakeRange(0, 6)];
394407
NSString *lastSeven = [html substringWithRange:NSMakeRange(html.length-7, 7)];
408+
NSInteger newlinesCount = [[html componentsSeparatedByString:@"\n"] count] - 1;
395409

396410
if([firstSix isEqualToString:@"<html>"] && [lastSeven isEqualToString:@"</html>"]) {
397-
// looks like our format
398-
// we want to get the string without <html> and </html> and their newlines
399-
// so we skip first 7 characters and get the string 7+8 = 15 characters shorter
400-
fixedHtml = [html substringWithRange: NSMakeRange(7, html.length - 15)];
411+
if(newlinesCount >= 2) {
412+
// looks like our format
413+
// we want to get the string without <html> and </html> and their newlines
414+
// so we skip first 7 characters and get the string 7+8 = 15 characters shorter
415+
fixedHtml = [html substringWithRange: NSMakeRange(7, html.length - 15)];
416+
} else {
417+
// most likely a valid html but with some newline differences
418+
fixedHtml = [html copy];
419+
// firstly remove newlined html tags if any:
420+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>\n" withString:@""];
421+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"\n</html>" withString:@""];
422+
// fallback; remove html tags without their newlines
423+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>" withString:@""];
424+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</html>" withString:@""];
425+
}
401426
} else {
402427
// in other case we are most likely working with some external html - try getting the styles from between body tags
403428
NSRange openingBodyRange = [html rangeOfString:@"<body>"];
@@ -411,9 +436,60 @@ - (NSString * _Nullable)initiallyProcessHtml:(NSString * _Nonnull)html {
411436
}
412437
}
413438

439+
// second processing - try fixing htmls with wrong newlines' setup
440+
if(fixedHtml != nullptr) {
441+
NSInteger newlinesCount = [[fixedHtml componentsSeparatedByString:@"/n"] count] - 1;
442+
if(newlinesCount == 0) {
443+
// add <br> tag wherever needed
444+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<p></p>" withString:@"<br>"];
445+
446+
// remove <p> tags inside of <li>
447+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<li><p>" withString:@"<li>"];
448+
fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</p></li>" withString:@"</li>"];
449+
450+
// tags that have to be in separate lines
451+
fixedHtml = [self stringByAddingNewlinesToTag:@"<br>" inString:fixedHtml leading:YES trailing:YES];
452+
fixedHtml = [self stringByAddingNewlinesToTag:@"<ul>" inString:fixedHtml leading:YES trailing:YES];
453+
fixedHtml = [self stringByAddingNewlinesToTag:@"</ul>" inString:fixedHtml leading:YES trailing:YES];
454+
fixedHtml = [self stringByAddingNewlinesToTag:@"<ol>" inString:fixedHtml leading:YES trailing:YES];
455+
fixedHtml = [self stringByAddingNewlinesToTag:@"</ol>" inString:fixedHtml leading:YES trailing:YES];
456+
fixedHtml = [self stringByAddingNewlinesToTag:@"<blockquote>" inString:fixedHtml leading:YES trailing:YES];
457+
fixedHtml = [self stringByAddingNewlinesToTag:@"</blockquote>" inString:fixedHtml leading:YES trailing:YES];
458+
459+
// line opening tags
460+
fixedHtml = [self stringByAddingNewlinesToTag:@"<p>" inString:fixedHtml leading:YES trailing:NO];
461+
fixedHtml = [self stringByAddingNewlinesToTag:@"<li>" inString:fixedHtml leading:YES trailing:NO];
462+
fixedHtml = [self stringByAddingNewlinesToTag:@"<h1>" inString:fixedHtml leading:YES trailing:NO];
463+
fixedHtml = [self stringByAddingNewlinesToTag:@"<h2>" inString:fixedHtml leading:YES trailing:NO];
464+
fixedHtml = [self stringByAddingNewlinesToTag:@"<h3>" inString:fixedHtml leading:YES trailing:NO];
465+
466+
// line closing tags
467+
fixedHtml = [self stringByAddingNewlinesToTag:@"</p>" inString:fixedHtml leading:NO trailing:YES];
468+
fixedHtml = [self stringByAddingNewlinesToTag:@"</li>" inString:fixedHtml leading:NO trailing:YES];
469+
fixedHtml = [self stringByAddingNewlinesToTag:@"</h1>" inString:fixedHtml leading:NO trailing:YES];
470+
fixedHtml = [self stringByAddingNewlinesToTag:@"</h2>" inString:fixedHtml leading:NO trailing:YES];
471+
fixedHtml = [self stringByAddingNewlinesToTag:@"</h3>" inString:fixedHtml leading:NO trailing:YES];
472+
}
473+
}
474+
414475
return fixedHtml;
415476
}
416477

478+
- (NSString *)stringByAddingNewlinesToTag:(NSString *)tag inString:(NSString *)html leading:(BOOL)leading trailing:(BOOL)trailing {
479+
NSString *str = [html copy];
480+
if(leading) {
481+
NSString *formattedTag = [NSString stringWithFormat:@">%@", tag];
482+
NSString *formattedNewTag = [NSString stringWithFormat:@">\n%@", tag];
483+
str = [str stringByReplacingOccurrencesOfString:formattedTag withString:formattedNewTag];
484+
}
485+
if(trailing) {
486+
NSString *formattedTag = [NSString stringWithFormat:@"%@<", tag];
487+
NSString *formattedNewTag = [NSString stringWithFormat:@"%@\n<", tag];
488+
str = [str stringByReplacingOccurrencesOfString:formattedTag withString:formattedNewTag];
489+
}
490+
return str;
491+
}
492+
417493
- (NSArray *)getTextAndStylesFromHtml:(NSString *)fixedHtml {
418494
NSMutableString *plainText = [[NSMutableString alloc] initWithString: @""];
419495
NSMutableDictionary *ongoingTags = [[NSMutableDictionary alloc] init];

0 commit comments

Comments
 (0)