From bf061d63670177719eba15b717472fcb7768091e Mon Sep 17 00:00:00 2001 From: iska Date: Mon, 27 Apr 2015 19:45:32 +0200 Subject: [PATCH] Add support for inserting a Document Fragment Previous implementation would just insert the fragment as a child node, whereas it should insert its child nodes. --- HTMLKit/HTMLNode.m | 64 +++++++++++-------- HTMLKitTests/HTMLKitMutationAlgorithmsTests.m | 27 ++++++++ 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/HTMLKit/HTMLNode.m b/HTMLKit/HTMLNode.m index 6b211be..d4c51aa 100644 --- a/HTMLKit/HTMLNode.m +++ b/HTMLKit/HTMLNode.m @@ -139,35 +139,48 @@ return [self.childNodes indexOfObject:node]; } -- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child -{ - node = [self preInsertNode:node beforeChildNode:child]; - node.parentNode = self; - return node; -} - - (HTMLNode *)appendNode:(HTMLNode *)node { - node = [self preInsertNode:node beforeChildNode:nil]; - node.parentNode = self; - return node; + return [self insertNode:node beforeChildNode:nil]; } - (void)appendNodes:(NSArray *)nodes { for (id node in nodes) { - [self appendNode:node]; + [self insertNode:node beforeChildNode:nil]; } } +- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child +{ + [self ensurePreInsertionValidityOfNode:node beforeChildNode:child]; + + [self.ownerDocument adoptNode:node]; + + NSArray *nodes = node.type == HTMLNodeDocumentFragment ? [NSArray arrayWithArray:node.childNodes.array] : @[node]; + + NSUInteger index = [self indexOfChildNode:child]; + if (index != NSNotFound) { + NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, nodes.count)]; + [(NSMutableOrderedSet *)self.childNodes insertObjects:nodes atIndexes:indexes]; + } else { + [(NSMutableOrderedSet *)self.childNodes addObjectsFromArray:nodes]; + } + + if (node.type == HTMLNodeDocumentFragment) { + [node removeAllChildNodes]; + } + + [nodes makeObjectsPerformSelector:@selector(setParentNode:) withObject:self]; + + return node; +} + - (HTMLNode *)replaceChildNode:(HTMLNode *)child withNode:(HTMLNode *)node { [self ensureReplacementValidityOfChildNode:child withNode:node]; - [self.ownerDocument adoptNode:node]; - NSUInteger index = [self indexOfChildNode:child]; - node.parentNode = self; - [(NSMutableOrderedSet *)self.childNodes replaceObjectAtIndex:index withObject:node]; + [self insertNode:node beforeChildNode:child]; [child removeFromParentNode]; return child; } @@ -216,7 +229,8 @@ - (void)removeAllChildNodes { - [self.childNodes.array makeObjectsPerformSelector:@selector(removeFromParentNode)]; + [self.childNodes.array makeObjectsPerformSelector:@selector(setParentNode:) withObject:nil]; + [(NSMutableOrderedSet *)self.childNodes removeAllObjects]; } #pragma mark - Enumeration @@ -242,22 +256,22 @@ return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:YES]; } -#pragma mark - Mutation Algorithms - -- (HTMLNode *)preInsertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child +- (void)doInsertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child { - [self ensurePreInsertionValidityOfNode:node beforeChildNode:child]; - [self.ownerDocument adoptNode:node]; + NSArray *nodes = node.type == HTMLNodeDocumentFragment ? node.childNodes.array : @[node]; + NSUInteger index = [self indexOfChildNode:child]; if (index != NSNotFound) { - [(NSMutableOrderedSet *)self.childNodes insertObject:node atIndex:index]; + NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, nodes.count)]; + [(NSMutableOrderedSet *)self.childNodes insertObjects:nodes atIndexes:indexes]; } else { - [(NSMutableOrderedSet *)self.childNodes addObject:node]; + [(NSMutableOrderedSet *)self.childNodes addObjectsFromArray:nodes]; } - - return node; } + +#pragma mark - Validity Checks + NS_INLINE void CheckParentValid(HTMLNode *parent, NSString *cmd) { if (parent.type != HTMLNodeDocument && diff --git a/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m b/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m index 4f69454..d4d37f6 100644 --- a/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m +++ b/HTMLKitTests/HTMLKitMutationAlgorithmsTests.m @@ -8,6 +8,9 @@ #import #import "HTMLNodes.h" +#import "NSString+HTMLKit.h" + +extern uint64_t dispatch_benchmark(size_t count, void (^block)(void)); @interface HTMLKitMutationAlgorithmsTests : XCTestCase @@ -15,6 +18,30 @@ @implementation HTMLKitMutationAlgorithmsTests +- (void)testAppendDocumentFragment +{ + HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"]; + HTMLComment *comment = [HTMLComment new]; + [element appendNode:comment]; + + HTMLDocumentFragment *fragment = [HTMLDocumentFragment new]; + HTMLElement *firstChild = [HTMLElement new]; + HTMLElement *secondChild = [HTMLElement new]; + [fragment appendNode:firstChild]; + [fragment appendNode:secondChild]; + + [element appendNode:fragment]; + XCTAssertEqual(element.childNodesCount, 3); + XCTAssertEqual(fragment.childNodesCount, 0); + + XCTAssertEqualObjects(firstChild.parentNode, element); + XCTAssertEqualObjects(secondChild.parentNode, element); + XCTAssertEqualObjects(element.firstChiledNode, comment); + XCTAssertEqualObjects(element.firstChiledNode.nextSibling, firstChild); + XCTAssertEqualObjects(element.lastChildNode.previousSibling, firstChild); + XCTAssertEqualObjects(element.lastChildNode, secondChild); +} + - (void)testValidParentNodeWhenAppending { HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];