55
66@implementation EnrichedHTMLParser {
77 NSDictionary <NSNumber *, id <BaseStyleProtocol>> *_styles;
8- NSArray <NSNumber *> *_inlineOrder ;
9- NSArray <NSNumber *> *_paragraphOrder ;
8+ NSArray <id <BaseStyleProtocol>> *_inlineStyles ;
9+ NSArray <id <BaseStyleProtocol>> *_paragraphStyles ;
1010}
1111
1212- (instancetype )initWithStyles : (NSDictionary <NSNumber *, id> *)stylesDict {
@@ -16,27 +16,27 @@ - (instancetype)initWithStyles:(NSDictionary<NSNumber *, id> *)stylesDict {
1616
1717 _styles = stylesDict ?: @{};
1818
19- NSMutableArray *inlineArr = [NSMutableArray array ];
20- NSMutableArray *paragraphArr = [NSMutableArray array ];
19+ NSMutableArray *inlineStylesArray = [NSMutableArray array ];
20+ NSMutableArray *paragraphStylesArray = [NSMutableArray array ];
2121
22- for (NSNumber *type in _styles) {
23- id <BaseStyleProtocol> style = _styles[type];
22+ NSArray *allKeys = stylesDict.allKeys ;
23+ for (NSInteger i = 0 ; i < allKeys.count ; i++) {
24+ NSNumber *key = allKeys[i];
25+ id <BaseStyleProtocol> style = stylesDict[key];
2426 Class cls = style.class ;
2527
26- BOOL isParagraph = ([cls respondsToSelector: @selector (isParagraphStyle )] &&
27- [cls isParagraphStyle ]) ;
28+ BOOL isParagraph = ([cls respondsToSelector: @selector (isParagraphStyle )]) &&
29+ [cls isParagraphStyle ];
2830
29- if (isParagraph)
30- [paragraphArr addObject: type];
31- else
32- [inlineArr addObject: type];
31+ if (isParagraph) {
32+ [paragraphStylesArray addObject: style];
33+ } else {
34+ [inlineStylesArray addObject: style];
35+ }
3336 }
3437
35- [inlineArr sortUsingSelector: @selector (compare: )];
36- [paragraphArr sortUsingSelector: @selector (compare: )];
37-
38- _inlineOrder = inlineArr.copy ;
39- _paragraphOrder = paragraphArr.copy ;
38+ _inlineStyles = inlineStylesArray.copy ;
39+ _paragraphStyles = paragraphStylesArray.copy ;
4040
4141 return self;
4242}
@@ -49,10 +49,10 @@ - (NSString *)buildHtmlFromAttributedString:(NSAttributedString *)text
4949
5050 HTMLElement *root = [self buildRootNodeFromAttributedString: text];
5151
52- NSMutableData *buf = [NSMutableData data ];
53- [self createHtmlFromNode: root into: buf pretify: pretify];
52+ NSMutableData *buffer = [NSMutableData data ];
53+ [self createHtmlFromNode: root into: buffer pretify: pretify];
5454
55- return [[NSString alloc ] initWithData: buf encoding: NSUTF8StringEncoding];
55+ return [[NSString alloc ] initWithData: buffer encoding: NSUTF8StringEncoding];
5656}
5757
5858- (HTMLElement *)buildRootNodeFromAttributedString : (NSAttributedString *)text {
@@ -65,7 +65,7 @@ - (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
6565 br.tag = " br" ;
6666 br.selfClosing = YES ;
6767
68- __block NSNumber *previousParagraphType = nil ;
68+ __block id <BaseStyleProtocol> previousParagraphStyle = nil ;
6969 __block HTMLElement *previousNode = nil ;
7070
7171 [plain
@@ -77,37 +77,27 @@ - (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
7777 BOOL *__unused stop) {
7878 if (paragraphRange.length == 0 ) {
7979 [root.children addObject: br];
80- previousParagraphType = nil ;
80+ previousParagraphStyle = nil ;
8181 previousNode = nil ;
8282 return ;
8383 }
84- NSDictionary *attrsAtStart =
85- [text attributesAtIndex: paragraphRange.location
86- effectiveRange: nil ];
87-
88- NSNumber *ptype = nil ;
89- for (NSNumber *sty in self->_paragraphOrder ) {
90- id <BaseStyleProtocol> s = self->_styles [sty];
91- NSString *key = [s.class attributeKey ];
92- id val = attrsAtStart[key];
93- if (val && [s styleCondition: val
94- range: paragraphRange]) {
95- ptype = sty;
96- break ;
97- }
98- }
9984
100- HTMLElement *container =
101- [self containerForBlock: ptype
102- reuseLastOf: previousParagraphType
103- previousNode: previousNode
104- rootNode: root];
85+ id <BaseStyleProtocol> paragraphStyle =
86+ [self detectParagraphStyle: text
87+ paragraphRange: paragraphRange];
10588
106- previousParagraphType = ptype;
89+ HTMLElement *container = [self
90+ containerForParagraphStyle: paragraphStyle
91+ previousParagraphStyle: previousParagraphStyle
92+ previousNode: previousNode
93+ rootNode: root];
94+
95+ previousParagraphStyle = paragraphStyle;
10796 previousNode = container;
10897
109- HTMLElement *target = [self getNextContainer: ptype
110- currentContainer: container];
98+ HTMLElement *target =
99+ [self nextContainerForParagraphStyle: paragraphStyle
100+ currentContainer: container];
111101
112102 [text
113103 enumerateAttributesInRange: paragraphRange
@@ -128,10 +118,47 @@ - (HTMLElement *)buildRootNodeFromAttributedString:(NSAttributedString *)text {
128118 return root;
129119}
130120
131- - (HTMLElement *)containerForBlock : (NSNumber *)currentParagraphType
132- reuseLastOf : (NSNumber *)previousParagraphType
133- previousNode : (HTMLElement *)previousNode
134- rootNode : (HTMLElement *)rootNode {
121+ - (HTMLElement *)nextContainerForParagraphStyle :
122+ (id <BaseStyleProtocol> _Nullable)style
123+ currentContainer : (HTMLElement *)container {
124+ if (!style)
125+ return container;
126+
127+ const char *sub = [style.class subTagName ];
128+ if (!sub)
129+ return container;
130+
131+ HTMLElement *inner = [HTMLElement new ];
132+ inner.tag = sub;
133+ [container.children addObject: inner];
134+ return inner;
135+ }
136+
137+ - (id <BaseStyleProtocol> _Nullable)
138+ detectParagraphStyle:(NSAttributedString *)text
139+ paragraphRange : (NSRange )paragraphRange {
140+ NSDictionary *attrsAtStart = [text attributesAtIndex: paragraphRange.location
141+ effectiveRange: nil ];
142+ id <BaseStyleProtocol> _Nullable foundParagraphStyle = nil ;
143+ for (NSInteger i = 0 ; i < _paragraphStyles.count ; i++) {
144+ id <BaseStyleProtocol> paragraphStyle = _paragraphStyles[i];
145+ Class paragraphStyleClass = paragraphStyle.class ;
146+
147+ NSAttributedStringKey attributeKey = [paragraphStyleClass attributeKey ];
148+ id value = attrsAtStart[attributeKey];
149+
150+ if (value && [paragraphStyle styleCondition: value range: paragraphRange]) {
151+ return paragraphStyle;
152+ }
153+ }
154+
155+ return foundParagraphStyle;
156+ }
157+
158+ - (HTMLElement *)currentParagraphType : (NSNumber *)currentParagraphType
159+ previousParagraphType : (NSNumber *)previousParagraphType
160+ previousNode : (HTMLElement *)previousNode
161+ rootNode : (HTMLElement *)rootNode {
135162 if (!currentParagraphType) {
136163 HTMLElement *outer = [HTMLElement new ];
137164 outer.tag = " p" ;
@@ -156,25 +183,31 @@ - (HTMLElement *)containerForBlock:(NSNumber *)currentParagraphType
156183 return outer;
157184}
158185
159- - (HTMLElement *)getNextContainer : (NSNumber *)blockType
160- currentContainer : (HTMLElement *)container {
161-
162- if (!blockType)
163- return container;
164-
165- id <BaseStyleProtocol> style = _styles[blockType];
186+ - (HTMLElement *)
187+ containerForParagraphStyle:(id <BaseStyleProtocol> _Nullable)currentStyle
188+ previousParagraphStyle : (id <BaseStyleProtocol> _Nullable)previousStyle
189+ previousNode : (HTMLElement *)previousNode
190+ rootNode : (HTMLElement *)rootNode {
191+ if (!currentStyle) {
192+ HTMLElement *outer = [HTMLElement new ];
193+ outer.tag = " p" ;
194+ [rootNode.children addObject: outer];
195+ return outer;
196+ }
166197
167- const char *subTagName = [style.class subTagName ];
198+ BOOL sameStyle = (currentStyle == previousStyle);
199+ Class styleClass = currentStyle.class ;
200+ BOOL hasSub = ([styleClass subTagName ] != NULL );
168201
169- if (subTagName) {
170- HTMLElement *inner = [HTMLElement new ];
171- inner.tag = subTagName;
172- [container.children addObject: inner];
173- return inner;
174- }
202+ if (sameStyle && hasSub)
203+ return previousNode;
175204
176- return container;
205+ HTMLElement *outer = [HTMLElement new ];
206+ outer.tag = [styleClass tagName ];
207+ [rootNode.children addObject: outer];
208+ return outer;
177209}
210+
178211- (HTMLNode *)getInlineStyleNodes : (NSAttributedString *)text
179212 range : (NSRange )range
180213 attrs : (NSDictionary *)attrs
@@ -184,13 +217,12 @@ - (HTMLNode *)getInlineStyleNodes:(NSAttributedString *)text
184217 textNode.range = range;
185218 HTMLNode *currentNode = textNode;
186219
187- for (NSNumber *inlineStyleType in _inlineOrder) {
188-
189- id <BaseStyleProtocol> styleObject = _styles[inlineStyleType];
220+ for (NSInteger i = 0 ; i < _inlineStyles.count ; i++) {
221+ id <BaseStyleProtocol> styleObject = _inlineStyles[i];
190222 Class styleClass = styleObject.class ;
191223
192- NSString *key = [styleClass attributeKey ];
193- id value = attrs[key ];
224+ NSAttributedStringKey attributeKey = [styleClass attributeKey ];
225+ id value = attrs[attributeKey ];
194226
195227 if (!value || ![styleObject styleCondition: value range: range])
196228 continue ;
0 commit comments