@@ -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