@@ -22,7 +22,7 @@ struct MarkupNSAttributedStringVisitor: MarkupVisitor {
2222
2323 func visit( _ markup: BreakLineMarkup ) -> Result {
2424 let style = collectMarkupStyle ( markup)
25- return makeString ( in: markup, string: Self . breakLineSymbol, attributes: [ . breaklinePlaceholder: NSAttributedString . Key . BreaklinePlaceholder . breaklineTag ] , style: style)
25+ return makeString ( in: markup, string: Self . breakLineSymbol, attributes: [ . breaklinePlaceholder: BreaklineTag ( ) ] , style: style)
2626 }
2727
2828 func visit( _ markup: RawStringMarkup ) -> Result {
@@ -119,7 +119,16 @@ struct MarkupNSAttributedStringVisitor: MarkupVisitor {
119119
120120 func visit( _ markup: ParagraphMarkup ) -> Result {
121121 let attributedString = collectAttributedString ( markup)
122- let thisAttributedString = NSMutableAttributedString ( attributedString: attributedString)
122+ var thisAttributedString = NSMutableAttributedString ( attributedString: attributedString)
123+
124+ // This code replicates browser behavior by trimming leading and trailing whitespace around HTML tags.
125+ // It removes unnecessary spaces and newlines at the beginning and end of the NSAttributedString.
126+ // If the entire content is just whitespace, it replaces it with an empty string.
127+
128+ if thisAttributedString. string. trimmingCharacters ( in: . whitespacesAndNewlines) . isEmpty {
129+ thisAttributedString = NSMutableAttributedString ( string: " " )
130+ }
131+
123132 thisAttributedString. markPrefixTagBoundaryBreakline ( )
124133 thisAttributedString. markSuffixTagBoundaryBreakline ( )
125134
@@ -221,35 +230,37 @@ extension MarkupNSAttributedStringVisitor {
221230 let mutableAttributedString = NSMutableAttributedString ( attributedString: attributedString)
222231 let totalLength = mutableAttributedString. string. utf16. count
223232
233+ var rangesToDelete : [ NSRange ] = [ ]
234+
224235 // merge tag Boundary Breakline, e.g. </p></div> -> /n/n -> /n
225- var pre : ( NSRange , NSAttributedString . Key . BreaklinePlaceholder ) ?
236+ var pre : ( NSRange , any BreaklinePlaceholder ) ?
226237 mutableAttributedString. enumerateAttribute ( . breaklinePlaceholder, in: NSMakeRange ( 0 , totalLength) ) { value, range, _ in
227- if let breaklinePlaceholder = value as? NSAttributedString . Key . BreaklinePlaceholder {
238+ if let breaklinePlaceholder = value as? any BreaklinePlaceholder {
228239 if range. location == 0 {
229- mutableAttributedString . deleteCharacters ( in : range)
240+ rangesToDelete . append ( range)
230241 } else if let pre = pre {
231242 let preRange = pre. 0
232243 let preBreaklinePlaceholder = pre. 1
233244
234245 switch ( preBreaklinePlaceholder, breaklinePlaceholder) {
235- case ( . breaklineTag , . tagBoundarySuffix ) :
246+ case ( is BreaklineTag , is TagBoundarySuffix ) :
236247 // <br/></div> -> /n/n -> /n
237- mutableAttributedString . deleteCharacters ( in : preRange)
238- case ( . breaklineTag , . tagBoundaryPrefix ) :
248+ rangesToDelete . append ( preRange)
249+ case ( is BreaklineTag , is TagBoundaryPrefix ) :
239250 // <br/><p> -> /n/n -> /n
240- mutableAttributedString . deleteCharacters ( in : preRange)
241- case ( . tagBoundarySuffix , . tagBoundarySuffix ) :
251+ rangesToDelete . append ( preRange)
252+ case ( is TagBoundarySuffix , is TagBoundarySuffix ) :
242253 // </div></div> -> /n/n -> /n
243- mutableAttributedString . deleteCharacters ( in : preRange)
244- case ( . tagBoundarySuffix , . tagBoundaryPrefix ) :
254+ rangesToDelete . append ( preRange)
255+ case ( is TagBoundarySuffix , is TagBoundaryPrefix ) :
245256 // </div><p> -> /n/n -> /n
246- mutableAttributedString . deleteCharacters ( in : preRange)
247- case ( . tagBoundaryPrefix , . tagBoundaryPrefix ) :
257+ rangesToDelete . append ( preRange)
258+ case ( is TagBoundaryPrefix , is TagBoundaryPrefix ) :
248259 // <div><p> -> /n/n -> /n
249- mutableAttributedString . deleteCharacters ( in : preRange)
250- case ( . tagBoundaryPrefix , . tagBoundarySuffix ) :
260+ rangesToDelete . append ( preRange)
261+ case ( is TagBoundaryPrefix , is TagBoundarySuffix ) :
251262 // <p></p> -> /n/n -> /n
252- mutableAttributedString . deleteCharacters ( in : preRange)
263+ rangesToDelete . append ( preRange)
253264 default :
254265 break
255266 }
@@ -260,6 +271,11 @@ extension MarkupNSAttributedStringVisitor {
260271 }
261272 }
262273
274+ // Delete ranges in reverse order to avoid range shifting issues
275+ for range in rangesToDelete. reversed ( ) {
276+ mutableAttributedString. deleteCharacters ( in: range)
277+ }
278+
263279 return mutableAttributedString
264280 }
265281
@@ -338,23 +354,33 @@ private extension MarkupNSAttributedStringVisitor {
338354 }
339355}
340356
357+ private protocol BreaklinePlaceholder : Hashable {
358+
359+ }
360+
361+ private class TagBoundaryPrefix : NSObject , BreaklinePlaceholder {
362+
363+ }
364+
365+ private class TagBoundarySuffix : NSObject , BreaklinePlaceholder {
366+
367+ }
368+
369+ private class BreaklineTag : NSObject , BreaklinePlaceholder {
370+
371+ }
372+
373+
341374private extension NSAttributedString . Key {
342375 static let breaklinePlaceholder : NSAttributedString . Key = . init( " breaklinePlaceholder " )
343- struct BreaklinePlaceholder : OptionSet {
344- let rawValue : Int
345-
346- static let tagBoundaryPrefix = BreaklinePlaceholder ( rawValue: 1 )
347- static let tagBoundarySuffix = BreaklinePlaceholder ( rawValue: 2 )
348- static let breaklineTag = BreaklinePlaceholder ( rawValue: 3 )
349- }
350376}
351377
352378private extension NSMutableAttributedString {
353379 func markPrefixTagBoundaryBreakline( ) {
354- self . insert ( NSAttributedString ( string: MarkupNSAttributedStringVisitor . breakLineSymbol, attributes: [ . breaklinePlaceholder: NSAttributedString . Key . BreaklinePlaceholder . tagBoundaryPrefix ] ) , at: 0 )
380+ self . insert ( NSAttributedString ( string: MarkupNSAttributedStringVisitor . breakLineSymbol, attributes: [ . breaklinePlaceholder: TagBoundaryPrefix ( ) ] ) , at: 0 )
355381 }
356382
357383 func markSuffixTagBoundaryBreakline( ) {
358- self . append ( NSAttributedString ( string: MarkupNSAttributedStringVisitor . breakLineSymbol, attributes: [ . breaklinePlaceholder: NSAttributedString . Key . BreaklinePlaceholder . tagBoundarySuffix ] ) )
384+ self . append ( NSAttributedString ( string: MarkupNSAttributedStringVisitor . breakLineSymbol, attributes: [ . breaklinePlaceholder: TagBoundarySuffix ( ) ] ) )
359385 }
360386}
0 commit comments